IndexedDataBuffer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / IndexedDataBuffer.cs / 1 / IndexedDataBuffer.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace Microsoft.InfoCards
{ 
    using System;
    using System.ComponentModel; 
    using System.Collections; 
    using System.IO;
    using System.Runtime.InteropServices; 
    using System.Security;
    using System.Security.Cryptography;

    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; 

    // 
    // Summary: 
    //  Internal FileStore class for managing data blobs
    //  the the master index offsets (LocalIds) 
    //
    internal unsafe class IndexedDataBuffer
    {
        byte[] m_buffer; 
        byte[] m_masterIndex;
        FreeIndexList m_freeList; 
        Int32 m_dataLength; 
        bool m_isOpen;
        DataSource m_owner; 


        //
        // Summary: 
        //  Creates an IndexedDataBuffer class using the specified data
        // 
        // Parameters: 
        //  masterIndex:    the buffer to use as the initial masterIndex
        //  buffer:         the buffer to use as the initial data buffer 
        //  dataLength:     the length of the data used in the data buffer
        //
        public IndexedDataBuffer(
                        byte[] masterIndex, 
                        byte[] buffer,
                        Int32 dataLength, 
                        DataSource owner ) 
        {
            if( null == masterIndex || 0 == masterIndex.Length ) 
            {
                throw IDT.ThrowHelperArgumentNull(
                                "masterIndex",
                                SR.GetString( SR.StoreIndexedDataBufferNullOrEmptyMasterIndexBuffer  ) ); 
            }
 
            if( null == buffer || 0 == buffer.Length ) 
            {
                throw IDT.ThrowHelperArgumentNull( 
                                    "buffer",
                                    SR.GetString( SR.StoreIndexedDataBufferNullOrEmptyDataIndexBuffer ) );
            }
 
            if( dataLength < 0 || dataLength > buffer.Length  )
            { 
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    "dataLength",
                                    dataLength, 
                                    SR.GetString( SR.StoreIndexDataBufferDataLengthOutOfRange ) ) );
            }

            m_owner = owner; 
            m_masterIndex = masterIndex;
            m_buffer = buffer; 
            m_dataLength = dataLength; 
            m_freeList = new FreeIndexList( 20 );
 

            fixed( byte* pIndexBuffer = &m_masterIndex[ 0 ] )
            {
                Int32* pIndex = (Int32*)pIndexBuffer; 
                for( int i = 1; i < m_masterIndex.Length / sizeof( Int32 ); i++ )
                { 
                    if( pIndex[ i ] <= 0 ) 
                    {
                        m_freeList.Put( i ); 
                    }
                }
            }
 
            m_isOpen = true;
        } 
 

        // 
        // Summary:
        //  Gets a pointer to the internal buffer used to managed the offerts.
        //
        // Remarks: 
        //  This is intended for use by tools
        // 
        public byte[] Index 
        {
            get 
            {
                ThrowIfNotOpen( );
                return m_masterIndex;
            } 
        }
 
        // 
        // Summary:
        //  Gets a pointer to the internal buffer containing the data blobs. 
        //
        // Remarks:
        //  This is intended for use by tools
        // 
        public byte[] Data
        { 
            get 
            {
                ThrowIfNotOpen( ); 
                return m_buffer;
            }
        }
 
        //
        // Summary: 
        //  The amount of data being actively used by data blobs 
        //
        public Int32 DataLength 
        {
            get
            {
                ThrowIfNotOpen( ); 
                return m_dataLength;
            } 
        } 

        // 
        // Summary:
        //  Closes and clears all open resources
        //
        public void Close() 
        {
            ThrowIfNotOpen( ); 
            Clear( ); 
            m_buffer = null;
            m_masterIndex = null; 
            m_isOpen = false;
        }

        // 
        // Summary:
        //  Creates a datarow using the specified local Id. 
        //  This data row only contains the header information from the row. 
        //
        // Parameters: 
        //  id:         The localId to use to get the object information.
        //  owner:      The owning datasource for the object.
        //
        // Returns: 
        //  The data row with header information
        // 
        public DataRow CreateDataRow( Int32 id ) 
        {
            ThrowIfNotOpen( ); 
            if( id > m_masterIndex.Length / sizeof( Int32 ) || m_freeList.Contains( id ) )
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException(
                                    "id", 
                                    id,
                                    SR.GetString( SR.StoreLocalIdOutOfRange ) ) ); 
            } 

            Int32 offset = GetOffset( ref id ); 
            fixed( byte* pBuffer = &m_buffer[ offset ] )
            {
                return DataRow.Create( (EncryptedObjectHeader*)pBuffer,m_owner );
            } 

        } 
 

 
        //
        // Summary:
        //  Copies the IV of a data object to the specified buffer
        // 
        // Remarks:
        // 
        // Parameters: 
        //  id:         The localid of the object to get the IV from
        //  iv:         The output buffer to copy the IV to. 
        //  index:      The index in the output buffer to start the copy
        //
        public void CopyIVFromObject( Int32 id, byte[] iv, int index )
        { 
            ThrowIfNotOpen( );
            if( null == iv || 0 == iv.Length ) 
            { 
                throw IDT.ThrowHelperArgumentNull( "iv" );
            } 

            if( index < 0 || index > ( this.DataLength - iv.Length ) )
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                "index",
                                index, 
                                SR.GetString( SR.StoreIndexDataBufferIndexOutOfRange ) ) ); 
            }
 
            if( id > m_masterIndex.Length / sizeof( Int32 ) || m_freeList.Contains( id ) )
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException(
                                    "id", 
                                    id,
                                    SR.GetString( SR.StoreLocalIdOutOfRange ) ) ); 
            } 

 
            Int32 offset = GetOffset( ref id );


           IDT.Assert( 
                   id >= 0,
                   "Invalid ID was returned by GetOffset." ); 
 

            fixed( byte* pBuffer = &m_buffer[ offset ] ) 
            {
                EncryptedObjectHeader* pObj = (EncryptedObjectHeader*)pBuffer;
                Marshal.Copy(
                            new IntPtr( &pObj->IV ),                    //source 
                            iv,                                         //dest
                            0,                                          //offset 
                            iv.Length );                                //size 

            } 
        }

        //
        // Summary: 
        //  Returns a readonly stream for the data object.
        // 
        // Remarks: 
        //  The return value is only valid if no other store change have occured.  If
        //  the unlerlying buffer get changed, this could return the wrong information. 
        //
        // Parameters:
        //  id:         The localId to get the data stream for
        // 
        // Returns:
        //  Read-Only Stream/Private stream bound to the data in the data buffer. 
        // 
        public Stream GetStreamForObjectData( Int32 id )
        { 
            ThrowIfNotOpen( );
            if( id > m_masterIndex.Length / sizeof( Int32 ) || m_freeList.Contains( id ) )
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    "id",
                                    id, 
                                    SR.GetString( SR.StoreLocalIdOutOfRange ) ) ); 
            }
 
            Int32 offset = GetOffset( ref id );


           IDT.Assert( 
                   id >= 0,
                   "Invalid ID was returned by GetOffset." ); 
 

            Int32 length = GetObjectDataSize( offset ); 

            IDT.Assert(
                length <= ( m_buffer.Length - offset ),
                "The length the stored object is invalid" ); 

            return new MemoryStream( m_buffer, offset + sizeof( EncryptedObjectHeader ), length, false, false ); 
        } 

        // 
        // Summary:
        //  Removes an object from the data source.
        //
        // Parameters: 
        //  id:         The localId for the object you want to remove
        // 
        public void RemoveObject( Int32 id ) 
        {
            ThrowIfNotOpen( ); 
            //
            // If it is beyond our rage, or it is part of our free list,
            // it is invalid.
            // 
            if( id > m_masterIndex.Length / sizeof( Int32 ) || m_freeList.Contains( id ) )
            { 
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    "id",
                                    id, 
                                    SR.GetString( SR.StoreLocalIdOutOfRange ) ) );
            }

            Int32 offset = GetOffset( ref id ); 

            IDT.Assert( 
                   id >= 0, 
                   "Invalid ID was returned by GetOffset." );
 
            RemoveFromMasterIndex(id);


            EnsureSpaceForData( offset, 0 ); 
        }
 
        // 
        // Summary:
        //  Write the provided data to the data blob. 
        //
        // Remarks:
        //
        // Parameters: 
        //  id:         The local ID you want to get write to.
        //  iv:         The value of the IV Field to save 
        //  data:       The raw data blob to save 
        //  objectType: The object type field to save
        //  lastChange: The lastChange field to save 
        //  globalId:   The globalId field to save.
        //
        public Int32 WriteObject( Int32 id, byte[] iv, byte[] data, Int32 objectType, Int64 lastChange, GlobalId globalId )
        { 
            ThrowIfNotOpen( );
 
            if( null == iv || 0 == iv.Length ) 
            {
                throw IDT.ThrowHelperArgumentNull( "iv" ); 
            }

            if( null == data || 0 == data.Length )
            { 
                throw IDT.ThrowHelperArgumentNull( "iv" );
            } 
 
            if( id > m_masterIndex.Length / sizeof( Int32 )  )
            { 
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException(
                                    "id",
                                    id,
                                    SR.GetString( SR.StoreLocalIdOutOfRange ) ) ); 
            }
 
            if( id > 0 && m_freeList.Contains( id ) ) 
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    "id",
                                    id,
                                    SR.GetString( SR.StoreLocalIdOutOfRange ) ) );
            } 

            Int32 offset = GetOffset( ref id ); 
 
             IDT.Assert(
                   id >= 0, 
                   "Invalid ID was returned by GetOffset." );

            Int32 size = EnsureSpaceForData( offset, data.Length );
 
            fixed( byte* pBuffer = &m_buffer[ offset ] )
            { 
                EncryptedObjectHeader* pObj = (EncryptedObjectHeader*)pBuffer; 
                byte* pData = (byte*)( pObj + 1 );
 
                //
                // Capture the input
                //
                pObj->LastChange = lastChange; 

                // 
                // Because decryption of this blob requires the exact size, not 
                // the rounded-up size provided, we must write the actual length,
                // and round up next time we need the value. 
                //
                pObj->DataSize = data.Length;
                pObj->ObjectType = objectType;
                pObj->LocalId = id; 
                pObj->GlobalId = globalId;
 
 
                IDT.Assert(
                        iv.Length <= EncryptedObjectHeader.IVBlockSize, 
                        "IV Length is invalid" );

                //
                //copy in the IV 
                //
                Marshal.Copy( 
                            iv,                         //source 
                            0,                          //source index
                            new IntPtr( &pObj->IV ),    //desination ptr 
                            iv.Length );                //size to copy

                //
                // Copy in the data 
                //
                Marshal.Copy( 
                            data,                   //source 
                            0,                      //source index
                            new IntPtr( pData ),    //destination ptr 
                            data.Length );          //size to copy
            }

            return id; 
        }
 
 
        //
        // Summary: 
        //  Gets the data size field from object at the specified offset
        //
        // Remarks:
        // 
        // Parameters:
        //  offset:     The offset in the data buffer where the EncryptedObjectHeader begins. 
        // 
        // Returns:
        //  Retunrs the size field of the object. 
        //
        private Int32 GetObjectDataSize( Int32 offset )
        {
            fixed( byte* pBuffer = &m_buffer[ offset ] ) 
            {
                EncryptedObjectHeader* pObj = (EncryptedObjectHeader*)pBuffer; 
                return pObj->DataSize; 
            }
        } 

        //
        // Summary:
        //  Clears all buffers, and set the length to 0 
        //
        private void Clear() 
        { 
            Array.Clear( this.m_buffer, 0, m_dataLength );
            Array.Clear( m_masterIndex, 0, m_masterIndex.Length ); 
            m_dataLength = 0;
        }

        // 
        // Summary:
        //  Shift,Moves, and manipulates the internal data buffer 
        //      to ensure that the all data can be written correctly. 
        //
        // Remarks: 
        //
        // Parameters:
        //  offset:     The offset to place the object.
        //  datasize:   The requested data size. 
        //
        // Returns: 
        //  the new space for the object 
        //
        private Int32 EnsureSpaceForData( Int32 offset, Int32 dataSize ) 
        {
            IDT.Assert(
                    (UInt32)offset <= (UInt32)m_dataLength,
                    "offset specified is outside the range of the data buffer" ); 
            IDT.Assert(
                    dataSize >= 0, 
                    "The requested data size must be greater than or equal to 0" ); 

            Int32 objRequiredSpace = 0; 
            Int32 currentSize = 0;
            Int32 nextIndex = 0;
            Int32 nextNewIndex = 0;
            Int32 newSizeDiff = 0; 

            // 
            // Data size can be 0 in the case of a delete. 
            //
            if( dataSize != 0 ) 
            {
                objRequiredSpace = dataSize + sizeof( EncryptedObjectHeader );
            }
 
            //
            // Ensure the data will align 
            // 
            if( 0 != ( objRequiredSpace % 8 ) )
            { 
                objRequiredSpace += 8 - ( objRequiredSpace % 8 );
            }

 
            //
            // This is an insert 
            // 
            if( offset == m_dataLength )
            { 
                currentSize = 0;
            }
            else
            { 
                fixed( byte* pBuffer = &m_buffer[ offset ] )
                { 
                    EncryptedObjectHeader* pHeader = (EncryptedObjectHeader*)pBuffer; 
                    currentSize = pHeader->DataSize + sizeof( EncryptedObjectHeader );
                    // 
                    // Because Decryption of the data requires the exact number of bytes
                    // that was encrypted, we must re-round the size to the neareast 8 bytes
                    // as we do above.
                    // 
                    if( 0 != ( currentSize % 8 ) )
                    { 
                        currentSize += 8 - ( currentSize % 8 ); 
                    }
 
                }
            }

            IDT.Assert( 
                    currentSize <= m_dataLength,
                    "currentSize can not be more " ); 
 
            if( currentSize == objRequiredSpace )
            { 
                return objRequiredSpace;
            }

            nextIndex = offset + currentSize; 
            newSizeDiff = objRequiredSpace - currentSize;
            nextNewIndex = nextIndex + newSizeDiff; 
 
            //
            // If we are growing, 
            // and the new length exceeds our size, grow
            //
            if( newSizeDiff > 0 && m_dataLength + newSizeDiff >= m_buffer.Length )
            { 
                GrowBuffer( ( m_dataLength + newSizeDiff ) );
            } 
 

            IDT.Assert( 
                    (UInt32)nextIndex <= (UInt32)m_buffer.Length &&
                    nextIndex >= offset,
                    "NextIndex value is corrupt when attempting to ensure space for object" );
 
            IDT.Assert(
                    (UInt32)nextNewIndex <= (UInt32)m_buffer.Length, 
                    "NextNewIndex value is corrupt when attempting to ensure space for object" ); 

 

            //
            // If we are not at the end of the list
            // 
            if( m_dataLength != nextIndex )
            { 
                IDT.Assert( 
                        m_dataLength - nextIndex > 0,
                        "NextIndex data is corrupt when attempting to ensure space for object in middle of content." ); 

                Array.Copy( m_buffer, nextIndex, m_buffer, nextNewIndex, m_dataLength - nextIndex );

                m_dataLength += newSizeDiff; 

                IDT.Assert( m_dataLength >= 0, 
                    "DataLength has been corrupted." 
                    );
 
                //
                // if this was as removal of space
                //
                if( newSizeDiff < 0 ) 
                {
                    IDT.Assert( 
                            m_dataLength <= m_buffer.Length, 
                            "DataLength is larger than allocated buffer." );
 
                    Array.Clear( m_buffer, m_dataLength, Math.Abs( newSizeDiff ) );
                }

 
                //
                // Take the lowest of the two numbers, 
                // and use that for the index update calculation. 
                //
                UpdateMasterIndex( Math.Min( nextIndex, nextNewIndex ), newSizeDiff ); 
            }
            else
            {
                m_dataLength += newSizeDiff; 
            }
 
            IDT.Assert( 
                    m_dataLength <= m_buffer.Length,
                    "DataLength is larger than allocated buffer." ); 

            return objRequiredSpace;
        }
 
        //
        // Summary: 
        //  Grows the buffer used for the master index by 5% 
        //
        private void GrowMasterIndex() 
        {
            //
            // If the free list is exhaused, we must need
            // to grow our list. 
            //
            int count = m_masterIndex.Length / sizeof( Int32 ); 
 
            int newSize = Utility.CalculateIncreaseByPercent(
                m_masterIndex.Length, 
                sizeof( Int32 ),
                5 );

            IDT.Assert( 
                    newSize > m_masterIndex.Length,
                    "NewSize must be greater than old size to grow master index buffer" ); 
 
            byte[] newIndex = new byte[ newSize ];
            Array.Copy( m_masterIndex, 0, newIndex, 0, m_masterIndex.Length ); 
            Array.Clear( m_masterIndex, 0, m_masterIndex.Length );
            m_masterIndex = newIndex;

            int newCount = m_masterIndex.Length / sizeof( Int32 ); 
            for( int j = count + 1; j < ( newCount ); j++ )
            { 
                m_freeList.Put( j ); 
            }
        } 

        //
        // Summary:
        //  Grows the buffer used for data object by 5% 
        //
        private void GrowBuffer( int spaceRequired ) 
        { 
            IDT.Assert(
                    spaceRequired >= m_buffer.Length, 
                    "RequireSpace must be greater than old size to grow data buffer" );

            int newLength = spaceRequired;
            newLength += newLength / 20;//grow by 5% 

            IDT.Assert( 
                    newLength >= spaceRequired, 
                    "NewLength must be greater than required space to grow data buffer" );
 
            byte[] newBuffer = new byte[ newLength ];

            Array.Copy( m_buffer, 0, newBuffer, 0, m_buffer.Length );
            Array.Clear( m_buffer, 0, m_buffer.Length ); 

            m_buffer = newBuffer; 
 
            IDT.Assert(
                    m_dataLength <= m_buffer.Length, 
                    "DataLength Corrupt or buffer growth failed." );
        }
        //
        // Summary: 
        //  Gets of offset in the data buffer for the specified LocalId
        // 
        // Remarks: 
        //
        // Parameters: 
        //  ref id:     pointer to the ID to use.  If <= 0 specfied, will be updated with new id.
        //
        // Returns:
        //  returns the offset in the data buffer that the id param points to when the method returns. 
        //
        private Int32 GetOffset( ref Int32 id ) 
        { 
            Int32 offset;
            if( id <= 0 ) 
            {
                if( m_dataLength <= 0 )
                {
                    // 
                    // Could use IntPtr.Size too but that would make
                    // store format different on different architectures 
                    // 
                    m_dataLength = sizeof( Int64 );
                } 

                offset = m_dataLength;
                id = GetNextLocalId( offset );
                return offset; 
            }
            else 
            { 
                fixed( byte* pIndexBuffer = &m_masterIndex[ 0 ] )
                { 
                    Int32* pIndex = (Int32*)pIndexBuffer;

                    IDT.Assert(
                            pIndex[ id ] >= 0, 
                            "Master Index offset value is invalid" );
 
                    return pIndex[ id ]; 
                }
            } 
        }

        //
        // Summary: 
        //  Removes the specified localId from the masterIndex
        // 
        // Remarks: 
        //
        // Parameters: 
        //  id:     LocalId to remove from the master index.
        //
        private void RemoveFromMasterIndex( Int32 id )
        { 
            IDT.Assert(
                    id > 0, 
                    "LocalId is invalid" ); 

 
            fixed( byte* pIndexBuffer = &m_masterIndex[ 0 ] )
            {
                Int32* pIndex = (Int32*)pIndexBuffer;
                pIndex[ id ] = 0; 
                m_freeList.Put( id );
            } 
        } 

        // 
        // Summary:
        //  Updates the master index with data shift information.
        //
        // Remarks: 
        //  for each item in the index who's offset would be changed
        //      we update them by adding the difference. 
        // 
        // Parameters:
        //  offset:     the base offset to start from 
        //  diff:       the difference to add to all changed values
        //
        private void UpdateMasterIndex( Int32 offset, Int32 diff )
        { 
            IDT.Assert(
                    offset > 0, 
                    "Offset is invalid" ); 
            IDT.Assert(
                    diff != 0, 
                    "Difference is invalid" );

            int count = m_masterIndex.Length / sizeof( Int32 );
            fixed( byte* pIndexBuffer = &m_masterIndex[ 0 ] ) 
            {
                Int32* pIndex = (Int32*)pIndexBuffer; 
 
                //
                // Loop through the index items. 
                // starting with item 1, becuase 0 is invalid.
                //
                for( int i = 1; i < count; i++ )
                { 
                    IDT.Assert(
                            ( &pIndex[ i ] - pIndex ) <= m_masterIndex.Length, 
                            "Pointer has walked past the end of the allocated buffer."); 

                    if( pIndex[ i ] > 0 && pIndex[ i ] >= offset ) 
                    {
                        pIndex[ i ] += diff;
                    }
 
                }
            } 
        } 

        // 
        // Summary:
        //  Gets the next localId available for use.
        //
        // Remarks: 
        //
        // Parameters: 
        //  offset:     offset to assign to the localId when returned 
        //
        // Returns: 
        //  The new localId that was assigned the offset.
        //
        private Int32 GetNextLocalId( Int32 offset )
        { 
            IDT.Assert(
                    offset >= 0, 
                    "The offset can not be negative." ); 

            Int32 i = m_freeList.GetNext( ); 

            //
            // If the free list didn't contain a match.
            // 
            if( i > 0 )
            { 
                IDT.Assert( 
                        null != m_masterIndex,
                        "m_masterIndex must not be null by now" ); 
                IDT.Assert(
                        m_masterIndex.Length > 0,
                        "m_masterIndex must not be empty." );
 
                fixed( byte* pIndexBuffer = &m_masterIndex[ 0 ] )
                { 
                    Int32* pIndex = (Int32*)pIndexBuffer; 
                    pIndex[ i ] = offset;
                    return i; 
                }
            }

            int count = m_masterIndex.Length / sizeof( Int32 ); 

            GrowMasterIndex( ); 
 

            int newCount = m_masterIndex.Length / sizeof( Int32 ); 

            IDT.Assert(
                    newCount > count &&
                    count > 0, 
                    "Calculated count is corrupt or invalid.");
 
 
            //
            // Set the item and return 
            // the index of that item.
            //
            fixed( byte* pIndexBuffer = &m_masterIndex[ 0 ] )
            { 
                Int32* pIndex = (Int32*)pIndexBuffer;
                pIndex[ count ] = offset; 
            } 

 
            return count;
        }

        public void ThrowIfNotOpen() 
        {
            if( !m_isOpen ) 
                throw IDT.ThrowHelperError( new ObjectDisposedException( "IndexedDataBuffer" ) ); 
        }
    } 
}

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

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