EncryptedPackage.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / System / IO / Packaging / EncryptedPackage.cs / 1305600 / EncryptedPackage.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 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
{
    ///  
    /// This class represents an OLE compound file that contains an encrypted package.
    ///  
    public class EncryptedPackageEnvelope : IDisposable 
    {
        //----------------------------------------------------- 
        //
        //  Constructors
        //
        //----------------------------------------------------- 

        #region Constructors 
 
        /// 
        /// 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.
        /// 
        ///  
        /// The path name of the compound file being created to hold the encrypted package.
        ///  
        ///  
        /// The publish license to be embedded in the compound file.
        ///  
        /// 
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        ///  
        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);
        } 

        /// 
        /// Constructor. Creates an EncryptedPackageEnvelope on the specified stream.
        ///  
        /// 
        /// The stream on which to create the compound file that will hold the 
        /// encrypted package. 
        /// 
        ///  
        /// The publish license to be embedded in the compound file.
        /// 
        /// 
        /// The object that determines what operations the current user is allowed 
        /// to perform on the encrypted content.
        ///  
        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);
        } 
 
        /// 
        /// Constructor. Create an EncryptedPackageEnvelope on the compound file, using 
        /// an existing package as the content.
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        ///  
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file being created in .
        ///  
        /// 
        /// The publish license to be embedded in the compound file.
        /// 
        ///  
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content. 
        ///  
        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);
        } 
 
        /// 
        /// Constructor. Create an EncryptedPackageEnvelope on the specified stream, using 
        /// an existing package as the content.
        /// 
        /// 
        /// The stream on which to create the compound file that will hold the 
        /// encrypted package.
        ///  
        ///  
        /// A stream containing an unencrypted package which is to be stored in
        /// the compound file being created on . 
        /// 
        /// 
        /// The publish license to be embedded in the compound file.
        ///  
        /// 
        /// The object that determines what operations the current user is allowed 
        /// to perform on the encrypted content. 
        /// 
        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);
        }
 
        /// 
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified 
        /// file, which must contain an RM-protected package. 
        /// 
        ///  
        /// The path name of the compound file being created to hold the encrypted package.
        /// 
        /// 
        /// Specifies whether the package is to be opened for read, write, or 
        /// read/write access.
        ///  
        ///  
        /// Specifies whether another process can have the file open simultaneously.
        ///  
        internal
        EncryptedPackageEnvelope(
            string envelopeFileName,
            FileAccess access, 
            FileShare sharing
            ) 
        { 
            if (envelopeFileName == null)
                throw new ArgumentNullException("envelopeFileName"); 

            _root = StorageRoot.Open(
                                    envelopeFileName,
                                    _defaultFileModeForOpen, 
                                    access,
                                    sharing 
                                    ); 

            InitForOpen(); 
        }

        /// 
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified 
        /// stream, which must contain an RM-protected package.
        ///  
        ///  
        /// A stream containing an RM-protected package.
        ///  
        internal
        EncryptedPackageEnvelope(
            Stream envelopeStream
            ) 
        {
            if (envelopeStream == null) 
                throw new ArgumentNullException("envelopeStream"); 

            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForOpen); 

            InitForOpen();
        }
 
        #endregion Constructors
 
        //------------------------------------------------------ 
        //
        //  Public Methods 
        //
        //-----------------------------------------------------

        #region Public Methods 

        ///  
        /// 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.
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        ///  
        /// The publish license to be embedded in the compound file. 
        /// 
        ///  
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// 
        public static EncryptedPackageEnvelope 
        Create(
            string envelopeFileName, 
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            ) 
        {
            return new EncryptedPackageEnvelope(envelopeFileName, publishLicense, cryptoProvider);
        }
 
        /// 
        /// Create an encrypted package on the specified stream with the specified license 
        /// information. The stream  opened for read/write. 
        /// 
        ///  
        /// The stream on which to create the compound file that will hold the
        /// encrypted package.
        /// 
        ///  
        /// The publish license to be embedded in the compound file.
        ///  
        ///  
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content. 
        /// 
        public static EncryptedPackageEnvelope
        Create(
            Stream envelopeStream, 
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider 
            ) 
        {
            return new EncryptedPackageEnvelope(envelopeStream, publishLicense, cryptoProvider); 
        }

        /// 
        /// Create an encrypted package from an existing package. 
        /// 
        ///  
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        ///  
        /// A stream from which to obtain the clear-text contents of an existing package.
        /// 
        /// 
        /// The publish license to be embedded in the compound file. 
        /// 
        ///  
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content.
        ///  
        public static EncryptedPackageEnvelope
        CreateFromPackage(
            string envelopeFileName,
            Stream packageStream, 
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider 
            ) 
        {
            return new EncryptedPackageEnvelope( 
                            envelopeFileName,
                            packageStream,
                            publishLicense,
                            cryptoProvider 
                            );
        } 
 
        /// 
        /// Create an encrypted package from an existing package. 
        /// 
        /// 
        /// The stream on which to create the compound file that will hold the
        /// encrypted package. 
        /// 
        ///  
        /// A stream from which to obtain the clear-text contents of an existing package. 
        /// 
        ///  
        /// The publish license to be embedded in the compound file.
        /// 
        /// 
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content.
        ///  
        public static EncryptedPackageEnvelope 
        CreateFromPackage(
            Stream envelopeStream, 
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            ) 
        {
            return new EncryptedPackageEnvelope( 
                            envelopeStream, 
                            packageStream,
                            publishLicense, 
                            cryptoProvider
                            );
        }
 
        /// 
        /// Open the encrypted package in the specified compound file. The file 
        /// must already exist. The file is opened read-only with no sharing. 
        /// 
        ///  
        /// The path name of the compound file being opened.
        /// 
        public static EncryptedPackageEnvelope
        Open( 
            string envelopeFileName
            ) 
        { 
            return Open(envelopeFileName, _defaultFileAccess, _defaultFileShare);
        } 

        /// 
        /// 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.
        ///  
        ///  
        /// The path name of the compound file being opened.
        ///  
        /// 
        /// Specifies whether the file is to be opened for read, write, or
        /// read/write access.
        ///  
        public static EncryptedPackageEnvelope
        Open( 
            string envelopeFileName, 
            FileAccess access
            ) 
        {
            return Open(envelopeFileName, access, _defaultFileShare);
        }
 
        /// 
        /// Open the encrypted package in the specified compound file. The file 
        /// must already exist. 
        /// 
        ///  
        /// The path name of the compound file being opened.
        /// 
        /// 
        /// Specifies whether the file is to be opened for read, write, or 
        /// read/write access.
        ///  
        ///  
        /// Specifies whether another process can have the file open simultaneously.
        ///  
        public static EncryptedPackageEnvelope
        Open(
            string envelopeFileName,
            FileAccess access, 
            FileShare sharing
            ) 
        { 
            return new EncryptedPackageEnvelope(envelopeFileName, access, sharing);
        } 

        /// 
        /// Open the encrypted package in the specified stream, which must
        /// contain an RM-protected package. 
        /// 
        ///  
        /// A stream containing an RM-protected package. 
        /// 
        public static EncryptedPackageEnvelope 
        Open(
            Stream envelopeStream
            )
        { 
            return new EncryptedPackageEnvelope(envelopeStream);
        } 
 

        ///  
        /// 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.
        /// 
        ///  
        /// The name of the file being probed.
        ///  
        ///  
        /// If  is null.
        ///  
        /// 
        /// If the file specified by  does not exist.
        /// 
        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; 
        } 

        ///  
        /// 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.
        /// 
        ///  
        /// The stream being probed.
        ///  
        ///  
        /// If  is null.
        ///  
        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;
        }

        ///  
        /// Flush the package and the underlying compound file.
        ///  
        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(); 
        }

        /// 
        /// Close the package and the underlying compound file. 
        /// 
        public void Close() 
        { 
            Dispose();
        } 

        #endregion Public Methods

        //------------------------------------------------------ 
        //
        //  IDisposable 
        // 
        //------------------------------------------------------
 
        /// 
        /// 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. 
        ///  
        public void Dispose()
        { 
            Dispose(true);

            GC.SuppressFinalize(this);
        } 

        //----------------------------------------------------- 
        // 
        //  Public Properties
        // 
        //------------------------------------------------------

        #region Public Properties
 
        /// 
        /// 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.
        ///  
        public RightsManagementInformation RightsManagementInformation
        {
            get
            { 
                CheckDisposed();
                return _rmi; 
            } 
        }
 
        /// 
        /// An object representing the core properties (such as Title and Subject)
        /// of the RM-protected document.
        ///  
        /// 
        /// 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.
        /// 
        public PackageProperties PackageProperties
        { 
            get
            { 
                CheckDisposed(); 
                if (_packageProperties == null)
                { 
                    _packageProperties = new StorageBasedPackageProperties(_root);
                }
                return _packageProperties;
            } 
        }
 
        ///  
        /// Access with which the compound file was opened.
        ///  
        public FileAccess FileOpenAccess
        {
            get
            { 
                CheckDisposed();
                return _root.OpenAccess; 
            } 
        }
 
        /// 
        /// Retrieve the package contained in the compound file.
        /// 
        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;
        }
 
        /// 
        /// Provides access to compound file streams outside of the encrypted package. 
        ///  
        public StorageInfo StorageInfo
        { 
            get
            {
                CheckDisposed();
                return (StorageInfo)_root; 
            }
        } 
 
        #endregion Public Properties
 
        //-----------------------------------------------------
        //
        //   Internal Methods
        // 
        //-----------------------------------------------------
 
        #region Internal Methods 

        ///  
        /// Retrieve the package stream contained in the compound file.
        /// 
        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 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);
        } 

        /// 
        /// Determine if the specified StorageRoot contains a stream with the well-
        /// known name that denotes the encrypted package. 
        /// 
        ///  
        /// The root storage or a compound file. 
        /// 
        private static bool 
        ContainsEncryptedPackageStream(
            StorageRoot root
            )
        { 
            return ((new StreamInfo(root, PackageStreamName)).InternalExists());
        } 
 
        /// 
        /// Retrieve the package stream contained in the compound file. 
        /// 
        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));
                }
            }
        } 

        ///  
        /// 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.
        /// 
        /// 
        /// true if called from Dispose(); false if called from the finalizer. 
        /// 
        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));
        } 

        /// 
        /// Create a stream in the "encrypted" data space to hold the package
        /// contents, and copy the package into that stream. 
        /// 
        ///  
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file.
        ///  
        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
    } 
}

// 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: 
//  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
{
    ///  
    /// This class represents an OLE compound file that contains an encrypted package.
    ///  
    public class EncryptedPackageEnvelope : IDisposable 
    {
        //----------------------------------------------------- 
        //
        //  Constructors
        //
        //----------------------------------------------------- 

        #region Constructors 
 
        /// 
        /// 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.
        /// 
        ///  
        /// The path name of the compound file being created to hold the encrypted package.
        ///  
        ///  
        /// The publish license to be embedded in the compound file.
        ///  
        /// 
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        ///  
        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);
        } 

        /// 
        /// Constructor. Creates an EncryptedPackageEnvelope on the specified stream.
        ///  
        /// 
        /// The stream on which to create the compound file that will hold the 
        /// encrypted package. 
        /// 
        ///  
        /// The publish license to be embedded in the compound file.
        /// 
        /// 
        /// The object that determines what operations the current user is allowed 
        /// to perform on the encrypted content.
        ///  
        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);
        } 
 
        /// 
        /// Constructor. Create an EncryptedPackageEnvelope on the compound file, using 
        /// an existing package as the content.
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        ///  
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file being created in .
        ///  
        /// 
        /// The publish license to be embedded in the compound file.
        /// 
        ///  
        /// The object that determines what operations the current user is allowed
        /// to perform on the encrypted content. 
        ///  
        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);
        } 
 
        /// 
        /// Constructor. Create an EncryptedPackageEnvelope on the specified stream, using 
        /// an existing package as the content.
        /// 
        /// 
        /// The stream on which to create the compound file that will hold the 
        /// encrypted package.
        ///  
        ///  
        /// A stream containing an unencrypted package which is to be stored in
        /// the compound file being created on . 
        /// 
        /// 
        /// The publish license to be embedded in the compound file.
        ///  
        /// 
        /// The object that determines what operations the current user is allowed 
        /// to perform on the encrypted content. 
        /// 
        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);
        }
 
        /// 
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified 
        /// file, which must contain an RM-protected package. 
        /// 
        ///  
        /// The path name of the compound file being created to hold the encrypted package.
        /// 
        /// 
        /// Specifies whether the package is to be opened for read, write, or 
        /// read/write access.
        ///  
        ///  
        /// Specifies whether another process can have the file open simultaneously.
        ///  
        internal
        EncryptedPackageEnvelope(
            string envelopeFileName,
            FileAccess access, 
            FileShare sharing
            ) 
        { 
            if (envelopeFileName == null)
                throw new ArgumentNullException("envelopeFileName"); 

            _root = StorageRoot.Open(
                                    envelopeFileName,
                                    _defaultFileModeForOpen, 
                                    access,
                                    sharing 
                                    ); 

            InitForOpen(); 
        }

        /// 
        /// Constructor. Create an EncryptedPackageEnvelope object by opening the specified 
        /// stream, which must contain an RM-protected package.
        ///  
        ///  
        /// A stream containing an RM-protected package.
        ///  
        internal
        EncryptedPackageEnvelope(
            Stream envelopeStream
            ) 
        {
            if (envelopeStream == null) 
                throw new ArgumentNullException("envelopeStream"); 

            _root = StorageRoot.CreateOnStream(envelopeStream, _defaultFileModeForOpen); 

            InitForOpen();
        }
 
        #endregion Constructors
 
        //------------------------------------------------------ 
        //
        //  Public Methods 
        //
        //-----------------------------------------------------

        #region Public Methods 

        ///  
        /// 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.
        /// 
        /// 
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        ///  
        /// The publish license to be embedded in the compound file. 
        /// 
        ///  
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content.
        /// 
        public static EncryptedPackageEnvelope 
        Create(
            string envelopeFileName, 
            PublishLicense publishLicense, 
            CryptoProvider cryptoProvider
            ) 
        {
            return new EncryptedPackageEnvelope(envelopeFileName, publishLicense, cryptoProvider);
        }
 
        /// 
        /// Create an encrypted package on the specified stream with the specified license 
        /// information. The stream  opened for read/write. 
        /// 
        ///  
        /// The stream on which to create the compound file that will hold the
        /// encrypted package.
        /// 
        ///  
        /// The publish license to be embedded in the compound file.
        ///  
        ///  
        /// The object that determines what operations the current user is allowed to perform
        /// on the encrypted content. 
        /// 
        public static EncryptedPackageEnvelope
        Create(
            Stream envelopeStream, 
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider 
            ) 
        {
            return new EncryptedPackageEnvelope(envelopeStream, publishLicense, cryptoProvider); 
        }

        /// 
        /// Create an encrypted package from an existing package. 
        /// 
        ///  
        /// The path name of the compound file being created to hold the encrypted package. 
        /// 
        ///  
        /// A stream from which to obtain the clear-text contents of an existing package.
        /// 
        /// 
        /// The publish license to be embedded in the compound file. 
        /// 
        ///  
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content.
        ///  
        public static EncryptedPackageEnvelope
        CreateFromPackage(
            string envelopeFileName,
            Stream packageStream, 
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider 
            ) 
        {
            return new EncryptedPackageEnvelope( 
                            envelopeFileName,
                            packageStream,
                            publishLicense,
                            cryptoProvider 
                            );
        } 
 
        /// 
        /// Create an encrypted package from an existing package. 
        /// 
        /// 
        /// The stream on which to create the compound file that will hold the
        /// encrypted package. 
        /// 
        ///  
        /// A stream from which to obtain the clear-text contents of an existing package. 
        /// 
        ///  
        /// The publish license to be embedded in the compound file.
        /// 
        /// 
        /// The object that determines what operations the current user is allowed to perform 
        /// on the encrypted content.
        ///  
        public static EncryptedPackageEnvelope 
        CreateFromPackage(
            Stream envelopeStream, 
            Stream packageStream,
            PublishLicense publishLicense,
            CryptoProvider cryptoProvider
            ) 
        {
            return new EncryptedPackageEnvelope( 
                            envelopeStream, 
                            packageStream,
                            publishLicense, 
                            cryptoProvider
                            );
        }
 
        /// 
        /// Open the encrypted package in the specified compound file. The file 
        /// must already exist. The file is opened read-only with no sharing. 
        /// 
        ///  
        /// The path name of the compound file being opened.
        /// 
        public static EncryptedPackageEnvelope
        Open( 
            string envelopeFileName
            ) 
        { 
            return Open(envelopeFileName, _defaultFileAccess, _defaultFileShare);
        } 

        /// 
        /// 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.
        ///  
        ///  
        /// The path name of the compound file being opened.
        ///  
        /// 
        /// Specifies whether the file is to be opened for read, write, or
        /// read/write access.
        ///  
        public static EncryptedPackageEnvelope
        Open( 
            string envelopeFileName, 
            FileAccess access
            ) 
        {
            return Open(envelopeFileName, access, _defaultFileShare);
        }
 
        /// 
        /// Open the encrypted package in the specified compound file. The file 
        /// must already exist. 
        /// 
        ///  
        /// The path name of the compound file being opened.
        /// 
        /// 
        /// Specifies whether the file is to be opened for read, write, or 
        /// read/write access.
        ///  
        ///  
        /// Specifies whether another process can have the file open simultaneously.
        ///  
        public static EncryptedPackageEnvelope
        Open(
            string envelopeFileName,
            FileAccess access, 
            FileShare sharing
            ) 
        { 
            return new EncryptedPackageEnvelope(envelopeFileName, access, sharing);
        } 

        /// 
        /// Open the encrypted package in the specified stream, which must
        /// contain an RM-protected package. 
        /// 
        ///  
        /// A stream containing an RM-protected package. 
        /// 
        public static EncryptedPackageEnvelope 
        Open(
            Stream envelopeStream
            )
        { 
            return new EncryptedPackageEnvelope(envelopeStream);
        } 
 

        ///  
        /// 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.
        /// 
        ///  
        /// The name of the file being probed.
        ///  
        ///  
        /// If  is null.
        ///  
        /// 
        /// If the file specified by  does not exist.
        /// 
        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; 
        } 

        ///  
        /// 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.
        /// 
        ///  
        /// The stream being probed.
        ///  
        ///  
        /// If  is null.
        ///  
        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;
        }

        ///  
        /// Flush the package and the underlying compound file.
        ///  
        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(); 
        }

        /// 
        /// Close the package and the underlying compound file. 
        /// 
        public void Close() 
        { 
            Dispose();
        } 

        #endregion Public Methods

        //------------------------------------------------------ 
        //
        //  IDisposable 
        // 
        //------------------------------------------------------
 
        /// 
        /// 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. 
        ///  
        public void Dispose()
        { 
            Dispose(true);

            GC.SuppressFinalize(this);
        } 

        //----------------------------------------------------- 
        // 
        //  Public Properties
        // 
        //------------------------------------------------------

        #region Public Properties
 
        /// 
        /// 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.
        ///  
        public RightsManagementInformation RightsManagementInformation
        {
            get
            { 
                CheckDisposed();
                return _rmi; 
            } 
        }
 
        /// 
        /// An object representing the core properties (such as Title and Subject)
        /// of the RM-protected document.
        ///  
        /// 
        /// 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.
        /// 
        public PackageProperties PackageProperties
        { 
            get
            { 
                CheckDisposed(); 
                if (_packageProperties == null)
                { 
                    _packageProperties = new StorageBasedPackageProperties(_root);
                }
                return _packageProperties;
            } 
        }
 
        ///  
        /// Access with which the compound file was opened.
        ///  
        public FileAccess FileOpenAccess
        {
            get
            { 
                CheckDisposed();
                return _root.OpenAccess; 
            } 
        }
 
        /// 
        /// Retrieve the package contained in the compound file.
        /// 
        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;
        }
 
        /// 
        /// Provides access to compound file streams outside of the encrypted package. 
        ///  
        public StorageInfo StorageInfo
        { 
            get
            {
                CheckDisposed();
                return (StorageInfo)_root; 
            }
        } 
 
        #endregion Public Properties
 
        //-----------------------------------------------------
        //
        //   Internal Methods
        // 
        //-----------------------------------------------------
 
        #region Internal Methods 

        ///  
        /// Retrieve the package stream contained in the compound file.
        /// 
        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 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);
        } 

        /// 
        /// Determine if the specified StorageRoot contains a stream with the well-
        /// known name that denotes the encrypted package. 
        /// 
        ///  
        /// The root storage or a compound file. 
        /// 
        private static bool 
        ContainsEncryptedPackageStream(
            StorageRoot root
            )
        { 
            return ((new StreamInfo(root, PackageStreamName)).InternalExists());
        } 
 
        /// 
        /// Retrieve the package stream contained in the compound file. 
        /// 
        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));
                }
            }
        } 

        ///  
        /// 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.
        /// 
        /// 
        /// true if called from Dispose(); false if called from the finalizer. 
        /// 
        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));
        } 

        /// 
        /// Create a stream in the "encrypted" data space to hold the package
        /// contents, and copy the package into that stream. 
        /// 
        ///  
        /// A stream containing an unencrypted package which is to be stored in 
        /// the compound file.
        ///  
        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
    } 
}

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