SQLBytes.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Data / System / Data / SQLTypes / SQLBytes.cs / 1 / SQLBytes.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
//  																
// junfang 
// [....]
// [....] 
//----------------------------------------------------------------------------- 

//************************************************************************* 
// @File: SqlBytes.cs
// @Owner: junfang
//
// Created by:	JunFang 
//
// Description: Class SqlBytes is used to represent a binary/varbinary/image 
//		data from SQL Server. It contains a byte array buffer, which can 
//		be refilled. For example, in data access, user could use one instance
//		of sqlbytes to bind to a binary column, and we will just keep copying 
//		the data into the same instance, and avoid allocation per row.
//		It is also used to construct a UDT from on-disk binary value.
//
// Notes: 
//	
// History: 
// 
//     @Version: Yukon
//     120214 JXF  09/23/02 SqlBytes/SqlChars class indexer 
//     112296 AZA  07/06/02 Seal SqlAccess classes.
//     107151 AZA  04/18/02 Track byte array buffer as well as SqlBytes in
//                          sqlaccess.
//     107216 JXF  04/17/02 Bug 514927 
//     106854 JXF  04/15/02 Fix http suites due to SqlChars
//     106448 JXF  04/12/02 Bugs on sqlchars 
//     106242 JXF  04/09/02 Bugs on SqlBytes/SqlChars 
//     105715 JXF  04/05/02 Handle NULL properly in SqlBytes.SetLength
//     91128 JXF  10/17/01 Make SqlBytes not unsafe 
//
//   04/20/01  JunFang	Created.
//
// @EndHeader@ 
//*************************************************************************
 
namespace System.Data.SqlTypes { 
    using System;
 	using System.Diagnostics; 
    using System.Data.Common;
    using System.Data.Sql;
    using System.Data.SqlClient;
	using System.Data.SqlTypes; 
	using System.IO;
	using System.Runtime.InteropServices; 
 	using System.Runtime.Serialization; 
	using System.Security.Permissions;
 	using System.Xml; 
 	using System.Xml.Schema;
	using System.Xml.Serialization;

 	[Serializable] 
	internal enum SqlBytesCharsState {
		Null = 0, 
		Buffer = 1, 
 		//IntPtr = 2,
		Stream = 3, 
#if WINFSFunctionality
 		Delayed = 4
#endif
 	} 

	[Serializable,XmlSchemaProvider("GetXsdType")] 
    public sealed class SqlBytes : System.Data.SqlTypes.INullable, IXmlSerializable, ISerializable { 
 		// --------------------------------------------------------------
		//	  Data members 
		// -------------------------------------------------------------

		// SqlBytes has five possible states
 		// 1) SqlBytes is Null 
		//		- m_pbData, and m_stream must be null, m_lCuLen must be x_lNull.
 		// 2) SqlBytes contains a valid buffer, 
 		//		- m_rgbBuf must not be null, m_pbData and m_stream must be null 
		// 3) SqlBytes contains a valid pointer
 		//		- m_pbData must not be null, m_rgbBuf could be null or not, 
		//			if not null, content is garbage, should never look into it.
		//      - m_stream must be null.
		// 4) SqlBytes contains a Stream
 		//      - m_stream must not be null 
		//      - m_rgbBuf could be null or not. if not null, content is garbage, should never look into it.
 		//      - m_pbData must be null. 
 		//		- m_lCurLen must be x_lNull. 
		// 5) SqlBytes contains a Lazy Materialized Blob (ie, StorageState.Delayed)
 		// 
		internal byte[]	            m_rgbBuf;	// Data buffer
		private  long	            m_lCurLen;	// Current data length
#pragma warning disable 169
        // this field is no longer used, hence the warning was disabled 
        // however, it can not be removed or it will break serialization with pre-release builds of V2.0
		private  IntPtr	            m_pbData;	// Pointer to data in unmanaged memory. We don't own this memory, should never free 
#pragma warning restore 169 
 		internal Stream             m_stream;
		private  SqlBytesCharsState m_state; 

 		private  byte[]	            m_rgbWorkBuf;	// A 1-byte work buffer.

 		// The max data length that we support at this time. 
		private  const long x_lMaxLen = (long)System.Int32.MaxValue;
 
 		private  const long x_lNull = -1L; 

		// -------------------------------------------------------------- 
		//	  Constructor(s)
		// --------------------------------------------------------------

 		// Public default constructor used for XML serialization 
		public SqlBytes() {
 			SetNull(); 
 		} 

		// Create a SqlBytes with an in-memory buffer 
 		public SqlBytes(byte[] buffer) {
			m_rgbBuf = buffer;
			m_stream = null;
			if (m_rgbBuf == null) { 
 				m_state = SqlBytesCharsState.Null;
				m_lCurLen = x_lNull; 
            } 
 			else {
 				m_state = SqlBytesCharsState.Buffer; 
				m_lCurLen = (long)m_rgbBuf.Length;
            }

 			m_rgbWorkBuf = null; 

			AssertValid(); 
		} 

		// Create a SqlBytes from a SqlBinary 
 		public SqlBytes(SqlBinary value) : this(value.IsNull ? (byte[])null : value.Value)	{
        }

		public SqlBytes(Stream s) { 
    		// Create a SqlBytes from a Stream
 			m_rgbBuf = null; 
 			m_lCurLen = x_lNull; 
			m_stream = s;
 			m_state = (s == null) ? SqlBytesCharsState.Null : SqlBytesCharsState.Stream; 

			m_rgbWorkBuf = null;

			AssertValid(); 
        }
 
#if WINFSFunctionality 
        // Internal constructor to be called by UdtExtensions.dll for LazyMat
        internal SqlBytes(byte[] cookie, bool lazyMat) : this(cookie) { 
            Debug.Assert(lazyMat, "FAILURE - lazyMat argument should not be false!");
            m_state = SqlBytesCharsState.Delayed;
        }
#endif 

		// Constructor required for serialization. Deserializes as a Buffer. If the bits have been tampered with 
 		// then this will throw a SerializationException or a InvalidCastException. 
		private SqlBytes(SerializationInfo info, StreamingContext context)
 			{ 
 			m_stream = null;
			m_rgbWorkBuf = null;

 			if (info.GetBoolean("IsNull")) 
				{
				m_state = SqlBytesCharsState.Null; 
				m_rgbBuf = null; 
 				}
			else 
 				{
 				m_state = SqlBytesCharsState.Buffer;
				m_rgbBuf = (byte[]) info.GetValue("data", typeof(byte[]));
 				m_lCurLen = m_rgbBuf.Length; 
				}
 
			AssertValid(); 
			}
 

 		// -------------------------------------------------------------
		//	  Public properties
 		// -------------------------------------------------------------- 

#if WINFSFunctionality 
 
#if WINFSInternalOnly
        internal 
#else
        public
#endif
        bool IsFilled { 
            get {
                return (m_state != SqlBytesCharsState.Delayed); 
            } 
        }
#endif 

 		// INullable
		public bool IsNull {
 			get { 
#if WINFSFunctionality
				AssertFilled(); 
#endif 
				return m_state == SqlBytesCharsState.Null;
			} 
 		}

