bump product version to 4.1.6.2
[LibreOffice.git] / sfx2 / source / doc / docfile.cxx
blob06d7a4b8e79e00a51cfaeff3d5640accef07294e
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/componentcontext.hxx>
72 #include <comphelper/interaction.hxx>
73 #include <framework/interaction.hxx>
74 #include <unotools/streamhelper.hxx>
75 #include <unotools/localedatawrapper.hxx>
76 #include <vcl/msgbox.hxx>
77 #include <svl/stritem.hxx>
78 #include <svl/eitem.hxx>
79 #include <svl/lckbitem.hxx>
80 #include <svtools/sfxecode.hxx>
81 #include <svl/itemset.hxx>
82 #include <svl/intitem.hxx>
83 #include <svtools/svparser.hxx> // SvKeyValue
84 #include <cppuhelper/weakref.hxx>
86 #include <unotools/streamwrap.hxx>
88 #include <rtl/logfile.hxx>
89 #include <osl/file.hxx>
91 #include <comphelper/storagehelper.hxx>
92 #include <comphelper/mediadescriptor.hxx>
93 #include <comphelper/configurationhelper.hxx>
94 #include <comphelper/docpasswordhelper.hxx>
95 #include <tools/inetmime.hxx>
96 #include <unotools/ucblockbytes.hxx>
97 #include <unotools/pathoptions.hxx>
98 #include <svtools/asynclink.hxx>
99 #include <svl/inettype.hxx>
100 #include <ucbhelper/commandenvironment.hxx>
101 #include <unotools/localfilehelper.hxx>
102 #include <unotools/ucbstreamhelper.hxx>
103 #include <unotools/ucbhelper.hxx>
104 #include <unotools/progresshandlerwrap.hxx>
105 #include <ucbhelper/content.hxx>
106 #include <ucbhelper/interactionrequest.hxx>
107 #include <sot/stg.hxx>
108 #include <unotools/saveopt.hxx>
109 #include <svl/documentlockfile.hxx>
110 #include <com/sun/star/document/DocumentRevisionListPersistence.hpp>
112 #include "helper.hxx"
113 #include <sfx2/request.hxx> // SFX_ITEMSET_SET
114 #include <sfx2/app.hxx> // GetFilterMatcher
115 #include <sfx2/frame.hxx> // LoadTargetFrame
116 #include "fltfnc.hxx" // SfxFilterMatcher
117 #include <sfx2/docfilt.hxx> // SfxFilter
118 #include <sfx2/objsh.hxx> // CheckOpenMode
119 #include <sfx2/docfac.hxx> // GetFilterContainer
120 #include "doc.hrc"
121 #include "openflag.hxx" // SFX_STREAM_READONLY etc.
122 #include "sfx2/sfxresid.hxx"
123 #include <sfx2/appuno.hxx>
124 #include "sfxacldetect.hxx"
125 #include "officecfg/Office/Common.hxx"
127 #include <boost/noncopyable.hpp>
128 #include <boost/scoped_ptr.hpp>
130 using namespace ::com::sun::star;
131 using namespace ::com::sun::star::uno;
132 using namespace ::com::sun::star::ucb;
133 using namespace ::com::sun::star::beans;
134 using namespace ::com::sun::star::io;
136 namespace {
138 static const sal_Int8 LOCK_UI_NOLOCK = 0;
139 static const sal_Int8 LOCK_UI_SUCCEEDED = 1;
140 static const sal_Int8 LOCK_UI_TRY = 2;
142 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
144 bool IsSystemFileLockingUsed()
146 // check whether system file locking has been used, the default value is false
147 bool bUseSystemLock = false;
151 uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig(
152 ::comphelper::getProcessComponentContext(),
153 OUString( "/org.openoffice.Office.Common" ),
154 ::comphelper::ConfigurationHelper::E_STANDARD );
155 if ( !xCommonConfig.is() )
156 throw uno::RuntimeException();
158 ::comphelper::ConfigurationHelper::readRelativeKey(
159 xCommonConfig,
160 OUString( "Misc/" ),
161 OUString( "UseDocumentSystemFileLocking" ) ) >>= bUseSystemLock;
163 catch( const uno::Exception& )
167 return bUseSystemLock;
170 //----------------------------------------------------------------
171 bool IsOOoLockFileUsed()
173 // check whether system file locking has been used, the default value is false
174 bool bOOoLockFileUsed = false;
178 uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig(
179 ::comphelper::getProcessComponentContext(),
180 OUString( "/org.openoffice.Office.Common" ),
181 ::comphelper::ConfigurationHelper::E_STANDARD );
182 if ( !xCommonConfig.is() )
183 throw uno::RuntimeException();
185 ::comphelper::ConfigurationHelper::readRelativeKey(
186 xCommonConfig,
187 OUString( "Misc/" ),
188 OUString( "UseDocumentOOoLockFile" ) ) >>= bOOoLockFileUsed;
190 catch( const uno::Exception& )
194 return bOOoLockFileUsed;
197 bool IsLockingUsed()
199 return officecfg::Office::Common::Misc::UseLocking::get();
202 #endif
204 } // anonymous namespace
205 //==========================================================
208 //----------------------------------------------------------------
209 class SfxMediumHandler_Impl : public ::cppu::WeakImplHelper1< com::sun::star::task::XInteractionHandler >
211 com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > m_xInter;
213 public:
214 virtual void SAL_CALL handle( const com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest >& xRequest )
215 throw( com::sun::star::uno::RuntimeException );
217 SfxMediumHandler_Impl( com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > xInteraction )
218 : m_xInter( xInteraction )
221 ~SfxMediumHandler_Impl();
224 //----------------------------------------------------------------
225 SfxMediumHandler_Impl::~SfxMediumHandler_Impl()
229 //----------------------------------------------------------------
230 void SAL_CALL SfxMediumHandler_Impl::handle( const com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest >& xRequest )
231 throw( com::sun::star::uno::RuntimeException )
233 if( !m_xInter.is() )
234 return;
236 com::sun::star::uno::Any aRequest = xRequest->getRequest();
237 com::sun::star::ucb::InteractiveIOException aIoException;
238 com::sun::star::ucb::UnsupportedDataSinkException aSinkException;
239 if ( (aRequest >>= aIoException) && ( aIoException.Code == IOErrorCode_ACCESS_DENIED || aIoException.Code == IOErrorCode_LOCKING_VIOLATION ) )
240 return;
241 else
242 if ( aRequest >>= aSinkException )
243 return;
244 else
245 m_xInter->handle( xRequest );
248 class SfxMedium_Impl : boost::noncopyable
250 public:
251 StreamMode m_nStorOpenMode;
252 sal_uInt32 m_eError;
254 ::ucbhelper::Content aContent;
255 bool bUpdatePickList:1;
256 bool bIsTemp:1;
257 bool bDownloadDone:1;
258 bool bIsStorage:1;
259 bool bUseInteractionHandler:1;
260 bool bAllowDefaultIntHdl:1;
261 bool bDisposeStorage:1;
262 bool bStorageBasedOnInStream:1;
263 bool m_bSalvageMode:1;
264 bool m_bVersionsAlreadyLoaded:1;
265 bool m_bLocked:1;
266 bool m_bGotDateTime:1;
267 bool m_bRemoveBackup:1;
268 bool m_bOriginallyReadOnly:1;
269 bool m_bTriedStorage:1;
270 bool m_bRemote:1;
271 bool m_bInputStreamIsReadOnly:1;
272 bool m_bInCheckIn:1;
274 OUString m_aName;
275 OUString m_aLogicName;
276 OUString m_aLongName;
278 mutable SfxItemSet* m_pSet;
279 mutable INetURLObject* m_pURLObj;
281 const SfxFilter* m_pFilter;
282 boost::scoped_ptr<SfxFilter> m_pCustomFilter;
284 SfxMedium* pAntiImpl;
285 SvStream* m_pInStream;
286 SvStream* m_pOutStream;
288 const SfxFilter* pOrigFilter;
289 OUString aOrigURL;
290 DateTime aExpireTime;
291 SfxFrameWeak wLoadTargetFrame;
292 SvKeyValueIteratorRef xAttributes;
294 svtools::AsynchronLink aDoneLink;
296 uno::Sequence < util::RevisionTag > aVersions;
298 ::utl::TempFile* pTempFile;
300 uno::Reference<embed::XStorage> xStorage;
301 uno::Reference<embed::XStorage> m_xZipStorage;
302 uno::Reference<io::XInputStream> m_xInputStreamToLoadFrom;
303 uno::Reference<io::XInputStream> xInputStream;
304 uno::Reference<io::XStream> xStream;
305 uno::Reference<io::XStream> m_xLockingStream;
306 uno::Reference<task::XInteractionHandler> xInteraction;
307 uno::Reference<logging::XSimpleLogRing> m_xLogRing;
309 sal_uInt32 nLastStorageError;
311 OUString m_aBackupURL;
313 // the following member is changed and makes sense only during saving
314 // TODO/LATER: in future the signature state should be controlled by the medium not by the document
315 // in this case the member will hold this information
316 sal_uInt16 m_nSignatureState;
318 util::DateTime m_aDateTime;
320 SfxMedium_Impl( SfxMedium* pAntiImplP );
321 ~SfxMedium_Impl();
323 OUString getFilterMimeType()
324 { return m_pFilter == 0 ? OUString() : m_pFilter->GetMimeType(); }
327 //------------------------------------------------------------------
328 SfxMedium_Impl::SfxMedium_Impl( SfxMedium* pAntiImplP ) :
329 m_nStorOpenMode(SFX_STREAM_READWRITE),
330 m_eError(SVSTREAM_OK),
331 bUpdatePickList(true),
332 bIsTemp( false ),
333 bDownloadDone( true ),
334 bIsStorage( false ),
335 bUseInteractionHandler( true ),
336 bAllowDefaultIntHdl( false ),
337 bDisposeStorage( false ),
338 bStorageBasedOnInStream( false ),
339 m_bSalvageMode( false ),
340 m_bVersionsAlreadyLoaded( false ),
341 m_bLocked( false ),
342 m_bGotDateTime( false ),
343 m_bRemoveBackup( false ),
344 m_bOriginallyReadOnly(false),
345 m_bTriedStorage(false),
346 m_bRemote(false),
347 m_bInputStreamIsReadOnly(false),
348 m_bInCheckIn(false),
349 m_pSet(NULL),
350 m_pURLObj(NULL),
351 m_pFilter(NULL),
352 pAntiImpl( pAntiImplP ),
353 m_pInStream(NULL),
354 m_pOutStream(NULL),
355 pOrigFilter( 0 ),
356 aExpireTime( Date( Date::SYSTEM ) + 10, Time( Time::SYSTEM ) ),
357 pTempFile( NULL ),
358 nLastStorageError( 0 ),
359 m_nSignatureState( SIGNATURESTATE_NOSIGNATURES )
361 aDoneLink.CreateMutex();
364 //------------------------------------------------------------------
365 SfxMedium_Impl::~SfxMedium_Impl()
367 aDoneLink.ClearPendingCall();
369 delete pTempFile;
370 delete m_pSet;
371 delete m_pURLObj;
374 void SfxMedium::ResetError()
376 pImp->m_eError = SVSTREAM_OK;
377 if( pImp->m_pInStream )
378 pImp->m_pInStream->ResetError();
379 if( pImp->m_pOutStream )
380 pImp->m_pOutStream->ResetError();
383 //------------------------------------------------------------------
384 sal_uInt32 SfxMedium::GetLastStorageCreationState()
386 return pImp->nLastStorageError;
389 //------------------------------------------------------------------
390 void SfxMedium::AddLog( const OUString& aMessage )
392 if ( !pImp->m_xLogRing.is() )
396 Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
397 pImp->m_xLogRing.set( logging::DocumentIOLogRing::get(xContext) );
399 catch( const uno::Exception& )
403 if ( pImp->m_xLogRing.is() )
404 pImp->m_xLogRing->logString( aMessage );
407 //------------------------------------------------------------------
408 void SfxMedium::SetError( sal_uInt32 nError, const OUString& aLogMessage )
410 pImp->m_eError = nError;
411 if ( pImp->m_eError != ERRCODE_NONE && !aLogMessage.isEmpty() )
412 AddLog( aLogMessage );
415 //------------------------------------------------------------------
416 sal_uInt32 SfxMedium::GetErrorCode() const
418 sal_uInt32 lError = pImp->m_eError;
419 if(!lError && pImp->m_pInStream)
420 lError = pImp->m_pInStream->GetErrorCode();
421 if(!lError && pImp->m_pOutStream)
422 lError = pImp->m_pOutStream->GetErrorCode();
423 return lError;
426 //------------------------------------------------------------------
427 void SfxMedium::CheckFileDate( const util::DateTime& aInitDate )
429 GetInitFileDate( true );
430 if ( pImp->m_aDateTime.Seconds != aInitDate.Seconds
431 || pImp->m_aDateTime.Minutes != aInitDate.Minutes
432 || pImp->m_aDateTime.Hours != aInitDate.Hours
433 || pImp->m_aDateTime.Day != aInitDate.Day
434 || pImp->m_aDateTime.Month != aInitDate.Month
435 || pImp->m_aDateTime.Year != aInitDate.Year )
437 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
439 if ( xHandler.is() )
443 ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
444 document::ChangedByOthersRequest() ) );
445 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 );
446 aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
447 aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
448 xInteractionRequestImpl->setContinuations( aContinuations );
450 xHandler->handle( xInteractionRequestImpl.get() );
452 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
453 if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() )
455 SetError( ERRCODE_ABORT, OUString( OSL_LOG_PREFIX ) );
458 catch ( const uno::Exception& )
464 //------------------------------------------------------------------
465 sal_Bool SfxMedium::DocNeedsFileDateCheck()
467 return ( !IsReadOnly() && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) );
470 //------------------------------------------------------------------
471 util::DateTime SfxMedium::GetInitFileDate( sal_Bool bIgnoreOldValue )
473 if ( ( bIgnoreOldValue || !pImp->m_bGotDateTime ) && !pImp->m_aLogicName.isEmpty() )
477 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
478 ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, comphelper::getProcessComponentContext() );
480 aContent.getPropertyValue( OUString("DateModified" ) ) >>= pImp->m_aDateTime;
481 pImp->m_bGotDateTime = true;
483 catch ( const ::com::sun::star::uno::Exception& )
488 return pImp->m_aDateTime;
491 //------------------------------------------------------------------
492 Reference < XContent > SfxMedium::GetContent() const
494 if ( !pImp->aContent.get().is() )
496 Reference < ::com::sun::star::ucb::XContent > xContent;
497 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
499 SFX_ITEMSET_ARG( pImp->m_pSet, pItem, SfxUnoAnyItem, SID_CONTENT, false);
500 if ( pItem )
501 pItem->GetValue() >>= xContent;
503 if ( xContent.is() )
507 pImp->aContent = ::ucbhelper::Content( xContent, xEnv, comphelper::getProcessComponentContext() );
509 catch ( const Exception& )
513 else
515 // TODO: OSL_FAIL("SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why its used.");
516 OUString aURL;
517 if ( !pImp->m_aName.isEmpty() )
518 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aURL );
519 else if ( !pImp->m_aLogicName.isEmpty() )
520 aURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
521 if (!aURL.isEmpty() )
522 ::ucbhelper::Content::create( aURL, xEnv, comphelper::getProcessComponentContext(), pImp->aContent );
526 return pImp->aContent.get();
529 //------------------------------------------------------------------
530 OUString SfxMedium::GetBaseURL( bool bForSaving )
532 OUString aBaseURL;
533 const SfxStringItem* pBaseURLItem = static_cast<const SfxStringItem*>( GetItemSet()->GetItem(SID_DOC_BASEURL) );
534 if ( pBaseURLItem )
535 aBaseURL = pBaseURLItem->GetValue();
536 else if ( GetContent().is() )
540 Any aAny = pImp->aContent.getPropertyValue( OUString("BaseURI" ) );
541 aAny >>= aBaseURL;
543 catch ( const ::com::sun::star::uno::Exception& )
547 if ( aBaseURL.isEmpty() )
548 aBaseURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
551 if ( bForSaving )
553 SvtSaveOptions aOpt;
554 bool bIsRemote = IsRemote();
555 if( (bIsRemote && !aOpt.IsSaveRelINet()) || (!pImp->m_bRemote && !aOpt.IsSaveRelFSys()) )
556 return OUString();
559 return aBaseURL;
562 //------------------------------------------------------------------
563 SvStream* SfxMedium::GetInStream()
565 if ( pImp->m_pInStream )
566 return pImp->m_pInStream;
568 if ( pImp->pTempFile )
570 pImp->m_pInStream = new SvFileStream(pImp->m_aName, pImp->m_nStorOpenMode);
572 pImp->m_eError = pImp->m_pInStream->GetError();
574 if (!pImp->m_eError && (pImp->m_nStorOpenMode & STREAM_WRITE)
575 && ! pImp->m_pInStream->IsWritable() )
577 pImp->m_eError = ERRCODE_IO_ACCESSDENIED;
578 delete pImp->m_pInStream;
579 pImp->m_pInStream = NULL;
581 else
582 return pImp->m_pInStream;
585 GetMedium_Impl();
587 if ( GetError() )
588 return NULL;
590 return pImp->m_pInStream;
593 //------------------------------------------------------------------
594 void SfxMedium::CloseInStream()
596 CloseInStream_Impl();
599 void SfxMedium::CloseInStream_Impl()
601 // if there is a storage based on the InStream, we have to
602 // close the storage, too, because otherwise the storage
603 // would use an invalid ( deleted ) stream.
604 if ( pImp->m_pInStream && pImp->xStorage.is() )
606 if ( pImp->bStorageBasedOnInStream )
607 CloseStorage();
610 if ( pImp->m_pInStream && !GetContent().is() )
612 CreateTempFile( true );
613 return;
616 DELETEZ( pImp->m_pInStream );
617 if ( pImp->m_pSet )
618 pImp->m_pSet->ClearItem( SID_INPUTSTREAM );
620 CloseZipStorage_Impl();
621 pImp->xInputStream.clear();
623 if ( !pImp->m_pOutStream )
625 // output part of the stream is not used so the whole stream can be closed
626 // TODO/LATER: is it correct?
627 pImp->xStream.clear();
628 if ( pImp->m_pSet )
629 pImp->m_pSet->ClearItem( SID_STREAM );
633 //------------------------------------------------------------------
634 SvStream* SfxMedium::GetOutStream()
636 if ( !pImp->m_pOutStream )
638 // Create a temp. file if there is none because we always
639 // need one.
640 CreateTempFile( false );
642 if ( pImp->pTempFile )
644 // On windows we try to re-use XOutStream from xStream if that exists;
645 // because opening new SvFileStream in this situation may fail with ERROR_SHARING_VIOLATION
646 #ifdef WNT
647 if (pImp->xStream.is())
649 assert(pImp->xStream->getOutputStream().is()); // need that...
650 pImp->m_pOutStream = utl::UcbStreamHelper::CreateStream(
651 pImp->xStream, false);
653 else
655 pImp->m_pOutStream = new SvFileStream(
656 pImp->m_aName, STREAM_STD_READWRITE);
658 // On Unix don't try to re-use XOutStream from xStream if that exists;
659 // it causes fdo#59022 (fails opening files via SMB on Linux)
660 #else
661 pImp->m_pOutStream = new SvFileStream(
662 pImp->m_aName, STREAM_STD_READWRITE);
663 #endif
664 CloseStorage();
668 return pImp->m_pOutStream;
671 //------------------------------------------------------------------
672 sal_Bool SfxMedium::CloseOutStream()
674 CloseOutStream_Impl();
675 return true;
678 sal_Bool SfxMedium::CloseOutStream_Impl()
680 if ( pImp->m_pOutStream )
682 // if there is a storage based on the OutStream, we have to
683 // close the storage, too, because otherwise the storage
684 // would use an invalid ( deleted ) stream.
685 //TODO/MBA: how to deal with this?!
686 //maybe we need a new flag when the storage was created from the outstream
687 if ( pImp->xStorage.is() )
689 CloseStorage();
692 delete pImp->m_pOutStream;
693 pImp->m_pOutStream = NULL;
696 if ( !pImp->m_pInStream )
698 // input part of the stream is not used so the whole stream can be closed
699 // TODO/LATER: is it correct?
700 pImp->xStream.clear();
701 if ( pImp->m_pSet )
702 pImp->m_pSet->ClearItem( SID_STREAM );
705 return true;
708 //------------------------------------------------------------------
709 const OUString& SfxMedium::GetPhysicalName() const
711 if ( pImp->m_aName.isEmpty() && !pImp->m_aLogicName.isEmpty() )
712 (( SfxMedium*)this)->CreateFileStream();
714 // return the name then
715 return pImp->m_aName;
718 //------------------------------------------------------------------
719 void SfxMedium::CreateFileStream()
721 ForceSynchronStream_Impl( true );
722 GetInStream();
723 if( pImp->m_pInStream )
725 CreateTempFile( false );
726 pImp->bIsTemp = true;
727 CloseInStream_Impl();
731 //------------------------------------------------------------------
732 sal_Bool SfxMedium::Commit()
734 if( pImp->xStorage.is() )
735 StorageCommit_Impl();
736 else if( pImp->m_pOutStream )
737 pImp->m_pOutStream->Flush();
738 else if( pImp->m_pInStream )
739 pImp->m_pInStream->Flush();
741 if ( GetError() == SVSTREAM_OK )
743 // does something only in case there is a temporary file ( means aName points to different location than aLogicName )
744 Transfer_Impl();
747 bool bResult = ( GetError() == SVSTREAM_OK );
749 if ( bResult && DocNeedsFileDateCheck() )
750 GetInitFileDate( true );
752 // remove truncation mode from the flags
753 pImp->m_nStorOpenMode &= (~STREAM_TRUNC);
754 return bResult;
757 //------------------------------------------------------------------
758 sal_Bool SfxMedium::IsStorage()
760 if ( pImp->xStorage.is() )
761 return true;
763 if ( pImp->m_bTriedStorage )
764 return pImp->bIsStorage;
766 if ( pImp->pTempFile )
768 OUString aURL;
769 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aURL ) )
771 OSL_FAIL("Physical name not convertible!");
773 pImp->bIsStorage = SotStorage::IsStorageFile( aURL ) && !SotStorage::IsOLEStorage( aURL);
774 if ( !pImp->bIsStorage )
775 pImp->m_bTriedStorage = true;
777 else if ( GetInStream() )
779 pImp->bIsStorage = SotStorage::IsStorageFile( pImp->m_pInStream ) && !SotStorage::IsOLEStorage( pImp->m_pInStream );
780 if ( !pImp->m_pInStream->GetError() && !pImp->bIsStorage )
781 pImp->m_bTriedStorage = true;
784 return pImp->bIsStorage;
787 //------------------------------------------------------------------
788 sal_Bool SfxMedium::IsPreview_Impl()
790 bool bPreview = false;
791 SFX_ITEMSET_ARG( GetItemSet(), pPreview, SfxBoolItem, SID_PREVIEW, false);
792 if ( pPreview )
793 bPreview = pPreview->GetValue();
794 else
796 SFX_ITEMSET_ARG( GetItemSet(), pFlags, SfxStringItem, SID_OPTIONS, false);
797 if ( pFlags )
799 String aFileFlags = pFlags->GetValue();
800 aFileFlags.ToUpperAscii();
801 if ( STRING_NOTFOUND != aFileFlags.Search( 'B' ) )
802 bPreview = true;
806 return bPreview;
809 //------------------------------------------------------------------
810 void SfxMedium::StorageBackup_Impl()
812 ::ucbhelper::Content aOriginalContent;
813 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
815 bool bBasedOnOriginalFile = ( !pImp->pTempFile && !( !pImp->m_aLogicName.isEmpty() && pImp->m_bSalvageMode )
816 && !GetURLObject().GetMainURL( INetURLObject::NO_DECODE ).isEmpty()
817 && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
818 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) );
820 if ( bBasedOnOriginalFile && pImp->m_aBackupURL.isEmpty()
821 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, comphelper::getProcessComponentContext(), aOriginalContent ) )
823 DoInternalBackup_Impl( aOriginalContent );
824 if( pImp->m_aBackupURL.isEmpty() )
825 SetError( ERRCODE_SFX_CANTCREATEBACKUP, OUString( OSL_LOG_PREFIX ) );
829 //------------------------------------------------------------------
830 OUString SfxMedium::GetBackup_Impl()
832 if ( pImp->m_aBackupURL.isEmpty() )
833 StorageBackup_Impl();
835 return pImp->m_aBackupURL;
838 //------------------------------------------------------------------
839 uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage()
841 if ( GetError() )
842 return uno::Reference< embed::XStorage >();
844 // if the medium was constructed with a Storage: use this one, not a temp. storage
845 // if a temporary storage already exists: use it
846 if ( pImp->xStorage.is() && ( pImp->m_aLogicName.isEmpty() || pImp->pTempFile ) )
847 return pImp->xStorage;
849 // if necessary close stream that was used for reading
850 if ( pImp->m_pInStream && !pImp->m_pInStream->IsWritable() )
851 CloseInStream();
853 DBG_ASSERT( !pImp->m_pOutStream, "OutStream in a readonly Medium?!" );
855 // TODO/LATER: The current solution is to store the document temporary and then copy it to the target location;
856 // in future it should be stored directly and then copied to the temporary location, since in this case no
857 // file attributes have to be preserved and system copying mechanics could be used instead of streaming.
858 CreateTempFileNoCopy();
860 return GetStorage();
863 //------------------------------------------------------------------
864 void SfxMedium::SetEncryptionDataToStorage_Impl()
866 // in case media-descriptor contains password it should be used on opening
867 if ( pImp->xStorage.is() && pImp->m_pSet )
869 uno::Sequence< beans::NamedValue > aEncryptionData;
870 if ( GetEncryptionData_Impl( pImp->m_pSet, aEncryptionData ) )
872 // replace the password with encryption data
873 pImp->m_pSet->ClearItem( SID_PASSWORD );
874 pImp->m_pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
878 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( pImp->xStorage, aEncryptionData );
880 catch( const uno::Exception& )
882 OSL_FAIL( "It must be possible to set a common password for the storage" );
883 // TODO/LATER: set the error code in case of problem
884 // SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
890 //------------------------------------------------------------------
891 sal_Int8 SfxMedium::ShowLockedDocumentDialog( const uno::Sequence< OUString >& aData, sal_Bool bIsLoading, sal_Bool bOwnLock )
893 sal_Int8 nResult = LOCK_UI_NOLOCK;
895 // show the interaction regarding the document opening
896 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
898 if ( ::svt::DocumentLockFile::IsInteractionAllowed() && xHandler.is() && ( bIsLoading || bOwnLock ) )
900 OUString aDocumentURL = GetURLObject().GetLastName();
901 OUString aInfo;
902 ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl;
904 if ( bOwnLock )
906 if ( aData.getLength() > LOCKFILE_EDITTIME_ID )
907 aInfo = aData[LOCKFILE_EDITTIME_ID];
909 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
910 document::OwnLockOnDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo, !bIsLoading ) ) );
912 else
914 if ( aData.getLength() > LOCKFILE_EDITTIME_ID )
916 if ( !aData[LOCKFILE_OOOUSERNAME_ID].isEmpty() )
917 aInfo = aData[LOCKFILE_OOOUSERNAME_ID];
918 else
919 aInfo = aData[LOCKFILE_SYSUSERNAME_ID];
921 if ( !aInfo.isEmpty() && !aData[LOCKFILE_EDITTIME_ID].isEmpty() )
923 aInfo += OUString( " ( " );
924 aInfo += aData[LOCKFILE_EDITTIME_ID];
925 aInfo += OUString( " )" );
929 if ( bIsLoading )
931 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
932 document::LockedDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
934 else
936 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
937 document::LockedOnSavingRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
942 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 );
943 aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
944 aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
945 aContinuations[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl.get() );
946 xInteractionRequestImpl->setContinuations( aContinuations );
948 xHandler->handle( xInteractionRequestImpl.get() );
950 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
951 if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() )
953 SetError( ERRCODE_ABORT, OUString( OSL_LOG_PREFIX ) );
955 else if ( uno::Reference< task::XInteractionDisapprove >( xSelected.get(), uno::UNO_QUERY ).is() )
957 // own lock on loading, user has selected to ignore the lock
958 // own lock on saving, user has selected to ignore the lock
959 // alien lock on loading, user has selected to edit a copy of document
960 // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location
961 if ( bIsLoading && !bOwnLock )
963 // means that a copy of the document should be opened
964 GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, true ) );
966 else if ( bOwnLock )
967 nResult = LOCK_UI_SUCCEEDED;
969 else // if ( XSelected == aContinuations[1] )
971 // own lock on loading, user has selected to open readonly
972 // own lock on saving, user has selected to open readonly
973 // alien lock on loading, user has selected to retry saving
974 // TODO/LATER: alien lock on saving, user has selected to retry saving
976 if ( bIsLoading )
977 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
978 else
979 nResult = LOCK_UI_TRY;
982 else
984 if ( bIsLoading )
986 // if no interaction handler is provided the default answer is open readonly
987 // that usually happens in case the document is loaded per API
988 // so the document must be opened readonly for backward compatibility
989 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
991 else
992 SetError( ERRCODE_IO_ACCESSDENIED, OUString( OSL_LOG_PREFIX ) );
996 return nResult;
999 namespace
1001 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1002 bool isSuitableProtocolForLocking(const String & rLogicName)
1004 INetURLObject aUrl( rLogicName );
1005 INetProtocol eProt = aUrl.GetProtocol();
1006 return eProt == INET_PROT_FILE || eProt == INET_PROT_SFTP;
1008 #endif
1011 // returns true if the document can be opened for editing ( even if it should be a copy )
1012 // otherwise the document should be opened readonly
1013 // if user cancel the loading the ERROR_ABORT is set
1014 bool SfxMedium::LockOrigFileOnDemand( sal_Bool bLoading, sal_Bool bNoUI )
1016 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1017 (void) bLoading;
1018 (void) bNoUI;
1019 return true;
1020 #else
1021 if (!IsLockingUsed())
1022 return true;
1024 if ( GetURLObject().HasError() )
1025 return false;
1027 bool bResult = false;
1030 if ( pImp->m_bLocked && bLoading && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
1032 // if the document is already locked the system locking might be temporarely off after storing
1033 // check whether the system file locking should be taken again
1034 GetLockingStream_Impl();
1037 bResult = pImp->m_bLocked;
1039 if ( !bResult )
1041 // no read-write access is necessary on loading if the document is explicitly opened as copy
1042 SFX_ITEMSET_ARG( GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, false);
1043 bResult = ( bLoading && pTemplateItem && pTemplateItem->GetValue() );
1046 if ( !bResult && !IsReadOnly() )
1048 bool bContentReadonly = false;
1049 if ( bLoading && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
1051 // let the original document be opened to check the possibility to open it for editing
1052 // and to let the writable stream stay open to hold the lock on the document
1053 GetLockingStream_Impl();
1056 // "IsReadOnly" property does not allow to detect whether the file is readonly always
1057 // so we try always to open the file for editing
1058 // the file is readonly only in case the read-write stream can not be opened
1059 if ( bLoading && !pImp->m_xLockingStream.is() )
1063 // MediaDescriptor does this check also, the duplication should be avoided in future
1064 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1065 ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, comphelper::getProcessComponentContext() );
1066 aContent.getPropertyValue( OUString( "IsReadOnly" ) ) >>= bContentReadonly;
1068 catch( const uno::Exception& ) {}
1070 #if EXTRA_ACL_CHECK
1071 // This block was introduced as a fix to i#102464, but removing
1072 // this does not make the problem re-appear. But leaving this
1073 // part would interfere with documents saved in samba share. This
1074 // affects Windows only.
1075 if ( !bContentReadonly )
1077 // the file is not readonly, check the ACL
1079 String aPhysPath;
1080 if ( ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), aPhysPath ) )
1081 bContentReadonly = IsReadonlyAccordingACL( aPhysPath.GetBuffer() );
1083 #endif
1085 if ( bContentReadonly )
1086 pImp->m_bOriginallyReadOnly = true;
1089 // do further checks only if the file not readonly in fs
1090 if ( !bContentReadonly )
1092 // the special file locking should be used only for suitable URLs
1093 if ( isSuitableProtocolForLocking( pImp->m_aLogicName ) )
1096 // in case of storing the document should request the output before locking
1097 if ( bLoading )
1099 // let the stream be opened to check the system file locking
1100 GetMedium_Impl();
1103 sal_Int8 bUIStatus = LOCK_UI_NOLOCK;
1105 // check whether system file locking has been used, the default value is false
1106 bool bUseSystemLock = ::utl::LocalFileHelper::IsLocalFile( pImp->m_aLogicName ) && IsSystemFileLockingUsed();
1108 // TODO/LATER: This implementation does not allow to detect the system lock on saving here, actually this is no big problem
1109 // if system lock is used the writeable stream should be available
1110 bool bHandleSysLocked = ( bLoading && bUseSystemLock && !pImp->xStream.is() && !pImp->m_pOutStream );
1116 ::svt::DocumentLockFile aLockFile( pImp->m_aLogicName );
1117 if ( !bHandleSysLocked )
1121 bResult = aLockFile.CreateOwnLockFile();
1123 catch ( const ucb::InteractiveIOException& e )
1125 // exception means that the lock file can not be successfully accessed
1126 // in this case it should be ignored if system file locking is anyway active
1127 if ( bUseSystemLock || !IsOOoLockFileUsed() )
1129 bResult = true;
1130 // take the ownership over the lock file
1131 aLockFile.OverwriteOwnLockFile();
1133 else if ( e.Code == IOErrorCode_INVALID_PARAMETER )
1135 // system file locking is not active, ask user whether he wants to open the document without any locking
1136 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
1138 if ( xHandler.is() )
1140 ::rtl::Reference< ::ucbhelper::InteractionRequest > xIgnoreRequestImpl
1141 = new ::ucbhelper::InteractionRequest( uno::makeAny( document::LockFileIgnoreRequest() ) );
1143 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 2 );
1144 aContinuations[0] = new ::ucbhelper::InteractionAbort( xIgnoreRequestImpl.get() );
1145 aContinuations[1] = new ::ucbhelper::InteractionApprove( xIgnoreRequestImpl.get() );
1146 xIgnoreRequestImpl->setContinuations( aContinuations );
1148 xHandler->handle( xIgnoreRequestImpl.get() );
1150 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xIgnoreRequestImpl->getSelection();
1151 bResult = uno::Reference< task::XInteractionApprove >( xSelected.get(), uno::UNO_QUERY ).is();
1155 catch ( const uno::Exception& )
1157 // exception means that the lock file can not be successfully accessed
1158 // in this case it should be ignored if system file locking is anyway active
1159 if ( bUseSystemLock || !IsOOoLockFileUsed() )
1161 bResult = true;
1162 // take the ownership over the lock file
1163 aLockFile.OverwriteOwnLockFile();
1167 // in case OOo locking is turned off the lock file is still written if possible
1168 // but it is ignored while deciding whether the document should be opened for editing or not
1169 if ( !bResult && !IsOOoLockFileUsed() )
1171 bResult = true;
1172 // take the ownership over the lock file
1173 aLockFile.OverwriteOwnLockFile();
1178 if ( !bResult )
1180 uno::Sequence< OUString > aData;
1183 // impossibility to get data is no real problem
1184 aData = aLockFile.GetLockData();
1186 catch( const uno::Exception& )
1190 bool bOwnLock = false;
1192 if ( !bHandleSysLocked )
1194 uno::Sequence< OUString > aOwnData = aLockFile.GenerateOwnEntry();
1195 bOwnLock = ( aData.getLength() > LOCKFILE_USERURL_ID
1196 && aOwnData.getLength() > LOCKFILE_USERURL_ID
1197 && aOwnData[LOCKFILE_SYSUSERNAME_ID].equals( aData[LOCKFILE_SYSUSERNAME_ID] ) );
1199 if ( bOwnLock
1200 && aOwnData[LOCKFILE_LOCALHOST_ID].equals( aData[LOCKFILE_LOCALHOST_ID] )
1201 && aOwnData[LOCKFILE_USERURL_ID].equals( aData[LOCKFILE_USERURL_ID] ) )
1203 // this is own lock from the same installation, it could remain because of crash
1204 bResult = true;
1208 if ( !bResult && !bNoUI )
1210 bUIStatus = ShowLockedDocumentDialog( aData, bLoading, bOwnLock );
1211 if ( bUIStatus == LOCK_UI_SUCCEEDED )
1213 // take the ownership over the lock file
1214 bResult = aLockFile.OverwriteOwnLockFile();
1218 bHandleSysLocked = false;
1221 catch( const uno::Exception& )
1224 } while( !bResult && bUIStatus == LOCK_UI_TRY );
1226 pImp->m_bLocked = bResult;
1228 else
1230 // this is no file URL, check whether the file is readonly
1231 bResult = !bContentReadonly;
1236 if ( !bResult && GetError() == ERRCODE_NONE )
1238 // the error should be set in case it is storing process
1239 // or the document has been opened for editing explicitly
1240 SFX_ITEMSET_ARG( pImp->m_pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, false );
1242 if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) )
1243 SetError( ERRCODE_IO_ACCESSDENIED, OUString( OSL_LOG_PREFIX ) );
1244 else
1245 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1248 // when the file is locked, get the current file date
1249 if ( bResult && DocNeedsFileDateCheck() )
1250 GetInitFileDate( true );
1252 catch( const uno::Exception& )
1254 OSL_FAIL( "Locking exception: high probability, that the content has not been created" );
1256 return bResult;
1257 #endif
1260 //------------------------------------------------------------------
1261 uno::Reference < embed::XStorage > SfxMedium::GetStorage( sal_Bool bCreateTempIfNo )
1263 if ( pImp->xStorage.is() || pImp->m_bTriedStorage )
1264 return pImp->xStorage;
1266 uno::Sequence< uno::Any > aArgs( 2 );
1268 // the medium should be retrieved before temporary file creation
1269 // to let the MediaDescriptor be filled with the streams
1270 GetMedium_Impl();
1272 if ( bCreateTempIfNo )
1273 CreateTempFile( false );
1275 GetMedium_Impl();
1277 if ( GetError() )
1278 return pImp->xStorage;
1280 SFX_ITEMSET_ARG( GetItemSet(), pRepairItem, SfxBoolItem, SID_REPAIRPACKAGE, false);
1281 if ( pRepairItem && pRepairItem->GetValue() )
1283 // the storage should be created for repairing mode
1284 CreateTempFile( false );
1285 GetMedium_Impl();
1287 Reference< ::com::sun::star::ucb::XProgressHandler > xProgressHandler;
1288 Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
1290 SFX_ITEMSET_ARG( GetItemSet(), pxProgressItem, SfxUnoAnyItem, SID_PROGRESS_STATUSBAR_CONTROL, false );
1291 if( pxProgressItem && ( pxProgressItem->GetValue() >>= xStatusIndicator ) )
1292 xProgressHandler = Reference< ::com::sun::star::ucb::XProgressHandler >(
1293 new utl::ProgressHandlerWrap( xStatusIndicator ) );
1295 uno::Sequence< beans::PropertyValue > aAddProps( 2 );
1296 aAddProps[0].Name = OUString("RepairPackage");
1297 aAddProps[0].Value <<= (sal_Bool)true;
1298 aAddProps[1].Name = OUString("StatusIndicator");
1299 aAddProps[1].Value <<= xProgressHandler;
1301 // the first arguments will be filled later
1302 aArgs.realloc( 3 );
1303 aArgs[2] <<= aAddProps;
1306 if ( pImp->xStream.is() )
1308 // since the storage is based on temporary stream we open it always read-write
1309 aArgs[0] <<= pImp->xStream;
1310 aArgs[1] <<= embed::ElementModes::READWRITE;
1311 pImp->bStorageBasedOnInStream = true;
1313 else if ( pImp->xInputStream.is() )
1315 // since the storage is based on temporary stream we open it always read-write
1316 aArgs[0] <<= pImp->xInputStream;
1317 aArgs[1] <<= embed::ElementModes::READ;
1318 pImp->bStorageBasedOnInStream = true;
1320 else
1322 CloseStreams_Impl();
1323 aArgs[0] <<= pImp->m_aName;
1324 aArgs[1] <<= embed::ElementModes::READ;
1325 pImp->bStorageBasedOnInStream = false;
1330 pImp->xStorage = uno::Reference< embed::XStorage >(
1331 ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ),
1332 uno::UNO_QUERY );
1334 catch( const uno::Exception& )
1336 // impossibility to create the storage is no error
1339 if( ( pImp->nLastStorageError = GetError() ) != SVSTREAM_OK )
1341 pImp->xStorage = 0;
1342 if ( pImp->m_pInStream )
1343 pImp->m_pInStream->Seek(0);
1344 return uno::Reference< embed::XStorage >();
1347 pImp->m_bTriedStorage = true;
1349 // TODO/LATER: Get versionlist on demand
1350 if ( pImp->xStorage.is() )
1352 SetEncryptionDataToStorage_Impl();
1353 GetVersionList();
1356 SFX_ITEMSET_ARG( pImp->m_pSet, pVersion, SfxInt16Item, SID_VERSION, false);
1358 bool bResetStorage = false;
1359 if ( pVersion && pVersion->GetValue() )
1361 // Read all available versions
1362 if ( pImp->aVersions.getLength() )
1364 // Search for the version fits the comment
1365 // The versions are numbered startign with 1, versions with
1366 // negative versions numbers are counted backwards from the
1367 // current version
1368 short nVersion = pVersion ? pVersion->GetValue() : 0;
1369 if ( nVersion<0 )
1370 nVersion = ( (short) pImp->aVersions.getLength() ) + nVersion;
1371 else if ( nVersion )
1372 nVersion--;
1374 util::RevisionTag& rTag = pImp->aVersions[nVersion];
1376 // Open SubStorage for all versions
1377 uno::Reference < embed::XStorage > xSub = pImp->xStorage->openStorageElement( "Versions",
1378 embed::ElementModes::READ );
1380 DBG_ASSERT( xSub.is(), "Version list, but no Versions!" );
1382 // There the version is stored as packed Stream
1383 uno::Reference < io::XStream > xStr = xSub->openStreamElement( rTag.Identifier, embed::ElementModes::READ );
1384 SvStream* pStream = utl::UcbStreamHelper::CreateStream( xStr );
1385 if ( pStream && pStream->GetError() == SVSTREAM_OK )
1387 // Unpack Stream in TempDir
1388 ::utl::TempFile aTempFile;
1389 String aTmpName = aTempFile.GetURL();
1390 SvFileStream aTmpStream( aTmpName, SFX_STREAM_READWRITE );
1392 *pStream >> aTmpStream;
1393 aTmpStream.Close();
1395 // Open data as Storage
1396 pImp->m_nStorOpenMode = SFX_STREAM_READONLY;
1397 pImp->xStorage = comphelper::OStorageHelper::GetStorageFromURL( aTmpName, embed::ElementModes::READ );
1398 pImp->bStorageBasedOnInStream = false;
1399 OUString aTemp;
1400 ::utl::LocalFileHelper::ConvertURLToPhysicalName( aTmpName, aTemp );
1401 SetPhysicalName_Impl( aTemp );
1403 pImp->bIsTemp = true;
1404 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1405 // TODO/MBA
1406 pImp->aVersions.realloc(0);
1408 else
1409 bResetStorage = true;
1412 else
1413 bResetStorage = true;
1416 if ( bResetStorage )
1418 pImp->xStorage.clear();
1419 if ( pImp->m_pInStream )
1420 pImp->m_pInStream->Seek( 0L );
1423 pImp->bIsStorage = pImp->xStorage.is();
1424 return pImp->xStorage;
1427 //------------------------------------------------------------------
1428 uno::Reference< embed::XStorage > SfxMedium::GetZipStorageToSign_Impl( sal_Bool bReadOnly )
1430 if ( !GetError() && !pImp->m_xZipStorage.is() )
1432 GetMedium_Impl();
1436 // we can not sign document if there is no stream
1437 // should it be possible at all?
1438 if ( !bReadOnly && pImp->xStream.is() )
1440 pImp->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImp->xStream, embed::ElementModes::READWRITE );
1442 else if ( pImp->xInputStream.is() )
1444 pImp->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( ZIP_STORAGE_FORMAT_STRING, pImp->xInputStream );
1447 catch( const uno::Exception& )
1449 OSL_FAIL( "No possibility to get readonly version of storage from medium!\n" );
1452 if ( GetError() ) // do not remove warnings
1453 ResetError();
1456 return pImp->m_xZipStorage;
1459 //------------------------------------------------------------------
1460 void SfxMedium::CloseZipStorage_Impl()
1462 if ( pImp->m_xZipStorage.is() )
1464 try {
1465 pImp->m_xZipStorage->dispose();
1466 } catch( const uno::Exception& )
1469 pImp->m_xZipStorage.clear();
1473 void SfxMedium::CloseStorage()
1475 if ( pImp->xStorage.is() )
1477 uno::Reference < lang::XComponent > xComp( pImp->xStorage, uno::UNO_QUERY );
1478 // in the salvage mode the medium does not own the storage
1479 if ( pImp->bDisposeStorage && !pImp->m_bSalvageMode )
1481 try {
1482 xComp->dispose();
1483 } catch( const uno::Exception& )
1485 OSL_FAIL( "Medium's storage is already disposed!\n" );
1489 pImp->xStorage.clear();
1490 pImp->bStorageBasedOnInStream = false;
1493 pImp->m_bTriedStorage = false;
1494 pImp->bIsStorage = false;
1497 void SfxMedium::CanDisposeStorage_Impl( sal_Bool bDisposeStorage )
1499 pImp->bDisposeStorage = bDisposeStorage;
1502 sal_Bool SfxMedium::WillDisposeStorageOnClose_Impl()
1504 return pImp->bDisposeStorage;
1507 StreamMode SfxMedium::GetOpenMode() const
1509 return pImp->m_nStorOpenMode;
1512 void SfxMedium::SetOpenMode( StreamMode nStorOpen,
1513 sal_Bool bDontClose )
1515 if ( pImp->m_nStorOpenMode != nStorOpen )
1517 pImp->m_nStorOpenMode = nStorOpen;
1519 if( !bDontClose )
1521 if ( pImp->xStorage.is() )
1522 CloseStorage();
1524 CloseStreams_Impl();
1529 //------------------------------------------------------------------
1530 sal_Bool SfxMedium::UseBackupToRestore_Impl( ::ucbhelper::Content& aOriginalContent,
1531 const Reference< ::com::sun::star::ucb::XCommandEnvironment >& xComEnv )
1535 ::ucbhelper::Content aTransactCont( pImp->m_aBackupURL, xComEnv, comphelper::getProcessComponentContext() );
1537 Reference< XInputStream > aOrigInput = aTransactCont.openStream();
1538 aOriginalContent.writeStream( aOrigInput, true );
1539 return true;
1541 catch( const Exception& )
1543 // in case of failure here the backup file should not be removed
1544 // TODO/LATER: a message should be used to let user know about the backup
1545 pImp->m_bRemoveBackup = false;
1546 // TODO/LATER: needs a specific error code
1547 pImp->m_eError = ERRCODE_IO_GENERAL;
1550 return false;
1553 //------------------------------------------------------------------
1554 sal_Bool SfxMedium::StorageCommit_Impl()
1556 bool bResult = false;
1557 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1558 ::ucbhelper::Content aOriginalContent;
1560 if ( pImp->xStorage.is() )
1562 if ( !GetError() )
1564 uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY );
1565 if ( xTrans.is() )
1569 xTrans->commit();
1570 CloseZipStorage_Impl();
1571 bResult = true;
1573 catch ( const embed::UseBackupException& aBackupExc )
1575 // since the temporary file is created always now, the scenario is close to be impossible
1576 if ( !pImp->pTempFile )
1578 OSL_ENSURE( !pImp->m_aBackupURL.isEmpty(), "No backup on storage commit!\n" );
1579 if ( !pImp->m_aBackupURL.isEmpty()
1580 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ),
1581 xDummyEnv, comphelper::getProcessComponentContext(),
1582 aOriginalContent ) )
1584 // use backup to restore the file
1585 // the storage has already disconnected from original location
1586 CloseAndReleaseStreams_Impl();
1587 if ( !UseBackupToRestore_Impl( aOriginalContent, xDummyEnv ) )
1589 // connect the medium to the temporary file of the storage
1590 pImp->aContent = ::ucbhelper::Content();
1591 pImp->m_aName = aBackupExc.TemporaryFileURL;
1592 OSL_ENSURE( !pImp->m_aName.isEmpty(), "The exception _must_ contain the temporary URL!\n" );
1596 if ( !GetError() )
1597 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1600 catch ( const uno::Exception& )
1602 //TODO/LATER: improve error handling
1603 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1609 return bResult;
1612 //------------------------------------------------------------------
1613 sal_Bool SfxMedium::TransactedTransferForFS_Impl( const INetURLObject& aSource,
1614 const INetURLObject& aDest,
1615 const Reference< ::com::sun::star::ucb::XCommandEnvironment >& xComEnv )
1617 bool bResult = false;
1618 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1619 Reference< XOutputStream > aDestStream;
1620 ::ucbhelper::Content aOriginalContent;
1624 aOriginalContent = ::ucbhelper::Content( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext() );
1626 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
1628 pImp->m_eError = ERRCODE_ABORT;
1630 catch ( const ::com::sun::star::ucb::CommandFailedException& )
1632 pImp->m_eError = ERRCODE_ABORT;
1634 catch (const ::com::sun::star::ucb::ContentCreationException& ex)
1636 pImp->m_eError = ERRCODE_IO_GENERAL;
1637 if (
1638 (ex.eError == ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
1639 (ex.eError == ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
1642 pImp->m_eError = ERRCODE_IO_NOTEXISTSPATH;
1645 catch (const ::com::sun::star::uno::Exception&)
1647 pImp->m_eError = ERRCODE_IO_GENERAL;
1650 if( !pImp->m_eError || (pImp->m_eError & ERRCODE_WARNING_MASK) )
1652 if ( pImp->xStorage.is() )
1653 CloseStorage();
1655 CloseStreams_Impl();
1657 ::ucbhelper::Content aTempCont;
1658 if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, comphelper::getProcessComponentContext(), aTempCont ) )
1660 bool bTransactStarted = false;
1661 SFX_ITEMSET_ARG( GetItemSet(), pOverWrite, SfxBoolItem, SID_OVERWRITE, false );
1662 SFX_ITEMSET_ARG( GetItemSet(), pRename, SfxBoolItem, SID_RENAME, false );
1663 bool bRename = pRename ? pRename->GetValue() : false;
1664 bool bOverWrite = pOverWrite ? pOverWrite->GetValue() : !bRename;
1668 if( bOverWrite && ::utl::UCBContentHelper::IsDocument( aDest.GetMainURL( INetURLObject::NO_DECODE ) ) )
1670 if( pImp->m_aBackupURL.isEmpty() )
1671 DoInternalBackup_Impl( aOriginalContent );
1673 if( !pImp->m_aBackupURL.isEmpty() )
1675 Reference< XInputStream > aTempInput = aTempCont.openStream();
1676 bTransactStarted = true;
1677 aOriginalContent.setPropertyValue( "Size", uno::makeAny( (sal_Int64)0 ) );
1678 aOriginalContent.writeStream( aTempInput, bOverWrite );
1679 bResult = true;
1681 else
1683 pImp->m_eError = ERRCODE_SFX_CANTCREATEBACKUP;
1686 else
1688 Reference< XInputStream > aTempInput = aTempCont.openStream();
1689 aOriginalContent.writeStream( aTempInput, bOverWrite );
1690 bResult = true;
1693 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
1695 pImp->m_eError = ERRCODE_ABORT;
1697 catch ( const ::com::sun::star::ucb::CommandFailedException& )
1699 pImp->m_eError = ERRCODE_ABORT;
1701 catch ( const ::com::sun::star::ucb::InteractiveIOException& r )
1703 if ( r.Code == IOErrorCode_ACCESS_DENIED )
1704 pImp->m_eError = ERRCODE_IO_ACCESSDENIED;
1705 else if ( r.Code == IOErrorCode_NOT_EXISTING )
1706 pImp->m_eError = ERRCODE_IO_NOTEXISTS;
1707 else if ( r.Code == IOErrorCode_CANT_READ )
1708 pImp->m_eError = ERRCODE_IO_CANTREAD;
1709 else
1710 pImp->m_eError = ERRCODE_IO_GENERAL;
1712 catch ( const ::com::sun::star::uno::Exception& )
1714 pImp->m_eError = ERRCODE_IO_GENERAL;
1717 if ( bResult )
1719 if ( pImp->pTempFile )
1721 pImp->pTempFile->EnableKillingFile( true );
1722 delete pImp->pTempFile;
1723 pImp->pTempFile = NULL;
1726 else if ( bTransactStarted )
1728 UseBackupToRestore_Impl( aOriginalContent, xDummyEnv );
1731 else
1732 pImp->m_eError = ERRCODE_IO_CANTREAD;
1735 return bResult;
1738 //------------------------------------------------------------------
1739 sal_Bool SfxMedium::TryDirectTransfer( const OUString& aURL, SfxItemSet& aTargetSet )
1741 if ( GetError() )
1742 return false;
1744 // if the document had no password it should be stored without password
1745 // if the document had password it should be stored with the same password
1746 // otherwise the stream copying can not be done
1747 SFX_ITEMSET_ARG( &aTargetSet, pNewPassItem, SfxStringItem, SID_PASSWORD, false );
1748 SFX_ITEMSET_ARG( GetItemSet(), pOldPassItem, SfxStringItem, SID_PASSWORD, false );
1749 if ( ( !pNewPassItem && !pOldPassItem )
1750 || ( pNewPassItem && pOldPassItem && pNewPassItem->GetValue() == pOldPassItem->GetValue() ) )
1752 // the filter must be the same
1753 SFX_ITEMSET_ARG( &aTargetSet, pNewFilterItem, SfxStringItem, SID_FILTER_NAME, false );
1754 SFX_ITEMSET_ARG( GetItemSet(), pOldFilterItem, SfxStringItem, SID_FILTER_NAME, false );
1755 if ( pNewFilterItem && pOldFilterItem && pNewFilterItem->GetValue() == pOldFilterItem->GetValue() )
1757 // get the input stream and copy it
1758 // in case of success return true
1759 uno::Reference< io::XInputStream > xInStream = GetInputStream();
1761 ResetError();
1762 if ( xInStream.is() )
1766 uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
1767 sal_Int64 nPos = 0;
1768 if ( xSeek.is() )
1770 nPos = xSeek->getPosition();
1771 xSeek->seek( 0 );
1774 uno::Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
1775 ::ucbhelper::Content aTargetContent( aURL, xEnv, comphelper::getProcessComponentContext() );
1777 InsertCommandArgument aInsertArg;
1778 aInsertArg.Data = xInStream;
1779 SFX_ITEMSET_ARG( &aTargetSet, pRename, SfxBoolItem, SID_RENAME, false );
1780 SFX_ITEMSET_ARG( &aTargetSet, pOverWrite, SfxBoolItem, SID_OVERWRITE, false );
1781 if ( (pOverWrite && !pOverWrite->GetValue()) // argument says: never overwrite
1782 || (pRename && pRename->GetValue()) ) // argument says: rename file
1783 aInsertArg.ReplaceExisting = false;
1784 else
1785 aInsertArg.ReplaceExisting = true; // default is overwrite existing files
1787 Any aCmdArg;
1788 aCmdArg <<= aInsertArg;
1789 aTargetContent.executeCommand( OUString( "insert" ),
1790 aCmdArg );
1792 if ( xSeek.is() )
1793 xSeek->seek( nPos );
1795 return true;
1797 catch( const uno::Exception& )
1803 return false;
1806 //------------------------------------------------------------------
1807 void SfxMedium::Transfer_Impl()
1809 // The transfer is required only in two cases: either if there is a temporary file or if there is a salvage item
1810 OUString aNameURL;
1811 if ( pImp->pTempFile )
1812 aNameURL = pImp->pTempFile->GetURL();
1813 else if ( !pImp->m_aLogicName.isEmpty() && pImp->m_bSalvageMode )
1815 // makes sence only in case logic name is set
1816 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aNameURL ) )
1817 OSL_FAIL( "The medium name is not convertible!\n" );
1820 if ( !aNameURL.isEmpty() && ( !pImp->m_eError || (pImp->m_eError & ERRCODE_WARNING_MASK) ) )
1822 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::Transfer_Impl, copying to target" );
1824 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
1825 Reference< XOutputStream > rOutStream;
1827 // in case an output stream is provided from outside and the URL is correct
1828 // commit to the stream
1829 if (pImp->m_aLogicName.startsWith("private:stream"))
1831 // TODO/LATER: support storing to SID_STREAM
1832 SFX_ITEMSET_ARG( pImp->m_pSet, pOutStreamItem, SfxUnoAnyItem, SID_OUTPUTSTREAM, false);
1833 if( pOutStreamItem && ( pOutStreamItem->GetValue() >>= rOutStream ) )
1835 if ( pImp->xStorage.is() )
1836 CloseStorage();
1838 CloseStreams_Impl();
1840 INetURLObject aSource( aNameURL );
1841 ::ucbhelper::Content aTempCont;
1842 if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, comphelper::getProcessComponentContext(), aTempCont ) )
1846 sal_Int32 nRead;
1847 sal_Int32 nBufferSize = 32767;
1848 Sequence < sal_Int8 > aSequence ( nBufferSize );
1849 Reference< XInputStream > aTempInput = aTempCont.openStream();
1853 nRead = aTempInput->readBytes ( aSequence, nBufferSize );
1854 if ( nRead < nBufferSize )
1856 Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead );
1857 rOutStream->writeBytes ( aTempBuf );
1859 else
1860 rOutStream->writeBytes ( aSequence );
1862 while ( nRead == nBufferSize );
1864 // remove temporary file
1865 if ( pImp->pTempFile )
1867 pImp->pTempFile->EnableKillingFile( true );
1868 delete pImp->pTempFile;
1869 pImp->pTempFile = NULL;
1872 catch( const Exception& )
1876 else
1878 OSL_FAIL( "Illegal Output stream parameter!\n" );
1879 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1882 // free the reference
1883 if ( pImp->m_pSet )
1884 pImp->m_pSet->ClearItem( SID_OUTPUTSTREAM );
1886 return;
1889 GetContent();
1890 if ( !pImp->aContent.get().is() )
1892 pImp->m_eError = ERRCODE_IO_NOTEXISTS;
1893 return;
1896 SFX_ITEMSET_ARG( GetItemSet(), pSegmentSize, SfxInt32Item, SID_SEGMENTSIZE, false);
1897 if ( pSegmentSize )
1899 // this file must be stored into a disk spanned package
1902 uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetStorageFromURL( GetName(),
1903 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1905 // set segment size property; package will automatically be divided in pieces fitting
1906 // into this size
1907 ::com::sun::star::uno::Any aAny;
1908 aAny <<= pSegmentSize->GetValue();
1910 uno::Reference < beans::XPropertySet > xSet( pImp->xStorage, uno::UNO_QUERY );
1911 xSet->setPropertyValue( OUString("SegmentSize"), aAny );
1913 // copy the temporary storage into the disk spanned package
1914 GetStorage()->copyToStorage( xStor );
1915 uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY );
1916 if ( xTrans.is() )
1917 xTrans->commit();
1920 catch ( const uno::Exception& )
1922 //TODO/MBA: error handling
1924 return;
1927 INetURLObject aDest( GetURLObject() );
1929 // source is the temp file written so far
1930 INetURLObject aSource( aNameURL );
1932 // a special case, an interaction handler should be used for
1933 // authentication in case it is available
1934 Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
1935 Reference< ::com::sun::star::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
1936 if (xInteractionHandler.is())
1937 xComEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler,
1938 Reference< ::com::sun::star::ucb::XProgressHandler >() );
1940 OUString aDestURL( aDest.GetMainURL( INetURLObject::NO_DECODE ) );
1942 if ( ::utl::LocalFileHelper::IsLocalFile( aDestURL ) || !aDest.removeSegment() )
1944 TransactedTransferForFS_Impl( aSource, aDest, xComEnv );
1946 // Hideous - no clean way to do this, so we re-open the file just to fsync it
1947 osl::File aFile( aDestURL );
1948 if ( aFile.open( osl_File_OpenFlag_Write ) == osl::FileBase::E_None )
1950 aFile.sync();
1951 OSL_TRACE("fsync'd saved file '%s'\n",
1952 OUStringToOString( aDestURL, RTL_TEXTENCODING_UTF8 ).getStr() );
1953 aFile.close();
1956 else
1958 // create content for the parent folder and call transfer on that content with the source content
1959 // and the destination file name as parameters
1960 ::ucbhelper::Content aSourceContent;
1961 ::ucbhelper::Content aTransferContent;
1963 ::ucbhelper::Content aDestContent;
1964 ::ucbhelper::Content::create( aDestURL, xComEnv, comphelper::getProcessComponentContext(), aDestContent );
1965 // For checkin, we need the object URL, not the parent folder:
1966 if ( !IsInCheckIn( ) )
1968 // Get the parent URL from the XChild if possible: why would the URL necessarily have
1969 // a hierarchical path? It's not always the case for CMIS.
1970 Reference< ::com::sun::star::container::XChild> xChild( aDestContent.get(), uno::UNO_QUERY );
1971 OUString sParentUrl;
1972 if ( xChild.is( ) )
1974 Reference< ::com::sun::star::ucb::XContent > xParent( xChild->getParent( ), uno::UNO_QUERY );
1975 if ( xParent.is( ) )
1977 sParentUrl = xParent->getIdentifier( )->getContentIdentifier();
1981 if ( sParentUrl.isEmpty() )
1982 aDestURL = aDest.GetMainURL( INetURLObject::NO_DECODE );
1983 // adjust to above aDest.removeSegment()
1984 else
1985 aDestURL = sParentUrl;
1988 // LongName wasn't defined anywhere, only used here... get the Title instead
1989 // as it's less probably empty
1990 OUString aFileName;
1991 Any aAny = aDestContent.getPropertyValue( OUString("Title" ) );
1992 aAny >>= aFileName;
1993 if ( aFileName.isEmpty() )
1994 aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
1998 aTransferContent = ::ucbhelper::Content( aDestURL, xComEnv, comphelper::getProcessComponentContext() );
2000 catch (const ::com::sun::star::ucb::ContentCreationException& ex)
2002 pImp->m_eError = ERRCODE_IO_GENERAL;
2003 if (
2004 (ex.eError == ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
2005 (ex.eError == ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
2008 pImp->m_eError = ERRCODE_IO_NOTEXISTSPATH;
2011 catch (const ::com::sun::star::uno::Exception&)
2013 pImp->m_eError = ERRCODE_IO_GENERAL;
2016 if ( !pImp->m_eError || (pImp->m_eError & ERRCODE_WARNING_MASK) )
2018 // free resources, otherwise the transfer may fail
2019 if ( pImp->xStorage.is() )
2020 CloseStorage();
2022 CloseStreams_Impl();
2024 ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, comphelper::getProcessComponentContext(), aSourceContent );
2026 // check for external parameters that may customize the handling of NameClash situations
2027 SFX_ITEMSET_ARG( GetItemSet(), pRename, SfxBoolItem, SID_RENAME, false );
2028 SFX_ITEMSET_ARG( GetItemSet(), pOverWrite, SfxBoolItem, SID_OVERWRITE, false );
2029 sal_Int32 nNameClash;
2030 if ( pOverWrite && !pOverWrite->GetValue() )
2031 // argument says: never overwrite
2032 nNameClash = NameClash::ERROR;
2033 else if ( pRename && pRename->GetValue() )
2034 // argument says: rename file
2035 nNameClash = NameClash::RENAME;
2036 else
2037 // default is overwrite existing files
2038 nNameClash = NameClash::OVERWRITE;
2042 OUString aMimeType = pImp->getFilterMimeType();
2043 ::ucbhelper::InsertOperation eOperation = ::ucbhelper::InsertOperation_COPY;
2044 bool bMajor = false;
2045 OUString sComment;
2046 if ( IsInCheckIn( ) )
2048 eOperation = ::ucbhelper::InsertOperation_CHECKIN;
2049 SFX_ITEMSET_ARG( GetItemSet(), pMajor, SfxBoolItem, SID_DOCINFO_MAJOR, false );
2050 bMajor = pMajor && pMajor->GetValue( );
2051 SFX_ITEMSET_ARG( GetItemSet(), pComments, SfxStringItem, SID_DOCINFO_COMMENTS, false );
2052 if ( pComments )
2053 sComment = pComments->GetValue( );
2055 OUString sResultURL;
2056 if (!aTransferContent.transferContent( aSourceContent, eOperation,
2057 aFileName, nNameClash, aMimeType, bMajor, sComment, &sResultURL ))
2058 pImp->m_eError = ERRCODE_IO_GENERAL;
2059 else if ( !sResultURL.isEmpty( ) ) // Likely to happen only for checkin
2060 SwitchDocumentToFile( sResultURL );
2062 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
2064 pImp->m_eError = ERRCODE_ABORT;
2066 catch ( const ::com::sun::star::ucb::CommandFailedException& )
2068 pImp->m_eError = ERRCODE_ABORT;
2070 catch ( const ::com::sun::star::ucb::InteractiveIOException& r )
2072 if ( r.Code == IOErrorCode_ACCESS_DENIED )
2073 pImp->m_eError = ERRCODE_IO_ACCESSDENIED;
2074 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2075 pImp->m_eError = ERRCODE_IO_NOTEXISTS;
2076 else if ( r.Code == IOErrorCode_CANT_READ )
2077 pImp->m_eError = ERRCODE_IO_CANTREAD;
2078 else
2079 pImp->m_eError = ERRCODE_IO_GENERAL;
2081 catch ( const ::com::sun::star::uno::Exception& )
2083 pImp->m_eError = ERRCODE_IO_GENERAL;
2086 // do not switch from temporary file in case of nonfile protocol
2090 if ( ( !pImp->m_eError || (pImp->m_eError & ERRCODE_WARNING_MASK) ) && !pImp->pTempFile )
2092 // without a TempFile the physical and logical name should be the same after successful transfer
2093 ::utl::LocalFileHelper::ConvertURLToPhysicalName(
2094 GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), pImp->m_aName );
2095 pImp->m_bSalvageMode = false;
2100 //------------------------------------------------------------------
2101 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent,
2102 const String& aPrefix,
2103 const String& aExtension,
2104 const String& aDestDir )
2106 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::DoInternalBackup_Impl( with destdir )" );
2108 if ( !pImp->m_aBackupURL.isEmpty() )
2109 return; // the backup was done already
2111 ::utl::TempFile aTransactTemp( aPrefix, &aExtension, &aDestDir );
2112 aTransactTemp.EnableKillingFile( false );
2114 INetURLObject aBackObj( aTransactTemp.GetURL() );
2115 OUString aBackupName = aBackObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2117 Reference < ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
2118 ::ucbhelper::Content aBackupCont;
2119 if( ::ucbhelper::Content::create( aDestDir, xDummyEnv, comphelper::getProcessComponentContext(), aBackupCont ) )
2123 OUString sMimeType = pImp->getFilterMimeType();
2124 if( aBackupCont.transferContent( aOriginalContent,
2125 ::ucbhelper::InsertOperation_COPY,
2126 aBackupName,
2127 NameClash::OVERWRITE,
2128 sMimeType ) )
2130 pImp->m_aBackupURL = aBackObj.GetMainURL( INetURLObject::NO_DECODE );
2131 pImp->m_bRemoveBackup = true;
2134 catch( const Exception& )
2138 if ( pImp->m_aBackupURL.isEmpty() )
2139 aTransactTemp.EnableKillingFile( true );
2142 //------------------------------------------------------------------
2143 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent )
2145 if ( !pImp->m_aBackupURL.isEmpty() )
2146 return; // the backup was done already
2148 OUString aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT,
2149 true,
2150 INetURLObject::NO_DECODE );
2152 sal_Int32 nPrefixLen = aFileName.lastIndexOf( '.' );
2153 String aPrefix = ( nPrefixLen == -1 ) ? aFileName : aFileName.copy( 0, nPrefixLen );
2154 String aExtension = ( nPrefixLen == -1 ) ? String() : String(aFileName.copy( nPrefixLen ));
2155 String aBakDir = SvtPathOptions().GetBackupPath();
2157 // create content for the parent folder ( = backup folder )
2158 ::ucbhelper::Content aContent;
2159 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
2160 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
2161 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aBakDir );
2163 if ( pImp->m_aBackupURL.isEmpty() )
2165 // the copiing to the backup catalog failed ( for example because
2166 // of using an encrypted partition as target catalog )
2167 // since the user did not specify to make backup explicitly
2168 // office should try to make backup in another place,
2169 // target catalog does not look bad for this case ( and looks
2170 // to be the only way for encrypted partitions )
2172 INetURLObject aDest = GetURLObject();
2173 if ( aDest.removeSegment() )
2174 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aDest.GetMainURL( INetURLObject::NO_DECODE ) );
2179 //------------------------------------------------------------------
2180 void SfxMedium::DoBackup_Impl()
2182 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::DoBackup_Impl" );
2184 // source file name is the logical name of this medium
2185 INetURLObject aSource( GetURLObject() );
2187 // there is nothing to backup in case source file does not exist
2188 if ( !::utl::UCBContentHelper::IsDocument( aSource.GetMainURL( INetURLObject::NO_DECODE ) ) )
2189 return;
2191 bool bSuccess = false;
2193 // get path for backups
2194 String aBakDir = SvtPathOptions().GetBackupPath();
2195 if( aBakDir.Len() )
2197 // create content for the parent folder ( = backup folder )
2198 ::ucbhelper::Content aContent;
2199 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
2200 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
2202 // save as ".bak" file
2203 INetURLObject aDest( aBakDir );
2204 aDest.insertName( aSource.getName() );
2205 aDest.setExtension( "bak" );
2206 String aFileName = aDest.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2208 // create a content for the source file
2209 ::ucbhelper::Content aSourceContent;
2210 if ( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, comphelper::getProcessComponentContext(), aSourceContent ) )
2214 // do the transfer ( copy source file to backup dir )
2215 OUString sMimeType = pImp->getFilterMimeType();
2216 bSuccess = aContent.transferContent( aSourceContent,
2217 ::ucbhelper::InsertOperation_COPY,
2218 aFileName,
2219 NameClash::OVERWRITE,
2220 sMimeType );
2221 if( bSuccess )
2223 pImp->m_aBackupURL = aDest.GetMainURL( INetURLObject::NO_DECODE );
2224 pImp->m_bRemoveBackup = false;
2227 catch ( const ::com::sun::star::uno::Exception& )
2234 if ( !bSuccess )
2236 pImp->m_eError = ERRCODE_SFX_CANTCREATEBACKUP;
2240 //------------------------------------------------------------------
2241 void SfxMedium::ClearBackup_Impl()
2243 if( pImp->m_bRemoveBackup )
2245 // currently a document is always stored in a new medium,
2246 // thus if a backup can not be removed the backup URL should not be cleaned
2247 if ( !pImp->m_aBackupURL.isEmpty() )
2249 if ( ::utl::UCBContentHelper::Kill( pImp->m_aBackupURL ) )
2251 pImp->m_bRemoveBackup = false;
2252 pImp->m_aBackupURL = OUString();
2254 else
2257 OSL_FAIL("Couldn't remove backup file!");
2261 else
2262 pImp->m_aBackupURL = OUString();
2265 //----------------------------------------------------------------
2266 void SfxMedium::GetLockingStream_Impl()
2268 if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
2269 && !pImp->m_xLockingStream.is() )
2271 SFX_ITEMSET_ARG( pImp->m_pSet, pWriteStreamItem, SfxUnoAnyItem, SID_STREAM, false);
2272 if ( pWriteStreamItem )
2273 pWriteStreamItem->GetValue() >>= pImp->m_xLockingStream;
2275 if ( !pImp->m_xLockingStream.is() )
2277 // open the original document
2278 uno::Sequence< beans::PropertyValue > xProps;
2279 TransformItems( SID_OPENDOC, *GetItemSet(), xProps );
2280 comphelper::MediaDescriptor aMedium( xProps );
2282 aMedium.addInputStreamOwnLock();
2284 uno::Reference< io::XInputStream > xInputStream;
2285 aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= pImp->m_xLockingStream;
2286 aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream;
2288 if ( !pImp->pTempFile && pImp->m_aName.isEmpty() )
2290 // the medium is still based on the original file, it makes sence to initialize the streams
2291 if ( pImp->m_xLockingStream.is() )
2292 pImp->xStream = pImp->m_xLockingStream;
2294 if ( xInputStream.is() )
2295 pImp->xInputStream = xInputStream;
2297 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2298 pImp->xInputStream = pImp->xStream->getInputStream();
2304 //----------------------------------------------------------------
2305 void SfxMedium::GetMedium_Impl()
2307 if ( !pImp->m_pInStream )
2309 pImp->bDownloadDone = false;
2310 Reference< ::com::sun::star::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
2312 //TODO/MBA: need support for SID_STREAM
2313 SFX_ITEMSET_ARG( pImp->m_pSet, pWriteStreamItem, SfxUnoAnyItem, SID_STREAM, false);
2314 SFX_ITEMSET_ARG( pImp->m_pSet, pInStreamItem, SfxUnoAnyItem, SID_INPUTSTREAM, false);
2315 if ( pWriteStreamItem )
2317 pWriteStreamItem->GetValue() >>= pImp->xStream;
2319 if ( pInStreamItem )
2320 pInStreamItem->GetValue() >>= pImp->xInputStream;
2322 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2323 pImp->xInputStream = pImp->xStream->getInputStream();
2325 else if ( pInStreamItem )
2327 pInStreamItem->GetValue() >>= pImp->xInputStream;
2329 else
2331 uno::Sequence < beans::PropertyValue > xProps;
2332 OUString aFileName;
2333 if (!pImp->m_aName.isEmpty())
2335 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aFileName ) )
2337 OSL_FAIL("Physical name not convertible!");
2340 else
2341 aFileName = GetName();
2343 // in case the temporary file exists the streams should be initialized from it,
2344 // but the original MediaDescriptor should not be changed
2345 bool bFromTempFile = ( pImp->pTempFile != NULL );
2347 if ( !bFromTempFile )
2349 GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, aFileName ) );
2350 if( !(pImp->m_nStorOpenMode & STREAM_WRITE) )
2351 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
2352 if (xInteractionHandler.is())
2353 GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny(xInteractionHandler) ) );
2356 if ( pImp->m_xInputStreamToLoadFrom.is() )
2358 pImp->xInputStream = pImp->m_xInputStreamToLoadFrom;
2359 pImp->xInputStream->skipBytes(0);
2360 if (pImp->m_bInputStreamIsReadOnly)
2361 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
2363 else
2365 TransformItems( SID_OPENDOC, *GetItemSet(), xProps );
2366 comphelper::MediaDescriptor aMedium( xProps );
2368 if ( pImp->m_xLockingStream.is() && !bFromTempFile )
2370 // the medium is not based on the temporary file, so the original stream can be used
2371 pImp->xStream = pImp->m_xLockingStream;
2373 else
2375 if ( bFromTempFile )
2377 aMedium[comphelper::MediaDescriptor::PROP_URL()] <<= OUString( aFileName );
2378 aMedium.erase( comphelper::MediaDescriptor::PROP_READONLY() );
2379 aMedium.addInputStream();
2381 else if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
2383 // use the special locking approach only for file URLs
2384 aMedium.addInputStreamOwnLock();
2386 else
2387 aMedium.addInputStream();
2389 // the ReadOnly property set in aMedium is ignored
2390 // the check is done in LockOrigFileOnDemand() for file and non-file URLs
2392 //TODO/MBA: what happens if property is not there?!
2393 aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= pImp->xStream;
2394 aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= pImp->xInputStream;
2397 GetContent();
2398 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2399 pImp->xInputStream = pImp->xStream->getInputStream();
2402 if ( !bFromTempFile )
2404 //TODO/MBA: need support for SID_STREAM
2405 if ( pImp->xStream.is() )
2406 GetItemSet()->Put( SfxUsrAnyItem( SID_STREAM, makeAny( pImp->xStream ) ) );
2408 GetItemSet()->Put( SfxUsrAnyItem( SID_INPUTSTREAM, makeAny( pImp->xInputStream ) ) );
2412 //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor
2413 if ( !GetError() && !pImp->xStream.is() && !pImp->xInputStream.is() )
2414 SetError( ERRCODE_IO_ACCESSDENIED, OUString( OSL_LOG_PREFIX ) );
2416 if ( !GetError() )
2418 if ( pImp->xStream.is() )
2419 pImp->m_pInStream = utl::UcbStreamHelper::CreateStream( pImp->xStream );
2420 else if ( pImp->xInputStream.is() )
2421 pImp->m_pInStream = utl::UcbStreamHelper::CreateStream( pImp->xInputStream );
2424 pImp->bDownloadDone = true;
2425 pImp->aDoneLink.ClearPendingCall();
2426 sal_uIntPtr nError = GetError();
2427 pImp->aDoneLink.Call( (void*)nError );
2431 //----------------------------------------------------------------
2432 sal_Bool SfxMedium::IsRemote()
2434 return pImp->m_bRemote;
2437 //------------------------------------------------------------------
2439 void SfxMedium::SetUpdatePickList(sal_Bool bVal)
2441 pImp->bUpdatePickList = bVal;
2443 //------------------------------------------------------------------
2445 sal_Bool SfxMedium::IsUpdatePickList() const
2447 return pImp->bUpdatePickList;
2450 void SfxMedium::SetLongName(const OUString &rName)
2452 pImp->m_aLongName = rName;
2455 const OUString& SfxMedium::GetLongName() const
2457 return pImp->m_aLongName;
2460 void SfxMedium::SetDoneLink( const Link& rLink )
2462 pImp->aDoneLink = rLink;
2465 void SfxMedium::DownLoad( const Link& aLink )
2467 SetDoneLink( aLink );
2468 GetInStream();
2469 if ( pImp->m_pInStream && !aLink.IsSet() )
2471 while( !pImp->bDownloadDone )
2472 Application::Yield();
2476 //------------------------------------------------------------------
2477 void SfxMedium::Init_Impl()
2478 /* [Description]
2479 Includes a valid:: sun:: com:: star:: util:: URL (If a file name was
2480 previously in there) in the logical name and if available sets the
2481 physical name as the file name.
2485 Reference< XOutputStream > rOutStream;
2487 // TODO/LATER: handle lifetime of storages
2488 pImp->bDisposeStorage = false;
2490 SFX_ITEMSET_ARG( pImp->m_pSet, pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, false);
2491 if ( pSalvageItem && pSalvageItem->GetValue().isEmpty() )
2493 pSalvageItem = NULL;
2494 pImp->m_pSet->ClearItem( SID_DOC_SALVAGE );
2497 if (!pImp->m_aLogicName.isEmpty())
2499 INetURLObject aUrl( pImp->m_aLogicName );
2500 INetProtocol eProt = aUrl.GetProtocol();
2501 if ( eProt == INET_PROT_NOT_VALID )
2503 OSL_FAIL( "Unknown protocol!" );
2505 else
2507 if ( aUrl.HasMark() )
2509 pImp->m_aLogicName = aUrl.GetURLNoMark( INetURLObject::NO_DECODE );
2510 GetItemSet()->Put( SfxStringItem( SID_JUMPMARK, aUrl.GetMark() ) );
2513 // try to convert the URL into a physical name - but never change a physical name
2514 // physical name may be set if the logical name is changed after construction
2515 if ( pImp->m_aName.isEmpty() )
2516 ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), pImp->m_aName );
2517 else
2519 DBG_ASSERT( pSalvageItem, "Suspicious change of logical name!" );
2524 if ( pSalvageItem && !pSalvageItem->GetValue().isEmpty() )
2526 pImp->m_aLogicName = pSalvageItem->GetValue();
2527 DELETEZ( pImp->m_pURLObj );
2528 pImp->m_bSalvageMode = true;
2531 // in case output stream is by mistake here
2532 // clear the reference
2533 SFX_ITEMSET_ARG( pImp->m_pSet, pOutStreamItem, SfxUnoAnyItem, SID_OUTPUTSTREAM, false);
2534 if( pOutStreamItem
2535 && ( !( pOutStreamItem->GetValue() >>= rOutStream )
2536 || !pImp->m_aLogicName.startsWith("private:stream")) )
2538 pImp->m_pSet->ClearItem( SID_OUTPUTSTREAM );
2539 OSL_FAIL( "Unexpected Output stream parameter!\n" );
2542 if (!pImp->m_aLogicName.isEmpty())
2544 // if the logic name is set it should be set in MediaDescriptor as well
2545 SFX_ITEMSET_ARG( pImp->m_pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, false );
2546 if ( !pFileNameItem )
2548 // let the ItemSet be created if necessary
2549 GetItemSet()->Put(
2550 SfxStringItem(
2551 SID_FILE_NAME, INetURLObject( pImp->m_aLogicName ).GetMainURL( INetURLObject::NO_DECODE ) ) );
2555 SetIsRemote_Impl();
2558 //------------------------------------------------------------------
2559 SfxMedium::SfxMedium() : pImp(new SfxMedium_Impl(this))
2561 Init_Impl();
2564 //------------------------------------------------------------------
2566 void SfxMedium::UseInteractionHandler( sal_Bool bUse )
2568 pImp->bAllowDefaultIntHdl = bUse;
2571 //------------------------------------------------------------------
2573 ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >
2574 SfxMedium::GetInteractionHandler()
2576 // if interaction isnt allowed explicitly ... return empty reference!
2577 if ( !pImp->bUseInteractionHandler )
2578 return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
2580 // search a possible existing handler inside cached item set
2581 if ( pImp->m_pSet )
2583 ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > xHandler;
2584 SFX_ITEMSET_ARG( pImp->m_pSet, pHandler, SfxUnoAnyItem, SID_INTERACTIONHANDLER, false);
2585 if ( pHandler && (pHandler->GetValue() >>= xHandler) && xHandler.is() )
2586 return xHandler;
2589 // if default interaction isnt allowed explicitly ... return empty reference!
2590 if ( !pImp->bAllowDefaultIntHdl )
2591 return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
2593 // otherwise return cached default handler ... if it exist.
2594 if ( pImp->xInteraction.is() )
2595 return pImp->xInteraction;
2597 // create default handler and cache it!
2598 Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2599 pImp->xInteraction.set(
2600 task::InteractionHandler::createWithParent(xContext, 0), UNO_QUERY_THROW );
2601 return pImp->xInteraction;
2604 //----------------------------------------------------------------
2606 void SfxMedium::SetFilter( const SfxFilter* pFilterP, sal_Bool /*bResetOrig*/ )
2608 pImp->m_pFilter = pFilterP;
2611 const SfxFilter* SfxMedium::GetFilter() const
2613 return pImp->m_pFilter;
2616 //----------------------------------------------------------------
2618 const SfxFilter* SfxMedium::GetOrigFilter( sal_Bool bNotCurrent ) const
2620 return ( pImp->pOrigFilter || bNotCurrent ) ? pImp->pOrigFilter : pImp->m_pFilter;
2623 //----------------------------------------------------------------
2625 sal_uInt32 SfxMedium::CreatePasswordToModifyHash( const OUString& aPasswd, sal_Bool bWriter )
2627 sal_uInt32 nHash = 0;
2629 if ( !aPasswd.isEmpty() )
2631 if ( bWriter )
2633 nHash = ::comphelper::DocPasswordHelper::GetWordHashAsUINT32( aPasswd );
2635 else
2637 rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
2638 nHash = ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd, nEncoding );
2642 return nHash;
2645 //------------------------------------------------------------------
2647 void SfxMedium::Close()
2649 if ( pImp->xStorage.is() )
2651 CloseStorage();
2654 CloseStreams_Impl();
2656 UnlockFile( false );
2659 void SfxMedium::CloseAndRelease()
2661 if ( pImp->xStorage.is() )
2663 CloseStorage();
2666 CloseAndReleaseStreams_Impl();
2668 UnlockFile( true );
2671 void SfxMedium::UnlockFile( sal_Bool bReleaseLockStream )
2673 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
2674 (void) bReleaseLockStream;
2675 #else
2676 if ( pImp->m_xLockingStream.is() )
2678 if ( bReleaseLockStream )
2682 uno::Reference< io::XInputStream > xInStream = pImp->m_xLockingStream->getInputStream();
2683 uno::Reference< io::XOutputStream > xOutStream = pImp->m_xLockingStream->getOutputStream();
2684 if ( xInStream.is() )
2685 xInStream->closeInput();
2686 if ( xOutStream.is() )
2687 xOutStream->closeOutput();
2689 catch( const uno::Exception& )
2693 pImp->m_xLockingStream.clear();
2696 if ( pImp->m_bLocked )
2700 pImp->m_bLocked = false;
2701 ::svt::DocumentLockFile aLockFile( pImp->m_aLogicName );
2702 // TODO/LATER: A warning could be shown in case the file is not the own one
2703 aLockFile.RemoveFile();
2705 catch( const uno::Exception& )
2708 #endif
2711 void SfxMedium::CloseAndReleaseStreams_Impl()
2713 CloseZipStorage_Impl();
2715 uno::Reference< io::XInputStream > xInToClose = pImp->xInputStream;
2716 uno::Reference< io::XOutputStream > xOutToClose;
2717 if ( pImp->xStream.is() )
2719 xOutToClose = pImp->xStream->getOutputStream();
2721 // if the locking stream is closed here the related member should be cleaned
2722 if ( pImp->xStream == pImp->m_xLockingStream )
2723 pImp->m_xLockingStream.clear();
2726 // The probably exsisting SvStream wrappers should be closed first
2727 CloseStreams_Impl();
2729 // in case of salvage mode the storage is based on the streams
2730 if ( !pImp->m_bSalvageMode )
2734 if ( xInToClose.is() )
2735 xInToClose->closeInput();
2736 if ( xOutToClose.is() )
2737 xOutToClose->closeOutput();
2739 catch ( const uno::Exception& )
2745 //------------------------------------------------------------------
2746 void SfxMedium::CloseStreams_Impl()
2748 CloseInStream_Impl();
2749 CloseOutStream_Impl();
2751 if ( pImp->m_pSet )
2752 pImp->m_pSet->ClearItem( SID_CONTENT );
2754 pImp->aContent = ::ucbhelper::Content();
2757 //------------------------------------------------------------------
2759 void SfxMedium::SetIsRemote_Impl()
2761 INetURLObject aObj( GetName() );
2762 switch( aObj.GetProtocol() )
2764 case INET_PROT_FTP:
2765 case INET_PROT_HTTP:
2766 case INET_PROT_HTTPS:
2767 case INET_PROT_POP3:
2768 case INET_PROT_NEWS:
2769 case INET_PROT_IMAP:
2770 case INET_PROT_VIM:
2771 pImp->m_bRemote = true;
2772 break;
2773 default:
2774 pImp->m_bRemote = GetName().startsWith("private:msgid");
2775 break;
2778 // As files that are written to the remote transmission must also be able
2779 // to be read.
2780 if (pImp->m_bRemote)
2781 pImp->m_nStorOpenMode |= STREAM_READ;
2786 void SfxMedium::SetName( const String& aNameP, sal_Bool bSetOrigURL )
2788 if (pImp->aOrigURL.isEmpty())
2789 pImp->aOrigURL = pImp->m_aLogicName;
2790 if( bSetOrigURL )
2791 pImp->aOrigURL = aNameP;
2792 pImp->m_aLogicName = aNameP;
2793 DELETEZ( pImp->m_pURLObj );
2794 pImp->aContent = ::ucbhelper::Content();
2795 Init_Impl();
2798 //----------------------------------------------------------------
2799 const OUString& SfxMedium::GetOrigURL() const
2801 return pImp->aOrigURL.isEmpty() ? pImp->m_aLogicName : pImp->aOrigURL;
2804 //----------------------------------------------------------------
2806 void SfxMedium::SetPhysicalName_Impl( const OUString& rNameP )
2808 if ( rNameP != pImp->m_aName )
2810 if( pImp->pTempFile )
2812 delete pImp->pTempFile;
2813 pImp->pTempFile = NULL;
2816 if ( !pImp->m_aName.isEmpty() || !rNameP.isEmpty() )
2817 pImp->aContent = ::ucbhelper::Content();
2819 pImp->m_aName = rNameP;
2820 pImp->m_bTriedStorage = false;
2821 pImp->bIsStorage = false;
2825 //------------------------------------------------------------------
2827 void SfxMedium::ReOpen()
2829 bool bUseInteractionHandler = pImp->bUseInteractionHandler;
2830 pImp->bUseInteractionHandler = false;
2831 GetMedium_Impl();
2832 pImp->bUseInteractionHandler = bUseInteractionHandler;
2835 //------------------------------------------------------------------
2837 void SfxMedium::CompleteReOpen()
2839 // do not use temporary file for reopen and in case of success throw the temporary file away
2840 bool bUseInteractionHandler = pImp->bUseInteractionHandler;
2841 pImp->bUseInteractionHandler = false;
2843 ::utl::TempFile* pTmpFile = NULL;
2844 if ( pImp->pTempFile )
2846 pTmpFile = pImp->pTempFile;
2847 pImp->pTempFile = NULL;
2848 pImp->m_aName = OUString();
2851 GetMedium_Impl();
2853 if ( GetError() )
2855 if ( pImp->pTempFile )
2857 pImp->pTempFile->EnableKillingFile( true );
2858 delete pImp->pTempFile;
2860 pImp->pTempFile = pTmpFile;
2861 if ( pImp->pTempFile )
2862 pImp->m_aName = pImp->pTempFile->GetFileName();
2864 else
2866 pTmpFile->EnableKillingFile( true );
2867 delete pTmpFile;
2871 pImp->bUseInteractionHandler = bUseInteractionHandler;
2874 SfxMedium::SfxMedium(const String &rName, StreamMode nOpenMode, const SfxFilter *pFlt, SfxItemSet *pInSet) :
2875 pImp(new SfxMedium_Impl(this))
2877 pImp->m_pSet = pInSet;
2878 pImp->m_pFilter = pFlt;
2879 pImp->m_aLogicName = rName;
2880 pImp->m_nStorOpenMode = nOpenMode;
2881 Init_Impl();
2884 SfxMedium::SfxMedium( const uno::Sequence<beans::PropertyValue>& aArgs ) :
2885 pImp(new SfxMedium_Impl(this))
2887 SfxAllItemSet *pParams = new SfxAllItemSet( SFX_APP()->GetPool() );
2888 pImp->m_pSet = pParams;
2889 TransformParameters( SID_OPENDOC, aArgs, *pParams );
2891 OUString aFilterProvider, aFilterName;
2893 const SfxPoolItem* pItem = NULL;
2894 if (pImp->m_pSet->HasItem(SID_FILTER_PROVIDER, &pItem))
2895 aFilterProvider = static_cast<const SfxStringItem*>(pItem)->GetValue();
2897 if (pImp->m_pSet->HasItem(SID_FILTER_NAME, &pItem))
2898 aFilterName = static_cast<const SfxStringItem*>(pItem)->GetValue();
2901 if (aFilterProvider.isEmpty())
2903 // This is a conventional filter type.
2904 pImp->m_pFilter = SFX_APP()->GetFilterMatcher().GetFilter4FilterName( aFilterName );
2906 else
2908 // This filter is from an external provider such as orcus.
2909 pImp->m_pCustomFilter.reset(new SfxFilter(aFilterProvider, aFilterName));
2910 pImp->m_pFilter = pImp->m_pCustomFilter.get();
2913 SFX_ITEMSET_ARG( pImp->m_pSet, pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, false );
2914 if( pSalvageItem )
2916 // QUESTION: there is some treatment of Salvage in Init_Impl; align!
2917 if ( !pSalvageItem->GetValue().isEmpty() )
2919 // if an URL is provided in SalvageItem that means that the FileName refers to a temporary file
2920 // that must be copied here
2922 SFX_ITEMSET_ARG( pImp->m_pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, false );
2923 if (!pFileNameItem) throw uno::RuntimeException();
2924 OUString aNewTempFileURL = SfxMedium::CreateTempCopyWithExt( pFileNameItem->GetValue() );
2925 if ( !aNewTempFileURL.isEmpty() )
2927 pImp->m_pSet->Put( SfxStringItem( SID_FILE_NAME, aNewTempFileURL ) );
2928 pImp->m_pSet->ClearItem( SID_INPUTSTREAM );
2929 pImp->m_pSet->ClearItem( SID_STREAM );
2930 pImp->m_pSet->ClearItem( SID_CONTENT );
2932 else
2934 OSL_FAIL( "Can not create a new temporary file for crash recovery!\n" );
2939 SFX_ITEMSET_ARG( pImp->m_pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, false );
2940 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
2941 pImp->m_bOriginallyReadOnly = true;
2943 SFX_ITEMSET_ARG( pImp->m_pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, false );
2944 if (!pFileNameItem) throw uno::RuntimeException();
2945 pImp->m_aLogicName = pFileNameItem->GetValue();
2946 pImp->m_nStorOpenMode = pImp->m_bOriginallyReadOnly ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
2947 Init_Impl();
2951 //------------------------------------------------------------------
2953 SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const String& rBaseURL, const SfxItemSet* p ) :
2954 pImp(new SfxMedium_Impl(this))
2956 OUString aType = SfxFilter::GetTypeFromStorage(rStor);
2957 pImp->m_pFilter = SFX_APP()->GetFilterMatcher().GetFilter4EA( aType );
2958 DBG_ASSERT( pImp->m_pFilter, "No Filter for storage found!" );
2960 Init_Impl();
2961 pImp->xStorage = rStor;
2962 pImp->bDisposeStorage = false;
2964 // always take BaseURL first, could be overwritten by ItemSet
2965 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
2966 if ( p )
2967 GetItemSet()->Put( *p );
2970 //------------------------------------------------------------------
2972 SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const String& rBaseURL, const String &rTypeName, const SfxItemSet* p ) :
2973 pImp(new SfxMedium_Impl(this))
2975 pImp->m_pFilter = SFX_APP()->GetFilterMatcher().GetFilter4EA( rTypeName );
2976 DBG_ASSERT( pImp->m_pFilter, "No Filter for storage found!" );
2978 Init_Impl();
2979 pImp->xStorage = rStor;
2980 pImp->bDisposeStorage = false;
2982 // always take BaseURL first, could be overwritten by ItemSet
2983 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
2984 if ( p )
2985 GetItemSet()->Put( *p );
2988 //------------------------------------------------------------------
2990 SfxMedium::~SfxMedium()
2992 // if there is a requirement to clean the backup this is the last possibility to do it
2993 ClearBackup_Impl();
2995 Close();
2997 if( pImp->bIsTemp && !pImp->m_aName.isEmpty() )
2999 OUString aTemp;
3000 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aTemp ))
3002 OSL_FAIL("Physical name not convertible!");
3005 if ( !::utl::UCBContentHelper::Kill( aTemp ) )
3007 OSL_FAIL("Couldn't remove temporary file!");
3011 delete pImp;
3014 const OUString& SfxMedium::GetName() const
3016 return pImp->m_aLogicName;
3019 const INetURLObject& SfxMedium::GetURLObject() const
3021 if (!pImp->m_pURLObj)
3023 pImp->m_pURLObj = new INetURLObject( pImp->m_aLogicName );
3024 if (pImp->m_pURLObj->HasMark())
3025 *pImp->m_pURLObj = INetURLObject( pImp->m_aLogicName ).GetURLNoMark();
3028 return *pImp->m_pURLObj;
3031 void SfxMedium::SetExpired_Impl( const DateTime& rDateTime )
3033 pImp->aExpireTime = rDateTime;
3035 //----------------------------------------------------------------
3037 sal_Bool SfxMedium::IsExpired() const
3039 return pImp->aExpireTime.IsValidAndGregorian() && pImp->aExpireTime < DateTime( DateTime::SYSTEM );
3041 //----------------------------------------------------------------
3043 void SfxMedium::ForceSynchronStream_Impl( sal_Bool bForce )
3045 if( pImp->m_pInStream )
3047 SvLockBytes* pBytes = pImp->m_pInStream->GetLockBytes();
3048 if( pBytes )
3049 pBytes->SetSynchronMode( bForce );
3053 //----------------------------------------------------------------
3054 SfxFrame* SfxMedium::GetLoadTargetFrame() const
3056 return pImp->wLoadTargetFrame;
3059 void SfxMedium::setStreamToLoadFrom(const com::sun::star::uno::Reference<com::sun::star::io::XInputStream>& xInputStream,sal_Bool bIsReadOnly )
3061 pImp->m_xInputStreamToLoadFrom = xInputStream;
3062 pImp->m_bInputStreamIsReadOnly = bIsReadOnly;
3065 void SfxMedium::SetLoadTargetFrame(SfxFrame* pFrame )
3067 pImp->wLoadTargetFrame = pFrame;
3069 //----------------------------------------------------------------
3071 void SfxMedium::SetStorage_Impl( const uno::Reference < embed::XStorage >& rStor )
3073 pImp->xStorage = rStor;
3075 //----------------------------------------------------------------
3077 SfxItemSet* SfxMedium::GetItemSet() const
3079 // this method *must* return an ItemSet, returning NULL can cause crashes
3080 if (!pImp->m_pSet)
3081 pImp->m_pSet = new SfxAllItemSet( SFX_APP()->GetPool() );
3082 return pImp->m_pSet;
3084 //----------------------------------------------------------------
3086 SvKeyValueIterator* SfxMedium::GetHeaderAttributes_Impl()
3088 if( !pImp->xAttributes.Is() )
3090 pImp->xAttributes = SvKeyValueIteratorRef( new SvKeyValueIterator );
3092 if ( GetContent().is() )
3096 Any aAny = pImp->aContent.getPropertyValue( OUString("MediaType") );
3097 OUString aContentType;
3098 aAny >>= aContentType;
3100 pImp->xAttributes->Append( SvKeyValue( OUString("content-type"), aContentType ) );
3102 catch ( const ::com::sun::star::uno::Exception& )
3108 return pImp->xAttributes;
3111 ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SfxMedium::GetInputStream()
3113 if ( !pImp->xInputStream.is() )
3114 GetMedium_Impl();
3115 return pImp->xInputStream;
3118 const uno::Sequence < util::RevisionTag >& SfxMedium::GetVersionList( bool _bNoReload )
3120 // if the medium has no name, then this medium should represent a new document and can have no version info
3121 if ( ( !_bNoReload || !pImp->m_bVersionsAlreadyLoaded ) && !pImp->aVersions.getLength() &&
3122 ( !pImp->m_aName.isEmpty() || !pImp->m_aLogicName.isEmpty() ) && GetStorage().is() )
3124 uno::Reference < document::XDocumentRevisionListPersistence > xReader =
3125 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3128 pImp->aVersions = xReader->load( GetStorage() );
3130 catch ( const uno::Exception& )
3135 if ( !pImp->m_bVersionsAlreadyLoaded )
3136 pImp->m_bVersionsAlreadyLoaded = true;
3138 return pImp->aVersions;
3141 uno::Sequence < util::RevisionTag > SfxMedium::GetVersionList( const uno::Reference < embed::XStorage >& xStorage )
3143 uno::Reference < document::XDocumentRevisionListPersistence > xReader =
3144 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3147 return xReader->load( xStorage );
3149 catch ( const uno::Exception& )
3153 return uno::Sequence < util::RevisionTag >();
3156 sal_uInt16 SfxMedium::AddVersion_Impl( util::RevisionTag& rRevision )
3158 if ( GetStorage().is() )
3160 // To determine a unique name for the stream
3161 std::vector<sal_uInt32> aLongs;
3162 sal_Int32 nLength = pImp->aVersions.getLength();
3163 for ( sal_Int32 m=0; m<nLength; m++ )
3165 sal_uInt32 nVer = static_cast<sal_uInt32>(String( pImp->aVersions[m].Identifier ).Copy(7).ToInt32());
3166 size_t n;
3167 for ( n=0; n<aLongs.size(); ++n )
3168 if ( nVer<aLongs[n] )
3169 break;
3171 aLongs.insert( aLongs.begin()+n, nVer );
3174 sal_uInt16 nKey;
3175 for ( nKey=0; nKey<aLongs.size(); ++nKey )
3176 if ( aLongs[nKey] > ( sal_uIntPtr ) nKey+1 )
3177 break;
3179 OUString aRevName = "Version" + OUString::number( nKey + 1 );
3180 pImp->aVersions.realloc( nLength+1 );
3181 rRevision.Identifier = aRevName;
3182 pImp->aVersions[nLength] = rRevision;
3183 return nKey;
3186 return 0;
3189 sal_Bool SfxMedium::RemoveVersion_Impl( const OUString& rName )
3191 if ( !pImp->aVersions.getLength() )
3192 return false;
3194 sal_Int32 nLength = pImp->aVersions.getLength();
3195 for ( sal_Int32 n=0; n<nLength; n++ )
3197 if ( pImp->aVersions[n].Identifier == rName )
3199 for ( sal_Int32 m=n; m<nLength-1; m++ )
3200 pImp->aVersions[m] = pImp->aVersions[m+1];
3201 pImp->aVersions.realloc(nLength-1);
3202 return true;
3206 return false;
3209 sal_Bool SfxMedium::TransferVersionList_Impl( SfxMedium& rMedium )
3211 if ( rMedium.pImp->aVersions.getLength() )
3213 pImp->aVersions = rMedium.pImp->aVersions;
3214 return true;
3217 return false;
3220 sal_Bool SfxMedium::SaveVersionList_Impl( sal_Bool /*bUseXML*/ )
3222 if ( GetStorage().is() )
3224 if ( !pImp->aVersions.getLength() )
3225 return true;
3227 uno::Reference < document::XDocumentRevisionListPersistence > xWriter =
3228 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3231 xWriter->store( GetStorage(), pImp->aVersions );
3232 return true;
3234 catch ( const uno::Exception& )
3239 return false;
3242 //----------------------------------------------------------------
3243 sal_Bool SfxMedium::IsReadOnly()
3245 // a) ReadOnly filter cant produce read/write contents!
3246 bool bReadOnly = (
3247 (pImp->m_pFilter ) &&
3248 ((pImp->m_pFilter->GetFilterFlags() & SFX_FILTER_OPENREADONLY) == SFX_FILTER_OPENREADONLY)
3251 // b) if filter allow read/write contents .. check open mode of the storage
3252 if (!bReadOnly)
3253 bReadOnly = !( GetOpenMode() & STREAM_WRITE );
3255 // c) the API can force the readonly state!
3256 if (!bReadOnly)
3258 SFX_ITEMSET_ARG( GetItemSet(), pItem, SfxBoolItem, SID_DOC_READONLY, false);
3259 if (pItem)
3260 bReadOnly = pItem->GetValue();
3263 return bReadOnly;
3266 bool SfxMedium::IsOriginallyReadOnly() const
3268 return pImp->m_bOriginallyReadOnly;
3271 //----------------------------------------------------------------
3272 sal_Bool SfxMedium::SetWritableForUserOnly( const OUString& aURL )
3274 // UCB does not allow to allow write access only for the user,
3275 // use osl API
3276 bool bResult = false;
3278 ::osl::DirectoryItem aDirItem;
3279 if ( ::osl::DirectoryItem::get( aURL, aDirItem ) == ::osl::FileBase::E_None )
3281 ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_Attributes );
3282 if ( aDirItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None
3283 && aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
3285 sal_uInt64 nAttributes = aFileStatus.getAttributes();
3287 nAttributes &= ~(osl_File_Attribute_OwnWrite |
3288 osl_File_Attribute_GrpWrite |
3289 osl_File_Attribute_OthWrite |
3290 osl_File_Attribute_ReadOnly);
3291 nAttributes |= (osl_File_Attribute_OwnWrite |
3292 osl_File_Attribute_OwnRead);
3294 bResult = ( osl::File::setAttributes( aURL, nAttributes ) == ::osl::FileBase::E_None );
3298 return bResult;
3301 //----------------------------------------------------------------
3302 void SfxMedium::CreateTempFile( sal_Bool bReplace )
3304 if ( pImp->pTempFile )
3306 if ( !bReplace )
3307 return;
3309 DELETEZ( pImp->pTempFile );
3310 pImp->m_aName = OUString();
3313 pImp->pTempFile = new ::utl::TempFile();
3314 pImp->pTempFile->EnableKillingFile( true );
3315 pImp->m_aName = pImp->pTempFile->GetFileName();
3316 OUString aTmpURL = pImp->pTempFile->GetURL();
3317 if ( pImp->m_aName.isEmpty() || aTmpURL.isEmpty() )
3319 SetError( ERRCODE_IO_CANTWRITE, OUString( OSL_LOG_PREFIX ) );
3320 return;
3323 if ( !(pImp->m_nStorOpenMode & STREAM_TRUNC) )
3325 bool bTransferSuccess = false;
3327 if ( GetContent().is()
3328 && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
3329 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
3331 // if there is already such a document, we should copy it
3332 // if it is a file system use OS copy process
3335 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
3336 INetURLObject aTmpURLObj( aTmpURL );
3337 OUString aFileName = aTmpURLObj.getName( INetURLObject::LAST_SEGMENT,
3338 true,
3339 INetURLObject::DECODE_WITH_CHARSET );
3340 if ( !aFileName.isEmpty() && aTmpURLObj.removeSegment() )
3342 ::ucbhelper::Content aTargetContent( aTmpURLObj.GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext() );
3343 OUString sMimeType = pImp->getFilterMimeType();
3344 if ( aTargetContent.transferContent( pImp->aContent, ::ucbhelper::InsertOperation_COPY, aFileName, NameClash::OVERWRITE, sMimeType ) )
3346 SetWritableForUserOnly( aTmpURL );
3347 bTransferSuccess = true;
3351 catch( const uno::Exception& )
3354 if ( bTransferSuccess )
3356 CloseOutStream();
3357 CloseInStream();
3361 if ( !bTransferSuccess && pImp->m_pInStream )
3363 // the case when there is no URL-access available or this is a remote protocoll
3364 // but there is an input stream
3365 GetOutStream();
3366 if ( pImp->m_pOutStream )
3368 char *pBuf = new char [8192];
3369 sal_uInt32 nErr = ERRCODE_NONE;
3371 pImp->m_pInStream->Seek(0);
3372 pImp->m_pOutStream->Seek(0);
3374 while( !pImp->m_pInStream->IsEof() && nErr == ERRCODE_NONE )
3376 sal_uInt32 nRead = pImp->m_pInStream->Read( pBuf, 8192 );
3377 nErr = pImp->m_pInStream->GetError();
3378 pImp->m_pOutStream->Write( pBuf, nRead );
3381 bTransferSuccess = true;
3382 delete[] pBuf;
3383 CloseInStream();
3385 CloseOutStream_Impl();
3387 else
3389 // Quite strange design, but currently it is expected that in this case no transfer happens
3390 // TODO/LATER: get rid of this inconsistent part of the call design
3391 bTransferSuccess = true;
3392 CloseInStream();
3395 if ( !bTransferSuccess )
3397 SetError( ERRCODE_IO_CANTWRITE, OUString( OSL_LOG_PREFIX ) );
3398 return;
3402 CloseStorage();
3405 //----------------------------------------------------------------
3406 void SfxMedium::CreateTempFileNoCopy()
3408 // this call always replaces the existing temporary file
3409 if ( pImp->pTempFile )
3410 delete pImp->pTempFile;
3412 pImp->pTempFile = new ::utl::TempFile();
3413 pImp->pTempFile->EnableKillingFile( true );
3414 pImp->m_aName = pImp->pTempFile->GetFileName();
3415 if ( pImp->m_aName.isEmpty() )
3417 SetError( ERRCODE_IO_CANTWRITE, OUString( OSL_LOG_PREFIX ) );
3418 return;
3421 CloseOutStream_Impl();
3422 CloseStorage();
3425 sal_Bool SfxMedium::SignContents_Impl( sal_Bool bScriptingContent, const OUString& aODFVersion, sal_Bool bHasValidDocumentSignature )
3427 bool bChanges = false;
3429 // the medium should be closed to be able to sign, the caller is responsible to close it
3430 if ( !IsOpen() && !GetError() )
3432 // The component should know if there was a valid document signature, since
3433 // it should show a warning in this case
3434 uno::Reference< security::XDocumentDigitalSignatures > xSigner(
3435 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
3436 comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
3438 uno::Reference< embed::XStorage > xWriteableZipStor;
3439 if ( !IsReadOnly() )
3441 // we can reuse the temporary file if there is one already
3442 CreateTempFile( false );
3443 GetMedium_Impl();
3447 if ( !pImp->xStream.is() )
3448 throw uno::RuntimeException();
3450 xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImp->xStream );
3451 if ( !xWriteableZipStor.is() )
3452 throw uno::RuntimeException();
3454 uno::Reference< embed::XStorage > xMetaInf = xWriteableZipStor->openStorageElement(
3455 OUString( "META-INF" ),
3456 embed::ElementModes::READWRITE );
3457 if ( !xMetaInf.is() )
3458 throw uno::RuntimeException();
3460 if ( bScriptingContent )
3462 // If the signature has already the document signature it will be removed
3463 // after the scripting signature is inserted.
3464 uno::Reference< io::XStream > xStream(
3465 xMetaInf->openStreamElement( xSigner->getScriptingContentSignatureDefaultStreamName(),
3466 embed::ElementModes::READWRITE ),
3467 uno::UNO_SET_THROW );
3469 if ( xSigner->signScriptingContent( GetZipStorageToSign_Impl(), xStream ) )
3471 // remove the document signature if any
3472 OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName();
3473 if ( !aDocSigName.isEmpty() && xMetaInf->hasByName( aDocSigName ) )
3474 xMetaInf->removeElement( aDocSigName );
3476 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
3477 xTransact->commit();
3478 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
3479 xTransact->commit();
3481 // the temporary file has been written, commit it to the original file
3482 Commit();
3483 bChanges = true;
3486 else
3488 uno::Reference< io::XStream > xStream(
3489 xMetaInf->openStreamElement( xSigner->getDocumentContentSignatureDefaultStreamName(),
3490 embed::ElementModes::READWRITE ),
3491 uno::UNO_SET_THROW );
3493 if ( xSigner->signDocumentContent( GetZipStorageToSign_Impl(), xStream ) )
3495 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
3496 xTransact->commit();
3497 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
3498 xTransact->commit();
3500 // the temporary file has been written, commit it to the original file
3501 Commit();
3502 bChanges = true;
3506 catch ( const uno::Exception& )
3508 OSL_FAIL( "Couldn't use signing functionality!\n" );
3511 CloseAndRelease();
3513 else
3517 if ( bScriptingContent )
3518 xSigner->showScriptingContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() );
3519 else
3520 xSigner->showDocumentContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() );
3522 catch( const uno::Exception& )
3524 OSL_FAIL( "Couldn't use signing functionality!\n" );
3528 ResetError();
3531 return bChanges;
3534 //----------------------------------------------------------------
3535 sal_uInt16 SfxMedium::GetCachedSignatureState_Impl()
3537 return pImp->m_nSignatureState;
3540 //----------------------------------------------------------------
3541 void SfxMedium::SetCachedSignatureState_Impl( sal_uInt16 nState )
3543 pImp->m_nSignatureState = nState;
3546 sal_Bool SfxMedium::HasStorage_Impl() const
3548 return pImp->xStorage.is();
3551 sal_Bool SfxMedium::IsOpen() const
3553 return pImp->m_pInStream || pImp->m_pOutStream || pImp->xStorage.is();
3556 OUString SfxMedium::CreateTempCopyWithExt( const OUString& aURL )
3558 OUString aResult;
3560 if ( !aURL.isEmpty() )
3562 sal_Int32 nPrefixLen = aURL.lastIndexOf( '.' );
3563 String aExt = ( nPrefixLen == -1 ) ? String() : String( aURL.copy( nPrefixLen ) );
3565 OUString aNewTempFileURL = ::utl::TempFile( String(), &aExt ).GetURL();
3566 if ( !aNewTempFileURL.isEmpty() )
3568 INetURLObject aSource( aURL );
3569 INetURLObject aDest( aNewTempFileURL );
3570 OUString aFileName = aDest.getName( INetURLObject::LAST_SEGMENT,
3571 true,
3572 INetURLObject::DECODE_WITH_CHARSET );
3573 if ( !aFileName.isEmpty() && aDest.removeSegment() )
3577 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
3578 ::ucbhelper::Content aTargetContent( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext() );
3579 ::ucbhelper::Content aSourceContent( aSource.GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext() );
3580 if ( aTargetContent.transferContent( aSourceContent,
3581 ::ucbhelper::InsertOperation_COPY,
3582 aFileName,
3583 NameClash::OVERWRITE ) )
3585 // Success
3586 aResult = aNewTempFileURL;
3589 catch( const uno::Exception& )
3595 return aResult;
3598 sal_Bool SfxMedium::CallApproveHandler( const uno::Reference< task::XInteractionHandler >& xHandler, uno::Any aRequest, sal_Bool bAllowAbort )
3600 bool bResult = false;
3602 if ( xHandler.is() )
3606 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( bAllowAbort ? 2 : 1 );
3608 ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( new ::comphelper::OInteractionApprove );
3609 aContinuations[ 0 ] = pApprove.get();
3611 if ( bAllowAbort )
3613 ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( new ::comphelper::OInteractionAbort );
3614 aContinuations[ 1 ] = pAbort.get();
3617 xHandler->handle(::framework::InteractionRequest::CreateRequest (aRequest,aContinuations));
3618 bResult = pApprove->wasSelected();
3620 catch( const Exception& )
3625 return bResult;
3628 OUString SfxMedium::SwitchDocumentToTempFile()
3630 // the method returns empty string in case of failure
3631 OUString aResult;
3632 OUString aOrigURL = pImp->m_aLogicName;
3634 if ( !aOrigURL.isEmpty() )
3636 sal_Int32 nPrefixLen = aOrigURL.lastIndexOf( '.' );
3637 String aExt = ( nPrefixLen == -1 ) ? String() : String( aOrigURL.copy( nPrefixLen ) );
3638 OUString aNewURL = ::utl::TempFile( String(), &aExt ).GetURL();
3640 // TODO/LATER: In future the aLogicName should be set to shared folder URL
3641 // and a temporary file should be created. Transport_Impl should be impossible then.
3642 if ( !aNewURL.isEmpty() )
3644 uno::Reference< embed::XStorage > xStorage = GetStorage();
3645 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
3647 if ( xOptStorage.is() )
3649 // TODO/LATER: reuse the pImp->pTempFile if it already exists
3650 CanDisposeStorage_Impl( false );
3651 Close();
3652 SetPhysicalName_Impl( String() );
3653 SetName( aNewURL );
3655 // remove the readonly state
3656 bool bWasReadonly = false;
3657 pImp->m_nStorOpenMode = SFX_STREAM_READWRITE;
3658 SFX_ITEMSET_ARG( pImp->m_pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, false );
3659 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
3660 bWasReadonly = true;
3661 GetItemSet()->ClearItem( SID_DOC_READONLY );
3663 GetMedium_Impl();
3664 LockOrigFileOnDemand( false, false );
3665 CreateTempFile( true );
3666 GetMedium_Impl();
3668 if ( pImp->xStream.is() )
3672 xOptStorage->writeAndAttachToStream( pImp->xStream );
3673 pImp->xStorage = xStorage;
3674 aResult = aNewURL;
3676 catch( const uno::Exception& )
3680 if ( aResult.isEmpty() )
3682 Close();
3683 SetPhysicalName_Impl( String() );
3684 SetName( aOrigURL );
3685 if ( bWasReadonly )
3687 // set the readonly state back
3688 pImp->m_nStorOpenMode = SFX_STREAM_READONLY;
3689 GetItemSet()->Put( SfxBoolItem(SID_DOC_READONLY, true));
3691 GetMedium_Impl();
3692 pImp->xStorage = xStorage;
3698 return aResult;
3701 sal_Bool SfxMedium::SwitchDocumentToFile( const OUString& aURL )
3703 // the method is only for storage based documents
3704 bool bResult = false;
3705 OUString aOrigURL = pImp->m_aLogicName;
3707 if ( !aURL.isEmpty() && !aOrigURL.isEmpty() )
3709 uno::Reference< embed::XStorage > xStorage = GetStorage();
3710 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
3712 if ( xOptStorage.is() )
3714 // TODO/LATER: reuse the pImp->pTempFile if it already exists
3715 CanDisposeStorage_Impl( false );
3716 Close();
3717 SetPhysicalName_Impl( String() );
3718 SetName( aURL );
3720 // open the temporary file based document
3721 GetMedium_Impl();
3722 LockOrigFileOnDemand( false, false );
3723 CreateTempFile( true );
3724 GetMedium_Impl();
3726 if ( pImp->xStream.is() )
3730 uno::Reference< io::XTruncate > xTruncate( pImp->xStream, uno::UNO_QUERY_THROW );
3731 if ( xTruncate.is() )
3732 xTruncate->truncate();
3734 xOptStorage->writeAndAttachToStream( pImp->xStream );
3735 pImp->xStorage = xStorage;
3736 bResult = true;
3738 catch( const uno::Exception& )
3742 if ( !bResult )
3744 Close();
3745 SetPhysicalName_Impl( String() );
3746 SetName( aOrigURL );
3747 GetMedium_Impl();
3748 pImp->xStorage = xStorage;
3753 return bResult;
3756 void SfxMedium::SetInCheckIn( bool bInCheckIn )
3758 pImp->m_bInCheckIn = bInCheckIn;
3761 bool SfxMedium::IsInCheckIn( )
3763 return pImp->m_bInCheckIn;
3766 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */