1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
22 #include <sfx2/docfile.hxx>
23 #include <sfx2/signaturestate.hxx>
25 #include <uno/mapping.hxx>
26 #include <com/sun/star/task/InteractionHandler.hpp>
27 #include <com/sun/star/uno/Reference.h>
28 #include <com/sun/star/ucb/XContent.hpp>
29 #include <com/sun/star/container/XChild.hpp>
30 #include <com/sun/star/document/XDocumentRevisionListPersistence.hpp>
31 #include <com/sun/star/document/LockedDocumentRequest.hpp>
32 #include <com/sun/star/document/OwnLockOnDocumentRequest.hpp>
33 #include <com/sun/star/document/LockedOnSavingRequest.hpp>
34 #include <com/sun/star/document/LockFileIgnoreRequest.hpp>
35 #include <com/sun/star/document/ChangedByOthersRequest.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/embed/XTransactedObject.hpp>
38 #include <com/sun/star/embed/ElementModes.hpp>
39 #include <com/sun/star/embed/UseBackupException.hpp>
40 #include <com/sun/star/embed/XOptimizedStorage.hpp>
41 #include <com/sun/star/ucb/InteractiveIOException.hpp>
42 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
43 #include <com/sun/star/ucb/CommandFailedException.hpp>
44 #include <com/sun/star/ucb/CommandAbortedException.hpp>
45 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
46 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
47 #include <com/sun/star/ucb/XContentProvider.hpp>
48 #include <com/sun/star/ucb/XProgressHandler.hpp>
49 #include <com/sun/star/ucb/XCommandInfo.hpp>
50 #include <com/sun/star/io/XOutputStream.hpp>
51 #include <com/sun/star/io/XInputStream.hpp>
52 #include <com/sun/star/io/XTruncate.hpp>
53 #include <com/sun/star/io/XStreamListener.hpp>
54 #include <com/sun/star/io/XSeekable.hpp>
55 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
56 #include <com/sun/star/lang/XInitialization.hpp>
57 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
58 #include <com/sun/star/ucb/NameClash.hpp>
59 #include <com/sun/star/ucb/TransferInfo.hpp>
60 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
61 #include <com/sun/star/ucb/OpenMode.hpp>
62 #include <com/sun/star/logging/DocumentIOLogRing.hpp>
63 #include <com/sun/star/logging/XSimpleLogRing.hpp>
64 #include <cppuhelper/implbase1.hxx>
65 #include <com/sun/star/beans/PropertyValue.hpp>
66 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
67 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
68 #include <tools/urlobj.hxx>
69 #include <unotools/tempfile.hxx>
70 #include <comphelper/processfactory.hxx>
71 #include <comphelper/interaction.hxx>
72 #include <framework/interaction.hxx>
73 #include <unotools/streamhelper.hxx>
74 #include <unotools/localedatawrapper.hxx>
75 #include <vcl/msgbox.hxx>
76 #include <svl/stritem.hxx>
77 #include <svl/eitem.hxx>
78 #include <svl/lckbitem.hxx>
79 #include <svtools/sfxecode.hxx>
80 #include <svl/itemset.hxx>
81 #include <svl/intitem.hxx>
82 #include <svtools/svparser.hxx>
83 #include <cppuhelper/weakref.hxx>
85 #include <unotools/streamwrap.hxx>
87 #include <osl/file.hxx>
89 #include <comphelper/storagehelper.hxx>
90 #include <unotools/mediadescriptor.hxx>
91 #include <comphelper/docpasswordhelper.hxx>
92 #include <tools/inetmime.hxx>
93 #include <unotools/ucblockbytes.hxx>
94 #include <unotools/pathoptions.hxx>
95 #include <svtools/asynclink.hxx>
96 #include <svl/inettype.hxx>
97 #include <ucbhelper/commandenvironment.hxx>
98 #include <unotools/localfilehelper.hxx>
99 #include <unotools/ucbstreamhelper.hxx>
100 #include <unotools/ucbhelper.hxx>
101 #include <unotools/progresshandlerwrap.hxx>
102 #include <ucbhelper/content.hxx>
103 #include <ucbhelper/interactionrequest.hxx>
104 #include <sot/stg.hxx>
105 #include <unotools/saveopt.hxx>
106 #include <svl/documentlockfile.hxx>
107 #include <com/sun/star/document/DocumentRevisionListPersistence.hpp>
109 #include "helper.hxx"
110 #include <sfx2/request.hxx>
111 #include <sfx2/app.hxx>
112 #include <sfx2/frame.hxx>
113 #include <sfx2/fcontnr.hxx>
114 #include <sfx2/docfilt.hxx>
115 #include <sfx2/objsh.hxx>
116 #include <sfx2/docfac.hxx>
118 #include "openflag.hxx"
119 #include <sfx2/sfxresid.hxx>
120 #include <sfx2/appuno.hxx>
121 #include "sfxacldetect.hxx"
122 #include <officecfg/Office/Common.hxx>
124 #include <boost/noncopyable.hpp>
125 #include <boost/scoped_ptr.hpp>
127 using namespace ::com::sun::star
;
128 using namespace ::com::sun::star::uno
;
129 using namespace ::com::sun::star::ucb
;
130 using namespace ::com::sun::star::beans
;
131 using namespace ::com::sun::star::io
;
135 static const sal_Int8 LOCK_UI_NOLOCK
= 0;
136 static const sal_Int8 LOCK_UI_SUCCEEDED
= 1;
137 static const sal_Int8 LOCK_UI_TRY
= 2;
139 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
141 bool IsSystemFileLockingUsed()
143 #if HAVE_FEATURE_MACOSX_SANDBOX
146 return officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::get();
150 //----------------------------------------------------------------
151 bool IsOOoLockFileUsed()
153 #if HAVE_FEATURE_MACOSX_SANDBOX
156 return officecfg::Office::Common::Misc::UseDocumentOOoLockFile::get();
162 return officecfg::Office::Common::Misc::UseLocking::get();
167 } // anonymous namespace
168 //==========================================================
171 //----------------------------------------------------------------
172 class SfxMediumHandler_Impl
: public ::cppu::WeakImplHelper1
< com::sun::star::task::XInteractionHandler
>
174 com::sun::star::uno::Reference
< com::sun::star::task::XInteractionHandler
> m_xInter
;
177 virtual void SAL_CALL
handle( const com::sun::star::uno::Reference
< com::sun::star::task::XInteractionRequest
>& xRequest
)
178 throw( com::sun::star::uno::RuntimeException
);
180 SfxMediumHandler_Impl( com::sun::star::uno::Reference
< com::sun::star::task::XInteractionHandler
> xInteraction
)
181 : m_xInter( xInteraction
)
184 ~SfxMediumHandler_Impl();
187 //----------------------------------------------------------------
188 SfxMediumHandler_Impl::~SfxMediumHandler_Impl()
192 //----------------------------------------------------------------
193 void SAL_CALL
SfxMediumHandler_Impl::handle( const com::sun::star::uno::Reference
< com::sun::star::task::XInteractionRequest
>& xRequest
)
194 throw( com::sun::star::uno::RuntimeException
)
199 com::sun::star::uno::Any aRequest
= xRequest
->getRequest();
200 com::sun::star::ucb::InteractiveIOException aIoException
;
201 com::sun::star::ucb::UnsupportedDataSinkException aSinkException
;
202 if ( (aRequest
>>= aIoException
) && ( aIoException
.Code
== IOErrorCode_ACCESS_DENIED
|| aIoException
.Code
== IOErrorCode_LOCKING_VIOLATION
) )
205 if ( aRequest
>>= aSinkException
)
208 m_xInter
->handle( xRequest
);
211 class SfxMedium_Impl
: boost::noncopyable
214 StreamMode m_nStorOpenMode
;
217 ::ucbhelper::Content aContent
;
218 bool bUpdatePickList
:1;
220 bool bDownloadDone
:1;
222 bool bUseInteractionHandler
:1;
223 bool bAllowDefaultIntHdl
:1;
224 bool bDisposeStorage
:1;
225 bool bStorageBasedOnInStream
:1;
226 bool m_bSalvageMode
:1;
227 bool m_bVersionsAlreadyLoaded
:1;
229 bool m_bGotDateTime
:1;
230 bool m_bRemoveBackup
:1;
231 bool m_bOriginallyReadOnly
:1;
232 bool m_bTriedStorage
:1;
234 bool m_bInputStreamIsReadOnly
:1;
238 OUString m_aLogicName
;
239 OUString m_aLongName
;
241 mutable SfxItemSet
* m_pSet
;
242 mutable INetURLObject
* m_pURLObj
;
244 const SfxFilter
* m_pFilter
;
245 boost::scoped_ptr
<SfxFilter
> m_pCustomFilter
;
247 SfxMedium
* pAntiImpl
;
248 SvStream
* m_pInStream
;
249 SvStream
* m_pOutStream
;
251 const SfxFilter
* pOrigFilter
;
253 DateTime aExpireTime
;
254 SfxFrameWeak wLoadTargetFrame
;
255 SvKeyValueIteratorRef xAttributes
;
257 svtools::AsynchronLink aDoneLink
;
259 uno::Sequence
< util::RevisionTag
> aVersions
;
261 ::utl::TempFile
* pTempFile
;
263 uno::Reference
<embed::XStorage
> xStorage
;
264 uno::Reference
<embed::XStorage
> m_xZipStorage
;
265 uno::Reference
<io::XInputStream
> m_xInputStreamToLoadFrom
;
266 uno::Reference
<io::XInputStream
> xInputStream
;
267 uno::Reference
<io::XStream
> xStream
;
268 uno::Reference
<io::XStream
> m_xLockingStream
;
269 uno::Reference
<task::XInteractionHandler
> xInteraction
;
270 uno::Reference
<logging::XSimpleLogRing
> m_xLogRing
;
272 sal_uInt32 nLastStorageError
;
274 OUString m_aBackupURL
;
276 // the following member is changed and makes sense only during saving
277 // TODO/LATER: in future the signature state should be controlled by the medium not by the document
278 // in this case the member will hold this information
279 sal_uInt16 m_nSignatureState
;
281 util::DateTime m_aDateTime
;
283 SfxMedium_Impl( SfxMedium
* pAntiImplP
);
286 OUString
getFilterMimeType()
287 { return m_pFilter
== 0 ? OUString() : m_pFilter
->GetMimeType(); }
290 //------------------------------------------------------------------
291 SfxMedium_Impl::SfxMedium_Impl( SfxMedium
* pAntiImplP
) :
292 m_nStorOpenMode(SFX_STREAM_READWRITE
),
293 m_eError(SVSTREAM_OK
),
294 bUpdatePickList(true),
296 bDownloadDone( true ),
298 bUseInteractionHandler( true ),
299 bAllowDefaultIntHdl( false ),
300 bDisposeStorage( false ),
301 bStorageBasedOnInStream( false ),
302 m_bSalvageMode( false ),
303 m_bVersionsAlreadyLoaded( false ),
305 m_bGotDateTime( false ),
306 m_bRemoveBackup( false ),
307 m_bOriginallyReadOnly(false),
308 m_bTriedStorage(false),
310 m_bInputStreamIsReadOnly(false),
315 pAntiImpl( pAntiImplP
),
319 aExpireTime( Date( Date::SYSTEM
) + 10, Time( Time::SYSTEM
) ),
321 nLastStorageError( 0 ),
322 m_nSignatureState( SIGNATURESTATE_NOSIGNATURES
)
324 aDoneLink
.CreateMutex();
327 //------------------------------------------------------------------
328 SfxMedium_Impl::~SfxMedium_Impl()
330 aDoneLink
.ClearPendingCall();
337 void SfxMedium::ResetError()
339 pImp
->m_eError
= SVSTREAM_OK
;
340 if( pImp
->m_pInStream
)
341 pImp
->m_pInStream
->ResetError();
342 if( pImp
->m_pOutStream
)
343 pImp
->m_pOutStream
->ResetError();
346 //------------------------------------------------------------------
347 sal_uInt32
SfxMedium::GetLastStorageCreationState()
349 return pImp
->nLastStorageError
;
352 //------------------------------------------------------------------
353 void SfxMedium::AddLog( const OUString
& aMessage
)
355 if ( !pImp
->m_xLogRing
.is() )
359 Reference
<XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
360 pImp
->m_xLogRing
.set( logging::DocumentIOLogRing::get(xContext
) );
362 catch( const uno::Exception
& )
366 if ( pImp
->m_xLogRing
.is() )
367 pImp
->m_xLogRing
->logString( aMessage
);
370 //------------------------------------------------------------------
371 void SfxMedium::SetError( sal_uInt32 nError
, const OUString
& aLogMessage
)
373 pImp
->m_eError
= nError
;
374 if ( pImp
->m_eError
!= ERRCODE_NONE
&& !aLogMessage
.isEmpty() )
375 AddLog( aLogMessage
);
378 //------------------------------------------------------------------
379 sal_uInt32
SfxMedium::GetErrorCode() const
381 sal_uInt32 lError
= pImp
->m_eError
;
382 if(!lError
&& pImp
->m_pInStream
)
383 lError
= pImp
->m_pInStream
->GetErrorCode();
384 if(!lError
&& pImp
->m_pOutStream
)
385 lError
= pImp
->m_pOutStream
->GetErrorCode();
389 //------------------------------------------------------------------
390 void SfxMedium::CheckFileDate( const util::DateTime
& aInitDate
)
392 GetInitFileDate( true );
393 if ( pImp
->m_aDateTime
.Seconds
!= aInitDate
.Seconds
394 || pImp
->m_aDateTime
.Minutes
!= aInitDate
.Minutes
395 || pImp
->m_aDateTime
.Hours
!= aInitDate
.Hours
396 || pImp
->m_aDateTime
.Day
!= aInitDate
.Day
397 || pImp
->m_aDateTime
.Month
!= aInitDate
.Month
398 || pImp
->m_aDateTime
.Year
!= aInitDate
.Year
)
400 uno::Reference
< task::XInteractionHandler
> xHandler
= GetInteractionHandler();
406 ::rtl::Reference
< ::ucbhelper::InteractionRequest
> xInteractionRequestImpl
= new ::ucbhelper::InteractionRequest( uno::makeAny(
407 document::ChangedByOthersRequest() ) );
408 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > aContinuations( 3 );
409 aContinuations
[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl
.get() );
410 aContinuations
[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl
.get() );
411 xInteractionRequestImpl
->setContinuations( aContinuations
);
413 xHandler
->handle( xInteractionRequestImpl
.get() );
415 ::rtl::Reference
< ::ucbhelper::InteractionContinuation
> xSelected
= xInteractionRequestImpl
->getSelection();
416 if ( uno::Reference
< task::XInteractionAbort
>( xSelected
.get(), uno::UNO_QUERY
).is() )
418 SetError( ERRCODE_ABORT
, OUString( OSL_LOG_PREFIX
) );
421 catch ( const uno::Exception
& )
427 //------------------------------------------------------------------
428 sal_Bool
SfxMedium::DocNeedsFileDateCheck()
430 return ( !IsReadOnly() && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) ) );
433 //------------------------------------------------------------------
434 util::DateTime
SfxMedium::GetInitFileDate( sal_Bool bIgnoreOldValue
)
436 if ( ( bIgnoreOldValue
|| !pImp
->m_bGotDateTime
) && !pImp
->m_aLogicName
.isEmpty() )
440 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xDummyEnv
;
441 ::ucbhelper::Content
aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
), xDummyEnv
, comphelper::getProcessComponentContext() );
443 aContent
.getPropertyValue("DateModified") >>= pImp
->m_aDateTime
;
444 pImp
->m_bGotDateTime
= true;
446 catch ( const ::com::sun::star::uno::Exception
& )
451 return pImp
->m_aDateTime
;
454 //------------------------------------------------------------------
455 Reference
< XContent
> SfxMedium::GetContent() const
457 if ( !pImp
->aContent
.get().is() )
459 Reference
< ::com::sun::star::ucb::XContent
> xContent
;
460 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
462 SFX_ITEMSET_ARG( pImp
->m_pSet
, pItem
, SfxUnoAnyItem
, SID_CONTENT
, false);
464 pItem
->GetValue() >>= xContent
;
470 pImp
->aContent
= ::ucbhelper::Content( xContent
, xEnv
, comphelper::getProcessComponentContext() );
472 catch ( const Exception
& )
478 // TODO: SAL_WARN( "sfx.doc", "SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why its used.");
480 if ( !pImp
->m_aName
.isEmpty() )
481 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp
->m_aName
, aURL
);
482 else if ( !pImp
->m_aLogicName
.isEmpty() )
483 aURL
= GetURLObject().GetMainURL( INetURLObject::NO_DECODE
);
484 if (!aURL
.isEmpty() )
485 ::ucbhelper::Content::create( aURL
, xEnv
, comphelper::getProcessComponentContext(), pImp
->aContent
);
489 return pImp
->aContent
.get();
492 //------------------------------------------------------------------
493 OUString
SfxMedium::GetBaseURL( bool bForSaving
)
496 const SfxStringItem
* pBaseURLItem
= static_cast<const SfxStringItem
*>( GetItemSet()->GetItem(SID_DOC_BASEURL
) );
498 aBaseURL
= pBaseURLItem
->GetValue();
499 else if ( GetContent().is() )
503 Any aAny
= pImp
->aContent
.getPropertyValue("BaseURI");
506 catch ( const ::com::sun::star::uno::Exception
& )
510 if ( aBaseURL
.isEmpty() )
511 aBaseURL
= GetURLObject().GetMainURL( INetURLObject::NO_DECODE
);
517 bool bIsRemote
= IsRemote();
518 if( (bIsRemote
&& !aOpt
.IsSaveRelINet()) || (!pImp
->m_bRemote
&& !aOpt
.IsSaveRelFSys()) )
525 //------------------------------------------------------------------
526 SvStream
* SfxMedium::GetInStream()
528 if ( pImp
->m_pInStream
)
529 return pImp
->m_pInStream
;
531 if ( pImp
->pTempFile
)
533 pImp
->m_pInStream
= new SvFileStream(pImp
->m_aName
, pImp
->m_nStorOpenMode
);
535 pImp
->m_eError
= pImp
->m_pInStream
->GetError();
537 if (!pImp
->m_eError
&& (pImp
->m_nStorOpenMode
& STREAM_WRITE
)
538 && ! pImp
->m_pInStream
->IsWritable() )
540 pImp
->m_eError
= ERRCODE_IO_ACCESSDENIED
;
541 delete pImp
->m_pInStream
;
542 pImp
->m_pInStream
= NULL
;
545 return pImp
->m_pInStream
;
553 return pImp
->m_pInStream
;
556 //------------------------------------------------------------------
557 void SfxMedium::CloseInStream()
559 CloseInStream_Impl();
562 void SfxMedium::CloseInStream_Impl()
564 // if there is a storage based on the InStream, we have to
565 // close the storage, too, because otherwise the storage
566 // would use an invalid ( deleted ) stream.
567 if ( pImp
->m_pInStream
&& pImp
->xStorage
.is() )
569 if ( pImp
->bStorageBasedOnInStream
)
573 if ( pImp
->m_pInStream
&& !GetContent().is() )
575 CreateTempFile( true );
579 DELETEZ( pImp
->m_pInStream
);
581 pImp
->m_pSet
->ClearItem( SID_INPUTSTREAM
);
583 CloseZipStorage_Impl();
584 pImp
->xInputStream
.clear();
586 if ( !pImp
->m_pOutStream
)
588 // output part of the stream is not used so the whole stream can be closed
589 // TODO/LATER: is it correct?
590 pImp
->xStream
.clear();
592 pImp
->m_pSet
->ClearItem( SID_STREAM
);
596 //------------------------------------------------------------------
597 SvStream
* SfxMedium::GetOutStream()
599 if ( !pImp
->m_pOutStream
)
601 // Create a temp. file if there is none because we always
603 CreateTempFile( false );
605 if ( pImp
->pTempFile
)
607 // On windows we try to re-use XOutStream from xStream if that exists;
608 // because opening new SvFileStream in this situation may fail with ERROR_SHARING_VIOLATION
610 if (pImp
->xStream
.is())
612 assert(pImp
->xStream
->getOutputStream().is()); // need that...
613 pImp
->m_pOutStream
= utl::UcbStreamHelper::CreateStream(
614 pImp
->xStream
, false);
618 pImp
->m_pOutStream
= new SvFileStream(
619 pImp
->m_aName
, STREAM_STD_READWRITE
);
621 // On Unix don't try to re-use XOutStream from xStream if that exists;
622 // it causes fdo#59022 (fails opening files via SMB on Linux)
624 pImp
->m_pOutStream
= new SvFileStream(
625 pImp
->m_aName
, STREAM_STD_READWRITE
);
631 return pImp
->m_pOutStream
;
634 //------------------------------------------------------------------
635 sal_Bool
SfxMedium::CloseOutStream()
637 CloseOutStream_Impl();
641 sal_Bool
SfxMedium::CloseOutStream_Impl()
643 if ( pImp
->m_pOutStream
)
645 // if there is a storage based on the OutStream, we have to
646 // close the storage, too, because otherwise the storage
647 // would use an invalid ( deleted ) stream.
648 //TODO/MBA: how to deal with this?!
649 //maybe we need a new flag when the storage was created from the outstream
650 if ( pImp
->xStorage
.is() )
655 delete pImp
->m_pOutStream
;
656 pImp
->m_pOutStream
= NULL
;
659 if ( !pImp
->m_pInStream
)
661 // input part of the stream is not used so the whole stream can be closed
662 // TODO/LATER: is it correct?
663 pImp
->xStream
.clear();
665 pImp
->m_pSet
->ClearItem( SID_STREAM
);
671 //------------------------------------------------------------------
672 const OUString
& SfxMedium::GetPhysicalName() const
674 if ( pImp
->m_aName
.isEmpty() && !pImp
->m_aLogicName
.isEmpty() )
675 (( SfxMedium
*)this)->CreateFileStream();
677 // return the name then
678 return pImp
->m_aName
;
681 //------------------------------------------------------------------
682 void SfxMedium::CreateFileStream()
684 ForceSynchronStream_Impl( true );
686 if( pImp
->m_pInStream
)
688 CreateTempFile( false );
689 pImp
->bIsTemp
= true;
690 CloseInStream_Impl();
694 //------------------------------------------------------------------
695 sal_Bool
SfxMedium::Commit()
697 if( pImp
->xStorage
.is() )
698 StorageCommit_Impl();
699 else if( pImp
->m_pOutStream
)
700 pImp
->m_pOutStream
->Flush();
701 else if( pImp
->m_pInStream
)
702 pImp
->m_pInStream
->Flush();
704 if ( GetError() == SVSTREAM_OK
)
706 // does something only in case there is a temporary file ( means aName points to different location than aLogicName )
710 bool bResult
= ( GetError() == SVSTREAM_OK
);
712 if ( bResult
&& DocNeedsFileDateCheck() )
713 GetInitFileDate( true );
715 // remove truncation mode from the flags
716 pImp
->m_nStorOpenMode
&= (~STREAM_TRUNC
);
720 //------------------------------------------------------------------
721 sal_Bool
SfxMedium::IsStorage()
723 if ( pImp
->xStorage
.is() )
726 if ( pImp
->m_bTriedStorage
)
727 return pImp
->bIsStorage
;
729 if ( pImp
->pTempFile
)
732 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp
->m_aName
, aURL
) )
734 SAL_WARN( "sfx.doc", "Physical name not convertible!");
736 pImp
->bIsStorage
= SotStorage::IsStorageFile( aURL
) && !SotStorage::IsOLEStorage( aURL
);
737 if ( !pImp
->bIsStorage
)
738 pImp
->m_bTriedStorage
= true;
740 else if ( GetInStream() )
742 pImp
->bIsStorage
= SotStorage::IsStorageFile( pImp
->m_pInStream
) && !SotStorage::IsOLEStorage( pImp
->m_pInStream
);
743 if ( !pImp
->m_pInStream
->GetError() && !pImp
->bIsStorage
)
744 pImp
->m_bTriedStorage
= true;
747 return pImp
->bIsStorage
;
750 //------------------------------------------------------------------
751 sal_Bool
SfxMedium::IsPreview_Impl()
753 bool bPreview
= false;
754 SFX_ITEMSET_ARG( GetItemSet(), pPreview
, SfxBoolItem
, SID_PREVIEW
, false);
756 bPreview
= pPreview
->GetValue();
759 SFX_ITEMSET_ARG( GetItemSet(), pFlags
, SfxStringItem
, SID_OPTIONS
, false);
762 OUString aFileFlags
= pFlags
->GetValue();
763 aFileFlags
= aFileFlags
.toAsciiUpperCase();
764 if ( -1 != aFileFlags
.indexOf( 'B' ) )
772 //------------------------------------------------------------------
773 void SfxMedium::StorageBackup_Impl()
775 ::ucbhelper::Content aOriginalContent
;
776 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xDummyEnv
;
778 bool bBasedOnOriginalFile
= ( !pImp
->pTempFile
&& !( !pImp
->m_aLogicName
.isEmpty() && pImp
->m_bSalvageMode
)
779 && !GetURLObject().GetMainURL( INetURLObject::NO_DECODE
).isEmpty()
780 && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) )
781 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) ) );
783 if ( bBasedOnOriginalFile
&& pImp
->m_aBackupURL
.isEmpty()
784 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
), xDummyEnv
, comphelper::getProcessComponentContext(), aOriginalContent
) )
786 DoInternalBackup_Impl( aOriginalContent
);
787 if( pImp
->m_aBackupURL
.isEmpty() )
788 SetError( ERRCODE_SFX_CANTCREATEBACKUP
, OUString( OSL_LOG_PREFIX
) );
792 //------------------------------------------------------------------
793 OUString
SfxMedium::GetBackup_Impl()
795 if ( pImp
->m_aBackupURL
.isEmpty() )
796 StorageBackup_Impl();
798 return pImp
->m_aBackupURL
;
801 //------------------------------------------------------------------
802 uno::Reference
< embed::XStorage
> SfxMedium::GetOutputStorage()
805 return uno::Reference
< embed::XStorage
>();
807 // if the medium was constructed with a Storage: use this one, not a temp. storage
808 // if a temporary storage already exists: use it
809 if ( pImp
->xStorage
.is() && ( pImp
->m_aLogicName
.isEmpty() || pImp
->pTempFile
) )
810 return pImp
->xStorage
;
812 // if necessary close stream that was used for reading
813 if ( pImp
->m_pInStream
&& !pImp
->m_pInStream
->IsWritable() )
816 DBG_ASSERT( !pImp
->m_pOutStream
, "OutStream in a readonly Medium?!" );
818 // TODO/LATER: The current solution is to store the document temporary and then copy it to the target location;
819 // in future it should be stored directly and then copied to the temporary location, since in this case no
820 // file attributes have to be preserved and system copying mechanics could be used instead of streaming.
821 CreateTempFileNoCopy();
826 //------------------------------------------------------------------
827 void SfxMedium::SetEncryptionDataToStorage_Impl()
829 // in case media-descriptor contains password it should be used on opening
830 if ( pImp
->xStorage
.is() && pImp
->m_pSet
)
832 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
833 if ( GetEncryptionData_Impl( pImp
->m_pSet
, aEncryptionData
) )
835 // replace the password with encryption data
836 pImp
->m_pSet
->ClearItem( SID_PASSWORD
);
837 pImp
->m_pSet
->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::makeAny( aEncryptionData
) ) );
841 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( pImp
->xStorage
, aEncryptionData
);
843 catch( const uno::Exception
& )
845 SAL_WARN( "sfx.doc", "It must be possible to set a common password for the storage" );
846 // TODO/LATER: set the error code in case of problem
847 // SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
853 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
855 // FIXME: Hmm actually lock files should be used for sftp: documents
856 // even if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT. Only the use of lock
857 // files for *local* documents is unnecessary in that case. But
858 // actually, the checks for sftp: here are just wishful thinking; I
859 // don't this there is any support for actually editing documents
860 // behind sftp: URLs anyway.
862 // Sure, there could perhaps be a 3rd-party extension that brings UCB
863 // the potential to handle files behind sftp:. But there could also be
864 // an extension that handles some arbitrary foobar: scheme *and* it
865 // could be that lock files would be the correct thing to use for
866 // foobar: documents, too. But the hardcoded test below won't know
867 // that. Clearly the knowledge whether lock files should be used or
868 // not for some URL scheme belongs in UCB, not here.
870 //------------------------------------------------------------------
871 sal_Int8
SfxMedium::ShowLockedDocumentDialog( const uno::Sequence
< OUString
>& aData
, sal_Bool bIsLoading
, sal_Bool bOwnLock
)
873 sal_Int8 nResult
= LOCK_UI_NOLOCK
;
875 // show the interaction regarding the document opening
876 uno::Reference
< task::XInteractionHandler
> xHandler
= GetInteractionHandler();
878 if ( ::svt::DocumentLockFile::IsInteractionAllowed() && xHandler
.is() && ( bIsLoading
|| bOwnLock
) )
880 OUString aDocumentURL
= GetURLObject().GetLastName();
882 ::rtl::Reference
< ::ucbhelper::InteractionRequest
> xInteractionRequestImpl
;
886 if ( aData
.getLength() > LOCKFILE_EDITTIME_ID
)
887 aInfo
= aData
[LOCKFILE_EDITTIME_ID
];
889 xInteractionRequestImpl
= new ::ucbhelper::InteractionRequest( uno::makeAny(
890 document::OwnLockOnDocumentRequest( OUString(), uno::Reference
< uno::XInterface
>(), aDocumentURL
, aInfo
, !bIsLoading
) ) );
894 if ( aData
.getLength() > LOCKFILE_EDITTIME_ID
)
896 if ( !aData
[LOCKFILE_OOOUSERNAME_ID
].isEmpty() )
897 aInfo
= aData
[LOCKFILE_OOOUSERNAME_ID
];
899 aInfo
= aData
[LOCKFILE_SYSUSERNAME_ID
];
901 if ( !aInfo
.isEmpty() && !aData
[LOCKFILE_EDITTIME_ID
].isEmpty() )
904 aInfo
+= aData
[LOCKFILE_EDITTIME_ID
];
911 xInteractionRequestImpl
= new ::ucbhelper::InteractionRequest( uno::makeAny(
912 document::LockedDocumentRequest( OUString(), uno::Reference
< uno::XInterface
>(), aDocumentURL
, aInfo
) ) );
916 xInteractionRequestImpl
= new ::ucbhelper::InteractionRequest( uno::makeAny(
917 document::LockedOnSavingRequest( OUString(), uno::Reference
< uno::XInterface
>(), aDocumentURL
, aInfo
) ) );
922 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > aContinuations( 3 );
923 aContinuations
[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl
.get() );
924 aContinuations
[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl
.get() );
925 aContinuations
[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl
.get() );
926 xInteractionRequestImpl
->setContinuations( aContinuations
);
928 xHandler
->handle( xInteractionRequestImpl
.get() );
930 ::rtl::Reference
< ::ucbhelper::InteractionContinuation
> xSelected
= xInteractionRequestImpl
->getSelection();
931 if ( uno::Reference
< task::XInteractionAbort
>( xSelected
.get(), uno::UNO_QUERY
).is() )
933 SetError( ERRCODE_ABORT
, OUString( OSL_LOG_PREFIX
) );
935 else if ( uno::Reference
< task::XInteractionDisapprove
>( xSelected
.get(), uno::UNO_QUERY
).is() )
937 // own lock on loading, user has selected to ignore the lock
938 // own lock on saving, user has selected to ignore the lock
939 // alien lock on loading, user has selected to edit a copy of document
940 // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location
941 if ( bIsLoading
&& !bOwnLock
)
943 // means that a copy of the document should be opened
944 GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE
, true ) );
947 nResult
= LOCK_UI_SUCCEEDED
;
949 else // if ( XSelected == aContinuations[1] )
951 // own lock on loading, user has selected to open readonly
952 // own lock on saving, user has selected to open readonly
953 // alien lock on loading, user has selected to retry saving
954 // TODO/LATER: alien lock on saving, user has selected to retry saving
957 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
959 nResult
= LOCK_UI_TRY
;
966 // if no interaction handler is provided the default answer is open readonly
967 // that usually happens in case the document is loaded per API
968 // so the document must be opened readonly for backward compatibility
969 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
972 SetError( ERRCODE_IO_ACCESSDENIED
, OUString( OSL_LOG_PREFIX
) );
981 bool isSuitableProtocolForLocking(const OUString
& rLogicName
)
983 INetURLObject
aUrl( rLogicName
);
984 INetProtocol eProt
= aUrl
.GetProtocol();
985 #if HAVE_FEATURE_MACOSX_SANDBOX
986 return eProt
== INET_PROT_SFTP
;
988 return eProt
== INET_PROT_FILE
|| eProt
== INET_PROT_SFTP
;
993 #endif // HAVE_FEATURE_MULTIUSER_ENVIRONMENT
995 // sets SID_DOC_READONLY if the document cannot be opened for editing
996 // if user cancel the loading the ERROR_ABORT is set
997 void SfxMedium::LockOrigFileOnDemand( sal_Bool bLoading
, sal_Bool bNoUI
)
999 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1003 if (!IsLockingUsed() || GetURLObject().HasError())
1008 if ( pImp
->m_bLocked
&& bLoading
&& ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) ) )
1010 // if the document is already locked the system locking might be temporarely off after storing
1011 // check whether the system file locking should be taken again
1012 GetLockingStream_Impl();
1015 bool bResult
= pImp
->m_bLocked
;
1019 // no read-write access is necessary on loading if the document is explicitly opened as copy
1020 SFX_ITEMSET_ARG( GetItemSet(), pTemplateItem
, SfxBoolItem
, SID_TEMPLATE
, false);
1021 bResult
= ( bLoading
&& pTemplateItem
&& pTemplateItem
->GetValue() );
1024 if ( !bResult
&& !IsReadOnly() )
1026 bool bContentReadonly
= false;
1027 if ( bLoading
&& ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) ) )
1029 // let the original document be opened to check the possibility to open it for editing
1030 // and to let the writable stream stay open to hold the lock on the document
1031 GetLockingStream_Impl();
1034 // "IsReadOnly" property does not allow to detect whether the file is readonly always
1035 // so we try always to open the file for editing
1036 // the file is readonly only in case the read-write stream can not be opened
1037 if ( bLoading
&& !pImp
->m_xLockingStream
.is() )
1041 // MediaDescriptor does this check also, the duplication should be avoided in future
1042 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xDummyEnv
;
1043 ::ucbhelper::Content
aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
), xDummyEnv
, comphelper::getProcessComponentContext() );
1044 aContent
.getPropertyValue("IsReadOnly") >>= bContentReadonly
;
1046 catch( const uno::Exception
& ) {}
1049 // This block was introduced as a fix to i#102464, but removing
1050 // this does not make the problem re-appear. But leaving this
1051 // part would interfere with documents saved in samba share. This
1052 // affects Windows only.
1053 if ( !bContentReadonly
)
1055 // the file is not readonly, check the ACL
1058 if ( ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
), aPhysPath
) )
1059 bContentReadonly
= IsReadonlyAccordingACL( aPhysPath
.getStr() );
1063 if ( bContentReadonly
)
1064 pImp
->m_bOriginallyReadOnly
= true;
1067 // do further checks only if the file not readonly in fs
1068 if ( !bContentReadonly
)
1070 // the special file locking should be used only for suitable URLs
1071 if ( isSuitableProtocolForLocking( pImp
->m_aLogicName
) )
1074 // in case of storing the document should request the output before locking
1077 // let the stream be opened to check the system file locking
1079 if (GetError() != ERRCODE_NONE
) {
1084 sal_Int8 bUIStatus
= LOCK_UI_NOLOCK
;
1086 // check whether system file locking has been used, the default value is false
1087 bool bUseSystemLock
= ::utl::LocalFileHelper::IsLocalFile( pImp
->m_aLogicName
) && IsSystemFileLockingUsed();
1089 // TODO/LATER: This implementation does not allow to detect the system lock on saving here, actually this is no big problem
1090 // if system lock is used the writeable stream should be available
1091 bool bHandleSysLocked
= ( bLoading
&& bUseSystemLock
&& !pImp
->xStream
.is() && !pImp
->m_pOutStream
);
1097 ::svt::DocumentLockFile
aLockFile( pImp
->m_aLogicName
);
1098 if ( !bHandleSysLocked
)
1102 bResult
= aLockFile
.CreateOwnLockFile();
1104 catch ( const ucb::InteractiveIOException
& e
)
1106 // exception means that the lock file can not be successfully accessed
1107 // in this case it should be ignored if system file locking is anyway active
1108 if ( bUseSystemLock
|| !IsOOoLockFileUsed() )
1111 // take the ownership over the lock file
1112 aLockFile
.OverwriteOwnLockFile();
1114 else if ( e
.Code
== IOErrorCode_INVALID_PARAMETER
)
1116 // system file locking is not active, ask user whether he wants to open the document without any locking
1117 uno::Reference
< task::XInteractionHandler
> xHandler
= GetInteractionHandler();
1119 if ( xHandler
.is() )
1121 ::rtl::Reference
< ::ucbhelper::InteractionRequest
> xIgnoreRequestImpl
1122 = new ::ucbhelper::InteractionRequest( uno::makeAny( document::LockFileIgnoreRequest() ) );
1124 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > aContinuations( 2 );
1125 aContinuations
[0] = new ::ucbhelper::InteractionAbort( xIgnoreRequestImpl
.get() );
1126 aContinuations
[1] = new ::ucbhelper::InteractionApprove( xIgnoreRequestImpl
.get() );
1127 xIgnoreRequestImpl
->setContinuations( aContinuations
);
1129 xHandler
->handle( xIgnoreRequestImpl
.get() );
1131 ::rtl::Reference
< ::ucbhelper::InteractionContinuation
> xSelected
= xIgnoreRequestImpl
->getSelection();
1132 bResult
= uno::Reference
< task::XInteractionApprove
>( xSelected
.get(), uno::UNO_QUERY
).is();
1136 catch ( const uno::Exception
& )
1138 // exception means that the lock file can not be successfully accessed
1139 // in this case it should be ignored if system file locking is anyway active
1140 if ( bUseSystemLock
|| !IsOOoLockFileUsed() )
1143 // take the ownership over the lock file
1144 aLockFile
.OverwriteOwnLockFile();
1148 // in case OOo locking is turned off the lock file is still written if possible
1149 // but it is ignored while deciding whether the document should be opened for editing or not
1150 if ( !bResult
&& !IsOOoLockFileUsed() )
1153 // take the ownership over the lock file
1154 aLockFile
.OverwriteOwnLockFile();
1161 uno::Sequence
< OUString
> aData
;
1164 // impossibility to get data is no real problem
1165 aData
= aLockFile
.GetLockData();
1167 catch( const uno::Exception
& )
1171 bool bOwnLock
= false;
1173 if ( !bHandleSysLocked
)
1175 uno::Sequence
< OUString
> aOwnData
= aLockFile
.GenerateOwnEntry();
1176 bOwnLock
= ( aData
.getLength() > LOCKFILE_USERURL_ID
1177 && aOwnData
.getLength() > LOCKFILE_USERURL_ID
1178 && aOwnData
[LOCKFILE_SYSUSERNAME_ID
].equals( aData
[LOCKFILE_SYSUSERNAME_ID
] ) );
1181 && aOwnData
[LOCKFILE_LOCALHOST_ID
].equals( aData
[LOCKFILE_LOCALHOST_ID
] )
1182 && aOwnData
[LOCKFILE_USERURL_ID
].equals( aData
[LOCKFILE_USERURL_ID
] ) )
1184 // this is own lock from the same installation, it could remain because of crash
1189 if ( !bResult
&& !bNoUI
)
1191 bUIStatus
= ShowLockedDocumentDialog( aData
, bLoading
, bOwnLock
);
1192 if ( bUIStatus
== LOCK_UI_SUCCEEDED
)
1194 // take the ownership over the lock file
1195 bResult
= aLockFile
.OverwriteOwnLockFile();
1199 bHandleSysLocked
= false;
1202 catch( const uno::Exception
& )
1205 } while( !bResult
&& bUIStatus
== LOCK_UI_TRY
);
1207 pImp
->m_bLocked
= bResult
;
1211 // this is no file URL, check whether the file is readonly
1212 bResult
= !bContentReadonly
;
1217 if ( !bResult
&& GetError() == ERRCODE_NONE
)
1219 // the error should be set in case it is storing process
1220 // or the document has been opened for editing explicitly
1221 SFX_ITEMSET_ARG( pImp
->m_pSet
, pReadOnlyItem
, SfxBoolItem
, SID_DOC_READONLY
, false );
1223 if ( !bLoading
|| (pReadOnlyItem
&& !pReadOnlyItem
->GetValue()) )
1224 SetError( ERRCODE_IO_ACCESSDENIED
, OUString( OSL_LOG_PREFIX
) );
1226 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
1229 // when the file is locked, get the current file date
1230 if ( bResult
&& DocNeedsFileDateCheck() )
1231 GetInitFileDate( true );
1233 catch( const uno::Exception
& )
1235 SAL_WARN( "sfx.doc", "Locking exception: high probability, that the content has not been created" );
1240 //------------------------------------------------------------------
1241 uno::Reference
< embed::XStorage
> SfxMedium::GetStorage( sal_Bool bCreateTempIfNo
)
1243 if ( pImp
->xStorage
.is() || pImp
->m_bTriedStorage
)
1244 return pImp
->xStorage
;
1246 uno::Sequence
< uno::Any
> aArgs( 2 );
1248 // the medium should be retrieved before temporary file creation
1249 // to let the MediaDescriptor be filled with the streams
1252 if ( bCreateTempIfNo
)
1253 CreateTempFile( false );
1258 return pImp
->xStorage
;
1260 SFX_ITEMSET_ARG( GetItemSet(), pRepairItem
, SfxBoolItem
, SID_REPAIRPACKAGE
, false);
1261 if ( pRepairItem
&& pRepairItem
->GetValue() )
1263 // the storage should be created for repairing mode
1264 CreateTempFile( false );
1267 Reference
< ::com::sun::star::ucb::XProgressHandler
> xProgressHandler
;
1268 Reference
< ::com::sun::star::task::XStatusIndicator
> xStatusIndicator
;
1270 SFX_ITEMSET_ARG( GetItemSet(), pxProgressItem
, SfxUnoAnyItem
, SID_PROGRESS_STATUSBAR_CONTROL
, false );
1271 if( pxProgressItem
&& ( pxProgressItem
->GetValue() >>= xStatusIndicator
) )
1272 xProgressHandler
= Reference
< ::com::sun::star::ucb::XProgressHandler
>(
1273 new utl::ProgressHandlerWrap( xStatusIndicator
) );
1275 uno::Sequence
< beans::PropertyValue
> aAddProps( 2 );
1276 aAddProps
[0].Name
= "RepairPackage";
1277 aAddProps
[0].Value
<<= (sal_Bool
)true;
1278 aAddProps
[1].Name
= "StatusIndicator";
1279 aAddProps
[1].Value
<<= xProgressHandler
;
1281 // the first arguments will be filled later
1283 aArgs
[2] <<= aAddProps
;
1286 if ( pImp
->xStream
.is() )
1288 // since the storage is based on temporary stream we open it always read-write
1289 aArgs
[0] <<= pImp
->xStream
;
1290 aArgs
[1] <<= embed::ElementModes::READWRITE
;
1291 pImp
->bStorageBasedOnInStream
= true;
1293 else if ( pImp
->xInputStream
.is() )
1295 // since the storage is based on temporary stream we open it always read-write
1296 aArgs
[0] <<= pImp
->xInputStream
;
1297 aArgs
[1] <<= embed::ElementModes::READ
;
1298 pImp
->bStorageBasedOnInStream
= true;
1302 CloseStreams_Impl();
1303 aArgs
[0] <<= pImp
->m_aName
;
1304 aArgs
[1] <<= embed::ElementModes::READ
;
1305 pImp
->bStorageBasedOnInStream
= false;
1310 pImp
->xStorage
= uno::Reference
< embed::XStorage
>(
1311 ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs
),
1314 catch( const uno::Exception
& )
1316 // impossibility to create the storage is no error
1319 if( ( pImp
->nLastStorageError
= GetError() ) != SVSTREAM_OK
)
1322 if ( pImp
->m_pInStream
)
1323 pImp
->m_pInStream
->Seek(0);
1324 return uno::Reference
< embed::XStorage
>();
1327 pImp
->m_bTriedStorage
= true;
1329 // TODO/LATER: Get versionlist on demand
1330 if ( pImp
->xStorage
.is() )
1332 SetEncryptionDataToStorage_Impl();
1336 SFX_ITEMSET_ARG( pImp
->m_pSet
, pVersion
, SfxInt16Item
, SID_VERSION
, false);
1338 bool bResetStorage
= false;
1339 if ( pVersion
&& pVersion
->GetValue() )
1341 // Read all available versions
1342 if ( pImp
->aVersions
.getLength() )
1344 // Search for the version fits the comment
1345 // The versions are numbered startign with 1, versions with
1346 // negative versions numbers are counted backwards from the
1348 short nVersion
= pVersion
? pVersion
->GetValue() : 0;
1350 nVersion
= ( (short) pImp
->aVersions
.getLength() ) + nVersion
;
1351 else if ( nVersion
)
1354 util::RevisionTag
& rTag
= pImp
->aVersions
[nVersion
];
1356 // Open SubStorage for all versions
1357 uno::Reference
< embed::XStorage
> xSub
= pImp
->xStorage
->openStorageElement( "Versions",
1358 embed::ElementModes::READ
);
1360 DBG_ASSERT( xSub
.is(), "Version list, but no Versions!" );
1362 // There the version is stored as packed Stream
1363 uno::Reference
< io::XStream
> xStr
= xSub
->openStreamElement( rTag
.Identifier
, embed::ElementModes::READ
);
1364 SvStream
* pStream
= utl::UcbStreamHelper::CreateStream( xStr
);
1365 if ( pStream
&& pStream
->GetError() == SVSTREAM_OK
)
1367 // Unpack Stream in TempDir
1368 ::utl::TempFile aTempFile
;
1369 OUString aTmpName
= aTempFile
.GetURL();
1370 SvFileStream
aTmpStream( aTmpName
, SFX_STREAM_READWRITE
);
1372 *pStream
>> aTmpStream
;
1375 // Open data as Storage
1376 pImp
->m_nStorOpenMode
= SFX_STREAM_READONLY
;
1377 pImp
->xStorage
= comphelper::OStorageHelper::GetStorageFromURL( aTmpName
, embed::ElementModes::READ
);
1378 pImp
->bStorageBasedOnInStream
= false;
1380 ::utl::LocalFileHelper::ConvertURLToPhysicalName( aTmpName
, aTemp
);
1381 SetPhysicalName_Impl( aTemp
);
1383 pImp
->bIsTemp
= true;
1384 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
1386 pImp
->aVersions
.realloc(0);
1389 bResetStorage
= true;
1393 bResetStorage
= true;
1396 if ( bResetStorage
)
1398 pImp
->xStorage
.clear();
1399 if ( pImp
->m_pInStream
)
1400 pImp
->m_pInStream
->Seek( 0L );
1403 pImp
->bIsStorage
= pImp
->xStorage
.is();
1404 return pImp
->xStorage
;
1407 //------------------------------------------------------------------
1408 uno::Reference
< embed::XStorage
> SfxMedium::GetZipStorageToSign_Impl( sal_Bool bReadOnly
)
1410 if ( !GetError() && !pImp
->m_xZipStorage
.is() )
1416 // we can not sign document if there is no stream
1417 // should it be possible at all?
1418 if ( !bReadOnly
&& pImp
->xStream
.is() )
1420 pImp
->m_xZipStorage
= ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING
, pImp
->xStream
, embed::ElementModes::READWRITE
);
1422 else if ( pImp
->xInputStream
.is() )
1424 pImp
->m_xZipStorage
= ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( ZIP_STORAGE_FORMAT_STRING
, pImp
->xInputStream
);
1427 catch( const uno::Exception
& )
1429 SAL_WARN( "sfx.doc", "No possibility to get readonly version of storage from medium!" );
1432 if ( GetError() ) // do not remove warnings
1436 return pImp
->m_xZipStorage
;
1439 //------------------------------------------------------------------
1440 void SfxMedium::CloseZipStorage_Impl()
1442 if ( pImp
->m_xZipStorage
.is() )
1445 pImp
->m_xZipStorage
->dispose();
1446 } catch( const uno::Exception
& )
1449 pImp
->m_xZipStorage
.clear();
1453 void SfxMedium::CloseStorage()
1455 if ( pImp
->xStorage
.is() )
1457 uno::Reference
< lang::XComponent
> xComp( pImp
->xStorage
, uno::UNO_QUERY
);
1458 // in the salvage mode the medium does not own the storage
1459 if ( pImp
->bDisposeStorage
&& !pImp
->m_bSalvageMode
)
1463 } catch( const uno::Exception
& )
1465 SAL_WARN( "sfx.doc", "Medium's storage is already disposed!" );
1469 pImp
->xStorage
.clear();
1470 pImp
->bStorageBasedOnInStream
= false;
1473 pImp
->m_bTriedStorage
= false;
1474 pImp
->bIsStorage
= false;
1477 void SfxMedium::CanDisposeStorage_Impl( sal_Bool bDisposeStorage
)
1479 pImp
->bDisposeStorage
= bDisposeStorage
;
1482 sal_Bool
SfxMedium::WillDisposeStorageOnClose_Impl()
1484 return pImp
->bDisposeStorage
;
1487 StreamMode
SfxMedium::GetOpenMode() const
1489 return pImp
->m_nStorOpenMode
;
1492 void SfxMedium::SetOpenMode( StreamMode nStorOpen
,
1493 sal_Bool bDontClose
)
1495 if ( pImp
->m_nStorOpenMode
!= nStorOpen
)
1497 pImp
->m_nStorOpenMode
= nStorOpen
;
1501 if ( pImp
->xStorage
.is() )
1504 CloseStreams_Impl();
1509 //------------------------------------------------------------------
1510 sal_Bool
SfxMedium::UseBackupToRestore_Impl( ::ucbhelper::Content
& aOriginalContent
,
1511 const Reference
< ::com::sun::star::ucb::XCommandEnvironment
>& xComEnv
)
1515 ::ucbhelper::Content
aTransactCont( pImp
->m_aBackupURL
, xComEnv
, comphelper::getProcessComponentContext() );
1517 Reference
< XInputStream
> aOrigInput
= aTransactCont
.openStream();
1518 aOriginalContent
.writeStream( aOrigInput
, true );
1521 catch( const Exception
& )
1523 // in case of failure here the backup file should not be removed
1524 // TODO/LATER: a message should be used to let user know about the backup
1525 pImp
->m_bRemoveBackup
= false;
1526 // TODO/LATER: needs a specific error code
1527 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
1533 //------------------------------------------------------------------
1534 sal_Bool
SfxMedium::StorageCommit_Impl()
1536 bool bResult
= false;
1537 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xDummyEnv
;
1538 ::ucbhelper::Content aOriginalContent
;
1540 if ( pImp
->xStorage
.is() )
1544 uno::Reference
< embed::XTransactedObject
> xTrans( pImp
->xStorage
, uno::UNO_QUERY
);
1550 CloseZipStorage_Impl();
1553 catch ( const embed::UseBackupException
& aBackupExc
)
1555 // since the temporary file is created always now, the scenario is close to be impossible
1556 if ( !pImp
->pTempFile
)
1558 OSL_ENSURE( !pImp
->m_aBackupURL
.isEmpty(), "No backup on storage commit!\n" );
1559 if ( !pImp
->m_aBackupURL
.isEmpty()
1560 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
),
1561 xDummyEnv
, comphelper::getProcessComponentContext(),
1562 aOriginalContent
) )
1564 // use backup to restore the file
1565 // the storage has already disconnected from original location
1566 CloseAndReleaseStreams_Impl();
1567 if ( !UseBackupToRestore_Impl( aOriginalContent
, xDummyEnv
) )
1569 // connect the medium to the temporary file of the storage
1570 pImp
->aContent
= ::ucbhelper::Content();
1571 pImp
->m_aName
= aBackupExc
.TemporaryFileURL
;
1572 OSL_ENSURE( !pImp
->m_aName
.isEmpty(), "The exception _must_ contain the temporary URL!\n" );
1577 SetError( ERRCODE_IO_GENERAL
, OUString( OSL_LOG_PREFIX
) );
1580 catch ( const uno::Exception
& )
1582 //TODO/LATER: improve error handling
1583 SetError( ERRCODE_IO_GENERAL
, OUString( OSL_LOG_PREFIX
) );
1592 //------------------------------------------------------------------
1593 sal_Bool
SfxMedium::TransactedTransferForFS_Impl( const INetURLObject
& aSource
,
1594 const INetURLObject
& aDest
,
1595 const Reference
< ::com::sun::star::ucb::XCommandEnvironment
>& xComEnv
)
1597 bool bResult
= false;
1598 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xDummyEnv
;
1599 Reference
< XOutputStream
> aDestStream
;
1600 ::ucbhelper::Content aOriginalContent
;
1604 aOriginalContent
= ::ucbhelper::Content( aDest
.GetMainURL( INetURLObject::NO_DECODE
), xComEnv
, comphelper::getProcessComponentContext() );
1606 catch ( const ::com::sun::star::ucb::CommandAbortedException
& )
1608 pImp
->m_eError
= ERRCODE_ABORT
;
1610 catch ( const ::com::sun::star::ucb::CommandFailedException
& )
1612 pImp
->m_eError
= ERRCODE_ABORT
;
1614 catch (const ::com::sun::star::ucb::ContentCreationException
& ex
)
1616 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
1618 (ex
.eError
== ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER
) ||
1619 (ex
.eError
== ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED
)
1622 pImp
->m_eError
= ERRCODE_IO_NOTEXISTSPATH
;
1625 catch (const ::com::sun::star::uno::Exception
&)
1627 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
1630 if( !pImp
->m_eError
|| (pImp
->m_eError
& ERRCODE_WARNING_MASK
) )
1632 if ( pImp
->xStorage
.is() )
1635 CloseStreams_Impl();
1637 ::ucbhelper::Content aTempCont
;
1638 if( ::ucbhelper::Content::create( aSource
.GetMainURL( INetURLObject::NO_DECODE
), xDummyEnv
, comphelper::getProcessComponentContext(), aTempCont
) )
1640 bool bTransactStarted
= false;
1641 SFX_ITEMSET_ARG( GetItemSet(), pOverWrite
, SfxBoolItem
, SID_OVERWRITE
, false );
1642 SFX_ITEMSET_ARG( GetItemSet(), pRename
, SfxBoolItem
, SID_RENAME
, false );
1643 bool bRename
= pRename
? pRename
->GetValue() : false;
1644 bool bOverWrite
= pOverWrite
? pOverWrite
->GetValue() : !bRename
;
1648 if( bOverWrite
&& ::utl::UCBContentHelper::IsDocument( aDest
.GetMainURL( INetURLObject::NO_DECODE
) ) )
1650 if( pImp
->m_aBackupURL
.isEmpty() )
1651 DoInternalBackup_Impl( aOriginalContent
);
1653 if( !pImp
->m_aBackupURL
.isEmpty() )
1655 Reference
< XInputStream
> aTempInput
= aTempCont
.openStream();
1656 bTransactStarted
= true;
1657 aOriginalContent
.setPropertyValue( "Size", uno::makeAny( (sal_Int64
)0 ) );
1658 aOriginalContent
.writeStream( aTempInput
, bOverWrite
);
1663 pImp
->m_eError
= ERRCODE_SFX_CANTCREATEBACKUP
;
1668 Reference
< XInputStream
> aTempInput
= aTempCont
.openStream();
1669 aOriginalContent
.writeStream( aTempInput
, bOverWrite
);
1673 catch ( const ::com::sun::star::ucb::CommandAbortedException
& )
1675 pImp
->m_eError
= ERRCODE_ABORT
;
1677 catch ( const ::com::sun::star::ucb::CommandFailedException
& )
1679 pImp
->m_eError
= ERRCODE_ABORT
;
1681 catch ( const ::com::sun::star::ucb::InteractiveIOException
& r
)
1683 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
)
1684 pImp
->m_eError
= ERRCODE_IO_ACCESSDENIED
;
1685 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
1686 pImp
->m_eError
= ERRCODE_IO_NOTEXISTS
;
1687 else if ( r
.Code
== IOErrorCode_CANT_READ
)
1688 pImp
->m_eError
= ERRCODE_IO_CANTREAD
;
1690 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
1692 catch ( const ::com::sun::star::uno::Exception
& )
1694 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
1699 if ( pImp
->pTempFile
)
1701 pImp
->pTempFile
->EnableKillingFile( true );
1702 delete pImp
->pTempFile
;
1703 pImp
->pTempFile
= NULL
;
1706 else if ( bTransactStarted
)
1708 UseBackupToRestore_Impl( aOriginalContent
, xDummyEnv
);
1712 pImp
->m_eError
= ERRCODE_IO_CANTREAD
;
1718 //------------------------------------------------------------------
1719 sal_Bool
SfxMedium::TryDirectTransfer( const OUString
& aURL
, SfxItemSet
& aTargetSet
)
1724 // if the document had no password it should be stored without password
1725 // if the document had password it should be stored with the same password
1726 // otherwise the stream copying can not be done
1727 SFX_ITEMSET_ARG( &aTargetSet
, pNewPassItem
, SfxStringItem
, SID_PASSWORD
, false );
1728 SFX_ITEMSET_ARG( GetItemSet(), pOldPassItem
, SfxStringItem
, SID_PASSWORD
, false );
1729 if ( ( !pNewPassItem
&& !pOldPassItem
)
1730 || ( pNewPassItem
&& pOldPassItem
&& pNewPassItem
->GetValue() == pOldPassItem
->GetValue() ) )
1732 // the filter must be the same
1733 SFX_ITEMSET_ARG( &aTargetSet
, pNewFilterItem
, SfxStringItem
, SID_FILTER_NAME
, false );
1734 SFX_ITEMSET_ARG( GetItemSet(), pOldFilterItem
, SfxStringItem
, SID_FILTER_NAME
, false );
1735 if ( pNewFilterItem
&& pOldFilterItem
&& pNewFilterItem
->GetValue() == pOldFilterItem
->GetValue() )
1737 // get the input stream and copy it
1738 // in case of success return true
1739 uno::Reference
< io::XInputStream
> xInStream
= GetInputStream();
1742 if ( xInStream
.is() )
1746 uno::Reference
< io::XSeekable
> xSeek( xInStream
, uno::UNO_QUERY
);
1750 nPos
= xSeek
->getPosition();
1754 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
1755 ::ucbhelper::Content
aTargetContent( aURL
, xEnv
, comphelper::getProcessComponentContext() );
1757 InsertCommandArgument aInsertArg
;
1758 aInsertArg
.Data
= xInStream
;
1759 SFX_ITEMSET_ARG( &aTargetSet
, pRename
, SfxBoolItem
, SID_RENAME
, false );
1760 SFX_ITEMSET_ARG( &aTargetSet
, pOverWrite
, SfxBoolItem
, SID_OVERWRITE
, false );
1761 if ( (pOverWrite
&& !pOverWrite
->GetValue()) // argument says: never overwrite
1762 || (pRename
&& pRename
->GetValue()) ) // argument says: rename file
1763 aInsertArg
.ReplaceExisting
= false;
1765 aInsertArg
.ReplaceExisting
= true; // default is overwrite existing files
1768 aCmdArg
<<= aInsertArg
;
1769 aTargetContent
.executeCommand( OUString( "insert" ),
1773 xSeek
->seek( nPos
);
1777 catch( const uno::Exception
& )
1786 //------------------------------------------------------------------
1787 void SfxMedium::Transfer_Impl()
1789 // The transfer is required only in two cases: either if there is a temporary file or if there is a salvage item
1791 if ( pImp
->pTempFile
)
1792 aNameURL
= pImp
->pTempFile
->GetURL();
1793 else if ( !pImp
->m_aLogicName
.isEmpty() && pImp
->m_bSalvageMode
)
1795 // makes sence only in case logic name is set
1796 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp
->m_aName
, aNameURL
) )
1797 SAL_WARN( "sfx.doc", "The medium name is not convertible!" );
1800 if ( !aNameURL
.isEmpty() && ( !pImp
->m_eError
|| (pImp
->m_eError
& ERRCODE_WARNING_MASK
) ) )
1802 SAL_INFO( "sfx.doc", "sfx2 (mv76033) SfxMedium::Transfer_Impl, copying to target" );
1804 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
1805 Reference
< XOutputStream
> rOutStream
;
1807 // in case an output stream is provided from outside and the URL is correct
1808 // commit to the stream
1809 if (pImp
->m_aLogicName
.startsWith("private:stream"))
1811 // TODO/LATER: support storing to SID_STREAM
1812 SFX_ITEMSET_ARG( pImp
->m_pSet
, pOutStreamItem
, SfxUnoAnyItem
, SID_OUTPUTSTREAM
, false);
1813 if( pOutStreamItem
&& ( pOutStreamItem
->GetValue() >>= rOutStream
) )
1815 if ( pImp
->xStorage
.is() )
1818 CloseStreams_Impl();
1820 INetURLObject
aSource( aNameURL
);
1821 ::ucbhelper::Content aTempCont
;
1822 if( ::ucbhelper::Content::create( aSource
.GetMainURL( INetURLObject::NO_DECODE
), xEnv
, comphelper::getProcessComponentContext(), aTempCont
) )
1827 sal_Int32 nBufferSize
= 32767;
1828 Sequence
< sal_Int8
> aSequence ( nBufferSize
);
1829 Reference
< XInputStream
> aTempInput
= aTempCont
.openStream();
1833 nRead
= aTempInput
->readBytes ( aSequence
, nBufferSize
);
1834 if ( nRead
< nBufferSize
)
1836 Sequence
< sal_Int8
> aTempBuf ( aSequence
.getConstArray(), nRead
);
1837 rOutStream
->writeBytes ( aTempBuf
);
1840 rOutStream
->writeBytes ( aSequence
);
1842 while ( nRead
== nBufferSize
);
1844 // remove temporary file
1845 if ( pImp
->pTempFile
)
1847 pImp
->pTempFile
->EnableKillingFile( true );
1848 delete pImp
->pTempFile
;
1849 pImp
->pTempFile
= NULL
;
1852 catch( const Exception
& )
1858 SAL_WARN( "sfx.doc", "Illegal Output stream parameter!" );
1859 SetError( ERRCODE_IO_GENERAL
, OUString( OSL_LOG_PREFIX
) );
1862 // free the reference
1864 pImp
->m_pSet
->ClearItem( SID_OUTPUTSTREAM
);
1870 if ( !pImp
->aContent
.get().is() )
1872 pImp
->m_eError
= ERRCODE_IO_NOTEXISTS
;
1876 SFX_ITEMSET_ARG( GetItemSet(), pSegmentSize
, SfxInt32Item
, SID_SEGMENTSIZE
, false);
1879 // this file must be stored into a disk spanned package
1882 uno::Reference
< embed::XStorage
> xStor
= comphelper::OStorageHelper::GetStorageFromURL( GetName(),
1883 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
1885 // set segment size property; package will automatically be divided in pieces fitting
1887 ::com::sun::star::uno::Any aAny
;
1888 aAny
<<= pSegmentSize
->GetValue();
1890 uno::Reference
< beans::XPropertySet
> xSet( pImp
->xStorage
, uno::UNO_QUERY
);
1891 xSet
->setPropertyValue("SegmentSize", aAny
);
1893 // copy the temporary storage into the disk spanned package
1894 GetStorage()->copyToStorage( xStor
);
1895 uno::Reference
< embed::XTransactedObject
> xTrans( pImp
->xStorage
, uno::UNO_QUERY
);
1900 catch ( const uno::Exception
& )
1902 //TODO/MBA: error handling
1907 INetURLObject
aDest( GetURLObject() );
1909 // source is the temp file written so far
1910 INetURLObject
aSource( aNameURL
);
1912 // a special case, an interaction handler should be used for
1913 // authentication in case it is available
1914 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
1915 Reference
< ::com::sun::star::task::XInteractionHandler
> xInteractionHandler
= GetInteractionHandler();
1916 if (xInteractionHandler
.is())
1917 xComEnv
= new ::ucbhelper::CommandEnvironment( xInteractionHandler
,
1918 Reference
< ::com::sun::star::ucb::XProgressHandler
>() );
1920 OUString
aDestURL( aDest
.GetMainURL( INetURLObject::NO_DECODE
) );
1922 if ( ::utl::LocalFileHelper::IsLocalFile( aDestURL
) || !aDest
.removeSegment() )
1924 TransactedTransferForFS_Impl( aSource
, aDest
, xComEnv
);
1926 // Hideous - no clean way to do this, so we re-open the file just to fsync it
1927 osl::File
aFile( aDestURL
);
1928 if ( aFile
.open( osl_File_OpenFlag_Write
) == osl::FileBase::E_None
)
1931 SAL_INFO( "sfx.doc", "fsync'd saved file '" << aDestURL
<< "'" );
1937 // create content for the parent folder and call transfer on that content with the source content
1938 // and the destination file name as parameters
1939 ::ucbhelper::Content aSourceContent
;
1940 ::ucbhelper::Content aTransferContent
;
1942 ::ucbhelper::Content aDestContent
;
1943 ::ucbhelper::Content::create( aDestURL
, xComEnv
, comphelper::getProcessComponentContext(), aDestContent
);
1944 // For checkin, we need the object URL, not the parent folder:
1945 if ( !IsInCheckIn( ) )
1947 // Get the parent URL from the XChild if possible: why would the URL necessarily have
1948 // a hierarchical path? It's not always the case for CMIS.
1949 Reference
< ::com::sun::star::container::XChild
> xChild( aDestContent
.get(), uno::UNO_QUERY
);
1950 OUString sParentUrl
;
1953 Reference
< ::com::sun::star::ucb::XContent
> xParent( xChild
->getParent( ), uno::UNO_QUERY
);
1954 if ( xParent
.is( ) )
1956 sParentUrl
= xParent
->getIdentifier( )->getContentIdentifier();
1960 if ( sParentUrl
.isEmpty() )
1961 aDestURL
= aDest
.GetMainURL( INetURLObject::NO_DECODE
);
1962 // adjust to above aDest.removeSegment()
1964 aDestURL
= sParentUrl
;
1967 // LongName wasn't defined anywhere, only used here... get the Title instead
1968 // as it's less probably empty
1970 Any aAny
= aDestContent
.getPropertyValue("Title");
1972 aAny
= aDestContent
.getPropertyValue( OUString("ObjectId" ) );
1975 if ( aFileName
.isEmpty() )
1976 aFileName
= GetURLObject().getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DECODE_WITH_CHARSET
);
1980 aTransferContent
= ::ucbhelper::Content( aDestURL
, xComEnv
, comphelper::getProcessComponentContext() );
1982 catch (const ::com::sun::star::ucb::ContentCreationException
& ex
)
1984 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
1986 (ex
.eError
== ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER
) ||
1987 (ex
.eError
== ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED
)
1990 pImp
->m_eError
= ERRCODE_IO_NOTEXISTSPATH
;
1993 catch (const ::com::sun::star::uno::Exception
&)
1995 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
1998 if ( !pImp
->m_eError
|| (pImp
->m_eError
& ERRCODE_WARNING_MASK
) )
2000 // free resources, otherwise the transfer may fail
2001 if ( pImp
->xStorage
.is() )
2004 CloseStreams_Impl();
2006 ::ucbhelper::Content::create( aSource
.GetMainURL( INetURLObject::NO_DECODE
), xEnv
, comphelper::getProcessComponentContext(), aSourceContent
);
2008 // check for external parameters that may customize the handling of NameClash situations
2009 SFX_ITEMSET_ARG( GetItemSet(), pRename
, SfxBoolItem
, SID_RENAME
, false );
2010 SFX_ITEMSET_ARG( GetItemSet(), pOverWrite
, SfxBoolItem
, SID_OVERWRITE
, false );
2011 sal_Int32 nNameClash
;
2012 if ( pOverWrite
&& !pOverWrite
->GetValue() )
2013 // argument says: never overwrite
2014 nNameClash
= NameClash::ERROR
;
2015 else if ( pRename
&& pRename
->GetValue() )
2016 // argument says: rename file
2017 nNameClash
= NameClash::RENAME
;
2019 // default is overwrite existing files
2020 nNameClash
= NameClash::OVERWRITE
;
2024 OUString aMimeType
= pImp
->getFilterMimeType();
2025 ::ucbhelper::InsertOperation eOperation
= ::ucbhelper::InsertOperation_COPY
;
2026 bool bMajor
= false;
2028 if ( IsInCheckIn( ) )
2030 eOperation
= ::ucbhelper::InsertOperation_CHECKIN
;
2031 SFX_ITEMSET_ARG( GetItemSet(), pMajor
, SfxBoolItem
, SID_DOCINFO_MAJOR
, false );
2032 bMajor
= pMajor
&& pMajor
->GetValue( );
2033 SFX_ITEMSET_ARG( GetItemSet(), pComments
, SfxStringItem
, SID_DOCINFO_COMMENTS
, false );
2035 sComment
= pComments
->GetValue( );
2037 OUString sResultURL
;
2038 if (!aTransferContent
.transferContent( aSourceContent
, eOperation
,
2039 aFileName
, nNameClash
, aMimeType
, bMajor
, sComment
, &sResultURL
, sObjectId
))
2040 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
2041 else if ( !sResultURL
.isEmpty( ) ) // Likely to happen only for checkin
2042 SwitchDocumentToFile( sResultURL
);
2044 catch ( const ::com::sun::star::ucb::CommandAbortedException
& )
2046 pImp
->m_eError
= ERRCODE_ABORT
;
2048 catch ( const ::com::sun::star::ucb::CommandFailedException
& )
2050 pImp
->m_eError
= ERRCODE_ABORT
;
2052 catch ( const ::com::sun::star::ucb::InteractiveIOException
& r
)
2054 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
)
2055 pImp
->m_eError
= ERRCODE_IO_ACCESSDENIED
;
2056 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
2057 pImp
->m_eError
= ERRCODE_IO_NOTEXISTS
;
2058 else if ( r
.Code
== IOErrorCode_CANT_READ
)
2059 pImp
->m_eError
= ERRCODE_IO_CANTREAD
;
2061 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
2063 catch ( const ::com::sun::star::uno::Exception
& )
2065 pImp
->m_eError
= ERRCODE_IO_GENERAL
;
2068 // do not switch from temporary file in case of nonfile protocol
2072 if ( ( !pImp
->m_eError
|| (pImp
->m_eError
& ERRCODE_WARNING_MASK
) ) && !pImp
->pTempFile
)
2074 // without a TempFile the physical and logical name should be the same after successful transfer
2075 ::utl::LocalFileHelper::ConvertURLToPhysicalName(
2076 GetURLObject().GetMainURL( INetURLObject::NO_DECODE
), pImp
->m_aName
);
2077 pImp
->m_bSalvageMode
= false;
2082 //------------------------------------------------------------------
2083 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content
& aOriginalContent
,
2084 const OUString
& aPrefix
,
2085 const OUString
& aExtension
,
2086 const OUString
& aDestDir
)
2088 SAL_INFO( "sfx.doc", "sfx2 (mv76033) SfxMedium::DoInternalBackup_Impl( with destdir )" );
2090 if ( !pImp
->m_aBackupURL
.isEmpty() )
2091 return; // the backup was done already
2093 ::utl::TempFile
aTransactTemp( aPrefix
, &aExtension
, &aDestDir
);
2094 aTransactTemp
.EnableKillingFile( false );
2096 INetURLObject
aBackObj( aTransactTemp
.GetURL() );
2097 OUString aBackupName
= aBackObj
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DECODE_WITH_CHARSET
);
2099 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xDummyEnv
;
2100 ::ucbhelper::Content aBackupCont
;
2101 if( ::ucbhelper::Content::create( aDestDir
, xDummyEnv
, comphelper::getProcessComponentContext(), aBackupCont
) )
2105 OUString sMimeType
= pImp
->getFilterMimeType();
2106 if( aBackupCont
.transferContent( aOriginalContent
,
2107 ::ucbhelper::InsertOperation_COPY
,
2109 NameClash::OVERWRITE
,
2112 pImp
->m_aBackupURL
= aBackObj
.GetMainURL( INetURLObject::NO_DECODE
);
2113 pImp
->m_bRemoveBackup
= true;
2116 catch( const Exception
& )
2120 if ( pImp
->m_aBackupURL
.isEmpty() )
2121 aTransactTemp
.EnableKillingFile( true );
2124 //------------------------------------------------------------------
2125 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content
& aOriginalContent
)
2127 if ( !pImp
->m_aBackupURL
.isEmpty() )
2128 return; // the backup was done already
2130 OUString aFileName
= GetURLObject().getName( INetURLObject::LAST_SEGMENT
,
2132 INetURLObject::NO_DECODE
);
2134 sal_Int32 nPrefixLen
= aFileName
.lastIndexOf( '.' );
2135 OUString aPrefix
= ( nPrefixLen
== -1 ) ? aFileName
: aFileName
.copy( 0, nPrefixLen
);
2136 OUString aExtension
= ( nPrefixLen
== -1 ) ? OUString() : aFileName
.copy( nPrefixLen
);
2137 OUString aBakDir
= SvtPathOptions().GetBackupPath();
2139 // create content for the parent folder ( = backup folder )
2140 ::ucbhelper::Content aContent
;
2141 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
2142 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv
, aBakDir
, aContent
) )
2143 DoInternalBackup_Impl( aOriginalContent
, aPrefix
, aExtension
, aBakDir
);
2145 if ( pImp
->m_aBackupURL
.isEmpty() )
2147 // the copiing to the backup catalog failed ( for example because
2148 // of using an encrypted partition as target catalog )
2149 // since the user did not specify to make backup explicitly
2150 // office should try to make backup in another place,
2151 // target catalog does not look bad for this case ( and looks
2152 // to be the only way for encrypted partitions )
2154 INetURLObject aDest
= GetURLObject();
2155 if ( aDest
.removeSegment() )
2156 DoInternalBackup_Impl( aOriginalContent
, aPrefix
, aExtension
, aDest
.GetMainURL( INetURLObject::NO_DECODE
) );
2161 //------------------------------------------------------------------
2162 void SfxMedium::DoBackup_Impl()
2164 SAL_INFO( "sfx.doc", "sfx2 (mv76033) SfxMedium::DoBackup_Impl" );
2166 // source file name is the logical name of this medium
2167 INetURLObject
aSource( GetURLObject() );
2169 // there is nothing to backup in case source file does not exist
2170 if ( !::utl::UCBContentHelper::IsDocument( aSource
.GetMainURL( INetURLObject::NO_DECODE
) ) )
2173 bool bSuccess
= false;
2175 // get path for backups
2176 OUString aBakDir
= SvtPathOptions().GetBackupPath();
2177 if( !aBakDir
.isEmpty() )
2179 // create content for the parent folder ( = backup folder )
2180 ::ucbhelper::Content aContent
;
2181 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
2182 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv
, aBakDir
, aContent
) )
2184 // save as ".bak" file
2185 INetURLObject
aDest( aBakDir
);
2186 aDest
.insertName( aSource
.getName() );
2187 aDest
.setExtension( "bak" );
2188 OUString aFileName
= aDest
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DECODE_WITH_CHARSET
);
2190 // create a content for the source file
2191 ::ucbhelper::Content aSourceContent
;
2192 if ( ::ucbhelper::Content::create( aSource
.GetMainURL( INetURLObject::NO_DECODE
), xEnv
, comphelper::getProcessComponentContext(), aSourceContent
) )
2196 // do the transfer ( copy source file to backup dir )
2197 OUString sMimeType
= pImp
->getFilterMimeType();
2198 bSuccess
= aContent
.transferContent( aSourceContent
,
2199 ::ucbhelper::InsertOperation_COPY
,
2201 NameClash::OVERWRITE
,
2205 pImp
->m_aBackupURL
= aDest
.GetMainURL( INetURLObject::NO_DECODE
);
2206 pImp
->m_bRemoveBackup
= false;
2209 catch ( const ::com::sun::star::uno::Exception
& )
2218 pImp
->m_eError
= ERRCODE_SFX_CANTCREATEBACKUP
;
2222 //------------------------------------------------------------------
2223 void SfxMedium::ClearBackup_Impl()
2225 if( pImp
->m_bRemoveBackup
)
2227 // currently a document is always stored in a new medium,
2228 // thus if a backup can not be removed the backup URL should not be cleaned
2229 if ( !pImp
->m_aBackupURL
.isEmpty() )
2231 if ( ::utl::UCBContentHelper::Kill( pImp
->m_aBackupURL
) )
2233 pImp
->m_bRemoveBackup
= false;
2234 pImp
->m_aBackupURL
= "";
2239 SAL_WARN( "sfx.doc", "Couldn't remove backup file!");
2244 pImp
->m_aBackupURL
= "";
2247 //----------------------------------------------------------------
2248 void SfxMedium::GetLockingStream_Impl()
2250 if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) )
2251 && !pImp
->m_xLockingStream
.is() )
2253 SFX_ITEMSET_ARG( pImp
->m_pSet
, pWriteStreamItem
, SfxUnoAnyItem
, SID_STREAM
, false);
2254 if ( pWriteStreamItem
)
2255 pWriteStreamItem
->GetValue() >>= pImp
->m_xLockingStream
;
2257 if ( !pImp
->m_xLockingStream
.is() )
2259 // open the original document
2260 uno::Sequence
< beans::PropertyValue
> xProps
;
2261 TransformItems( SID_OPENDOC
, *GetItemSet(), xProps
);
2262 utl::MediaDescriptor
aMedium( xProps
);
2264 aMedium
.addInputStreamOwnLock();
2266 uno::Reference
< io::XInputStream
> xInputStream
;
2267 aMedium
[utl::MediaDescriptor::PROP_STREAM()] >>= pImp
->m_xLockingStream
;
2268 aMedium
[utl::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream
;
2270 if ( !pImp
->pTempFile
&& pImp
->m_aName
.isEmpty() )
2272 // the medium is still based on the original file, it makes sence to initialize the streams
2273 if ( pImp
->m_xLockingStream
.is() )
2274 pImp
->xStream
= pImp
->m_xLockingStream
;
2276 if ( xInputStream
.is() )
2277 pImp
->xInputStream
= xInputStream
;
2279 if ( !pImp
->xInputStream
.is() && pImp
->xStream
.is() )
2280 pImp
->xInputStream
= pImp
->xStream
->getInputStream();
2286 //----------------------------------------------------------------
2287 void SfxMedium::GetMedium_Impl()
2289 if ( !pImp
->m_pInStream
)
2291 pImp
->bDownloadDone
= false;
2292 Reference
< ::com::sun::star::task::XInteractionHandler
> xInteractionHandler
= GetInteractionHandler();
2294 //TODO/MBA: need support for SID_STREAM
2295 SFX_ITEMSET_ARG( pImp
->m_pSet
, pWriteStreamItem
, SfxUnoAnyItem
, SID_STREAM
, false);
2296 SFX_ITEMSET_ARG( pImp
->m_pSet
, pInStreamItem
, SfxUnoAnyItem
, SID_INPUTSTREAM
, false);
2297 if ( pWriteStreamItem
)
2299 pWriteStreamItem
->GetValue() >>= pImp
->xStream
;
2301 if ( pInStreamItem
)
2302 pInStreamItem
->GetValue() >>= pImp
->xInputStream
;
2304 if ( !pImp
->xInputStream
.is() && pImp
->xStream
.is() )
2305 pImp
->xInputStream
= pImp
->xStream
->getInputStream();
2307 else if ( pInStreamItem
)
2309 pInStreamItem
->GetValue() >>= pImp
->xInputStream
;
2313 uno::Sequence
< beans::PropertyValue
> xProps
;
2315 if (!pImp
->m_aName
.isEmpty())
2317 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp
->m_aName
, aFileName
) )
2319 SAL_WARN( "sfx.doc", "Physical name not convertible!");
2323 aFileName
= GetName();
2325 // in case the temporary file exists the streams should be initialized from it,
2326 // but the original MediaDescriptor should not be changed
2327 bool bFromTempFile
= ( pImp
->pTempFile
!= NULL
);
2329 if ( !bFromTempFile
)
2331 GetItemSet()->Put( SfxStringItem( SID_FILE_NAME
, aFileName
) );
2332 if( !(pImp
->m_nStorOpenMode
& STREAM_WRITE
) )
2333 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
2334 if (xInteractionHandler
.is())
2335 GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER
, makeAny(xInteractionHandler
) ) );
2338 if ( pImp
->m_xInputStreamToLoadFrom
.is() )
2340 pImp
->xInputStream
= pImp
->m_xInputStreamToLoadFrom
;
2341 pImp
->xInputStream
->skipBytes(0);
2342 if (pImp
->m_bInputStreamIsReadOnly
)
2343 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
2347 TransformItems( SID_OPENDOC
, *GetItemSet(), xProps
);
2348 utl::MediaDescriptor
aMedium( xProps
);
2350 if ( pImp
->m_xLockingStream
.is() && !bFromTempFile
)
2352 // the medium is not based on the temporary file, so the original stream can be used
2353 pImp
->xStream
= pImp
->m_xLockingStream
;
2357 if ( bFromTempFile
)
2359 aMedium
[utl::MediaDescriptor::PROP_URL()] <<= OUString( aFileName
);
2360 aMedium
.erase( utl::MediaDescriptor::PROP_READONLY() );
2361 aMedium
.addInputStream();
2363 else if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) ) )
2365 // use the special locking approach only for file URLs
2366 aMedium
.addInputStreamOwnLock();
2369 aMedium
.addInputStream();
2371 // the ReadOnly property set in aMedium is ignored
2372 // the check is done in LockOrigFileOnDemand() for file and non-file URLs
2374 //TODO/MBA: what happens if property is not there?!
2375 aMedium
[utl::MediaDescriptor::PROP_STREAM()] >>= pImp
->xStream
;
2376 aMedium
[utl::MediaDescriptor::PROP_INPUTSTREAM()] >>= pImp
->xInputStream
;
2380 if ( !pImp
->xInputStream
.is() && pImp
->xStream
.is() )
2381 pImp
->xInputStream
= pImp
->xStream
->getInputStream();
2384 if ( !bFromTempFile
)
2386 //TODO/MBA: need support for SID_STREAM
2387 if ( pImp
->xStream
.is() )
2388 GetItemSet()->Put( SfxUsrAnyItem( SID_STREAM
, makeAny( pImp
->xStream
) ) );
2390 GetItemSet()->Put( SfxUsrAnyItem( SID_INPUTSTREAM
, makeAny( pImp
->xInputStream
) ) );
2394 //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor
2395 if ( !GetError() && !pImp
->xStream
.is() && !pImp
->xInputStream
.is() )
2396 SetError( ERRCODE_IO_ACCESSDENIED
, OUString( OSL_LOG_PREFIX
) );
2400 if ( pImp
->xStream
.is() )
2401 pImp
->m_pInStream
= utl::UcbStreamHelper::CreateStream( pImp
->xStream
);
2402 else if ( pImp
->xInputStream
.is() )
2403 pImp
->m_pInStream
= utl::UcbStreamHelper::CreateStream( pImp
->xInputStream
);
2406 pImp
->bDownloadDone
= true;
2407 pImp
->aDoneLink
.ClearPendingCall();
2408 sal_uIntPtr nError
= GetError();
2409 pImp
->aDoneLink
.Call( (void*)nError
);
2413 //----------------------------------------------------------------
2414 sal_Bool
SfxMedium::IsRemote()
2416 return pImp
->m_bRemote
;
2419 //------------------------------------------------------------------
2421 void SfxMedium::SetUpdatePickList(sal_Bool bVal
)
2423 pImp
->bUpdatePickList
= bVal
;
2425 //------------------------------------------------------------------
2427 sal_Bool
SfxMedium::IsUpdatePickList() const
2429 return pImp
->bUpdatePickList
;
2432 void SfxMedium::SetLongName(const OUString
&rName
)
2434 pImp
->m_aLongName
= rName
;
2437 const OUString
& SfxMedium::GetLongName() const
2439 return pImp
->m_aLongName
;
2442 void SfxMedium::SetDoneLink( const Link
& rLink
)
2444 pImp
->aDoneLink
= rLink
;
2447 void SfxMedium::DownLoad( const Link
& aLink
)
2449 SetDoneLink( aLink
);
2451 if ( pImp
->m_pInStream
&& !aLink
.IsSet() )
2453 while( !pImp
->bDownloadDone
)
2454 Application::Yield();
2458 //------------------------------------------------------------------
2459 void SfxMedium::Init_Impl()
2461 Includes a valid:: sun:: com:: star:: util:: URL (If a file name was
2462 previously in there) in the logical name and if available sets the
2463 physical name as the file name.
2467 Reference
< XOutputStream
> rOutStream
;
2469 // TODO/LATER: handle lifetime of storages
2470 pImp
->bDisposeStorage
= false;
2472 SFX_ITEMSET_ARG( pImp
->m_pSet
, pSalvageItem
, SfxStringItem
, SID_DOC_SALVAGE
, false);
2473 if ( pSalvageItem
&& pSalvageItem
->GetValue().isEmpty() )
2475 pSalvageItem
= NULL
;
2476 pImp
->m_pSet
->ClearItem( SID_DOC_SALVAGE
);
2479 if (!pImp
->m_aLogicName
.isEmpty())
2481 INetURLObject
aUrl( pImp
->m_aLogicName
);
2482 INetProtocol eProt
= aUrl
.GetProtocol();
2483 if ( eProt
== INET_PROT_NOT_VALID
)
2485 SAL_WARN( "sfx.doc", "Unknown protocol!" );
2489 if ( aUrl
.HasMark() )
2491 pImp
->m_aLogicName
= aUrl
.GetURLNoMark( INetURLObject::NO_DECODE
);
2492 GetItemSet()->Put( SfxStringItem( SID_JUMPMARK
, aUrl
.GetMark() ) );
2495 // try to convert the URL into a physical name - but never change a physical name
2496 // physical name may be set if the logical name is changed after construction
2497 if ( pImp
->m_aName
.isEmpty() )
2498 ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
), pImp
->m_aName
);
2501 DBG_ASSERT( pSalvageItem
, "Suspicious change of logical name!" );
2506 if ( pSalvageItem
&& !pSalvageItem
->GetValue().isEmpty() )
2508 pImp
->m_aLogicName
= pSalvageItem
->GetValue();
2509 DELETEZ( pImp
->m_pURLObj
);
2510 pImp
->m_bSalvageMode
= true;
2513 // in case output stream is by mistake here
2514 // clear the reference
2515 SFX_ITEMSET_ARG( pImp
->m_pSet
, pOutStreamItem
, SfxUnoAnyItem
, SID_OUTPUTSTREAM
, false);
2517 && ( !( pOutStreamItem
->GetValue() >>= rOutStream
)
2518 || !pImp
->m_aLogicName
.startsWith("private:stream")) )
2520 pImp
->m_pSet
->ClearItem( SID_OUTPUTSTREAM
);
2521 SAL_WARN( "sfx.doc", "Unexpected Output stream parameter!\n" );
2524 if (!pImp
->m_aLogicName
.isEmpty())
2526 // if the logic name is set it should be set in MediaDescriptor as well
2527 SFX_ITEMSET_ARG( pImp
->m_pSet
, pFileNameItem
, SfxStringItem
, SID_FILE_NAME
, false );
2528 if ( !pFileNameItem
)
2530 // let the ItemSet be created if necessary
2533 SID_FILE_NAME
, INetURLObject( pImp
->m_aLogicName
).GetMainURL( INetURLObject::NO_DECODE
) ) );
2540 //------------------------------------------------------------------
2541 SfxMedium::SfxMedium() : pImp(new SfxMedium_Impl(this))
2546 //------------------------------------------------------------------
2548 void SfxMedium::UseInteractionHandler( sal_Bool bUse
)
2550 pImp
->bAllowDefaultIntHdl
= bUse
;
2553 //------------------------------------------------------------------
2555 ::com::sun::star::uno::Reference
< ::com::sun::star::task::XInteractionHandler
>
2556 SfxMedium::GetInteractionHandler()
2558 // if interaction isnt allowed explicitly ... return empty reference!
2559 if ( !pImp
->bUseInteractionHandler
)
2560 return ::com::sun::star::uno::Reference
< ::com::sun::star::task::XInteractionHandler
>();
2562 // search a possible existing handler inside cached item set
2565 ::com::sun::star::uno::Reference
< ::com::sun::star::task::XInteractionHandler
> xHandler
;
2566 SFX_ITEMSET_ARG( pImp
->m_pSet
, pHandler
, SfxUnoAnyItem
, SID_INTERACTIONHANDLER
, false);
2567 if ( pHandler
&& (pHandler
->GetValue() >>= xHandler
) && xHandler
.is() )
2571 // if default interaction isnt allowed explicitly ... return empty reference!
2572 if ( !pImp
->bAllowDefaultIntHdl
)
2573 return ::com::sun::star::uno::Reference
< ::com::sun::star::task::XInteractionHandler
>();
2575 // otherwise return cached default handler ... if it exist.
2576 if ( pImp
->xInteraction
.is() )
2577 return pImp
->xInteraction
;
2579 // create default handler and cache it!
2580 Reference
< uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2581 pImp
->xInteraction
.set(
2582 task::InteractionHandler::createWithParent(xContext
, 0), UNO_QUERY_THROW
);
2583 return pImp
->xInteraction
;
2586 //----------------------------------------------------------------
2588 void SfxMedium::SetFilter( const SfxFilter
* pFilterP
, sal_Bool
/*bResetOrig*/ )
2590 pImp
->m_pFilter
= pFilterP
;
2593 const SfxFilter
* SfxMedium::GetFilter() const
2595 return pImp
->m_pFilter
;
2598 //----------------------------------------------------------------
2600 const SfxFilter
* SfxMedium::GetOrigFilter( sal_Bool bNotCurrent
) const
2602 return ( pImp
->pOrigFilter
|| bNotCurrent
) ? pImp
->pOrigFilter
: pImp
->m_pFilter
;
2605 //----------------------------------------------------------------
2607 sal_uInt32
SfxMedium::CreatePasswordToModifyHash( const OUString
& aPasswd
, sal_Bool bWriter
)
2609 sal_uInt32 nHash
= 0;
2611 if ( !aPasswd
.isEmpty() )
2615 nHash
= ::comphelper::DocPasswordHelper::GetWordHashAsUINT32( aPasswd
);
2619 rtl_TextEncoding nEncoding
= osl_getThreadTextEncoding();
2620 nHash
= ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd
, nEncoding
);
2627 //------------------------------------------------------------------
2629 void SfxMedium::Close()
2631 if ( pImp
->xStorage
.is() )
2636 CloseStreams_Impl();
2638 UnlockFile( false );
2641 void SfxMedium::CloseAndRelease()
2643 if ( pImp
->xStorage
.is() )
2648 CloseAndReleaseStreams_Impl();
2653 void SfxMedium::UnlockFile( sal_Bool bReleaseLockStream
)
2655 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
2656 (void) bReleaseLockStream
;
2658 if ( pImp
->m_xLockingStream
.is() )
2660 if ( bReleaseLockStream
)
2664 uno::Reference
< io::XInputStream
> xInStream
= pImp
->m_xLockingStream
->getInputStream();
2665 uno::Reference
< io::XOutputStream
> xOutStream
= pImp
->m_xLockingStream
->getOutputStream();
2666 if ( xInStream
.is() )
2667 xInStream
->closeInput();
2668 if ( xOutStream
.is() )
2669 xOutStream
->closeOutput();
2671 catch( const uno::Exception
& )
2675 pImp
->m_xLockingStream
.clear();
2678 if ( pImp
->m_bLocked
)
2682 pImp
->m_bLocked
= false;
2683 ::svt::DocumentLockFile
aLockFile( pImp
->m_aLogicName
);
2684 // TODO/LATER: A warning could be shown in case the file is not the own one
2685 aLockFile
.RemoveFile();
2687 catch( const uno::Exception
& )
2693 void SfxMedium::CloseAndReleaseStreams_Impl()
2695 CloseZipStorage_Impl();
2697 uno::Reference
< io::XInputStream
> xInToClose
= pImp
->xInputStream
;
2698 uno::Reference
< io::XOutputStream
> xOutToClose
;
2699 if ( pImp
->xStream
.is() )
2701 xOutToClose
= pImp
->xStream
->getOutputStream();
2703 // if the locking stream is closed here the related member should be cleaned
2704 if ( pImp
->xStream
== pImp
->m_xLockingStream
)
2705 pImp
->m_xLockingStream
.clear();
2708 // The probably exsisting SvStream wrappers should be closed first
2709 CloseStreams_Impl();
2711 // in case of salvage mode the storage is based on the streams
2712 if ( !pImp
->m_bSalvageMode
)
2716 if ( xInToClose
.is() )
2717 xInToClose
->closeInput();
2718 if ( xOutToClose
.is() )
2719 xOutToClose
->closeOutput();
2721 catch ( const uno::Exception
& )
2727 //------------------------------------------------------------------
2728 void SfxMedium::CloseStreams_Impl()
2730 CloseInStream_Impl();
2731 CloseOutStream_Impl();
2734 pImp
->m_pSet
->ClearItem( SID_CONTENT
);
2736 pImp
->aContent
= ::ucbhelper::Content();
2739 //------------------------------------------------------------------
2741 void SfxMedium::SetIsRemote_Impl()
2743 INetURLObject
aObj( GetName() );
2744 switch( aObj
.GetProtocol() )
2747 case INET_PROT_HTTP
:
2748 case INET_PROT_HTTPS
:
2749 case INET_PROT_POP3
:
2750 case INET_PROT_NEWS
:
2751 case INET_PROT_IMAP
:
2753 pImp
->m_bRemote
= true;
2756 pImp
->m_bRemote
= GetName().startsWith("private:msgid");
2760 // As files that are written to the remote transmission must also be able
2762 if (pImp
->m_bRemote
)
2763 pImp
->m_nStorOpenMode
|= STREAM_READ
;
2768 void SfxMedium::SetName( const OUString
& aNameP
, sal_Bool bSetOrigURL
)
2770 if (pImp
->aOrigURL
.isEmpty())
2771 pImp
->aOrigURL
= pImp
->m_aLogicName
;
2773 pImp
->aOrigURL
= aNameP
;
2774 pImp
->m_aLogicName
= aNameP
;
2775 DELETEZ( pImp
->m_pURLObj
);
2776 pImp
->aContent
= ::ucbhelper::Content();
2780 //----------------------------------------------------------------
2781 const OUString
& SfxMedium::GetOrigURL() const
2783 return pImp
->aOrigURL
.isEmpty() ? pImp
->m_aLogicName
: pImp
->aOrigURL
;
2786 //----------------------------------------------------------------
2788 void SfxMedium::SetPhysicalName_Impl( const OUString
& rNameP
)
2790 if ( rNameP
!= pImp
->m_aName
)
2792 if( pImp
->pTempFile
)
2794 delete pImp
->pTempFile
;
2795 pImp
->pTempFile
= NULL
;
2798 if ( !pImp
->m_aName
.isEmpty() || !rNameP
.isEmpty() )
2799 pImp
->aContent
= ::ucbhelper::Content();
2801 pImp
->m_aName
= rNameP
;
2802 pImp
->m_bTriedStorage
= false;
2803 pImp
->bIsStorage
= false;
2807 //------------------------------------------------------------------
2809 void SfxMedium::ReOpen()
2811 bool bUseInteractionHandler
= pImp
->bUseInteractionHandler
;
2812 pImp
->bUseInteractionHandler
= false;
2814 pImp
->bUseInteractionHandler
= bUseInteractionHandler
;
2817 //------------------------------------------------------------------
2819 void SfxMedium::CompleteReOpen()
2821 // do not use temporary file for reopen and in case of success throw the temporary file away
2822 bool bUseInteractionHandler
= pImp
->bUseInteractionHandler
;
2823 pImp
->bUseInteractionHandler
= false;
2825 ::utl::TempFile
* pTmpFile
= NULL
;
2826 if ( pImp
->pTempFile
)
2828 pTmpFile
= pImp
->pTempFile
;
2829 pImp
->pTempFile
= NULL
;
2837 if ( pImp
->pTempFile
)
2839 pImp
->pTempFile
->EnableKillingFile( true );
2840 delete pImp
->pTempFile
;
2842 pImp
->pTempFile
= pTmpFile
;
2843 if ( pImp
->pTempFile
)
2844 pImp
->m_aName
= pImp
->pTempFile
->GetFileName();
2848 pTmpFile
->EnableKillingFile( true );
2853 pImp
->bUseInteractionHandler
= bUseInteractionHandler
;
2856 SfxMedium::SfxMedium(const OUString
&rName
, StreamMode nOpenMode
, const SfxFilter
*pFlt
, SfxItemSet
*pInSet
) :
2857 pImp(new SfxMedium_Impl(this))
2859 pImp
->m_pSet
= pInSet
;
2860 pImp
->m_pFilter
= pFlt
;
2861 pImp
->m_aLogicName
= rName
;
2862 pImp
->m_nStorOpenMode
= nOpenMode
;
2866 SfxMedium::SfxMedium(const OUString
&rName
, const OUString
&rReferer
, StreamMode nOpenMode
, const SfxFilter
*pFlt
, SfxItemSet
*pInSet
) :
2867 pImp(new SfxMedium_Impl(this))
2869 pImp
->m_pSet
= pInSet
;
2870 SfxItemSet
* s
= GetItemSet();
2871 if (s
->GetItem(SID_REFERER
) == 0) {
2872 s
->Put(SfxStringItem(SID_REFERER
, rReferer
));
2874 pImp
->m_pFilter
= pFlt
;
2875 pImp
->m_aLogicName
= rName
;
2876 pImp
->m_nStorOpenMode
= nOpenMode
;
2880 SfxMedium::SfxMedium( const uno::Sequence
<beans::PropertyValue
>& aArgs
) :
2881 pImp(new SfxMedium_Impl(this))
2883 SfxAllItemSet
*pParams
= new SfxAllItemSet( SFX_APP()->GetPool() );
2884 pImp
->m_pSet
= pParams
;
2885 TransformParameters( SID_OPENDOC
, aArgs
, *pParams
);
2887 OUString aFilterProvider
, aFilterName
;
2889 const SfxPoolItem
* pItem
= NULL
;
2890 if (pImp
->m_pSet
->HasItem(SID_FILTER_PROVIDER
, &pItem
))
2891 aFilterProvider
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
2893 if (pImp
->m_pSet
->HasItem(SID_FILTER_NAME
, &pItem
))
2894 aFilterName
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
2897 if (aFilterProvider
.isEmpty())
2899 // This is a conventional filter type.
2900 pImp
->m_pFilter
= SFX_APP()->GetFilterMatcher().GetFilter4FilterName( aFilterName
);
2904 // This filter is from an external provider such as orcus.
2905 pImp
->m_pCustomFilter
.reset(new SfxFilter(aFilterProvider
, aFilterName
));
2906 pImp
->m_pFilter
= pImp
->m_pCustomFilter
.get();
2909 SFX_ITEMSET_ARG( pImp
->m_pSet
, pSalvageItem
, SfxStringItem
, SID_DOC_SALVAGE
, false );
2912 // QUESTION: there is some treatment of Salvage in Init_Impl; align!
2913 if ( !pSalvageItem
->GetValue().isEmpty() )
2915 // if an URL is provided in SalvageItem that means that the FileName refers to a temporary file
2916 // that must be copied here
2918 SFX_ITEMSET_ARG( pImp
->m_pSet
, pFileNameItem
, SfxStringItem
, SID_FILE_NAME
, false );
2919 if (!pFileNameItem
) throw uno::RuntimeException();
2920 OUString aNewTempFileURL
= SfxMedium::CreateTempCopyWithExt( pFileNameItem
->GetValue() );
2921 if ( !aNewTempFileURL
.isEmpty() )
2923 pImp
->m_pSet
->Put( SfxStringItem( SID_FILE_NAME
, aNewTempFileURL
) );
2924 pImp
->m_pSet
->ClearItem( SID_INPUTSTREAM
);
2925 pImp
->m_pSet
->ClearItem( SID_STREAM
);
2926 pImp
->m_pSet
->ClearItem( SID_CONTENT
);
2930 SAL_WARN( "sfx.doc", "Can not create a new temporary file for crash recovery!\n" );
2935 SFX_ITEMSET_ARG( pImp
->m_pSet
, pReadOnlyItem
, SfxBoolItem
, SID_DOC_READONLY
, false );
2936 if ( pReadOnlyItem
&& pReadOnlyItem
->GetValue() )
2937 pImp
->m_bOriginallyReadOnly
= true;
2939 SFX_ITEMSET_ARG( pImp
->m_pSet
, pFileNameItem
, SfxStringItem
, SID_FILE_NAME
, false );
2940 if (!pFileNameItem
) throw uno::RuntimeException();
2941 pImp
->m_aLogicName
= pFileNameItem
->GetValue();
2942 pImp
->m_nStorOpenMode
= pImp
->m_bOriginallyReadOnly
? SFX_STREAM_READONLY
: SFX_STREAM_READWRITE
;
2947 //------------------------------------------------------------------
2949 SfxMedium::SfxMedium( const uno::Reference
< embed::XStorage
>& rStor
, const OUString
& rBaseURL
, const SfxItemSet
* p
) :
2950 pImp(new SfxMedium_Impl(this))
2952 OUString aType
= SfxFilter::GetTypeFromStorage(rStor
);
2953 pImp
->m_pFilter
= SFX_APP()->GetFilterMatcher().GetFilter4EA( aType
);
2954 DBG_ASSERT( pImp
->m_pFilter
, "No Filter for storage found!" );
2957 pImp
->xStorage
= rStor
;
2958 pImp
->bDisposeStorage
= false;
2960 // always take BaseURL first, could be overwritten by ItemSet
2961 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL
, rBaseURL
) );
2963 GetItemSet()->Put( *p
);
2966 //------------------------------------------------------------------
2968 SfxMedium::SfxMedium( const uno::Reference
< embed::XStorage
>& rStor
, const OUString
& rBaseURL
, const OUString
&rTypeName
, const SfxItemSet
* p
) :
2969 pImp(new SfxMedium_Impl(this))
2971 pImp
->m_pFilter
= SFX_APP()->GetFilterMatcher().GetFilter4EA( rTypeName
);
2972 DBG_ASSERT( pImp
->m_pFilter
, "No Filter for storage found!" );
2975 pImp
->xStorage
= rStor
;
2976 pImp
->bDisposeStorage
= false;
2978 // always take BaseURL first, could be overwritten by ItemSet
2979 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL
, rBaseURL
) );
2981 GetItemSet()->Put( *p
);
2984 //------------------------------------------------------------------
2986 SfxMedium::~SfxMedium()
2988 // if there is a requirement to clean the backup this is the last possibility to do it
2993 if( pImp
->bIsTemp
&& !pImp
->m_aName
.isEmpty() )
2996 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp
->m_aName
, aTemp
))
2998 SAL_WARN( "sfx.doc", "Physical name not convertible!");
3001 if ( !::utl::UCBContentHelper::Kill( aTemp
) )
3003 SAL_WARN( "sfx.doc", "Couldn't remove temporary file!");
3010 const OUString
& SfxMedium::GetName() const
3012 return pImp
->m_aLogicName
;
3015 const INetURLObject
& SfxMedium::GetURLObject() const
3017 if (!pImp
->m_pURLObj
)
3019 pImp
->m_pURLObj
= new INetURLObject( pImp
->m_aLogicName
);
3020 pImp
->m_pURLObj
->SetMark("");
3023 return *pImp
->m_pURLObj
;
3026 void SfxMedium::SetExpired_Impl( const DateTime
& rDateTime
)
3028 pImp
->aExpireTime
= rDateTime
;
3030 //----------------------------------------------------------------
3032 sal_Bool
SfxMedium::IsExpired() const
3034 return pImp
->aExpireTime
.IsValidAndGregorian() && pImp
->aExpireTime
< DateTime( DateTime::SYSTEM
);
3036 //----------------------------------------------------------------
3038 void SfxMedium::ForceSynchronStream_Impl( sal_Bool bForce
)
3040 if( pImp
->m_pInStream
)
3042 SvLockBytes
* pBytes
= pImp
->m_pInStream
->GetLockBytes();
3044 pBytes
->SetSynchronMode( bForce
);
3048 //----------------------------------------------------------------
3049 SfxFrame
* SfxMedium::GetLoadTargetFrame() const
3051 return pImp
->wLoadTargetFrame
;
3054 void SfxMedium::setStreamToLoadFrom(const com::sun::star::uno::Reference
<com::sun::star::io::XInputStream
>& xInputStream
,sal_Bool bIsReadOnly
)
3056 pImp
->m_xInputStreamToLoadFrom
= xInputStream
;
3057 pImp
->m_bInputStreamIsReadOnly
= bIsReadOnly
;
3060 void SfxMedium::SetLoadTargetFrame(SfxFrame
* pFrame
)
3062 pImp
->wLoadTargetFrame
= pFrame
;
3064 //----------------------------------------------------------------
3066 void SfxMedium::SetStorage_Impl( const uno::Reference
< embed::XStorage
>& rStor
)
3068 pImp
->xStorage
= rStor
;
3070 //----------------------------------------------------------------
3072 SfxItemSet
* SfxMedium::GetItemSet() const
3074 // this method *must* return an ItemSet, returning NULL can cause crashes
3076 pImp
->m_pSet
= new SfxAllItemSet( SFX_APP()->GetPool() );
3077 return pImp
->m_pSet
;
3079 //----------------------------------------------------------------
3081 SvKeyValueIterator
* SfxMedium::GetHeaderAttributes_Impl()
3083 if( !pImp
->xAttributes
.Is() )
3085 pImp
->xAttributes
= SvKeyValueIteratorRef( new SvKeyValueIterator
);
3087 if ( GetContent().is() )
3091 Any aAny
= pImp
->aContent
.getPropertyValue("MediaType");
3092 OUString aContentType
;
3093 aAny
>>= aContentType
;
3095 pImp
->xAttributes
->Append( SvKeyValue( OUString("content-type"), aContentType
) );
3097 catch ( const ::com::sun::star::uno::Exception
& )
3103 return pImp
->xAttributes
;
3106 ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> SfxMedium::GetInputStream()
3108 if ( !pImp
->xInputStream
.is() )
3110 return pImp
->xInputStream
;
3113 const uno::Sequence
< util::RevisionTag
>& SfxMedium::GetVersionList( bool _bNoReload
)
3115 // if the medium has no name, then this medium should represent a new document and can have no version info
3116 if ( ( !_bNoReload
|| !pImp
->m_bVersionsAlreadyLoaded
) && !pImp
->aVersions
.getLength() &&
3117 ( !pImp
->m_aName
.isEmpty() || !pImp
->m_aLogicName
.isEmpty() ) && GetStorage().is() )
3119 uno::Reference
< document::XDocumentRevisionListPersistence
> xReader
=
3120 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3123 pImp
->aVersions
= xReader
->load( GetStorage() );
3125 catch ( const uno::Exception
& )
3130 if ( !pImp
->m_bVersionsAlreadyLoaded
)
3131 pImp
->m_bVersionsAlreadyLoaded
= true;
3133 return pImp
->aVersions
;
3136 uno::Sequence
< util::RevisionTag
> SfxMedium::GetVersionList( const uno::Reference
< embed::XStorage
>& xStorage
)
3138 uno::Reference
< document::XDocumentRevisionListPersistence
> xReader
=
3139 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3142 return xReader
->load( xStorage
);
3144 catch ( const uno::Exception
& )
3148 return uno::Sequence
< util::RevisionTag
>();
3151 sal_uInt16
SfxMedium::AddVersion_Impl( util::RevisionTag
& rRevision
)
3153 if ( GetStorage().is() )
3155 // To determine a unique name for the stream
3156 std::vector
<sal_uInt32
> aLongs
;
3157 sal_Int32 nLength
= pImp
->aVersions
.getLength();
3158 for ( sal_Int32 m
=0; m
<nLength
; m
++ )
3160 sal_uInt32 nVer
= static_cast<sal_uInt32
>( pImp
->aVersions
[m
].Identifier
.copy(7).toInt32());
3162 for ( n
=0; n
<aLongs
.size(); ++n
)
3163 if ( nVer
<aLongs
[n
] )
3166 aLongs
.insert( aLongs
.begin()+n
, nVer
);
3170 for ( nKey
=0; nKey
<aLongs
.size(); ++nKey
)
3171 if ( aLongs
[nKey
] > ( sal_uIntPtr
) nKey
+1 )
3174 OUString aRevName
= "Version" + OUString::number( nKey
+ 1 );
3175 pImp
->aVersions
.realloc( nLength
+1 );
3176 rRevision
.Identifier
= aRevName
;
3177 pImp
->aVersions
[nLength
] = rRevision
;
3184 sal_Bool
SfxMedium::RemoveVersion_Impl( const OUString
& rName
)
3186 if ( !pImp
->aVersions
.getLength() )
3189 sal_Int32 nLength
= pImp
->aVersions
.getLength();
3190 for ( sal_Int32 n
=0; n
<nLength
; n
++ )
3192 if ( pImp
->aVersions
[n
].Identifier
== rName
)
3194 for ( sal_Int32 m
=n
; m
<nLength
-1; m
++ )
3195 pImp
->aVersions
[m
] = pImp
->aVersions
[m
+1];
3196 pImp
->aVersions
.realloc(nLength
-1);
3204 sal_Bool
SfxMedium::TransferVersionList_Impl( SfxMedium
& rMedium
)
3206 if ( rMedium
.pImp
->aVersions
.getLength() )
3208 pImp
->aVersions
= rMedium
.pImp
->aVersions
;
3215 sal_Bool
SfxMedium::SaveVersionList_Impl( sal_Bool
/*bUseXML*/ )
3217 if ( GetStorage().is() )
3219 if ( !pImp
->aVersions
.getLength() )
3222 uno::Reference
< document::XDocumentRevisionListPersistence
> xWriter
=
3223 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3226 xWriter
->store( GetStorage(), pImp
->aVersions
);
3229 catch ( const uno::Exception
& )
3237 //----------------------------------------------------------------
3238 sal_Bool
SfxMedium::IsReadOnly()
3240 // a) ReadOnly filter cant produce read/write contents!
3242 (pImp
->m_pFilter
) &&
3243 ((pImp
->m_pFilter
->GetFilterFlags() & SFX_FILTER_OPENREADONLY
) == SFX_FILTER_OPENREADONLY
)
3246 // b) if filter allow read/write contents .. check open mode of the storage
3248 bReadOnly
= !( GetOpenMode() & STREAM_WRITE
);
3250 // c) the API can force the readonly state!
3253 SFX_ITEMSET_ARG( GetItemSet(), pItem
, SfxBoolItem
, SID_DOC_READONLY
, false);
3255 bReadOnly
= pItem
->GetValue();
3261 bool SfxMedium::IsOriginallyReadOnly() const
3263 return pImp
->m_bOriginallyReadOnly
;
3266 //----------------------------------------------------------------
3267 sal_Bool
SfxMedium::SetWritableForUserOnly( const OUString
& aURL
)
3269 // UCB does not allow to allow write access only for the user,
3271 bool bResult
= false;
3273 ::osl::DirectoryItem aDirItem
;
3274 if ( ::osl::DirectoryItem::get( aURL
, aDirItem
) == ::osl::FileBase::E_None
)
3276 ::osl::FileStatus
aFileStatus( osl_FileStatus_Mask_Attributes
);
3277 if ( aDirItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
3278 && aFileStatus
.isValid( osl_FileStatus_Mask_Attributes
) )
3280 sal_uInt64 nAttributes
= aFileStatus
.getAttributes();
3282 nAttributes
&= ~(osl_File_Attribute_OwnWrite
|
3283 osl_File_Attribute_GrpWrite
|
3284 osl_File_Attribute_OthWrite
|
3285 osl_File_Attribute_ReadOnly
);
3286 nAttributes
|= (osl_File_Attribute_OwnWrite
|
3287 osl_File_Attribute_OwnRead
);
3289 bResult
= ( osl::File::setAttributes( aURL
, nAttributes
) == ::osl::FileBase::E_None
);
3296 //----------------------------------------------------------------
3297 void SfxMedium::CreateTempFile( sal_Bool bReplace
)
3299 if ( pImp
->pTempFile
)
3304 DELETEZ( pImp
->pTempFile
);
3308 pImp
->pTempFile
= new ::utl::TempFile();
3309 pImp
->pTempFile
->EnableKillingFile( true );
3310 pImp
->m_aName
= pImp
->pTempFile
->GetFileName();
3311 OUString aTmpURL
= pImp
->pTempFile
->GetURL();
3312 if ( pImp
->m_aName
.isEmpty() || aTmpURL
.isEmpty() )
3314 SetError( ERRCODE_IO_CANTWRITE
, OUString( OSL_LOG_PREFIX
) );
3318 if ( !(pImp
->m_nStorOpenMode
& STREAM_TRUNC
) )
3320 bool bTransferSuccess
= false;
3322 if ( GetContent().is()
3323 && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) )
3324 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) ) )
3326 // if there is already such a document, we should copy it
3327 // if it is a file system use OS copy process
3330 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
3331 INetURLObject
aTmpURLObj( aTmpURL
);
3332 OUString aFileName
= aTmpURLObj
.getName( INetURLObject::LAST_SEGMENT
,
3334 INetURLObject::DECODE_WITH_CHARSET
);
3335 if ( !aFileName
.isEmpty() && aTmpURLObj
.removeSegment() )
3337 ::ucbhelper::Content
aTargetContent( aTmpURLObj
.GetMainURL( INetURLObject::NO_DECODE
), xComEnv
, comphelper::getProcessComponentContext() );
3338 OUString sMimeType
= pImp
->getFilterMimeType();
3339 if ( aTargetContent
.transferContent( pImp
->aContent
, ::ucbhelper::InsertOperation_COPY
, aFileName
, NameClash::OVERWRITE
, sMimeType
) )
3341 SetWritableForUserOnly( aTmpURL
);
3342 bTransferSuccess
= true;
3346 catch( const uno::Exception
& )
3349 if ( bTransferSuccess
)
3356 if ( !bTransferSuccess
&& pImp
->m_pInStream
)
3358 // the case when there is no URL-access available or this is a remote protocoll
3359 // but there is an input stream
3361 if ( pImp
->m_pOutStream
)
3363 char *pBuf
= new char [8192];
3364 sal_uInt32 nErr
= ERRCODE_NONE
;
3366 pImp
->m_pInStream
->Seek(0);
3367 pImp
->m_pOutStream
->Seek(0);
3369 while( !pImp
->m_pInStream
->IsEof() && nErr
== ERRCODE_NONE
)
3371 sal_uInt32 nRead
= pImp
->m_pInStream
->Read( pBuf
, 8192 );
3372 nErr
= pImp
->m_pInStream
->GetError();
3373 pImp
->m_pOutStream
->Write( pBuf
, nRead
);
3376 bTransferSuccess
= true;
3380 CloseOutStream_Impl();
3384 // Quite strange design, but currently it is expected that in this case no transfer happens
3385 // TODO/LATER: get rid of this inconsistent part of the call design
3386 bTransferSuccess
= true;
3390 if ( !bTransferSuccess
)
3392 SetError( ERRCODE_IO_CANTWRITE
, OUString( OSL_LOG_PREFIX
) );
3400 //----------------------------------------------------------------
3401 void SfxMedium::CreateTempFileNoCopy()
3403 // this call always replaces the existing temporary file
3404 if ( pImp
->pTempFile
)
3405 delete pImp
->pTempFile
;
3407 pImp
->pTempFile
= new ::utl::TempFile();
3408 pImp
->pTempFile
->EnableKillingFile( true );
3409 pImp
->m_aName
= pImp
->pTempFile
->GetFileName();
3410 if ( pImp
->m_aName
.isEmpty() )
3412 SetError( ERRCODE_IO_CANTWRITE
, OUString( OSL_LOG_PREFIX
) );
3416 CloseOutStream_Impl();
3420 sal_Bool
SfxMedium::SignContents_Impl( sal_Bool bScriptingContent
, const OUString
& aODFVersion
, sal_Bool bHasValidDocumentSignature
)
3422 bool bChanges
= false;
3424 // the medium should be closed to be able to sign, the caller is responsible to close it
3425 if ( !IsOpen() && !GetError() )
3427 // The component should know if there was a valid document signature, since
3428 // it should show a warning in this case
3429 uno::Reference
< security::XDocumentDigitalSignatures
> xSigner(
3430 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
3431 comphelper::getProcessComponentContext(), aODFVersion
, bHasValidDocumentSignature
) );
3433 uno::Reference
< embed::XStorage
> xWriteableZipStor
;
3434 if ( !IsReadOnly() )
3436 // we can reuse the temporary file if there is one already
3437 CreateTempFile( false );
3442 if ( !pImp
->xStream
.is() )
3443 throw uno::RuntimeException();
3445 xWriteableZipStor
= ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING
, pImp
->xStream
);
3446 if ( !xWriteableZipStor
.is() )
3447 throw uno::RuntimeException();
3449 uno::Reference
< embed::XStorage
> xMetaInf
= xWriteableZipStor
->openStorageElement(
3450 OUString( "META-INF" ),
3451 embed::ElementModes::READWRITE
);
3452 if ( !xMetaInf
.is() )
3453 throw uno::RuntimeException();
3455 if ( bScriptingContent
)
3457 // If the signature has already the document signature it will be removed
3458 // after the scripting signature is inserted.
3459 uno::Reference
< io::XStream
> xStream(
3460 xMetaInf
->openStreamElement( xSigner
->getScriptingContentSignatureDefaultStreamName(),
3461 embed::ElementModes::READWRITE
),
3462 uno::UNO_SET_THROW
);
3464 if ( xSigner
->signScriptingContent( GetZipStorageToSign_Impl(), xStream
) )
3466 // remove the document signature if any
3467 OUString aDocSigName
= xSigner
->getDocumentContentSignatureDefaultStreamName();
3468 if ( !aDocSigName
.isEmpty() && xMetaInf
->hasByName( aDocSigName
) )
3469 xMetaInf
->removeElement( aDocSigName
);
3471 uno::Reference
< embed::XTransactedObject
> xTransact( xMetaInf
, uno::UNO_QUERY_THROW
);
3472 xTransact
->commit();
3473 xTransact
.set( xWriteableZipStor
, uno::UNO_QUERY_THROW
);
3474 xTransact
->commit();
3476 // the temporary file has been written, commit it to the original file
3483 uno::Reference
< io::XStream
> xStream(
3484 xMetaInf
->openStreamElement( xSigner
->getDocumentContentSignatureDefaultStreamName(),
3485 embed::ElementModes::READWRITE
),
3486 uno::UNO_SET_THROW
);
3488 if ( xSigner
->signDocumentContent( GetZipStorageToSign_Impl(), xStream
) )
3490 uno::Reference
< embed::XTransactedObject
> xTransact( xMetaInf
, uno::UNO_QUERY_THROW
);
3491 xTransact
->commit();
3492 xTransact
.set( xWriteableZipStor
, uno::UNO_QUERY_THROW
);
3493 xTransact
->commit();
3495 // the temporary file has been written, commit it to the original file
3501 catch ( const uno::Exception
& )
3503 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!\n" );
3512 if ( bScriptingContent
)
3513 xSigner
->showScriptingContentSignatures( GetZipStorageToSign_Impl(), uno::Reference
< io::XInputStream
>() );
3515 xSigner
->showDocumentContentSignatures( GetZipStorageToSign_Impl(), uno::Reference
< io::XInputStream
>() );
3517 catch( const uno::Exception
& )
3519 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!\n" );
3529 //----------------------------------------------------------------
3530 sal_uInt16
SfxMedium::GetCachedSignatureState_Impl()
3532 return pImp
->m_nSignatureState
;
3535 //----------------------------------------------------------------
3536 void SfxMedium::SetCachedSignatureState_Impl( sal_uInt16 nState
)
3538 pImp
->m_nSignatureState
= nState
;
3541 sal_Bool
SfxMedium::HasStorage_Impl() const
3543 return pImp
->xStorage
.is();
3546 sal_Bool
SfxMedium::IsOpen() const
3548 return pImp
->m_pInStream
|| pImp
->m_pOutStream
|| pImp
->xStorage
.is();
3551 OUString
SfxMedium::CreateTempCopyWithExt( const OUString
& aURL
)
3555 if ( !aURL
.isEmpty() )
3557 sal_Int32 nPrefixLen
= aURL
.lastIndexOf( '.' );
3558 OUString aExt
= ( nPrefixLen
== -1 ) ? OUString() : aURL
.copy( nPrefixLen
);
3560 OUString aNewTempFileURL
= ::utl::TempFile( OUString(), &aExt
).GetURL();
3561 if ( !aNewTempFileURL
.isEmpty() )
3563 INetURLObject
aSource( aURL
);
3564 INetURLObject
aDest( aNewTempFileURL
);
3565 OUString aFileName
= aDest
.getName( INetURLObject::LAST_SEGMENT
,
3567 INetURLObject::DECODE_WITH_CHARSET
);
3568 if ( !aFileName
.isEmpty() && aDest
.removeSegment() )
3572 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
3573 ::ucbhelper::Content
aTargetContent( aDest
.GetMainURL( INetURLObject::NO_DECODE
), xComEnv
, comphelper::getProcessComponentContext() );
3574 ::ucbhelper::Content
aSourceContent( aSource
.GetMainURL( INetURLObject::NO_DECODE
), xComEnv
, comphelper::getProcessComponentContext() );
3575 if ( aTargetContent
.transferContent( aSourceContent
,
3576 ::ucbhelper::InsertOperation_COPY
,
3578 NameClash::OVERWRITE
) )
3581 aResult
= aNewTempFileURL
;
3584 catch( const uno::Exception
& )
3593 sal_Bool
SfxMedium::CallApproveHandler( const uno::Reference
< task::XInteractionHandler
>& xHandler
, uno::Any aRequest
, sal_Bool bAllowAbort
)
3595 bool bResult
= false;
3597 if ( xHandler
.is() )
3601 uno::Sequence
< uno::Reference
< task::XInteractionContinuation
> > aContinuations( bAllowAbort
? 2 : 1 );
3603 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove( new ::comphelper::OInteractionApprove
);
3604 aContinuations
[ 0 ] = pApprove
.get();
3608 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort( new ::comphelper::OInteractionAbort
);
3609 aContinuations
[ 1 ] = pAbort
.get();
3612 xHandler
->handle(::framework::InteractionRequest::CreateRequest (aRequest
,aContinuations
));
3613 bResult
= pApprove
->wasSelected();
3615 catch( const Exception
& )
3623 OUString
SfxMedium::SwitchDocumentToTempFile()
3625 // the method returns empty string in case of failure
3627 OUString aOrigURL
= pImp
->m_aLogicName
;
3629 if ( !aOrigURL
.isEmpty() )
3631 sal_Int32 nPrefixLen
= aOrigURL
.lastIndexOf( '.' );
3632 OUString
const aExt
= (nPrefixLen
== -1)
3634 : aOrigURL
.copy(nPrefixLen
);
3635 OUString aNewURL
= ::utl::TempFile( OUString(), &aExt
).GetURL();
3637 // TODO/LATER: In future the aLogicName should be set to shared folder URL
3638 // and a temporary file should be created. Transport_Impl should be impossible then.
3639 if ( !aNewURL
.isEmpty() )
3641 uno::Reference
< embed::XStorage
> xStorage
= GetStorage();
3642 uno::Reference
< embed::XOptimizedStorage
> xOptStorage( xStorage
, uno::UNO_QUERY
);
3644 if ( xOptStorage
.is() )
3646 // TODO/LATER: reuse the pImp->pTempFile if it already exists
3647 CanDisposeStorage_Impl( false );
3649 SetPhysicalName_Impl( OUString() );
3652 // remove the readonly state
3653 bool bWasReadonly
= false;
3654 pImp
->m_nStorOpenMode
= SFX_STREAM_READWRITE
;
3655 SFX_ITEMSET_ARG( pImp
->m_pSet
, pReadOnlyItem
, SfxBoolItem
, SID_DOC_READONLY
, false );
3656 if ( pReadOnlyItem
&& pReadOnlyItem
->GetValue() )
3657 bWasReadonly
= true;
3658 GetItemSet()->ClearItem( SID_DOC_READONLY
);
3661 LockOrigFileOnDemand( false, false );
3662 CreateTempFile( true );
3665 if ( pImp
->xStream
.is() )
3669 xOptStorage
->writeAndAttachToStream( pImp
->xStream
);
3670 pImp
->xStorage
= xStorage
;
3673 catch( const uno::Exception
& )
3677 if ( aResult
.isEmpty() )
3680 SetPhysicalName_Impl( OUString() );
3681 SetName( aOrigURL
);
3684 // set the readonly state back
3685 pImp
->m_nStorOpenMode
= SFX_STREAM_READONLY
;
3686 GetItemSet()->Put( SfxBoolItem(SID_DOC_READONLY
, true));
3689 pImp
->xStorage
= xStorage
;
3698 sal_Bool
SfxMedium::SwitchDocumentToFile( const OUString
& aURL
)
3700 // the method is only for storage based documents
3701 bool bResult
= false;
3702 OUString aOrigURL
= pImp
->m_aLogicName
;
3704 if ( !aURL
.isEmpty() && !aOrigURL
.isEmpty() )
3706 uno::Reference
< embed::XStorage
> xStorage
= GetStorage();
3707 uno::Reference
< embed::XOptimizedStorage
> xOptStorage( xStorage
, uno::UNO_QUERY
);
3709 if ( xOptStorage
.is() )
3711 // TODO/LATER: reuse the pImp->pTempFile if it already exists
3712 CanDisposeStorage_Impl( false );
3714 SetPhysicalName_Impl( OUString() );
3717 // open the temporary file based document
3719 LockOrigFileOnDemand( false, false );
3720 CreateTempFile( true );
3723 if ( pImp
->xStream
.is() )
3727 uno::Reference
< io::XTruncate
> xTruncate( pImp
->xStream
, uno::UNO_QUERY_THROW
);
3728 if ( xTruncate
.is() )
3729 xTruncate
->truncate();
3731 xOptStorage
->writeAndAttachToStream( pImp
->xStream
);
3732 pImp
->xStorage
= xStorage
;
3735 catch( const uno::Exception
& )
3742 SetPhysicalName_Impl( OUString() );
3743 SetName( aOrigURL
);
3745 pImp
->xStorage
= xStorage
;
3753 void SfxMedium::SetInCheckIn( bool bInCheckIn
)
3755 pImp
->m_bInCheckIn
= bInCheckIn
;
3758 bool SfxMedium::IsInCheckIn( )
3760 return pImp
->m_bInCheckIn
;
3763 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */