DataSpaceManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Base / System / IO / Packaging / CompoundFile / DataSpaceManager.cs / 1 / DataSpaceManager.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//   The object for manipulating data spaces within the WPP Package. 
//
// History: 
//  06/04/2002: RogerCh: Initial creation of class & method stubs.
//  06/17/2002: RogerCh: Initial implementation.
//  05/20/2003: RogerCh: Ported to WCP tree.
//  05/28/2003: RogerCh: Added long name support 
//
//----------------------------------------------------------------------------- 
 
using System;
using System.Collections; 
using System.Diagnostics;           // For Debug.Assert
using System.Globalization;
using System.IO;
using System.Reflection;            // For finding transform objects & their constructor 
using System.Security.Permissions;  // For StrongNameIdentityPermission
using System.Collections.Generic; 
 
using System.Windows;               // ExceptionStringTable
using MS.Internal.IO.Packaging; 
using MS.Internal.IO.Packaging.CompoundFile;
using CU = MS.Internal.IO.Packaging.CompoundFile.ContainerUtilities;

 
namespace System.IO.Packaging
{ 
///  
/// This class is used to manipulate the data spaces within a specific instance
/// of the Avalon container.  This is how data transform modules are plugged 
/// into the container to enable features like data compression and data
/// encryption.
/// 
internal class DataSpaceManager 
{
    /***********************************************************************/ 
    // Constants 

    // The header bytes that this version understands and supports 
    const int KnownBytesInMapTableHeader = 8; // Two Int32s == 8 bytes
    const int KnownBytesInDataSpaceDefinitionHeader = 8;
    const int KnownBytesInTransformDefinitionHeader = 8;
    const int AllowedExtraDataMaximumSize = 8192; // 8K 

    // Names for streams and storages within the container 
    const string DataSpaceStorageName = "\x0006DataSpaces"; 
    const string DataSpaceVersionName = "Version";
    const string DataSpaceMapTableName= "DataSpaceMap"; 
    const string DataSpaceDefinitionsStorageName = "DataSpaceInfo";
    const string TransformDefinitions = "TransformInfo";
    const string TransformPrimaryInfo = "\x0006Primary";
 
    // The string used in FormatVersion
    private static readonly string DataSpaceVersionIdentifier = "Microsoft.Container.DataSpaces"; 
 
    // Version Writer - 1.0, Reader - 1.0, Updater - 1.0
    private static readonly VersionPair DataSpaceCurrentWriterVersion  = new VersionPair(1 /*major*/, 0 /*minor*/); 
    private static readonly VersionPair DataSpaceCurrentReaderVersion  = new VersionPair(1 /*major*/, 0 /*minor*/);
    private static readonly VersionPair DataSpaceCurrentUpdaterVersion = new VersionPair(1 /*major*/, 0 /*minor*/);

    // The version information we read from the file 
    private FormatVersion _fileFormatVersion;
 
    private bool _dirtyFlag; 

    /***********************************************************************/ 
    // Data space manager instance values

    /// 
    /// There is only one data space manager per container instance.  This 
    /// points back to "our" reference.
    ///  
    StorageRoot _associatedStorage; 

    ///  
    /// Maps container references to data spaces
    ///
    /// Keys into this list are CompoundFileReference instances, each
    /// representing a subset of the container that is encoded with a 
    /// particular data space.
    /// 
    /// Values are strings, which are data space labels and can be used 
    /// as keys into _dataSpaceDefinitions for more details
    ///  
    SortedList _dataSpaceMap;

    /// 
    /// Extra data in the data space mapping table header is preserved 
    /// in this byte array.
    ///  
    byte[] _mapTableHeaderPreservation; 

    ///  
    /// Maps a data space name to a string array of transform names.
    ///
    /// Keys into this hash table are strings, each a unique label for
    /// a data space. 
    ///
    /// Values from this hash table are ArrayLists, each an array of 
    /// strings.  Each string is a data space label.  This transform 
    /// stack is stored in bottom-up order.  The first transform listed
    /// is the first to get the raw bytes from disk. 
    /// 
    Hashtable _dataSpaceDefinitions;

 
    /// 
    /// Maps a transform name to an instance of transform handle class 
    /// 
    /// Keys into this hash table are strings, each a unique label for
    /// a transform object instance. 
    ///
    /// Values from this hash table are references to the TransformInstance
    /// class defined below, each of which contains information for a
    /// particular transform instance. 
    /// 
    Hashtable _transformDefinitions; 
 
    /// 
    /// When shutting down, we need to flush each open transformed stream in 
    /// order to ensure that all encoding data has been propagated through
    /// the transform stack before we shut things down.  Otherwise we may leave
    /// data in a state where it could not be written out because parts of the
    /// transform stack has already been disposed. 
    /// 
    ArrayList _transformedStreams; 
 
    /// 
    /// Table of "well-known" -- that is, "built-in" -- transforms. The keys are 
    /// the TransformClassName identifier strings for the well-known transforms,
    /// such as encryption and compression. The values are the assembly-qualified
    /// .NET class names of the classes that implement the transforms.
    ///  
    static readonly Hashtable _transformLookupTable;
 
    /***********************************************************************/ 
    // Private class for tracking individual transform instances
 
    private class TransformInstance
    {
        // When we only know the CLR type name
        internal TransformInstance( int classType, string name ) : this(classType, name, null, null, null, null ) {;} 

        // When we also have an actual object in memory and its associated 
        //  environment object 
        internal TransformInstance(
            int classType, 
            string name,
            IDataTransform instance,
            TransformEnvironment environment ) : this(classType, name, instance, environment, null, null ) {;}
 
        // When we know everything to put into a TransformInstance.
        internal TransformInstance( 
            int classType, 
            string name,
            IDataTransform instance, 
            TransformEnvironment environment,
            Stream primaryStream,
            StorageInfo storage )
        { 
            typeName = name;
            transformReference = instance; 
            transformEnvironment = environment; 
            transformPrimaryStream = primaryStream;
            transformStorage = storage; 
            _classType = classType;
        }

        internal byte[] ExtraData 
        {
            get 
            { 
                return _extraData;
            } 

            set
            {
                _extraData = value; 
            }
        } 
 
        internal int ClassType
        { 
            get
            {
                return _classType;
            } 
        }
 
        ///  
        /// This is the CLR name used to define this transform.  Keep in
        /// mind that this is not necessarily what we retrieve when we 
        /// call Type.FullName or Type.AssemblyQualifiedName.  This is
        /// the name that needs to be persisted in the file because it is
        /// what the caller told us to use to find the type.
        ///  
        internal string          typeName;
 
        ///  
        /// If we have actually created the transform object, we keep
        /// a reference to it here.  This may be null if we haven't 
        /// had a need to create the transform object.
        /// 
        internal IDataTransform  transformReference;
 
        /// 
        /// The instance of TransformEnvironment that we created and 
        /// handed off to the transform object to tell us about things. 
        /// This can also be null, but only when transformReference is
        /// null.  It is not valid for only one of these two to be null, 
        /// either they're both null or they're both non-null.
        /// 
        internal TransformEnvironment transformEnvironment;
 
        /// 
        /// The stream that is the primary data storage for this instance 
        /// of the transform object. 
        /// 
        internal Stream transformPrimaryStream; 

        /// 
        /// The storage that is available if the transform object requires
        /// more than the primary stream 
        /// 
        internal StorageInfo transformStorage; 
 
        private int _classType;
        private byte[] _extraData; 
    }

    private class DirtyStateTrackingStream:  Stream
    { 

        //////////////////////////////////// 
        // Stream section 
        /////////////////////////////////
        public override bool CanRead 
        {
            get
            {
                return (_baseStream != null && _baseStream.CanRead); 
            }
        } 
 
        public override bool CanSeek
        { 
            get
            {
                return (_baseStream != null && _baseStream.CanSeek);
            } 
        }
 
        public override bool CanWrite 
        {
            get 
            {
                return (_baseStream != null && _baseStream.CanWrite);
            }
        } 

        public override long Length 
        { 
            get
            { 
                CheckDisposed();

                return  _baseStream.Length;
            } 
        }
 
        public override long Position 
        {
            get 
            {
                CheckDisposed();

                return _baseStream.Position; 
            }
 
            set 
            {
                CheckDisposed(); 

                _baseStream.Position = value;
            }
        } 

        public override void SetLength(long newLength) 
        { 
            CheckDisposed();
 
            if (newLength != _baseStream.Length)
            {
                _dirty = true;
            } 

            _baseStream.SetLength(newLength); 
        } 

        public override long Seek(long offset, SeekOrigin origin) 
        {
            CheckDisposed();

            return _baseStream.Seek(offset, origin); 
        }
 
        public override int Read(byte[] buffer, int offset, int count) 
        {
            CheckDisposed(); 

            return _baseStream.Read(buffer, offset, count);
        }
 
        public override void Write(byte[] buffer, int offset, int count)
        { 
            CheckDisposed(); 

            _baseStream.Write(buffer, offset, count); 
            _dirty = true;
        }

        public override void Flush() 
        {
            CheckDisposed(); 
 
            _baseStream.Flush();
        } 

        /////////////////////////////
        // Internal Constructor
        ///////////////////////////// 
        internal  DirtyStateTrackingStream(Stream baseStream)
        { 
            Debug.Assert(baseStream != null); 

            _baseStream = baseStream; 
        }

        internal bool DirtyFlag
        { 
            get
            { 
                return (_baseStream != null && _dirty); 
            }
        } 

        internal Stream BaseStream
        {
            get 
            {
                return _baseStream; 
            } 
        }
 
        //-----------------------------------------------------
        //
        //  Protected Methods
        // 
        //-----------------------------------------------------
        ///  
        /// Dispose(bool) 
        /// 
        ///  
        /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to
        /// call Dispose() instead of Close().
        protected override void Dispose(bool disposing)
        { 
            try
            { 
                if (disposing) 
                {
                    if (_baseStream != null) 
                        _baseStream.Close();
                }
            }
            finally 
            {
                _baseStream = null; 
                base.Dispose(disposing); 
            }
        } 

        /////////////////////////////
        // Private Methods
        ///////////////////////////// 

        private void CheckDisposed() 
        { 
            if (_baseStream == null)
            { 
                throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed));
            }
        }
 
        private bool _dirty;
        private Stream _baseStream; 
    } 

    private struct DataSpaceDefinition 
    {
        ArrayList _transformStack;
        Byte[]    _extraData;
 
        internal DataSpaceDefinition(ArrayList transformStack, Byte[] extraData)
        { 
            _transformStack = transformStack; 
            _extraData = extraData;
        } 

        internal ArrayList TransformStack
        {
            get 
            {
                return _transformStack; 
            } 
        }
 
        internal Byte[] ExtraData
        {
            get
            { 
                return _extraData;
            } 
        } 
    }
 
    /***********************************************************************/
    // Constructors

    ///  
    /// Static constructor that initializes the transformLookupTable (which see).
    ///  
    static DataSpaceManager() 
    {
        // Transform Identifier: we preserve casing, but do case-insensitive comparison 
        _transformLookupTable = new Hashtable(CU.StringCaseInsensitiveComparer);

        _transformLookupTable[RightsManagementEncryptionTransform.ClassTransformIdentifier]
            = "System.IO.Packaging.RightsManagementEncryptionTransform"; 
        _transformLookupTable[CompressionTransform.ClassTransformIdentifier]
            = "System.IO.Packaging.CompressionTransform"; 
    } 

    ///  
    /// Internally visible constructor
    /// 
    /// The container instance we're associated with
    internal DataSpaceManager( StorageRoot containerInstance ) 
    {
        _associatedStorage = containerInstance; 
 
        // Storage under which all data space information is stored.
        StorageInfo dataSpaceStorage = 
            new StorageInfo( _associatedStorage, DataSpaceStorageName );

        // Initialize internal data structures.
        // 
        _dataSpaceMap = new SortedList();
        _mapTableHeaderPreservation = new byte[0]; 
        _dataSpaceDefinitions = new Hashtable(CU.StringCaseInsensitiveComparer); 
        _transformDefinitions = new Hashtable(CU.StringCaseInsensitiveComparer);
        _transformedStreams = new ArrayList(); 

        // Check to see if we have any data space information to read
        if (dataSpaceStorage.Exists)
        { 
            // Read any existing data space mapping information from the container
            // 
            ReadDataSpaceMap(); 
            ReadDataSpaceDefinitions();
            ReadTransformDefinitions(); 
        }
        return;
    }
 
    /// 
    /// Returns the number of data spaces defined in this manager object 
    ///  
    internal int Count
    { 
        get
        {
            CheckDisposedStatus();
            return _dataSpaceMap.Count; 
        }
    } 
 
    private bool DirtyFlag
    { 
        get
        {
            if (_dirtyFlag)     // It is already dirty don't need to check further
                return true; 

            foreach( string transformDef in _transformDefinitions.Keys ) 
            { 
                TransformInstance transformInstance = GetTransformInstanceOf( transformDef );
                if (((DirtyStateTrackingStream) transformInstance.transformPrimaryStream).DirtyFlag) 
                {
                    return true;
                }
            } 

            return false; 
        } 
    }
 
    /// 
    /// Clean up the data space information and flush all data to the container.
    /// 
    public void Dispose() 
    {
        CheckDisposedStatus(); 
 
        // Flush any outstanding data in the transformed streams
        foreach( StreamWithDictionary dataStream in _transformedStreams ) 
        {
            if (!dataStream.Disposed)
                dataStream.Flush();
        } 
        _transformedStreams.Clear();
 
        // Now that all data have been flushed, shut down the transform 
        //  objects.
        foreach( object o in _transformDefinitions.Values ) 
        {
            IDataTransform idt = ((TransformInstance)o).transformReference;

            if( null != idt && 
                null != (idt as IDisposable))
            { 
                ((IDisposable)idt).Dispose(); 
            }
        } 

        // Now write the tables out.
        //
 
        if (FileAccess.Read != _associatedStorage.OpenAccess && DirtyFlag)
        { 
            WriteDataSpaceMap(); 
            WriteDataSpaceDefinitions();
            WriteTransformDefinitions(); 
        }

        _dataSpaceMap = null;
        _dataSpaceDefinitions = null; 
        _transformDefinitions = null;
 
        return; 
    }
 
    /// 
    /// Removes the container reference from the dataspace map. This is called when the container/substorage is getting deleted from the root storage. [DeleteSubStorage in StorageInfo]
    /// 
    internal void RemoveContainerFromDataSpaceMap(CompoundFileReference target) 
    {
       CheckDisposedStatus(); 
       if (_dataSpaceMap.Contains(target)) 
       {
            _dataSpaceMap.Remove(target); 
            _dirtyFlag = true;
       }
    }
 
    // Check to see if the dispose method has been called.  If so, throw an
    //  ObjectDisposedException. 
    internal void CheckDisposedStatus() 
    {
        // First check root 
        _associatedStorage.CheckRootDisposedStatus();

        // Check if we've been disposed
        if( null == _dataSpaceMap ) 
        {
            Debug.Assert( null == _dataSpaceDefinitions, 
                "Having a null data space map and a non-null data space definitions map is an inconsistent state" ); 
            Debug.Assert( null == _transformDefinitions,
                "Having a null data space map and a non-null transform definition map is an inconsistent state" ); 

            throw new ObjectDisposedException(null, SR.Get(SRID.DataSpaceManagerDisposed));
        }
    } 

    ///  
    /// Define a data space with the given stack of transform objects and 
    /// labeled with the given name.  The transform stack is interpreted in
    /// bottom-up order.  (Clear-text transform is last.) 
    /// 
    /// Transform stack
    /// New data space label
    internal void DefineDataSpace( string[] transformStack, string newDataSpaceLabel ) 
    {
        CheckDisposedStatus(); 
        // Data space must have at least one transform 
        if( null == transformStack ||
            0 == transformStack.Length ) 
            throw new ArgumentException(
                SR.Get(SRID.TransformStackValid));

        // Given label must be a non-empty string 
        CU.CheckStringAgainstNullAndEmpty(newDataSpaceLabel, "newDataSpaceLabel");
 
        // Given label must not be a reserved string 
        CU.CheckStringAgainstReservedName(newDataSpaceLabel, "newDataSpaceLabel");
 
        // Given label must not already be in use
        if( DataSpaceIsDefined( newDataSpaceLabel ) )
            throw new ArgumentException(
                SR.Get(SRID.DataSpaceLabelInUse)); 

        // Given transform array must include labels that have already been defined 
        foreach( string transformLabel in transformStack ) 
        {
            CU.CheckStringAgainstNullAndEmpty( transformLabel, "Transform label" ); 

            if( !TransformLabelIsDefined( transformLabel ) )
                throw new ArgumentException(
                    SR.Get(SRID.TransformLabelUndefined)); 
        }
 
        // Passes all inspection, data space definition successful. 
        SetDataSpaceDefinition( newDataSpaceLabel, new DataSpaceDefinition(new ArrayList(transformStack), null));
        _dirtyFlag = true; 

        return;
    }
 
    /// 
    /// Internal shortcut to check if data space is defined.  When we start 
    /// doing on-demand reads of data space definitions, the "demand" could 
    /// be triggered by this.
    ///  
    /// Label to check
    /// True if label is in use
    internal bool DataSpaceIsDefined( string dataSpaceLabel )
    { 
        CU.CheckStringAgainstNullAndEmpty(dataSpaceLabel, "dataSpaceLabel");
 
        return _dataSpaceDefinitions.Contains( dataSpaceLabel ); 
    }
 
    /// 
    ///     Central place to set a data space definition, centralizing the
    /// call to the name manager.
    ///  
    private void SetDataSpaceDefinition( string dataSpaceLabel, DataSpaceDefinition definition )
    { 
        _dataSpaceDefinitions[ dataSpaceLabel ] = definition; 
    }
 
    /// 
    ///     Central place to get a data space definition, centralizing the
    /// call to the name manager.
    ///  
    private DataSpaceDefinition GetDataSpaceDefinition( string dataSpaceLabel )
    { 
        return ((DataSpaceDefinition) _dataSpaceDefinitions[dataSpaceLabel]); 
    }
    ///  
    /// Internal method to retrieve the data space label corresponding to
    /// a container reference.  Returns null if no data space is associated.
    /// 
    /// CompoundFileReference whose data space label is to be retrieved 
    /// Data space label
    internal string DataSpaceOf( CompoundFileReference target ) 
    { 
        // Can't simply return _dataSpaceMap[target] because I need to cast it
        //  into a string, and if it's null the cast `blows up. 
        if( _dataSpaceMap.Contains(target) )
        {
            return (string)_dataSpaceMap[target];
        } 
        else
        { 
            return null; 
        }
    } 

    /// 
    /// This method returns all the transforms that are applied to a particular stream as an
    /// List of IDataTransform objects. 
    /// 
    /// StreamInfo for the stream whose transforms are requested 
    /// A List of IDataTransform objects that are applied to the stream represented by streamInfo 
    internal List GetTransformsForStreamInfo(StreamInfo streamInfo)
    { 
        string dataSpaces = this.DataSpaceOf(streamInfo.StreamReference);

        if (dataSpaces == null) // No datas pace is associated with the stream
        { 
            return new List(0);     // return an empty list
        } 
 
        ArrayList transformsList = this.GetDataSpaceDefinition(dataSpaces).TransformStack;
        List dataTransforms = new List(transformsList.Count); 

        for (int i = 0; i < transformsList.Count; i++)
        {
            dataTransforms.Add(this.GetTransformFromName(transformsList[i] as string)); 
        }
 
        return dataTransforms; 
    }
 
    /// 
    /// Define a data space with the given stack of transform objects and
    /// labeled with an auto-generated name
    ///  
    /// Transform stack
    /// The auto-generated label for this data space 
    internal string DefineDataSpace( string[] transformStack ) 
    {
        CheckDisposedStatus(); 
        Int64   timeSeed      = DateTime.Now.ToFileTime();
        string  generatedName = timeSeed.ToString(CultureInfo.InvariantCulture);

        // If there is a name collision, just keep incrementing the number 
        while( DataSpaceIsDefined( generatedName ) )
        { 
            timeSeed++; 
            generatedName = timeSeed.ToString(CultureInfo.InvariantCulture);
        } 

        // Submit the definition
        DefineDataSpace( transformStack, generatedName );
 
        return generatedName;
    } 
 
    /// 
    /// Tranform object is created. We are no longer using reflection to do this. We are supporting limited data transforms. 
    /// 
    private IDataTransform InstantiateDataTransformObject(int transformClassType,  string transformClassName, TransformEnvironment transformEnvironment )
    {
        object transformInstance = null; 

        if (transformClassType != (int) TransformIdentifierTypes_PredefinedTransformName) 
            throw new NotSupportedException(SR.Get(SRID.TransformTypeUnsupported)); 

        // Transform Identifier: we preserve casing, but do case-insensitive comparison 
        if (((IEqualityComparer) CU.StringCaseInsensitiveComparer).Equals(transformClassName,
                RightsManagementEncryptionTransform.ClassTransformIdentifier))
        {
            transformInstance = new RightsManagementEncryptionTransform( transformEnvironment); 
        }
        else if (((IEqualityComparer) CU.StringCaseInsensitiveComparer).Equals(transformClassName, 
                CompressionTransform.ClassTransformIdentifier)) 
        {
             transformInstance = new CompressionTransform( transformEnvironment ); 
        }
        else
        {
            //this transform class is not supported. Need to change this to appropriate error. 
            throw new ArgumentException(
                    SR.Get(SRID.TransformLabelUndefined)); 
        } 

        if (null != transformInstance) 
        {
            if( !( transformInstance is IDataTransform ) )
                throw new ArgumentException(
                    SR.Get(SRID.TransformObjectImplementIDataTransform)); 
            return (IDataTransform)transformInstance;
        } 
 
        return null;
    } 

    /// 
    /// Private method to check if a transform label is defined.  When we
    /// start reading transform defintions on-demand, we would probably do it 
    /// here as necessary.
    ///  
    /// Transform label to check 
    /// True if label is defined in hash table
    internal bool TransformLabelIsDefined( string transformLabel ) 
    {
        //

 
        return _transformDefinitions.Contains( transformLabel );
    } 
 
    /// 
    ///     Central place to set a transform definition, centralizing the 
    /// call to the name manager.
    /// 
    private void SetTransformDefinition( string transformLabel, TransformInstance definition )
    { 
        _transformDefinitions[ transformLabel ] = definition;
    } 
 
    /// 
    /// Private method to get the TransformInstance class representing 
    /// a transform instance.
    /// 
    private TransformInstance GetTransformInstanceOf( string transformLabel )
    { 
        Debug.Assert( TransformLabelIsDefined( transformLabel ),
            "Data space manager caller failed to verify transform exists before retrieving instance" ); 
 
        //
 


        return _transformDefinitions[ transformLabel ] as TransformInstance;
    } 

    ///  
    /// Internal method to get a MemoryStream whose contents will be 
    /// stored in the "\x0006Primary" data stream after our type identification
    /// information 
    /// 
    /// Transform Label
    /// Memory stream object for transform instance primary stream
    internal Stream GetPrimaryInstanceStreamOf( string transformLabel ) 
    {
        TransformInstance targetInstance = GetTransformInstanceOf( transformLabel ); 
 
        if( null == targetInstance.transformPrimaryStream )
        { 
            //build memory stream on the byte[0] , and allow writes only if
            // FileAccess is Write or ReadWrite
            if (_associatedStorage.OpenAccess == FileAccess.Read)
            { 
                targetInstance.transformPrimaryStream =
                    new DirtyStateTrackingStream (new MemoryStream 
                            (new byte[0], 
                            false /* Not writable */));
            } 
            else
            {
                targetInstance.transformPrimaryStream = new DirtyStateTrackingStream (new MemoryStream());
            } 
        }
 
        return targetInstance.transformPrimaryStream; 
    }
 
    /// 
    /// Internal method to get the StorageInfo where the transform instance
    /// data is stored.  This StorageInfo may not yet exist!
    ///  
    /// Transform Label
    /// StorageInfo pointing to transform instance data storage 
    internal StorageInfo GetInstanceDataStorageOf( string transformLabel ) 
    {
        TransformInstance targetInstance = GetTransformInstanceOf( transformLabel ); 

        if( null == targetInstance.transformStorage )
        {
            //string name = DataSpaceStorageName + '\\' + TransformDefinitions + '\\' + transformLabel; 

            //targetInstance.transformStorage  = new StorageInfo(_associatedStorage,name); 
 
            StorageInfo dataSpaceStorage = new StorageInfo( _associatedStorage, DataSpaceStorageName );
            if (!dataSpaceStorage.Exists ) 
            {
                dataSpaceStorage.Create();
            }
            StorageInfo transformDefinition = new StorageInfo( dataSpaceStorage, TransformDefinitions ); 
            if (!transformDefinition.Exists)
            { 
                transformDefinition.Create(); 
            }
            targetInstance.transformStorage  = new StorageInfo(transformDefinition,transformLabel); 
        }
        return targetInstance.transformStorage;
    }
 
    /// 
    /// Internal method to get the transform object corresponding to the specified 
    /// transform instance label. The transform object is created if it does not exist. 
    /// 
    ///  
    /// String that identifies the transform instance.
    /// 
    /// 
    /// An IDataTransform interface pointer to the transform object identified by 
    /// , or null if there is no such transform.
    ///  
    internal IDataTransform GetTransformFromName(string transformLabel) 
    {
        TransformInstance transformInstance = _transformDefinitions[transformLabel] as TransformInstance; 

        if (transformInstance == null)
        {
            // 
            // There is no transform instance with the specified name.
            // 
            return null; 
        }
 
        IDataTransform transformObject = transformInstance.transformReference;
        if (transformObject == null)
        {
            // 
            // There is a transform instance with the specified name, but its transform
            // object has not yet been created. Create it now. This code is modeled on the 
            // code in DefineTransform. 
            //
            TransformEnvironment transformEnvironment = new TransformEnvironment(this, transformLabel); 

            // Create the transform object.
            transformObject = InstantiateDataTransformObject(
                                    transformInstance.ClassType, 
                                    transformInstance.typeName,
                                    transformEnvironment); 
            transformInstance.transformReference = transformObject; 
        }
 
        return transformObject;
    }

    ///  
    /// Define a data transform object with the given object identification and
    /// labeled with the given name. 
    ///  
    /// Transform identification string
    /// Label to use for new transform 
    internal void DefineTransform(string transformClassName, string newTransformLabel )
    {
        CheckDisposedStatus();
 
        // Check to see if transform name is obviously invalid
        CU.CheckStringAgainstNullAndEmpty( transformClassName, "Transform identifier name" ); 
 
        // Check to see if transform name is valid
        CU.CheckStringAgainstNullAndEmpty( newTransformLabel, "Transform label" ); 

        // Given transform name must not be a reserved string
        CU.CheckStringAgainstReservedName( newTransformLabel, "Transform label" );
 
        // Can't re-use an existing transform name
        if( TransformLabelIsDefined( newTransformLabel ) ) 
            throw new ArgumentException( 
                SR.Get(SRID.TransformLabelInUse));
 
        // Create class the transform object will use to communicate to us
        TransformEnvironment transformEnvironment = new TransformEnvironment( this, newTransformLabel );

        // Create a TransformInstance object to represent this transform instance. 
        TransformInstance newTransform = new TransformInstance(
            TransformIdentifierTypes_PredefinedTransformName, 
            transformClassName, 
            null,
            transformEnvironment ); 

        SetTransformDefinition( newTransformLabel, newTransform );

        // Create the transform object 
        IDataTransform transformObject = InstantiateDataTransformObject(
                                                    TransformIdentifierTypes_PredefinedTransformName, 
                                                    transformClassName, 
                                                    transformEnvironment );
        newTransform.transformReference = transformObject; 

        // If transform is not ready out-of-the-box, do an initialization run.
        //  Note: Transform is not required to be "ready" after this.  This is
        //  done for those transforms that need initialization work up-front. 
        if( ! transformObject.IsReady )
        { 
            CallTransformInitializers( 
                new TransformInitializationEventArgs(
                    transformObject, 
                    null,
                    null,
                    newTransformLabel)
                ); 
        }
 
        _dirtyFlag = true; 

        return; 
    }

    /// 
    /// Define a data transform object with the given object identification and 
    /// labeled with an auto-generated name.
    ///  
    /// Transform identification string 
    /// The auto-generated label for this transform
    internal string DefineTransform( string transformClassName ) 
    {
        CheckDisposedStatus();
        Int64   timeSeed      = DateTime.Now.ToFileTime();
        string generatedName = timeSeed.ToString(CultureInfo.InvariantCulture); 

        // If there is a name collision, just keep incrementing the number 
        while( TransformLabelIsDefined( generatedName ) ) 
        {
            timeSeed++; 
            generatedName = timeSeed.ToString(CultureInfo.InvariantCulture);
        }

        // Submit the definition 
        DefineTransform( transformClassName, generatedName );
 
        return generatedName; 
    }
 
    //+----------------------------------------------------------------------
    //  Transform initialization event/delegate/etc.

    ///  
    ///     Delegate method for initializing transforms
    ///  
    internal delegate void TransformInitializeEventHandler( 
        object sender,
        TransformInitializationEventArgs e ); 

    /// 
    ///     Transform initialization event
    ///  
    internal event TransformInitializeEventHandler OnTransformInitialization;
 
    ///  
    /// Internal shortcut to kick off all the initializers
    ///  
    /// Arguments for the initializers
    internal void CallTransformInitializers( TransformInitializationEventArgs initArguments )
    {
        if( null != OnTransformInitialization ) 
            OnTransformInitialization( this, initArguments );
    } 
 
    /// 
    /// Reads a data space map from the associated container, if such a thing 
    /// is written to the file.
    /// 
    void ReadDataSpaceMap()
    { 
        // See if there's even a data spaces storage
        StorageInfo dataSpaceStorage = 
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StreamInfo dataSpaceMapStreamInfo =
            new StreamInfo( dataSpaceStorage, DataSpaceMapTableName ); 

        if( dataSpaceStorage.StreamExists(DataSpaceMapTableName) )
        {
            // There is an existing data space mapping table to read. 

            // Read the versioning information 
            ReadDataSpaceVersionInformation(dataSpaceStorage); 

            // Check if its the correct version for reading 
            ThrowIfIncorrectReaderVersion();

            // Read the data space mapping table
            using(Stream dataSpaceMapStream = dataSpaceMapStreamInfo.GetStream(FileMode.Open)) 
            {
                using(BinaryReader dataSpaceMapReader = 
                    new BinaryReader( dataSpaceMapStream, System.Text.Encoding.Unicode )) 
                {
                    int headerLength = dataSpaceMapReader.ReadInt32(); 
                    int entryCount = dataSpaceMapReader.ReadInt32();

                    if (headerLength < KnownBytesInMapTableHeader || entryCount < 0)
                        throw new FileFormatException(SR.Get(SRID.CorruptedData)); 

                    int extraDataSize = headerLength - KnownBytesInMapTableHeader; 
 
                    if( 0 < extraDataSize )
                    { 
                        if (extraDataSize > AllowedExtraDataMaximumSize)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));

                        _mapTableHeaderPreservation = dataSpaceMapReader.ReadBytes(extraDataSize); 

                        if (_mapTableHeaderPreservation.Length != extraDataSize) 
                            throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
                    }
 
                    _dataSpaceMap.Capacity = entryCount;

                    int entryLength;
                    int bytesRead; 
                    int totalBytesRead;
 
                    for( int i = 0; i < entryCount; i++ ) 
                    {
                        entryLength = dataSpaceMapReader.ReadInt32(); 

                        if (entryLength < 0)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));
 
                        totalBytesRead = 4; // entryLength
                        // Read the container reference entry 
                        CompoundFileReference entryRef = 
                            CompoundFileReference.Load( dataSpaceMapReader, out bytesRead );
                        checked { totalBytesRead += bytesRead; } 

                        // Read data space string and add to data space mapping table
                        string label = CU.ReadByteLengthPrefixedDWordPaddedUnicodeString(dataSpaceMapReader, out bytesRead);
                        checked { totalBytesRead += bytesRead; } 

                        _dataSpaceMap[entryRef] = label; 
 
                        // Verify entryLength against what was actually read:
                        if (entryLength != totalBytesRead) 
                        {
                            throw new IOException(SR.Get(SRID.DataSpaceMapEntryInvalid));
                        }
                    } 
                }
            } 
        } 
    }
 
    /// 
    /// Write the data space mapping table to underlying storage.
    /// 
    void WriteDataSpaceMap() 
    {
        ThrowIfIncorrectUpdaterVersion(); 
 
        StorageInfo dataSpaceStorage =
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StreamInfo dataSpaceMapStreamInfo =
            new StreamInfo ( dataSpaceStorage, DataSpaceMapTableName );

        if( 0 < _dataSpaceMap.Count ) 
        {
            // Write versioning information 
            StreamInfo versionStreamInfo = null; 
            if (dataSpaceStorage.StreamExists( DataSpaceVersionName ) )
                versionStreamInfo = dataSpaceStorage.GetStreamInfo( DataSpaceVersionName ); 
            else
                versionStreamInfo = dataSpaceStorage.CreateStream( DataSpaceVersionName );
            Stream versionStream = versionStreamInfo.GetStream();
            _fileFormatVersion.SaveToStream(versionStream); 
            versionStream.Close();
 
            // Create stream for write, overwrite any existing 
            using(Stream dataSpaceMapStream = dataSpaceMapStreamInfo.GetStream(FileMode.Create))
            { 
                using(BinaryWriter dataSpaceMapWriter =
                    new BinaryWriter( dataSpaceMapStream, System.Text.Encoding.Unicode ))
                {
                    // Write header 

                    // header length = our known size + preserved array size 
                    dataSpaceMapWriter.Write( 
                        checked ((Int32) (KnownBytesInMapTableHeader + _mapTableHeaderPreservation.Length)));
                    // number of entries 
                    dataSpaceMapWriter.Write(
                        _dataSpaceMap.Count );
                    // anything else we've preserved
                    dataSpaceMapWriter.Write( 
                        _mapTableHeaderPreservation );
 
                    // Loop to write entries 
                    foreach( CompoundFileReference o in _dataSpaceMap.Keys )
                    { 
                        // determine the entry length
                        string label = (string)_dataSpaceMap[o];
                        int entryLength = CompoundFileReference.Save(o, null);
 
                        checked { entryLength += CU.WriteByteLengthPrefixedDWordPaddedUnicodeString(null, label); }
 
                        // length of entryLength itself 
                        checked { entryLength += 4; }
 
                        // write out the entry length
                        dataSpaceMapWriter.Write((Int32) entryLength);

                        // Write out reference 
                        CompoundFileReference.Save( o, dataSpaceMapWriter);
 
                        // Write out dataspace label 
                        CU.WriteByteLengthPrefixedDWordPaddedUnicodeString(
                            dataSpaceMapWriter, label); 
                    }
                }
            }
        } 
        else
        { 
            // data space map is empty, remove existing stream if there. 
            if ( dataSpaceStorage.StreamExists( DataSpaceMapTableName ) )
                dataSpaceStorage.DeleteStream( DataSpaceMapTableName ); 
        }
    }

    ///  
    /// Read all data space definitions in one chunk.  To be replaced
    /// with on-demand reading mechanism. 
    ///  
    void ReadDataSpaceDefinitions()
    { 
        ThrowIfIncorrectReaderVersion();

        StorageInfo dataSpaceStorage =
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StorageInfo dataSpaceDefinitionsStorage =
            new StorageInfo( dataSpaceStorage, DataSpaceDefinitionsStorageName ); 
 
        if( dataSpaceDefinitionsStorage.Exists )
        { 
            // Fill in the Data Space Definitions hash table
            foreach( StreamInfo definitionStreamInfo in dataSpaceDefinitionsStorage.GetStreams())
            {
                // Open up the stream for this data space definition 
                using(Stream definitionStream = definitionStreamInfo.GetStream(FileMode.Open))
                { 
                    using(BinaryReader definitionReader = new BinaryReader( definitionStream, System.Text.Encoding.Unicode )) 
                    {
                        // Read data space definition stream 
                        int headerLength = definitionReader.ReadInt32();
                        int transformCount = definitionReader.ReadInt32();

                        if (headerLength < KnownBytesInDataSpaceDefinitionHeader || transformCount < 0) 
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));
 
                        ArrayList transformLabels = new ArrayList(transformCount); 
                        byte[] extraData = null;
                        int extraDataSize = headerLength - KnownBytesInDataSpaceDefinitionHeader; 

                        if (extraDataSize > AllowedExtraDataMaximumSize)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));
 
                        if (extraDataSize > 0)
                        { 
                            extraData = definitionReader.ReadBytes(extraDataSize); 

                            if (extraData.Length != extraDataSize) 
                                throw new FileFormatException(SR.Get(SRID.CorruptedData));
                        }

                        // Read the array of strings that make up the transform stack 
                        for( int i = 0; i < transformCount; i++ )
                        { 
                            transformLabels.Add( 
                                CU.ReadByteLengthPrefixedDWordPaddedUnicodeString( definitionReader ) );
                        } 

                        // Add data space definition to table
                        SetDataSpaceDefinition( definitionStreamInfo.Name, new DataSpaceDefinition(transformLabels, extraData));
                    } 
                }
            } 
        } 
    }
 
    /// 
    /// Write all data space definitions to underlying storage in one chunk.
    /// 
    /// 
    //
    void WriteDataSpaceDefinitions() 
    { 
        ThrowIfIncorrectUpdaterVersion();
 
        StorageInfo dataSpaceStorage =
            new StorageInfo( _associatedStorage, DataSpaceStorageName );

        // 

 
 
        // Write out data space definitions
        if( 0 < _dataSpaceDefinitions.Count ) 
        {

            StorageInfo dataSpaceDefinitionsStorage =
                new StorageInfo(dataSpaceStorage, DataSpaceDefinitionsStorageName); 
            dataSpaceDefinitionsStorage.Create();
 
            foreach( string name in _dataSpaceDefinitions.Keys ) 
            {
                StreamInfo singleDefinitionInfo = 
                    new StreamInfo(dataSpaceDefinitionsStorage,name);

                using(Stream singleDefinition = singleDefinitionInfo.GetStream())
                { 
                    using(BinaryWriter definitionWriter =new BinaryWriter( singleDefinition, System.Text.Encoding.Unicode ))
                    { 
                        DataSpaceDefinition definition = (DataSpaceDefinition) _dataSpaceDefinitions[name]; 

                        int headerSize = KnownBytesInDataSpaceDefinitionHeader; 

                        if (definition.ExtraData != null)
                        {
                            checked { headerSize += definition.ExtraData.Length; } 
                        }
                        definitionWriter.Write( headerSize ); 
                        definitionWriter.Write( definition.TransformStack.Count ); 
                        if (definition.ExtraData != null)
                        { 
                            definitionWriter.Write(definition.ExtraData);
                        }

                        foreach( object transformLabel in definition.TransformStack) 
                        {
                            CU.WriteByteLengthPrefixedDWordPaddedUnicodeString( 
                                definitionWriter, (string)transformLabel); 
                        }
                    } 
                }
            }
        }
    } 

    ///  
    /// Read all transform definitions in one chunk 
    /// 
    // 

    void ReadTransformDefinitions()
    {
        ThrowIfIncorrectReaderVersion(); 

        StorageInfo dataSpaceStorage = 
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StorageInfo transformDefinitionsStorage =
            new StorageInfo( dataSpaceStorage, TransformDefinitions ); 

        if( transformDefinitionsStorage.Exists )
        {
            // Read transform definitions from file 
            foreach( StorageInfo transformStorage in transformDefinitionsStorage.GetSubStorages() )
            { 
                // Read from primary stream 
                StreamInfo transformPrimary = new StreamInfo(
                    transformStorage, TransformPrimaryInfo ); 

                using(Stream transformDefinition = transformPrimary.GetStream(FileMode.Open))
                {
                    using(BinaryReader definitionReader = new BinaryReader( transformDefinition, System.Text.Encoding.Unicode )) 
                    {
                        int headerLength = definitionReader.ReadInt32(); // We don't actually do anything with HeaderLen at the moment 
                        int transformType = definitionReader.ReadInt32(); 

                        if (headerLength < 0) 
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));

                        // Create a TransformInstance class using name from file
                        TransformInstance transformInstance = 
                            new TransformInstance(transformType, CU.ReadByteLengthPrefixedDWordPaddedUnicodeString( definitionReader ) );
 
 
                        int extraDataSize = checked ((int) (headerLength - transformDefinition.Position));
 
                        if (extraDataSize < 0)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));

                        if (extraDataSize > 0) 
                        {
                            if (extraDataSize > AllowedExtraDataMaximumSize) 
                                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 

                            // Preserve the fields we don't know about. 
                            byte[] extraData = definitionReader.ReadBytes(extraDataSize);

                            if (extraData.Length != extraDataSize)
                                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 

                            transformInstance.ExtraData = extraData; 
                        } 

                        if( transformDefinition.Length > transformDefinition.Position ) 
                        {
                            // We have additional data in the primary instance data stream
                            int instanceDataSize = checked ((int)(transformDefinition.Length - transformDefinition.Position));
                            byte[] instanceData = new byte[instanceDataSize]; 
                            PackagingUtilities.ReliableRead(transformDefinition, instanceData, 0, instanceDataSize);
 
                            //build memory stream on the byte[] , and allow writes only if 
                            // FileAccess is Write or ReadWrite
                            MemoryStream instanceDataStream; 
                            if (_associatedStorage.OpenAccess == FileAccess.Read)
                            {
                                //  NOTE: Building MemoryStream directly on top of
                                //  instanceData byte array because we want it to be 
                                //  NOT resizable and NOT writable.
                                instanceDataStream = new MemoryStream(instanceData, false /* Not writable */); 
                            } 
                            else
                            { 
                                // Copy additional data into a memory stream
                                //  NOTE: Not building MemoryStream directly on top of
                                //  instanceData byte array because we want it to be
                                //  resizable. 
                                instanceDataStream = new MemoryStream();
                                instanceDataStream.Write( instanceData, 0, instanceDataSize ); 
                            } 
                            instanceDataStream.Seek( 0, SeekOrigin.Begin );
 
                            // Dirty state should be tracked after the original data is read in from the disk into the memory stream
                            transformInstance.transformPrimaryStream = new DirtyStateTrackingStream(instanceDataStream);
                        }
 
                        transformInstance.transformStorage = transformStorage;
 
                        SetTransformDefinition( transformStorage.Name, transformInstance ); 
                    }
                } 
            }
        }
    }
 
    /// 
    /// Write out all transform definitions all at once 
    ///  
    ///
    // 

    void WriteTransformDefinitions()
    {
        ThrowIfIncorrectUpdaterVersion(); 

        StorageInfo dataSpaceStorage = 
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StorageInfo transformDefinitionsStorage =
            new StorageInfo( dataSpaceStorage, TransformDefinitions ); 

        //

 

        if( 0 < _transformDefinitions.Count ) 
        { 
            foreach( string transformDef in _transformDefinitions.Keys )
            { 
                // 'transformDef' is the normalized label.  We need to dig a
                //  bit to retrieve the original transform label.
                string transformLabel = null;
                TransformInstance transformInstance = GetTransformInstanceOf( transformDef ); 
                Debug.Assert( transformInstance != null, "A transform instance should be available if its name is in the transformDefinitions hashtable");
 
                if( transformInstance.transformEnvironment != null ) 
                {
                    // We have a transform environment object - it has the transform label. 
                    transformLabel = transformInstance.transformEnvironment.TransformLabel;
                }
                else
                { 
                    // We don't have a transform environment object - we'll need to do a
                    //  more expensive reverse-lookup with the name manager. 
                    transformLabel = transformDef; 
                }
 
                // Now use transformLabel to create the storage.
                StorageInfo singleTransformStorage =
                    new StorageInfo( transformDefinitionsStorage, transformLabel );
                StreamInfo transformPrimaryInfo = 
                    new StreamInfo( singleTransformStorage, TransformPrimaryInfo );
 
                using(Stream transformPrimary = transformPrimaryInfo.GetStream()) 
                {
                    using(BinaryWriter transformWriter = new BinaryWriter( transformPrimary, System.Text.Encoding.Unicode )) 
                    {
                        // Header length size = Known (the number itself + identifier) +
                        //  to be calculated (length of type name)
                        int headerLength = checked (KnownBytesInTransformDefinitionHeader + 
                                                CU.WriteByteLengthPrefixedDWordPaddedUnicodeString( null, transformInstance.typeName));
 
                        if (transformInstance.ExtraData != null) 
                        {
                            Debug.Assert(transformInstance.ExtraData.Length > 0); 

                            checked { headerLength += transformInstance.ExtraData.Length; }
                        }
 
                        transformWriter.Write(headerLength);
 
                        transformWriter.Write((int)TransformIdentifierTypes_PredefinedTransformName); 
                        CU.WriteByteLengthPrefixedDWordPaddedUnicodeString(
                            transformWriter, transformInstance.typeName); 

                        // Write out the preserved unknown data if there are some
                        if (transformInstance.ExtraData != null)
                        { 
                            transformWriter.Write(transformInstance.ExtraData);
                        } 
 
                        if( null != transformInstance.transformPrimaryStream )
                        { 
                            byte[] memoryBuffer = ((MemoryStream) ((DirtyStateTrackingStream) transformInstance.transformPrimaryStream).BaseStream).GetBuffer();
                            transformPrimary.Write( memoryBuffer, 0, memoryBuffer.Length );
                        }
                    } 
                }
            } 
        } 
        else // No transform definitions
        { 
            if ( transformDefinitionsStorage.Exists)
            {
                dataSpaceStorage.Delete(true, TransformDefinitions);
                //transformDefinitionStorage.Delete(true); 
            }
        } 
    } 

    ///  
    /// Internal method to create an entry in the data space mapping table
    /// 
    /// Package reference describing the scope of the data space
    /// Label of the data space definition 
    internal void CreateDataSpaceMapping( CompoundFileReference containerReference, string label )
    { 
        Debug.Assert( DataSpaceIsDefined( label ), 
            "Internal method illegally defining a data space reference on a data space that has not yet been defined");
        _dataSpaceMap[containerReference] = label; 
        _dirtyFlag = true;
    }

    ///  
    /// Internal method to create the actual transform stack of streams which
    /// will handle the encoding and decoding 
    ///  
    /// Package reference for the data space stream
    /// Stream with raw bytes on disk 
    /// Stream with clear text
    internal Stream CreateDataSpaceStream( CompoundFileStreamReference containerReference , Stream rawStream )
    {
        Stream outputStream = rawStream; 
        // RightsManagementEncryptionTransform and CompressionTransform do not use transformContext
        IDictionary transformContext = new Hashtable(); // Transform context object 
 
        // See which data space we're creating this stream in
        string dataSpaceLabel = _dataSpaceMap[containerReference] as string; 
        Debug.Assert( null != dataSpaceLabel,
            "Internal caller has asked to create a data space stream but the reference is not associated with a data space" );

        // Retrieve the transform object stack 
        ArrayList transformStack = GetDataSpaceDefinition(dataSpaceLabel).TransformStack;
        Debug.Assert( null != transformStack, 
            "Internal inconsistency - data space name does not have a transform stack definition" ); 

        // Iterate the initialization process for each transform on the stack 
        foreach( string transformLabel in transformStack )
        {
            // Get information on this layer of the transform stack
            TransformInstance transformLayer = GetTransformInstanceOf( transformLabel ); 
            Debug.Assert( null != transformLayer, "Data space definition included an undefined transform" );
 
            // If we haven't gotten around to creating the transform object, go do it. 
            if( null == transformLayer.transformReference )
            { 
                transformLayer.transformEnvironment = new TransformEnvironment( this, transformLabel );

                transformLayer.transformReference = InstantiateDataTransformObject(
                                                        transformLayer.ClassType, 
                                                        transformLayer.typeName,
                                                        transformLayer.transformEnvironment ); 
            } 
            Debug.Assert( null != transformLayer.transformReference,
                "Failed to have a transform instance going in" ); 
            IDataTransform transformObject = transformLayer.transformReference;

            // If transform is not ready, call initializers to make it ready.
            if( ! transformObject.IsReady ) 
            {
                CallTransformInitializers( 
                    new TransformInitializationEventArgs( 
                        transformObject,
                        dataSpaceLabel, 
                        containerReference.FullName,
                        transformLabel)
                    );
 
                if( ! transformObject.IsReady ) // If STILL not ready, nobody could make it "ready".
                    throw new InvalidOperationException( 
                        SR.Get(SRID.TransformObjectInitFailed)); 
            }
            // Everything is setup, get a transformed stream 
            outputStream = transformObject.GetTransformedStream( outputStream, transformContext );
        }

        outputStream = new BufferedStream( outputStream ); // Add buffering layer 

        outputStream = new StreamWithDictionary( outputStream, transformContext ); 
 
        _transformedStreams.Add( outputStream ); // Remember this for later use
 
        return outputStream;
    }

    ///  
    /// When naming a transform object, the string being passed in can be
    /// interpreted in one of several ways.  This enumerated type is used 
    /// to specify the semantics of the identification string. 
    ///
    /// The transform identification string is key into a table of 
    ///  well-known transform definitions.
    /// 
    internal const int TransformIdentifierTypes_PredefinedTransformName = 1;
 
    #region Version Methods
 
    ///  
    /// Read the version information that specifies the minimum versions of the
    /// DataSpaceManager software that can read, write, or update the data space 
    /// information in this file.
    /// 
    /// 
    ///  
    /// If the format version information in the stream is corrupt.
    ///  
    private void ReadDataSpaceVersionInformation(StorageInfo dataSpaceStorage) 
    {
        if (_fileFormatVersion == null) 
        {
            if (dataSpaceStorage.StreamExists( DataSpaceVersionName ))
            {
                StreamInfo versionStreamInfo = dataSpaceStorage.GetStreamInfo( DataSpaceVersionName ); 
                using (Stream versionStream = versionStreamInfo.GetStream(FileMode.Open))
                { 
                    _fileFormatVersion = FormatVersion.LoadFromStream(versionStream); 

                    // Transform Identifier: we preserve casing, but do case-insensitive comparison 
                    //Case-insensitive comparison. As per recommendations, we convert both strings
                    //to Upper case and then compare with StringComparison.Ordinal
                    if (!((IEqualityComparer) CU.StringCaseInsensitiveComparer).Equals(_fileFormatVersion.FeatureIdentifier,
                                       DataSpaceVersionIdentifier)) 
                    {
                        throw new FileFormatException( 
                                            SR.Get(SRID.InvalidTransformFeatureName, 
                                            _fileFormatVersion.FeatureIdentifier,
                                            DataSpaceVersionIdentifier)); 
                    }
                    // If we ever write this version number out again, we will want to record
                    // the fact that it was done by the current version of the Dataspace software.
                    _fileFormatVersion.WriterVersion = DataSpaceCurrentWriterVersion; 
                }
            } 
        } 
    }
 
    /// 
    /// If the DataSpace version information was not present in the file, we initialize it with the
    /// values for the current DataSpace software.
    /// If the information was present we should have already read it as a part of the ReadDataSpaceMap. 
    /// 
    private void EnsureDataSpaceVersionInformation() 
    { 
        if (_fileFormatVersion == null)
        { 
            _fileFormatVersion = new FormatVersion(
                                        DataSpaceVersionIdentifier,
                                        DataSpaceCurrentWriterVersion,
                                        DataSpaceCurrentReaderVersion, 
                                        DataSpaceCurrentUpdaterVersion
                                     ); 
        } 
    }
 
    /// 
    /// Verify that the current version of this class can read the DataSpace information in
    /// this file.
    ///  
    /// 
    /// If the current version of this class cannot read the DataSpace information in this file. 
    ///  
    private void ThrowIfIncorrectReaderVersion()
    { 
        EnsureDataSpaceVersionInformation();

        if (!_fileFormatVersion.IsReadableBy(DataSpaceCurrentReaderVersion))
        { 
            throw new FileFormatException(
                            SR.Get( 
                                SRID.ReaderVersionError, 
                                _fileFormatVersion.ReaderVersion,
                                DataSpaceCurrentReaderVersion 
                                )
                            );
        }
    } 

    ///  
    /// Verify that the current version of this class can update the DataSpace information in 
    /// this file.
    ///  
    /// 
    /// If the current version of this class cannot update the DataSpace information in this file,
    /// or if the header information in the stream is corrupt.
    ///  
    private void ThrowIfIncorrectUpdaterVersion()
    { 
        EnsureDataSpaceVersionInformation(); 

        if (!_fileFormatVersion.IsUpdatableBy(DataSpaceCurrentUpdaterVersion)) 
        {
            throw new FileFormatException(
                            SR.Get(
                                SRID.UpdaterVersionError, 
                                _fileFormatVersion.UpdaterVersion,
                                DataSpaceCurrentUpdaterVersion 
                                ) 
                            );
        } 
    }

    #endregion Version Methods
} 

///  
/// Interface to be implemented by all data transform objects 
/// 
internal interface IDataTransform 
{
    /// 
    /// Whether this transform is ready to perform.  If false, it needs
    /// further initialization. 
    /// 
    bool IsReady { get; } 
 
    /// 
    /// Whether this transform is in a stable state 
    /// 
    bool FixedSettings { get; }

    ///  
    /// Data transform identifier object
    ///  
    object TransformIdentifier { get; } 

    ///  
    /// Given a stream for storing the encoded data, return a stream for
    /// manipulating the "cleartext" data.
    /// 
    Stream GetTransformedStream( Stream encodedDataStream, IDictionary transformContext ); 
}
 
///  
/// Internal class for passing arguments into event handlers
///  
internal class TransformInitializationEventArgs : EventArgs
{
    IDataTransform  dataInstance;
    string          dataSpaceLabel; 
    string          streamPath;
    string          transformLabel; 
 
    internal TransformInitializationEventArgs(
        IDataTransform instance, 
        string dataSpaceInstanceLabel,
        string transformedStreamPath,
        string transformInstanceLabel )
    { 
        dataInstance = instance;
        dataSpaceLabel = dataSpaceInstanceLabel; 
        streamPath = transformedStreamPath; 
        transformLabel = transformInstanceLabel;
    } 
    /// 
    /// Reference to the data object that requires initialization
    /// 
    internal IDataTransform DataTransform 
    {
        get 
        { 
            return dataInstance;
        } 
    }

