File: MS\Internal\Documents\Application\PackageController.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationUI\PresentationUI_r5prqfe0_wpftmp.csproj (PresentationUI)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
// Description:
//  Responsible for the lifecycle of the PackageDocument and the actions that can
//  be performed on it.
 
using System;
using System.IO.Packaging;
using System.Security;
using System.Windows.TrustUI;
using System.Windows.Xps.Packaging;
 
namespace MS.Internal.Documents.Application
{
/// <summary>
/// Responsible for the lifecycle of the PackageDocument and the actions that can
/// be performed on it.
/// <see cref="MS.Internal.Documents.Application.IDocumentController"/>
/// </summary>
internal class PackageController : IDocumentController
{
    #region IDocumentController Members
    //--------------------------------------------------------------------------
    // IDocumentController Members
    //--------------------------------------------------------------------------
 
    /// <summary>
    /// <see cref="MS.Internal.Documents.Application.IDocumentController"/>
    /// </summary>
    bool IDocumentController.EnableEdit(Document document)
    {
        PackageDocument doc = (PackageDocument)document;
 
        if (doc.Workspace != null)
        {
            doc.Package.EnableEditMode(doc.Workspace);
        }
 
        return true;
    }
 
    /// <summary>
    /// <see cref="MS.Internal.Documents.Application.IDocumentController"/>
    /// </summary>
    bool IDocumentController.Open(Document document)
    {
        PackageDocument doc = (PackageDocument)document;
 
        TransactionalPackage package = new RestrictedTransactionalPackage(
            doc.Source);
 
        doc.Package = package;
 
        DocumentProperties.Current.SetXpsProperties(package.PackageProperties);
 
        DocumentSignatureManager.Initialize(new DigitalSignatureProvider(package));
 
        // when signatures change (are added or removed) we can no longer simply copy bits on disk
        DocumentSignatureManager.Current.SignaturesChanged += 
            new EventHandler(
                delegate (
                    object sender, 
                    EventArgs args)
                    {
                        if (doc.IsFileCopySafe)                
                        {
                            Trace.SafeWrite(
                                Trace.Signatures,
                                "Disabling file copy for current document.");
                            doc.IsFileCopySafe = false;
                        }
                    });
 
        return true;
    }
 
    /// <summary>
    /// <see cref="MS.Internal.Documents.Application.IDocumentController"/>
    /// </summary>
    bool IDocumentController.Rebind(Document document)
    {
        PackageDocument doc = (PackageDocument)document;
 
        if (doc.IsRebindNeeded)
        {
            doc.Package.Rebind(doc.Source);
 
            // no rebinds are needed above us for documents as package
            doc.IsRebindNeeded = false;
        }
 
        return true;
    }
 
    /// <summary>
    /// <see cref="MS.Internal.Documents.Application.IDocumentController"/>
    /// </summary>
    bool IDocumentController.SaveAsPreperation(Document document)
    {
        return ((IDocumentController)this).SavePreperation(document);
    }
 
    /// <summary>
    /// <see cref="MS.Internal.Documents.Application.IDocumentController"/>
    /// <exception cref="System.InvalidOperationException"/>
    /// </summary>
    bool IDocumentController.SaveCommit(Document document)
    {
        PackageDocument doc = (PackageDocument)document;
 
        if (doc.Destination == null)
        {
            return false;
        }
 
        if (doc.Package.IsDirty || !doc.IsDestinationIdenticalToSource)
        {
            StreamProxy source = doc.Source as StreamProxy;
            StreamProxy destination = doc.Destination as StreamProxy;
 
            // this will catch the case where our source stream is our destination
            // stream, which would cause corruption of the package
            if (source.GetHashCode() == destination.GetHashCode())
            {
                throw new InvalidOperationException(
                    SR.PackageControllerStreamCorruption);
            }
 
            // this will catch the case where no one was able to copy the stream
            // thus the lengths will not match
            if (doc.Source.Length != doc.Destination.Length)
            {
                throw new InvalidOperationException(
                    SR.PackageControllerStreamCorruption);
            }
 
            // Flush the package to ensure that the relationship parts are
            // written out before changes are merged
            doc.Package.Flush();
 
            doc.Package.MergeChanges(doc.Destination);
            Trace.SafeWrite(Trace.File, "Destination Merged.");
        }
        else
        {
            Trace.SafeWrite(Trace.File, "Destination Merge Skipped (nothing to do).");
        }
        return true;
    }
 
    /// <summary>
    /// <see cref="MS.Internal.Documents.Application.IDocumentController"/>
    /// </summary>
    /// <remarks>
    /// This method severely breaks encapsulating the chain, however it does
    /// so because the requirement breaks encapsulation and the original design
    /// of the class only consider streams not properties.  The requirement is
    /// that as we transition to/from a protected document we copy properties
    /// between the layers.  It was least risk to compromise the design here
    /// then extend it.
    /// </remarks>
    bool IDocumentController.SavePreperation(Document document)
    {
        // we don't have to check packageDoc for because we are only responsible
        // for PackageDocuments
        PackageDocument packageDoc = (PackageDocument)document;
        RightsDocument rightsDoc = document.Dependency as RightsDocument;
 
        if (rightsDoc != null)
        {
            bool isDestinationProtected = rightsDoc.IsDestinationProtected();
            bool isSourceProtected = rightsDoc.IsSourceProtected();
 
            // the only time we don't need to copy properties is when
            // neither source nor destination is protected as OPC properties
            // are copied as parts
 
            // if the source was protected and the destination is not
            // then we need to copy properties to the package
            if (isSourceProtected && !isDestinationProtected)
            {
                DocumentProperties.Copy(
                    new SuppressedProperties(rightsDoc.SourcePackage),
                    packageDoc.Package.PackageProperties);
            }
 
            // if the source was not protected and the destination is
            // then we need to copy properties from the package to the envelope
            if (!isSourceProtected && isDestinationProtected)
            {
                DocumentProperties.Copy(
                    packageDoc.Package.PackageProperties,
                    new SuppressedProperties(rightsDoc.DestinationPackage));
            }
 
            // if they were both protected we need to copy properties
            // from the old envelope to the new
            if (isDestinationProtected && isSourceProtected)
            {
                DocumentProperties.Copy(
                    new SuppressedProperties(rightsDoc.SourcePackage),
                    new SuppressedProperties(rightsDoc.DestinationPackage));
            }
        }
        return true;
    }
 
    #endregion IDocumentController Members
 
    #region IChainOfResponsibiltyNode<Document> Members
    //--------------------------------------------------------------------------
    // IChainOfResponsibiltyNode<Document> Members
    //--------------------------------------------------------------------------
 
    /// <summary>
    /// <see cref="MS.Internal.Documents.Application.IChainOfResponsibiltyNode<T>"/>
    /// </summary>
    bool IChainOfResponsibiltyNode<Document>.IsResponsible(Document subject)
    {
        return subject is PackageDocument;
    }
 
    #endregion IChainOfResponsibiltyNode<Document> Members
}
}