File: Base\System\IO\Packaging\EncryptedPackage.cs
Project: wpf\src\WindowsBase.csproj (WindowsBase)
//-----------------------------------------------------------------------------
//
// <copyright file="EncryptedPackageEnvelope.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description:
//  This class represents an OLE compound file that contains an encrypted package.
//
// History:
//  06/06/2005: LGolding:    Initial implementation.
//
//-----------------------------------------------------------------------------
 
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Packaging;
using System.Runtime.InteropServices;
using System.Security.RightsManagement;
using System.Windows;
using System.Collections;
using System.Collections.Generic;
 
using MS.Internal;                  // Invariant.Assert
using MS.Internal.IO.Packaging;
using MS.Internal.IO.Packaging.CompoundFile;    // RightsManagementEncryptionTransform
using MS.Internal.WindowsBase;
 
namespace System.IO.Packaging
{
    /// <summary>
    /// This class represents an OLE compound file that contains an encrypted package.
    /// </summary>
    public class EncryptedPackageEnvelope : IDisposable
    {
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
 
        #region Constructors
 
        /// <summary>
        /// Constructor. Creates an EncryptedPackageEnvelope on a new compound file. The file
        /// is overwritten if it already exists, and it is opened for read-write access
        /// with no sharing.
        /// </summary>
        /// <param name="envelopeFileName">
        /// The path name of the compound file being created to hold the encrypted package.
        /// </param>
        /// <param name="publishLicense">
        /// The publish license to be embedded in the compound file.
        /// </param>
        /// <param name="cryptoProvider">
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// </param>
        internal
        EncryptedPackageEnvelope(
            string envelopeFileName,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            if (envelopeFileName == null)
                throw new ArgumentNullException("envelopeFileName");
 
            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider);
 
 
            _root = StorageRoot.Open(
                                    envelopeFileName,
                                    _defaultFileModeForCreate,
                                    _defaultFileAccess,
                                    _defaultFileShare
                                    );
 
            InitializeRMForCreate(publishLicense, cryptoProvider);
            EmbedPackage(null);
        }
 
