Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / Mail / Base64Stream.cs / 1305376 / Base64Stream.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Net { using System; using System.IO; using System.Net.Mime; using System.Text; using System.Diagnostics; internal class Base64Stream : DelegatedStream, IEncodableStream { static byte[] base64DecodeMap = new byte[] { //0 1 2 3 4 5 6 7 8 9 A B C D E F 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, // 2 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, // 3 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 4 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, // 5 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 6 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255, // 7 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // F }; static byte[] base64EncodeMap = new byte[] { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99,100,101,102, 103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, 119,120,121,122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 61 }; int lineLength; ReadStateInfo readState; Base64WriteStateInfo writeState; //the number of bytes needed to encode three bytes (see algorithm description in Encode method below) const int sizeOfBase64EncodedChar = 4; //bytes with this value in the decode map are invalid const byte invalidBase64Value = 255; //length in bytes of a soft CRLF for folding const int sizeOfSoftCRLF = 3; internal Base64Stream(Stream stream, Base64WriteStateInfo writeStateInfo) : base(stream) { this.writeState = new Base64WriteStateInfo(); this.lineLength = writeStateInfo.MaxLineLength; } internal Base64Stream(Stream stream, int lineLength) : base(stream) { this.lineLength = lineLength; this.writeState = new Base64WriteStateInfo(); } internal Base64Stream(Base64WriteStateInfo writeStateInfo) { this.lineLength = writeStateInfo.MaxLineLength; this.writeState = writeStateInfo; } public override bool CanWrite { get { return base.CanWrite; } } ReadStateInfo ReadState { get { if (this.readState == null) this.readState = new ReadStateInfo(); return this.readState; } } internal Base64WriteStateInfo WriteState { get { Debug.Assert(writeState != null, "writeState was null"); return this.writeState; } } public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count"); ReadAsyncResult result = new ReadAsyncResult(this, buffer, offset, count, callback, state); result.Read(); return result; } public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count"); WriteAsyncResult result = new WriteAsyncResult(this, buffer, offset, count, callback, state); result.Write(); return result; } public override void Close() { if (this.writeState != null && WriteState.Length > 0) { switch (WriteState.Padding) { case 2: WriteState.Buffer[WriteState.Length++] = base64EncodeMap[WriteState.LastBits]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; break; case 1: WriteState.Buffer[WriteState.Length++] = base64EncodeMap[WriteState.LastBits]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; break; } WriteState.Padding = 0; FlushInternal(); } base.Close(); } public int DecodeBytes(byte[] buffer, int offset, int count) { unsafe { fixed (byte* pBuffer = buffer) { byte* start = pBuffer + offset; byte* source = start; byte* dest = start; byte* end = start + count; while (source < end) { //space and tab are ok because folding must include a whitespace char. if (*source == '\r' || *source == '\n' || *source == '=' || *source == ' ' || *source == '\t') { source++; continue; } byte s = base64DecodeMap[*source]; if (s == invalidBase64Value) throw new FormatException(SR.GetString(SR.MailBase64InvalidCharacter)); switch (ReadState.Pos) { case 0: ReadState.Val = (byte)(s << 2); ReadState.Pos++; break; case 1: *dest++ = (byte)(ReadState.Val + (s >> 4)); ReadState.Val = (byte)(s << 4); ReadState.Pos++; break; case 2: *dest++ = (byte)(ReadState.Val + (s >> 2)); ReadState.Val = (byte)(s << 6); ReadState.Pos++; break; case 3: *dest++ = (byte)(ReadState.Val + s); ReadState.Pos = 0; break; } source++; } count = (int)(dest - start); } } return count; } public int EncodeBytes(byte[] buffer, int offset, int count) { return this.EncodeBytes(buffer, offset, count, true, true); } internal int EncodeBytes(byte[] buffer, int offset, int count, bool dontDeferFinalBytes, bool shouldAppendSpaceToCRLF) { //if the header length is 0 then we should use a soft CRLF without appending the ?= footer //always because this is part of the body encoding. //otherwise we should append the footer, then the soft clrf, then whitespace, then the =?xxxx?B? header again bool ShouldAppendHeaderValue = writeState.HeaderLength != 0; int cur = offset; Debug.Assert(buffer != null, "buffer was null"); Debug.Assert(this.writeState != null, "writestate was null"); Debug.Assert(this.writeState.Buffer != null, "writestate.buffer was null"); WriteState.AppendHeader(); WriteState.CurrentLineLength += writeState.MimeHeaderLength; switch (WriteState.Padding) { case 2: WriteState.Buffer[WriteState.Length++] = base64EncodeMap[WriteState.LastBits | ((buffer[cur]&0xf0)>>4)]; if (count == 1) { WriteState.LastBits = (byte)((buffer[cur]&0x0f)<<2); WriteState.Padding = 1; return cur - offset; } WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur]&0x0f)<<2) | ((buffer[cur+1]&0xc0)>>6)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur+1]&0x3f)]; cur+=2; count-=2; WriteState.Padding = 0; WriteState.CurrentLineLength += 2; break; case 1: WriteState.Buffer[WriteState.Length++] = base64EncodeMap[WriteState.LastBits | ((buffer[cur]&0xc0)>>6)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur]&0x3f)]; cur++; count--; WriteState.Padding = 0; WriteState.CurrentLineLength ++; break; } int calcLength = cur + (count - (count%3)); //Convert three bytes at a time to base64 notation. This will consume 4 chars. for (; cur < calcLength; cur+=3) { if (lineLength != -1 && WriteState.CurrentLineLength + sizeOfBase64EncodedChar > lineLength - sizeOfSoftCRLF && !ShouldAppendHeaderValue) { WriteState.Buffer[WriteState.Length++] = (byte)'\r'; WriteState.Buffer[WriteState.Length++] = (byte)'\n'; if (shouldAppendSpaceToCRLF) { WriteState.Buffer[WriteState.Length++] = (byte)' '; } WriteState.CurrentLineLength = 0; } //can we encode another three bytes with a buffer this long? if (WriteState.Length + sizeOfBase64EncodedChar > WriteState.Buffer.Length) { WriteState.ResizeBuffer(); } //how we actually encode: get three bytes in the //buffer to be encoded. Then, extract six bits at a time and encode each six bit chunk as a base-64 character. //this means that three bytes of data will be encoded as four base64 characters. It also means that to encode //a character, we must have three bytes to encode so if the number of bytes is not divisible by three, we //must pad the buffer (this happens below) WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur]&0xfc)>>2]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur]&0x03)<<4) | ((buffer[cur+1]&0xf0)>>4)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur+1]&0x0f)<<2) | ((buffer[cur+2]&0xc0)>>6)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur+2]&0x3f)]; WriteState.CurrentLineLength += 4; //should I fold? //how many characters have we written on this line and how many spaces do I have left //if spaces left - 4 (enough for one more character) - the space the footer would occupy //is less than the space it would take to write the footer //then fold, which is to add the trailing footer and then a soft crlf. //then we need to prepare the buffer for the new line by appending the header again and incrementing //the count appropriately if (WriteState.CurrentLineLength + sizeOfBase64EncodedChar + writeState.FooterLength >= EncodedStreamFactory.DefaultMaxLineLength && ShouldAppendHeaderValue) { //see if we should resize if (WriteState.Length + writeState.FooterLength + writeState.HeaderLength > WriteState.Buffer.Length) WriteState.ResizeBuffer(); //add footer WriteState.AppendFooter(); //add soft line break writeState.Buffer[WriteState.Length++] = (byte)'\r'; writeState.Buffer[WriteState.Length++] = (byte)'\n'; if (shouldAppendSpaceToCRLF) { //add whitespace to new line (RFC 2045, soft CRLF must be followed by whitespace char) //space selected for parity with other MS email clients WriteState.Buffer[WriteState.Length++] = (byte)' '; } //add header to new line WriteState.AppendHeader(); //reset writeStateInfo WriteState.CurrentLineLength = WriteState.HeaderLength + 1; } } cur = calcLength; //Where we left off before if (WriteState.Length + sizeOfBase64EncodedChar > WriteState.Buffer.Length) { WriteState.ResizeBuffer(); } //now pad this thing if we need to. Since it must be a number of bytes that is evenly divisble by 3, //if there are extra bytes, pad with '=' until we have a number of bytes divisible by 3 switch(count%3) { case 2: //One character padding needed WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur]&0xFC)>>2]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur]&0x03)<<4)|((buffer[cur+1]&0xf0)>>4)]; if (dontDeferFinalBytes) { WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur+1]&0x0f)<<2)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; WriteState.Padding = 0; WriteState.CurrentLineLength += 4; } else{ WriteState.LastBits = (byte)((buffer[cur+1]&0x0F)<<2); WriteState.Padding = 1; WriteState.CurrentLineLength += 2; } cur += 2; break; case 1: // Two character padding needed WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur]&0xFC)>>2]; if (dontDeferFinalBytes) { WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(byte)((buffer[cur]&0x03)<<4)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; WriteState.Padding = 0; WriteState.CurrentLineLength+=4; } else{ WriteState.LastBits = (byte)((buffer[cur]&0x03)<<4); WriteState.Padding = 2; WriteState.CurrentLineLength ++; } cur++; break; } WriteState.AppendFooter(); return cur - offset; } public Stream GetStream() { return this; } public string GetEncodedString() { return ASCIIEncoding.ASCII.GetString(this.WriteState.Buffer, 0, this.WriteState.Length); } public override int EndRead(IAsyncResult asyncResult) { if (asyncResult == null) throw new ArgumentNullException("asyncResult"); int read = ReadAsyncResult.End(asyncResult); return read; } public override void EndWrite(IAsyncResult asyncResult) { if (asyncResult == null) throw new ArgumentNullException("asyncResult"); WriteAsyncResult.End(asyncResult); } public override void Flush() { if (this.writeState != null && WriteState.Length > 0) { FlushInternal(); } base.Flush(); } private void FlushInternal() { base.Write(WriteState.Buffer, 0, WriteState.Length); WriteState.Length = 0; } public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count"); for (;;) { // read data from the underlying stream int read = base.Read(buffer, offset, count); // if the underlying stream returns 0 then there // is no more data - ust return 0. if (read == 0) return 0; // while decoding, we may end up not having // any bytes to return pending additional data // from the underlying stream. read = DecodeBytes(buffer, offset, read); if (read > 0) return read; } } public override void Write(byte[] buffer, int offset, int count) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count"); int written = 0; // do not append a space when writing from a stream since this means // it's writing the email body for (;;) { written += EncodeBytes(buffer, offset + written, count - written, false, false); if (written < count) FlushInternal(); else break; } } class ReadAsyncResult : LazyAsyncResult { Base64Stream parent; byte[] buffer; int offset; int count; int read; static AsyncCallback onRead = new AsyncCallback(OnRead); internal ReadAsyncResult(Base64Stream parent, byte[] buffer, int offset, int count, AsyncCallback callback, object state) : base(null,state,callback) { this.parent = parent; this.buffer = buffer; this.offset = offset; this.count = count; } bool CompleteRead(IAsyncResult result) { this.read = this.parent.BaseStream.EndRead(result); // if the underlying stream returns 0 then there // is no more data - ust return 0. if (read == 0) { InvokeCallback(); return true; } // while decoding, we may end up not having // any bytes to return pending additional data // from the underlying stream. this.read = this.parent.DecodeBytes(this.buffer, this.offset, this.read); if (this.read > 0) { InvokeCallback(); return true; } return false; } internal void Read() { for (;;) { IAsyncResult result = this.parent.BaseStream.BeginRead(this.buffer, this.offset, this.count, onRead, this); if (!result.CompletedSynchronously || CompleteRead(result)) break; } } static void OnRead(IAsyncResult result) { if (!result.CompletedSynchronously) { ReadAsyncResult thisPtr = (ReadAsyncResult)result.AsyncState; try { if (!thisPtr.CompleteRead(result)) thisPtr.Read(); } catch (Exception e) { if (thisPtr.IsCompleted) throw; thisPtr.InvokeCallback(e); } } } internal static int End(IAsyncResult result) { ReadAsyncResult thisPtr = (ReadAsyncResult)result; thisPtr.InternalWaitForCompletion(); return thisPtr.read; } } class WriteAsyncResult : LazyAsyncResult { Base64Stream parent; byte[] buffer; int offset; int count; static AsyncCallback onWrite = new AsyncCallback(OnWrite); int written; internal WriteAsyncResult(Base64Stream parent, byte[] buffer, int offset, int count, AsyncCallback callback, object state) : base(null, state, callback) { this.parent = parent; this.buffer = buffer; this.offset = offset; this.count = count; } internal void Write() { for (;;) { // do not append a space when writing from a stream since this means // it's writing the email body this.written += this.parent.EncodeBytes(this.buffer, this.offset + this.written, this.count - this.written, false, false); if (this.written < this.count) { IAsyncResult result = this.parent.BaseStream.BeginWrite(this.parent.WriteState.Buffer, 0, this.parent.WriteState.Length, onWrite, this); if (!result.CompletedSynchronously) break; CompleteWrite(result); } else { InvokeCallback(); break; } } } void CompleteWrite(IAsyncResult result) { this.parent.BaseStream.EndWrite(result); this.parent.WriteState.Length = 0; } static void OnWrite(IAsyncResult result) { if (!result.CompletedSynchronously) { WriteAsyncResult thisPtr = (WriteAsyncResult)result.AsyncState; try { thisPtr.CompleteWrite(result); thisPtr.Write(); } catch (Exception e) { if (thisPtr.IsCompleted) throw; thisPtr.InvokeCallback(e); } } } internal static void End(IAsyncResult result) { WriteAsyncResult thisPtr = (WriteAsyncResult)result; thisPtr.InternalWaitForCompletion(); Debug.Assert(thisPtr.written == thisPtr.count); } } class ReadStateInfo { byte val; byte pos; internal byte Val { get { return this.val; } set { this.val = value; } } internal byte Pos { get { return this.pos; } set { this.pos = value; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Net { using System; using System.IO; using System.Net.Mime; using System.Text; using System.Diagnostics; internal class Base64Stream : DelegatedStream, IEncodableStream { static byte[] base64DecodeMap = new byte[] { //0 1 2 3 4 5 6 7 8 9 A B C D E F 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, // 2 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, // 3 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 4 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, // 5 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 6 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255, // 7 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // F }; static byte[] base64EncodeMap = new byte[] { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99,100,101,102, 103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, 119,120,121,122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 61 }; int lineLength; ReadStateInfo readState; Base64WriteStateInfo writeState; //the number of bytes needed to encode three bytes (see algorithm description in Encode method below) const int sizeOfBase64EncodedChar = 4; //bytes with this value in the decode map are invalid const byte invalidBase64Value = 255; //length in bytes of a soft CRLF for folding const int sizeOfSoftCRLF = 3; internal Base64Stream(Stream stream, Base64WriteStateInfo writeStateInfo) : base(stream) { this.writeState = new Base64WriteStateInfo(); this.lineLength = writeStateInfo.MaxLineLength; } internal Base64Stream(Stream stream, int lineLength) : base(stream) { this.lineLength = lineLength; this.writeState = new Base64WriteStateInfo(); } internal Base64Stream(Base64WriteStateInfo writeStateInfo) { this.lineLength = writeStateInfo.MaxLineLength; this.writeState = writeStateInfo; } public override bool CanWrite { get { return base.CanWrite; } } ReadStateInfo ReadState { get { if (this.readState == null) this.readState = new ReadStateInfo(); return this.readState; } } internal Base64WriteStateInfo WriteState { get { Debug.Assert(writeState != null, "writeState was null"); return this.writeState; } } public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count"); ReadAsyncResult result = new ReadAsyncResult(this, buffer, offset, count, callback, state); result.Read(); return result; } public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count"); WriteAsyncResult result = new WriteAsyncResult(this, buffer, offset, count, callback, state); result.Write(); return result; } public override void Close() { if (this.writeState != null && WriteState.Length > 0) { switch (WriteState.Padding) { case 2: WriteState.Buffer[WriteState.Length++] = base64EncodeMap[WriteState.LastBits]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; break; case 1: WriteState.Buffer[WriteState.Length++] = base64EncodeMap[WriteState.LastBits]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; break; } WriteState.Padding = 0; FlushInternal(); } base.Close(); } public int DecodeBytes(byte[] buffer, int offset, int count) { unsafe { fixed (byte* pBuffer = buffer) { byte* start = pBuffer + offset; byte* source = start; byte* dest = start; byte* end = start + count; while (source < end) { //space and tab are ok because folding must include a whitespace char. if (*source == '\r' || *source == '\n' || *source == '=' || *source == ' ' || *source == '\t') { source++; continue; } byte s = base64DecodeMap[*source]; if (s == invalidBase64Value) throw new FormatException(SR.GetString(SR.MailBase64InvalidCharacter)); switch (ReadState.Pos) { case 0: ReadState.Val = (byte)(s << 2); ReadState.Pos++; break; case 1: *dest++ = (byte)(ReadState.Val + (s >> 4)); ReadState.Val = (byte)(s << 4); ReadState.Pos++; break; case 2: *dest++ = (byte)(ReadState.Val + (s >> 2)); ReadState.Val = (byte)(s << 6); ReadState.Pos++; break; case 3: *dest++ = (byte)(ReadState.Val + s); ReadState.Pos = 0; break; } source++; } count = (int)(dest - start); } } return count; } public int EncodeBytes(byte[] buffer, int offset, int count) { return this.EncodeBytes(buffer, offset, count, true, true); } internal int EncodeBytes(byte[] buffer, int offset, int count, bool dontDeferFinalBytes, bool shouldAppendSpaceToCRLF) { //if the header length is 0 then we should use a soft CRLF without appending the ?= footer //always because this is part of the body encoding. //otherwise we should append the footer, then the soft clrf, then whitespace, then the =?xxxx?B? header again bool ShouldAppendHeaderValue = writeState.HeaderLength != 0; int cur = offset; Debug.Assert(buffer != null, "buffer was null"); Debug.Assert(this.writeState != null, "writestate was null"); Debug.Assert(this.writeState.Buffer != null, "writestate.buffer was null"); WriteState.AppendHeader(); WriteState.CurrentLineLength += writeState.MimeHeaderLength; switch (WriteState.Padding) { case 2: WriteState.Buffer[WriteState.Length++] = base64EncodeMap[WriteState.LastBits | ((buffer[cur]&0xf0)>>4)]; if (count == 1) { WriteState.LastBits = (byte)((buffer[cur]&0x0f)<<2); WriteState.Padding = 1; return cur - offset; } WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur]&0x0f)<<2) | ((buffer[cur+1]&0xc0)>>6)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur+1]&0x3f)]; cur+=2; count-=2; WriteState.Padding = 0; WriteState.CurrentLineLength += 2; break; case 1: WriteState.Buffer[WriteState.Length++] = base64EncodeMap[WriteState.LastBits | ((buffer[cur]&0xc0)>>6)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur]&0x3f)]; cur++; count--; WriteState.Padding = 0; WriteState.CurrentLineLength ++; break; } int calcLength = cur + (count - (count%3)); //Convert three bytes at a time to base64 notation. This will consume 4 chars. for (; cur < calcLength; cur+=3) { if (lineLength != -1 && WriteState.CurrentLineLength + sizeOfBase64EncodedChar > lineLength - sizeOfSoftCRLF && !ShouldAppendHeaderValue) { WriteState.Buffer[WriteState.Length++] = (byte)'\r'; WriteState.Buffer[WriteState.Length++] = (byte)'\n'; if (shouldAppendSpaceToCRLF) { WriteState.Buffer[WriteState.Length++] = (byte)' '; } WriteState.CurrentLineLength = 0; } //can we encode another three bytes with a buffer this long? if (WriteState.Length + sizeOfBase64EncodedChar > WriteState.Buffer.Length) { WriteState.ResizeBuffer(); } //how we actually encode: get three bytes in the //buffer to be encoded. Then, extract six bits at a time and encode each six bit chunk as a base-64 character. //this means that three bytes of data will be encoded as four base64 characters. It also means that to encode //a character, we must have three bytes to encode so if the number of bytes is not divisible by three, we //must pad the buffer (this happens below) WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur]&0xfc)>>2]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur]&0x03)<<4) | ((buffer[cur+1]&0xf0)>>4)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur+1]&0x0f)<<2) | ((buffer[cur+2]&0xc0)>>6)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur+2]&0x3f)]; WriteState.CurrentLineLength += 4; //should I fold? //how many characters have we written on this line and how many spaces do I have left //if spaces left - 4 (enough for one more character) - the space the footer would occupy //is less than the space it would take to write the footer //then fold, which is to add the trailing footer and then a soft crlf. //then we need to prepare the buffer for the new line by appending the header again and incrementing //the count appropriately if (WriteState.CurrentLineLength + sizeOfBase64EncodedChar + writeState.FooterLength >= EncodedStreamFactory.DefaultMaxLineLength && ShouldAppendHeaderValue) { //see if we should resize if (WriteState.Length + writeState.FooterLength + writeState.HeaderLength > WriteState.Buffer.Length) WriteState.ResizeBuffer(); //add footer WriteState.AppendFooter(); //add soft line break writeState.Buffer[WriteState.Length++] = (byte)'\r'; writeState.Buffer[WriteState.Length++] = (byte)'\n'; if (shouldAppendSpaceToCRLF) { //add whitespace to new line (RFC 2045, soft CRLF must be followed by whitespace char) //space selected for parity with other MS email clients WriteState.Buffer[WriteState.Length++] = (byte)' '; } //add header to new line WriteState.AppendHeader(); //reset writeStateInfo WriteState.CurrentLineLength = WriteState.HeaderLength + 1; } } cur = calcLength; //Where we left off before if (WriteState.Length + sizeOfBase64EncodedChar > WriteState.Buffer.Length) { WriteState.ResizeBuffer(); } //now pad this thing if we need to. Since it must be a number of bytes that is evenly divisble by 3, //if there are extra bytes, pad with '=' until we have a number of bytes divisible by 3 switch(count%3) { case 2: //One character padding needed WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur]&0xFC)>>2]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur]&0x03)<<4)|((buffer[cur+1]&0xf0)>>4)]; if (dontDeferFinalBytes) { WriteState.Buffer[WriteState.Length++] = base64EncodeMap[((buffer[cur+1]&0x0f)<<2)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; WriteState.Padding = 0; WriteState.CurrentLineLength += 4; } else{ WriteState.LastBits = (byte)((buffer[cur+1]&0x0F)<<2); WriteState.Padding = 1; WriteState.CurrentLineLength += 2; } cur += 2; break; case 1: // Two character padding needed WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(buffer[cur]&0xFC)>>2]; if (dontDeferFinalBytes) { WriteState.Buffer[WriteState.Length++] = base64EncodeMap[(byte)((buffer[cur]&0x03)<<4)]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; WriteState.Buffer[WriteState.Length++] = base64EncodeMap[64]; WriteState.Padding = 0; WriteState.CurrentLineLength+=4; } else{ WriteState.LastBits = (byte)((buffer[cur]&0x03)<<4); WriteState.Padding = 2; WriteState.CurrentLineLength ++; } cur++; break; } WriteState.AppendFooter(); return cur - offset; } public Stream GetStream() { return this; } public string GetEncodedString() { return ASCIIEncoding.ASCII.GetString(this.WriteState.Buffer, 0, this.WriteState.Length); } public override int EndRead(IAsyncResult asyncResult) { if (asyncResult == null) throw new ArgumentNullException("asyncResult"); int read = ReadAsyncResult.End(asyncResult); return read; } public override void EndWrite(IAsyncResult asyncResult) { if (asyncResult == null) throw new ArgumentNullException("asyncResult"); WriteAsyncResult.End(asyncResult); } public override void Flush() { if (this.writeState != null && WriteState.Length > 0) { FlushInternal(); } base.Flush(); } private void FlushInternal() { base.Write(WriteState.Buffer, 0, WriteState.Length); WriteState.Length = 0; } public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count"); for (;;) { // read data from the underlying stream int read = base.Read(buffer, offset, count); // if the underlying stream returns 0 then there // is no more data - ust return 0. if (read == 0) return 0; // while decoding, we may end up not having // any bytes to return pending additional data // from the underlying stream. read = DecodeBytes(buffer, offset, read); if (read > 0) return read; } } public override void Write(byte[] buffer, int offset, int count) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count"); int written = 0; // do not append a space when writing from a stream since this means // it's writing the email body for (;;) { written += EncodeBytes(buffer, offset + written, count - written, false, false); if (written < count) FlushInternal(); else break; } } class ReadAsyncResult : LazyAsyncResult { Base64Stream parent; byte[] buffer; int offset; int count; int read; static AsyncCallback onRead = new AsyncCallback(OnRead); internal ReadAsyncResult(Base64Stream parent, byte[] buffer, int offset, int count, AsyncCallback callback, object state) : base(null,state,callback) { this.parent = parent; this.buffer = buffer; this.offset = offset; this.count = count; } bool CompleteRead(IAsyncResult result) { this.read = this.parent.BaseStream.EndRead(result); // if the underlying stream returns 0 then there // is no more data - ust return 0. if (read == 0) { InvokeCallback(); return true; } // while decoding, we may end up not having // any bytes to return pending additional data // from the underlying stream. this.read = this.parent.DecodeBytes(this.buffer, this.offset, this.read); if (this.read > 0) { InvokeCallback(); return true; } return false; } internal void Read() { for (;;) { IAsyncResult result = this.parent.BaseStream.BeginRead(this.buffer, this.offset, this.count, onRead, this); if (!result.CompletedSynchronously || CompleteRead(result)) break; } } static void OnRead(IAsyncResult result) { if (!result.CompletedSynchronously) { ReadAsyncResult thisPtr = (ReadAsyncResult)result.AsyncState; try { if (!thisPtr.CompleteRead(result)) thisPtr.Read(); } catch (Exception e) { if (thisPtr.IsCompleted) throw; thisPtr.InvokeCallback(e); } } } internal static int End(IAsyncResult result) { ReadAsyncResult thisPtr = (ReadAsyncResult)result; thisPtr.InternalWaitForCompletion(); return thisPtr.read; } } class WriteAsyncResult : LazyAsyncResult { Base64Stream parent; byte[] buffer; int offset; int count; static AsyncCallback onWrite = new AsyncCallback(OnWrite); int written; internal WriteAsyncResult(Base64Stream parent, byte[] buffer, int offset, int count, AsyncCallback callback, object state) : base(null, state, callback) { this.parent = parent; this.buffer = buffer; this.offset = offset; this.count = count; } internal void Write() { for (;;) { // do not append a space when writing from a stream since this means // it's writing the email body this.written += this.parent.EncodeBytes(this.buffer, this.offset + this.written, this.count - this.written, false, false); if (this.written < this.count) { IAsyncResult result = this.parent.BaseStream.BeginWrite(this.parent.WriteState.Buffer, 0, this.parent.WriteState.Length, onWrite, this); if (!result.CompletedSynchronously) break; CompleteWrite(result); } else { InvokeCallback(); break; } } } void CompleteWrite(IAsyncResult result) { this.parent.BaseStream.EndWrite(result); this.parent.WriteState.Length = 0; } static void OnWrite(IAsyncResult result) { if (!result.CompletedSynchronously) { WriteAsyncResult thisPtr = (WriteAsyncResult)result.AsyncState; try { thisPtr.CompleteWrite(result); thisPtr.Write(); } catch (Exception e) { if (thisPtr.IsCompleted) throw; thisPtr.InvokeCallback(e); } } } internal static void End(IAsyncResult result) { WriteAsyncResult thisPtr = (WriteAsyncResult)result; thisPtr.InternalWaitForCompletion(); Debug.Assert(thisPtr.written == thisPtr.count); } } class ReadStateInfo { byte val; byte pos; internal byte Val { get { return this.val; } set { this.val = value; } } internal byte Pos { get { return this.pos; } set { this.pos = value; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- GeneralTransform.cs
- OleDbWrapper.cs
- LinkLabelLinkClickedEvent.cs
- Bitmap.cs
- XmlValueConverter.cs
- PageCodeDomTreeGenerator.cs
- CharacterMetricsDictionary.cs
- DbConnectionPoolOptions.cs
- XmlAnyElementAttributes.cs
- GridEntryCollection.cs
- SymbolType.cs
- WindowsGraphicsWrapper.cs
- ToolStripMenuItemCodeDomSerializer.cs
- DataGridComponentEditor.cs
- AgileSafeNativeMemoryHandle.cs
- HtmlControlDesigner.cs
- AsyncResult.cs
- OletxCommittableTransaction.cs
- BitmapSizeOptions.cs
- LinqDataSourceHelper.cs
- WebPartsSection.cs
- ContactManager.cs
- BrowserCapabilitiesCompiler.cs
- HttpCacheParams.cs
- DataGridColumn.cs
- UpdatePanel.cs
- UrlAuthFailureHandler.cs
- Subtree.cs
- _NetworkingPerfCounters.cs
- AuthenticationService.cs
- MenuScrollingVisibilityConverter.cs
- PersonalizableTypeEntry.cs
- ResourceWriter.cs
- FormViewDeletedEventArgs.cs
- DayRenderEvent.cs
- DataBoundControlAdapter.cs
- GridViewHeaderRowPresenter.cs
- ValuePatternIdentifiers.cs
- SplineKeyFrames.cs
- UiaCoreTypesApi.cs
- DriveInfo.cs
- GroupBoxRenderer.cs
- PolicyChain.cs
- UnsafeNativeMethods.cs
- DataControlHelper.cs
- LinkConverter.cs
- ReturnEventArgs.cs
- DefaultTextStoreTextComposition.cs
- ToolStripSeparator.cs
- SapiRecoContext.cs
- FlowchartStart.xaml.cs
- LinqToSqlWrapper.cs
- GACIdentityPermission.cs
- MetadataItemCollectionFactory.cs
- WindowsBrush.cs
- SqlSupersetValidator.cs
- CallSiteHelpers.cs
- CapacityStreamGeometryContext.cs
- ResourceExpression.cs
- LineBreakRecord.cs
- ProjectionCamera.cs
- PartialCachingAttribute.cs
- Section.cs
- FrameworkContentElementAutomationPeer.cs
- DetailsViewPageEventArgs.cs
- HtmlHead.cs
- SiteMapNodeCollection.cs
- ImageIndexConverter.cs
- CreateParams.cs
- RemotingConfigParser.cs
- _ScatterGatherBuffers.cs
- ToolBar.cs
- SortedDictionary.cs
- WebContentFormatHelper.cs
- IdnMapping.cs
- RNGCryptoServiceProvider.cs
- Attributes.cs
- InheritedPropertyChangedEventArgs.cs
- InputLanguageCollection.cs
- DateTimeOffset.cs
- ProxyGenerator.cs
- ReadOnlyDictionary.cs
- BindingManagerDataErrorEventArgs.cs
- FunctionImportElement.cs
- AdRotatorDesigner.cs
- ExpandSegmentCollection.cs
- BindToObject.cs
- _PooledStream.cs
- PathGeometry.cs
- GradientStopCollection.cs
- FixedPage.cs
- XmlSchemaException.cs
- CultureSpecificCharacterBufferRange.cs
- FileStream.cs
- SchemaImporterExtension.cs
- BinaryConverter.cs
- MergePropertyDescriptor.cs
- StretchValidation.cs
- ClientRolePrincipal.cs
- CellTreeSimplifier.cs