1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
26 #include <sfx2/docfile.hxx>
27 #include <sfx2/signaturestate.hxx>
29 #include <com/sun/star/task/InteractionHandler.hpp>
30 #include <com/sun/star/task/XStatusIndicator.hpp>
31 #include <com/sun/star/uno/Reference.h>
32 #include <com/sun/star/ucb/XContent.hpp>
33 #include <com/sun/star/container/XChild.hpp>
34 #include <com/sun/star/document/XDocumentRevisionListPersistence.hpp>
35 #include <com/sun/star/document/LockedDocumentRequest.hpp>
36 #include <com/sun/star/document/LockedOnSavingRequest.hpp>
37 #include <com/sun/star/document/OwnLockOnDocumentRequest.hpp>
38 #include <com/sun/star/document/LockFileIgnoreRequest.hpp>
39 #include <com/sun/star/document/LockFileCorruptRequest.hpp>
40 #include <com/sun/star/document/ChangedByOthersRequest.hpp>
41 #include <com/sun/star/embed/XTransactedObject.hpp>
42 #include <com/sun/star/embed/ElementModes.hpp>
43 #include <com/sun/star/embed/UseBackupException.hpp>
44 #include <com/sun/star/embed/XOptimizedStorage.hpp>
45 #include <com/sun/star/frame/XModel.hpp>
46 #include <com/sun/star/graphic/XGraphic.hpp>
47 #include <com/sun/star/ucb/ContentCreationException.hpp>
48 #include <com/sun/star/ucb/InteractiveIOException.hpp>
49 #include <com/sun/star/ucb/CommandFailedException.hpp>
50 #include <com/sun/star/ucb/CommandAbortedException.hpp>
51 #include <com/sun/star/ucb/InteractiveLockingLockedException.hpp>
52 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
53 #include <com/sun/star/ucb/Lock.hpp>
54 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
55 #include <com/sun/star/ucb/XProgressHandler.hpp>
56 #include <com/sun/star/io/XOutputStream.hpp>
57 #include <com/sun/star/io/XInputStream.hpp>
58 #include <com/sun/star/io/XTruncate.hpp>
59 #include <com/sun/star/io/XSeekable.hpp>
60 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
61 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
62 #include <com/sun/star/ucb/NameClash.hpp>
63 #include <com/sun/star/beans/NamedValue.hpp>
64 #include <com/sun/star/beans/PropertyValue.hpp>
65 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
66 #include <com/sun/star/security/XCertificate.hpp>
67 #include <tools/urlobj.hxx>
68 #include <tools/fileutil.hxx>
69 #include <unotools/configmgr.hxx>
70 #include <unotools/tempfile.hxx>
71 #include <comphelper/fileurl.hxx>
72 #include <comphelper/processfactory.hxx>
73 #include <comphelper/interaction.hxx>
74 #include <comphelper/sequence.hxx>
75 #include <comphelper/simplefileaccessinteraction.hxx>
76 #include <framework/interaction.hxx>
78 #include <svl/stritem.hxx>
79 #include <svl/eitem.hxx>
80 #include <svtools/sfxecode.hxx>
81 #include <svl/itemset.hxx>
82 #include <svl/intitem.hxx>
83 #include <svtools/svparser.hxx>
84 #include <sal/log.hxx>
86 #include <unotools/streamwrap.hxx>
88 #include <osl/file.hxx>
90 #include <comphelper/storagehelper.hxx>
91 #include <unotools/mediadescriptor.hxx>
92 #include <comphelper/docpasswordhelper.hxx>
93 #include <tools/datetime.hxx>
94 #include <unotools/pathoptions.hxx>
95 #include <svtools/asynclink.hxx>
96 #include <ucbhelper/commandenvironment.hxx>
97 #include <unotools/ucbstreamhelper.hxx>
98 #include <unotools/ucbhelper.hxx>
99 #include <unotools/progresshandlerwrap.hxx>
100 #include <ucbhelper/content.hxx>
101 #include <ucbhelper/interactionrequest.hxx>
102 #include <sot/storage.hxx>
103 #include <unotools/saveopt.hxx>
104 #include <svl/documentlockfile.hxx>
105 #include <svl/msodocumentlockfile.hxx>
106 #include <com/sun/star/document/DocumentRevisionListPersistence.hpp>
108 #include <sfx2/app.hxx>
109 #include <sfx2/frame.hxx>
110 #include <sfx2/fcontnr.hxx>
111 #include <sfx2/docfilt.hxx>
112 #include <sfx2/sfxsids.hrc>
113 #include <sfx2/sfxuno.hxx>
114 #include <openflag.hxx>
115 #include <officecfg/Office/Common.hxx>
116 #include <comphelper/propertysequence.hxx>
117 #include <vcl/weld.hxx>
118 #include <vcl/svapp.hxx>
119 #include <tools/diagnose_ex.h>
120 #include <unotools/fltrcfg.hxx>
121 #include <sfx2/digitalsignatures.hxx>
123 #include <com/sun/star/io/WrongFormatException.hpp>
127 using namespace ::com::sun::star
;
128 using namespace ::com::sun::star::graphic
;
129 using namespace ::com::sun::star::uno
;
130 using namespace ::com::sun::star::ucb
;
131 using namespace ::com::sun::star::beans
;
132 using namespace ::com::sun::star::io
;
133 using namespace ::com::sun::star::security
;
137 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
139 bool IsSystemFileLockingUsed()
141 #if HAVE_FEATURE_MACOSX_SANDBOX
144 return officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::get();
149 bool IsOOoLockFileUsed()
151 #if HAVE_FEATURE_MACOSX_SANDBOX
154 return officecfg::Office::Common::Misc::UseDocumentOOoLockFile::get();
160 return officecfg::Office::Common::Misc::UseLocking::get();
165 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
166 bool IsWebDAVLockingUsed()
168 return officecfg::Office::Common::Misc::UseWebDAVFileLocking::get();
172 /// Gets default attributes of a file:// URL.
173 sal_uInt64
GetDefaultFileAttributes(const OUString
& rURL
)
177 if (!comphelper::isFileUrl(rURL
))
180 // Make sure the file exists (and create it if not).
181 osl::File
aFile(rURL
);
182 osl::File::RC nRes
= aFile
.open(osl_File_OpenFlag_Create
);
183 if (nRes
!= osl::File::E_None
&& nRes
!= osl::File::E_EXIST
)
188 osl::DirectoryItem aItem
;
189 if (osl::DirectoryItem::get(rURL
, aItem
) != osl::DirectoryItem::E_None
)
192 osl::FileStatus
aStatus(osl_FileStatus_Mask_Attributes
);
193 if (aItem
.getFileStatus(aStatus
) != osl::DirectoryItem::E_None
)
196 nRet
= aStatus
.getAttributes();
200 /// Determines if rURL is safe to move or not.
201 bool IsFileMovable(const INetURLObject
& rURL
)
205 // Hide extension macOS-specific file property would be lost.
209 if (rURL
.GetProtocol() != INetProtocol::File
)
210 // Not a file:// URL.
214 OUString sPath
= rURL
.getFSysPath(FSysStyle::Unix
);
219 if (lstat(sPath
.toUtf8().getStr(), &buf
) != 0)
222 // Hardlink or symlink: osl::File::move() doesn't play with these nicely.
223 if (buf
.st_nlink
> 1 || S_ISLNK(buf
.st_mode
))
226 if (tools::IsMappedWebDAVPath(rURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
)))
234 } // anonymous namespace
239 StreamMode m_nStorOpenMode
;
242 ::ucbhelper::Content aContent
;
243 bool bUpdatePickList
:1;
245 bool bDownloadDone
:1;
247 bool bUseInteractionHandler
:1;
248 bool bAllowDefaultIntHdl
:1;
249 bool bDisposeStorage
:1;
250 bool bStorageBasedOnInStream
:1;
251 bool m_bSalvageMode
:1;
252 bool m_bVersionsAlreadyLoaded
:1;
254 bool m_bMSOLockFileCreated
: 1;
255 bool m_bDisableUnlockWebDAV
:1;
256 bool m_bGotDateTime
:1;
257 bool m_bRemoveBackup
:1;
258 bool m_bOriginallyReadOnly
:1;
259 bool m_bOriginallyLoadedReadOnly
:1;
260 bool m_bTriedStorage
:1;
262 bool m_bInputStreamIsReadOnly
:1;
264 bool m_bDisableFileSync
= false;
267 OUString m_aLogicName
;
268 OUString m_aLongName
;
270 mutable std::shared_ptr
<SfxItemSet
> m_pSet
;
271 mutable std::unique_ptr
<INetURLObject
> m_pURLObj
;
273 std::shared_ptr
<const SfxFilter
> m_pFilter
;
274 std::shared_ptr
<const SfxFilter
> m_pCustomFilter
;
276 std::unique_ptr
<SvStream
> m_pInStream
;
277 std::unique_ptr
<SvStream
> m_pOutStream
;
280 DateTime aExpireTime
;
281 SfxFrameWeakRef wLoadTargetFrame
;
282 SvKeyValueIteratorRef xAttributes
;
284 svtools::AsynchronLink aDoneLink
;
286 uno::Sequence
< util::RevisionTag
> aVersions
;
288 std::unique_ptr
<::utl::TempFile
> pTempFile
;
290 uno::Reference
<embed::XStorage
> xStorage
;
291 uno::Reference
<embed::XStorage
> m_xZipStorage
;
292 uno::Reference
<io::XInputStream
> m_xInputStreamToLoadFrom
;
293 uno::Reference
<io::XInputStream
> xInputStream
;
294 uno::Reference
<io::XStream
> xStream
;
295 uno::Reference
<io::XStream
> m_xLockingStream
;
296 uno::Reference
<task::XInteractionHandler
> xInteraction
;
298 ErrCode nLastStorageError
;
300 OUString m_aBackupURL
;
302 // the following member is changed and makes sense only during saving
303 // TODO/LATER: in future the signature state should be controlled by the medium not by the document
304 // in this case the member will hold this information
305 SignatureState m_nSignatureState
;
307 bool m_bHasEmbeddedObjects
= false;
309 util::DateTime m_aDateTime
;
311 uno::Sequence
<beans::PropertyValue
> m_aArgs
;
313 explicit SfxMedium_Impl();
315 SfxMedium_Impl(const SfxMedium_Impl
&) = delete;
316 SfxMedium_Impl
& operator=(const SfxMedium_Impl
&) = delete;
318 OUString
getFilterMimeType() const
319 { return !m_pFilter
? OUString() : m_pFilter
->GetMimeType(); }
323 SfxMedium_Impl::SfxMedium_Impl() :
324 m_nStorOpenMode(SFX_STREAM_READWRITE
),
325 m_eError(ERRCODE_NONE
),
326 bUpdatePickList(true),
328 bDownloadDone( true ),
330 bUseInteractionHandler( true ),
331 bAllowDefaultIntHdl( false ),
332 bDisposeStorage( false ),
333 bStorageBasedOnInStream( false ),
334 m_bSalvageMode( false ),
335 m_bVersionsAlreadyLoaded( false ),
337 m_bMSOLockFileCreated( false ),
338 m_bDisableUnlockWebDAV( false ),
339 m_bGotDateTime( false ),
340 m_bRemoveBackup( false ),
341 m_bOriginallyReadOnly(false),
342 m_bOriginallyLoadedReadOnly(false),
343 m_bTriedStorage(false),
345 m_bInputStreamIsReadOnly(false),
347 aExpireTime( DateTime( DateTime::SYSTEM
) + static_cast<sal_Int32
>(10) ),
348 nLastStorageError( ERRCODE_NONE
),
349 m_nSignatureState( SignatureState::NOSIGNATURES
)
351 aDoneLink
.CreateMutex();
355 SfxMedium_Impl::~SfxMedium_Impl()
357 aDoneLink
.ClearPendingCall();
364 void SfxMedium::ResetError()
366 pImpl
->m_eError
= ERRCODE_NONE
;
367 if( pImpl
->m_pInStream
)
368 pImpl
->m_pInStream
->ResetError();
369 if( pImpl
->m_pOutStream
)
370 pImpl
->m_pOutStream
->ResetError();
373 ErrCode
const & SfxMedium::GetLastStorageCreationState() const
375 return pImpl
->nLastStorageError
;
378 void SfxMedium::SetError(ErrCode nError
)
380 pImpl
->m_eError
= nError
;
383 ErrCode
SfxMedium::GetErrorCode() const
385 ErrCode lError
= pImpl
->m_eError
;
386 if(!lError
&& pImpl
->m_pInStream
)
387 lError
= pImpl
->m_pInStream
->GetErrorCode();
388 if(!lError
&& pImpl
->m_pOutStream
)
389 lError
= pImpl
->m_pOutStream
->GetErrorCode();
393 void SfxMedium::CheckFileDate( const util::DateTime
& aInitDate
)
395 GetInitFileDate( true );
396 if ( pImpl
->m_aDateTime
.Seconds
== aInitDate
.Seconds
397 && pImpl
->m_aDateTime
.Minutes
== aInitDate
.Minutes
398 && pImpl
->m_aDateTime
.Hours
== aInitDate
.Hours
399 && pImpl
->m_aDateTime
.Day
== aInitDate
.Day
400 && pImpl
->m_aDateTime
.Month
== aInitDate
.Month
401 && pImpl
->m_aDateTime
.Year
== aInitDate
.Year
)
404 uno::Reference
< task::XInteractionHandler
> xHandler
= GetInteractionHandler();
406 if ( !xHandler
.is() )
411 ::rtl::Reference
< ::ucbhelper::InteractionRequest
> xInteractionRequestImpl
= new ::ucbhelper::InteractionRequest( uno::makeAny(
412 document::ChangedByOthersRequest() ) );
413 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > aContinuations( 3 );
414 aContinuations
[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl
.get() );
415 aContinuations
[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl
.get() );
416 xInteractionRequestImpl
->setContinuations( aContinuations
);
418 xHandler
->handle( xInteractionRequestImpl
.get() );
420 ::rtl::Reference
< ::ucbhelper::InteractionContinuation
> xSelected
= xInteractionRequestImpl
->getSelection();
421 if ( uno::Reference
< task::XInteractionAbort
>( xSelected
.get(), uno::UNO_QUERY
).is() )
423 SetError(ERRCODE_ABORT
);
426 catch ( const uno::Exception
& )
430 bool SfxMedium::DocNeedsFileDateCheck() const
432 return ( !IsReadOnly() && ( GetURLObject().GetProtocol() == INetProtocol::File
||
433 GetURLObject().isAnyKnownWebDAVScheme() ) );
436 util::DateTime
const & SfxMedium::GetInitFileDate( bool bIgnoreOldValue
)
438 if ( ( bIgnoreOldValue
|| !pImpl
->m_bGotDateTime
) && !pImpl
->m_aLogicName
.isEmpty() )
442 // add a default css::ucb::XCommandEnvironment
443 // in order to have the WebDAV UCP provider manage http/https authentication correctly
444 ::ucbhelper::Content
aContent( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
),
445 utl::UCBContentHelper::getDefaultCommandEnvironment(),
446 comphelper::getProcessComponentContext() );
448 aContent
.getPropertyValue("DateModified") >>= pImpl
->m_aDateTime
;
449 pImpl
->m_bGotDateTime
= true;
451 catch ( const css::uno::Exception
& )
456 return pImpl
->m_aDateTime
;
460 Reference
< XContent
> SfxMedium::GetContent() const
462 if ( !pImpl
->aContent
.get().is() )
464 Reference
< css::ucb::XContent
> xContent
;
466 // tdf#95144 add a default css::ucb::XCommandEnvironment
467 // in order to have the WebDAV UCP provider manage https protocol certificates correctly
468 css:: uno::Reference
< task::XInteractionHandler
> xIH(
469 css::task::InteractionHandler::createWithParent( comphelper::getProcessComponentContext(), nullptr ) );
471 css::uno::Reference
< css::ucb::XProgressHandler
> xProgress
;
472 ::ucbhelper::CommandEnvironment
* pCommandEnv
= new ::ucbhelper::CommandEnvironment( new comphelper::SimpleFileAccessInteraction( xIH
), xProgress
);
474 Reference
< css::ucb::XCommandEnvironment
> xEnv( static_cast< css::ucb::XCommandEnvironment
* >(pCommandEnv
), css::uno::UNO_QUERY
);
476 const SfxUnoAnyItem
* pItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(pImpl
->m_pSet
.get(), SID_CONTENT
, false);
478 pItem
->GetValue() >>= xContent
;
484 pImpl
->aContent
= ::ucbhelper::Content( xContent
, xEnv
, comphelper::getProcessComponentContext() );
486 catch ( const Exception
& )
492 // TODO: SAL_WARN( "sfx.doc", "SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why it's used.");
494 if ( !pImpl
->m_aName
.isEmpty() )
495 osl::FileBase::getFileURLFromSystemPath( pImpl
->m_aName
, aURL
);
496 else if ( !pImpl
->m_aLogicName
.isEmpty() )
497 aURL
= GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
);
498 if (!aURL
.isEmpty() )
499 (void)::ucbhelper::Content::create( aURL
, xEnv
, comphelper::getProcessComponentContext(), pImpl
->aContent
);
503 return pImpl
->aContent
.get();
506 OUString
SfxMedium::GetBaseURL( bool bForSaving
)
509 const SfxStringItem
* pBaseURLItem
= GetItemSet()->GetItem
<SfxStringItem
>(SID_DOC_BASEURL
);
511 aBaseURL
= pBaseURLItem
->GetValue();
512 else if (!utl::ConfigManager::IsFuzzing() && GetContent().is())
516 Any aAny
= pImpl
->aContent
.getPropertyValue("BaseURI");
519 catch ( const css::uno::Exception
& )
523 if ( aBaseURL
.isEmpty() )
524 aBaseURL
= GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
);
530 bool bIsRemote
= IsRemote();
531 if( (bIsRemote
&& !aOpt
.IsSaveRelINet()) || (!pImpl
->m_bRemote
&& !aOpt
.IsSaveRelFSys()) )
538 bool SfxMedium::IsSkipImages() const
540 const SfxStringItem
* pSkipImagesItem
= GetItemSet()->GetItem
<SfxStringItem
>(SID_FILE_FILTEROPTIONS
);
541 return pSkipImagesItem
&& pSkipImagesItem
->GetValue() == "SkipImages";
544 SvStream
* SfxMedium::GetInStream()
546 if ( pImpl
->m_pInStream
)
547 return pImpl
->m_pInStream
.get();
549 if ( pImpl
->pTempFile
)
551 pImpl
->m_pInStream
.reset( new SvFileStream(pImpl
->m_aName
, pImpl
->m_nStorOpenMode
) );
553 pImpl
->m_eError
= pImpl
->m_pInStream
->GetError();
555 if (!pImpl
->m_eError
&& (pImpl
->m_nStorOpenMode
& StreamMode::WRITE
)
556 && ! pImpl
->m_pInStream
->IsWritable() )
558 pImpl
->m_eError
= ERRCODE_IO_ACCESSDENIED
;
559 pImpl
->m_pInStream
.reset();
562 return pImpl
->m_pInStream
.get();
570 return pImpl
->m_pInStream
.get();
574 void SfxMedium::CloseInStream()
576 CloseInStream_Impl();
579 void SfxMedium::CloseInStream_Impl(bool bInDestruction
)
581 // if there is a storage based on the InStream, we have to
582 // close the storage, too, because otherwise the storage
583 // would use an invalid ( deleted ) stream.
584 if ( pImpl
->m_pInStream
&& pImpl
->xStorage
.is() )
586 if ( pImpl
->bStorageBasedOnInStream
)
590 if ( pImpl
->m_pInStream
&& !GetContent().is() && !bInDestruction
)
596 pImpl
->m_pInStream
.reset();
598 pImpl
->m_pSet
->ClearItem( SID_INPUTSTREAM
);
600 CloseZipStorage_Impl();
601 pImpl
->xInputStream
.clear();
603 if ( !pImpl
->m_pOutStream
)
605 // output part of the stream is not used so the whole stream can be closed
606 // TODO/LATER: is it correct?
607 pImpl
->xStream
.clear();
609 pImpl
->m_pSet
->ClearItem( SID_STREAM
);
614 SvStream
* SfxMedium::GetOutStream()
616 if ( !pImpl
->m_pOutStream
)
618 // Create a temp. file if there is none because we always
620 CreateTempFile( false );
622 if ( pImpl
->pTempFile
)
624 // On windows we try to re-use XOutStream from xStream if that exists;
625 // because opening new SvFileStream in this situation may fail with ERROR_SHARING_VIOLATION
626 // TODO: this is a horrible hack that should probably be removed,
627 // somebody needs to investigate this more thoroughly...
628 if (getenv("SFX_MEDIUM_REUSE_STREAM") && pImpl
->xStream
.is())
630 assert(pImpl
->xStream
->getOutputStream().is()); // need that...
631 pImpl
->m_pOutStream
= utl::UcbStreamHelper::CreateStream(
632 pImpl
->xStream
, false);
636 // On Unix don't try to re-use XOutStream from xStream if that exists;
637 // it causes fdo#59022 (fails opening files via SMB on Linux)
638 pImpl
->m_pOutStream
.reset( new SvFileStream(
639 pImpl
->m_aName
, StreamMode::STD_READWRITE
) );
645 return pImpl
->m_pOutStream
.get();
649 void SfxMedium::CloseOutStream()
651 CloseOutStream_Impl();
654 void SfxMedium::CloseOutStream_Impl()
656 if ( pImpl
->m_pOutStream
)
658 // if there is a storage based on the OutStream, we have to
659 // close the storage, too, because otherwise the storage
660 // would use an invalid ( deleted ) stream.
661 //TODO/MBA: how to deal with this?!
662 //maybe we need a new flag when the storage was created from the outstream
663 if ( pImpl
->xStorage
.is() )
668 pImpl
->m_pOutStream
.reset();
671 if ( !pImpl
->m_pInStream
)
673 // input part of the stream is not used so the whole stream can be closed
674 // TODO/LATER: is it correct?
675 pImpl
->xStream
.clear();
677 pImpl
->m_pSet
->ClearItem( SID_STREAM
);
682 const OUString
& SfxMedium::GetPhysicalName() const
684 if ( pImpl
->m_aName
.isEmpty() && !pImpl
->m_aLogicName
.isEmpty() )
685 const_cast<SfxMedium
*>(this)->CreateFileStream();
687 // return the name then
688 return pImpl
->m_aName
;
692 void SfxMedium::CreateFileStream()
695 if( pImpl
->m_pInStream
)
697 SvLockBytes
* pBytes
= pImpl
->m_pInStream
->GetLockBytes();
699 pBytes
->SetSynchronMode();
703 if( pImpl
->m_pInStream
)
705 CreateTempFile( false );
706 pImpl
->bIsTemp
= true;
707 CloseInStream_Impl();
712 bool SfxMedium::Commit()
714 if( pImpl
->xStorage
.is() )
715 StorageCommit_Impl();
716 else if( pImpl
->m_pOutStream
)
717 pImpl
->m_pOutStream
->Flush();
718 else if( pImpl
->m_pInStream
)
719 pImpl
->m_pInStream
->Flush();
721 if ( GetError() == ERRCODE_NONE
)
723 // does something only in case there is a temporary file ( means aName points to different location than aLogicName )
727 bool bResult
= ( GetError() == ERRCODE_NONE
);
729 if ( bResult
&& DocNeedsFileDateCheck() )
730 GetInitFileDate( true );
732 // remove truncation mode from the flags
733 pImpl
->m_nStorOpenMode
&= ~StreamMode::TRUNC
;
738 bool SfxMedium::IsStorage()
740 if ( pImpl
->xStorage
.is() )
743 if ( pImpl
->m_bTriedStorage
)
744 return pImpl
->bIsStorage
;
746 if ( pImpl
->pTempFile
)
749 if ( osl::FileBase::getFileURLFromSystemPath( pImpl
->m_aName
, aURL
)
750 != osl::FileBase::E_None
)
752 SAL_WARN( "sfx.doc", "Physical name '" << pImpl
->m_aName
<< "' not convertible to file URL");
754 pImpl
->bIsStorage
= SotStorage::IsStorageFile( aURL
) && !SotStorage::IsOLEStorage( aURL
);
755 if ( !pImpl
->bIsStorage
)
756 pImpl
->m_bTriedStorage
= true;
758 else if ( GetInStream() )
760 pImpl
->bIsStorage
= SotStorage::IsStorageFile( pImpl
->m_pInStream
.get() ) && !SotStorage::IsOLEStorage( pImpl
->m_pInStream
.get() );
761 if ( !pImpl
->m_pInStream
->GetError() && !pImpl
->bIsStorage
)
762 pImpl
->m_bTriedStorage
= true;
765 return pImpl
->bIsStorage
;
769 bool SfxMedium::IsPreview_Impl() const
771 bool bPreview
= false;
772 const SfxBoolItem
* pPreview
= SfxItemSet::GetItem
<SfxBoolItem
>(GetItemSet(), SID_PREVIEW
, false);
774 bPreview
= pPreview
->GetValue();
777 const SfxStringItem
* pFlags
= SfxItemSet::GetItem
<SfxStringItem
>(GetItemSet(), SID_OPTIONS
, false);
780 OUString aFileFlags
= pFlags
->GetValue();
781 aFileFlags
= aFileFlags
.toAsciiUpperCase();
782 if ( -1 != aFileFlags
.indexOf( 'B' ) )
791 void SfxMedium::StorageBackup_Impl()
793 ::ucbhelper::Content aOriginalContent
;
794 Reference
< css::ucb::XCommandEnvironment
> xDummyEnv
;
796 bool bBasedOnOriginalFile
=
798 && ( pImpl
->m_aLogicName
.isEmpty() || !pImpl
->m_bSalvageMode
)
799 && !GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
).isEmpty()
800 && GetURLObject().GetProtocol() == INetProtocol::File
801 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
803 if ( bBasedOnOriginalFile
&& pImpl
->m_aBackupURL
.isEmpty()
804 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
), xDummyEnv
, comphelper::getProcessComponentContext(), aOriginalContent
) )
806 DoInternalBackup_Impl( aOriginalContent
);
807 if( pImpl
->m_aBackupURL
.isEmpty() )
808 SetError(ERRCODE_SFX_CANTCREATEBACKUP
);
813 OUString
const & SfxMedium::GetBackup_Impl()
815 if ( pImpl
->m_aBackupURL
.isEmpty() )
816 StorageBackup_Impl();
818 return pImpl
->m_aBackupURL
;
822 uno::Reference
< embed::XStorage
> SfxMedium::GetOutputStorage()
825 return uno::Reference
< embed::XStorage
>();
827 // if the medium was constructed with a Storage: use this one, not a temp. storage
828 // if a temporary storage already exists: use it
829 if ( pImpl
->xStorage
.is() && ( pImpl
->m_aLogicName
.isEmpty() || pImpl
->pTempFile
) )
830 return pImpl
->xStorage
;
832 // if necessary close stream that was used for reading
833 if ( pImpl
->m_pInStream
&& !pImpl
->m_pInStream
->IsWritable() )
836 DBG_ASSERT( !pImpl
->m_pOutStream
, "OutStream in a readonly Medium?!" );
838 // TODO/LATER: The current solution is to store the document temporary and then copy it to the target location;
839 // in future it should be stored directly and then copied to the temporary location, since in this case no
840 // file attributes have to be preserved and system copying mechanics could be used instead of streaming.
841 CreateTempFileNoCopy();
847 void SfxMedium::SetEncryptionDataToStorage_Impl()
849 // in case media-descriptor contains password it should be used on opening
850 if ( !pImpl
->xStorage
.is() || !pImpl
->m_pSet
)
853 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
854 if ( !GetEncryptionData_Impl( pImpl
->m_pSet
.get(), aEncryptionData
) )
857 // replace the password with encryption data
858 pImpl
->m_pSet
->ClearItem( SID_PASSWORD
);
859 pImpl
->m_pSet
->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::makeAny( aEncryptionData
) ) );
863 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( pImpl
->xStorage
, aEncryptionData
);
865 catch( const uno::Exception
& )
867 SAL_WARN( "sfx.doc", "It must be possible to set a common password for the storage" );
868 // TODO/LATER: set the error code in case of problem
869 // SetError(ERRCODE_IO_GENERAL);
873 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
875 // FIXME: Hmm actually lock files should be used for sftp: documents
876 // even if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT. Only the use of lock
877 // files for *local* documents is unnecessary in that case. But
878 // actually, the checks for sftp: here are just wishful thinking; I
879 // don't this there is any support for actually editing documents
880 // behind sftp: URLs anyway.
882 // Sure, there could perhaps be a 3rd-party extension that brings UCB
883 // the potential to handle files behind sftp:. But there could also be
884 // an extension that handles some arbitrary foobar: scheme *and* it
885 // could be that lock files would be the correct thing to use for
886 // foobar: documents, too. But the hardcoded test below won't know
887 // that. Clearly the knowledge whether lock files should be used or
888 // not for some URL scheme belongs in UCB, not here.
893 OUString
tryMSOwnerFiles(const OUString
& sDocURL
)
895 svt::MSODocumentLockFile
aMSOLockFile(sDocURL
);
899 aData
= aMSOLockFile
.GetLockData();
901 catch( const uno::Exception
& )
906 OUString sUserData
= aData
[LockFileComponent::OOOUSERNAME
];
908 if (!sUserData
.isEmpty())
909 sUserData
+= " (MS Office)"; // Mention the used office suite
914 OUString
tryForeignLockfiles(const OUString
& sDocURL
)
916 OUString sUserData
= tryMSOwnerFiles(sDocURL
);
917 // here we can test for empty result, and add other known applications' lockfile testing
918 return sUserData
.trim();
922 SfxMedium::ShowLockResult
SfxMedium::ShowLockedDocumentDialog(const LockFileEntry
& aData
,
923 bool bIsLoading
, bool bOwnLock
,
924 bool bHandleSysLocked
)
926 ShowLockResult nResult
= ShowLockResult::NoLock
;
928 // tdf#92817: Simple check for empty lock file that needs to be deleted, when system locking is enabled
929 if( aData
[LockFileComponent::OOOUSERNAME
].isEmpty() && aData
[LockFileComponent::SYSUSERNAME
].isEmpty() && !bHandleSysLocked
)
932 // show the interaction regarding the document opening
933 uno::Reference
< task::XInteractionHandler
> xHandler
= GetInteractionHandler();
935 if ( xHandler
.is() && ( bIsLoading
|| !bHandleSysLocked
|| bOwnLock
) )
937 OUString aDocumentURL
938 = GetURLObject().GetLastName(INetURLObject::DecodeMechanism::WithCharset
);
940 ::rtl::Reference
< ::ucbhelper::InteractionRequest
> xInteractionRequestImpl
;
942 sal_Int32 nContinuations
= 3;
946 aInfo
= aData
[LockFileComponent::EDITTIME
];
948 xInteractionRequestImpl
= new ::ucbhelper::InteractionRequest( uno::makeAny(
949 document::OwnLockOnDocumentRequest( OUString(), uno::Reference
< uno::XInterface
>(), aDocumentURL
, aInfo
, !bIsLoading
) ) );
953 // Use a fourth continuation in case there's no filesystem lock:
954 // "Ignore lock file and open/replace the document"
955 if (!bHandleSysLocked
)
958 if ( !aData
[LockFileComponent::OOOUSERNAME
].isEmpty() )
959 aInfo
= aData
[LockFileComponent::OOOUSERNAME
];
961 aInfo
= aData
[LockFileComponent::SYSUSERNAME
];
963 if (aInfo
.isEmpty() && !GetURLObject().isAnyKnownWebDAVScheme())
964 // Try to get name of user who has locked the file using other applications
965 aInfo
= tryForeignLockfiles(
966 GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE
));
968 if ( !aInfo
.isEmpty() && !aData
[LockFileComponent::EDITTIME
].isEmpty() )
969 aInfo
+= " ( " + aData
[LockFileComponent::EDITTIME
] + " )";
971 if (!bIsLoading
) // so, !bHandleSysLocked
973 xInteractionRequestImpl
= new ::ucbhelper::InteractionRequest(uno::makeAny(
974 document::LockedOnSavingRequest(OUString(), uno::Reference
< uno::XInterface
>(), aDocumentURL
, aInfo
)));
975 // Currently, only the last "Retry" continuation (meaning ignore the lock and try overwriting) can be returned.
977 else /*logically therefore bIsLoading is set */
979 xInteractionRequestImpl
= new ::ucbhelper::InteractionRequest( uno::makeAny(
980 document::LockedDocumentRequest( OUString(), uno::Reference
< uno::XInterface
>(), aDocumentURL
, aInfo
) ) );
984 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > aContinuations(nContinuations
);
985 aContinuations
[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl
.get() );
986 aContinuations
[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl
.get() );
987 aContinuations
[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl
.get() );
988 if (nContinuations
> 3)
990 // We use InteractionRetry to reflect that user wants to
991 // ignore the (stale?) alien lock file and open/overwrite the document
992 aContinuations
[3] = new ::ucbhelper::InteractionRetry(xInteractionRequestImpl
.get());
994 xInteractionRequestImpl
->setContinuations( aContinuations
);
996 xHandler
->handle( xInteractionRequestImpl
.get() );
998 ::rtl::Reference
< ::ucbhelper::InteractionContinuation
> xSelected
= xInteractionRequestImpl
->getSelection();
999 if ( uno::Reference
< task::XInteractionAbort
>( xSelected
.get(), uno::UNO_QUERY
).is() )
1001 SetError(ERRCODE_ABORT
);
1003 else if ( uno::Reference
< task::XInteractionDisapprove
>( xSelected
.get(), uno::UNO_QUERY
).is() )
1005 // own lock on loading, user has selected to ignore the lock
1006 // own lock on saving, user has selected to ignore the lock
1007 // alien lock on loading, user has selected to edit a copy of document
1008 // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location
1009 if ( !bOwnLock
) // bIsLoading implied from outermost condition
1011 // means that a copy of the document should be opened
1012 GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE
, true ) );
1015 nResult
= ShowLockResult::Succeeded
;
1017 else if (uno::Reference
< task::XInteractionRetry
>(xSelected
.get(), uno::UNO_QUERY
).is())
1019 // User decided to ignore the alien (stale?) lock file without filesystem lock
1020 nResult
= ShowLockResult::Succeeded
;
1022 else // if ( XSelected == aContinuations[1] )
1024 // own lock on loading, user has selected to open readonly
1025 // own lock on saving, user has selected to open readonly
1026 // alien lock on loading, user has selected to retry saving
1027 // TODO/LATER: alien lock on saving, user has selected to retry saving
1030 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
1032 nResult
= ShowLockResult::Try
;
1039 // if no interaction handler is provided the default answer is open readonly
1040 // that usually happens in case the document is loaded per API
1041 // so the document must be opened readonly for backward compatibility
1042 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
1045 SetError(ERRCODE_IO_ACCESSDENIED
);
1053 bool SfxMedium::ShowLockFileProblemDialog(MessageDlg nWhichDlg
)
1055 // system file locking is not active, ask user whether he wants to open the document without any locking
1056 uno::Reference
< task::XInteractionHandler
> xHandler
= GetInteractionHandler();
1060 ::rtl::Reference
< ::ucbhelper::InteractionRequest
> xIgnoreRequestImpl
;
1064 case MessageDlg::LockFileIgnore
:
1065 xIgnoreRequestImpl
= new ::ucbhelper::InteractionRequest(uno::makeAny( document::LockFileIgnoreRequest() ));
1067 case MessageDlg::LockFileCorrupt
:
1068 xIgnoreRequestImpl
= new ::ucbhelper::InteractionRequest(uno::makeAny( document::LockFileCorruptRequest() ));
1072 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > aContinuations(2);
1073 aContinuations
[0] = new ::ucbhelper::InteractionAbort(xIgnoreRequestImpl
.get());
1074 aContinuations
[1] = new ::ucbhelper::InteractionApprove(xIgnoreRequestImpl
.get());
1075 xIgnoreRequestImpl
->setContinuations(aContinuations
);
1077 xHandler
->handle(xIgnoreRequestImpl
.get());
1079 ::rtl::Reference
< ::ucbhelper::InteractionContinuation
> xSelected
= xIgnoreRequestImpl
->getSelection();
1080 bool bReadOnly
= uno::Reference
< task::XInteractionApprove
>(xSelected
.get(), uno::UNO_QUERY
).is();
1084 GetItemSet()->Put(SfxBoolItem(SID_DOC_READONLY
, true));
1088 SetError(ERRCODE_ABORT
);
1099 bool isSuitableProtocolForLocking(const OUString
& rLogicName
)
1101 INetURLObject
aUrl( rLogicName
);
1102 INetProtocol eProt
= aUrl
.GetProtocol();
1103 #if !HAVE_FEATURE_MACOSX_SANDBOX
1104 if (eProt
== INetProtocol::File
) {
1108 return eProt
== INetProtocol::Smb
|| eProt
== INetProtocol::Sftp
;
1112 #endif // HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1114 // sets SID_DOC_READONLY if the document cannot be opened for editing
1115 // if user cancel the loading the ERROR_ABORT is set
1116 SfxMedium::LockFileResult
SfxMedium::LockOrigFileOnDemand(bool bLoading
, bool bNoUI
,
1117 bool bTryIgnoreLockFile
,
1118 LockFileEntry
* pLockData
)
1120 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1123 (void) bTryIgnoreLockFile
;
1125 return LockFileResult::Succeeded
;
1127 LockFileResult eResult
= LockFileResult::Failed
;
1129 // check if path scheme is http:// or https://
1130 // may be this is better if used always, in Android and iOS as well?
1131 // if this code should be always there, remember to move the relevant code in UnlockFile method as well !
1133 if ( GetURLObject().isAnyKnownWebDAVScheme() )
1135 // do nothing if WebDAV locking is disabled
1136 if (!IsWebDAVLockingUsed())
1137 return LockFileResult::Succeeded
;
1141 bool bResult
= pImpl
->m_bLocked
;
1142 bool bIsTemplate
= false;
1143 // so, this is webdav stuff...
1146 // no read-write access is necessary on loading if the document is explicitly opened as copy
1147 const SfxBoolItem
* pTemplateItem
= SfxItemSet::GetItem
<SfxBoolItem
>(GetItemSet(), SID_TEMPLATE
, false);
1148 bIsTemplate
= ( bLoading
&& pTemplateItem
&& pTemplateItem
->GetValue() );
1151 if ( !bIsTemplate
&& !bResult
&& !IsReadOnly() )
1153 ShowLockResult bUIStatus
= ShowLockResult::NoLock
;
1158 uno::Reference
< task::XInteractionHandler
> xCHandler
= GetInteractionHandler( true );
1159 Reference
< css::ucb::XCommandEnvironment
> xComEnv
= new ::ucbhelper::CommandEnvironment(
1160 xCHandler
, Reference
< css::ucb::XProgressHandler
>() );
1162 ucbhelper::Content
aContentToLock(
1163 GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
),
1164 xComEnv
, comphelper::getProcessComponentContext() );
1168 aContentToLock
.lock();
1171 catch ( ucb::InteractiveLockingLockedException
& )
1173 // received when the resource is already locked
1174 if (!bNoUI
|| pLockData
)
1176 // get the lock owner, using a special ucb.webdav property
1177 // the owner property retrieved here is what the other principal send the server
1178 // when activating the lock.
1179 // See http://tools.ietf.org/html/rfc4918#section-14.17 for details
1180 LockFileEntry aLockData
;
1181 aLockData
[LockFileComponent::OOOUSERNAME
] = "Unknown user";
1182 // This solution works right when the LO user name and the WebDAV user
1183 // name are the same.
1184 // A better thing to do would be to obtain the 'real' WebDAV user name,
1185 // but that's not possible from a WebDAV UCP provider client.
1186 LockFileEntry aOwnData
= svt::LockFileCommon::GenerateOwnEntry();
1187 // use the current LO user name as the system name
1188 aLockData
[LockFileComponent::SYSUSERNAME
]
1189 = aOwnData
[LockFileComponent::SYSUSERNAME
];
1191 uno::Sequence
<css::ucb::Lock
> aLocks
;
1192 // getting the property, send a PROPFIND to the server over the net
1193 if ((aContentToLock
.getPropertyValue("DAV:lockdiscovery") >>= aLocks
) && aLocks
.hasElements())
1195 // got at least a lock, show the owner of the first lock returned
1196 css::ucb::Lock aLock
= aLocks
[0];
1198 if (aLock
.Owner
>>= aOwner
)
1200 // we need to display the WebDAV user name owning the lock, not the local one
1201 aLockData
[LockFileComponent::OOOUSERNAME
] = aOwner
;
1207 bUIStatus
= ShowLockedDocumentDialog(aLockData
, bLoading
, false,
1213 std::copy(aLockData
.begin(), aLockData
.end(), pLockData
->begin());
1217 catch( ucb::InteractiveNetworkWriteException
& )
1219 // This catch it's not really needed, here just for the sake of documentation on the behaviour.
1220 // This is the most likely reason:
1221 // - the remote site is a WebDAV with special configuration: read/only for read operations
1222 // and read/write for write operations, the user is not allowed to lock/write and
1223 // she cancelled the credentials request.
1224 // this is not actually an error, but the exception is sent directly from ucb, avoiding the automatic
1225 // management that takes part in cancelCommandExecution()
1226 // Unfortunately there is no InteractiveNetwork*Exception available to signal this more correctly
1227 // since it mostly happens on read/only part of webdav, this can be the most correct
1228 // exception available
1230 catch( uno::Exception
& )
1233 } while( !bResult
&& bUIStatus
== ShowLockResult::Try
);
1236 pImpl
->m_bLocked
= bResult
;
1238 if ( !bResult
&& GetError() == ERRCODE_NONE
)
1240 // the error should be set in case it is storing process
1241 // or the document has been opened for editing explicitly
1242 const SfxBoolItem
* pReadOnlyItem
= SfxItemSet::GetItem
<SfxBoolItem
>(pImpl
->m_pSet
.get(), SID_DOC_READONLY
, false);
1244 if ( !bLoading
|| (pReadOnlyItem
&& !pReadOnlyItem
->GetValue()) )
1245 SetError(ERRCODE_IO_ACCESSDENIED
);
1247 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
1250 // when the file is locked, get the current file date
1251 if ( bResult
&& DocNeedsFileDateCheck() )
1252 GetInitFileDate( true );
1255 eResult
= LockFileResult::Succeeded
;
1257 catch ( const uno::Exception
& )
1259 TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
1264 if (!IsLockingUsed())
1265 return LockFileResult::Succeeded
;
1266 if (GetURLObject().HasError())
1271 if ( pImpl
->m_bLocked
&& bLoading
1272 && GetURLObject().GetProtocol() == INetProtocol::File
)
1274 // if the document is already locked the system locking might be temporarily off after storing
1275 // check whether the system file locking should be taken again
1276 GetLockingStream_Impl();
1279 bool bResult
= pImpl
->m_bLocked
;
1283 // no read-write access is necessary on loading if the document is explicitly opened as copy
1284 const SfxBoolItem
* pTemplateItem
= SfxItemSet::GetItem
<SfxBoolItem
>(GetItemSet(), SID_TEMPLATE
, false);
1285 bResult
= ( bLoading
&& pTemplateItem
&& pTemplateItem
->GetValue() );
1288 if ( !bResult
&& !IsReadOnly() )
1290 bool bContentReadonly
= false;
1291 if ( bLoading
&& GetURLObject().GetProtocol() == INetProtocol::File
)
1293 // let the original document be opened to check the possibility to open it for editing
1294 // and to let the writable stream stay open to hold the lock on the document
1295 GetLockingStream_Impl();
1298 // "IsReadOnly" property does not allow to detect whether the file is readonly always
1299 // so we try always to open the file for editing
1300 // the file is readonly only in case the read-write stream can not be opened
1301 if ( bLoading
&& !pImpl
->m_xLockingStream
.is() )
1305 // MediaDescriptor does this check also, the duplication should be avoided in future
1306 Reference
< css::ucb::XCommandEnvironment
> xDummyEnv
;
1307 ::ucbhelper::Content
aContent( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
), xDummyEnv
, comphelper::getProcessComponentContext() );
1308 aContent
.getPropertyValue("IsReadOnly") >>= bContentReadonly
;
1310 catch( const uno::Exception
& ) {}
1313 // do further checks only if the file not readonly in fs
1314 if ( !bContentReadonly
)
1316 // the special file locking should be used only for suitable URLs
1317 if ( isSuitableProtocolForLocking( pImpl
->m_aLogicName
) )
1320 // in case of storing the document should request the output before locking
1323 // let the stream be opened to check the system file locking
1325 if (GetError() != ERRCODE_NONE
) {
1330 ShowLockResult bUIStatus
= ShowLockResult::NoLock
;
1332 // check whether system file locking has been used, the default value is false
1333 bool bUseSystemLock
= comphelper::isFileUrl( pImpl
->m_aLogicName
) && IsSystemFileLockingUsed();
1335 // TODO/LATER: This implementation does not allow to detect the system lock on saving here, actually this is no big problem
1336 // if system lock is used the writeable stream should be available
1337 bool bHandleSysLocked
= ( bLoading
&& bUseSystemLock
&& !pImpl
->xStream
.is() && !pImpl
->m_pOutStream
);
1339 // The file is attempted to get locked for the duration of lockfile creation on save
1340 std::unique_ptr
<osl::File
> pFileLock
;
1341 if (!bLoading
&& bUseSystemLock
&& pImpl
->pTempFile
)
1343 INetURLObject
aDest(GetURLObject());
1344 OUString
aDestURL(aDest
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
1346 if (comphelper::isFileUrl(aDestURL
) || !aDest
.removeSegment())
1348 pFileLock
= std::make_unique
<osl::File
>(aDestURL
);
1349 auto rc
= pFileLock
->open(osl_File_OpenFlag_Write
);
1350 if (rc
== osl::FileBase::E_ACCES
)
1351 bHandleSysLocked
= true;
1359 ::svt::DocumentLockFile
aLockFile( pImpl
->m_aLogicName
);
1361 std::unique_ptr
<svt::MSODocumentLockFile
> pMSOLockFile
;
1362 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
1363 if (rOpt
.IsMSOLockFileCreationIsEnabled() && svt::MSODocumentLockFile::IsMSOSupportedFileFormat(pImpl
->m_aLogicName
))
1365 pMSOLockFile
.reset(new svt::MSODocumentLockFile(pImpl
->m_aLogicName
));
1366 pImpl
->m_bMSOLockFileCreated
= true;
1369 bool bIoErr
= false;
1371 if (!bHandleSysLocked
)
1375 bResult
= aLockFile
.CreateOwnLockFile();
1377 bResult
&= pMSOLockFile
->CreateOwnLockFile();
1379 catch (const uno::Exception
&)
1381 if (tools::IsMappedWebDAVPath(GetURLObject().GetMainURL(
1382 INetURLObject::DecodeMechanism::NONE
)))
1384 // This is a path that redirects to a WebDAV resource;
1385 // so failure creating lockfile is not an error here.
1388 else if (bLoading
&& !bNoUI
)
1391 ShowLockFileProblemDialog(MessageDlg::LockFileIgnore
);
1392 bResult
= true; // always delete the defect lock-file
1396 // in case OOo locking is turned off the lock file is still written if possible
1397 // but it is ignored while deciding whether the document should be opened for editing or not
1398 if (!bResult
&& !IsOOoLockFileUsed() && !bIoErr
)
1401 // take the ownership over the lock file
1402 aLockFile
.OverwriteOwnLockFile();
1405 pMSOLockFile
->OverwriteOwnLockFile();
1411 LockFileEntry aData
;
1414 aData
= aLockFile
.GetLockData();
1416 catch (const io::WrongFormatException
&)
1418 // we get empty or corrupt data
1420 if (!bIoErr
&& bLoading
&& !bNoUI
)
1421 bResult
= ShowLockFileProblemDialog(MessageDlg::LockFileCorrupt
);
1423 // not show the Lock Document Dialog
1426 catch( const uno::Exception
& )
1428 // show the Lock Document Dialog, when locked from other app
1429 bIoErr
= !bHandleSysLocked
;
1432 bool bOwnLock
= false;
1434 if (!bHandleSysLocked
)
1436 LockFileEntry aOwnData
= svt::LockFileCommon::GenerateOwnEntry();
1437 bOwnLock
= aOwnData
[LockFileComponent::SYSUSERNAME
] == aData
[LockFileComponent::SYSUSERNAME
];
1440 && aOwnData
[LockFileComponent::LOCALHOST
] == aData
[LockFileComponent::LOCALHOST
]
1441 && aOwnData
[LockFileComponent::USERURL
] == aData
[LockFileComponent::USERURL
])
1443 // this is own lock from the same installation, it could remain because of crash
1448 if ( !bResult
&& !bIoErr
)
1451 bUIStatus
= ShowLockedDocumentDialog(
1452 aData
, bLoading
, bOwnLock
, bHandleSysLocked
);
1453 else if (bLoading
&& bTryIgnoreLockFile
&& !bHandleSysLocked
)
1454 bUIStatus
= ShowLockResult::Succeeded
;
1456 if ( bUIStatus
== ShowLockResult::Succeeded
)
1458 // take the ownership over the lock file
1459 bResult
= aLockFile
.OverwriteOwnLockFile();
1462 pMSOLockFile
->OverwriteOwnLockFile();
1464 else if (bLoading
&& !bHandleSysLocked
)
1465 eResult
= LockFileResult::FailedLockFile
;
1467 if (!bResult
&& pLockData
)
1469 std::copy(aData
.begin(), aData
.end(), pLockData
->begin());
1474 catch( const uno::Exception
& )
1477 } while( !bResult
&& bUIStatus
== ShowLockResult::Try
);
1479 pImpl
->m_bLocked
= bResult
;
1483 // this is no file URL, check whether the file is readonly
1484 bResult
= !bContentReadonly
;
1489 if ( !bResult
&& GetError() == ERRCODE_NONE
)
1491 // the error should be set in case it is storing process
1492 // or the document has been opened for editing explicitly
1493 const SfxBoolItem
* pReadOnlyItem
= SfxItemSet::GetItem
<SfxBoolItem
>(pImpl
->m_pSet
.get(), SID_DOC_READONLY
, false);
1495 if ( !bLoading
|| (pReadOnlyItem
&& !pReadOnlyItem
->GetValue()) )
1496 SetError(ERRCODE_IO_ACCESSDENIED
);
1498 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
1501 // when the file is locked, get the current file date
1502 if ( bResult
&& DocNeedsFileDateCheck() )
1503 GetInitFileDate( true );
1506 eResult
= LockFileResult::Succeeded
;
1508 catch( const uno::Exception
& )
1510 TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: high probability, that the content has not been created" );
1518 uno::Reference
< embed::XStorage
> SfxMedium::GetStorage( bool bCreateTempFile
)
1520 if ( pImpl
->xStorage
.is() || pImpl
->m_bTriedStorage
)
1521 return pImpl
->xStorage
;
1523 uno::Sequence
< uno::Any
> aArgs( 2 );
1525 // the medium should be retrieved before temporary file creation
1526 // to let the MediaDescriptor be filled with the streams
1529 if ( bCreateTempFile
)
1530 CreateTempFile( false );
1535 return pImpl
->xStorage
;
1537 const SfxBoolItem
* pRepairItem
= SfxItemSet::GetItem
<SfxBoolItem
>(GetItemSet(), SID_REPAIRPACKAGE
, false);
1538 if ( pRepairItem
&& pRepairItem
->GetValue() )
1540 // the storage should be created for repairing mode
1541 CreateTempFile( false );
1544 Reference
< css::ucb::XProgressHandler
> xProgressHandler
;
1545 Reference
< css::task::XStatusIndicator
> xStatusIndicator
;
1547 const SfxUnoAnyItem
* pxProgressItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(GetItemSet(), SID_PROGRESS_STATUSBAR_CONTROL
, false);
1548 if( pxProgressItem
&& ( pxProgressItem
->GetValue() >>= xStatusIndicator
) )
1549 xProgressHandler
.set( new utl::ProgressHandlerWrap( xStatusIndicator
) );
1551 uno::Sequence
< beans::PropertyValue
> aAddProps( 2 );
1552 aAddProps
[0].Name
= "RepairPackage";
1553 aAddProps
[0].Value
<<= true;
1554 aAddProps
[1].Name
= "StatusIndicator";
1555 aAddProps
[1].Value
<<= xProgressHandler
;
1557 // the first arguments will be filled later
1559 aArgs
[2] <<= aAddProps
;
1562 if ( pImpl
->xStream
.is() )
1564 // since the storage is based on temporary stream we open it always read-write
1565 aArgs
[0] <<= pImpl
->xStream
;
1566 aArgs
[1] <<= embed::ElementModes::READWRITE
;
1567 pImpl
->bStorageBasedOnInStream
= true;
1568 if (pImpl
->m_bDisableFileSync
)
1570 // Forward NoFileSync to the storage factory.
1572 uno::Sequence
<beans::PropertyValue
> aProperties(
1573 comphelper::InitPropertySequence({ { "NoFileSync", uno::makeAny(true) } }));
1574 aArgs
[2] <<= aProperties
;
1577 else if ( pImpl
->xInputStream
.is() )
1579 // since the storage is based on temporary stream we open it always read-write
1580 aArgs
[0] <<= pImpl
->xInputStream
;
1581 aArgs
[1] <<= embed::ElementModes::READ
;
1582 pImpl
->bStorageBasedOnInStream
= true;
1586 CloseStreams_Impl();
1587 aArgs
[0] <<= pImpl
->m_aName
;
1588 aArgs
[1] <<= embed::ElementModes::READ
;
1589 pImpl
->bStorageBasedOnInStream
= false;
1594 pImpl
->xStorage
.set( ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs
),
1597 catch( const uno::Exception
& )
1599 // impossibility to create the storage is no error
1602 if( ( pImpl
->nLastStorageError
= GetError() ) != ERRCODE_NONE
)
1604 pImpl
->xStorage
= nullptr;
1605 if ( pImpl
->m_pInStream
)
1606 pImpl
->m_pInStream
->Seek(0);
1607 return uno::Reference
< embed::XStorage
>();
1610 pImpl
->m_bTriedStorage
= true;
1612 // TODO/LATER: Get versionlist on demand
1613 if ( pImpl
->xStorage
.is() )
1615 SetEncryptionDataToStorage_Impl();
1619 const SfxInt16Item
* pVersion
= SfxItemSet::GetItem
<SfxInt16Item
>(pImpl
->m_pSet
.get(), SID_VERSION
, false);
1621 bool bResetStorage
= false;
1622 if ( pVersion
&& pVersion
->GetValue() )
1624 // Read all available versions
1625 if ( pImpl
->aVersions
.hasElements() )
1627 // Search for the version fits the comment
1628 // The versions are numbered starting with 1, versions with
1629 // negative versions numbers are counted backwards from the
1631 short nVersion
= pVersion
->GetValue();
1633 nVersion
= static_cast<short>(pImpl
->aVersions
.getLength()) + nVersion
;
1634 else // nVersion > 0; pVersion->GetValue() != 0 was the condition to this block
1637 util::RevisionTag
& rTag
= pImpl
->aVersions
[nVersion
];
1639 // Open SubStorage for all versions
1640 uno::Reference
< embed::XStorage
> xSub
= pImpl
->xStorage
->openStorageElement( "Versions",
1641 embed::ElementModes::READ
);
1643 DBG_ASSERT( xSub
.is(), "Version list, but no Versions!" );
1645 // There the version is stored as packed Stream
1646 uno::Reference
< io::XStream
> xStr
= xSub
->openStreamElement( rTag
.Identifier
, embed::ElementModes::READ
);
1647 std::unique_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream( xStr
));
1648 if ( pStream
&& pStream
->GetError() == ERRCODE_NONE
)
1650 // Unpack Stream in TempDir
1651 ::utl::TempFile aTempFile
;
1652 const OUString
& aTmpName
= aTempFile
.GetURL();
1653 SvFileStream
aTmpStream( aTmpName
, SFX_STREAM_READWRITE
);
1655 pStream
->ReadStream( aTmpStream
);
1659 // Open data as Storage
1660 pImpl
->m_nStorOpenMode
= SFX_STREAM_READONLY
;
1661 pImpl
->xStorage
= comphelper::OStorageHelper::GetStorageFromURL( aTmpName
, embed::ElementModes::READ
);
1662 pImpl
->bStorageBasedOnInStream
= false;
1664 osl::FileBase::getSystemPathFromFileURL( aTmpName
, aTemp
);
1665 SetPhysicalName_Impl( aTemp
);
1667 pImpl
->bIsTemp
= true;
1668 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
1670 pImpl
->aVersions
.realloc(0);
1673 bResetStorage
= true;
1677 bResetStorage
= true;
1680 if ( bResetStorage
)
1682 pImpl
->xStorage
.clear();
1683 if ( pImpl
->m_pInStream
)
1684 pImpl
->m_pInStream
->Seek( 0 );
1687 pImpl
->bIsStorage
= pImpl
->xStorage
.is();
1688 return pImpl
->xStorage
;
1692 uno::Reference
< embed::XStorage
> const & SfxMedium::GetZipStorageToSign_Impl( bool bReadOnly
)
1694 if ( !GetError() && !pImpl
->m_xZipStorage
.is() )
1700 // we can not sign document if there is no stream
1701 // should it be possible at all?
1702 if ( !bReadOnly
&& pImpl
->xStream
.is() )
1704 pImpl
->m_xZipStorage
= ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING
, pImpl
->xStream
);
1706 else if ( pImpl
->xInputStream
.is() )
1708 pImpl
->m_xZipStorage
= ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( ZIP_STORAGE_FORMAT_STRING
, pImpl
->xInputStream
);
1711 catch( const uno::Exception
& )
1713 SAL_WARN( "sfx.doc", "No possibility to get readonly version of storage from medium!" );
1716 if ( GetError() ) // do not remove warnings
1720 return pImpl
->m_xZipStorage
;
1724 void SfxMedium::CloseZipStorage_Impl()
1726 if ( pImpl
->m_xZipStorage
.is() )
1729 pImpl
->m_xZipStorage
->dispose();
1730 } catch( const uno::Exception
& )
1733 pImpl
->m_xZipStorage
.clear();
1737 void SfxMedium::CloseStorage()
1739 if ( pImpl
->xStorage
.is() )
1741 uno::Reference
< lang::XComponent
> xComp
= pImpl
->xStorage
;
1742 // in the salvage mode the medium does not own the storage
1743 if ( pImpl
->bDisposeStorage
&& !pImpl
->m_bSalvageMode
)
1747 } catch( const uno::Exception
& )
1749 SAL_WARN( "sfx.doc", "Medium's storage is already disposed!" );
1753 pImpl
->xStorage
.clear();
1754 pImpl
->bStorageBasedOnInStream
= false;
1757 pImpl
->m_bTriedStorage
= false;
1758 pImpl
->bIsStorage
= false;
1761 void SfxMedium::CanDisposeStorage_Impl( bool bDisposeStorage
)
1763 pImpl
->bDisposeStorage
= bDisposeStorage
;
1766 bool SfxMedium::WillDisposeStorageOnClose_Impl()
1768 return pImpl
->bDisposeStorage
;
1771 StreamMode
SfxMedium::GetOpenMode() const
1773 return pImpl
->m_nStorOpenMode
;
1776 void SfxMedium::SetOpenMode( StreamMode nStorOpen
,
1779 if ( pImpl
->m_nStorOpenMode
!= nStorOpen
)
1781 pImpl
->m_nStorOpenMode
= nStorOpen
;
1785 if ( pImpl
->xStorage
.is() )
1788 CloseStreams_Impl();
1794 bool SfxMedium::UseBackupToRestore_Impl( ::ucbhelper::Content
& aOriginalContent
,
1795 const Reference
< css::ucb::XCommandEnvironment
>& xComEnv
)
1799 ::ucbhelper::Content
aTransactCont( pImpl
->m_aBackupURL
, xComEnv
, comphelper::getProcessComponentContext() );
1801 Reference
< XInputStream
> aOrigInput
= aTransactCont
.openStream();
1802 aOriginalContent
.writeStream( aOrigInput
, true );
1805 catch( const Exception
& )
1807 // in case of failure here the backup file should not be removed
1808 // TODO/LATER: a message should be used to let user know about the backup
1809 pImpl
->m_bRemoveBackup
= false;
1810 // TODO/LATER: needs a specific error code
1811 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
1818 bool SfxMedium::StorageCommit_Impl()
1820 bool bResult
= false;
1821 Reference
< css::ucb::XCommandEnvironment
> xDummyEnv
;
1822 ::ucbhelper::Content aOriginalContent
;
1824 if ( pImpl
->xStorage
.is() )
1828 uno::Reference
< embed::XTransactedObject
> xTrans( pImpl
->xStorage
, uno::UNO_QUERY
);
1834 CloseZipStorage_Impl();
1837 catch ( const embed::UseBackupException
& aBackupExc
)
1839 // since the temporary file is created always now, the scenario is close to be impossible
1840 if ( !pImpl
->pTempFile
)
1842 OSL_ENSURE( !pImpl
->m_aBackupURL
.isEmpty(), "No backup on storage commit!" );
1843 if ( !pImpl
->m_aBackupURL
.isEmpty()
1844 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
),
1845 xDummyEnv
, comphelper::getProcessComponentContext(),
1846 aOriginalContent
) )
1848 // use backup to restore the file
1849 // the storage has already disconnected from original location
1850 CloseAndReleaseStreams_Impl();
1851 if ( !UseBackupToRestore_Impl( aOriginalContent
, xDummyEnv
) )
1853 // connect the medium to the temporary file of the storage
1854 pImpl
->aContent
= ::ucbhelper::Content();
1855 pImpl
->m_aName
= aBackupExc
.TemporaryFileURL
;
1856 OSL_ENSURE( !pImpl
->m_aName
.isEmpty(), "The exception _must_ contain the temporary URL!" );
1862 SetError(ERRCODE_IO_GENERAL
);
1864 catch ( const uno::Exception
& )
1866 //TODO/LATER: improve error handling
1867 SetError(ERRCODE_IO_GENERAL
);
1877 void SfxMedium::TransactedTransferForFS_Impl( const INetURLObject
& aSource
,
1878 const INetURLObject
& aDest
,
1879 const Reference
< css::ucb::XCommandEnvironment
>& xComEnv
)
1881 Reference
< css::ucb::XCommandEnvironment
> xDummyEnv
;
1882 ::ucbhelper::Content aOriginalContent
;
1886 aOriginalContent
= ::ucbhelper::Content( aDest
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), xComEnv
, comphelper::getProcessComponentContext() );
1888 catch ( const css::ucb::CommandAbortedException
& )
1890 pImpl
->m_eError
= ERRCODE_ABORT
;
1892 catch ( const css::ucb::CommandFailedException
& )
1894 pImpl
->m_eError
= ERRCODE_ABORT
;
1896 catch (const css::ucb::ContentCreationException
& ex
)
1898 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
1900 (ex
.eError
== css::ucb::ContentCreationError_NO_CONTENT_PROVIDER
) ||
1901 (ex
.eError
== css::ucb::ContentCreationError_CONTENT_CREATION_FAILED
)
1904 pImpl
->m_eError
= ERRCODE_IO_NOTEXISTSPATH
;
1907 catch (const css::uno::Exception
&)
1909 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
1912 if( pImpl
->m_eError
&& !pImpl
->m_eError
.IsWarning() )
1915 if ( pImpl
->xStorage
.is() )
1918 CloseStreams_Impl();
1920 ::ucbhelper::Content aTempCont
;
1921 if( ::ucbhelper::Content::create( aSource
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), xDummyEnv
, comphelper::getProcessComponentContext(), aTempCont
) )
1923 bool bTransactStarted
= false;
1924 const SfxBoolItem
* pOverWrite
= SfxItemSet::GetItem
<SfxBoolItem
>(GetItemSet(), SID_OVERWRITE
, false);
1925 bool bOverWrite
= !pOverWrite
|| pOverWrite
->GetValue();
1926 bool bResult
= false;
1930 OUString aSourceMainURL
= aSource
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
1931 OUString aDestMainURL
= aDest
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
1933 sal_uInt64 nAttributes
= GetDefaultFileAttributes(aDestMainURL
);
1934 if (IsFileMovable(aDest
)
1935 && osl::File::replace(aSourceMainURL
, aDestMainURL
) == osl::FileBase::E_None
)
1938 // Adjust attributes, source might be created with
1939 // the osl_File_OpenFlag_Private flag.
1940 osl::File::setAttributes(aDestMainURL
, nAttributes
);
1945 if (bOverWrite
&& ::utl::UCBContentHelper::IsDocument(aDestMainURL
))
1947 if( pImpl
->m_aBackupURL
.isEmpty() )
1948 DoInternalBackup_Impl( aOriginalContent
);
1950 if( !pImpl
->m_aBackupURL
.isEmpty() )
1952 Reference
< XInputStream
> aTempInput
= aTempCont
.openStream();
1953 bTransactStarted
= true;
1954 aOriginalContent
.setPropertyValue( "Size", uno::makeAny( sal_Int64(0) ) );
1955 aOriginalContent
.writeStream( aTempInput
, bOverWrite
);
1960 pImpl
->m_eError
= ERRCODE_SFX_CANTCREATEBACKUP
;
1965 Reference
< XInputStream
> aTempInput
= aTempCont
.openStream();
1966 aOriginalContent
.writeStream( aTempInput
, bOverWrite
);
1971 catch ( const css::ucb::CommandAbortedException
& )
1973 pImpl
->m_eError
= ERRCODE_ABORT
;
1975 catch ( const css::ucb::CommandFailedException
& )
1977 pImpl
->m_eError
= ERRCODE_ABORT
;
1979 catch ( const css::ucb::InteractiveIOException
& r
)
1981 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
)
1982 pImpl
->m_eError
= ERRCODE_IO_ACCESSDENIED
;
1983 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
1984 pImpl
->m_eError
= ERRCODE_IO_NOTEXISTS
;
1985 else if ( r
.Code
== IOErrorCode_CANT_READ
)
1986 pImpl
->m_eError
= ERRCODE_IO_CANTREAD
;
1988 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
1990 catch ( const css::uno::Exception
& )
1992 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
1997 if ( pImpl
->pTempFile
)
1999 pImpl
->pTempFile
->EnableKillingFile();
2000 pImpl
->pTempFile
.reset();
2003 else if ( bTransactStarted
)
2005 UseBackupToRestore_Impl( aOriginalContent
, xDummyEnv
);
2009 pImpl
->m_eError
= ERRCODE_IO_CANTREAD
;
2013 bool SfxMedium::TryDirectTransfer( const OUString
& aURL
, SfxItemSet
const & aTargetSet
)
2018 // if the document had no password it should be stored without password
2019 // if the document had password it should be stored with the same password
2020 // otherwise the stream copying can not be done
2021 const SfxStringItem
* pNewPassItem
= aTargetSet
.GetItem
<SfxStringItem
>(SID_PASSWORD
, false);
2022 const SfxStringItem
* pOldPassItem
= SfxItemSet::GetItem
<SfxStringItem
>(GetItemSet(), SID_PASSWORD
, false);
2023 if ( ( !pNewPassItem
&& !pOldPassItem
)
2024 || ( pNewPassItem
&& pOldPassItem
&& pNewPassItem
->GetValue() == pOldPassItem
->GetValue() ) )
2026 // the filter must be the same
2027 const SfxStringItem
* pNewFilterItem
= aTargetSet
.GetItem
<SfxStringItem
>(SID_FILTER_NAME
, false);
2028 const SfxStringItem
* pOldFilterItem
= SfxItemSet::GetItem
<SfxStringItem
>(GetItemSet(), SID_FILTER_NAME
, false);
2029 if ( pNewFilterItem
&& pOldFilterItem
&& pNewFilterItem
->GetValue() == pOldFilterItem
->GetValue() )
2031 // get the input stream and copy it
2032 // in case of success return true
2033 uno::Reference
< io::XInputStream
> xInStream
= GetInputStream();
2036 if ( xInStream
.is() )
2040 uno::Reference
< io::XSeekable
> xSeek( xInStream
, uno::UNO_QUERY
);
2044 nPos
= xSeek
->getPosition();
2048 uno::Reference
< css::ucb::XCommandEnvironment
> xEnv
;
2049 ::ucbhelper::Content
aTargetContent( aURL
, xEnv
, comphelper::getProcessComponentContext() );
2051 InsertCommandArgument aInsertArg
;
2052 aInsertArg
.Data
= xInStream
;
2053 const SfxBoolItem
* pOverWrite
= aTargetSet
.GetItem
<SfxBoolItem
>(SID_OVERWRITE
, false);
2054 if ( pOverWrite
&& !pOverWrite
->GetValue() ) // argument says: never overwrite
2055 aInsertArg
.ReplaceExisting
= false;
2057 aInsertArg
.ReplaceExisting
= true; // default is overwrite existing files
2060 aCmdArg
<<= aInsertArg
;
2061 aTargetContent
.executeCommand( "insert",
2065 xSeek
->seek( nPos
);
2069 catch( const uno::Exception
& )
2079 void SfxMedium::Transfer_Impl()
2081 // The transfer is required only in two cases: either if there is a temporary file or if there is a salvage item
2083 if ( pImpl
->pTempFile
)
2084 aNameURL
= pImpl
->pTempFile
->GetURL();
2085 else if ( !pImpl
->m_aLogicName
.isEmpty() && pImpl
->m_bSalvageMode
)
2087 // makes sense only in case logic name is set
2088 if ( osl::FileBase::getFileURLFromSystemPath( pImpl
->m_aName
, aNameURL
)
2089 != osl::FileBase::E_None
)
2090 SAL_WARN( "sfx.doc", "The medium name is not convertible!" );
2093 if ( aNameURL
.isEmpty() || ( pImpl
->m_eError
&& !pImpl
->m_eError
.IsWarning() ) )
2096 SAL_INFO( "sfx.doc", "SfxMedium::Transfer_Impl, copying to target" );
2098 Reference
< css::ucb::XCommandEnvironment
> xEnv
;
2099 Reference
< XOutputStream
> rOutStream
;
2101 // in case an output stream is provided from outside and the URL is correct
2102 // commit to the stream
2103 if (pImpl
->m_aLogicName
.startsWith("private:stream"))
2105 // TODO/LATER: support storing to SID_STREAM
2106 const SfxUnoAnyItem
* pOutStreamItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(pImpl
->m_pSet
.get(), SID_OUTPUTSTREAM
, false);
2107 if( pOutStreamItem
&& ( pOutStreamItem
->GetValue() >>= rOutStream
) )
2109 if ( pImpl
->xStorage
.is() )
2112 CloseStreams_Impl();
2114 INetURLObject
aSource( aNameURL
);
2115 ::ucbhelper::Content aTempCont
;
2116 if( ::ucbhelper::Content::create( aSource
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), xEnv
, comphelper::getProcessComponentContext(), aTempCont
) )
2121 sal_Int32 nBufferSize
= 32767;
2122 Sequence
< sal_Int8
> aSequence ( nBufferSize
);
2123 Reference
< XInputStream
> aTempInput
= aTempCont
.openStream();
2127 nRead
= aTempInput
->readBytes ( aSequence
, nBufferSize
);
2128 if ( nRead
< nBufferSize
)
2130 Sequence
< sal_Int8
> aTempBuf ( aSequence
.getConstArray(), nRead
);
2131 rOutStream
->writeBytes ( aTempBuf
);
2134 rOutStream
->writeBytes ( aSequence
);
2136 while ( nRead
== nBufferSize
);
2138 // remove temporary file
2139 if ( pImpl
->pTempFile
)
2141 pImpl
->pTempFile
->EnableKillingFile();
2142 pImpl
->pTempFile
.reset();
2145 catch( const Exception
& )
2151 SAL_WARN( "sfx.doc", "Illegal Output stream parameter!" );
2152 SetError(ERRCODE_IO_GENERAL
);
2155 // free the reference
2156 if ( pImpl
->m_pSet
)
2157 pImpl
->m_pSet
->ClearItem( SID_OUTPUTSTREAM
);
2163 if ( !pImpl
->aContent
.get().is() )
2165 pImpl
->m_eError
= ERRCODE_IO_NOTEXISTS
;
2169 INetURLObject
aDest( GetURLObject() );
2171 // source is the temp file written so far
2172 INetURLObject
aSource( aNameURL
);
2174 // a special case, an interaction handler should be used for
2175 // authentication in case it is available
2176 Reference
< css::ucb::XCommandEnvironment
> xComEnv
;
2177 Reference
< css::task::XInteractionHandler
> xInteractionHandler
= GetInteractionHandler();
2178 if (xInteractionHandler
.is())
2179 xComEnv
= new ::ucbhelper::CommandEnvironment( xInteractionHandler
,
2180 Reference
< css::ucb::XProgressHandler
>() );
2182 OUString
aDestURL( aDest
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
2184 if ( comphelper::isFileUrl( aDestURL
) || !aDest
.removeSegment() )
2186 TransactedTransferForFS_Impl( aSource
, aDest
, xComEnv
);
2188 if (!pImpl
->m_bDisableFileSync
)
2190 // Hideous - no clean way to do this, so we re-open the file just to fsync it
2191 osl::File
aFile( aDestURL
);
2192 if ( aFile
.open( osl_File_OpenFlag_Write
) == osl::FileBase::E_None
)
2195 SAL_INFO( "sfx.doc", "fsync'd saved file '" << aDestURL
<< "'" );
2202 // create content for the parent folder and call transfer on that content with the source content
2203 // and the destination file name as parameters
2204 ::ucbhelper::Content aSourceContent
;
2205 ::ucbhelper::Content aTransferContent
;
2207 ::ucbhelper::Content aDestContent
;
2208 (void)::ucbhelper::Content::create( aDestURL
, xComEnv
, comphelper::getProcessComponentContext(), aDestContent
);
2209 // For checkin, we need the object URL, not the parent folder:
2210 if ( !IsInCheckIn( ) )
2212 // Get the parent URL from the XChild if possible: why would the URL necessarily have
2213 // a hierarchical path? It's not always the case for CMIS.
2214 Reference
< css::container::XChild
> xChild( aDestContent
.get(), uno::UNO_QUERY
);
2215 OUString sParentUrl
;
2218 Reference
< css::ucb::XContent
> xParent( xChild
->getParent( ), uno::UNO_QUERY
);
2219 if ( xParent
.is( ) )
2221 sParentUrl
= xParent
->getIdentifier( )->getContentIdentifier();
2225 if ( sParentUrl
.isEmpty() )
2226 aDestURL
= aDest
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
2227 // adjust to above aDest.removeSegment()
2229 aDestURL
= sParentUrl
;
2232 // LongName wasn't defined anywhere, only used here... get the Title instead
2233 // as it's less probably empty
2235 Any aAny
= aDestContent
.getPropertyValue("Title");
2237 aAny
= aDestContent
.getPropertyValue( "ObjectId" );
2240 if ( aFileName
.isEmpty() )
2241 aFileName
= GetURLObject().getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
);
2245 aTransferContent
= ::ucbhelper::Content( aDestURL
, xComEnv
, comphelper::getProcessComponentContext() );
2247 catch (const css::ucb::ContentCreationException
& ex
)
2249 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
2251 (ex
.eError
== css::ucb::ContentCreationError_NO_CONTENT_PROVIDER
) ||
2252 (ex
.eError
== css::ucb::ContentCreationError_CONTENT_CREATION_FAILED
)
2255 pImpl
->m_eError
= ERRCODE_IO_NOTEXISTSPATH
;
2258 catch (const css::uno::Exception
&)
2260 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
2263 if ( !pImpl
->m_eError
|| pImpl
->m_eError
.IsWarning() )
2265 // free resources, otherwise the transfer may fail
2266 if ( pImpl
->xStorage
.is() )
2269 CloseStreams_Impl();
2271 (void)::ucbhelper::Content::create( aSource
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), xEnv
, comphelper::getProcessComponentContext(), aSourceContent
);
2273 // check for external parameters that may customize the handling of NameClash situations
2274 const SfxBoolItem
* pOverWrite
= SfxItemSet::GetItem
<SfxBoolItem
>(GetItemSet(), SID_OVERWRITE
, false);
2275 sal_Int32 nNameClash
;
2276 if ( pOverWrite
&& !pOverWrite
->GetValue() )
2277 // argument says: never overwrite
2278 nNameClash
= NameClash::ERROR
;
2280 // default is overwrite existing files
2281 nNameClash
= NameClash::OVERWRITE
;
2285 OUString aMimeType
= pImpl
->getFilterMimeType();
2286 ::ucbhelper::InsertOperation eOperation
= ::ucbhelper::InsertOperation::Copy
;
2287 bool bMajor
= false;
2289 if ( IsInCheckIn( ) )
2291 eOperation
= ::ucbhelper::InsertOperation::Checkin
;
2292 const SfxBoolItem
* pMajor
= SfxItemSet::GetItem
<SfxBoolItem
>(GetItemSet(), SID_DOCINFO_MAJOR
, false);
2293 bMajor
= pMajor
&& pMajor
->GetValue( );
2294 const SfxStringItem
* pComments
= SfxItemSet::GetItem
<SfxStringItem
>(GetItemSet(), SID_DOCINFO_COMMENTS
, false);
2296 sComment
= pComments
->GetValue( );
2298 OUString sResultURL
;
2299 aTransferContent
.transferContent(
2300 aSourceContent
, eOperation
,
2301 aFileName
, nNameClash
, aMimeType
, bMajor
, sComment
,
2302 &sResultURL
, sObjectId
);
2304 if ( !sResultURL
.isEmpty( ) ) // Likely to happen only for checkin
2305 SwitchDocumentToFile( sResultURL
);
2308 if ( GetURLObject().isAnyKnownWebDAVScheme() &&
2309 eOperation
== ::ucbhelper::InsertOperation::Copy
)
2311 // tdf#95272 try to re-issue a lock command when a new file is created.
2312 // This may be needed because some WebDAV servers fail to implement the
2313 // 'LOCK on unallocated reference', see issue comment:
2314 // <https://bugs.documentfoundation.org/show_bug.cgi?id=95792#c8>
2315 // and specification at:
2316 // <http://tools.ietf.org/html/rfc4918#section-7.3>
2317 // If the WebDAV resource is already locked by this LO instance, nothing will
2318 // happen, e.g. the LOCK method will not be sent to the server.
2319 ::ucbhelper::Content
aLockContent( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
), xComEnv
, comphelper::getProcessComponentContext() );
2320 aLockContent
.lock();
2323 catch ( css::uno::Exception
& )
2325 TOOLS_WARN_EXCEPTION( "sfx.doc", "LOCK not working while re-issuing it" );
2328 catch ( const css::ucb::CommandAbortedException
& )
2330 pImpl
->m_eError
= ERRCODE_ABORT
;
2332 catch ( const css::ucb::CommandFailedException
& )
2334 pImpl
->m_eError
= ERRCODE_ABORT
;
2336 catch ( const css::ucb::InteractiveIOException
& r
)
2338 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
)
2339 pImpl
->m_eError
= ERRCODE_IO_ACCESSDENIED
;
2340 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
2341 pImpl
->m_eError
= ERRCODE_IO_NOTEXISTS
;
2342 else if ( r
.Code
== IOErrorCode_CANT_READ
)
2343 pImpl
->m_eError
= ERRCODE_IO_CANTREAD
;
2345 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
2347 catch ( const css::uno::Exception
& )
2349 pImpl
->m_eError
= ERRCODE_IO_GENERAL
;
2352 // do not switch from temporary file in case of nonfile protocol
2356 if ( ( !pImpl
->m_eError
|| pImpl
->m_eError
.IsWarning() ) && !pImpl
->pTempFile
)
2358 // without a TempFile the physical and logical name should be the same after successful transfer
2359 if (osl::FileBase::getSystemPathFromFileURL(
2360 GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
), pImpl
->m_aName
)
2361 != osl::FileBase::E_None
)
2363 pImpl
->m_aName
.clear();
2365 pImpl
->m_bSalvageMode
= false;
2370 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content
& aOriginalContent
,
2371 const OUString
& aPrefix
,
2372 const OUString
& aExtension
,
2373 const OUString
& aDestDir
)
2375 if ( !pImpl
->m_aBackupURL
.isEmpty() )
2376 return; // the backup was done already
2378 ::utl::TempFile
aTransactTemp( aPrefix
, true, &aExtension
, &aDestDir
);
2380 INetURLObject
aBackObj( aTransactTemp
.GetURL() );
2381 OUString aBackupName
= aBackObj
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
);
2383 Reference
< css::ucb::XCommandEnvironment
> xDummyEnv
;
2384 ::ucbhelper::Content aBackupCont
;
2385 if( ::ucbhelper::Content::create( aDestDir
, xDummyEnv
, comphelper::getProcessComponentContext(), aBackupCont
) )
2389 OUString sMimeType
= pImpl
->getFilterMimeType();
2390 aBackupCont
.transferContent( aOriginalContent
,
2391 ::ucbhelper::InsertOperation::Copy
,
2393 NameClash::OVERWRITE
,
2395 pImpl
->m_aBackupURL
= aBackObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
2396 pImpl
->m_bRemoveBackup
= true;
2398 catch( const Exception
& )
2402 if ( pImpl
->m_aBackupURL
.isEmpty() )
2403 aTransactTemp
.EnableKillingFile();
2407 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content
& aOriginalContent
)
2409 if ( !pImpl
->m_aBackupURL
.isEmpty() )
2410 return; // the backup was done already
2412 OUString aFileName
= GetURLObject().getName( INetURLObject::LAST_SEGMENT
,
2414 INetURLObject::DecodeMechanism::NONE
);
2416 sal_Int32 nPrefixLen
= aFileName
.lastIndexOf( '.' );
2417 OUString aPrefix
= ( nPrefixLen
== -1 ) ? aFileName
: aFileName
.copy( 0, nPrefixLen
);
2418 OUString aExtension
= ( nPrefixLen
== -1 ) ? OUString() : aFileName
.copy( nPrefixLen
);
2419 OUString aBakDir
= SvtPathOptions().GetBackupPath();
2421 // create content for the parent folder ( = backup folder )
2422 ::ucbhelper::Content aContent
;
2423 Reference
< css::ucb::XCommandEnvironment
> xEnv
;
2424 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv
, aBakDir
, aContent
) )
2425 DoInternalBackup_Impl( aOriginalContent
, aPrefix
, aExtension
, aBakDir
);
2427 if ( !pImpl
->m_aBackupURL
.isEmpty() )
2430 // the copying to the backup catalog failed ( for example because
2431 // of using an encrypted partition as target catalog )
2432 // since the user did not specify to make backup explicitly
2433 // office should try to make backup in another place,
2434 // target catalog does not look bad for this case ( and looks
2435 // to be the only way for encrypted partitions )
2437 INetURLObject aDest
= GetURLObject();
2438 if ( aDest
.removeSegment() )
2439 DoInternalBackup_Impl( aOriginalContent
, aPrefix
, aExtension
, aDest
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
2443 void SfxMedium::DoBackup_Impl()
2445 // source file name is the logical name of this medium
2446 INetURLObject
aSource( GetURLObject() );
2448 // there is nothing to backup in case source file does not exist
2449 if ( !::utl::UCBContentHelper::IsDocument( aSource
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) ) )
2452 bool bSuccess
= false;
2454 // get path for backups
2455 OUString aBakDir
= SvtPathOptions().GetBackupPath();
2456 if( !aBakDir
.isEmpty() )
2458 // create content for the parent folder ( = backup folder )
2459 ::ucbhelper::Content aContent
;
2460 Reference
< css::ucb::XCommandEnvironment
> xEnv
;
2461 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv
, aBakDir
, aContent
) )
2463 // save as ".bak" file
2464 INetURLObject
aDest( aBakDir
);
2465 aDest
.insertName( aSource
.getName() );
2466 aDest
.setExtension( "bak" );
2467 OUString aFileName
= aDest
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
);
2469 // create a content for the source file
2470 ::ucbhelper::Content aSourceContent
;
2471 if ( ::ucbhelper::Content::create( aSource
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), xEnv
, comphelper::getProcessComponentContext(), aSourceContent
) )
2475 // do the transfer ( copy source file to backup dir )
2476 OUString sMimeType
= pImpl
->getFilterMimeType();
2477 aContent
.transferContent( aSourceContent
,
2478 ::ucbhelper::InsertOperation::Copy
,
2480 NameClash::OVERWRITE
,
2482 pImpl
->m_aBackupURL
= aDest
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
2483 pImpl
->m_bRemoveBackup
= false;
2486 catch ( const css::uno::Exception
& )
2495 pImpl
->m_eError
= ERRCODE_SFX_CANTCREATEBACKUP
;
2500 void SfxMedium::ClearBackup_Impl()
2502 if( pImpl
->m_bRemoveBackup
)
2504 // currently a document is always stored in a new medium,
2505 // thus if a backup can not be removed the backup URL should not be cleaned
2506 if ( !pImpl
->m_aBackupURL
.isEmpty() )
2508 if ( ::utl::UCBContentHelper::Kill( pImpl
->m_aBackupURL
) )
2510 pImpl
->m_bRemoveBackup
= false;
2511 pImpl
->m_aBackupURL
.clear();
2516 SAL_WARN( "sfx.doc", "Couldn't remove backup file!");
2521 pImpl
->m_aBackupURL
.clear();
2525 void SfxMedium::GetLockingStream_Impl()
2527 if ( GetURLObject().GetProtocol() != INetProtocol::File
2528 || pImpl
->m_xLockingStream
.is() )
2531 const SfxUnoAnyItem
* pWriteStreamItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(pImpl
->m_pSet
.get(), SID_STREAM
, false);
2532 if ( pWriteStreamItem
)
2533 pWriteStreamItem
->GetValue() >>= pImpl
->m_xLockingStream
;
2535 if ( pImpl
->m_xLockingStream
.is() )
2538 // open the original document
2539 uno::Sequence
< beans::PropertyValue
> xProps
;
2540 TransformItems( SID_OPENDOC
, *GetItemSet(), xProps
);
2541 utl::MediaDescriptor
aMedium( xProps
);
2543 aMedium
.addInputStreamOwnLock();
2545 uno::Reference
< io::XInputStream
> xInputStream
;
2546 aMedium
[utl::MediaDescriptor::PROP_STREAM()] >>= pImpl
->m_xLockingStream
;
2547 aMedium
[utl::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream
;
2549 if ( !pImpl
->pTempFile
&& pImpl
->m_aName
.isEmpty() )
2551 // the medium is still based on the original file, it makes sense to initialize the streams
2552 if ( pImpl
->m_xLockingStream
.is() )
2553 pImpl
->xStream
= pImpl
->m_xLockingStream
;
2555 if ( xInputStream
.is() )
2556 pImpl
->xInputStream
= xInputStream
;
2558 if ( !pImpl
->xInputStream
.is() && pImpl
->xStream
.is() )
2559 pImpl
->xInputStream
= pImpl
->xStream
->getInputStream();
2564 void SfxMedium::GetMedium_Impl()
2566 if ( pImpl
->m_pInStream
2567 && (!pImpl
->bIsTemp
|| pImpl
->xInputStream
.is() || pImpl
->m_xInputStreamToLoadFrom
.is() || pImpl
->xStream
.is() || pImpl
->m_xLockingStream
.is() ) )
2570 pImpl
->bDownloadDone
= false;
2571 Reference
< css::task::XInteractionHandler
> xInteractionHandler
= GetInteractionHandler();
2573 //TODO/MBA: need support for SID_STREAM
2574 const SfxUnoAnyItem
* pWriteStreamItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(pImpl
->m_pSet
.get(), SID_STREAM
, false);
2575 const SfxUnoAnyItem
* pInStreamItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(pImpl
->m_pSet
.get(), SID_INPUTSTREAM
, false);
2576 if ( pWriteStreamItem
)
2578 pWriteStreamItem
->GetValue() >>= pImpl
->xStream
;
2580 if ( pInStreamItem
)
2581 pInStreamItem
->GetValue() >>= pImpl
->xInputStream
;
2583 if ( !pImpl
->xInputStream
.is() && pImpl
->xStream
.is() )
2584 pImpl
->xInputStream
= pImpl
->xStream
->getInputStream();
2586 else if ( pInStreamItem
)
2588 pInStreamItem
->GetValue() >>= pImpl
->xInputStream
;
2592 uno::Sequence
< beans::PropertyValue
> xProps
;
2594 if (!pImpl
->m_aName
.isEmpty())
2596 if ( osl::FileBase::getFileURLFromSystemPath( pImpl
->m_aName
, aFileName
)
2597 != osl::FileBase::E_None
)
2599 SAL_WARN( "sfx.doc", "Physical name not convertible!");
2603 aFileName
= GetName();
2605 // in case the temporary file exists the streams should be initialized from it,
2606 // but the original MediaDescriptor should not be changed
2607 bool bFromTempFile
= ( pImpl
->pTempFile
!= nullptr );
2609 if ( !bFromTempFile
)
2611 GetItemSet()->Put( SfxStringItem( SID_FILE_NAME
, aFileName
) );
2612 if( !(pImpl
->m_nStorOpenMode
& StreamMode::WRITE
) )
2613 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
2614 if (xInteractionHandler
.is())
2615 GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER
, makeAny(xInteractionHandler
) ) );
2618 if ( pImpl
->m_xInputStreamToLoadFrom
.is() )
2620 pImpl
->xInputStream
= pImpl
->m_xInputStreamToLoadFrom
;
2621 if (pImpl
->m_bInputStreamIsReadOnly
)
2622 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
2626 TransformItems( SID_OPENDOC
, *GetItemSet(), xProps
);
2627 utl::MediaDescriptor
aMedium( xProps
);
2629 if ( pImpl
->m_xLockingStream
.is() && !bFromTempFile
)
2631 // the medium is not based on the temporary file, so the original stream can be used
2632 pImpl
->xStream
= pImpl
->m_xLockingStream
;
2636 if ( bFromTempFile
)
2638 aMedium
[utl::MediaDescriptor::PROP_URL()] <<= aFileName
;
2639 aMedium
.erase( utl::MediaDescriptor::PROP_READONLY() );
2640 aMedium
.addInputStream();
2642 else if ( GetURLObject().GetProtocol() == INetProtocol::File
)
2644 // use the special locking approach only for file URLs
2645 aMedium
.addInputStreamOwnLock();
2649 // add a check for protocol, if it's http or https or provide webdav then add
2650 // the interaction handler to be used by the authentication dialog
2651 if ( GetURLObject().isAnyKnownWebDAVScheme() )
2653 aMedium
[utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER()] <<= GetInteractionHandler( true );
2655 aMedium
.addInputStream();
2657 // the ReadOnly property set in aMedium is ignored
2658 // the check is done in LockOrigFileOnDemand() for file and non-file URLs
2660 //TODO/MBA: what happens if property is not there?!
2661 aMedium
[utl::MediaDescriptor::PROP_STREAM()] >>= pImpl
->xStream
;
2662 aMedium
[utl::MediaDescriptor::PROP_INPUTSTREAM()] >>= pImpl
->xInputStream
;
2666 if ( !pImpl
->xInputStream
.is() && pImpl
->xStream
.is() )
2667 pImpl
->xInputStream
= pImpl
->xStream
->getInputStream();
2670 if ( !bFromTempFile
)
2672 //TODO/MBA: need support for SID_STREAM
2673 if ( pImpl
->xStream
.is() )
2674 GetItemSet()->Put( SfxUnoAnyItem( SID_STREAM
, makeAny( pImpl
->xStream
) ) );
2676 GetItemSet()->Put( SfxUnoAnyItem( SID_INPUTSTREAM
, makeAny( pImpl
->xInputStream
) ) );
2680 //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor
2681 if ( !GetError() && !pImpl
->xStream
.is() && !pImpl
->xInputStream
.is() )
2682 SetError(ERRCODE_IO_ACCESSDENIED
);
2684 if ( !GetError() && !pImpl
->m_pInStream
)
2686 if ( pImpl
->xStream
.is() )
2687 pImpl
->m_pInStream
= utl::UcbStreamHelper::CreateStream( pImpl
->xStream
);
2688 else if ( pImpl
->xInputStream
.is() )
2689 pImpl
->m_pInStream
= utl::UcbStreamHelper::CreateStream( pImpl
->xInputStream
);
2692 pImpl
->bDownloadDone
= true;
2693 pImpl
->aDoneLink
.ClearPendingCall();
2694 ErrCode nError
= GetError();
2695 pImpl
->aDoneLink
.Call( reinterpret_cast<void*>(sal_uInt32(nError
)) );
2698 bool SfxMedium::IsRemote() const
2700 return pImpl
->m_bRemote
;
2703 void SfxMedium::SetUpdatePickList(bool bVal
)
2705 pImpl
->bUpdatePickList
= bVal
;
2708 bool SfxMedium::IsUpdatePickList() const
2710 return pImpl
->bUpdatePickList
;
2713 void SfxMedium::SetLongName(const OUString
&rName
)
2715 pImpl
->m_aLongName
= rName
;
2718 const OUString
& SfxMedium::GetLongName() const
2720 return pImpl
->m_aLongName
;
2723 void SfxMedium::SetDoneLink( const Link
<void*,void>& rLink
)
2725 pImpl
->aDoneLink
= rLink
;
2728 void SfxMedium::Download( const Link
<void*,void>& aLink
)
2730 SetDoneLink( aLink
);
2732 if ( pImpl
->m_pInStream
&& !aLink
.IsSet() )
2734 while( !pImpl
->bDownloadDone
)
2735 Application::Yield();
2740 void SfxMedium::Init_Impl()
2742 Includes a valid:: sun:: com:: star:: util:: URL (If a file name was
2743 previously in there) in the logical name and if available sets the
2744 physical name as the file name.
2748 Reference
< XOutputStream
> rOutStream
;
2750 // TODO/LATER: handle lifetime of storages
2751 pImpl
->bDisposeStorage
= false;
2753 const SfxStringItem
* pSalvageItem
= SfxItemSet::GetItem
<SfxStringItem
>(pImpl
->m_pSet
.get(), SID_DOC_SALVAGE
, false);
2754 if ( pSalvageItem
&& pSalvageItem
->GetValue().isEmpty() )
2756 pSalvageItem
= nullptr;
2757 pImpl
->m_pSet
->ClearItem( SID_DOC_SALVAGE
);
2760 if (!pImpl
->m_aLogicName
.isEmpty())
2762 INetURLObject
aUrl( pImpl
->m_aLogicName
);
2763 INetProtocol eProt
= aUrl
.GetProtocol();
2764 if ( eProt
== INetProtocol::NotValid
)
2766 SAL_WARN( "sfx.doc", "URL <" << pImpl
->m_aLogicName
<< "> with unknown protocol" );
2770 if ( aUrl
.HasMark() )
2772 pImpl
->m_aLogicName
= aUrl
.GetURLNoMark( INetURLObject::DecodeMechanism::NONE
);
2773 GetItemSet()->Put( SfxStringItem( SID_JUMPMARK
, aUrl
.GetMark() ) );
2776 // try to convert the URL into a physical name - but never change a physical name
2777 // physical name may be set if the logical name is changed after construction
2778 if ( pImpl
->m_aName
.isEmpty() )
2779 osl::FileBase::getSystemPathFromFileURL( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
), pImpl
->m_aName
);
2782 DBG_ASSERT( pSalvageItem
, "Suspicious change of logical name!" );
2787 if ( pSalvageItem
&& !pSalvageItem
->GetValue().isEmpty() )
2789 pImpl
->m_aLogicName
= pSalvageItem
->GetValue();
2790 pImpl
->m_pURLObj
.reset();
2791 pImpl
->m_bSalvageMode
= true;
2794 // in case output stream is by mistake here
2795 // clear the reference
2796 const SfxUnoAnyItem
* pOutStreamItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(pImpl
->m_pSet
.get(), SID_OUTPUTSTREAM
, false);
2798 && ( !( pOutStreamItem
->GetValue() >>= rOutStream
)
2799 || !pImpl
->m_aLogicName
.startsWith("private:stream")) )
2801 pImpl
->m_pSet
->ClearItem( SID_OUTPUTSTREAM
);
2802 SAL_WARN( "sfx.doc", "Unexpected Output stream parameter!" );
2805 if (!pImpl
->m_aLogicName
.isEmpty())
2807 // if the logic name is set it should be set in MediaDescriptor as well
2808 const SfxStringItem
* pFileNameItem
= SfxItemSet::GetItem
<SfxStringItem
>(pImpl
->m_pSet
.get(), SID_FILE_NAME
, false);
2809 if ( !pFileNameItem
)
2811 // let the ItemSet be created if necessary
2814 SID_FILE_NAME
, INetURLObject( pImpl
->m_aLogicName
).GetMainURL( INetURLObject::DecodeMechanism::NONE
) ) );
2820 osl::DirectoryItem item
;
2821 if (osl::DirectoryItem::get(GetName(), item
) == osl::FileBase::E_None
) {
2822 osl::FileStatus
stat(osl_FileStatus_Mask_Attributes
);
2823 if (item
.getFileStatus(stat
) == osl::FileBase::E_None
2824 && stat
.isValid(osl_FileStatus_Mask_Attributes
))
2826 if ((stat
.getAttributes() & osl_File_Attribute_ReadOnly
) != 0) {
2827 pImpl
->m_bOriginallyReadOnly
= true;
2834 SfxMedium::SfxMedium() : pImpl(new SfxMedium_Impl
)
2840 void SfxMedium::UseInteractionHandler( bool bUse
)
2842 pImpl
->bAllowDefaultIntHdl
= bUse
;
2846 css::uno::Reference
< css::task::XInteractionHandler
>
2847 SfxMedium::GetInteractionHandler( bool bGetAlways
)
2849 // if interaction isn't allowed explicitly ... return empty reference!
2850 if ( !bGetAlways
&& !pImpl
->bUseInteractionHandler
)
2851 return css::uno::Reference
< css::task::XInteractionHandler
>();
2853 // search a possible existing handler inside cached item set
2854 if ( pImpl
->m_pSet
)
2856 css::uno::Reference
< css::task::XInteractionHandler
> xHandler
;
2857 const SfxUnoAnyItem
* pHandler
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(pImpl
->m_pSet
.get(), SID_INTERACTIONHANDLER
, false);
2858 if ( pHandler
&& (pHandler
->GetValue() >>= xHandler
) && xHandler
.is() )
2862 // if default interaction isn't allowed explicitly ... return empty reference!
2863 if ( !bGetAlways
&& !pImpl
->bAllowDefaultIntHdl
)
2864 return css::uno::Reference
< css::task::XInteractionHandler
>();
2866 // otherwise return cached default handler ... if it exist.
2867 if ( pImpl
->xInteraction
.is() )
2868 return pImpl
->xInteraction
;
2870 // create default handler and cache it!
2871 Reference
< uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2872 pImpl
->xInteraction
.set(
2873 task::InteractionHandler::createWithParent(xContext
, nullptr), UNO_QUERY_THROW
);
2874 return pImpl
->xInteraction
;
2878 void SfxMedium::SetFilter( const std::shared_ptr
<const SfxFilter
>& pFilter
)
2880 pImpl
->m_pFilter
= pFilter
;
2883 const std::shared_ptr
<const SfxFilter
>& SfxMedium::GetFilter() const
2885 return pImpl
->m_pFilter
;
2888 sal_uInt32
SfxMedium::CreatePasswordToModifyHash( const OUString
& aPasswd
, bool bWriter
)
2890 sal_uInt32 nHash
= 0;
2892 if ( !aPasswd
.isEmpty() )
2896 nHash
= ::comphelper::DocPasswordHelper::GetWordHashAsUINT32( aPasswd
);
2900 rtl_TextEncoding nEncoding
= osl_getThreadTextEncoding();
2901 nHash
= ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd
, nEncoding
);
2909 void SfxMedium::Close(bool bInDestruction
)
2911 if ( pImpl
->xStorage
.is() )
2916 CloseStreams_Impl(bInDestruction
);
2918 UnlockFile( false );
2921 void SfxMedium::CloseAndRelease()
2923 if ( pImpl
->xStorage
.is() )
2928 CloseAndReleaseStreams_Impl();
2933 void SfxMedium::DisableUnlockWebDAV( bool bDisableUnlockWebDAV
)
2935 pImpl
->m_bDisableUnlockWebDAV
= bDisableUnlockWebDAV
;
2938 void SfxMedium::DisableFileSync(bool bDisableFileSync
)
2940 pImpl
->m_bDisableFileSync
= bDisableFileSync
;
2943 void SfxMedium::UnlockFile( bool bReleaseLockStream
)
2945 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
2946 (void) bReleaseLockStream
;
2949 if ( GetURLObject().isAnyKnownWebDAVScheme() )
2951 // do nothing if WebDAV locking if disabled
2952 // (shouldn't happen because we already skipped locking,
2953 // see LockOrigFileOnDemand, but just in case ...)
2954 if (!IsWebDAVLockingUsed())
2957 if ( pImpl
->m_bLocked
)
2959 // an interaction handler should be used for authentication, if needed
2961 uno::Reference
< css::task::XInteractionHandler
> xHandler
= GetInteractionHandler( true );
2962 uno::Reference
< css::ucb::XCommandEnvironment
> xComEnv
= new ::ucbhelper::CommandEnvironment( xHandler
,
2963 Reference
< css::ucb::XProgressHandler
>() );
2964 ucbhelper::Content
aContentToUnlock( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
), xComEnv
, comphelper::getProcessComponentContext());
2965 pImpl
->m_bLocked
= false;
2966 //check if WebDAV unlock was explicitly disabled
2967 if ( !pImpl
->m_bDisableUnlockWebDAV
)
2968 aContentToUnlock
.unlock();
2970 catch ( uno::Exception
& )
2972 TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
2978 if ( pImpl
->m_xLockingStream
.is() )
2980 if ( bReleaseLockStream
)
2984 uno::Reference
< io::XInputStream
> xInStream
= pImpl
->m_xLockingStream
->getInputStream();
2985 uno::Reference
< io::XOutputStream
> xOutStream
= pImpl
->m_xLockingStream
->getOutputStream();
2986 if ( xInStream
.is() )
2987 xInStream
->closeInput();
2988 if ( xOutStream
.is() )
2989 xOutStream
->closeOutput();
2991 catch( const uno::Exception
& )
2995 pImpl
->m_xLockingStream
.clear();
2998 if ( !pImpl
->m_bLocked
)
3001 ::svt::DocumentLockFile
aLockFile( pImpl
->m_aLogicName
);
3005 pImpl
->m_bLocked
= false;
3006 // TODO/LATER: A warning could be shown in case the file is not the own one
3007 aLockFile
.RemoveFile();
3009 catch( const io::WrongFormatException
& )
3013 // erase the empty or corrupt file
3014 aLockFile
.RemoveFileDirectly();
3016 catch( const uno::Exception
& )
3019 catch( const uno::Exception
& )
3022 if(!pImpl
->m_bMSOLockFileCreated
)
3025 ::svt::MSODocumentLockFile
aMSOLockFile( pImpl
->m_aLogicName
);
3029 pImpl
->m_bLocked
= false;
3030 // TODO/LATER: A warning could be shown in case the file is not the own one
3031 aMSOLockFile
.RemoveFile();
3033 catch( const io::WrongFormatException
& )
3037 // erase the empty or corrupt file
3038 aMSOLockFile
.RemoveFileDirectly();
3040 catch( const uno::Exception
& )
3043 catch( const uno::Exception
& )
3045 pImpl
->m_bMSOLockFileCreated
= false;
3049 void SfxMedium::CloseAndReleaseStreams_Impl()
3051 CloseZipStorage_Impl();
3053 uno::Reference
< io::XInputStream
> xInToClose
= pImpl
->xInputStream
;
3054 uno::Reference
< io::XOutputStream
> xOutToClose
;
3055 if ( pImpl
->xStream
.is() )
3057 xOutToClose
= pImpl
->xStream
->getOutputStream();
3059 // if the locking stream is closed here the related member should be cleaned
3060 if ( pImpl
->xStream
== pImpl
->m_xLockingStream
)
3061 pImpl
->m_xLockingStream
.clear();
3064 // The probably existing SvStream wrappers should be closed first
3065 CloseStreams_Impl();
3067 // in case of salvage mode the storage is based on the streams
3068 if ( pImpl
->m_bSalvageMode
)
3073 if ( xInToClose
.is() )
3074 xInToClose
->closeInput();
3075 if ( xOutToClose
.is() )
3076 xOutToClose
->closeOutput();
3078 catch ( const uno::Exception
& )
3084 void SfxMedium::CloseStreams_Impl(bool bInDestruction
)
3086 CloseInStream_Impl(bInDestruction
);
3087 CloseOutStream_Impl();
3089 if ( pImpl
->m_pSet
)
3090 pImpl
->m_pSet
->ClearItem( SID_CONTENT
);
3092 pImpl
->aContent
= ::ucbhelper::Content();
3096 void SfxMedium::SetIsRemote_Impl()
3098 INetURLObject
aObj( GetName() );
3099 switch( aObj
.GetProtocol() )
3101 case INetProtocol::Ftp
:
3102 case INetProtocol::Http
:
3103 case INetProtocol::Https
:
3104 pImpl
->m_bRemote
= true;
3107 pImpl
->m_bRemote
= GetName().startsWith("private:msgid");
3111 // As files that are written to the remote transmission must also be able
3113 if (pImpl
->m_bRemote
)
3114 pImpl
->m_nStorOpenMode
|= StreamMode::READ
;
3118 void SfxMedium::SetName( const OUString
& aNameP
, bool bSetOrigURL
)
3120 if (pImpl
->aOrigURL
.isEmpty())
3121 pImpl
->aOrigURL
= pImpl
->m_aLogicName
;
3123 pImpl
->aOrigURL
= aNameP
;
3124 pImpl
->m_aLogicName
= aNameP
;
3125 pImpl
->m_pURLObj
.reset();
3126 pImpl
->aContent
= ::ucbhelper::Content();
3131 const OUString
& SfxMedium::GetOrigURL() const
3133 return pImpl
->aOrigURL
.isEmpty() ? pImpl
->m_aLogicName
: pImpl
->aOrigURL
;
3137 void SfxMedium::SetPhysicalName_Impl( const OUString
& rNameP
)
3139 if ( rNameP
!= pImpl
->m_aName
)
3141 pImpl
->pTempFile
.reset();
3143 if ( !pImpl
->m_aName
.isEmpty() || !rNameP
.isEmpty() )
3144 pImpl
->aContent
= ::ucbhelper::Content();
3146 pImpl
->m_aName
= rNameP
;
3147 pImpl
->m_bTriedStorage
= false;
3148 pImpl
->bIsStorage
= false;
3153 void SfxMedium::ReOpen()
3155 bool bUseInteractionHandler
= pImpl
->bUseInteractionHandler
;
3156 pImpl
->bUseInteractionHandler
= false;
3158 pImpl
->bUseInteractionHandler
= bUseInteractionHandler
;
3162 void SfxMedium::CompleteReOpen()
3164 // do not use temporary file for reopen and in case of success throw the temporary file away
3165 bool bUseInteractionHandler
= pImpl
->bUseInteractionHandler
;
3166 pImpl
->bUseInteractionHandler
= false;
3168 std::unique_ptr
<::utl::TempFile
> pTmpFile
;
3169 if ( pImpl
->pTempFile
)
3171 pTmpFile
= std::move(pImpl
->pTempFile
);
3172 pImpl
->m_aName
.clear();
3179 if ( pImpl
->pTempFile
)
3181 pImpl
->pTempFile
->EnableKillingFile();
3182 pImpl
->pTempFile
.reset();
3184 pImpl
->pTempFile
= std::move( pTmpFile
);
3185 if ( pImpl
->pTempFile
)
3186 pImpl
->m_aName
= pImpl
->pTempFile
->GetFileName();
3190 pTmpFile
->EnableKillingFile();
3194 pImpl
->bUseInteractionHandler
= bUseInteractionHandler
;
3197 SfxMedium::SfxMedium(const OUString
&rName
, StreamMode nOpenMode
, std::shared_ptr
<const SfxFilter
> pFilter
, const std::shared_ptr
<SfxItemSet
>& pInSet
) :
3198 pImpl(new SfxMedium_Impl
)
3200 pImpl
->m_pSet
= pInSet
;
3201 pImpl
->m_pFilter
= std::move(pFilter
);
3202 pImpl
->m_aLogicName
= rName
;
3203 pImpl
->m_nStorOpenMode
= nOpenMode
;
3207 SfxMedium::SfxMedium(const OUString
&rName
, const OUString
&rReferer
, StreamMode nOpenMode
, std::shared_ptr
<const SfxFilter
> pFilter
, const std::shared_ptr
<SfxItemSet
>& pInSet
) :
3208 pImpl(new SfxMedium_Impl
)
3210 pImpl
->m_pSet
= pInSet
;
3211 SfxItemSet
* s
= GetItemSet();
3212 if (s
->GetItem(SID_REFERER
) == nullptr) {
3213 s
->Put(SfxStringItem(SID_REFERER
, rReferer
));
3215 pImpl
->m_pFilter
= std::move(pFilter
);
3216 pImpl
->m_aLogicName
= rName
;
3217 pImpl
->m_nStorOpenMode
= nOpenMode
;
3221 SfxMedium::SfxMedium( const uno::Sequence
<beans::PropertyValue
>& aArgs
) :
3222 pImpl(new SfxMedium_Impl
)
3224 SfxAllItemSet
*pParams
= new SfxAllItemSet( SfxGetpApp()->GetPool() );
3225 pImpl
->m_pSet
.reset( pParams
);
3226 TransformParameters( SID_OPENDOC
, aArgs
, *pParams
);
3229 OUString aFilterProvider
, aFilterName
;
3231 const SfxPoolItem
* pItem
= nullptr;
3232 if (pImpl
->m_pSet
->HasItem(SID_FILTER_PROVIDER
, &pItem
))
3233 aFilterProvider
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
3235 if (pImpl
->m_pSet
->HasItem(SID_FILTER_NAME
, &pItem
))
3236 aFilterName
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
3239 if (aFilterProvider
.isEmpty())
3241 // This is a conventional filter type.
3242 pImpl
->m_pFilter
= SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName( aFilterName
);
3246 // This filter is from an external provider such as orcus.
3247 pImpl
->m_pCustomFilter
= std::make_shared
<SfxFilter
>(aFilterProvider
, aFilterName
);
3248 pImpl
->m_pFilter
= pImpl
->m_pCustomFilter
;
3251 const SfxStringItem
* pSalvageItem
= SfxItemSet::GetItem
<SfxStringItem
>(pImpl
->m_pSet
.get(), SID_DOC_SALVAGE
, false);
3254 // QUESTION: there is some treatment of Salvage in Init_Impl; align!
3255 if ( !pSalvageItem
->GetValue().isEmpty() )
3257 // if a URL is provided in SalvageItem that means that the FileName refers to a temporary file
3258 // that must be copied here
3260 const SfxStringItem
* pFileNameItem
= SfxItemSet::GetItem
<SfxStringItem
>(pImpl
->m_pSet
.get(), SID_FILE_NAME
, false);
3261 if (!pFileNameItem
) throw uno::RuntimeException();
3262 OUString aNewTempFileURL
= SfxMedium::CreateTempCopyWithExt( pFileNameItem
->GetValue() );
3263 if ( !aNewTempFileURL
.isEmpty() )
3265 pImpl
->m_pSet
->Put( SfxStringItem( SID_FILE_NAME
, aNewTempFileURL
) );
3266 pImpl
->m_pSet
->ClearItem( SID_INPUTSTREAM
);
3267 pImpl
->m_pSet
->ClearItem( SID_STREAM
);
3268 pImpl
->m_pSet
->ClearItem( SID_CONTENT
);
3272 SAL_WARN( "sfx.doc", "Can not create a new temporary file for crash recovery!" );
3277 const SfxBoolItem
* pReadOnlyItem
= SfxItemSet::GetItem
<SfxBoolItem
>(pImpl
->m_pSet
.get(), SID_DOC_READONLY
, false);
3278 if ( pReadOnlyItem
&& pReadOnlyItem
->GetValue() )
3279 pImpl
->m_bOriginallyLoadedReadOnly
= true;
3281 const SfxStringItem
* pFileNameItem
= SfxItemSet::GetItem
<SfxStringItem
>(pImpl
->m_pSet
.get(), SID_FILE_NAME
, false);
3282 if (!pFileNameItem
) throw uno::RuntimeException();
3283 pImpl
->m_aLogicName
= pFileNameItem
->GetValue();
3284 pImpl
->m_nStorOpenMode
= pImpl
->m_bOriginallyLoadedReadOnly
3285 ? SFX_STREAM_READONLY
: SFX_STREAM_READWRITE
;
3289 void SfxMedium::SetArgs(const uno::Sequence
<beans::PropertyValue
>& rArgs
)
3291 comphelper::SequenceAsHashMap
aArgsMap(rArgs
);
3292 aArgsMap
.erase("Stream");
3293 aArgsMap
.erase("InputStream");
3294 pImpl
->m_aArgs
= aArgsMap
.getAsConstPropertyValueList();
3297 uno::Sequence
<beans::PropertyValue
> SfxMedium::GetArgs() const { return pImpl
->m_aArgs
; }
3299 SfxMedium::SfxMedium( const uno::Reference
< embed::XStorage
>& rStor
, const OUString
& rBaseURL
, const std::shared_ptr
<SfxItemSet
>& p
) :
3300 pImpl(new SfxMedium_Impl
)
3302 OUString aType
= SfxFilter::GetTypeFromStorage(rStor
);
3303 pImpl
->m_pFilter
= SfxGetpApp()->GetFilterMatcher().GetFilter4EA( aType
);
3304 DBG_ASSERT( pImpl
->m_pFilter
, "No Filter for storage found!" );
3307 pImpl
->xStorage
= rStor
;
3308 pImpl
->bDisposeStorage
= false;
3310 // always take BaseURL first, could be overwritten by ItemSet
3311 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL
, rBaseURL
) );
3313 GetItemSet()->Put( *p
);
3317 SfxMedium::SfxMedium( const uno::Reference
< embed::XStorage
>& rStor
, const OUString
& rBaseURL
, const OUString
&rTypeName
, const std::shared_ptr
<SfxItemSet
>& p
) :
3318 pImpl(new SfxMedium_Impl
)
3320 pImpl
->m_pFilter
= SfxGetpApp()->GetFilterMatcher().GetFilter4EA( rTypeName
);
3321 DBG_ASSERT( pImpl
->m_pFilter
, "No Filter for storage found!" );
3324 pImpl
->xStorage
= rStor
;
3325 pImpl
->bDisposeStorage
= false;
3327 // always take BaseURL first, could be overwritten by ItemSet
3328 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL
, rBaseURL
) );
3330 GetItemSet()->Put( *p
);
3334 SfxMedium::~SfxMedium()
3336 // if there is a requirement to clean the backup this is the last possibility to do it
3339 Close(/*bInDestruction*/true);
3341 if( !pImpl
->bIsTemp
|| pImpl
->m_aName
.isEmpty() )
3345 if ( osl::FileBase::getFileURLFromSystemPath( pImpl
->m_aName
, aTemp
)
3346 != osl::FileBase::E_None
)
3348 SAL_WARN( "sfx.doc", "Physical name not convertible!");
3351 if ( !::utl::UCBContentHelper::Kill( aTemp
) )
3353 SAL_WARN( "sfx.doc", "Couldn't remove temporary file!");
3357 const OUString
& SfxMedium::GetName() const
3359 return pImpl
->m_aLogicName
;
3362 const INetURLObject
& SfxMedium::GetURLObject() const
3364 if (!pImpl
->m_pURLObj
)
3366 pImpl
->m_pURLObj
.reset( new INetURLObject( pImpl
->m_aLogicName
) );
3367 pImpl
->m_pURLObj
->SetMark("");
3370 return *pImpl
->m_pURLObj
;
3373 void SfxMedium::SetExpired_Impl( const DateTime
& rDateTime
)
3375 pImpl
->aExpireTime
= rDateTime
;
3379 bool SfxMedium::IsExpired() const
3381 return pImpl
->aExpireTime
.IsValidAndGregorian() && pImpl
->aExpireTime
< DateTime( DateTime::SYSTEM
);
3385 SfxFrame
* SfxMedium::GetLoadTargetFrame() const
3387 return pImpl
->wLoadTargetFrame
;
3390 void SfxMedium::setStreamToLoadFrom(const css::uno::Reference
<css::io::XInputStream
>& xInputStream
, bool bIsReadOnly
)
3392 pImpl
->m_xInputStreamToLoadFrom
= xInputStream
;
3393 pImpl
->m_bInputStreamIsReadOnly
= bIsReadOnly
;
3396 void SfxMedium::SetLoadTargetFrame(SfxFrame
* pFrame
)
3398 pImpl
->wLoadTargetFrame
= pFrame
;
3402 void SfxMedium::SetStorage_Impl( const uno::Reference
< embed::XStorage
>& rStor
)
3404 pImpl
->xStorage
= rStor
;
3408 SfxItemSet
* SfxMedium::GetItemSet() const
3410 // this method *must* return an ItemSet, returning NULL can cause crashes
3412 pImpl
->m_pSet
= std::make_shared
<SfxAllItemSet
>( SfxGetpApp()->GetPool() );
3413 return pImpl
->m_pSet
.get();
3417 SvKeyValueIterator
* SfxMedium::GetHeaderAttributes_Impl()
3419 if( !pImpl
->xAttributes
.is() )
3421 pImpl
->xAttributes
= SvKeyValueIteratorRef( new SvKeyValueIterator
);
3423 if ( GetContent().is() )
3427 Any aAny
= pImpl
->aContent
.getPropertyValue("MediaType");
3428 OUString aContentType
;
3429 aAny
>>= aContentType
;
3431 pImpl
->xAttributes
->Append( SvKeyValue( "content-type", aContentType
) );
3433 catch ( const css::uno::Exception
& )
3439 return pImpl
->xAttributes
.get();
3442 css::uno::Reference
< css::io::XInputStream
> const & SfxMedium::GetInputStream()
3444 if ( !pImpl
->xInputStream
.is() )
3446 return pImpl
->xInputStream
;
3449 const uno::Sequence
< util::RevisionTag
>& SfxMedium::GetVersionList( bool _bNoReload
)
3451 // if the medium has no name, then this medium should represent a new document and can have no version info
3452 if ( ( !_bNoReload
|| !pImpl
->m_bVersionsAlreadyLoaded
) && !pImpl
->aVersions
.hasElements() &&
3453 ( !pImpl
->m_aName
.isEmpty() || !pImpl
->m_aLogicName
.isEmpty() ) && GetStorage().is() )
3455 uno::Reference
< document::XDocumentRevisionListPersistence
> xReader
=
3456 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3459 pImpl
->aVersions
= xReader
->load( GetStorage() );
3461 catch ( const uno::Exception
& )
3466 if ( !pImpl
->m_bVersionsAlreadyLoaded
)
3467 pImpl
->m_bVersionsAlreadyLoaded
= true;
3469 return pImpl
->aVersions
;
3472 uno::Sequence
< util::RevisionTag
> SfxMedium::GetVersionList( const uno::Reference
< embed::XStorage
>& xStorage
)
3474 uno::Reference
< document::XDocumentRevisionListPersistence
> xReader
=
3475 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3478 return xReader
->load( xStorage
);
3480 catch ( const uno::Exception
& )
3484 return uno::Sequence
< util::RevisionTag
>();
3487 void SfxMedium::AddVersion_Impl( util::RevisionTag
& rRevision
)
3489 if ( !GetStorage().is() )
3492 // To determine a unique name for the stream
3493 std::vector
<sal_uInt32
> aLongs
;
3494 sal_Int32 nLength
= pImpl
->aVersions
.getLength();
3495 for ( const auto& rVersion
: std::as_const(pImpl
->aVersions
) )
3497 sal_uInt32 nVer
= static_cast<sal_uInt32
>( rVersion
.Identifier
.copy(7).toInt32());
3499 for ( n
=0; n
<aLongs
.size(); ++n
)
3500 if ( nVer
<aLongs
[n
] )
3503 aLongs
.insert( aLongs
.begin()+n
, nVer
);
3506 std::vector
<sal_uInt32
>::size_type nKey
;
3507 for ( nKey
=0; nKey
<aLongs
.size(); ++nKey
)
3508 if ( aLongs
[nKey
] > nKey
+1 )
3511 OUString aRevName
= "Version" + OUString::number( nKey
+ 1 );
3512 pImpl
->aVersions
.realloc( nLength
+1 );
3513 rRevision
.Identifier
= aRevName
;
3514 pImpl
->aVersions
[nLength
] = rRevision
;
3517 void SfxMedium::RemoveVersion_Impl( const OUString
& rName
)
3519 if ( !pImpl
->aVersions
.hasElements() )
3522 auto pVersion
= std::find_if(pImpl
->aVersions
.begin(), pImpl
->aVersions
.end(),
3523 [&rName
](const auto& rVersion
) { return rVersion
.Identifier
== rName
; });
3524 if (pVersion
!= pImpl
->aVersions
.end())
3526 auto nIndex
= static_cast<sal_Int32
>(std::distance(pImpl
->aVersions
.begin(), pVersion
));
3527 comphelper::removeElementAt(pImpl
->aVersions
, nIndex
);
3531 bool SfxMedium::TransferVersionList_Impl( SfxMedium
const & rMedium
)
3533 if ( rMedium
.pImpl
->aVersions
.hasElements() )
3535 pImpl
->aVersions
= rMedium
.pImpl
->aVersions
;
3542 void SfxMedium::SaveVersionList_Impl()
3544 if ( !GetStorage().is() )
3547 if ( !pImpl
->aVersions
.hasElements() )
3550 uno::Reference
< document::XDocumentRevisionListPersistence
> xWriter
=
3551 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3554 xWriter
->store( GetStorage(), pImpl
->aVersions
);
3556 catch ( const uno::Exception
& )
3561 bool SfxMedium::IsReadOnly() const
3563 // a) ReadOnly filter can't produce read/write contents!
3564 bool bReadOnly
= pImpl
->m_pFilter
&& (pImpl
->m_pFilter
->GetFilterFlags() & SfxFilterFlags::OPENREADONLY
);
3566 // b) if filter allow read/write contents .. check open mode of the storage
3568 bReadOnly
= !( GetOpenMode() & StreamMode::WRITE
);
3570 // c) the API can force the readonly state!
3573 const SfxBoolItem
* pItem
= SfxItemSet::GetItem
<SfxBoolItem
>(GetItemSet(), SID_DOC_READONLY
, false);
3575 bReadOnly
= pItem
->GetValue();
3581 bool SfxMedium::IsOriginallyReadOnly() const
3583 return pImpl
->m_bOriginallyReadOnly
;
3586 bool SfxMedium::IsOriginallyLoadedReadOnly() const
3588 return pImpl
->m_bOriginallyLoadedReadOnly
;
3591 bool SfxMedium::SetWritableForUserOnly( const OUString
& aURL
)
3593 // UCB does not allow to allow write access only for the user,
3595 bool bResult
= false;
3597 ::osl::DirectoryItem aDirItem
;
3598 if ( ::osl::DirectoryItem::get( aURL
, aDirItem
) == ::osl::FileBase::E_None
)
3600 ::osl::FileStatus
aFileStatus( osl_FileStatus_Mask_Attributes
);
3601 if ( aDirItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
3602 && aFileStatus
.isValid( osl_FileStatus_Mask_Attributes
) )
3604 sal_uInt64 nAttributes
= aFileStatus
.getAttributes();
3606 nAttributes
&= ~(osl_File_Attribute_OwnWrite
|
3607 osl_File_Attribute_GrpWrite
|
3608 osl_File_Attribute_OthWrite
|
3609 osl_File_Attribute_ReadOnly
);
3610 nAttributes
|= (osl_File_Attribute_OwnWrite
|
3611 osl_File_Attribute_OwnRead
);
3613 bResult
= ( osl::File::setAttributes( aURL
, nAttributes
) == ::osl::FileBase::E_None
);
3622 /// Get the parent directory of a temporary file for output purposes.
3623 OUString
GetLogicBase(const INetURLObject
& rURL
, std::unique_ptr
<SfxMedium_Impl
> const & pImpl
)
3625 OUString aLogicBase
;
3627 #if HAVE_FEATURE_MACOSX_SANDBOX
3628 // In a sandboxed environment we don't want to attempt to create temporary files in the same
3629 // directory where the user has selected an output file to be stored. The sandboxed process has
3630 // permission only to create the specifically named output file in that directory.
3635 if (rURL
.GetProtocol() == INetProtocol::File
&& !pImpl
->m_pInStream
)
3637 // Try to create the temp file in the same directory when storing.
3638 INetURLObject
aURL(rURL
);
3639 aURL
.removeSegment();
3640 aLogicBase
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::WithCharset
);
3643 if (pImpl
->m_bHasEmbeddedObjects
)
3644 // Embedded objects would mean a special base, ignore that.
3647 #endif // !HAVE_FEATURE_MACOSX_SANDBOX
3653 void SfxMedium::CreateTempFile( bool bReplace
)
3655 if ( pImpl
->pTempFile
)
3660 pImpl
->pTempFile
.reset();
3661 pImpl
->m_aName
.clear();
3664 OUString aLogicBase
= GetLogicBase(GetURLObject(), pImpl
);
3665 pImpl
->pTempFile
.reset( new ::utl::TempFile(aLogicBase
.isEmpty() ? nullptr : &aLogicBase
) );
3666 pImpl
->pTempFile
->EnableKillingFile();
3667 pImpl
->m_aName
= pImpl
->pTempFile
->GetFileName();
3668 OUString aTmpURL
= pImpl
->pTempFile
->GetURL();
3669 if ( pImpl
->m_aName
.isEmpty() || aTmpURL
.isEmpty() )
3671 SetError(ERRCODE_IO_CANTWRITE
);
3675 if ( !(pImpl
->m_nStorOpenMode
& StreamMode::TRUNC
) )
3677 bool bTransferSuccess
= false;
3679 if ( GetContent().is()
3680 && GetURLObject().GetProtocol() == INetProtocol::File
3681 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
) ) )
3683 // if there is already such a document, we should copy it
3684 // if it is a file system use OS copy process
3687 uno::Reference
< css::ucb::XCommandEnvironment
> xComEnv
;
3688 INetURLObject
aTmpURLObj( aTmpURL
);
3689 OUString aFileName
= aTmpURLObj
.getName( INetURLObject::LAST_SEGMENT
,
3691 INetURLObject::DecodeMechanism::WithCharset
);
3692 if ( !aFileName
.isEmpty() && aTmpURLObj
.removeSegment() )
3694 ::ucbhelper::Content
aTargetContent( aTmpURLObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), xComEnv
, comphelper::getProcessComponentContext() );
3695 OUString sMimeType
= pImpl
->getFilterMimeType();
3696 aTargetContent
.transferContent( pImpl
->aContent
, ::ucbhelper::InsertOperation::Copy
, aFileName
, NameClash::OVERWRITE
, sMimeType
);
3697 SetWritableForUserOnly( aTmpURL
);
3698 bTransferSuccess
= true;
3701 catch( const uno::Exception
& )
3704 if ( bTransferSuccess
)
3711 if ( !bTransferSuccess
&& pImpl
->m_pInStream
)
3713 // the case when there is no URL-access available or this is a remote protocol
3714 // but there is an input stream
3716 if ( pImpl
->m_pOutStream
)
3718 std::unique_ptr
<char[]> pBuf(new char [8192]);
3719 ErrCode nErr
= ERRCODE_NONE
;
3721 pImpl
->m_pInStream
->Seek(0);
3722 pImpl
->m_pOutStream
->Seek(0);
3724 while( !pImpl
->m_pInStream
->eof() && nErr
== ERRCODE_NONE
)
3726 sal_uInt32 nRead
= pImpl
->m_pInStream
->ReadBytes(pBuf
.get(), 8192);
3727 nErr
= pImpl
->m_pInStream
->GetError();
3728 pImpl
->m_pOutStream
->WriteBytes( pBuf
.get(), nRead
);
3731 bTransferSuccess
= true;
3734 CloseOutStream_Impl();
3738 // Quite strange design, but currently it is expected that in this case no transfer happens
3739 // TODO/LATER: get rid of this inconsistent part of the call design
3740 bTransferSuccess
= true;
3744 if ( !bTransferSuccess
)
3746 SetError(ERRCODE_IO_CANTWRITE
);
3755 void SfxMedium::CreateTempFileNoCopy()
3757 // this call always replaces the existing temporary file
3758 pImpl
->pTempFile
.reset();
3760 OUString aLogicBase
= GetLogicBase(GetURLObject(), pImpl
);
3761 pImpl
->pTempFile
.reset( new ::utl::TempFile(aLogicBase
.isEmpty() ? nullptr : &aLogicBase
) );
3762 pImpl
->pTempFile
->EnableKillingFile();
3763 pImpl
->m_aName
= pImpl
->pTempFile
->GetFileName();
3764 if ( pImpl
->m_aName
.isEmpty() )
3766 SetError(ERRCODE_IO_CANTWRITE
);
3770 CloseOutStream_Impl();
3774 bool SfxMedium::SignDocumentContentUsingCertificate(
3775 const css::uno::Reference
<css::frame::XModel
>& xModel
, bool bHasValidDocumentSignature
,
3776 const Reference
<XCertificate
>& xCertificate
)
3778 bool bChanges
= false;
3780 if (IsOpen() || GetError())
3782 SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
3786 // The component should know if there was a valid document signature, since
3787 // it should show a warning in this case
3788 OUString
aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
3789 uno::Reference
< security::XDocumentDigitalSignatures
> xSigner(
3790 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
3791 comphelper::getProcessComponentContext(), aODFVersion
, bHasValidDocumentSignature
) );
3792 auto xModelSigner
= dynamic_cast<sfx2::DigitalSignatures
*>(xSigner
.get());
3798 uno::Reference
< embed::XStorage
> xWriteableZipStor
;
3800 // we can reuse the temporary file if there is one already
3801 CreateTempFile( false );
3806 if ( !pImpl
->xStream
.is() )
3807 throw uno::RuntimeException();
3809 bool bODF
= GetFilter()->IsOwnFormat();
3812 xWriteableZipStor
= ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING
, pImpl
->xStream
);
3814 catch (const io::IOException
&)
3818 TOOLS_WARN_EXCEPTION("sfx.doc", "ODF stream is not a zip storage");
3822 if ( !xWriteableZipStor
.is() && bODF
)
3823 throw uno::RuntimeException();
3825 uno::Reference
< embed::XStorage
> xMetaInf
;
3826 if (xWriteableZipStor
.is() && xWriteableZipStor
->hasByName("META-INF"))
3828 xMetaInf
= xWriteableZipStor
->openStorageElement(
3830 embed::ElementModes::READWRITE
);
3831 if ( !xMetaInf
.is() )
3832 throw uno::RuntimeException();
3839 uno::Reference
< io::XStream
> xStream
;
3840 if (GetFilter() && GetFilter()->IsOwnFormat())
3841 xStream
.set(xMetaInf
->openStreamElement(xSigner
->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE
), uno::UNO_SET_THROW
);
3843 bool bSuccess
= xModelSigner
->SignModelWithCertificate(
3844 xModel
, xCertificate
, GetZipStorageToSign_Impl(), xStream
);
3848 uno::Reference
< embed::XTransactedObject
> xTransact( xMetaInf
, uno::UNO_QUERY_THROW
);
3849 xTransact
->commit();
3850 xTransact
.set( xWriteableZipStor
, uno::UNO_QUERY_THROW
);
3851 xTransact
->commit();
3853 // the temporary file has been written, commit it to the original file
3858 else if (xWriteableZipStor
.is())
3861 uno::Reference
<io::XStream
> xStream
;
3863 // We need read-write to be able to add the signature relation.
3864 bool bSuccess
= xModelSigner
->SignModelWithCertificate(
3865 xModel
, xCertificate
, GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream
);
3869 uno::Reference
<embed::XTransactedObject
> xTransact(xWriteableZipStor
, uno::UNO_QUERY_THROW
);
3870 xTransact
->commit();
3872 // the temporary file has been written, commit it to the original file
3879 // Something not ZIP based: e.g. PDF.
3880 std::unique_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ
| StreamMode::WRITE
));
3881 uno::Reference
<io::XStream
> xStream(new utl::OStreamWrapper(*pStream
));
3882 if (xModelSigner
->SignModelWithCertificate(
3883 xModel
, xCertificate
, uno::Reference
<embed::XStorage
>(), xStream
))
3888 catch ( const uno::Exception
& )
3890 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!" );
3900 bool SfxMedium::SignContents_Impl(weld::Window
* pDialogParent
,
3901 bool bSignScriptingContent
,
3902 bool bHasValidDocumentSignature
,
3903 const OUString
& aSignatureLineId
,
3904 const Reference
<XCertificate
>& xCert
,
3905 const Reference
<XGraphic
>& xValidGraphic
,
3906 const Reference
<XGraphic
>& xInvalidGraphic
,
3907 const OUString
& aComment
)
3909 bool bChanges
= false;
3911 if (IsOpen() || GetError())
3913 SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
3917 // The component should know if there was a valid document signature, since
3918 // it should show a warning in this case
3919 OUString
aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
3920 uno::Reference
< security::XDocumentDigitalSignatures
> xSigner(
3921 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
3922 comphelper::getProcessComponentContext(), aODFVersion
, bHasValidDocumentSignature
) );
3924 xSigner
->setParentWindow(pDialogParent
->GetXWindow());
3926 uno::Reference
< embed::XStorage
> xWriteableZipStor
;
3928 // we can reuse the temporary file if there is one already
3929 CreateTempFile( false );
3934 if ( !pImpl
->xStream
.is() )
3935 throw uno::RuntimeException();
3937 bool bODF
= GetFilter()->IsOwnFormat();
3940 xWriteableZipStor
= ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING
, pImpl
->xStream
);
3942 catch (const io::IOException
&)
3946 TOOLS_WARN_EXCEPTION("sfx.doc", "ODF stream is not a zip storage");
3950 if ( !xWriteableZipStor
.is() && bODF
)
3951 throw uno::RuntimeException();
3953 uno::Reference
< embed::XStorage
> xMetaInf
;
3954 if (xWriteableZipStor
.is() && xWriteableZipStor
->hasByName("META-INF"))
3956 xMetaInf
= xWriteableZipStor
->openStorageElement(
3958 embed::ElementModes::READWRITE
);
3959 if ( !xMetaInf
.is() )
3960 throw uno::RuntimeException();
3963 if ( bSignScriptingContent
)
3965 // If the signature has already the document signature it will be removed
3966 // after the scripting signature is inserted.
3967 uno::Reference
< io::XStream
> xStream(
3968 xMetaInf
->openStreamElement( xSigner
->getScriptingContentSignatureDefaultStreamName(),
3969 embed::ElementModes::READWRITE
),
3970 uno::UNO_SET_THROW
);
3972 if ( xSigner
->signScriptingContent( GetZipStorageToSign_Impl(), xStream
) )
3974 // remove the document signature if any
3975 OUString aDocSigName
= xSigner
->getDocumentContentSignatureDefaultStreamName();
3976 if ( !aDocSigName
.isEmpty() && xMetaInf
->hasByName( aDocSigName
) )
3977 xMetaInf
->removeElement( aDocSigName
);
3979 uno::Reference
< embed::XTransactedObject
> xTransact( xMetaInf
, uno::UNO_QUERY_THROW
);
3980 xTransact
->commit();
3981 xTransact
.set( xWriteableZipStor
, uno::UNO_QUERY_THROW
);
3982 xTransact
->commit();
3984 // the temporary file has been written, commit it to the original file
3994 uno::Reference
< io::XStream
> xStream
;
3995 if (GetFilter() && GetFilter()->IsOwnFormat())
3996 xStream
.set(xMetaInf
->openStreamElement(xSigner
->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE
), uno::UNO_SET_THROW
);
3998 bool bSuccess
= false;
4000 bSuccess
= xSigner
->signSignatureLine(
4001 GetZipStorageToSign_Impl(), xStream
, aSignatureLineId
, xCert
,
4002 xValidGraphic
, xInvalidGraphic
, aComment
);
4004 bSuccess
= xSigner
->signDocumentContent(GetZipStorageToSign_Impl(),
4009 uno::Reference
< embed::XTransactedObject
> xTransact( xMetaInf
, uno::UNO_QUERY_THROW
);
4010 xTransact
->commit();
4011 xTransact
.set( xWriteableZipStor
, uno::UNO_QUERY_THROW
);
4012 xTransact
->commit();
4014 // the temporary file has been written, commit it to the original file
4019 else if (xWriteableZipStor
.is())
4022 uno::Reference
<io::XStream
> xStream
;
4024 bool bSuccess
= false;
4027 bSuccess
= xSigner
->signSignatureLine(
4028 GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream
, aSignatureLineId
,
4029 xCert
, xValidGraphic
, xInvalidGraphic
, aComment
);
4033 // We need read-write to be able to add the signature relation.
4034 bSuccess
=xSigner
->signDocumentContent(
4035 GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream
);
4040 uno::Reference
<embed::XTransactedObject
> xTransact(xWriteableZipStor
, uno::UNO_QUERY_THROW
);
4041 xTransact
->commit();
4043 // the temporary file has been written, commit it to the original file
4050 // Something not ZIP based: e.g. PDF.
4051 std::unique_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ
| StreamMode::WRITE
));
4052 uno::Reference
<io::XStream
> xStream(new utl::OStreamWrapper(*pStream
));
4053 if (xSigner
->signDocumentContent(uno::Reference
<embed::XStorage
>(), xStream
))
4058 catch ( const uno::Exception
& )
4060 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!" );
4071 SignatureState
SfxMedium::GetCachedSignatureState_Impl() const
4073 return pImpl
->m_nSignatureState
;
4077 void SfxMedium::SetCachedSignatureState_Impl( SignatureState nState
)
4079 pImpl
->m_nSignatureState
= nState
;
4082 void SfxMedium::SetHasEmbeddedObjects(bool bHasEmbeddedObjects
)
4084 pImpl
->m_bHasEmbeddedObjects
= bHasEmbeddedObjects
;
4087 bool SfxMedium::HasStorage_Impl() const
4089 return pImpl
->xStorage
.is();
4092 bool SfxMedium::IsOpen() const
4094 return pImpl
->m_pInStream
|| pImpl
->m_pOutStream
|| pImpl
->xStorage
.is();
4097 OUString
SfxMedium::CreateTempCopyWithExt( const OUString
& aURL
)
4101 if ( !aURL
.isEmpty() )
4103 sal_Int32 nPrefixLen
= aURL
.lastIndexOf( '.' );
4104 OUString aExt
= ( nPrefixLen
== -1 ) ? OUString() : aURL
.copy( nPrefixLen
);
4106 OUString aNewTempFileURL
= ::utl::TempFile( OUString(), true, &aExt
).GetURL();
4107 if ( !aNewTempFileURL
.isEmpty() )
4109 INetURLObject
aSource( aURL
);
4110 INetURLObject
aDest( aNewTempFileURL
);
4111 OUString aFileName
= aDest
.getName( INetURLObject::LAST_SEGMENT
,
4113 INetURLObject::DecodeMechanism::WithCharset
);
4114 if ( !aFileName
.isEmpty() && aDest
.removeSegment() )
4118 uno::Reference
< css::ucb::XCommandEnvironment
> xComEnv
;
4119 ::ucbhelper::Content
aTargetContent( aDest
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), xComEnv
, comphelper::getProcessComponentContext() );
4120 ::ucbhelper::Content
aSourceContent( aSource
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), xComEnv
, comphelper::getProcessComponentContext() );
4121 aTargetContent
.transferContent( aSourceContent
,
4122 ::ucbhelper::InsertOperation::Copy
,
4124 NameClash::OVERWRITE
);
4125 aResult
= aNewTempFileURL
;
4127 catch( const uno::Exception
& )
4136 bool SfxMedium::CallApproveHandler(const uno::Reference
< task::XInteractionHandler
>& xHandler
, const uno::Any
& rRequest
, bool bAllowAbort
)
4138 bool bResult
= false;
4140 if ( xHandler
.is() )
4144 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > aContinuations( bAllowAbort
? 2 : 1 );
4146 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove( new ::comphelper::OInteractionApprove
);
4147 aContinuations
[ 0 ] = pApprove
.get();
4151 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort( new ::comphelper::OInteractionAbort
);
4152 aContinuations
[ 1 ] = pAbort
.get();
4155 xHandler
->handle(::framework::InteractionRequest::CreateRequest(rRequest
, aContinuations
));
4156 bResult
= pApprove
->wasSelected();
4158 catch( const Exception
& )
4166 OUString
SfxMedium::SwitchDocumentToTempFile()
4168 // the method returns empty string in case of failure
4170 OUString aOrigURL
= pImpl
->m_aLogicName
;
4172 if ( !aOrigURL
.isEmpty() )
4174 sal_Int32 nPrefixLen
= aOrigURL
.lastIndexOf( '.' );
4175 OUString
const aExt
= (nPrefixLen
== -1)
4177 : aOrigURL
.copy(nPrefixLen
);
4178 OUString aNewURL
= ::utl::TempFile( OUString(), true, &aExt
).GetURL();
4180 // TODO/LATER: In future the aLogicName should be set to shared folder URL
4181 // and a temporary file should be created. Transport_Impl should be impossible then.
4182 if ( !aNewURL
.isEmpty() )
4184 uno::Reference
< embed::XStorage
> xStorage
= GetStorage();
4185 uno::Reference
< embed::XOptimizedStorage
> xOptStorage( xStorage
, uno::UNO_QUERY
);
4187 if ( xOptStorage
.is() )
4189 // TODO/LATER: reuse the pImpl->pTempFile if it already exists
4190 CanDisposeStorage_Impl( false );
4192 SetPhysicalName_Impl( OUString() );
4195 // remove the readonly state
4196 bool bWasReadonly
= false;
4197 pImpl
->m_nStorOpenMode
= SFX_STREAM_READWRITE
;
4198 const SfxBoolItem
* pReadOnlyItem
= SfxItemSet::GetItem
<SfxBoolItem
>(pImpl
->m_pSet
.get(), SID_DOC_READONLY
, false);
4199 if ( pReadOnlyItem
&& pReadOnlyItem
->GetValue() )
4200 bWasReadonly
= true;
4201 GetItemSet()->ClearItem( SID_DOC_READONLY
);
4204 LockOrigFileOnDemand( false, false );
4208 if ( pImpl
->xStream
.is() )
4212 xOptStorage
->writeAndAttachToStream( pImpl
->xStream
);
4213 pImpl
->xStorage
= xStorage
;
4216 catch( const uno::Exception
& )
4220 if ( aResult
.isEmpty() )
4223 SetPhysicalName_Impl( OUString() );
4224 SetName( aOrigURL
);
4227 // set the readonly state back
4228 pImpl
->m_nStorOpenMode
= SFX_STREAM_READONLY
;
4229 GetItemSet()->Put( SfxBoolItem(SID_DOC_READONLY
, true));
4232 pImpl
->xStorage
= xStorage
;
4241 bool SfxMedium::SwitchDocumentToFile( const OUString
& aURL
)
4243 // the method is only for storage based documents
4244 bool bResult
= false;
4245 OUString aOrigURL
= pImpl
->m_aLogicName
;
4247 if ( !aURL
.isEmpty() && !aOrigURL
.isEmpty() )
4249 uno::Reference
< embed::XStorage
> xStorage
= GetStorage();
4250 uno::Reference
< embed::XOptimizedStorage
> xOptStorage( xStorage
, uno::UNO_QUERY
);
4252 // TODO/LATER: reuse the pImpl->pTempFile if it already exists
4253 CanDisposeStorage_Impl( false );
4255 SetPhysicalName_Impl( OUString() );
4258 // open the temporary file based document
4260 LockOrigFileOnDemand( false, false );
4264 if ( pImpl
->xStream
.is() )
4268 uno::Reference
< io::XTruncate
> xTruncate( pImpl
->xStream
, uno::UNO_QUERY_THROW
);
4269 xTruncate
->truncate();
4270 if ( xOptStorage
.is() )
4271 xOptStorage
->writeAndAttachToStream( pImpl
->xStream
);
4272 pImpl
->xStorage
= xStorage
;
4275 catch( const uno::Exception
& )
4282 SetPhysicalName_Impl( OUString() );
4283 SetName( aOrigURL
);
4285 pImpl
->xStorage
= xStorage
;
4292 void SfxMedium::SetInCheckIn( bool bInCheckIn
)
4294 pImpl
->m_bInCheckIn
= bInCheckIn
;
4297 bool SfxMedium::IsInCheckIn( ) const
4299 return pImpl
->m_bInCheckIn
;
4302 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */