/// <summary>
        /// Will create an DocumentStream backed by a tempoary file.
        /// </summary>
        /// <remarks>
        /// We prefer to create the temporary file in the same location as the
        /// source to inherit the folders attributes and security.
        ///
        /// If we can not we will use a system generated file.
        /// </remarks>
        /// <param name="copyoriginal">When true we will copy the source file if
        /// possible.  You must check for a non-zero result on the returning stream
        /// to determin success.</param>
        /// <returns>An DocumentStream.</returns>
        internal DocumentStream CreateTemporary(bool copyOriginal)
        {
            CriticalFileToken tempToken = null;
            DocumentStream    result    = null;

            FileStream temporary    = null;
            bool       isFileSource = (_xpsFileToken != null);

            //----------------------------------------------------------------------
            // Open File in Same Location (if possible)
            if (isFileSource)
            {
                MakeTempFile(true, out temporary, out tempToken);
            }

            //----------------------------------------------------------------------
            // Open File in System Generated Location
            if (tempToken == null)
            {
                // TODO: Should we prompt user asking if it is okay in the case
                // where the source is a local file, as it may mean degraded
                // security?  We could check if this would be the case by
                // comparing ACLs & attributes before prompting

                MakeTempFile(false, out temporary, out tempToken);
            }

            //----------------------------------------------------------------------
            // File Was Opened
            if ((temporary != null) && (tempToken != null))
            {
                //------------------------------------------------------------------
                // Copy Data
                if (copyOriginal)
                {
                    // We use a native File.Copy if possible because this is
                    // most performant.  This is only possible if the source is file
                    // based.
                    if (isFileSource)
                    {
                        string sourcePath = _xpsFileToken.Location.LocalPath;
                        string tempPath   = tempToken.Location.LocalPath;

                        temporary.Close();

                        File.Copy(sourcePath, tempPath, true);

                        temporary = new FileStream(
                            tempPath,
                            FileMode.Open,
                            FileAccess.ReadWrite,
                            FileShare.None);

                        // we did the copy
                        copyOriginal = false;

                        Trace.SafeWrite(Trace.File, "Performed a file copy from source.");
                    }
                    else
                    {
                        StreamHelper.CopyStream(
                            this, temporary);
                        Trace.SafeWrite(Trace.File, "Performed a stream copy from source.");
                    }
                }

                //------------------------------------------------------------------
                // Create the DocumentStream
                result = new DocumentStream(
                    tempToken, temporary, this);

                result.DeleteOnClose = true;

                Trace.SafeWrite(Trace.File, "Created temporary file {0}.", tempToken.Location);
            }
            else
            {
                // rescind consent if any was given
                tempToken = null;
                Trace.SafeWrite(Trace.File, "Unable to create a temporary file.  Caller is expected to disable edits.");
            }
            return(result);
        }
        /// <summary>
        /// <see cref="MS.Internal.Documents.Application.IDocumentController"/>
        /// </summary>
        bool IDocumentController.SavePreperation(Document document)
        {
            bool handled = false;

            RightsDocument doc      = (RightsDocument)document; // see class remarks on why this is ok
            Stream         ciphered = doc.Dependency.Destination;
            Stream         clear    = ciphered;

            // We protect the actual decrypted content (if necessary) using the
            // RightsManagementSuppressedStream that prevents callers from writing
            // to it. This still allows us to save an acquired use license back to
            // the package even if the user does not have the permissions to modify
            // the document itself. It also means that there is no need to check if
            // the user has permission to save before starting the operation.

            // If we are encrypted and the destination stream is identical to the
            // source stream, there is no need to create a new envelope. Instead we
            // can simply open the envelope on the destination stream, which
            // already contains the complete encrypted envelope that was the source
            // file.
            //
            // It doesn't actually matter to this class why the flag was set, but
            // we know the destination is identical to the source in two situations:
            //  1) The source and the destination are the same file, and since the
            //     publish license didn't change there is no need to write to a
            //     temporary file first
            //  2) The destination file was copied directly from the source file.
            if (doc.IsDestinationProtected() && doc.IsDestinationIdenticalToSource)
            {
                // we can't reuse protections because EncryptedPackage caches the
                // original permissions for the stream (if we re-open the package r/w
                // the Encrypted package will still be r/o)

                doc.DestinationPackage = OpenEnvelopeOnStream(
                    doc.Dependency.Destination);

                doc.DestinationPackage.RightsManagementInformation.CryptoProvider =
                    doc.SourcePackage.RightsManagementInformation.CryptoProvider;

                clear = DecryptEnvelopeAndSuppressStream(
                    doc.DestinationPackage,
                    DocumentRightsManagementManager.Current.HasPermissionToEdit);
                doc.DestinationProxy = new StreamProxy(clear);

                // save the use license in case the user acquired one
                _provider.Value.SaveUseLicense(doc.DestinationPackage);

                handled = true;

                Trace.SafeWrite(
                    Trace.Rights,
                    "Reused CryptoProvider as underlying stream is the same.");
            }
            else // we are not protected and/or the RM protections have changed
            {
                bool canEdit =
                    DocumentRightsManagementManager.Current.HasPermissionToEdit;

                // canEdit should always be true here - either the document is not
                // protected, or the protections have been changed.  In the latter
                // case, the user has to have Owner permissions to change the
                // protections, and that of course includes Edit permissions.
                Invariant.Assert(
                    canEdit,
                    "Cannot save with changes if Edit permission was not granted.");

                EncryptedPackageEnvelope encryptedPackage =
                    _provider.Value.EncryptPackage(ciphered);

                // the destination is intended to be encrypted when a non-null
                // value is returned

                if (encryptedPackage != null)
                {
                    clear = DecryptEnvelopeAndSuppressStream(
                        encryptedPackage,
                        canEdit);
                    doc.DestinationPackage = encryptedPackage;
                }

                Trace.SafeWriteIf(
                    encryptedPackage == null,
                    Trace.Rights,
                    "Destination package is unprotected.");

                doc.DestinationProxy = new StreamProxy(clear);

                // If the destination file is not identical to the source file, we
                // need to copy the (possibly decrypted) source stream to the
                // destination here.
                if (!doc.IsDestinationIdenticalToSource)
                {
                    StreamHelper.CopyStream(doc.Source, doc.Destination);

                    doc.DestinationProxy.Flush();

                    Trace.SafeWrite(
                        Trace.Rights,
                        "Copied Source contents to Destination.");
                }

                handled = true;
            }

            return(handled);
        }
        //--------------------------------------------------------------------------
        // Internal Methods
        //--------------------------------------------------------------------------

        /// <summary>
        /// Will create an XpsDocument by copying this one to a target file and
        /// returning a stream corresponding to the new file.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"/>
        /// <exception cref="System.IO.InvalidDataException"/>
        /// <param name="copiesToken">The token for the target file.</param>
        /// <returns>An DocumentStream.</returns>
        internal DocumentStream Copy(CriticalFileToken copiesToken)
        {
            DocumentStream result;
            FileStream     target = null;

            bool isFileSource = (_xpsFileToken != null);

            Invariant.Assert(copiesToken != null, "No target file to which to copy.");

            ThrowIfInvalidXpsFileForSave(copiesToken.Location);

            string sourcePath = string.Empty;
            string copiesPath = copiesToken.Location.LocalPath;

            // if the source is a file, we need to release our lock on the source
            // file and also assert for permissions to read the file
            if (isFileSource)
            {
                Target.Close();
                sourcePath = _xpsFileToken.Location.LocalPath;
            }

            try
            {
                // if the source is a file, file copy is the fastest
                if (isFileSource)
                {
                    File.Copy(sourcePath, copiesPath, true);

                    // If the original file was marked read-only, the copy will be read-only as
                    // well.  However, the copy is done for the purpose of creating a new file,
                    // so it should not be marked read-only.
                    FileAttributes attrib = File.GetAttributes(copiesPath);
                    if ((attrib & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
                    {
                        File.SetAttributes(copiesPath, attrib ^ FileAttributes.ReadOnly);
                    }

                    // open the destination file that was just created by File.Copy
                    target = new FileStream(
                        copiesPath,
                        FileMode.Open,
                        FileAccess.ReadWrite,
                        FileShare.None);
                }
                else
                {
                    // open the destination file for create; we will copy the
                    // source stream's data to the new stream outside the assert
                    target = new FileStream(
                        copiesPath,
                        FileMode.Create,
                        FileAccess.ReadWrite,
                        FileShare.None);
                }
            }
            // Since we have already closed the original file, we need to reopen it if we
            // fail to copy the file or open the new file.  After doing so, we rethrow the
            // original exception so it can be handled at a higher level.
#pragma warning suppress 56500 // suppress PreSharp Warning 56500: Avoid `swallowing errors by catching non-specific exceptions..
            catch
            {
                if (isFileSource)
                {
                    Trace.SafeWrite(
                        Trace.File,
                        "File copy failed -- reopening original file.");
                    try
                    {
                        Target = new FileStream(
                            sourcePath,
                            FileMode.Open,
                            FileAccess.Read,
                            FileShare.Read);
                    }
                    // If we fail to reopen the original file, rethrow an exception to
                    // indicate this specific error.
#pragma warning suppress 56500 // suppress PreSharp Warning 56500: Avoid `swallowing errors by catching non-specific exceptions..
                    catch (Exception e)
                    {
                        Trace.SafeWrite(
                            Trace.File,
                            "Unable to reopen original file.");

                        throw new UnauthorizedAccessException(
                                  SR.Get(SRID.DocumentStreamCanNoLongerOpen), e);
                    }
                }
                throw;
            }

            if (isFileSource)
            {
                Trace.SafeWrite(Trace.File, "Performed a file copy from source.");

                // reacquire our stream
                ReOpenWriteable();
            }
            else
            {
                // if the source wasn't a file, we want to copy the stream now
                StreamHelper.CopyStream(this, target);
                Trace.SafeWrite(Trace.File, "Performed a stream copy from source.");
            }

            //----------------------------------------------------------------------
            // Create the DocumentStream
            result = new DocumentStream(copiesToken, target, this);

            result.DeleteOnClose = false;

            Trace.SafeWrite(Trace.File, "Created copy to file {0}.", copiesToken.Location);

            return(result);
        }