		// Property: the in-memory buffer of SqlBytes
 		//		Return Buffer even if SqlBytes is Null. 
 		public byte[] Buffer {
			get { 
#if WINFSFunctionality 
 				AssertFilled();
#endif 
				if (FStream())	{
					CopyStreamToBuffer();
				}
 				return m_rgbBuf; 
			}
 		} 
 
 		// Property: the actual length of the data
		public long Length { 
 			get {
#if WINFSFunctionality
				AssertFilled();
#endif 
				switch (m_state) {
					case SqlBytesCharsState.Null: 
                        throw new SqlNullValueException(); 

 					case SqlBytesCharsState.Stream: 
						return m_stream.Length;

 					default:
 						return m_lCurLen; 
				}
 			} 
		} 

		// Property: the max length of the data 
		//		Return MaxLength even if SqlBytes is Null.
 		//		When the buffer is also null, return -1.
		//		If containing a Stream, return -1.
 		public long MaxLength { 
 			get {
#if WINFSFunctionality 
				AssertFilled(); 
#endif
 				switch (m_state) { 
					case SqlBytesCharsState.Stream:
						return -1L;

					default: 
 						return (m_rgbBuf == null) ? -1L : (long)m_rgbBuf.Length;
                } 
            } 
        }
 
		// Property: get a copy of the data in a new byte[] array.
 		public byte[] Value {
 			get {
#if WINFSFunctionality 
				AssertFilled();
#endif 
 				byte[] buffer; 

				switch (m_state) { 
					case SqlBytesCharsState.Null:
						throw new SqlNullValueException();

 					case SqlBytesCharsState.Stream: 
						if (m_stream.Length > x_lMaxLen)
                                            throw new SqlTypeException(Res.GetString(Res.SqlMisc_BufferInsufficientMessage)); 
 						buffer = new byte[m_stream.Length]; 
 						if (m_stream.Position != 0)
							m_stream.Seek(0, SeekOrigin.Begin); 
 						m_stream.Read(buffer, 0, checked((int)m_stream.Length));
						break;

					default: 
						buffer = new byte[m_lCurLen];
 						Array.Copy(m_rgbBuf, buffer, (int)m_lCurLen); 
						break; 
                }
 
 				return buffer;
            }
        }
 
 		// class indexer
		public byte this[long offset] { 
 			get { 
#if WINFSFunctionality
				AssertFilled(); 
#endif
                if (offset < 0 || offset >= this.Length)
                    throw new ArgumentOutOfRangeException("offset");
 
                if (m_rgbWorkBuf == null)
					m_rgbWorkBuf = new byte[1]; 
 
                Read(offset, m_rgbWorkBuf, 0, 1);
				return m_rgbWorkBuf[0]; 
            }
 			set {
#if WINFSFunctionality
				AssertFilled(); 
#endif
 				if (m_rgbWorkBuf == null) 
 					m_rgbWorkBuf = new byte[1]; 
				m_rgbWorkBuf[0] = value;
 				Write(offset, m_rgbWorkBuf, 0, 1); 
            }
        }

		public StorageState Storage { 
			get {
#if WINFSFunctionality 
				AssertFilled(); 
#endif
 				switch (m_state) { 
					case SqlBytesCharsState.Null:
 						throw new SqlNullValueException();
 					case SqlBytesCharsState.Stream:
					    return StorageState.Stream; 

 					case SqlBytesCharsState.Buffer: 
					    return StorageState.Buffer; 

#if WINFSFunctionality 
					case SqlBytesCharsState.Delayed:
					    return StorageState.Delayed;
#endif
 
 					default:
					    return StorageState.UnmanagedBuffer; 
 				} 
 			}
		} 

        public Stream Stream {
            get {
#if WINFSFunctionality 
                AssertFilled();
#endif 
    			return FStream() ? m_stream : new StreamOnSqlBytes(this); 
            }
            set { 
    			m_lCurLen = x_lNull;
    			m_stream = value;
    			m_state = (value == null) ? SqlBytesCharsState.Null : SqlBytesCharsState.Stream;
    			AssertValid(); 
            }
        } 
 
 		// -------------------------------------------------------------
		//	  Public methods 
		// -------------------------------------------------------------

#if WINFSFunctionality
 
#if WINFSInternalOnly
        internal 
#else 
        public
#endif 
        void Fill(SqlConnection connection) {
            Fill(connection, null);
        }
 
        internal void Fill(SqlConnection connection, SqlTransaction transaction) {
            AssertNotFilled(); 
 
            Object result = SQLUtility.GetLOBFromCookie(m_rgbBuf, connection, transaction);
            m_rgbBuf = null; 

            if ((result == null) || (result is DBNull))
                SetNull();
            else 
                SetBuffer((byte[])result);
        } 
#endif 

		public void SetNull() { 
#if WINFSFunctionality
    		// Clear the buffer only if it was a cookie.
    		if (!IsFilled)
    			m_rgbBuf = null; 
#endif
    		m_lCurLen = x_lNull; 
    		m_stream = null; 
    		m_state = SqlBytesCharsState.Null;
 
    		AssertValid();
 		}

		// Set the current length of the data 
 		// If the SqlBytes is Null, setLength will make it non-Null.
 		public void SetLength(long value) { 
#if WINFSFunctionality 
			AssertFilled();
#endif 

 			if (value < 0)
				throw new ArgumentOutOfRangeException("value");
 
			if (FStream()) {
				m_stream.SetLength(value); 
 			} 
			else {
 				// If there is a buffer, even the value of SqlBytes is Null, 
 				// still allow setting length to zero, which will make it not Null.
				// If the buffer is null, raise exception
 				//
				if (null == m_rgbBuf) 
                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_NoBufferMessage));
 
				if (value > (long)m_rgbBuf.Length) 
					throw new ArgumentOutOfRangeException("value");
 
 				else if (IsNull)
					// At this point we know that value is small enough
 					// Go back in buffer mode
 					m_state = SqlBytesCharsState.Buffer; 

				m_lCurLen = value; 
            } 

 			AssertValid(); 
        }

		// Read data of specified length from specified offset into a buffer
		public long Read(long offset, byte[] buffer, int offsetInBuffer, int count) { 
#if WINFSFunctionality
			AssertFilled(); 
#endif 

 			if (IsNull) 
                throw new SqlNullValueException();

			// Validate the arguments
 			if (buffer == null) 
 				throw new ArgumentNullException("buffer");
 
			if (offset > this.Length || offset < 0) 
 				throw new ArgumentOutOfRangeException("offset");
 
			if (offsetInBuffer > buffer.Length || offsetInBuffer < 0)
				throw new ArgumentOutOfRangeException("offsetInBuffer");

			if (count < 0 || count > buffer.Length - offsetInBuffer) 
 				throw new ArgumentOutOfRangeException("count");
 
			// Adjust count based on data length 
 			if (count > this.Length - offset)
 				count = (int)(this.Length - offset); 

			if (count != 0)	{
 				switch (m_state) {
                    case SqlBytesCharsState.Stream: 
						if (m_stream.Position != offset)
							m_stream.Seek(offset, SeekOrigin.Begin); 
						m_stream.Read(buffer, offsetInBuffer, count); 
 						break;
 
					default:
 						Array.Copy(m_rgbBuf, offset, buffer, offsetInBuffer, count);
 						break;
    			} 
			}
 			return count; 
		} 

		// Write data of specified length into the SqlBytes from specified offset 
		public void Write(long offset, byte[] buffer, int offsetInBuffer, int count) {
#if WINFSFunctionality
 			AssertFilled();
#endif 

			if (FStream()) { 
 				if (m_stream.Position != offset) 
 					m_stream.Seek(offset, SeekOrigin.Begin);
				m_stream.Write(buffer, offsetInBuffer, count); 
            }
 			else {
				// Validate the arguments
				if (buffer == null) 
					throw new ArgumentNullException("buffer");
 
 				if (m_rgbBuf == null) 
                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_NoBufferMessage));
 
				if (offset < 0)
 					throw new ArgumentOutOfRangeException("offset");
 				if (offset > m_rgbBuf.Length)
                                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_BufferInsufficientMessage)); 

				if (offsetInBuffer < 0 || offsetInBuffer > buffer.Length) 
 					throw new ArgumentOutOfRangeException("offsetInBuffer"); 

				if (count < 0 || count > buffer.Length - offsetInBuffer) 
					throw new ArgumentOutOfRangeException("count");

				if (count > m_rgbBuf.Length - offset)
                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_BufferInsufficientMessage)); 

 				if (IsNull) { 
					// If NULL and there is buffer inside, we only allow writing from 
 					// offset zero.
 					// 
					if (offset != 0)
                        throw new SqlTypeException(Res.GetString(Res.SqlMisc_WriteNonZeroOffsetOnNullMessage));

 					// treat as if our current length is zero. 
					// Note this has to be done after all inputs are validated, so that
					// we won't throw exception after this point. 
					// 
 					m_lCurLen = 0;
                    m_state = SqlBytesCharsState.Buffer; 
				}
 				else if (offset > m_lCurLen) {
 					// Don't allow writing from an offset that this larger than current length.
					// It would leave uninitialized data in the buffer. 
 					//
                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_WriteOffsetLargerThanLenMessage)); 
				} 

				if (count != 0)	{ 
					Array.Copy(buffer, offsetInBuffer, m_rgbBuf, offset, count);

 					// If the last position that has been written is after
					// the current data length, reset the length 
 					if (m_lCurLen < offset + count)
 						m_lCurLen = offset + count; 
				} 
 			}
 
    		AssertValid();
		}

		public SqlBinary ToSqlBinary() { 
#if WINFSFunctionality
			AssertFilled(); 
#endif 
 			return IsNull ? SqlBinary.Null : new SqlBinary(Value);
		} 

 		// -------------------------------------------------------------
 		//	  Conversion operators
		// -------------------------------------------------------------- 

 		// Alternative method: ToSqlBinary() 
		public static explicit operator SqlBinary(SqlBytes value) { 
			return value.ToSqlBinary();
		} 

 		// Alternative method: constructor SqlBytes(SqlBinary)
		public static explicit operator SqlBytes(SqlBinary value) {
 			return new SqlBytes(value); 
 		}
 
		// ------------------------------------------------------------- 
 		//	  Private utility functions
		// -------------------------------------------------------------- 

		[System.Diagnostics.Conditional("DEBUG")]
		private void AssertValid() {
    		Debug.Assert(m_state >= SqlBytesCharsState.Null && m_state <= SqlBytesCharsState.Stream); 

 			if (IsNull) { 
			} 
 			else {
 				Debug.Assert((m_lCurLen >= 0 && m_lCurLen <= x_lMaxLen) || FStream()); 
				Debug.Assert(FStream() || (m_rgbBuf != null && m_lCurLen <= m_rgbBuf.Length));
 				Debug.Assert(!FStream() || (m_lCurLen == x_lNull));
			}
			Debug.Assert(m_rgbWorkBuf == null || m_rgbWorkBuf.Length == 1); 
		}
 
#if WINFSFunctionality 
 		// User is not allowed to use any methods until this SqlBytes has been filled
		// except Fill() 
 		private void AssertFilled() {
 			if (!IsFilled)
				throw new SqlNotFilledException();
 		} 

        private void AssertNotFilled() { 
            if (IsFilled) 
                throw new SqlAlreadyFilledException();
        } 

        internal byte[] Cookie {
            get {
                Debug.Assert(!IsFilled, "Unexpected state on Cookie getter!"); 
                return m_rgbBuf;
            } 
        } 
#endif
 
		// Copy the data from the Stream to the array buffer.
		// If the SqlBytes doesn't hold a buffer or the buffer
		// is not big enough, allocate new byte array.
 		private void CopyStreamToBuffer() { 
			Debug.Assert(FStream());
 
 			long lStreamLen = m_stream.Length; 
 			if (lStreamLen >= x_lMaxLen)
                           throw new SqlTypeException(Res.GetString(Res.SqlMisc_WriteOffsetLargerThanLenMessage)); 

			if (m_rgbBuf == null || m_rgbBuf.Length < lStreamLen)
 				m_rgbBuf = new byte[lStreamLen];
 
			if (m_stream.Position != 0)
				m_stream.Seek(0, SeekOrigin.Begin); 
 
			m_stream.Read(m_rgbBuf, 0, (int)lStreamLen);
 			m_stream = null; 
			m_lCurLen = lStreamLen;
 			m_state = SqlBytesCharsState.Buffer;

 			AssertValid(); 
        }
 
		// whether the SqlBytes contains a pointer 
 		// whether the SqlBytes contains a Stream
		internal bool FStream()	{ 
			return m_state == SqlBytesCharsState.Stream;
        }

		private void SetBuffer(byte[] buffer) { 
 			m_rgbBuf = buffer;
			m_lCurLen = (m_rgbBuf == null) ? x_lNull : (long)m_rgbBuf.Length; 
 			m_stream = null; 
 			m_state = (m_rgbBuf == null) ? SqlBytesCharsState.Null : SqlBytesCharsState.Buffer;
 
			AssertValid();
        }

 		// -------------------------------------------------------------- 
		// 		XML Serialization
		// ------------------------------------------------------------- 
 
		XmlSchema IXmlSerializable.GetSchema() {
 			return null; 
        }
		
 		void IXmlSerializable.ReadXml(XmlReader r) {
#if WINFSFunctionality 
 			AssertFilled();
#endif 
			byte[] value = null; 
 			
			string isNull = r.GetAttribute("nil", XmlSchema.InstanceNamespace); 
			
			if (isNull != null && XmlConvert.ToBoolean(isNull)) {
 				SetNull();
			} 
 			else {
 				string base64 = r.ReadElementString(); 
				if (base64 == null) { 
 					value = new byte[0];
				} 
				else {
					base64 = base64.Trim();
 					if (base64.Length == 0)
						value = new byte[0]; 
 					else
 						value = Convert.FromBase64String(base64); 
				} 
 			}
			 
            SetBuffer(value);
		}

		void IXmlSerializable.WriteXml(XmlWriter writer) { 
#if WINFSFunctionality
 			AssertFilled(); 
#endif 
			if (IsNull) {
 				writer.WriteAttributeString("xsi", "nil", XmlSchema.InstanceNamespace, "true"); 
 			}
			else {
 				byte[] value = this.Buffer;
				writer.WriteString(Convert.ToBase64String(value, 0, (int)(this.Length))); 
            }
        } 
 
		public static XmlQualifiedName GetXsdType(XmlSchemaSet schemaSet) {
			return new XmlQualifiedName("base64Binary", XmlSchema.Namespace); 
 		}


		// -------------------------------------------------------------- 
 		// 		Serialization using ISerializable
 		// ------------------------------------------------------------- 
 
		// State information is not saved. The current state is converted to Buffer and only the underlying
 		// array is serialized, except for Null, in which case this state is kept. 
		[SecurityPermissionAttribute(SecurityAction.LinkDemand,SerializationFormatter=true)]
		void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
			{
#if WINFSFunctionality 
 			AssertFilled();
#endif 
 
			switch (m_state)
 				{ 
 				case SqlBytesCharsState.Null:
					info.AddValue("IsNull", true);
 					break;
 
				case SqlBytesCharsState.Buffer:
					info.AddValue("IsNull", false); 
					info.AddValue("data", m_rgbBuf); 
 					break;
 
				case SqlBytesCharsState.Stream:
 					CopyStreamToBuffer();
 					goto case SqlBytesCharsState.Buffer;
 
				default:
 					Debug.Assert(false); 
					goto case SqlBytesCharsState.Null; 
					
				} 
 			}

		// -------------------------------------------------------------
 		//	  Static fields, properties 
 		// -------------------------------------------------------------
 
		// Get a Null instance. 
 		// Since SqlBytes is mutable, have to be property and create a new one each time.
		public static SqlBytes Null { 
			get	{
				return new SqlBytes((byte[])null);
 			}
		} 
 	} // class SqlBytes
 
 	// StreamOnSqlBytes is a stream build on top of SqlBytes, and 
	// provides the Stream interface. The purpose is to help users
 	// to read/write SqlBytes object. After getting the stream from 
	// SqlBytes, users could create a BinaryReader/BinaryWriter object
	// to easily read and write primitive types.
	internal sealed class StreamOnSqlBytes : Stream
 		{ 
		// --------------------------------------------------------------
 		//	  Data members 
 		// ------------------------------------------------------------- 

		private SqlBytes	m_sb;		// the SqlBytes object 
 		private long		m_lPosition;

		// --------------------------------------------------------------
		//	  Constructor(s) 
		// --------------------------------------------------------------
 
 		internal StreamOnSqlBytes(SqlBytes sb) { 
			m_sb = sb;
 			m_lPosition = 0; 
 		}

		// -------------------------------------------------------------
 		//	  Public properties 
		// --------------------------------------------------------------
 
		// Always can read/write/seek, unless sb is null, 
		// which means the stream has been closed.
 
 		public override bool CanRead {
			get	{
 				return m_sb != null && !m_sb.IsNull;
 			} 
		}
 
 		public override bool CanSeek { 
			get {
				return m_sb != null; 
			}
 		}

		public override bool CanWrite { 
 			get	{
 				return m_sb != null && (!m_sb.IsNull || m_sb.m_rgbBuf != null); 
			} 
 		}
 
		public override long Length	{
			get	{
    			CheckIfStreamClosed("get_Length");
	    		return m_sb.Length; 
            }
        } 
 
 		public override long Position {
			get	{ 
 				CheckIfStreamClosed("get_Position");
 				return m_lPosition;
			}
 			set	{ 
				CheckIfStreamClosed("set_Position");
				if (value < 0 || value > m_sb.Length) 
					throw new ArgumentOutOfRangeException("value"); 
 				else
					m_lPosition = value; 
 			}
 		}

		// ------------------------------------------------------------- 
 		//	  Public methods
		// ------------------------------------------------------------- 
 
		public override long Seek(long offset, SeekOrigin origin) {
			CheckIfStreamClosed("Seek"); 

 			long lPosition = 0;

			switch(origin) { 
 				case SeekOrigin.Begin:
 					if (offset < 0 || offset > m_sb.Length) 
						throw new ArgumentOutOfRangeException("offset"); 
 					m_lPosition = offset;
					break; 
					
				case SeekOrigin.Current:
 					lPosition = m_lPosition + offset;
					if (lPosition < 0 || lPosition > m_sb.Length) 
 						throw new ArgumentOutOfRangeException("offset");
 					m_lPosition = lPosition; 
					break; 
 					
				case SeekOrigin.End: 
					lPosition = m_sb.Length + offset;
					if (lPosition < 0 || lPosition > m_sb.Length)
 						throw new ArgumentOutOfRangeException("offset");
					m_lPosition = lPosition; 
 					break;
 					 
				default: 
                                throw ADP.InvalidSeekOrigin("offset");
 			} 

			return m_lPosition;
		}
 
		// The Read/Write/ReadByte/WriteByte simply delegates to SqlBytes
 		public override int Read(byte[] buffer, int offset, int count) { 
			CheckIfStreamClosed("Read"); 

 			if (buffer==null) 
 				throw new ArgumentNullException("buffer");
			if (offset < 0 || offset > buffer.Length)
 				throw new ArgumentOutOfRangeException("offset");
			if (count < 0 || count > buffer.Length - offset) 
				throw new ArgumentOutOfRangeException("count");
 
			int iBytesRead = (int)m_sb.Read(m_lPosition, buffer, offset, count); 
 			m_lPosition += iBytesRead;
 
			return iBytesRead;
 		}

 		public override void Write(byte[] buffer, int offset, int count) { 
			CheckIfStreamClosed("Write");
 
 			if (buffer==null) 
				throw new ArgumentNullException("buffer");
			if (offset < 0 || offset > buffer.Length) 
				throw new ArgumentOutOfRangeException("offset");
 			if (count < 0 || count > buffer.Length - offset)
				throw new ArgumentOutOfRangeException("count");
 
 			m_sb.Write(m_lPosition, buffer, offset, count);
 			m_lPosition += count; 
		} 

 		public override int ReadByte() { 
			CheckIfStreamClosed("ReadByte");

			// If at the end of stream, return -1, rather than call SqlBytes.ReadByte,
			// which will throw exception. This is the behavior for Stream. 
 			//
			if (m_lPosition >= m_sb.Length) 
 				return -1; 

 			int ret = m_sb[m_lPosition]; 
			m_lPosition ++;
 			return ret;
		}
 
		public override void WriteByte(byte value) {
			CheckIfStreamClosed("WriteByte"); 
 
 			m_sb[m_lPosition] = value;
			m_lPosition ++; 
 		}

 		public override void SetLength(long value) {
			CheckIfStreamClosed("SetLength"); 

 			m_sb.SetLength(value); 
			if (m_lPosition > value) 
				m_lPosition = value;
		} 

 		// Flush is a no-op for stream on SqlBytes, because they are all in memory
		public override void Flush() {
 			if (m_sb.FStream()) 
 				m_sb.m_stream.Flush();
		} 
 
 		protected override void Dispose(bool disposing) {
			// When m_sb is null, it means the stream has been closed, and 
			// any opearation in the future should fail.
			// This is the only case that m_sb is null.
            try {
 			m_sb = null; 
		}
            finally { 
                base.Dispose(disposing); 
            }
 		} 

 		// -------------------------------------------------------------
		//	  Private utility functions
 		// -------------------------------------------------------------- 

		private bool FClosed() { 
			return m_sb == null; 
		}
 
        private void CheckIfStreamClosed(string methodname) {
 			if (FClosed())
                throw ADP.StreamClosed(methodname);
        } 
    } // class StreamOnSqlBytes
} // namespace System.Data.SqlTypes 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
//  																
// junfang 
// [....]
// [....] 
//----------------------------------------------------------------------------- 