        /// <summary>
        /// Constructor. Creates an EncryptedPackageEnvelope on the specified stream.
        /// </summary>
        /// <param name="envelopeStream">
        /// The stream on which to create the compound file that will hold the
        /// encrypted package.
        /// </param>
        /// <param name="publishLicense">
        /// The publish license to be embedded in the compound file.
        /// </param>
        /// <param name="cryptoProvider">
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content.
        /// </param>
        internal
        EncryptedPackageEnvelope(
            Stream envelopeStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            if (envelopeStream == null)
                throw new ArgumentNullException("envelopeStream");
 
            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider);
 
            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForCreate);
 
            //
            // CreateOnStream opens the stream for read access if it's readable, and for
            // read/write access if it's writable. We're going to need it to be writable,
            // so check that it is.
            //
            if (_root.OpenAccess != FileAccess.ReadWrite)
            {
                throw new NotSupportedException(SR.Get(SRID.StreamNeedsReadWriteAccess));
            }
 
            InitializeRMForCreate(publishLicense, cryptoProvider);
            EmbedPackage(null);
        }
 
        /// <summary>
        /// Constructor. Create an EncryptedPackageEnvelope on the compound file, using
        /// an existing package as the content.
        /// </summary>
        /// <param name="envelopeFileName">
        /// The path name of the compound file being created to hold the encrypted package.
        /// </param>
        /// <param name="packageStream">
        /// A stream containing an unencrypted package which is to be stored in
        /// the compound file being created in <paramref name="envelopeFileName"/>.
        /// </param>
        /// <param name="publishLicense">
        /// The publish license to be embedded in the compound file.
        /// </param>
        /// <param name="cryptoProvider">
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content.
        /// </param>
        internal
        EncryptedPackageEnvelope(
            string envelopeFileName, 
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            if (envelopeFileName == null)
                throw new ArgumentNullException("envelopeFileName");
 
            if (packageStream == null)
                throw new ArgumentNullException("packageStream");
 
            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider);
 
            _root = StorageRoot.Open(
                                    envelopeFileName,
                                    _defaultFileModeForCreate,
                                    _defaultFileAccess,
                                    _defaultFileShare
                                    );
 
            InitializeRMForCreate(publishLicense, cryptoProvider);
            EmbedPackage(packageStream);
        }
 
        /// <summary>
        /// Constructor. Create an EncryptedPackageEnvelope on the specified stream, using
        /// an existing package as the content.
        /// </summary>
        /// <param name="envelopeStream">
        /// The stream on which to create the compound file that will hold the
        /// encrypted package.
        /// </param>
        /// <param name="packageStream">
        /// A stream containing an unencrypted package which is to be stored in
        /// the compound file being created on <paramref name="envelopeStream"/>.
        /// </param>
        /// <param name="publishLicense">
        /// The publish license to be embedded in the compound file.
        /// </param>
        /// <param name="cryptoProvider">
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content.
        /// </param>
        internal
        EncryptedPackageEnvelope(
            Stream envelopeStream, 
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            if (envelopeStream == null)
                throw new ArgumentNullException("envelopeStream");
 
            if (packageStream == null)
                throw new ArgumentNullException("packageStream");
 
            ThrowIfRMEncryptionInfoInvalid(publishLicense, cryptoProvider);
 
            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForCreate);
 
            //
            // CreateOnStream opens the stream for read access if it's readable, and for
            // read/write access if it's writable. We're going to need it to be writable,
            // so check that it is.
            //
            if (_root.OpenAccess != FileAccess.ReadWrite)
            {
                throw new NotSupportedException(SR.Get(SRID.StreamNeedsReadWriteAccess));
            }
 
            InitializeRMForCreate(publishLicense, cryptoProvider);
            EmbedPackage(packageStream);
        }
 
        /// <summary>
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified
        /// file, which must contain an RM-protected package.
        /// </summary>
        /// <param name="envelopeFileName">
        /// The path name of the compound file being created to hold the encrypted package.
        /// </param>
        /// <param name="access">
        /// Specifies whether the package is to be opened for read, write, or
        /// read/write access.
        /// </param>
        /// <param name="sharing">
        /// Specifies whether another process can have the file open simultaneously.
        /// </param>
        internal
        EncryptedPackageEnvelope(
            string envelopeFileName,
            FileAccess access,
            FileShare sharing
            )
        {
            if (envelopeFileName == null)
                throw new ArgumentNullException("envelopeFileName");
 
            _root = StorageRoot.Open(
                                    envelopeFileName,
                                    _defaultFileModeForOpen,
                                    access,
                                    sharing
                                    );
 
            InitForOpen();
        }
 
        /// <summary>
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified
        /// stream, which must contain an RM-protected package.
        /// </summary>
        /// <param name="envelopeStream">
        /// A stream containing an RM-protected package.
        /// </param>
        internal
        EncryptedPackageEnvelope(
            Stream envelopeStream
            )
        {
            if (envelopeStream == null)
                throw new ArgumentNullException("envelopeStream");
 
            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForOpen);
 
            InitForOpen();
        }
 
        #endregion Constructors
 
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------
 
        #region Public Methods
 
        /// <summary>
        /// Create an encrypted package in the specified file with the specified license
        /// information. The file is created if it does not exist and overwritten
        /// if it does exist, it is opened for read/write, and it is opened with
        /// no sharing.
        /// </summary>
        /// <param name="envelopeFileName">
        /// The path name of the compound file being created to hold the encrypted package.
        /// </param>
        /// <param name="publishLicense">
        /// The publish license to be embedded in the compound file.
        /// </param>
        /// <param name="cryptoProvider">
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// </param>
        public static EncryptedPackageEnvelope
        Create(
            string envelopeFileName,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            return new EncryptedPackageEnvelope(envelopeFileName, publishLicense, cryptoProvider);
        }
 
        /// <summary>
        /// Create an encrypted package on the specified stream with the specified license
        /// information. The stream  opened for read/write.
        /// </summary>
        /// <param name="envelopeStream">
        /// The stream on which to create the compound file that will hold the
        /// encrypted package.
        /// </param>
        /// <param name="publishLicense">
        /// The publish license to be embedded in the compound file.
        /// </param>
        /// <param name="cryptoProvider">
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// </param>
        public static EncryptedPackageEnvelope
        Create(
            Stream envelopeStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            return new EncryptedPackageEnvelope(envelopeStream, publishLicense, cryptoProvider);
        }
 
        /// <summary>
        /// Create an encrypted package from an existing package.
        /// </summary>
        /// <param name="envelopeFileName">
        /// The path name of the compound file being created to hold the encrypted package.
        /// </param>
        /// <param name="packageStream">
        /// A stream from which to obtain the clear-text contents of an existing package.
        /// </param>
        /// <param name="publishLicense">
        /// The publish license to be embedded in the compound file.
        /// </param>
        /// <param name="cryptoProvider">
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// </param>
        public static EncryptedPackageEnvelope
        CreateFromPackage(
            string envelopeFileName, 
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            return new EncryptedPackageEnvelope(
                            envelopeFileName,
                            packageStream,
                            publishLicense,
                            cryptoProvider
                            );
        }
 
        /// <summary>
        /// Create an encrypted package from an existing package.
        /// </summary>
        /// <param name="envelopeStream">
        /// The stream on which to create the compound file that will hold the
        /// encrypted package.
        /// </param>
        /// <param name="packageStream">
        /// A stream from which to obtain the clear-text contents of an existing package.
        /// </param>
        /// <param name="publishLicense">
        /// The publish license to be embedded in the compound file.
        /// </param>
        /// <param name="cryptoProvider">
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// </param>
        public static EncryptedPackageEnvelope
        CreateFromPackage(
            Stream envelopeStream, 
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            return new EncryptedPackageEnvelope(
                            envelopeStream,
                            packageStream,
                            publishLicense,
                            cryptoProvider
                            );
        }
 
        /// <summary>
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist. The file is opened read-only with no sharing.
        /// </summary>
        /// <param name="envelopeFileName">
        /// The path name of the compound file being opened.
        /// </param>
        public static EncryptedPackageEnvelope
        Open(
            string envelopeFileName
            )
        {
            return Open(envelopeFileName, _defaultFileAccess, _defaultFileShare);
        }
 
        /// <summary>
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist. The file is opened for the specified access,
        /// with no sharing.
        /// </summary>
        /// <param name="envelopeFileName">
        /// The path name of the compound file being opened.
        /// </param>
        /// <param name="access">
        /// Specifies whether the file is to be opened for read, write, or
        /// read/write access.
        /// </param>
        public static EncryptedPackageEnvelope
        Open(
            string envelopeFileName,
            FileAccess access
            )
        {
            return Open(envelopeFileName, access, _defaultFileShare);
        }
 
        /// <summary>
        /// Open the encrypted package in the specified compound file. The file
        /// must already exist.
        /// </summary>
        /// <param name="envelopeFileName">
        /// The path name of the compound file being opened.
        /// </param>
        /// <param name="access">
        /// Specifies whether the file is to be opened for read, write, or
        /// read/write access.
        /// </param>
        /// <param name="sharing">
        /// Specifies whether another process can have the file open simultaneously.
        /// </param>
        public static EncryptedPackageEnvelope
        Open(
            string envelopeFileName,
            FileAccess access,
            FileShare sharing
            )
        {
            return new EncryptedPackageEnvelope(envelopeFileName, access, sharing);
        }
 
        /// <summary>
        /// Open the encrypted package in the specified stream, which must
        /// contain an RM-protected package.
        /// </summary>
        /// <param name="envelopeStream">
        /// A stream containing an RM-protected package.
        /// </param>
        public static EncryptedPackageEnvelope
        Open(
            Stream envelopeStream
            )
        {
            return new EncryptedPackageEnvelope(envelopeStream);
        }
 
 
        /// <summary>
        /// Probe to see if a file is an RM-protected file. Returns true if the file
        /// is an OLE compound file with the well-known "EncryptedPackage" stream.
        /// </summary>
        /// <param name="fileName">
        /// The name of the file being probed.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="fileName"/> is null.
        /// </exception>
        /// <exception cref="FileNotFoundException">
        /// If the file specified by <paramref name="fileName"/> does not exist.
        /// </exception>
        public static bool
        IsEncryptedPackageEnvelope(
            string fileName
            )
        {
            bool retval = false;
 
            if (fileName == null)
                throw new ArgumentNullException("fileName");
 
            StorageRoot root = null;
 
            try
            {
                //
                // When StorageRoot.Open is called on a file that is not a compound file,
                // it throws an IOException whose inner exception is a COMException whose
                // error code is 0x80030050, STG_E_FILEALREADYEXISTS. Check for that case
                // and return false because that means that this is not an RM-protected file.
                //
                // Any other exception is a real error. For example, StorageRoot.Open
                // throws FileNotFoundException if path does not exist, and we let that
                // flow through.
                //
                root = StorageRoot.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
 
                //
                // It's a compound file. Does it contain an "EncryptedPackage" stream?
                //
                retval = ContainsEncryptedPackageStream(root);
            }
            catch (IOException ex)
            {
                COMException comException = ex.InnerException as COMException;
                if (comException != null && comException.ErrorCode == STG_E_FILEALREADYEXISTS)
                    return false;
 
                throw;  // Any other kind of IOException is a real error.
            }
            finally
            {
                if (root != null)
                {
                    root.Close();
                }
            }
 
            return retval;
        }
 
        /// <summary>
        /// Probe to see if a stream is an RM-protected file. Returns true if the
        /// stream is an OLE compound file with the well-known "EncryptedPackage" stream.
        /// </summary>
        /// <param name="stream">
        /// The stream being probed.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="stream"/> is null.
        /// </exception>
        public static bool
        IsEncryptedPackageEnvelope(
            Stream stream
            )
        {
            if (stream == null)
                throw new ArgumentNullException("stream");
 
            bool retval = false;
            StorageRoot root = null;
 
            try
            {
                //
                // When StorageRoot.CreateOnStream is called on a stream that is not
                // a storage object, it throws an IOException whose inner exception is
                // a COMException whose error code is 0x80030050, STG_E_FILEALREADYEXISTS.
                // Check for that case and return false because that means that this
                // stream is not an RM-protected file.
                //
                // Any other exception is a real error.
                //
                root = StorageRoot.CreateOnStream(stream, FileMode.Open);
 
                //
                // It's a compound file. Does it contain an "EncryptedPackage" stream?
                //
                retval = ContainsEncryptedPackageStream(root);
            }
            catch (IOException ex)
            {
                COMException comException = ex.InnerException as COMException;
                if (comException != null && comException.ErrorCode == STG_E_FILEALREADYEXISTS)
                    return false;
 
                throw;  // Any other kind of IOException is a real error.
            }
            finally
            {
                if (root != null)
                {
                    root.Close();
                }
            }
 
            return retval;
        }
 
        /// <summary>
        /// Flush the package and the underlying compound file.
        /// </summary>
        public void Flush()
        {
            CheckDisposed();
 
            //
            // Since _package is only initialized when the client calls GetPackage, it might
            // not be set when the client calls Flush, so we have to check.
            //
            if (_package != null)
            {
                _package.Flush();
            }
 
            if (_packageStream != null)
            {
                _packageStream.Flush();
            }
 
            Invariant.Assert(_root != null, "The envelope cannot be null");
 
            _root.Flush();
        }
 
        /// <summary>
        /// Close the package and the underlying compound file.
        /// </summary>
        public void Close()
        {
            Dispose();
        }
 
        #endregion Public Methods
 
        //------------------------------------------------------
        //
        //  IDisposable
        //
        //------------------------------------------------------
 
        /// <summary>
        /// Clean up all resources held by this object (both managed and
        /// unmanaged), and ensure that the resources won't be released a
        /// second time by removing it from the finalization queue.
        /// For this class, Dispose() ensures that the encrypted package
        /// is flushed and closed.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            
            GC.SuppressFinalize(this);
        }
 
        //------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------
 
        #region Public Properties
 
        /// <value>
        /// An object representing the rights-management information stored in
        /// the EncryptedPackageEnvelope, specifically, the PublishLicense and the
        /// UseLicenses stored in the compound file that embodies the RM protected Package.
        /// </value>
        public RightsManagementInformation RightsManagementInformation
        {
            get
            {
                CheckDisposed();
                return _rmi;
            }
        }
 
        /// <value>
        /// An object representing the core properties (such as Title and Subject)
        /// of the RM-protected document.
        /// </value>
        /// <remarks>
        /// These core properties are stored in the standard OLE property streams
        /// \005SummaryInformation and \005DocumentSummaryInformation, not the ones
        /// that are stored in the package itself. It is the responsibility
        /// of the application to keep the two sets of properties synchronized.
        /// properties.
        /// </remarks>
        public PackageProperties PackageProperties
        {
            get
            {
                CheckDisposed();
                if (_packageProperties == null)
                {
                    _packageProperties = new StorageBasedPackageProperties(_root);
                }
                return _packageProperties;
            }
        }
 
        /// <value>
        /// Access with which the compound file was opened.
        /// </value>
        public FileAccess FileOpenAccess
        {
            get
            {
                CheckDisposed();
                return _root.OpenAccess;
            }
        }
 
        /// <summary>
        /// Retrieve the package contained in the compound file.
        /// </summary>
        public Package GetPackage()
        {
            CheckDisposed();
 
            Invariant.Assert(!_handedOutPackageStream, "Copy of package stream has been already handed out");
 
            if (_package == null)
            {
                //
                // Open the package on the package stream, again with the same level
                // of access.
                // NOTE: The _packageStream must remain open as long as the _package
                // is open, that is to say, for the life of the EncryptedPackageEnvelope object.
                // Dispose takes care of flushing and closing the stream.
                //
                EnsurePackageStream();
 
                //We need to inspect the package stream's CanRead and CanWrite properties
                //to determine if we can open the package with the same access mode as 
                //that of the EncryptedPackage. 
                //We will try to open the package with the max possible permissions based
                //on the current EncryptedPackage access and the stream read/write properties.
 
                FileAccess fileAccessForPackage = 0 ;
 
                //Convert CanRead to FileAccess.Read
                if (_packageStream.CanRead)
                    fileAccessForPackage |= FileAccess.Read;
                //Convert CanWrite to FileAccess.Write
                if (_packageStream.CanWrite)
                    fileAccessForPackage |= FileAccess.Write;
 
                //check it against the mode of EncryptedPackage
                fileAccessForPackage &= this.FileOpenAccess;
 
                 _package = Package.Open(
                    _packageStream,
                    FileMode.Open,
                    fileAccessForPackage);
            }
 
            _handedOutPackage = true;
 
            return _package;
        }
 
        /// <value>
        /// Provides access to compound file streams outside of the encrypted package.
        /// </value>
        public StorageInfo StorageInfo
        {
            get
            {
                CheckDisposed();
                return (StorageInfo)_root;
            }
        }
 
        #endregion Public Properties
 
        //------------------------------------------------------
        //
        //   Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        /// <summary>
        /// Retrieve the package stream contained in the compound file.
        /// </summary>
        internal Stream GetPackageStream() 
        {
            CheckDisposed();
 
            Invariant.Assert(!_handedOutPackage, "Copy of package has been already handed out");
 
            EnsurePackageStream();
            _handedOutPackageStream = true;
 
            if (_package != null)
            {
                try
                {
                    _package.Close();
                }
                finally
                {
                    _package = null;
                }
            }
 
            return _packageStream;
        }
 
        #endregion
 
 
        //------------------------------------------------------
        //
        //   Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Properties
 
        //
        // Instance name for the encryption transform. This is used in StorageInfo as well.
        //
        internal static string EncryptionTransformName
        {
            get
            {
                return _encryptionTransformName;
            }
        }
 
        //
        // Name of the stream containing the encrypted content. This is used in StorageInfo as well.
        //
        internal static string PackageStreamName
        {
            get
            {
                return _packageStreamName;
            }
        }
 
        //Name of the dataspace label. This is used in StorageInfo as well.     
        internal static string DataspaceLabelRMEncryptionNoCompression
        {
            get
            {
                return _dataspaceLabelRMEncryptionNoCompression;
            }
        }
        
        #endregion Internal Properties
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        private void
        InitializeRMForCreate(
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            )
        {
            //
            // Define a data space consisting of a single transform, namely the
            // RightsManagementEncryptionTransform.
            //
            DataSpaceManager dsm = _root.GetDataSpaceManager();
 
            dsm.DefineTransform(
                    RightsManagementEncryptionTransform.ClassTransformIdentifier,
                    EncryptionTransformName
                    );
 
            string[] transformStack = new string[1];
            transformStack[0] = EncryptionTransformName;
            _dataSpaceName = DataspaceLabelRMEncryptionNoCompression;
            dsm.DefineDataSpace(transformStack, _dataSpaceName);
 
            //
            // The call to DefineTransform created a RightsManagementEncryptionTransform
            // object. Obtain this object from the DataSpaceManager, and wrap it in a
            // RightsManagementInformation object. This makes the RM information in the
            // compound file available to the application (through the RightsManagementInformation
            // property), without exposing to the application the implementation detail
            // that there -is- such a thing as a "transform".
            //
            RightsManagementEncryptionTransform rmet =
                dsm.GetTransformFromName(EncryptionTransformName) as RightsManagementEncryptionTransform;
 
            //
            // We just defined this transform, so it must exist.
            //
            Debug.Assert(
                rmet != null,
                "RightsManagementEncryptionTransform not found"
                );
 
            _rmi = new RightsManagementInformation(rmet);
 
            //
            // Prepare the transform object for use.
            //
            rmet.SavePublishLicense(publishLicense);
            rmet.CryptoProvider = cryptoProvider;
 
            //
            // The transform object is now ready for use. When the data space manager
            // queries the transform's IsReady property, it will return true. So there
            // is no need to sign up for the TransformInitializationEvent.
            //
        }
 
        private void
        InitForOpen()
        {           
 
            StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
            if (!siPackage.InternalExists())
            {
                throw new FileFormatException(SR.Get(SRID.PackageNotFound));
            }
 
            //If the StreamInfo exists we go on to check if correct transform has been
            //applied to the Stream
 
            DataSpaceManager dsm = _root.GetDataSpaceManager();
 
            List<IDataTransform> transforms = dsm.GetTransformsForStreamInfo(siPackage);
 
            RightsManagementEncryptionTransform rmet = null;
 
            foreach (IDataTransform dataTransform in transforms)
            {
                string id = dataTransform.TransformIdentifier as string;
                if (id != null &&
                        String.CompareOrdinal(id.ToUpperInvariant(),
                            RightsManagementEncryptionTransform.ClassTransformIdentifier.ToUpperInvariant()) == 0)
                {
                    // Do not allow more than one RM Transform
                    if (rmet != null)
                    {
                        throw new FileFormatException(SR.Get(SRID.MultipleRightsManagementEncryptionTransformFound));
                    }
 
                    rmet = dataTransform as RightsManagementEncryptionTransform;
                }
            }
 
            if (rmet == null)
            {
                throw new FileFormatException(SR.Get(SRID.RightsManagementEncryptionTransformNotFound));
            }
 
            //
            //  There is no reason to further push initialization of the Rights Management 
            //  data (parsing publish / use license). It will add unnecessary costs to the 
            //  scenarios where RM license are not relevant, for example indexing and 
            //  working with document properties            
            //
            
            //
            // Make the rights management information stored in the compound file
            // available to the application through the RightsManagementInformation
            // property.
            //
            _rmi = new RightsManagementInformation(rmet);
        }
 
        /// <summary>
        /// Determine if the specified StorageRoot contains a stream with the well-
        /// known name that denotes the encrypted package.
        /// </summary>
        /// <param name="root">
        /// The root storage or a compound file.
        /// </param>
        private static bool
        ContainsEncryptedPackageStream(
            StorageRoot root
            )
        {
            return ((new StreamInfo(root, PackageStreamName)).InternalExists());
        }
 
        /// <summary>
        /// Retrieve the package stream contained in the compound file.
        /// </summary>
        private void EnsurePackageStream()
        {
            if (_packageStream == null)
            {
                StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
                if (siPackage.InternalExists())
                {
                    //
                    // Open the existing package stream with the same level of access
                    // that the compound file is open.
                    //
                    _packageStream = siPackage.GetStream(FileMode.Open, this.FileOpenAccess);
                }
                else
                {
                    //Error. This package is created in InitForCreate while creating EncryptedPackageEnvelope.
                    //If it does not exist, throw an error.
                    throw new FileFormatException(SR.Get(SRID.PackageNotFound));
                }
            }
        }
 
        /// <summary>
        /// Dispose(bool disposing) executes in two distinct scenarios.
        /// If disposing equals true, the method has been called directly
        /// or indirectly by a user's code. Managed and unmanaged resources
        /// can be disposed.
        ///
        /// If disposing equals false, the method has been called by the 
        /// runtime from inside the finalizer and you should not reference 
        /// other objects. Only unmanaged resources can be disposed.
        ///
        /// This class has no unmanaged resources, so it has no finalizer,
        /// so this method will only ever be called with disposing=true,
        /// -unless- a subclass overrides Dispose(bool) and calls the
        /// base class method.
        /// </summary>
        /// <param name="disposing">
        /// true if called from Dispose(); false if called from the finalizer.
        /// </param>
        protected virtual void
        Dispose(
            bool disposing
            )
        {
            try
            {
                //
                // If disposing is true, dispose all managed and unmanaged
                // resources. This class has managed resources _package, _root,
                // and _packageProperties that need to be cleaned up.
                //
                if (disposing)
                {
                    try
                    {
                        //
                        // Close the package, if we had it open. It might not be open because we
                        // might have opened the compound file just to look at the properties, and
                        // never even opened the package.
                        //
                        if (_package != null)
                        {
                            _package.Close();
                        }
                    }
                    finally
                    {
                        _package = null;
 
                        try
                        {
                            if (_packageStream != null)
                            {
                                _packageStream.Close();
                            }
                        }
                        finally
                        {
                            _packageStream = null;
 
                            try
                            {
                                if (_packageProperties != null)
                                {
                                    _packageProperties.Dispose();
                                }
                            }
                            finally
                            {
                                _packageProperties = null;
 
                                try
                                {
                                    if (_root != null)
                                    {
                                        _root.Close();
                                    }
                                }
                                finally
                                {
                                    _root = null;
                                }
                            }
                        }
                    }
                }
 
                //
                // If disposing is false, only clean up unmanaged resources.
                // This class has no unmanaged resources.
                //
            }
            finally
            {
                //
                // By setting _disposed = true, we ensure that all future accesses to
                // this object will fail (because all public methods and property accessors
                // call CheckDisposed). Note that we do -not- wrap the entire body of
                // Dispose(bool) (this method) in an "if (!_disposed)". This is safe
                // because we set each reference to null immediately after attempting
                // to release it, so we never attempt to release any reference more
                // than once.
                //
                _disposed = true;         
            }
        }
 
        private void
        CheckDisposed()
        {
            if (_disposed)
                throw new ObjectDisposedException(null, SR.Get(SRID.EncryptedPackageEnvelopeDisposed));
        }
 
        /// <summary>
        /// Create a stream in the "encrypted" data space to hold the package
        /// contents, and copy the package into that stream.
        /// </summary>
        /// <param name="packageStream">
        /// A stream containing an unencrypted package which is to be stored in
        /// the compound file.
        /// </param>
        private void
        EmbedPackage(Stream packageStream)
        {
            StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);
 
            Debug.Assert(!siPackage.InternalExists());
 
            //
            // Create a stream to hold the document content. Create it in the
            // dataspace containing the RightsManagementEncryptionTransform. This
            // will cause the compound file code (specifically, the DataSpaceManager)
            // to create a RightsManagementEncryptionTransform object, and then
            // to trigger the TransformInitializationEvent, which will allow us to
            // retrieve the transform object.
            //
             _packageStream = siPackage.Create(
                                                FileMode.Create,
                                                _root.OpenAccess,
                                                _dataSpaceName
                                                );
 
            if (packageStream != null)
            {
                //copy the stream
 
                PackagingUtilities.CopyStream(packageStream, _packageStream,
                                                Int64.MaxValue, /*bytes to copy*/
                                                4096 /*buffer size */);
                _package = Package.Open(_packageStream, FileMode.Open, this.FileOpenAccess);
            }
            else
            {
                //
                // Create the package on the package stream
                //                   
                _package = Package.Open(_packageStream, FileMode.Create, FileAccess.ReadWrite);
                _package.Flush();
                _packageStream.Flush();
            }
        }
 
        private void ThrowIfRMEncryptionInfoInvalid(
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider)
        {
            if (publishLicense == null)
                throw new ArgumentNullException("publishLicense");
 
            if (cryptoProvider == null)
                throw new ArgumentNullException("cryptoProvider");
 
        }
 
        #endregion Private Methods
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        private bool _disposed;
        private bool _handedOutPackage;
        private bool _handedOutPackageStream;
 
        // Resources managed by this class.
        private StorageRoot                     _root;
        private Package                         _package;
 
        private string                          _dataSpaceName;
        private Stream                          _packageStream;
        private StorageBasedPackageProperties   _packageProperties;
        private RightsManagementInformation     _rmi;
 
        //
        // Instance name for the encryption transform. This is used in StorageInfo as well.
        //
        private const string _encryptionTransformName = "EncryptionTransform";
 
        //
        // Name of the stream containing the encrypted content. This is used in StorageInfo as well.
        //
        private const string _packageStreamName = "EncryptedPackage";
 
        //Name of the dataspace label. This is used in StorageInfo as well.      
        private const string _dataspaceLabelRMEncryptionNoCompression = "RMEncryptionNoCompression";
 
        private const int STG_E_FILEALREADYEXISTS = unchecked((int)0x80030050);
 
        private const FileMode   _defaultFileModeForCreate   = FileMode.Create;
        private const FileAccess _defaultFileAccess = FileAccess.ReadWrite;
        private const FileShare  _defaultFileShare  = FileShare.None;
 
        private const FileMode   _defaultFileModeForOpen   = FileMode.Open;
 
        #endregion Private Fields
    }
}