Bump version to 4.2-24
[LibreOffice.git] / sfx2 / source / doc / docfile.cxx
blob3830b11c9d4a8e2ec11c602b7a1314c1a470dc08
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
117 #include "doc.hrc"
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;
133 namespace {
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
144 return true;
145 #else
146 return officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::get();
147 #endif
150 //----------------------------------------------------------------
151 bool IsOOoLockFileUsed()
153 #if HAVE_FEATURE_MACOSX_SANDBOX
154 return false;
155 #else
156 return officecfg::Office::Common::Misc::UseDocumentOOoLockFile::get();
157 #endif
160 bool IsLockingUsed()
162 return officecfg::Office::Common::Misc::UseLocking::get();
165 #endif
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;
176 public:
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 )
196 if( !m_xInter.is() )
197 return;
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 ) )
203 return;
204 else
205 if ( aRequest >>= aSinkException )
206 return;
207 else
208 m_xInter->handle( xRequest );
211 class SfxMedium_Impl : boost::noncopyable
213 public:
214 StreamMode m_nStorOpenMode;
215 sal_uInt32 m_eError;
217 ::ucbhelper::Content aContent;
218 bool bUpdatePickList:1;
219 bool bIsTemp:1;
220 bool bDownloadDone:1;
221 bool bIsStorage: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;
228 bool m_bLocked:1;
229 bool m_bGotDateTime:1;
230 bool m_bRemoveBackup:1;
231 bool m_bOriginallyReadOnly:1;
232 bool m_bTriedStorage:1;
233 bool m_bRemote:1;
234 bool m_bInputStreamIsReadOnly:1;
235 bool m_bInCheckIn:1;
237 OUString m_aName;
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;
252 OUString aOrigURL;
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 );
284 ~SfxMedium_Impl();
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),
295 bIsTemp( false ),
296 bDownloadDone( true ),
297 bIsStorage( false ),
298 bUseInteractionHandler( true ),
299 bAllowDefaultIntHdl( false ),
300 bDisposeStorage( false ),
301 bStorageBasedOnInStream( false ),
302 m_bSalvageMode( false ),
303 m_bVersionsAlreadyLoaded( false ),
304 m_bLocked( false ),
305 m_bGotDateTime( false ),
306 m_bRemoveBackup( false ),
307 m_bOriginallyReadOnly(false),
308 m_bTriedStorage(false),
309 m_bRemote(false),
310 m_bInputStreamIsReadOnly(false),
311 m_bInCheckIn(false),
312 m_pSet(NULL),
313 m_pURLObj(NULL),
314 m_pFilter(NULL),
315 pAntiImpl( pAntiImplP ),
316 m_pInStream(NULL),
317 m_pOutStream(NULL),
318 pOrigFilter( 0 ),
319 aExpireTime( Date( Date::SYSTEM ) + 10, Time( Time::SYSTEM ) ),
320 pTempFile( NULL ),
321 nLastStorageError( 0 ),
322 m_nSignatureState( SIGNATURESTATE_NOSIGNATURES )
324 aDoneLink.CreateMutex();
327 //------------------------------------------------------------------
328 SfxMedium_Impl::~SfxMedium_Impl()
330 aDoneLink.ClearPendingCall();
332 delete pTempFile;
333 delete m_pSet;
334 delete m_pURLObj;
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();
386 return lError;
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();
402 if ( xHandler.is() )
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);
463 if ( pItem )
464 pItem->GetValue() >>= xContent;
466 if ( xContent.is() )
470 pImp->aContent = ::ucbhelper::Content( xContent, xEnv, comphelper::getProcessComponentContext() );
472 catch ( const Exception& )
476 else
478 // TODO: SAL_WARN( "sfx.doc", "SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why its used.");
479 OUString aURL;
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 )
495 OUString aBaseURL;
496 const SfxStringItem* pBaseURLItem = static_cast<const SfxStringItem*>( GetItemSet()->GetItem(SID_DOC_BASEURL) );
497 if ( pBaseURLItem )
498 aBaseURL = pBaseURLItem->GetValue();
499 else if ( GetContent().is() )
503 Any aAny = pImp->aContent.getPropertyValue("BaseURI");
504 aAny >>= aBaseURL;
506 catch ( const ::com::sun::star::uno::Exception& )
510 if ( aBaseURL.isEmpty() )
511 aBaseURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
514 if ( bForSaving )
516 SvtSaveOptions aOpt;
517 bool bIsRemote = IsRemote();
518 if( (bIsRemote && !aOpt.IsSaveRelINet()) || (!pImp->m_bRemote && !aOpt.IsSaveRelFSys()) )
519 return OUString();
522 return aBaseURL;
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;
544 else
545 return pImp->m_pInStream;
548 GetMedium_Impl();
550 if ( GetError() )
551 return NULL;
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 )
570 CloseStorage();
573 if ( pImp->m_pInStream && !GetContent().is() )
575 CreateTempFile( true );
576 return;
579 DELETEZ( pImp->m_pInStream );
580 if ( pImp->m_pSet )
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();
591 if ( pImp->m_pSet )
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
602 // need one.
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
609 #ifdef WNT
610 if (pImp->xStream.is())
612 assert(pImp->xStream->getOutputStream().is()); // need that...
613 pImp->m_pOutStream = utl::UcbStreamHelper::CreateStream(
614 pImp->xStream, false);
616 else
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)
623 #else
624 pImp->m_pOutStream = new SvFileStream(
625 pImp->m_aName, STREAM_STD_READWRITE);
626 #endif
627 CloseStorage();
631 return pImp->m_pOutStream;
634 //------------------------------------------------------------------
635 sal_Bool SfxMedium::CloseOutStream()
637 CloseOutStream_Impl();
638 return true;
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() )
652 CloseStorage();
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();
664 if ( pImp->m_pSet )
665 pImp->m_pSet->ClearItem( SID_STREAM );
668 return true;
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 );
685 GetInStream();
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 )
707 Transfer_Impl();
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);
717 return bResult;
720 //------------------------------------------------------------------
721 sal_Bool SfxMedium::IsStorage()
723 if ( pImp->xStorage.is() )
724 return true;
726 if ( pImp->m_bTriedStorage )
727 return pImp->bIsStorage;
729 if ( pImp->pTempFile )
731 OUString aURL;
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);
755 if ( pPreview )
756 bPreview = pPreview->GetValue();
757 else
759 SFX_ITEMSET_ARG( GetItemSet(), pFlags, SfxStringItem, SID_OPTIONS, false);
760 if ( pFlags )
762 OUString aFileFlags = pFlags->GetValue();
763 aFileFlags = aFileFlags.toAsciiUpperCase();
764 if ( -1 != aFileFlags.indexOf( 'B' ) )
765 bPreview = true;
769 return bPreview;
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()
804 if ( GetError() )
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() )
814 CloseInStream();
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();
823 return GetStorage();
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();
881 OUString aInfo;
882 ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl;
884 if ( bOwnLock )
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 ) ) );
892 else
894 if ( aData.getLength() > LOCKFILE_EDITTIME_ID )
896 if ( !aData[LOCKFILE_OOOUSERNAME_ID].isEmpty() )
897 aInfo = aData[LOCKFILE_OOOUSERNAME_ID];
898 else
899 aInfo = aData[LOCKFILE_SYSUSERNAME_ID];
901 if ( !aInfo.isEmpty() && !aData[LOCKFILE_EDITTIME_ID].isEmpty() )
903 aInfo += " ( " ;
904 aInfo += aData[LOCKFILE_EDITTIME_ID];
905 aInfo += " )";
909 if ( bIsLoading )
911 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
912 document::LockedDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
914 else
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 ) );
946 else if ( bOwnLock )
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
956 if ( bIsLoading )
957 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
958 else
959 nResult = LOCK_UI_TRY;
962 else
964 if ( bIsLoading )
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 ) );
971 else
972 SetError( ERRCODE_IO_ACCESSDENIED, OUString( OSL_LOG_PREFIX ) );
976 return nResult;
979 namespace
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;
987 #else
988 return eProt == INET_PROT_FILE || eProt == INET_PROT_SFTP;
989 #endif
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
1000 (void) bLoading;
1001 (void) bNoUI;
1002 #else
1003 if (!IsLockingUsed() || GetURLObject().HasError())
1004 return;
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;
1017 if ( !bResult )
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& ) {}
1048 #if EXTRA_ACL_CHECK
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
1057 OUString aPhysPath;
1058 if ( ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), aPhysPath ) )
1059 bContentReadonly = IsReadonlyAccordingACL( aPhysPath.getStr() );
1061 #endif
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
1075 if ( bLoading )
1077 // let the stream be opened to check the system file locking
1078 GetMedium_Impl();
1079 if (GetError() != ERRCODE_NONE) {
1080 return;
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() )
1110 bResult = true;
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() )
1142 bResult = true;
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() )
1152 bResult = true;
1153 // take the ownership over the lock file
1154 aLockFile.OverwriteOwnLockFile();
1159 if ( !bResult )
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] ) );
1180 if ( bOwnLock
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
1185 bResult = true;
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;
1209 else
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 ) );
1225 else
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" );
1237 #endif
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
1250 GetMedium_Impl();
1252 if ( bCreateTempIfNo )
1253 CreateTempFile( false );
1255 GetMedium_Impl();
1257 if ( GetError() )
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 );
1265 GetMedium_Impl();
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
1282 aArgs.realloc( 3 );
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;
1300 else
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 ),
1312 uno::UNO_QUERY );
1314 catch( const uno::Exception& )
1316 // impossibility to create the storage is no error
1319 if( ( pImp->nLastStorageError = GetError() ) != SVSTREAM_OK )
1321 pImp->xStorage = 0;
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();
1333 GetVersionList();
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
1347 // current version
1348 short nVersion = pVersion ? pVersion->GetValue() : 0;
1349 if ( nVersion<0 )
1350 nVersion = ( (short) pImp->aVersions.getLength() ) + nVersion;
1351 else if ( nVersion )
1352 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;
1373 aTmpStream.Close();
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;
1379 OUString aTemp;
1380 ::utl::LocalFileHelper::ConvertURLToPhysicalName( aTmpName, aTemp );
1381 SetPhysicalName_Impl( aTemp );
1383 pImp->bIsTemp = true;
1384 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1385 // TODO/MBA
1386 pImp->aVersions.realloc(0);
1388 else
1389 bResetStorage = true;
1392 else
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() )
1412 GetMedium_Impl();
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
1433 ResetError();
1436 return pImp->m_xZipStorage;
1439 //------------------------------------------------------------------
1440 void SfxMedium::CloseZipStorage_Impl()
1442 if ( pImp->m_xZipStorage.is() )
1444 try {
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 )
1461 try {
1462 xComp->dispose();
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;
1499 if( !bDontClose )
1501 if ( pImp->xStorage.is() )
1502 CloseStorage();
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 );
1519 return 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;
1530 return false;
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() )
1542 if ( !GetError() )
1544 uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY );
1545 if ( xTrans.is() )
1549 xTrans->commit();
1550 CloseZipStorage_Impl();
1551 bResult = true;
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" );
1576 if ( !GetError() )
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 ) );
1589 return bResult;
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;
1617 if (
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() )
1633 CloseStorage();
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 );
1659 bResult = true;
1661 else
1663 pImp->m_eError = ERRCODE_SFX_CANTCREATEBACKUP;
1666 else
1668 Reference< XInputStream > aTempInput = aTempCont.openStream();
1669 aOriginalContent.writeStream( aTempInput, bOverWrite );
1670 bResult = true;
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;
1689 else
1690 pImp->m_eError = ERRCODE_IO_GENERAL;
1692 catch ( const ::com::sun::star::uno::Exception& )
1694 pImp->m_eError = ERRCODE_IO_GENERAL;
1697 if ( bResult )
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 );
1711 else
1712 pImp->m_eError = ERRCODE_IO_CANTREAD;
1715 return bResult;
1718 //------------------------------------------------------------------
1719 sal_Bool SfxMedium::TryDirectTransfer( const OUString& aURL, SfxItemSet& aTargetSet )
1721 if ( GetError() )
1722 return false;
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();
1741 ResetError();
1742 if ( xInStream.is() )
1746 uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
1747 sal_Int64 nPos = 0;
1748 if ( xSeek.is() )
1750 nPos = xSeek->getPosition();
1751 xSeek->seek( 0 );
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;
1764 else
1765 aInsertArg.ReplaceExisting = true; // default is overwrite existing files
1767 Any aCmdArg;
1768 aCmdArg <<= aInsertArg;
1769 aTargetContent.executeCommand( OUString( "insert" ),
1770 aCmdArg );
1772 if ( xSeek.is() )
1773 xSeek->seek( nPos );
1775 return true;
1777 catch( const uno::Exception& )
1783 return false;
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
1790 OUString aNameURL;
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() )
1816 CloseStorage();
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 ) )
1826 sal_Int32 nRead;
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 );
1839 else
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& )
1856 else
1858 SAL_WARN( "sfx.doc", "Illegal Output stream parameter!" );
1859 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1862 // free the reference
1863 if ( pImp->m_pSet )
1864 pImp->m_pSet->ClearItem( SID_OUTPUTSTREAM );
1866 return;
1869 GetContent();
1870 if ( !pImp->aContent.get().is() )
1872 pImp->m_eError = ERRCODE_IO_NOTEXISTS;
1873 return;
1876 SFX_ITEMSET_ARG( GetItemSet(), pSegmentSize, SfxInt32Item, SID_SEGMENTSIZE, false);
1877 if ( pSegmentSize )
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
1886 // into this size
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 );
1896 if ( xTrans.is() )
1897 xTrans->commit();
1900 catch ( const uno::Exception& )
1902 //TODO/MBA: error handling
1904 return;
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 )
1930 aFile.sync();
1931 SAL_INFO( "sfx.doc", "fsync'd saved file '" << aDestURL << "'" );
1932 aFile.close();
1935 else
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;
1951 if ( xChild.is( ) )
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()
1963 else
1964 aDestURL = sParentUrl;
1967 // LongName wasn't defined anywhere, only used here... get the Title instead
1968 // as it's less probably empty
1969 OUString aFileName;
1970 Any aAny = aDestContent.getPropertyValue("Title");
1971 aAny >>= aFileName;
1972 aAny = aDestContent.getPropertyValue( OUString("ObjectId" ) );
1973 OUString sObjectId;
1974 aAny >>= sObjectId;
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;
1985 if (
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() )
2002 CloseStorage();
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;
2018 else
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;
2027 OUString sComment;
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 );
2034 if ( pComments )
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;
2060 else
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,
2108 aBackupName,
2109 NameClash::OVERWRITE,
2110 sMimeType ) )
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,
2131 true,
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 ) ) )
2171 return;
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,
2200 aFileName,
2201 NameClash::OVERWRITE,
2202 sMimeType );
2203 if( bSuccess )
2205 pImp->m_aBackupURL = aDest.GetMainURL( INetURLObject::NO_DECODE );
2206 pImp->m_bRemoveBackup = false;
2209 catch ( const ::com::sun::star::uno::Exception& )
2216 if ( !bSuccess )
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 = "";
2236 else
2239 SAL_WARN( "sfx.doc", "Couldn't remove backup file!");
2243 else
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;
2311 else
2313 uno::Sequence < beans::PropertyValue > xProps;
2314 OUString aFileName;
2315 if (!pImp->m_aName.isEmpty())
2317 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aFileName ) )
2319 SAL_WARN( "sfx.doc", "Physical name not convertible!");
2322 else
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 ) );
2345 else
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;
2355 else
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();
2368 else
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;
2379 GetContent();
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 ) );
2398 if ( !GetError() )
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 );
2450 GetInStream();
2451 if ( pImp->m_pInStream && !aLink.IsSet() )
2453 while( !pImp->bDownloadDone )
2454 Application::Yield();
2458 //------------------------------------------------------------------
2459 void SfxMedium::Init_Impl()
2460 /* [Description]
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!" );
2487 else
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 );
2499 else
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);
2516 if( pOutStreamItem
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
2531 GetItemSet()->Put(
2532 SfxStringItem(
2533 SID_FILE_NAME, INetURLObject( pImp->m_aLogicName ).GetMainURL( INetURLObject::NO_DECODE ) ) );
2537 SetIsRemote_Impl();
2540 //------------------------------------------------------------------
2541 SfxMedium::SfxMedium() : pImp(new SfxMedium_Impl(this))
2543 Init_Impl();
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
2563 if ( pImp->m_pSet )
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() )
2568 return xHandler;
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() )
2613 if ( bWriter )
2615 nHash = ::comphelper::DocPasswordHelper::GetWordHashAsUINT32( aPasswd );
2617 else
2619 rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
2620 nHash = ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd, nEncoding );
2624 return nHash;
2627 //------------------------------------------------------------------
2629 void SfxMedium::Close()
2631 if ( pImp->xStorage.is() )
2633 CloseStorage();
2636 CloseStreams_Impl();
2638 UnlockFile( false );
2641 void SfxMedium::CloseAndRelease()
2643 if ( pImp->xStorage.is() )
2645 CloseStorage();
2648 CloseAndReleaseStreams_Impl();
2650 UnlockFile( true );
2653 void SfxMedium::UnlockFile( sal_Bool bReleaseLockStream )
2655 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
2656 (void) bReleaseLockStream;
2657 #else
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& )
2690 #endif
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();
2733 if ( pImp->m_pSet )
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() )
2746 case INET_PROT_FTP:
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:
2752 case INET_PROT_VIM:
2753 pImp->m_bRemote = true;
2754 break;
2755 default:
2756 pImp->m_bRemote = GetName().startsWith("private:msgid");
2757 break;
2760 // As files that are written to the remote transmission must also be able
2761 // to be read.
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;
2772 if( bSetOrigURL )
2773 pImp->aOrigURL = aNameP;
2774 pImp->m_aLogicName = aNameP;
2775 DELETEZ( pImp->m_pURLObj );
2776 pImp->aContent = ::ucbhelper::Content();
2777 Init_Impl();
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;
2813 GetMedium_Impl();
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;
2830 pImp->m_aName = "";
2833 GetMedium_Impl();
2835 if ( GetError() )
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();
2846 else
2848 pTmpFile->EnableKillingFile( true );
2849 delete pTmpFile;
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;
2863 Init_Impl();
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;
2877 Init_Impl();
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 );
2902 else
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 );
2910 if( pSalvageItem )
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 );
2928 else
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;
2943 Init_Impl();
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!" );
2956 Init_Impl();
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 ) );
2962 if ( p )
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!" );
2974 Init_Impl();
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 ) );
2980 if ( p )
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
2989 ClearBackup_Impl();
2991 Close();
2993 if( pImp->bIsTemp && !pImp->m_aName.isEmpty() )
2995 OUString aTemp;
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!");
3007 delete pImp;
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();
3043 if( pBytes )
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
3075 if (!pImp->m_pSet)
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() )
3109 GetMedium_Impl();
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());
3161 size_t n;
3162 for ( n=0; n<aLongs.size(); ++n )
3163 if ( nVer<aLongs[n] )
3164 break;
3166 aLongs.insert( aLongs.begin()+n, nVer );
3169 sal_uInt16 nKey;
3170 for ( nKey=0; nKey<aLongs.size(); ++nKey )
3171 if ( aLongs[nKey] > ( sal_uIntPtr ) nKey+1 )
3172 break;
3174 OUString aRevName = "Version" + OUString::number( nKey + 1 );
3175 pImp->aVersions.realloc( nLength+1 );
3176 rRevision.Identifier = aRevName;
3177 pImp->aVersions[nLength] = rRevision;
3178 return nKey;
3181 return 0;
3184 sal_Bool SfxMedium::RemoveVersion_Impl( const OUString& rName )
3186 if ( !pImp->aVersions.getLength() )
3187 return false;
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);
3197 return true;
3201 return false;
3204 sal_Bool SfxMedium::TransferVersionList_Impl( SfxMedium& rMedium )
3206 if ( rMedium.pImp->aVersions.getLength() )
3208 pImp->aVersions = rMedium.pImp->aVersions;
3209 return true;
3212 return false;
3215 sal_Bool SfxMedium::SaveVersionList_Impl( sal_Bool /*bUseXML*/ )
3217 if ( GetStorage().is() )
3219 if ( !pImp->aVersions.getLength() )
3220 return true;
3222 uno::Reference < document::XDocumentRevisionListPersistence > xWriter =
3223 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3226 xWriter->store( GetStorage(), pImp->aVersions );
3227 return true;
3229 catch ( const uno::Exception& )
3234 return false;
3237 //----------------------------------------------------------------
3238 sal_Bool SfxMedium::IsReadOnly()
3240 // a) ReadOnly filter cant produce read/write contents!
3241 bool bReadOnly = (
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
3247 if (!bReadOnly)
3248 bReadOnly = !( GetOpenMode() & STREAM_WRITE );
3250 // c) the API can force the readonly state!
3251 if (!bReadOnly)
3253 SFX_ITEMSET_ARG( GetItemSet(), pItem, SfxBoolItem, SID_DOC_READONLY, false);
3254 if (pItem)
3255 bReadOnly = pItem->GetValue();
3258 return bReadOnly;
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,
3270 // use osl API
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 );
3293 return bResult;
3296 //----------------------------------------------------------------
3297 void SfxMedium::CreateTempFile( sal_Bool bReplace )
3299 if ( pImp->pTempFile )
3301 if ( !bReplace )
3302 return;
3304 DELETEZ( pImp->pTempFile );
3305 pImp->m_aName = "";
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 ) );
3315 return;
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,
3333 true,
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 )
3351 CloseOutStream();
3352 CloseInStream();
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
3360 GetOutStream();
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;
3377 delete[] pBuf;
3378 CloseInStream();
3380 CloseOutStream_Impl();
3382 else
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;
3387 CloseInStream();
3390 if ( !bTransferSuccess )
3392 SetError( ERRCODE_IO_CANTWRITE, OUString( OSL_LOG_PREFIX ) );
3393 return;
3397 CloseStorage();
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 ) );
3413 return;
3416 CloseOutStream_Impl();
3417 CloseStorage();
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 );
3438 GetMedium_Impl();
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
3477 Commit();
3478 bChanges = true;
3481 else
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
3496 Commit();
3497 bChanges = true;
3501 catch ( const uno::Exception& )
3503 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!\n" );
3506 CloseAndRelease();
3508 else
3512 if ( bScriptingContent )
3513 xSigner->showScriptingContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() );
3514 else
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" );
3523 ResetError();
3526 return bChanges;
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 )
3553 OUString aResult;
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,
3566 true,
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,
3577 aFileName,
3578 NameClash::OVERWRITE ) )
3580 // Success
3581 aResult = aNewTempFileURL;
3584 catch( const uno::Exception& )
3590 return aResult;
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();
3606 if ( bAllowAbort )
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& )
3620 return bResult;
3623 OUString SfxMedium::SwitchDocumentToTempFile()
3625 // the method returns empty string in case of failure
3626 OUString aResult;
3627 OUString aOrigURL = pImp->m_aLogicName;
3629 if ( !aOrigURL.isEmpty() )
3631 sal_Int32 nPrefixLen = aOrigURL.lastIndexOf( '.' );
3632 OUString const aExt = (nPrefixLen == -1)
3633 ? OUString()
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 );
3648 Close();
3649 SetPhysicalName_Impl( OUString() );
3650 SetName( aNewURL );
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 );
3660 GetMedium_Impl();
3661 LockOrigFileOnDemand( false, false );
3662 CreateTempFile( true );
3663 GetMedium_Impl();
3665 if ( pImp->xStream.is() )
3669 xOptStorage->writeAndAttachToStream( pImp->xStream );
3670 pImp->xStorage = xStorage;
3671 aResult = aNewURL;
3673 catch( const uno::Exception& )
3677 if ( aResult.isEmpty() )
3679 Close();
3680 SetPhysicalName_Impl( OUString() );
3681 SetName( aOrigURL );
3682 if ( bWasReadonly )
3684 // set the readonly state back
3685 pImp->m_nStorOpenMode = SFX_STREAM_READONLY;
3686 GetItemSet()->Put( SfxBoolItem(SID_DOC_READONLY, true));
3688 GetMedium_Impl();
3689 pImp->xStorage = xStorage;
3695 return aResult;
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 );
3713 Close();
3714 SetPhysicalName_Impl( OUString() );
3715 SetName( aURL );
3717 // open the temporary file based document
3718 GetMedium_Impl();
3719 LockOrigFileOnDemand( false, false );
3720 CreateTempFile( true );
3721 GetMedium_Impl();
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;
3733 bResult = true;
3735 catch( const uno::Exception& )
3739 if ( !bResult )
3741 Close();
3742 SetPhysicalName_Impl( OUString() );
3743 SetName( aOrigURL );
3744 GetMedium_Impl();
3745 pImp->xStorage = xStorage;
3750 return bResult;
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: */