//************************************************************************* 
// @File: SqlBytes.cs
// @Owner: junfang
//
// Created by:	JunFang 
//
// Description: Class SqlBytes is used to represent a binary/varbinary/image 
//		data from SQL Server. It contains a byte array buffer, which can 
//		be refilled. For example, in data access, user could use one instance
//		of sqlbytes to bind to a binary column, and we will just keep copying 
//		the data into the same instance, and avoid allocation per row.
//		It is also used to construct a UDT from on-disk binary value.
//
// Notes: 
//	
// History: 
// 
//     @Version: Yukon
//     120214 JXF  09/23/02 SqlBytes/SqlChars class indexer 
//     112296 AZA  07/06/02 Seal SqlAccess classes.
//     107151 AZA  04/18/02 Track byte array buffer as well as SqlBytes in
//                          sqlaccess.
//     107216 JXF  04/17/02 Bug 514927 
//     106854 JXF  04/15/02 Fix http suites due to SqlChars
//     106448 JXF  04/12/02 Bugs on sqlchars 
//     106242 JXF  04/09/02 Bugs on SqlBytes/SqlChars 
//     105715 JXF  04/05/02 Handle NULL properly in SqlBytes.SetLength
//     91128 JXF  10/17/01 Make SqlBytes not unsafe 
//
//   04/20/01  JunFang	Created.
//
// @EndHeader@ 
//*************************************************************************
 
namespace System.Data.SqlTypes { 
    using System;
 	using System.Diagnostics; 
    using System.Data.Common;
    using System.Data.Sql;
    using System.Data.SqlClient;
	using System.Data.SqlTypes; 
	using System.IO;
	using System.Runtime.InteropServices; 
 	using System.Runtime.Serialization; 
	using System.Security.Permissions;
 	using System.Xml; 
 	using System.Xml.Schema;
	using System.Xml.Serialization;

 	[Serializable] 
	internal enum SqlBytesCharsState {
		Null = 0, 
		Buffer = 1, 
 		//IntPtr = 2,
		Stream = 3, 
#if WINFSFunctionality
 		Delayed = 4
#endif
 	} 

	[Serializable,XmlSchemaProvider("GetXsdType")] 
    public sealed class SqlBytes : System.Data.SqlTypes.INullable, IXmlSerializable, ISerializable { 
 		// --------------------------------------------------------------
		//	  Data members 
		// -------------------------------------------------------------

		// SqlBytes has five possible states
 		// 1) SqlBytes is Null 
		//		- m_pbData, and m_stream must be null, m_lCuLen must be x_lNull.
 		// 2) SqlBytes contains a valid buffer, 
 		//		- m_rgbBuf must not be null, m_pbData and m_stream must be null 
		// 3) SqlBytes contains a valid pointer
 		//		- m_pbData must not be null, m_rgbBuf could be null or not, 
		//			if not null, content is garbage, should never look into it.
		//      - m_stream must be null.
		// 4) SqlBytes contains a Stream
 		//      - m_stream must not be null 
		//      - m_rgbBuf could be null or not. if not null, content is garbage, should never look into it.
 		//      - m_pbData must be null. 
 		//		- m_lCurLen must be x_lNull. 
		// 5) SqlBytes contains a Lazy Materialized Blob (ie, StorageState.Delayed)
 		// 
		internal byte[]	            m_rgbBuf;	// Data buffer
		private  long	            m_lCurLen;	// Current data length
#pragma warning disable 169
        // this field is no longer used, hence the warning was disabled 
        // however, it can not be removed or it will break serialization with pre-release builds of V2.0
		private  IntPtr	            m_pbData;	// Pointer to data in unmanaged memory. We don't own this memory, should never free 
#pragma warning restore 169 
 		internal Stream             m_stream;
		private  SqlBytesCharsState m_state; 

 		private  byte[]	            m_rgbWorkBuf;	// A 1-byte work buffer.

 		// The max data length that we support at this time. 
		private  const long x_lMaxLen = (long)System.Int32.MaxValue;
 
 		private  const long x_lNull = -1L; 

		// -------------------------------------------------------------- 
		//	  Constructor(s)
		// --------------------------------------------------------------

 		// Public default constructor used for XML serialization 
		public SqlBytes() {
 			SetNull(); 
 		} 

		// Create a SqlBytes with an in-memory buffer 
 		public SqlBytes(byte[] buffer) {
			m_rgbBuf = buffer;
			m_stream = null;
			if (m_rgbBuf == null) { 
 				m_state = SqlBytesCharsState.Null;
				m_lCurLen = x_lNull; 
            } 
 			else {
 				m_state = SqlBytesCharsState.Buffer; 
				m_lCurLen = (long)m_rgbBuf.Length;
            }

 			m_rgbWorkBuf = null; 

			AssertValid(); 
		} 

		// Create a SqlBytes from a SqlBinary 
 		public SqlBytes(SqlBinary value) : this(value.IsNull ? (byte[])null : value.Value)	{
        }

		public SqlBytes(Stream s) { 
    		// Create a SqlBytes from a Stream
 			m_rgbBuf = null; 
 			m_lCurLen = x_lNull; 
			m_stream = s;
 			m_state = (s == null) ? SqlBytesCharsState.Null : SqlBytesCharsState.Stream; 

			m_rgbWorkBuf = null;

			AssertValid(); 
        }
 
#if WINFSFunctionality 
        // Internal constructor to be called by UdtExtensions.dll for LazyMat
        internal SqlBytes(byte[] cookie, bool lazyMat) : this(cookie) { 
            Debug.Assert(lazyMat, "FAILURE - lazyMat argument should not be false!");
            m_state = SqlBytesCharsState.Delayed;
        }
#endif 

		// Constructor required for serialization. Deserializes as a Buffer. If the bits have been tampered with 
 		// then this will throw a SerializationException or a InvalidCastException. 
		private SqlBytes(SerializationInfo info, StreamingContext context)
 			{ 
 			m_stream = null;
			m_rgbWorkBuf = null;

 			if (info.GetBoolean("IsNull")) 
				{
				m_state = SqlBytesCharsState.Null; 
				m_rgbBuf = null; 
 				}
			else 
 				{
 				m_state = SqlBytesCharsState.Buffer;
				m_rgbBuf = (byte[]) info.GetValue("data", typeof(byte[]));
 				m_lCurLen = m_rgbBuf.Length; 
				}
 
			AssertValid(); 
			}
 

 		// -------------------------------------------------------------
		//	  Public properties
 		// -------------------------------------------------------------- 

#if WINFSFunctionality 
 
#if WINFSInternalOnly
        internal 
#else
        public
#endif
        bool IsFilled { 
            get {
                return (m_state != SqlBytesCharsState.Delayed); 
            } 
        }
#endif 

 		// INullable
		public bool IsNull {
 			get { 
#if WINFSFunctionality
				AssertFilled(); 
#endif 
				return m_state == SqlBytesCharsState.Null;
			} 
 		}

		// Property: the in-memory buffer of SqlBytes
 		//		Return Buffer even if SqlBytes is Null. 
 		public byte[] Buffer {
			get { 
#if WINFSFunctionality 
 				AssertFilled();
#endif 
				if (FStream())	{
					CopyStreamToBuffer();
				}
 				return m_rgbBuf; 
			}
 		} 
 