    /// 
    /// Label for the data space whose initialization this is a part of 
    /// 
    internal string DataSpaceLabel 
    { 
        get
        { 
            return dataSpaceLabel;
        }
    }
 
    /// 
    /// The path to the stream whose use initiated this process 
    ///  
    internal string Path
    { 
        get
        {
            return streamPath;
        } 
    }
 
    ///  
    /// Label for the transform object instance being initialized
    ///  
    internal string TransformInstanceLabel
    {
        get
        { 
            return transformLabel;
        } 
    } 
}
 
/// 
/// An instance of this class is given to each transform object as a
/// means for the transform object to interact with the environment
/// provided by the data space manager.  It is not mandatory for a 
/// transform object to keep a reference on the given TransformEnvironment
/// object  it may choose to discard it if there is no need to interact 
/// with the transform environment. 
/// 
internal  class TransformEnvironment 
{
    DataSpaceManager transformHost;
    string  transformLabel;
 
    /// 
    /// This object is only created internally by the data space manager. 
    ///  
    /// The data space manager who created this class
    /// Text label for this transform instance 
    internal TransformEnvironment( DataSpaceManager host, string instanceLabel )
    {
        transformHost = host;
        transformLabel = instanceLabel; 
    }
 
    ///  
    /// Whether this transform demands that all instance data of other
    /// transform above it in the transform stack be transformed too 
    /// 
    internal bool RequireOtherInstanceData
    {
        get 
        {
            return false; 
        } 
        set
        { 
            transformHost.CheckDisposedStatus();
            throw new NotSupportedException(
                SR.Get(SRID.NYIDefault));
        } 
    }
 
    ///  
    /// Whether this transform demands that its own instance data be
    /// free from other data transformation 
    /// 
    internal bool RequireInstanceDataUnaltered
    {
        get 
        {
            return false; 
        } 
        set
        { 
            transformHost.CheckDisposedStatus();
            throw new NotSupportedException(
                SR.Get(SRID.NYIDefault));
        } 
    }
 
    ///  
    /// Whether this transform requests that its own instance data be
    /// processed by other transforms below it in the stack 
    /// 
    internal bool DefaultInstanceDataTransform
    {
        get 
        {
            return false; 
        } 
        set
        { 
            transformHost.CheckDisposedStatus();
            throw new NotSupportedException(
                SR.Get(SRID.NYIDefault));
        } 
    }
 
    ///  
    ///     In the transform definition hashtable, we only have the normalized
    /// label as the key.  By digging our way to this property via the hashtable 
    /// value, we can recover the original label.
    /// 
    internal string TransformLabel
    { 
        get
        { 
            return transformLabel; 
        }
    } 

    /// 
    /// Returns the stream specific to this instance of the transform
    /// object, in which it can store any instance data it needs 
    /// 
    /// System.IO.Stream object for storing instance data 
    internal Stream GetPrimaryInstanceData() 
    {
        transformHost.CheckDisposedStatus(); 
        return transformHost.GetPrimaryInstanceStreamOf( transformLabel );
    }

    ///  
    /// When the primary instance data stream is insufficient, this returns
    /// a storage in which to store multiple streams that comprise the instance 
    /// data that this transform object wants to store. 
    /// 
    /// StorageInfo pointing to the storage that this transform is free to use 
    internal StorageInfo GetInstanceDataStorage()
    {
        transformHost.CheckDisposedStatus();
 
        StorageInfo storageInfo = transformHost.GetInstanceDataStorageOf( transformLabel );
 
        if (! storageInfo.Exists) 
        {
            storageInfo.Create(); 
        }

        return storageInfo;
    } 
}
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//   The object for manipulating data spaces within the WPP Package. 
//
// History: 
//  06/04/2002: RogerCh: Initial creation of class & method stubs.
//  06/17/2002: RogerCh: Initial implementation.
//  05/20/2003: RogerCh: Ported to WCP tree.
//  05/28/2003: RogerCh: Added long name support 
//
//----------------------------------------------------------------------------- 
 
using System;
using System.Collections; 
using System.Diagnostics;           // For Debug.Assert
using System.Globalization;
using System.IO;
using System.Reflection;            // For finding transform objects & their constructor 
using System.Security.Permissions;  // For StrongNameIdentityPermission
using System.Collections.Generic; 
 
using System.Windows;               // ExceptionStringTable
using MS.Internal.IO.Packaging; 
using MS.Internal.IO.Packaging.CompoundFile;
using CU = MS.Internal.IO.Packaging.CompoundFile.ContainerUtilities;

 
namespace System.IO.Packaging
{ 
///  
/// This class is used to manipulate the data spaces within a specific instance
/// of the Avalon container.  This is how data transform modules are plugged 
/// into the container to enable features like data compression and data
/// encryption.
/// 
internal class DataSpaceManager 
{
    /***********************************************************************/ 
    // Constants 

    // The header bytes that this version understands and supports 
    const int KnownBytesInMapTableHeader = 8; // Two Int32s == 8 bytes
    const int KnownBytesInDataSpaceDefinitionHeader = 8;
    const int KnownBytesInTransformDefinitionHeader = 8;
    const int AllowedExtraDataMaximumSize = 8192; // 8K 

    // Names for streams and storages within the container 
    const string DataSpaceStorageName = "\x0006DataSpaces"; 
    const string DataSpaceVersionName = "Version";
    const string DataSpaceMapTableName= "DataSpaceMap"; 
    const string DataSpaceDefinitionsStorageName = "DataSpaceInfo";
    const string TransformDefinitions = "TransformInfo";
    const string TransformPrimaryInfo = "\x0006Primary";
 
    // The string used in FormatVersion
    private static readonly string DataSpaceVersionIdentifier = "Microsoft.Container.DataSpaces"; 
 
    // Version Writer - 1.0, Reader - 1.0, Updater - 1.0
    private static readonly VersionPair DataSpaceCurrentWriterVersion  = new VersionPair(1 /*major*/, 0 /*minor*/); 
    private static readonly VersionPair DataSpaceCurrentReaderVersion  = new VersionPair(1 /*major*/, 0 /*minor*/);
    private static readonly VersionPair DataSpaceCurrentUpdaterVersion = new VersionPair(1 /*major*/, 0 /*minor*/);

    // The version information we read from the file 
    private FormatVersion _fileFormatVersion;
 
    private bool _dirtyFlag; 

    /***********************************************************************/ 
    // Data space manager instance values

    /// 
    /// There is only one data space manager per container instance.  This 
    /// points back to "our" reference.
    ///  
    StorageRoot _associatedStorage; 

    ///  
    /// Maps container references to data spaces
    ///
    /// Keys into this list are CompoundFileReference instances, each
    /// representing a subset of the container that is encoded with a 
    /// particular data space.
    /// 
    /// Values are strings, which are data space labels and can be used 
    /// as keys into _dataSpaceDefinitions for more details
    ///  
    SortedList _dataSpaceMap;

    /// 
    /// Extra data in the data space mapping table header is preserved 
    /// in this byte array.
    ///  
    byte[] _mapTableHeaderPreservation; 

    ///  
    /// Maps a data space name to a string array of transform names.
    ///
    /// Keys into this hash table are strings, each a unique label for
    /// a data space. 
    ///
    /// Values from this hash table are ArrayLists, each an array of 
    /// strings.  Each string is a data space label.  This transform 
    /// stack is stored in bottom-up order.  The first transform listed
    /// is the first to get the raw bytes from disk. 
    /// 
    Hashtable _dataSpaceDefinitions;

 
    /// 
    /// Maps a transform name to an instance of transform handle class 
    /// 
    /// Keys into this hash table are strings, each a unique label for
    /// a transform object instance. 
    ///
    /// Values from this hash table are references to the TransformInstance
    /// class defined below, each of which contains information for a
    /// particular transform instance. 
    /// 
    Hashtable _transformDefinitions; 
 
    /// 
    /// When shutting down, we need to flush each open transformed stream in 
    /// order to ensure that all encoding data has been propagated through
    /// the transform stack before we shut things down.  Otherwise we may leave
    /// data in a state where it could not be written out because parts of the
    /// transform stack has already been disposed. 
    /// 
    ArrayList _transformedStreams; 
 
    /// 
    /// Table of "well-known" -- that is, "built-in" -- transforms. The keys are 
    /// the TransformClassName identifier strings for the well-known transforms,
    /// such as encryption and compression. The values are the assembly-qualified
    /// .NET class names of the classes that implement the transforms.
    ///  
    static readonly Hashtable _transformLookupTable;
 
    /***********************************************************************/ 
    // Private class for tracking individual transform instances
 
    private class TransformInstance
    {
        // When we only know the CLR type name
        internal TransformInstance( int classType, string name ) : this(classType, name, null, null, null, null ) {;} 

        // When we also have an actual object in memory and its associated 
        //  environment object 
        internal TransformInstance(
            int classType, 
            string name,
            IDataTransform instance,
            TransformEnvironment environment ) : this(classType, name, instance, environment, null, null ) {;}
 
        // When we know everything to put into a TransformInstance.
        internal TransformInstance( 
            int classType, 
            string name,
            IDataTransform instance, 
            TransformEnvironment environment,
            Stream primaryStream,
            StorageInfo storage )
        { 
            typeName = name;
            transformReference = instance; 
            transformEnvironment = environment; 
            transformPrimaryStream = primaryStream;
            transformStorage = storage; 
            _classType = classType;
        }

        internal byte[] ExtraData 
        {
            get 
            { 
                return _extraData;
            } 

            set
            {
                _extraData = value; 
            }
        } 
 
        internal int ClassType
        { 
            get
            {
                return _classType;
            } 
        }
 
        ///  
        /// This is the CLR name used to define this transform.  Keep in
        /// mind that this is not necessarily what we retrieve when we 
        /// call Type.FullName or Type.AssemblyQualifiedName.  This is
        /// the name that needs to be persisted in the file because it is
        /// what the caller told us to use to find the type.
        ///  
        internal string          typeName;
 
        ///  
        /// If we have actually created the transform object, we keep
        /// a reference to it here.  This may be null if we haven't 
        /// had a need to create the transform object.
        /// 
        internal IDataTransform  transformReference;
 
        /// 
        /// The instance of TransformEnvironment that we created and 
        /// handed off to the transform object to tell us about things. 
        /// This can also be null, but only when transformReference is
        /// null.  It is not valid for only one of these two to be null, 
        /// either they're both null or they're both non-null.
        /// 
        internal TransformEnvironment transformEnvironment;
 
        /// 
        /// The stream that is the primary data storage for this instance 
        /// of the transform object. 
        /// 
        internal Stream transformPrimaryStream; 

        /// 
        /// The storage that is available if the transform object requires
        /// more than the primary stream 
        /// 
        internal StorageInfo transformStorage; 
 
        private int _classType;
        private byte[] _extraData; 
    }

    private class DirtyStateTrackingStream:  Stream
    { 

        //////////////////////////////////// 
        // Stream section 
        /////////////////////////////////
        public override bool CanRead 
        {
            get
            {
                return (_baseStream != null && _baseStream.CanRead); 
            }
        } 
 
        public override bool CanSeek
        { 
            get
            {
                return (_baseStream != null && _baseStream.CanSeek);
            } 
        }
 
        public override bool CanWrite 
        {
            get 
            {
                return (_baseStream != null && _baseStream.CanWrite);
            }
        } 

        public override long Length 
        { 
            get
            { 
                CheckDisposed();

                return  _baseStream.Length;
            } 
        }
 
        public override long Position 
        {
            get 
            {
                CheckDisposed();

                return _baseStream.Position; 
            }
 
            set 
            {
                CheckDisposed(); 

                _baseStream.Position = value;
            }
        } 

        public override void SetLength(long newLength) 
        { 
            CheckDisposed();
 
            if (newLength != _baseStream.Length)
            {
                _dirty = true;
            } 

            _baseStream.SetLength(newLength); 
        } 

        public override long Seek(long offset, SeekOrigin origin) 
        {
            CheckDisposed();

            return _baseStream.Seek(offset, origin); 
        }
 
        public override int Read(byte[] buffer, int offset, int count) 
        {
            CheckDisposed(); 

            return _baseStream.Read(buffer, offset, count);
        }
 
        public override void Write(byte[] buffer, int offset, int count)
        { 
            CheckDisposed(); 

            _baseStream.Write(buffer, offset, count); 
            _dirty = true;
        }

        public override void Flush() 
        {
            CheckDisposed(); 
 
            _baseStream.Flush();
        } 

        /////////////////////////////
        // Internal Constructor
        ///////////////////////////// 
        internal  DirtyStateTrackingStream(Stream baseStream)
        { 
            Debug.Assert(baseStream != null); 

            _baseStream = baseStream; 
        }

        internal bool DirtyFlag
        { 
            get
            { 
                return (_baseStream != null && _dirty); 
            }
        } 

        internal Stream BaseStream
        {
            get 
            {
                return _baseStream; 
            } 
        }
 
        //-----------------------------------------------------
        //
        //  Protected Methods
        // 
        //-----------------------------------------------------
        ///  
        /// Dispose(bool) 
        /// 
        ///  
        /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to
        /// call Dispose() instead of Close().
        protected override void Dispose(bool disposing)
        { 
            try
            { 
                if (disposing) 
                {
                    if (_baseStream != null) 
                        _baseStream.Close();
                }
            }
            finally 
            {
                _baseStream = null; 
                base.Dispose(disposing); 
            }
        } 

        /////////////////////////////
        // Private Methods
        ///////////////////////////// 

        private void CheckDisposed() 
        { 
            if (_baseStream == null)
            { 
                throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed));
            }
        }
 
        private bool _dirty;
        private Stream _baseStream; 
    } 

    private struct DataSpaceDefinition 
    {
        ArrayList _transformStack;
        Byte[]    _extraData;
 
        internal DataSpaceDefinition(ArrayList transformStack, Byte[] extraData)
        { 
            _transformStack = transformStack; 
            _extraData = extraData;
        } 

        internal ArrayList TransformStack
        {
            get 
            {
                return _transformStack; 
            } 
        }
 
        internal Byte[] ExtraData
        {
            get
            { 
                return _extraData;
            } 
        } 
    }
 
    /***********************************************************************/
    // Constructors

    ///  
    /// Static constructor that initializes the transformLookupTable (which see).
    ///  
    static DataSpaceManager() 
    {
        // Transform Identifier: we preserve casing, but do case-insensitive comparison 
        _transformLookupTable = new Hashtable(CU.StringCaseInsensitiveComparer);

        _transformLookupTable[RightsManagementEncryptionTransform.ClassTransformIdentifier]
            = "System.IO.Packaging.RightsManagementEncryptionTransform"; 
        _transformLookupTable[CompressionTransform.ClassTransformIdentifier]
            = "System.IO.Packaging.CompressionTransform"; 
    } 

    ///  
    /// Internally visible constructor
    /// 
    /// The container instance we're associated with
    internal DataSpaceManager( StorageRoot containerInstance ) 
    {
        _associatedStorage = containerInstance; 
 
        // Storage under which all data space information is stored.
        StorageInfo dataSpaceStorage = 
            new StorageInfo( _associatedStorage, DataSpaceStorageName );

        // Initialize internal data structures.
        // 
        _dataSpaceMap = new SortedList();
        _mapTableHeaderPreservation = new byte[0]; 
        _dataSpaceDefinitions = new Hashtable(CU.StringCaseInsensitiveComparer); 
        _transformDefinitions = new Hashtable(CU.StringCaseInsensitiveComparer);
        _transformedStreams = new ArrayList(); 

        // Check to see if we have any data space information to read
        if (dataSpaceStorage.Exists)
        { 
            // Read any existing data space mapping information from the container
            // 
            ReadDataSpaceMap(); 
            ReadDataSpaceDefinitions();
            ReadTransformDefinitions(); 
        }
        return;
    }
 
    /// 
    /// Returns the number of data spaces defined in this manager object 
    ///  
    internal int Count
    { 
        get
        {
            CheckDisposedStatus();
            return _dataSpaceMap.Count; 
        }
    } 
 
    private bool DirtyFlag
    { 
        get
        {
            if (_dirtyFlag)     // It is already dirty don't need to check further
                return true; 

            foreach( string transformDef in _transformDefinitions.Keys ) 
            { 
                TransformInstance transformInstance = GetTransformInstanceOf( transformDef );
                if (((DirtyStateTrackingStream) transformInstance.transformPrimaryStream).DirtyFlag) 
                {
                    return true;
                }
            } 

            return false; 
        } 
    }
 
    /// 
    /// Clean up the data space information and flush all data to the container.
    /// 
    public void Dispose() 
    {
        CheckDisposedStatus(); 
 
        // Flush any outstanding data in the transformed streams
        foreach( StreamWithDictionary dataStream in _transformedStreams ) 
        {
            if (!dataStream.Disposed)
                dataStream.Flush();
        } 
        _transformedStreams.Clear();
 
        // Now that all data have been flushed, shut down the transform 
        //  objects.
        foreach( object o in _transformDefinitions.Values ) 
        {
            IDataTransform idt = ((TransformInstance)o).transformReference;

            if( null != idt && 
                null != (idt as IDisposable))
            { 
                ((IDisposable)idt).Dispose(); 
            }
        } 

        // Now write the tables out.
        //
 
        if (FileAccess.Read != _associatedStorage.OpenAccess && DirtyFlag)
        { 
            WriteDataSpaceMap(); 
            WriteDataSpaceDefinitions();
            WriteTransformDefinitions(); 
        }

        _dataSpaceMap = null;
        _dataSpaceDefinitions = null; 
        _transformDefinitions = null;
 
        return; 
    }
 
    /// 
    /// Removes the container reference from the dataspace map. This is called when the container/substorage is getting deleted from the root storage. [DeleteSubStorage in StorageInfo]
    /// 
    internal void RemoveContainerFromDataSpaceMap(CompoundFileReference target) 
    {
       CheckDisposedStatus(); 
       if (_dataSpaceMap.Contains(target)) 
       {
            _dataSpaceMap.Remove(target); 
            _dirtyFlag = true;
       }
    }
 
    // Check to see if the dispose method has been called.  If so, throw an
    //  ObjectDisposedException. 
    internal void CheckDisposedStatus() 
    {
        // First check root 
        _associatedStorage.CheckRootDisposedStatus();

        // Check if we've been disposed
        if( null == _dataSpaceMap ) 
        {
            Debug.Assert( null == _dataSpaceDefinitions, 
                "Having a null data space map and a non-null data space definitions map is an inconsistent state" ); 
            Debug.Assert( null == _transformDefinitions,
                "Having a null data space map and a non-null transform definition map is an inconsistent state" ); 

            throw new ObjectDisposedException(null, SR.Get(SRID.DataSpaceManagerDisposed));
        }
    } 

    ///  
    /// Define a data space with the given stack of transform objects and 
    /// labeled with the given name.  The transform stack is interpreted in
    /// bottom-up order.  (Clear-text transform is last.) 
    /// 
    /// Transform stack
    /// New data space label
    internal void DefineDataSpace( string[] transformStack, string newDataSpaceLabel ) 
    {
        CheckDisposedStatus(); 
        // Data space must have at least one transform 
        if( null == transformStack ||
            0 == transformStack.Length ) 
            throw new ArgumentException(
                SR.Get(SRID.TransformStackValid));

        // Given label must be a non-empty string 
        CU.CheckStringAgainstNullAndEmpty(newDataSpaceLabel, "newDataSpaceLabel");
 
        // Given label must not be a reserved string 
        CU.CheckStringAgainstReservedName(newDataSpaceLabel, "newDataSpaceLabel");
 
        // Given label must not already be in use
        if( DataSpaceIsDefined( newDataSpaceLabel ) )
            throw new ArgumentException(
                SR.Get(SRID.DataSpaceLabelInUse)); 

        // Given transform array must include labels that have already been defined 
        foreach( string transformLabel in transformStack ) 
        {
            CU.CheckStringAgainstNullAndEmpty( transformLabel, "Transform label" ); 

            if( !TransformLabelIsDefined( transformLabel ) )
                throw new ArgumentException(
                    SR.Get(SRID.TransformLabelUndefined)); 
        }
 
        // Passes all inspection, data space definition successful. 
        SetDataSpaceDefinition( newDataSpaceLabel, new DataSpaceDefinition(new ArrayList(transformStack), null));
        _dirtyFlag = true; 

        return;
    }
 
    /// 
    /// Internal shortcut to check if data space is defined.  When we start 
    /// doing on-demand reads of data space definitions, the "demand" could 
    /// be triggered by this.
    ///  
    /// Label to check
    /// True if label is in use
    internal bool DataSpaceIsDefined( string dataSpaceLabel )
    { 
        CU.CheckStringAgainstNullAndEmpty(dataSpaceLabel, "dataSpaceLabel");
 
        return _dataSpaceDefinitions.Contains( dataSpaceLabel ); 
    }
 
    /// 
    ///     Central place to set a data space definition, centralizing the
    /// call to the name manager.
    ///  
    private void SetDataSpaceDefinition( string dataSpaceLabel, DataSpaceDefinition definition )
    { 
        _dataSpaceDefinitions[ dataSpaceLabel ] = definition; 
    }
 
    /// 
    ///     Central place to get a data space definition, centralizing the
    /// call to the name manager.
    ///  
    private DataSpaceDefinition GetDataSpaceDefinition( string dataSpaceLabel )
    { 
        return ((DataSpaceDefinition) _dataSpaceDefinitions[dataSpaceLabel]); 
    }
    ///  
    /// Internal method to retrieve the data space label corresponding to
    /// a container reference.  Returns null if no data space is associated.
    /// 
    /// CompoundFileReference whose data space label is to be retrieved 
    /// Data space label
    internal string DataSpaceOf( CompoundFileReference target ) 
    { 
        // Can't simply return _dataSpaceMap[target] because I need to cast it
        //  into a string, and if it's null the cast `blows up. 
        if( _dataSpaceMap.Contains(target) )
        {
            return (string)_dataSpaceMap[target];
        } 
        else
        { 
            return null; 
        }
    } 

    /// 
    /// This method returns all the transforms that are applied to a particular stream as an
    /// List of IDataTransform objects. 
    /// 
    /// StreamInfo for the stream whose transforms are requested 
    /// A List of IDataTransform objects that are applied to the stream represented by streamInfo 
    internal List GetTransformsForStreamInfo(StreamInfo streamInfo)
    { 
        string dataSpaces = this.DataSpaceOf(streamInfo.StreamReference);

        if (dataSpaces == null) // No datas pace is associated with the stream
        { 
            return new List(0);     // return an empty list
        } 
 
        ArrayList transformsList = this.GetDataSpaceDefinition(dataSpaces).TransformStack;
        List dataTransforms = new List(transformsList.Count); 

        for (int i = 0; i < transformsList.Count; i++)
        {
            dataTransforms.Add(this.GetTransformFromName(transformsList[i] as string)); 
        }
 
        return dataTransforms; 
    }
 
    /// 
    /// Define a data space with the given stack of transform objects and
    /// labeled with an auto-generated name
    ///  
    /// Transform stack
    /// The auto-generated label for this data space 
    internal string DefineDataSpace( string[] transformStack ) 
    {
        CheckDisposedStatus(); 
        Int64   timeSeed      = DateTime.Now.ToFileTime();
        string  generatedName = timeSeed.ToString(CultureInfo.InvariantCulture);

        // If there is a name collision, just keep incrementing the number 
        while( DataSpaceIsDefined( generatedName ) )
        { 
            timeSeed++; 
            generatedName = timeSeed.ToString(CultureInfo.InvariantCulture);
        } 

        // Submit the definition
        DefineDataSpace( transformStack, generatedName );
 
        return generatedName;
    } 
 
    /// 
    /// Tranform object is created. We are no longer using reflection to do this. We are supporting limited data transforms. 
    /// 
    private IDataTransform InstantiateDataTransformObject(int transformClassType,  string transformClassName, TransformEnvironment transformEnvironment )
    {
        object transformInstance = null; 

        if (transformClassType != (int) TransformIdentifierTypes_PredefinedTransformName) 
            throw new NotSupportedException(SR.Get(SRID.TransformTypeUnsupported)); 

        // Transform Identifier: we preserve casing, but do case-insensitive comparison 
        if (((IEqualityComparer) CU.StringCaseInsensitiveComparer).Equals(transformClassName,
                RightsManagementEncryptionTransform.ClassTransformIdentifier))
        {
            transformInstance = new RightsManagementEncryptionTransform( transformEnvironment); 
        }
        else if (((IEqualityComparer) CU.StringCaseInsensitiveComparer).Equals(transformClassName, 
                CompressionTransform.ClassTransformIdentifier)) 
        {
             transformInstance = new CompressionTransform( transformEnvironment ); 
        }
        else
        {
            //this transform class is not supported. Need to change this to appropriate error. 
            throw new ArgumentException(
                    SR.Get(SRID.TransformLabelUndefined)); 
        } 

        if (null != transformInstance) 
        {
            if( !( transformInstance is IDataTransform ) )
                throw new ArgumentException(
                    SR.Get(SRID.TransformObjectImplementIDataTransform)); 
            return (IDataTransform)transformInstance;
        } 
 
        return null;
    } 

    /// 
    /// Private method to check if a transform label is defined.  When we
    /// start reading transform defintions on-demand, we would probably do it 
    /// here as necessary.
    ///  
    /// Transform label to check 
    /// True if label is defined in hash table
    internal bool TransformLabelIsDefined( string transformLabel ) 
    {
        //

 
        return _transformDefinitions.Contains( transformLabel );
    } 
 
    /// 
    ///     Central place to set a transform definition, centralizing the 
    /// call to the name manager.
    /// 
    private void SetTransformDefinition( string transformLabel, TransformInstance definition )
    { 
        _transformDefinitions[ transformLabel ] = definition;
    } 
 
    /// 
    /// Private method to get the TransformInstance class representing 
    /// a transform instance.
    /// 
    private TransformInstance GetTransformInstanceOf( string transformLabel )
    { 
        Debug.Assert( TransformLabelIsDefined( transformLabel ),
            "Data space manager caller failed to verify transform exists before retrieving instance" ); 
 
        //
 


        return _transformDefinitions[ transformLabel ] as TransformInstance;
    } 

    ///  
    /// Internal method to get a MemoryStream whose contents will be 
    /// stored in the "\x0006Primary" data stream after our type identification
    /// information 
    /// 
    /// Transform Label
    /// Memory stream object for transform instance primary stream
    internal Stream GetPrimaryInstanceStreamOf( string transformLabel ) 
    {
        TransformInstance targetInstance = GetTransformInstanceOf( transformLabel ); 
 
        if( null == targetInstance.transformPrimaryStream )
        { 
            //build memory stream on the byte[0] , and allow writes only if
            // FileAccess is Write or ReadWrite
            if (_associatedStorage.OpenAccess == FileAccess.Read)
            { 
                targetInstance.transformPrimaryStream =
                    new DirtyStateTrackingStream (new MemoryStream 
                            (new byte[0], 
                            false /* Not writable */));
            } 
            else
            {
                targetInstance.transformPrimaryStream = new DirtyStateTrackingStream (new MemoryStream());
            } 
        }
 
        return targetInstance.transformPrimaryStream; 
    }
 
    /// 
    /// Internal method to get the StorageInfo where the transform instance
    /// data is stored.  This StorageInfo may not yet exist!
    ///  
    /// Transform Label
    /// StorageInfo pointing to transform instance data storage 
    internal StorageInfo GetInstanceDataStorageOf( string transformLabel ) 
    {
        TransformInstance targetInstance = GetTransformInstanceOf( transformLabel ); 

        if( null == targetInstance.transformStorage )
        {
            //string name = DataSpaceStorageName + '\\' + TransformDefinitions + '\\' + transformLabel; 

            //targetInstance.transformStorage  = new StorageInfo(_associatedStorage,name); 
 
            StorageInfo dataSpaceStorage = new StorageInfo( _associatedStorage, DataSpaceStorageName );
            if (!dataSpaceStorage.Exists ) 
            {
                dataSpaceStorage.Create();
            }
            StorageInfo transformDefinition = new StorageInfo( dataSpaceStorage, TransformDefinitions ); 
            if (!transformDefinition.Exists)
            { 
                transformDefinition.Create(); 
            }
            targetInstance.transformStorage  = new StorageInfo(transformDefinition,transformLabel); 
        }
        return targetInstance.transformStorage;
    }
 
    /// 
    /// Internal method to get the transform object corresponding to the specified 
    /// transform instance label. The transform object is created if it does not exist. 
    /// 
    ///  
    /// String that identifies the transform instance.
    /// 
    /// 
    /// An IDataTransform interface pointer to the transform object identified by 
    /// , or null if there is no such transform.
    ///  
    internal IDataTransform GetTransformFromName(string transformLabel) 
    {
        TransformInstance transformInstance = _transformDefinitions[transformLabel] as TransformInstance; 

        if (transformInstance == null)
        {
            // 
            // There is no transform instance with the specified name.
            // 
            return null; 
        }
 
        IDataTransform transformObject = transformInstance.transformReference;
        if (transformObject == null)
        {
            // 
            // There is a transform instance with the specified name, but its transform
            // object has not yet been created. Create it now. This code is modeled on the 
            // code in DefineTransform. 
            //
            TransformEnvironment transformEnvironment = new TransformEnvironment(this, transformLabel); 

            // Create the transform object.
            transformObject = InstantiateDataTransformObject(
                                    transformInstance.ClassType, 
                                    transformInstance.typeName,
                                    transformEnvironment); 
            transformInstance.transformReference = transformObject; 
        }
 
        return transformObject;
    }

    ///  
    /// Define a data transform object with the given object identification and
    /// labeled with the given name. 
    ///  
    /// Transform identification string
    /// Label to use for new transform 
    internal void DefineTransform(string transformClassName, string newTransformLabel )
    {
        CheckDisposedStatus();
 
        // Check to see if transform name is obviously invalid
        CU.CheckStringAgainstNullAndEmpty( transformClassName, "Transform identifier name" ); 
 
        // Check to see if transform name is valid
        CU.CheckStringAgainstNullAndEmpty( newTransformLabel, "Transform label" ); 

        // Given transform name must not be a reserved string
        CU.CheckStringAgainstReservedName( newTransformLabel, "Transform label" );
 
        // Can't re-use an existing transform name
        if( TransformLabelIsDefined( newTransformLabel ) ) 
            throw new ArgumentException( 
                SR.Get(SRID.TransformLabelInUse));
 
        // Create class the transform object will use to communicate to us
        TransformEnvironment transformEnvironment = new TransformEnvironment( this, newTransformLabel );

        // Create a TransformInstance object to represent this transform instance. 
        TransformInstance newTransform = new TransformInstance(
            TransformIdentifierTypes_PredefinedTransformName, 
            transformClassName, 
            null,
            transformEnvironment ); 

        SetTransformDefinition( newTransformLabel, newTransform );

        // Create the transform object 
        IDataTransform transformObject = InstantiateDataTransformObject(
                                                    TransformIdentifierTypes_PredefinedTransformName, 
                                                    transformClassName, 
                                                    transformEnvironment );
        newTransform.transformReference = transformObject; 

        // If transform is not ready out-of-the-box, do an initialization run.
        //  Note: Transform is not required to be "ready" after this.  This is
        //  done for those transforms that need initialization work up-front. 
        if( ! transformObject.IsReady )
        { 
            CallTransformInitializers( 
                new TransformInitializationEventArgs(
                    transformObject, 
                    null,
                    null,
                    newTransformLabel)
                ); 
        }
 
        _dirtyFlag = true; 

        return; 
    }

    /// 
    /// Define a data transform object with the given object identification and 
    /// labeled with an auto-generated name.
    ///  
    /// Transform identification string 
    /// The auto-generated label for this transform
    internal string DefineTransform( string transformClassName ) 
    {
        CheckDisposedStatus();
        Int64   timeSeed      = DateTime.Now.ToFileTime();
        string generatedName = timeSeed.ToString(CultureInfo.InvariantCulture); 

        // If there is a name collision, just keep incrementing the number 
        while( TransformLabelIsDefined( generatedName ) ) 
        {
            timeSeed++; 
            generatedName = timeSeed.ToString(CultureInfo.InvariantCulture);
        }

        // Submit the definition 
        DefineTransform( transformClassName, generatedName );
 
        return generatedName; 
    }
 
    //+----------------------------------------------------------------------
    //  Transform initialization event/delegate/etc.

    ///  
    ///     Delegate method for initializing transforms
    ///  
    internal delegate void TransformInitializeEventHandler( 
        object sender,
        TransformInitializationEventArgs e ); 

    /// 
    ///     Transform initialization event
    ///  
    internal event TransformInitializeEventHandler OnTransformInitialization;
 
    ///  
    /// Internal shortcut to kick off all the initializers
    ///  
    /// Arguments for the initializers
    internal void CallTransformInitializers( TransformInitializationEventArgs initArguments )
    {
        if( null != OnTransformInitialization ) 
            OnTransformInitialization( this, initArguments );
    } 
 
    /// 
    /// Reads a data space map from the associated container, if such a thing 
    /// is written to the file.
    /// 
    void ReadDataSpaceMap()
    { 
        // See if there's even a data spaces storage
        StorageInfo dataSpaceStorage = 
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StreamInfo dataSpaceMapStreamInfo =
            new StreamInfo( dataSpaceStorage, DataSpaceMapTableName ); 

        if( dataSpaceStorage.StreamExists(DataSpaceMapTableName) )
        {
            // There is an existing data space mapping table to read. 

            // Read the versioning information 
            ReadDataSpaceVersionInformation(dataSpaceStorage); 

            // Check if its the correct version for reading 
            ThrowIfIncorrectReaderVersion();

            // Read the data space mapping table
            using(Stream dataSpaceMapStream = dataSpaceMapStreamInfo.GetStream(FileMode.Open)) 
            {
                using(BinaryReader dataSpaceMapReader = 
                    new BinaryReader( dataSpaceMapStream, System.Text.Encoding.Unicode )) 
                {
                    int headerLength = dataSpaceMapReader.ReadInt32(); 
                    int entryCount = dataSpaceMapReader.ReadInt32();

                    if (headerLength < KnownBytesInMapTableHeader || entryCount < 0)
                        throw new FileFormatException(SR.Get(SRID.CorruptedData)); 

                    int extraDataSize = headerLength - KnownBytesInMapTableHeader; 
 
                    if( 0 < extraDataSize )
                    { 
                        if (extraDataSize > AllowedExtraDataMaximumSize)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));

                        _mapTableHeaderPreservation = dataSpaceMapReader.ReadBytes(extraDataSize); 

                        if (_mapTableHeaderPreservation.Length != extraDataSize) 
                            throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
                    }
 
                    _dataSpaceMap.Capacity = entryCount;

                    int entryLength;
                    int bytesRead; 
                    int totalBytesRead;
 
                    for( int i = 0; i < entryCount; i++ ) 
                    {
                        entryLength = dataSpaceMapReader.ReadInt32(); 

                        if (entryLength < 0)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));
 
                        totalBytesRead = 4; // entryLength
                        // Read the container reference entry 
                        CompoundFileReference entryRef = 
                            CompoundFileReference.Load( dataSpaceMapReader, out bytesRead );
                        checked { totalBytesRead += bytesRead; } 

                        // Read data space string and add to data space mapping table
                        string label = CU.ReadByteLengthPrefixedDWordPaddedUnicodeString(dataSpaceMapReader, out bytesRead);
                        checked { totalBytesRead += bytesRead; } 

                        _dataSpaceMap[entryRef] = label; 
 
                        // Verify entryLength against what was actually read:
                        if (entryLength != totalBytesRead) 
                        {
                            throw new IOException(SR.Get(SRID.DataSpaceMapEntryInvalid));
                        }
                    } 
                }
            } 
        } 
    }
 
    /// 
    /// Write the data space mapping table to underlying storage.
    /// 
    void WriteDataSpaceMap() 
    {
        ThrowIfIncorrectUpdaterVersion(); 
 
        StorageInfo dataSpaceStorage =
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StreamInfo dataSpaceMapStreamInfo =
            new StreamInfo ( dataSpaceStorage, DataSpaceMapTableName );

        if( 0 < _dataSpaceMap.Count ) 
        {
            // Write versioning information 
            StreamInfo versionStreamInfo = null; 
            if (dataSpaceStorage.StreamExists( DataSpaceVersionName ) )
                versionStreamInfo = dataSpaceStorage.GetStreamInfo( DataSpaceVersionName ); 
            else
                versionStreamInfo = dataSpaceStorage.CreateStream( DataSpaceVersionName );
            Stream versionStream = versionStreamInfo.GetStream();
            _fileFormatVersion.SaveToStream(versionStream); 
            versionStream.Close();
 
            // Create stream for write, overwrite any existing 
            using(Stream dataSpaceMapStream = dataSpaceMapStreamInfo.GetStream(FileMode.Create))
            { 
                using(BinaryWriter dataSpaceMapWriter =
                    new BinaryWriter( dataSpaceMapStream, System.Text.Encoding.Unicode ))
                {
                    // Write header 

                    // header length = our known size + preserved array size 
                    dataSpaceMapWriter.Write( 
                        checked ((Int32) (KnownBytesInMapTableHeader + _mapTableHeaderPreservation.Length)));
                    // number of entries 
                    dataSpaceMapWriter.Write(
                        _dataSpaceMap.Count );
                    // anything else we've preserved
                    dataSpaceMapWriter.Write( 
                        _mapTableHeaderPreservation );
 
                    // Loop to write entries 
                    foreach( CompoundFileReference o in _dataSpaceMap.Keys )
                    { 
                        // determine the entry length
                        string label = (string)_dataSpaceMap[o];
                        int entryLength = CompoundFileReference.Save(o, null);
 
                        checked { entryLength += CU.WriteByteLengthPrefixedDWordPaddedUnicodeString(null, label); }
 
                        // length of entryLength itself 
                        checked { entryLength += 4; }
 
                        // write out the entry length
                        dataSpaceMapWriter.Write((Int32) entryLength);

                        // Write out reference 
                        CompoundFileReference.Save( o, dataSpaceMapWriter);
 
                        // Write out dataspace label 
                        CU.WriteByteLengthPrefixedDWordPaddedUnicodeString(
                            dataSpaceMapWriter, label); 
                    }
                }
            }
        } 
        else
        { 
            // data space map is empty, remove existing stream if there. 
            if ( dataSpaceStorage.StreamExists( DataSpaceMapTableName ) )
                dataSpaceStorage.DeleteStream( DataSpaceMapTableName ); 
        }
    }

    ///  
    /// Read all data space definitions in one chunk.  To be replaced
    /// with on-demand reading mechanism. 
    ///  
    void ReadDataSpaceDefinitions()
    { 
        ThrowIfIncorrectReaderVersion();

        StorageInfo dataSpaceStorage =
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StorageInfo dataSpaceDefinitionsStorage =
            new StorageInfo( dataSpaceStorage, DataSpaceDefinitionsStorageName ); 
 
        if( dataSpaceDefinitionsStorage.Exists )
        { 
            // Fill in the Data Space Definitions hash table
            foreach( StreamInfo definitionStreamInfo in dataSpaceDefinitionsStorage.GetStreams())
            {
                // Open up the stream for this data space definition 
                using(Stream definitionStream = definitionStreamInfo.GetStream(FileMode.Open))
                { 
                    using(BinaryReader definitionReader = new BinaryReader( definitionStream, System.Text.Encoding.Unicode )) 
                    {
                        // Read data space definition stream 
                        int headerLength = definitionReader.ReadInt32();
                        int transformCount = definitionReader.ReadInt32();

                        if (headerLength < KnownBytesInDataSpaceDefinitionHeader || transformCount < 0) 
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));
 
                        ArrayList transformLabels = new ArrayList(transformCount); 
                        byte[] extraData = null;
                        int extraDataSize = headerLength - KnownBytesInDataSpaceDefinitionHeader; 

                        if (extraDataSize > AllowedExtraDataMaximumSize)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));
 
                        if (extraDataSize > 0)
                        { 
                            extraData = definitionReader.ReadBytes(extraDataSize); 

                            if (extraData.Length != extraDataSize) 
                                throw new FileFormatException(SR.Get(SRID.CorruptedData));
                        }

                        // Read the array of strings that make up the transform stack 
                        for( int i = 0; i < transformCount; i++ )
                        { 
                            transformLabels.Add( 
                                CU.ReadByteLengthPrefixedDWordPaddedUnicodeString( definitionReader ) );
                        } 

                        // Add data space definition to table
                        SetDataSpaceDefinition( definitionStreamInfo.Name, new DataSpaceDefinition(transformLabels, extraData));
                    } 
                }
            } 
        } 
    }
 
    /// 
    /// Write all data space definitions to underlying storage in one chunk.
    /// 
    /// 
    //
    void WriteDataSpaceDefinitions() 
    { 
        ThrowIfIncorrectUpdaterVersion();
 
        StorageInfo dataSpaceStorage =
            new StorageInfo( _associatedStorage, DataSpaceStorageName );

        // 

 
 
        // Write out data space definitions
        if( 0 < _dataSpaceDefinitions.Count ) 
        {

            StorageInfo dataSpaceDefinitionsStorage =
                new StorageInfo(dataSpaceStorage, DataSpaceDefinitionsStorageName); 
            dataSpaceDefinitionsStorage.Create();
 
            foreach( string name in _dataSpaceDefinitions.Keys ) 
            {
                StreamInfo singleDefinitionInfo = 
                    new StreamInfo(dataSpaceDefinitionsStorage,name);

                using(Stream singleDefinition = singleDefinitionInfo.GetStream())
                { 
                    using(BinaryWriter definitionWriter =new BinaryWriter( singleDefinition, System.Text.Encoding.Unicode ))
                    { 
                        DataSpaceDefinition definition = (DataSpaceDefinition) _dataSpaceDefinitions[name]; 

                        int headerSize = KnownBytesInDataSpaceDefinitionHeader; 

                        if (definition.ExtraData != null)
                        {
                            checked { headerSize += definition.ExtraData.Length; } 
                        }
                        definitionWriter.Write( headerSize ); 
                        definitionWriter.Write( definition.TransformStack.Count ); 
                        if (definition.ExtraData != null)
                        { 
                            definitionWriter.Write(definition.ExtraData);
                        }

                        foreach( object transformLabel in definition.TransformStack) 
                        {
                            CU.WriteByteLengthPrefixedDWordPaddedUnicodeString( 
                                definitionWriter, (string)transformLabel); 
                        }
                    } 
                }
            }
        }
    } 

    ///  
    /// Read all transform definitions in one chunk 
    /// 
    // 

    void ReadTransformDefinitions()
    {
        ThrowIfIncorrectReaderVersion(); 

        StorageInfo dataSpaceStorage = 
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StorageInfo transformDefinitionsStorage =
            new StorageInfo( dataSpaceStorage, TransformDefinitions ); 

        if( transformDefinitionsStorage.Exists )
        {
            // Read transform definitions from file 
            foreach( StorageInfo transformStorage in transformDefinitionsStorage.GetSubStorages() )
            { 
                // Read from primary stream 
                StreamInfo transformPrimary = new StreamInfo(
                    transformStorage, TransformPrimaryInfo ); 

                using(Stream transformDefinition = transformPrimary.GetStream(FileMode.Open))
                {
                    using(BinaryReader definitionReader = new BinaryReader( transformDefinition, System.Text.Encoding.Unicode )) 
                    {
                        int headerLength = definitionReader.ReadInt32(); // We don't actually do anything with HeaderLen at the moment 
                        int transformType = definitionReader.ReadInt32(); 

                        if (headerLength < 0) 
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));

                        // Create a TransformInstance class using name from file
                        TransformInstance transformInstance = 
                            new TransformInstance(transformType, CU.ReadByteLengthPrefixedDWordPaddedUnicodeString( definitionReader ) );
 
 
                        int extraDataSize = checked ((int) (headerLength - transformDefinition.Position));
 
                        if (extraDataSize < 0)
                            throw new FileFormatException(SR.Get(SRID.CorruptedData));

                        if (extraDataSize > 0) 
                        {
                            if (extraDataSize > AllowedExtraDataMaximumSize) 
                                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 

                            // Preserve the fields we don't know about. 
                            byte[] extraData = definitionReader.ReadBytes(extraDataSize);

                            if (extraData.Length != extraDataSize)
                                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 

                            transformInstance.ExtraData = extraData; 
                        } 

                        if( transformDefinition.Length > transformDefinition.Position ) 
                        {
                            // We have additional data in the primary instance data stream
                            int instanceDataSize = checked ((int)(transformDefinition.Length - transformDefinition.Position));
                            byte[] instanceData = new byte[instanceDataSize]; 
                            PackagingUtilities.ReliableRead(transformDefinition, instanceData, 0, instanceDataSize);
 
                            //build memory stream on the byte[] , and allow writes only if 
                            // FileAccess is Write or ReadWrite
                            MemoryStream instanceDataStream; 
                            if (_associatedStorage.OpenAccess == FileAccess.Read)
                            {
                                //  NOTE: Building MemoryStream directly on top of
                                //  instanceData byte array because we want it to be 
                                //  NOT resizable and NOT writable.
                                instanceDataStream = new MemoryStream(instanceData, false /* Not writable */); 
                            } 
                            else
                            { 
                                // Copy additional data into a memory stream
                                //  NOTE: Not building MemoryStream directly on top of
                                //  instanceData byte array because we want it to be
                                //  resizable. 
                                instanceDataStream = new MemoryStream();
                                instanceDataStream.Write( instanceData, 0, instanceDataSize ); 
                            } 
                            instanceDataStream.Seek( 0, SeekOrigin.Begin );
 
                            // Dirty state should be tracked after the original data is read in from the disk into the memory stream
                            transformInstance.transformPrimaryStream = new DirtyStateTrackingStream(instanceDataStream);
                        }
 
                        transformInstance.transformStorage = transformStorage;
 
                        SetTransformDefinition( transformStorage.Name, transformInstance ); 
                    }
                } 
            }
        }
    }
 
    /// 
    /// Write out all transform definitions all at once 
    ///  
    ///
    // 

    void WriteTransformDefinitions()
    {
        ThrowIfIncorrectUpdaterVersion(); 

        StorageInfo dataSpaceStorage = 
            new StorageInfo( _associatedStorage, DataSpaceStorageName ); 
        StorageInfo transformDefinitionsStorage =
            new StorageInfo( dataSpaceStorage, TransformDefinitions ); 

        //

 

        if( 0 < _transformDefinitions.Count ) 
        { 
            foreach( string transformDef in _transformDefinitions.Keys )
            { 
                // 'transformDef' is the normalized label.  We need to dig a
                //  bit to retrieve the original transform label.
                string transformLabel = null;
                TransformInstance transformInstance = GetTransformInstanceOf( transformDef ); 
                Debug.Assert( transformInstance != null, "A transform instance should be available if its name is in the transformDefinitions hashtable");
 
                if( transformInstance.transformEnvironment != null ) 
                {
                    // We have a transform environment object - it has the transform label. 
                    transformLabel = transformInstance.transformEnvironment.TransformLabel;
                }
                else
                { 
                    // We don't have a transform environment object - we'll need to do a
                    //  more expensive reverse-lookup with the name manager. 
                    transformLabel = transformDef; 
                }
 
                // Now use transformLabel to create the storage.
                StorageInfo singleTransformStorage =
                    new StorageInfo( transformDefinitionsStorage, transformLabel );
                StreamInfo transformPrimaryInfo = 
                    new StreamInfo( singleTransformStorage, TransformPrimaryInfo );
 
                using(Stream transformPrimary = transformPrimaryInfo.GetStream()) 
                {
                    using(BinaryWriter transformWriter = new BinaryWriter( transformPrimary, System.Text.Encoding.Unicode )) 
                    {
                        // Header length size = Known (the number itself + identifier) +
                        //  to be calculated (length of type name)
                        int headerLength = checked (KnownBytesInTransformDefinitionHeader + 
                                                CU.WriteByteLengthPrefixedDWordPaddedUnicodeString( null, transformInstance.typeName));
 
                        if (transformInstance.ExtraData != null) 
                        {
                            Debug.Assert(transformInstance.ExtraData.Length > 0); 

                            checked { headerLength += transformInstance.ExtraData.Length; }
                        }
 
                        transformWriter.Write(headerLength);
 
                        transformWriter.Write((int)TransformIdentifierTypes_PredefinedTransformName); 
                        CU.WriteByteLengthPrefixedDWordPaddedUnicodeString(
                            transformWriter, transformInstance.typeName); 

                        // Write out the preserved unknown data if there are some
                        if (transformInstance.ExtraData != null)
                        { 
                            transformWriter.Write(transformInstance.ExtraData);
                        } 
 
                        if( null != transformInstance.transformPrimaryStream )
                        { 
                            byte[] memoryBuffer = ((MemoryStream) ((DirtyStateTrackingStream) transformInstance.transformPrimaryStream).BaseStream).GetBuffer();
                            transformPrimary.Write( memoryBuffer, 0, memoryBuffer.Length );
                        }
                    } 
                }
            } 
        } 
        else // No transform definitions
        { 
            if ( transformDefinitionsStorage.Exists)
            {
                dataSpaceStorage.Delete(true, TransformDefinitions);
                //transformDefinitionStorage.Delete(true); 
            }
        } 
    } 

    ///  
    /// Internal method to create an entry in the data space mapping table
    /// 
    /// Package reference describing the scope of the data space
    /// Label of the data space definition 
    internal void CreateDataSpaceMapping( CompoundFileReference containerReference, string label )
    { 
        Debug.Assert( DataSpaceIsDefined( label ), 
            "Internal method illegally defining a data space reference on a data space that has not yet been defined");
        _dataSpaceMap[containerReference] = label; 
        _dirtyFlag = true;
    }

    ///  
    /// Internal method to create the actual transform stack of streams which
    /// will handle the encoding and decoding 
    ///  
    /// Package reference for the data space stream
    /// Stream with raw bytes on disk 
    /// Stream with clear text
    internal Stream CreateDataSpaceStream( CompoundFileStreamReference containerReference , Stream rawStream )
    {
        Stream outputStream = rawStream; 
        // RightsManagementEncryptionTransform and CompressionTransform do not use transformContext
        IDictionary transformContext = new Hashtable(); // Transform context object 
 
        // See which data space we're creating this stream in
        string dataSpaceLabel = _dataSpaceMap[containerReference] as string; 
        Debug.Assert( null != dataSpaceLabel,
            "Internal caller has asked to create a data space stream but the reference is not associated with a data space" );

        // Retrieve the transform object stack 
        ArrayList transformStack = GetDataSpaceDefinition(dataSpaceLabel).TransformStack;
        Debug.Assert( null != transformStack, 
            "Internal inconsistency - data space name does not have a transform stack definition" ); 

        // Iterate the initialization process for each transform on the stack 
        foreach( string transformLabel in transformStack )
        {
            // Get information on this layer of the transform stack
            TransformInstance transformLayer = GetTransformInstanceOf( transformLabel ); 
            Debug.Assert( null != transformLayer, "Data space definition included an undefined transform" );
 
            // If we haven't gotten around to creating the transform object, go do it. 
            if( null == transformLayer.transformReference )
            { 
                transformLayer.transformEnvironment = new TransformEnvironment( this, transformLabel );

                transformLayer.transformReference = InstantiateDataTransformObject(
                                                        transformLayer.ClassType, 
                                                        transformLayer.typeName,
                                                        transformLayer.transformEnvironment ); 
            } 
            Debug.Assert( null != transformLayer.transformReference,
                "Failed to have a transform instance going in" ); 
            IDataTransform transformObject = transformLayer.transformReference;

            // If transform is not ready, call initializers to make it ready.
            if( ! transformObject.IsReady ) 
            {
                CallTransformInitializers( 
                    new TransformInitializationEventArgs( 
                        transformObject,
                        dataSpaceLabel, 
                        containerReference.FullName,
                        transformLabel)
                    );
 
                if( ! transformObject.IsReady ) // If STILL not ready, nobody could make it "ready".
                    throw new InvalidOperationException( 
                        SR.Get(SRID.TransformObjectInitFailed)); 
            }
            // Everything is setup, get a transformed stream 
            outputStream = transformObject.GetTransformedStream( outputStream, transformContext );
        }

        outputStream = new BufferedStream( outputStream ); // Add buffering layer 

        outputStream = new StreamWithDictionary( outputStream, transformContext ); 
 
        _transformedStreams.Add( outputStream ); // Remember this for later use
 
        return outputStream;
    }

    ///  
    /// When naming a transform object, the string being passed in can be
    /// interpreted in one of several ways.  This enumerated type is used 
    /// to specify the semantics of the identification string. 
    ///
    /// The transform identification string is key into a table of 
    ///  well-known transform definitions.
    /// 
    internal const int TransformIdentifierTypes_PredefinedTransformName = 1;
 
    #region Version Methods
 
    ///  
    /// Read the version information that specifies the minimum versions of the
    /// DataSpaceManager software that can read, write, or update the data space 
    /// information in this file.
    /// 
    /// 
    ///  
    /// If the format version information in the stream is corrupt.
    ///  
    private void ReadDataSpaceVersionInformation(StorageInfo dataSpaceStorage) 
    {
        if (_fileFormatVersion == null) 
        {
            if (dataSpaceStorage.StreamExists( DataSpaceVersionName ))
            {
                StreamInfo versionStreamInfo = dataSpaceStorage.GetStreamInfo( DataSpaceVersionName ); 
                using (Stream versionStream = versionStreamInfo.GetStream(FileMode.Open))
                { 
                    _fileFormatVersion = FormatVersion.LoadFromStream(versionStream); 

                    // Transform Identifier: we preserve casing, but do case-insensitive comparison 
                    //Case-insensitive comparison. As per recommendations, we convert both strings
                    //to Upper case and then compare with StringComparison.Ordinal
                    if (!((IEqualityComparer) CU.StringCaseInsensitiveComparer).Equals(_fileFormatVersion.FeatureIdentifier,
                                       DataSpaceVersionIdentifier)) 
                    {
                        throw new FileFormatException( 
                                            SR.Get(SRID.InvalidTransformFeatureName, 
                                            _fileFormatVersion.FeatureIdentifier,
                                            DataSpaceVersionIdentifier)); 
                    }
                    // If we ever write this version number out again, we will want to record
                    // the fact that it was done by the current version of the Dataspace software.
                    _fileFormatVersion.WriterVersion = DataSpaceCurrentWriterVersion; 
                }
            } 
        } 
    }
 
    /// 
    /// If the DataSpace version information was not present in the file, we initialize it with the
    /// values for the current DataSpace software.
    /// If the information was present we should have already read it as a part of the ReadDataSpaceMap. 
    /// 
    private void EnsureDataSpaceVersionInformation() 
    { 
        if (_fileFormatVersion == null)
        { 
            _fileFormatVersion = new FormatVersion(
                                        DataSpaceVersionIdentifier,
                                        DataSpaceCurrentWriterVersion,
                                        DataSpaceCurrentReaderVersion, 
                                        DataSpaceCurrentUpdaterVersion
                                     ); 
        } 
    }
 
    /// 
    /// Verify that the current version of this class can read the DataSpace information in
    /// this file.
    ///  
    /// 
    /// If the current version of this class cannot read the DataSpace information in this file. 
    ///  
    private void ThrowIfIncorrectReaderVersion()
    { 
        EnsureDataSpaceVersionInformation();

        if (!_fileFormatVersion.IsReadableBy(DataSpaceCurrentReaderVersion))
        { 
            throw new FileFormatException(
                            SR.Get( 
                                SRID.ReaderVersionError, 
                                _fileFormatVersion.ReaderVersion,
                                DataSpaceCurrentReaderVersion 
                                )
                            );
        }
    } 

    ///  
    /// Verify that the current version of this class can update the DataSpace information in 
    /// this file.
    ///  
    /// 
    /// If the current version of this class cannot update the DataSpace information in this file,
    /// or if the header information in the stream is corrupt.
    ///  
    private void ThrowIfIncorrectUpdaterVersion()
    { 
        EnsureDataSpaceVersionInformation(); 

        if (!_fileFormatVersion.IsUpdatableBy(DataSpaceCurrentUpdaterVersion)) 
        {
            throw new FileFormatException(
                            SR.Get(
                                SRID.UpdaterVersionError, 
                                _fileFormatVersion.UpdaterVersion,
                                DataSpaceCurrentUpdaterVersion 
                                ) 
                            );
        } 
    }

    #endregion Version Methods
} 

///  
/// Interface to be implemented by all data transform objects 
/// 
internal interface IDataTransform 
{
    /// 
    /// Whether this transform is ready to perform.  If false, it needs
    /// further initialization. 
    /// 
    bool IsReady { get; } 
 
    /// 
    /// Whether this transform is in a stable state 
    /// 
    bool FixedSettings { get; }

    ///  
    /// Data transform identifier object
    ///  
    object TransformIdentifier { get; } 

    ///  
    /// Given a stream for storing the encoded data, return a stream for
    /// manipulating the "cleartext" data.
    /// 
    Stream GetTransformedStream( Stream encodedDataStream, IDictionary transformContext ); 
}
 
///  
/// Internal class for passing arguments into event handlers
///  
internal class TransformInitializationEventArgs : EventArgs
{
    IDataTransform  dataInstance;
    string          dataSpaceLabel; 
    string          streamPath;
    string          transformLabel; 
 
    internal TransformInitializationEventArgs(
        IDataTransform instance, 
        string dataSpaceInstanceLabel,
        string transformedStreamPath,
        string transformInstanceLabel )
    { 
        dataInstance = instance;
        dataSpaceLabel = dataSpaceInstanceLabel; 
        streamPath = transformedStreamPath; 
        transformLabel = transformInstanceLabel;
    } 
    /// 
    /// Reference to the data object that requires initialization
    /// 
    internal IDataTransform DataTransform 
    {
        get 
        { 
            return dataInstance;
        } 
    }

    /// 
    /// Label for the data space whose initialization this is a part of 
    /// 
    internal string DataSpaceLabel 
    { 
        get
        { 
            return dataSpaceLabel;
        }
    }
 
    /// 
    /// The path to the stream whose use initiated this process 
    ///  
    internal string Path
    { 
        get
        {
            return streamPath;
        } 
    }
 
    ///  
    /// Label for the transform object instance being initialized
    ///  
    internal string TransformInstanceLabel
    {
        get
        { 
            return transformLabel;
        } 
    } 
}
 
/// 
/// An instance of this class is given to each transform object as a
/// means for the transform object to interact with the environment
/// provided by the data space manager.  It is not mandatory for a 
/// transform object to keep a reference on the given TransformEnvironment
/// object  it may choose to discard it if there is no need to interact 
/// with the transform environment. 
/// 
internal  class TransformEnvironment 
{
    DataSpaceManager transformHost;
    string  transformLabel;
 
    /// 
    /// This object is only created internally by the data space manager. 
    ///  
    /// The data space manager who created this class
    /// Text label for this transform instance 
    internal TransformEnvironment( DataSpaceManager host, string instanceLabel )
    {
        transformHost = host;
        transformLabel = instanceLabel; 
    }
 
    ///  
    /// Whether this transform demands that all instance data of other
    /// transform above it in the transform stack be transformed too 
    /// 
    internal bool RequireOtherInstanceData
    {
        get 
        {
            return false; 
        } 
        set
        { 
            transformHost.CheckDisposedStatus();
            throw new NotSupportedException(
                SR.Get(SRID.NYIDefault));
        } 
    }
 
    ///  
    /// Whether this transform demands that its own instance data be
    /// free from other data transformation 
    /// 
    internal bool RequireInstanceDataUnaltered
    {
        get 
        {
            return false; 
        } 
        set
        { 
            transformHost.CheckDisposedStatus();
            throw new NotSupportedException(
                SR.Get(SRID.NYIDefault));
        } 
    }
 
    ///  
    /// Whether this transform requests that its own instance data be
    /// processed by other transforms below it in the stack 
    /// 
    internal bool DefaultInstanceDataTransform
    {
        get 
        {
            return false; 
        } 
        set
        { 
            transformHost.CheckDisposedStatus();
            throw new NotSupportedException(
                SR.Get(SRID.NYIDefault));
        } 
    }
 
    ///  
    ///     In the transform definition hashtable, we only have the normalized
    /// label as the key.  By digging our way to this property via the hashtable 
    /// value, we can recover the original label.
    /// 
    internal string TransformLabel
    { 
        get
        { 
            return transformLabel; 
        }
    } 

    /// 
    /// Returns the stream specific to this instance of the transform
    /// object, in which it can store any instance data it needs 
    /// 
    /// System.IO.Stream object for storing instance data 
    internal Stream GetPrimaryInstanceData() 
    {
        transformHost.CheckDisposedStatus(); 
        return transformHost.GetPrimaryInstanceStreamOf( transformLabel );
    }

    ///  
    /// When the primary instance data stream is insufficient, this returns
    /// a storage in which to store multiple streams that comprise the instance 
    /// data that this transform object wants to store. 
    /// 
    /// StorageInfo pointing to the storage that this transform is free to use 
    internal StorageInfo GetInstanceDataStorage()
    {
        transformHost.CheckDisposedStatus();
 
        StorageInfo storageInfo = transformHost.GetInstanceDataStorageOf( transformLabel );
 
        if (! storageInfo.Exists) 
        {
            storageInfo.Create(); 
        }

        return storageInfo;
    } 
}
} 

// 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