 		// Property: the actual length of the data
		public long Length { 
 			get {
#if WINFSFunctionality
				AssertFilled();
#endif 
				switch (m_state) {
					case SqlBytesCharsState.Null: 
                        throw new SqlNullValueException(); 

 					case SqlBytesCharsState.Stream: 
						return m_stream.Length;

 					default:
 						return m_lCurLen; 
				}
 			} 
		} 

		// Property: the max length of the data 
		//		Return MaxLength even if SqlBytes is Null.
 		//		When the buffer is also null, return -1.
		//		If containing a Stream, return -1.
 		public long MaxLength { 
 			get {
#if WINFSFunctionality 
				AssertFilled(); 
#endif
 				switch (m_state) { 
					case SqlBytesCharsState.Stream:
						return -1L;

					default: 
 						return (m_rgbBuf == null) ? -1L : (long)m_rgbBuf.Length;
                } 
            } 
        }
 
		// Property: get a copy of the data in a new byte[] array.
 		public byte[] Value {
 			get {
#if WINFSFunctionality 
				AssertFilled();
#endif 
 				byte[] buffer; 

				switch (m_state) { 
					case SqlBytesCharsState.Null:
						throw new SqlNullValueException();

 					case SqlBytesCharsState.Stream: 
						if (m_stream.Length > x_lMaxLen)
                                            throw new SqlTypeException(Res.GetString(Res.SqlMisc_BufferInsufficientMessage)); 
 						buffer = new byte[m_stream.Length]; 
 						if (m_stream.Position != 0)
							m_stream.Seek(0, SeekOrigin.Begin); 
 						m_stream.Read(buffer, 0, checked((int)m_stream.Length));
						break;

					default: 
						buffer = new byte[m_lCurLen];
 						Array.Copy(m_rgbBuf, buffer, (int)m_lCurLen); 
						break; 
                }
 
 				return buffer;
            }
        }
 
 		// class indexer
		public byte this[long offset] { 
 			get { 
#if WINFSFunctionality
				AssertFilled(); 
#endif
                if (offset < 0 || offset >= this.Length)
                    throw new ArgumentOutOfRangeException("offset");
 
                if (m_rgbWorkBuf == null)
					m_rgbWorkBuf = new byte[1]; 
 
                Read(offset, m_rgbWorkBuf, 0, 1);
				return m_rgbWorkBuf[0]; 
            }
 			set {
#if WINFSFunctionality
				AssertFilled(); 
#endif
 				if (m_rgbWorkBuf == null) 
 					m_rgbWorkBuf = new byte[1]; 
				m_rgbWorkBuf[0] = value;
 				Write(offset, m_rgbWorkBuf, 0, 1); 
            }
        }

		public StorageState Storage { 
			get {
#if WINFSFunctionality 
				AssertFilled(); 
#endif
 				switch (m_state) { 
					case SqlBytesCharsState.Null:
 						throw new SqlNullValueException();
 					case SqlBytesCharsState.Stream:
					    return StorageState.Stream; 

 					case SqlBytesCharsState.Buffer: 
					    return StorageState.Buffer; 

#if WINFSFunctionality 
					case SqlBytesCharsState.Delayed:
					    return StorageState.Delayed;
#endif
 
 					default:
					    return StorageState.UnmanagedBuffer; 
 				} 
 			}
		} 

        public Stream Stream {
            get {
#if WINFSFunctionality 
                AssertFilled();
#endif 
    			return FStream() ? m_stream : new StreamOnSqlBytes(this); 
            }
            set { 
    			m_lCurLen = x_lNull;
    			m_stream = value;
    			m_state = (value == null) ? SqlBytesCharsState.Null : SqlBytesCharsState.Stream;
    			AssertValid(); 
            }
        } 
 
 		// -------------------------------------------------------------
		//	  Public methods 
		// -------------------------------------------------------------

#if WINFSFunctionality
 
#if WINFSInternalOnly
        internal 
#else 
        public
#endif 
        void Fill(SqlConnection connection) {
            Fill(connection, null);
        }
 
        internal void Fill(SqlConnection connection, SqlTransaction transaction) {
            AssertNotFilled(); 
 
            Object result = SQLUtility.GetLOBFromCookie(m_rgbBuf, connection, transaction);
            m_rgbBuf = null; 

            if ((result == null) || (result is DBNull))
                SetNull();
            else 
                SetBuffer((byte[])result);
        } 
#endif 

		public void SetNull() { 
#if WINFSFunctionality
    		// Clear the buffer only if it was a cookie.
    		if (!IsFilled)
    			m_rgbBuf = null; 
#endif
    		m_lCurLen = x_lNull; 
    		m_stream = null; 
    		m_state = SqlBytesCharsState.Null;
 
    		AssertValid();
 		}

		// Set the current length of the data 
 		// If the SqlBytes is Null, setLength will make it non-Null.
 		public void SetLength(long value) { 
#if WINFSFunctionality 
			AssertFilled();
#endif 

 			if (value < 0)
				throw new ArgumentOutOfRangeException("value");
 
			if (FStream()) {
				m_stream.SetLength(value); 
 			} 
			else {
 				// If there is a buffer, even the value of SqlBytes is Null, 
 				// still allow setting length to zero, which will make it not Null.
				// If the buffer is null, raise exception
 				//
				if (null == m_rgbBuf) 
                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_NoBufferMessage));
 
				if (value > (long)m_rgbBuf.Length) 
					throw new ArgumentOutOfRangeException("value");
 
 				else if (IsNull)
					// At this point we know that value is small enough
 					// Go back in buffer mode
 					m_state = SqlBytesCharsState.Buffer; 

				m_lCurLen = value; 
            } 

 			AssertValid(); 
        }

		// Read data of specified length from specified offset into a buffer
		public long Read(long offset, byte[] buffer, int offsetInBuffer, int count) { 
#if WINFSFunctionality
			AssertFilled(); 
#endif 

 			if (IsNull) 
                throw new SqlNullValueException();

			// Validate the arguments
 			if (buffer == null) 
 				throw new ArgumentNullException("buffer");
 
			if (offset > this.Length || offset < 0) 
 				throw new ArgumentOutOfRangeException("offset");
 
			if (offsetInBuffer > buffer.Length || offsetInBuffer < 0)
				throw new ArgumentOutOfRangeException("offsetInBuffer");

			if (count < 0 || count > buffer.Length - offsetInBuffer) 
 				throw new ArgumentOutOfRangeException("count");
 
			// Adjust count based on data length 
 			if (count > this.Length - offset)
 				count = (int)(this.Length - offset); 

			if (count != 0)	{
 				switch (m_state) {
                    case SqlBytesCharsState.Stream: 
						if (m_stream.Position != offset)
							m_stream.Seek(offset, SeekOrigin.Begin); 
						m_stream.Read(buffer, offsetInBuffer, count); 
 						break;
 
					default:
 						Array.Copy(m_rgbBuf, offset, buffer, offsetInBuffer, count);
 						break;
    			} 
			}
 			return count; 
		} 

		// Write data of specified length into the SqlBytes from specified offset 
		public void Write(long offset, byte[] buffer, int offsetInBuffer, int count) {
#if WINFSFunctionality
 			AssertFilled();
#endif 

			if (FStream()) { 
 				if (m_stream.Position != offset) 
 					m_stream.Seek(offset, SeekOrigin.Begin);
				m_stream.Write(buffer, offsetInBuffer, count); 
            }
 			else {
				// Validate the arguments
				if (buffer == null) 
					throw new ArgumentNullException("buffer");
 
 				if (m_rgbBuf == null) 
                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_NoBufferMessage));
 
				if (offset < 0)
 					throw new ArgumentOutOfRangeException("offset");
 				if (offset > m_rgbBuf.Length)
                                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_BufferInsufficientMessage)); 

				if (offsetInBuffer < 0 || offsetInBuffer > buffer.Length) 
 					throw new ArgumentOutOfRangeException("offsetInBuffer"); 

				if (count < 0 || count > buffer.Length - offsetInBuffer) 
					throw new ArgumentOutOfRangeException("count");

				if (count > m_rgbBuf.Length - offset)
                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_BufferInsufficientMessage)); 

 				if (IsNull) { 
					// If NULL and there is buffer inside, we only allow writing from 
 					// offset zero.
 					// 
					if (offset != 0)
                        throw new SqlTypeException(Res.GetString(Res.SqlMisc_WriteNonZeroOffsetOnNullMessage));

 					// treat as if our current length is zero. 
					// Note this has to be done after all inputs are validated, so that
					// we won't throw exception after this point. 
					// 
 					m_lCurLen = 0;
                    m_state = SqlBytesCharsState.Buffer; 
				}
 				else if (offset > m_lCurLen) {
 					// Don't allow writing from an offset that this larger than current length.
					// It would leave uninitialized data in the buffer. 
 					//
                    throw new SqlTypeException(Res.GetString(Res.SqlMisc_WriteOffsetLargerThanLenMessage)); 
				} 

				if (count != 0)	{ 
					Array.Copy(buffer, offsetInBuffer, m_rgbBuf, offset, count);

 					// If the last position that has been written is after
					// the current data length, reset the length 
 					if (m_lCurLen < offset + count)
 						m_lCurLen = offset + count; 
				} 
 			}
 
    		AssertValid();
		}

		public SqlBinary ToSqlBinary() { 
#if WINFSFunctionality
			AssertFilled(); 
#endif 
 			return IsNull ? SqlBinary.Null : new SqlBinary(Value);
		} 

 		// -------------------------------------------------------------
 		//	  Conversion operators
		// -------------------------------------------------------------- 

 		// Alternative method: ToSqlBinary() 
		public static explicit operator SqlBinary(SqlBytes value) { 
			return value.ToSqlBinary();
		} 

 		// Alternative method: constructor SqlBytes(SqlBinary)
		public static explicit operator SqlBytes(SqlBinary value) {
 			return new SqlBytes(value); 
 		}
 
		// ------------------------------------------------------------- 
 		//	  Private utility functions
		// -------------------------------------------------------------- 

		[System.Diagnostics.Conditional("DEBUG")]
		private void AssertValid() {
    		Debug.Assert(m_state >= SqlBytesCharsState.Null && m_state <= SqlBytesCharsState.Stream); 

 			if (IsNull) { 
			} 
 			else {
 				Debug.Assert((m_lCurLen >= 0 && m_lCurLen <= x_lMaxLen) || FStream()); 
				Debug.Assert(FStream() || (m_rgbBuf != null && m_lCurLen <= m_rgbBuf.Length));
 				Debug.Assert(!FStream() || (m_lCurLen == x_lNull));
			}
			Debug.Assert(m_rgbWorkBuf == null || m_rgbWorkBuf.Length == 1); 
		}
 
#if WINFSFunctionality 
 		// User is not allowed to use any methods until this SqlBytes has been filled
		// except Fill() 
 		private void AssertFilled() {
 			if (!IsFilled)
				throw new SqlNotFilledException();
 		} 

        private void AssertNotFilled() { 
            if (IsFilled) 
                throw new SqlAlreadyFilledException();
        } 

        internal byte[] Cookie {
            get {
                Debug.Assert(!IsFilled, "Unexpected state on Cookie getter!"); 
                return m_rgbBuf;
            } 
        } 
#endif
 
		// Copy the data from the Stream to the array buffer.
		// If the SqlBytes doesn't hold a buffer or the buffer
		// is not big enough, allocate new byte array.
 		private void CopyStreamToBuffer() { 
			Debug.Assert(FStream());
 
 			long lStreamLen = m_stream.Length; 
 			if (lStreamLen >= x_lMaxLen)
                           throw new SqlTypeException(Res.GetString(Res.SqlMisc_WriteOffsetLargerThanLenMessage)); 

			if (m_rgbBuf == null || m_rgbBuf.Length < lStreamLen)
 				m_rgbBuf = new byte[lStreamLen];
 
			if (m_stream.Position != 0)
				m_stream.Seek(0, SeekOrigin.Begin); 
 
			m_stream.Read(m_rgbBuf, 0, (int)lStreamLen);
 			m_stream = null; 
			m_lCurLen = lStreamLen;
 			m_state = SqlBytesCharsState.Buffer;

 			AssertValid(); 
        }
 
		// whether the SqlBytes contains a pointer 
 		// whether the SqlBytes contains a Stream
		internal bool FStream()	{ 
			return m_state == SqlBytesCharsState.Stream;
        }

		private void SetBuffer(byte[] buffer) { 
 			m_rgbBuf = buffer;
			m_lCurLen = (m_rgbBuf == null) ? x_lNull : (long)m_rgbBuf.Length; 
 			m_stream = null; 
 			m_state = (m_rgbBuf == null) ? SqlBytesCharsState.Null : SqlBytesCharsState.Buffer;
 
			AssertValid();
        }

 		// -------------------------------------------------------------- 
		// 		XML Serialization
		// ------------------------------------------------------------- 
 
		XmlSchema IXmlSerializable.GetSchema() {
 			return null; 
        }
		
 		void IXmlSerializable.ReadXml(XmlReader r) {
#if WINFSFunctionality 
 			AssertFilled();
#endif 
			byte[] value = null; 
 			
			string isNull = r.GetAttribute("nil", XmlSchema.InstanceNamespace); 
			
			if (isNull != null && XmlConvert.ToBoolean(isNull)) {
 				SetNull();
			} 
 			else {
 				string base64 = r.ReadElementString(); 
				if (base64 == null) { 
 					value = new byte[0];
				} 
				else {
					base64 = base64.Trim();
 					if (base64.Length == 0)
						value = new byte[0]; 
 					else
 						value = Convert.FromBase64String(base64); 
				} 
 			}
			 
            SetBuffer(value);
		}

		void IXmlSerializable.WriteXml(XmlWriter writer) { 
#if WINFSFunctionality
 			AssertFilled(); 
#endif 
			if (IsNull) {
 				writer.WriteAttributeString("xsi", "nil", XmlSchema.InstanceNamespace, "true"); 
 			}
			else {
 				byte[] value = this.Buffer;
				writer.WriteString(Convert.ToBase64String(value, 0, (int)(this.Length))); 
            }
        } 
 
		public static XmlQualifiedName GetXsdType(XmlSchemaSet schemaSet) {
			return new XmlQualifiedName("base64Binary", XmlSchema.Namespace); 
 		}


		// -------------------------------------------------------------- 
 		// 		Serialization using ISerializable
 		// ------------------------------------------------------------- 
 
		// State information is not saved. The current state is converted to Buffer and only the underlying
 		// array is serialized, except for Null, in which case this state is kept. 
		[SecurityPermissionAttribute(SecurityAction.LinkDemand,SerializationFormatter=true)]
		void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
			{
#if WINFSFunctionality 
 			AssertFilled();
#endif 
 
			switch (m_state)
 				{ 
 				case SqlBytesCharsState.Null:
					info.AddValue("IsNull", true);
 					break;
 
				case SqlBytesCharsState.Buffer:
					info.AddValue("IsNull", false); 
					info.AddValue("data", m_rgbBuf); 
 					break;
 
				case SqlBytesCharsState.Stream:
 					CopyStreamToBuffer();
 					goto case SqlBytesCharsState.Buffer;
 
				default:
 					Debug.Assert(false); 
					goto case SqlBytesCharsState.Null; 
					
				} 
 			}

		// -------------------------------------------------------------
 		//	  Static fields, properties 
 		// -------------------------------------------------------------
 
		// Get a Null instance. 
 		// Since SqlBytes is mutable, have to be property and create a new one each time.
		public static SqlBytes Null { 
			get	{
				return new SqlBytes((byte[])null);
 			}
		} 
 	} // class SqlBytes
 
 	// StreamOnSqlBytes is a stream build on top of SqlBytes, and 
	// provides the Stream interface. The purpose is to help users
 	// to read/write SqlBytes object. After getting the stream from 
	// SqlBytes, users could create a BinaryReader/BinaryWriter object
	// to easily read and write primitive types.
	internal sealed class StreamOnSqlBytes : Stream
 		{ 
		// --------------------------------------------------------------
 		//	  Data members 
 		// ------------------------------------------------------------- 

		private SqlBytes	m_sb;		// the SqlBytes object 
 		private long		m_lPosition;

		// --------------------------------------------------------------
		//	  Constructor(s) 
		// --------------------------------------------------------------
 
 		internal StreamOnSqlBytes(SqlBytes sb) { 
			m_sb = sb;
 			m_lPosition = 0; 
 		}

		// -------------------------------------------------------------
 		//	  Public properties 
		// --------------------------------------------------------------
 
		// Always can read/write/seek, unless sb is null, 
		// which means the stream has been closed.
 
 		public override bool CanRead {
			get	{
 				return m_sb != null && !m_sb.IsNull;
 			} 
		}
 
 		public override bool CanSeek { 
			get {
				return m_sb != null; 
			}
 		}

		public override bool CanWrite { 
 			get	{
 				return m_sb != null && (!m_sb.IsNull || m_sb.m_rgbBuf != null); 
			} 
 		}
 
		public override long Length	{
			get	{
    			CheckIfStreamClosed("get_Length");
	    		return m_sb.Length; 
            }
        } 
 
 		public override long Position {
			get	{ 
 				CheckIfStreamClosed("get_Position");
 				return m_lPosition;
			}
 			set	{ 
				CheckIfStreamClosed("set_Position");
				if (value < 0 || value > m_sb.Length) 
					throw new ArgumentOutOfRangeException("value"); 
 				else
					m_lPosition = value; 
 			}
 		}

		// ------------------------------------------------------------- 
 		//	  Public methods
		// ------------------------------------------------------------- 
 
		public override long Seek(long offset, SeekOrigin origin) {
			CheckIfStreamClosed("Seek"); 

 			long lPosition = 0;

			switch(origin) { 
 				case SeekOrigin.Begin:
 					if (offset < 0 || offset > m_sb.Length) 
						throw new ArgumentOutOfRangeException("offset"); 
 					m_lPosition = offset;
					break; 
					
				case SeekOrigin.Current:
 					lPosition = m_lPosition + offset;
					if (lPosition < 0 || lPosition > m_sb.Length) 
 						throw new ArgumentOutOfRangeException("offset");
 					m_lPosition = lPosition; 
					break; 
 					
				case SeekOrigin.End: 
					lPosition = m_sb.Length + offset;
					if (lPosition < 0 || lPosition > m_sb.Length)
 						throw new ArgumentOutOfRangeException("offset");
					m_lPosition = lPosition; 
 					break;
 					 
				default: 
                                throw ADP.InvalidSeekOrigin("offset");
 			} 

			return m_lPosition;
		}
 
		// The Read/Write/ReadByte/WriteByte simply delegates to SqlBytes
 		public override int Read(byte[] buffer, int offset, int count) { 
			CheckIfStreamClosed("Read"); 

 			if (buffer==null) 
 				throw new ArgumentNullException("buffer");
			if (offset < 0 || offset > buffer.Length)
 				throw new ArgumentOutOfRangeException("offset");
			if (count < 0 || count > buffer.Length - offset) 
				throw new ArgumentOutOfRangeException("count");
 
			int iBytesRead = (int)m_sb.Read(m_lPosition, buffer, offset, count); 
 			m_lPosition += iBytesRead;
 
			return iBytesRead;
 		}

 		public override void Write(byte[] buffer, int offset, int count) { 
			CheckIfStreamClosed("Write");
 
 			if (buffer==null) 
				throw new ArgumentNullException("buffer");
			if (offset < 0 || offset > buffer.Length) 
				throw new ArgumentOutOfRangeException("offset");
 			if (count < 0 || count > buffer.Length - offset)
				throw new ArgumentOutOfRangeException("count");
 
 			m_sb.Write(m_lPosition, buffer, offset, count);
 			m_lPosition += count; 
		} 

 		public override int ReadByte() { 
			CheckIfStreamClosed("ReadByte");

			// If at the end of stream, return -1, rather than call SqlBytes.ReadByte,
			// which will throw exception. This is the behavior for Stream. 
 			//
			if (m_lPosition >= m_sb.Length) 
 				return -1; 

 			int ret = m_sb[m_lPosition]; 
			m_lPosition ++;
 			return ret;
		}
 
		public override void WriteByte(byte value) {
			CheckIfStreamClosed("WriteByte"); 
 
 			m_sb[m_lPosition] = value;
			m_lPosition ++; 
 		}

 		public override void SetLength(long value) {
			CheckIfStreamClosed("SetLength"); 

 			m_sb.SetLength(value); 
			if (m_lPosition > value) 
				m_lPosition = value;
		} 

 		// Flush is a no-op for stream on SqlBytes, because they are all in memory
		public override void Flush() {
 			if (m_sb.FStream()) 
 				m_sb.m_stream.Flush();
		} 
 
 		protected override void Dispose(bool disposing) {
			// When m_sb is null, it means the stream has been closed, and 
			// any opearation in the future should fail.
			// This is the only case that m_sb is null.
            try {
 			m_sb = null; 
		}
            finally { 
                base.Dispose(disposing); 
            }
 		} 

 		// -------------------------------------------------------------
		//	  Private utility functions
 		// -------------------------------------------------------------- 

		private bool FClosed() { 
			return m_sb == null; 
		}
 
        private void CheckIfStreamClosed(string methodname) {
 			if (FClosed())
                throw ADP.StreamClosed(methodname);
        } 
    } // class StreamOnSqlBytes
} // namespace System.Data.SqlTypes 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK