Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / doc / docfile.cxx
blobb20fc573721442e7ea50ee1cde208b09642cb107
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 #if HAVE_FEATURE_MACOSX_SANDBOX
147 return true;
148 #else
149 // check whether system file locking has been used, the default value is false
150 bool bUseSystemLock = false;
154 uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig(
155 ::comphelper::getProcessComponentContext(),
156 OUString( "/org.openoffice.Office.Common" ),
157 ::comphelper::ConfigurationHelper::E_STANDARD );
158 if ( !xCommonConfig.is() )
159 throw uno::RuntimeException();
161 ::comphelper::ConfigurationHelper::readRelativeKey(
162 xCommonConfig,
163 OUString( "Misc/" ),
164 OUString( "UseDocumentSystemFileLocking" ) ) >>= bUseSystemLock;
166 catch( const uno::Exception& )
170 return bUseSystemLock;
171 #endif
174 //----------------------------------------------------------------
175 bool IsOOoLockFileUsed()
177 #if HAVE_FEATURE_MACOSX_SANDBOX
178 return false;
179 #else
180 // check whether system file locking has been used, the default value is false
181 bool bOOoLockFileUsed = false;
185 uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig(
186 ::comphelper::getProcessComponentContext(),
187 OUString( "/org.openoffice.Office.Common" ),
188 ::comphelper::ConfigurationHelper::E_STANDARD );
189 if ( !xCommonConfig.is() )
190 throw uno::RuntimeException();
192 ::comphelper::ConfigurationHelper::readRelativeKey(
193 xCommonConfig,
194 OUString( "Misc/" ),
195 OUString( "UseDocumentOOoLockFile" ) ) >>= bOOoLockFileUsed;
197 catch( const uno::Exception& )
201 return bOOoLockFileUsed;
202 #endif
205 bool IsLockingUsed()
207 return officecfg::Office::Common::Misc::UseLocking::get();
210 #endif
212 } // anonymous namespace
213 //==========================================================
216 //----------------------------------------------------------------
217 class SfxMediumHandler_Impl : public ::cppu::WeakImplHelper1< com::sun::star::task::XInteractionHandler >
219 com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > m_xInter;
221 public:
222 virtual void SAL_CALL handle( const com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest >& xRequest )
223 throw( com::sun::star::uno::RuntimeException );
225 SfxMediumHandler_Impl( com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > xInteraction )
226 : m_xInter( xInteraction )
229 ~SfxMediumHandler_Impl();
232 //----------------------------------------------------------------
233 SfxMediumHandler_Impl::~SfxMediumHandler_Impl()
237 //----------------------------------------------------------------
238 void SAL_CALL SfxMediumHandler_Impl::handle( const com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest >& xRequest )
239 throw( com::sun::star::uno::RuntimeException )
241 if( !m_xInter.is() )
242 return;
244 com::sun::star::uno::Any aRequest = xRequest->getRequest();
245 com::sun::star::ucb::InteractiveIOException aIoException;
246 com::sun::star::ucb::UnsupportedDataSinkException aSinkException;
247 if ( (aRequest >>= aIoException) && ( aIoException.Code == IOErrorCode_ACCESS_DENIED || aIoException.Code == IOErrorCode_LOCKING_VIOLATION ) )
248 return;
249 else
250 if ( aRequest >>= aSinkException )
251 return;
252 else
253 m_xInter->handle( xRequest );
256 class SfxMedium_Impl : boost::noncopyable
258 public:
259 StreamMode m_nStorOpenMode;
260 sal_uInt32 m_eError;
262 ::ucbhelper::Content aContent;
263 bool bUpdatePickList:1;
264 bool bIsTemp:1;
265 bool bDownloadDone:1;
266 bool bIsStorage:1;
267 bool bUseInteractionHandler:1;
268 bool bAllowDefaultIntHdl:1;
269 bool bDisposeStorage:1;
270 bool bStorageBasedOnInStream:1;
271 bool m_bSalvageMode:1;
272 bool m_bVersionsAlreadyLoaded:1;
273 bool m_bLocked:1;
274 bool m_bGotDateTime:1;
275 bool m_bRemoveBackup:1;
276 bool m_bOriginallyReadOnly:1;
277 bool m_bTriedStorage:1;
278 bool m_bRemote:1;
279 bool m_bInputStreamIsReadOnly:1;
280 bool m_bInCheckIn:1;
282 OUString m_aName;
283 OUString m_aLogicName;
284 OUString m_aLongName;
286 mutable SfxItemSet* m_pSet;
287 mutable INetURLObject* m_pURLObj;
289 const SfxFilter* m_pFilter;
290 boost::scoped_ptr<SfxFilter> m_pCustomFilter;
292 SfxMedium* pAntiImpl;
293 SvStream* m_pInStream;
294 SvStream* m_pOutStream;
296 const SfxFilter* pOrigFilter;
297 OUString aOrigURL;
298 DateTime aExpireTime;
299 SfxFrameWeak wLoadTargetFrame;
300 SvKeyValueIteratorRef xAttributes;
302 svtools::AsynchronLink aDoneLink;
304 uno::Sequence < util::RevisionTag > aVersions;
306 ::utl::TempFile* pTempFile;
308 uno::Reference<embed::XStorage> xStorage;
309 uno::Reference<embed::XStorage> m_xZipStorage;
310 uno::Reference<io::XInputStream> m_xInputStreamToLoadFrom;
311 uno::Reference<io::XInputStream> xInputStream;
312 uno::Reference<io::XStream> xStream;
313 uno::Reference<io::XStream> m_xLockingStream;
314 uno::Reference<task::XInteractionHandler> xInteraction;
315 uno::Reference<logging::XSimpleLogRing> m_xLogRing;
317 sal_uInt32 nLastStorageError;
319 OUString m_aBackupURL;
321 // the following member is changed and makes sense only during saving
322 // TODO/LATER: in future the signature state should be controlled by the medium not by the document
323 // in this case the member will hold this information
324 sal_uInt16 m_nSignatureState;
326 util::DateTime m_aDateTime;
328 SfxMedium_Impl( SfxMedium* pAntiImplP );
329 ~SfxMedium_Impl();
331 OUString getFilterMimeType()
332 { return m_pFilter == 0 ? OUString() : m_pFilter->GetMimeType(); }
335 //------------------------------------------------------------------
336 SfxMedium_Impl::SfxMedium_Impl( SfxMedium* pAntiImplP ) :
337 m_nStorOpenMode(SFX_STREAM_READWRITE),
338 m_eError(SVSTREAM_OK),
339 bUpdatePickList(true),
340 bIsTemp( false ),
341 bDownloadDone( true ),
342 bIsStorage( false ),
343 bUseInteractionHandler( true ),
344 bAllowDefaultIntHdl( false ),
345 bDisposeStorage( false ),
346 bStorageBasedOnInStream( false ),
347 m_bSalvageMode( false ),
348 m_bVersionsAlreadyLoaded( false ),
349 m_bLocked( false ),
350 m_bGotDateTime( false ),
351 m_bRemoveBackup( false ),
352 m_bOriginallyReadOnly(false),
353 m_bTriedStorage(false),
354 m_bRemote(false),
355 m_bInputStreamIsReadOnly(false),
356 m_bInCheckIn(false),
357 m_pSet(NULL),
358 m_pURLObj(NULL),
359 m_pFilter(NULL),
360 pAntiImpl( pAntiImplP ),
361 m_pInStream(NULL),
362 m_pOutStream(NULL),
363 pOrigFilter( 0 ),
364 aExpireTime( Date( Date::SYSTEM ) + 10, Time( Time::SYSTEM ) ),
365 pTempFile( NULL ),
366 nLastStorageError( 0 ),
367 m_nSignatureState( SIGNATURESTATE_NOSIGNATURES )
369 aDoneLink.CreateMutex();
372 //------------------------------------------------------------------
373 SfxMedium_Impl::~SfxMedium_Impl()
375 aDoneLink.ClearPendingCall();
377 delete pTempFile;
378 delete m_pSet;
379 delete m_pURLObj;
382 void SfxMedium::ResetError()
384 pImp->m_eError = SVSTREAM_OK;
385 if( pImp->m_pInStream )
386 pImp->m_pInStream->ResetError();
387 if( pImp->m_pOutStream )
388 pImp->m_pOutStream->ResetError();
391 //------------------------------------------------------------------
392 sal_uInt32 SfxMedium::GetLastStorageCreationState()
394 return pImp->nLastStorageError;
397 //------------------------------------------------------------------
398 void SfxMedium::AddLog( const OUString& aMessage )
400 if ( !pImp->m_xLogRing.is() )
404 Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
405 pImp->m_xLogRing.set( logging::DocumentIOLogRing::get(xContext) );
407 catch( const uno::Exception& )
411 if ( pImp->m_xLogRing.is() )
412 pImp->m_xLogRing->logString( aMessage );
415 //------------------------------------------------------------------
416 void SfxMedium::SetError( sal_uInt32 nError, const OUString& aLogMessage )
418 pImp->m_eError = nError;
419 if ( pImp->m_eError != ERRCODE_NONE && !aLogMessage.isEmpty() )
420 AddLog( aLogMessage );
423 //------------------------------------------------------------------
424 sal_uInt32 SfxMedium::GetErrorCode() const
426 sal_uInt32 lError = pImp->m_eError;
427 if(!lError && pImp->m_pInStream)
428 lError = pImp->m_pInStream->GetErrorCode();
429 if(!lError && pImp->m_pOutStream)
430 lError = pImp->m_pOutStream->GetErrorCode();
431 return lError;
434 //------------------------------------------------------------------
435 void SfxMedium::CheckFileDate( const util::DateTime& aInitDate )
437 GetInitFileDate( true );
438 if ( pImp->m_aDateTime.Seconds != aInitDate.Seconds
439 || pImp->m_aDateTime.Minutes != aInitDate.Minutes
440 || pImp->m_aDateTime.Hours != aInitDate.Hours
441 || pImp->m_aDateTime.Day != aInitDate.Day
442 || pImp->m_aDateTime.Month != aInitDate.Month
443 || pImp->m_aDateTime.Year != aInitDate.Year )
445 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
447 if ( xHandler.is() )
451 ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
452 document::ChangedByOthersRequest() ) );
453 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 );
454 aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
455 aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
456 xInteractionRequestImpl->setContinuations( aContinuations );
458 xHandler->handle( xInteractionRequestImpl.get() );
460 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
461 if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() )
463 SetError( ERRCODE_ABORT, OUString( OSL_LOG_PREFIX ) );
466 catch ( const uno::Exception& )
472 //------------------------------------------------------------------
473 sal_Bool SfxMedium::DocNeedsFileDateCheck()
475 return ( !IsReadOnly() && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) );
478 //------------------------------------------------------------------
479 util::DateTime SfxMedium::GetInitFileDate( sal_Bool bIgnoreOldValue )
481 if ( ( bIgnoreOldValue || !pImp->m_bGotDateTime ) && !pImp->m_aLogicName.isEmpty() )
485 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
486 ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, comphelper::getProcessComponentContext() );
488 aContent.getPropertyValue( OUString("DateModified" ) ) >>= pImp->m_aDateTime;
489 pImp->m_bGotDateTime = true;
491 catch ( const ::com::sun::star::uno::Exception& )
496 return pImp->m_aDateTime;
499 //------------------------------------------------------------------
500 Reference < XContent > SfxMedium::GetContent() const
502 if ( !pImp->aContent.get().is() )
504 Reference < ::com::sun::star::ucb::XContent > xContent;
505 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
507 SFX_ITEMSET_ARG( pImp->m_pSet, pItem, SfxUnoAnyItem, SID_CONTENT, false);
508 if ( pItem )
509 pItem->GetValue() >>= xContent;
511 if ( xContent.is() )
515 pImp->aContent = ::ucbhelper::Content( xContent, xEnv, comphelper::getProcessComponentContext() );
517 catch ( const Exception& )
521 else
523 // TODO: OSL_FAIL("SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why its used.");
524 OUString aURL;
525 if ( !pImp->m_aName.isEmpty() )
526 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aURL );
527 else if ( !pImp->m_aLogicName.isEmpty() )
528 aURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
529 if (!aURL.isEmpty() )
530 ::ucbhelper::Content::create( aURL, xEnv, comphelper::getProcessComponentContext(), pImp->aContent );
534 return pImp->aContent.get();
537 //------------------------------------------------------------------
538 OUString SfxMedium::GetBaseURL( bool bForSaving )
540 OUString aBaseURL;
541 const SfxStringItem* pBaseURLItem = static_cast<const SfxStringItem*>( GetItemSet()->GetItem(SID_DOC_BASEURL) );
542 if ( pBaseURLItem )
543 aBaseURL = pBaseURLItem->GetValue();
544 else if ( GetContent().is() )
548 Any aAny = pImp->aContent.getPropertyValue( OUString("BaseURI" ) );
549 aAny >>= aBaseURL;
551 catch ( const ::com::sun::star::uno::Exception& )
555 if ( aBaseURL.isEmpty() )
556 aBaseURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
559 if ( bForSaving )
561 SvtSaveOptions aOpt;
562 bool bIsRemote = IsRemote();
563 if( (bIsRemote && !aOpt.IsSaveRelINet()) || (!pImp->m_bRemote && !aOpt.IsSaveRelFSys()) )
564 return OUString();
567 return aBaseURL;
570 //------------------------------------------------------------------
571 SvStream* SfxMedium::GetInStream()
573 if ( pImp->m_pInStream )
574 return pImp->m_pInStream;
576 if ( pImp->pTempFile )
578 pImp->m_pInStream = new SvFileStream(pImp->m_aName, pImp->m_nStorOpenMode);
580 pImp->m_eError = pImp->m_pInStream->GetError();
582 if (!pImp->m_eError && (pImp->m_nStorOpenMode & STREAM_WRITE)
583 && ! pImp->m_pInStream->IsWritable() )
585 pImp->m_eError = ERRCODE_IO_ACCESSDENIED;
586 delete pImp->m_pInStream;
587 pImp->m_pInStream = NULL;
589 else
590 return pImp->m_pInStream;
593 GetMedium_Impl();
595 if ( GetError() )
596 return NULL;
598 return pImp->m_pInStream;
601 //------------------------------------------------------------------
602 void SfxMedium::CloseInStream()
604 CloseInStream_Impl();
607 void SfxMedium::CloseInStream_Impl()
609 // if there is a storage based on the InStream, we have to
610 // close the storage, too, because otherwise the storage
611 // would use an invalid ( deleted ) stream.
612 if ( pImp->m_pInStream && pImp->xStorage.is() )
614 if ( pImp->bStorageBasedOnInStream )
615 CloseStorage();
618 if ( pImp->m_pInStream && !GetContent().is() )
620 CreateTempFile( true );
621 return;
624 DELETEZ( pImp->m_pInStream );
625 if ( pImp->m_pSet )
626 pImp->m_pSet->ClearItem( SID_INPUTSTREAM );
628 CloseZipStorage_Impl();
629 pImp->xInputStream.clear();
631 if ( !pImp->m_pOutStream )
633 // output part of the stream is not used so the whole stream can be closed
634 // TODO/LATER: is it correct?
635 pImp->xStream.clear();
636 if ( pImp->m_pSet )
637 pImp->m_pSet->ClearItem( SID_STREAM );
641 //------------------------------------------------------------------
642 SvStream* SfxMedium::GetOutStream()
644 if ( !pImp->m_pOutStream )
646 // Create a temp. file if there is none because we always
647 // need one.
648 CreateTempFile( false );
650 if ( pImp->pTempFile )
652 // On windows we try to re-use XOutStream from xStream if that exists;
653 // because opening new SvFileStream in this situation may fail with ERROR_SHARING_VIOLATION
654 #ifdef WNT
655 if (pImp->xStream.is())
657 assert(pImp->xStream->getOutputStream().is()); // need that...
658 pImp->m_pOutStream = utl::UcbStreamHelper::CreateStream(
659 pImp->xStream, false);
661 else
663 pImp->m_pOutStream = new SvFileStream(
664 pImp->m_aName, STREAM_STD_READWRITE);
666 // On Unix don't try to re-use XOutStream from xStream if that exists;
667 // it causes fdo#59022 (fails opening files via SMB on Linux)
668 #else
669 pImp->m_pOutStream = new SvFileStream(
670 pImp->m_aName, STREAM_STD_READWRITE);
671 #endif
672 CloseStorage();
676 return pImp->m_pOutStream;
679 //------------------------------------------------------------------
680 sal_Bool SfxMedium::CloseOutStream()
682 CloseOutStream_Impl();
683 return true;
686 sal_Bool SfxMedium::CloseOutStream_Impl()
688 if ( pImp->m_pOutStream )
690 // if there is a storage based on the OutStream, we have to
691 // close the storage, too, because otherwise the storage
692 // would use an invalid ( deleted ) stream.
693 //TODO/MBA: how to deal with this?!
694 //maybe we need a new flag when the storage was created from the outstream
695 if ( pImp->xStorage.is() )
697 CloseStorage();
700 delete pImp->m_pOutStream;
701 pImp->m_pOutStream = NULL;
704 if ( !pImp->m_pInStream )
706 // input part of the stream is not used so the whole stream can be closed
707 // TODO/LATER: is it correct?
708 pImp->xStream.clear();
709 if ( pImp->m_pSet )
710 pImp->m_pSet->ClearItem( SID_STREAM );
713 return true;
716 //------------------------------------------------------------------
717 const OUString& SfxMedium::GetPhysicalName() const
719 if ( pImp->m_aName.isEmpty() && !pImp->m_aLogicName.isEmpty() )
720 (( SfxMedium*)this)->CreateFileStream();
722 // return the name then
723 return pImp->m_aName;
726 //------------------------------------------------------------------
727 void SfxMedium::CreateFileStream()
729 ForceSynchronStream_Impl( true );
730 GetInStream();
731 if( pImp->m_pInStream )
733 CreateTempFile( false );
734 pImp->bIsTemp = true;
735 CloseInStream_Impl();
739 //------------------------------------------------------------------
740 sal_Bool SfxMedium::Commit()
742 if( pImp->xStorage.is() )
743 StorageCommit_Impl();
744 else if( pImp->m_pOutStream )
745 pImp->m_pOutStream->Flush();
746 else if( pImp->m_pInStream )
747 pImp->m_pInStream->Flush();
749 if ( GetError() == SVSTREAM_OK )
751 // does something only in case there is a temporary file ( means aName points to different location than aLogicName )
752 Transfer_Impl();
755 bool bResult = ( GetError() == SVSTREAM_OK );
757 if ( bResult && DocNeedsFileDateCheck() )
758 GetInitFileDate( true );
760 // remove truncation mode from the flags
761 pImp->m_nStorOpenMode &= (~STREAM_TRUNC);
762 return bResult;
765 //------------------------------------------------------------------
766 sal_Bool SfxMedium::IsStorage()
768 if ( pImp->xStorage.is() )
769 return true;
771 if ( pImp->m_bTriedStorage )
772 return pImp->bIsStorage;
774 if ( pImp->pTempFile )
776 OUString aURL;
777 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aURL ) )
779 OSL_FAIL("Physical name not convertible!");
781 pImp->bIsStorage = SotStorage::IsStorageFile( aURL ) && !SotStorage::IsOLEStorage( aURL);
782 if ( !pImp->bIsStorage )
783 pImp->m_bTriedStorage = true;
785 else if ( GetInStream() )
787 pImp->bIsStorage = SotStorage::IsStorageFile( pImp->m_pInStream ) && !SotStorage::IsOLEStorage( pImp->m_pInStream );
788 if ( !pImp->m_pInStream->GetError() && !pImp->bIsStorage )
789 pImp->m_bTriedStorage = true;
792 return pImp->bIsStorage;
795 //------------------------------------------------------------------
796 sal_Bool SfxMedium::IsPreview_Impl()
798 bool bPreview = false;
799 SFX_ITEMSET_ARG( GetItemSet(), pPreview, SfxBoolItem, SID_PREVIEW, false);
800 if ( pPreview )
801 bPreview = pPreview->GetValue();
802 else
804 SFX_ITEMSET_ARG( GetItemSet(), pFlags, SfxStringItem, SID_OPTIONS, false);
805 if ( pFlags )
807 String aFileFlags = pFlags->GetValue();
808 aFileFlags.ToUpperAscii();
809 if ( STRING_NOTFOUND != aFileFlags.Search( 'B' ) )
810 bPreview = true;
814 return bPreview;
817 //------------------------------------------------------------------
818 void SfxMedium::StorageBackup_Impl()
820 ::ucbhelper::Content aOriginalContent;
821 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
823 bool bBasedOnOriginalFile = ( !pImp->pTempFile && !( !pImp->m_aLogicName.isEmpty() && pImp->m_bSalvageMode )
824 && !GetURLObject().GetMainURL( INetURLObject::NO_DECODE ).isEmpty()
825 && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
826 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) );
828 if ( bBasedOnOriginalFile && pImp->m_aBackupURL.isEmpty()
829 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, comphelper::getProcessComponentContext(), aOriginalContent ) )
831 DoInternalBackup_Impl( aOriginalContent );
832 if( pImp->m_aBackupURL.isEmpty() )
833 SetError( ERRCODE_SFX_CANTCREATEBACKUP, OUString( OSL_LOG_PREFIX ) );
837 //------------------------------------------------------------------
838 OUString SfxMedium::GetBackup_Impl()
840 if ( pImp->m_aBackupURL.isEmpty() )
841 StorageBackup_Impl();
843 return pImp->m_aBackupURL;
846 //------------------------------------------------------------------
847 uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage()
849 if ( GetError() )
850 return uno::Reference< embed::XStorage >();
852 // if the medium was constructed with a Storage: use this one, not a temp. storage
853 // if a temporary storage already exists: use it
854 if ( pImp->xStorage.is() && ( pImp->m_aLogicName.isEmpty() || pImp->pTempFile ) )
855 return pImp->xStorage;
857 // if necessary close stream that was used for reading
858 if ( pImp->m_pInStream && !pImp->m_pInStream->IsWritable() )
859 CloseInStream();
861 DBG_ASSERT( !pImp->m_pOutStream, "OutStream in a readonly Medium?!" );
863 // TODO/LATER: The current solution is to store the document temporary and then copy it to the target location;
864 // in future it should be stored directly and then copied to the temporary location, since in this case no
865 // file attributes have to be preserved and system copying mechanics could be used instead of streaming.
866 CreateTempFileNoCopy();
868 return GetStorage();
871 //------------------------------------------------------------------
872 void SfxMedium::SetEncryptionDataToStorage_Impl()
874 // in case media-descriptor contains password it should be used on opening
875 if ( pImp->xStorage.is() && pImp->m_pSet )
877 uno::Sequence< beans::NamedValue > aEncryptionData;
878 if ( GetEncryptionData_Impl( pImp->m_pSet, aEncryptionData ) )
880 // replace the password with encryption data
881 pImp->m_pSet->ClearItem( SID_PASSWORD );
882 pImp->m_pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
886 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( pImp->xStorage, aEncryptionData );
888 catch( const uno::Exception& )
890 OSL_FAIL( "It must be possible to set a common password for the storage" );
891 // TODO/LATER: set the error code in case of problem
892 // SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
898 //------------------------------------------------------------------
899 sal_Int8 SfxMedium::ShowLockedDocumentDialog( const uno::Sequence< OUString >& aData, sal_Bool bIsLoading, sal_Bool bOwnLock )
901 sal_Int8 nResult = LOCK_UI_NOLOCK;
903 // show the interaction regarding the document opening
904 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
906 if ( ::svt::DocumentLockFile::IsInteractionAllowed() && xHandler.is() && ( bIsLoading || bOwnLock ) )
908 OUString aDocumentURL = GetURLObject().GetLastName();
909 OUString aInfo;
910 ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl;
912 if ( bOwnLock )
914 if ( aData.getLength() > LOCKFILE_EDITTIME_ID )
915 aInfo = aData[LOCKFILE_EDITTIME_ID];
917 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
918 document::OwnLockOnDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo, !bIsLoading ) ) );
920 else
922 if ( aData.getLength() > LOCKFILE_EDITTIME_ID )
924 if ( !aData[LOCKFILE_OOOUSERNAME_ID].isEmpty() )
925 aInfo = aData[LOCKFILE_OOOUSERNAME_ID];
926 else
927 aInfo = aData[LOCKFILE_SYSUSERNAME_ID];
929 if ( !aInfo.isEmpty() && !aData[LOCKFILE_EDITTIME_ID].isEmpty() )
931 aInfo += OUString( " ( " );
932 aInfo += aData[LOCKFILE_EDITTIME_ID];
933 aInfo += OUString( " )" );
937 if ( bIsLoading )
939 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
940 document::LockedDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
942 else
944 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
945 document::LockedOnSavingRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
950 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 );
951 aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
952 aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
953 aContinuations[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl.get() );
954 xInteractionRequestImpl->setContinuations( aContinuations );
956 xHandler->handle( xInteractionRequestImpl.get() );
958 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
959 if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() )
961 SetError( ERRCODE_ABORT, OUString( OSL_LOG_PREFIX ) );
963 else if ( uno::Reference< task::XInteractionDisapprove >( xSelected.get(), uno::UNO_QUERY ).is() )
965 // own lock on loading, user has selected to ignore the lock
966 // own lock on saving, user has selected to ignore the lock
967 // alien lock on loading, user has selected to edit a copy of document
968 // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location
969 if ( bIsLoading && !bOwnLock )
971 // means that a copy of the document should be opened
972 GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, true ) );
974 else if ( bOwnLock )
975 nResult = LOCK_UI_SUCCEEDED;
977 else // if ( XSelected == aContinuations[1] )
979 // own lock on loading, user has selected to open readonly
980 // own lock on saving, user has selected to open readonly
981 // alien lock on loading, user has selected to retry saving
982 // TODO/LATER: alien lock on saving, user has selected to retry saving
984 if ( bIsLoading )
985 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
986 else
987 nResult = LOCK_UI_TRY;
990 else
992 if ( bIsLoading )
994 // if no interaction handler is provided the default answer is open readonly
995 // that usually happens in case the document is loaded per API
996 // so the document must be opened readonly for backward compatibility
997 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
999 else
1000 SetError( ERRCODE_IO_ACCESSDENIED, OUString( OSL_LOG_PREFIX ) );
1004 return nResult;
1007 namespace
1009 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1010 bool isSuitableProtocolForLocking(const String & rLogicName)
1012 INetURLObject aUrl( rLogicName );
1013 INetProtocol eProt = aUrl.GetProtocol();
1014 #if HAVE_FEATURE_MACOSX_SANDBOX
1015 return eProt == INET_PROT_SFTP;
1016 #else
1017 return eProt == INET_PROT_FILE || eProt == INET_PROT_SFTP;
1018 #endif
1020 #endif
1023 // returns true if the document can be opened for editing ( even if it should be a copy )
1024 // otherwise the document should be opened readonly
1025 // if user cancel the loading the ERROR_ABORT is set
1026 bool SfxMedium::LockOrigFileOnDemand( sal_Bool bLoading, sal_Bool bNoUI )
1028 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1029 (void) bLoading;
1030 (void) bNoUI;
1031 return true;
1032 #else
1033 if (!IsLockingUsed())
1034 return true;
1036 if ( GetURLObject().HasError() )
1037 return false;
1039 bool bResult = false;
1042 if ( pImp->m_bLocked && bLoading && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
1044 // if the document is already locked the system locking might be temporarely off after storing
1045 // check whether the system file locking should be taken again
1046 GetLockingStream_Impl();
1049 bResult = pImp->m_bLocked;
1051 if ( !bResult )
1053 // no read-write access is necessary on loading if the document is explicitly opened as copy
1054 SFX_ITEMSET_ARG( GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, false);
1055 bResult = ( bLoading && pTemplateItem && pTemplateItem->GetValue() );
1058 if ( !bResult && !IsReadOnly() )
1060 bool bContentReadonly = false;
1061 if ( bLoading && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
1063 // let the original document be opened to check the possibility to open it for editing
1064 // and to let the writable stream stay open to hold the lock on the document
1065 GetLockingStream_Impl();
1068 // "IsReadOnly" property does not allow to detect whether the file is readonly always
1069 // so we try always to open the file for editing
1070 // the file is readonly only in case the read-write stream can not be opened
1071 if ( bLoading && !pImp->m_xLockingStream.is() )
1075 // MediaDescriptor does this check also, the duplication should be avoided in future
1076 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1077 ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, comphelper::getProcessComponentContext() );
1078 aContent.getPropertyValue( OUString( "IsReadOnly" ) ) >>= bContentReadonly;
1080 catch( const uno::Exception& ) {}
1082 #if EXTRA_ACL_CHECK
1083 // This block was introduced as a fix to i#102464, but removing
1084 // this does not make the problem re-appear. But leaving this
1085 // part would interfere with documents saved in samba share. This
1086 // affects Windows only.
1087 if ( !bContentReadonly )
1089 // the file is not readonly, check the ACL
1091 String aPhysPath;
1092 if ( ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), aPhysPath ) )
1093 bContentReadonly = IsReadonlyAccordingACL( aPhysPath.GetBuffer() );
1095 #endif
1097 if ( bContentReadonly )
1098 pImp->m_bOriginallyReadOnly = true;
1101 // do further checks only if the file not readonly in fs
1102 if ( !bContentReadonly )
1104 // the special file locking should be used only for suitable URLs
1105 if ( isSuitableProtocolForLocking( pImp->m_aLogicName ) )
1108 // in case of storing the document should request the output before locking
1109 if ( bLoading )
1111 // let the stream be opened to check the system file locking
1112 GetMedium_Impl();
1115 sal_Int8 bUIStatus = LOCK_UI_NOLOCK;
1117 // check whether system file locking has been used, the default value is false
1118 bool bUseSystemLock = ::utl::LocalFileHelper::IsLocalFile( pImp->m_aLogicName ) && IsSystemFileLockingUsed();
1120 // TODO/LATER: This implementation does not allow to detect the system lock on saving here, actually this is no big problem
1121 // if system lock is used the writeable stream should be available
1122 bool bHandleSysLocked = ( bLoading && bUseSystemLock && !pImp->xStream.is() && !pImp->m_pOutStream );
1128 ::svt::DocumentLockFile aLockFile( pImp->m_aLogicName );
1129 if ( !bHandleSysLocked )
1133 bResult = aLockFile.CreateOwnLockFile();
1135 catch ( const ucb::InteractiveIOException& e )
1137 // exception means that the lock file can not be successfully accessed
1138 // in this case it should be ignored if system file locking is anyway active
1139 if ( bUseSystemLock || !IsOOoLockFileUsed() )
1141 bResult = true;
1142 // take the ownership over the lock file
1143 aLockFile.OverwriteOwnLockFile();
1145 else if ( e.Code == IOErrorCode_INVALID_PARAMETER )
1147 // system file locking is not active, ask user whether he wants to open the document without any locking
1148 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
1150 if ( xHandler.is() )
1152 ::rtl::Reference< ::ucbhelper::InteractionRequest > xIgnoreRequestImpl
1153 = new ::ucbhelper::InteractionRequest( uno::makeAny( document::LockFileIgnoreRequest() ) );
1155 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 2 );
1156 aContinuations[0] = new ::ucbhelper::InteractionAbort( xIgnoreRequestImpl.get() );
1157 aContinuations[1] = new ::ucbhelper::InteractionApprove( xIgnoreRequestImpl.get() );
1158 xIgnoreRequestImpl->setContinuations( aContinuations );
1160 xHandler->handle( xIgnoreRequestImpl.get() );
1162 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xIgnoreRequestImpl->getSelection();
1163 bResult = uno::Reference< task::XInteractionApprove >( xSelected.get(), uno::UNO_QUERY ).is();
1167 catch ( const uno::Exception& )
1169 // exception means that the lock file can not be successfully accessed
1170 // in this case it should be ignored if system file locking is anyway active
1171 if ( bUseSystemLock || !IsOOoLockFileUsed() )
1173 bResult = true;
1174 // take the ownership over the lock file
1175 aLockFile.OverwriteOwnLockFile();
1179 // in case OOo locking is turned off the lock file is still written if possible
1180 // but it is ignored while deciding whether the document should be opened for editing or not
1181 if ( !bResult && !IsOOoLockFileUsed() )
1183 bResult = true;
1184 // take the ownership over the lock file
1185 aLockFile.OverwriteOwnLockFile();
1190 if ( !bResult )
1192 uno::Sequence< OUString > aData;
1195 // impossibility to get data is no real problem
1196 aData = aLockFile.GetLockData();
1198 catch( const uno::Exception& )
1202 bool bOwnLock = false;
1204 if ( !bHandleSysLocked )
1206 uno::Sequence< OUString > aOwnData = aLockFile.GenerateOwnEntry();
1207 bOwnLock = ( aData.getLength() > LOCKFILE_USERURL_ID
1208 && aOwnData.getLength() > LOCKFILE_USERURL_ID
1209 && aOwnData[LOCKFILE_SYSUSERNAME_ID].equals( aData[LOCKFILE_SYSUSERNAME_ID] ) );
1211 if ( bOwnLock
1212 && aOwnData[LOCKFILE_LOCALHOST_ID].equals( aData[LOCKFILE_LOCALHOST_ID] )
1213 && aOwnData[LOCKFILE_USERURL_ID].equals( aData[LOCKFILE_USERURL_ID] ) )
1215 // this is own lock from the same installation, it could remain because of crash
1216 bResult = true;
1220 if ( !bResult && !bNoUI )
1222 bUIStatus = ShowLockedDocumentDialog( aData, bLoading, bOwnLock );
1223 if ( bUIStatus == LOCK_UI_SUCCEEDED )
1225 // take the ownership over the lock file
1226 bResult = aLockFile.OverwriteOwnLockFile();
1230 bHandleSysLocked = false;
1233 catch( const uno::Exception& )
1236 } while( !bResult && bUIStatus == LOCK_UI_TRY );
1238 pImp->m_bLocked = bResult;
1240 else
1242 // this is no file URL, check whether the file is readonly
1243 bResult = !bContentReadonly;
1248 if ( !bResult && GetError() == ERRCODE_NONE )
1250 // the error should be set in case it is storing process
1251 // or the document has been opened for editing explicitly
1252 SFX_ITEMSET_ARG( pImp->m_pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, false );
1254 if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) )
1255 SetError( ERRCODE_IO_ACCESSDENIED, OUString( OSL_LOG_PREFIX ) );
1256 else
1257 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1260 // when the file is locked, get the current file date
1261 if ( bResult && DocNeedsFileDateCheck() )
1262 GetInitFileDate( true );
1264 catch( const uno::Exception& )
1266 OSL_FAIL( "Locking exception: high probability, that the content has not been created" );
1268 return bResult;
1269 #endif
1272 //------------------------------------------------------------------
1273 uno::Reference < embed::XStorage > SfxMedium::GetStorage( sal_Bool bCreateTempIfNo )
1275 if ( pImp->xStorage.is() || pImp->m_bTriedStorage )
1276 return pImp->xStorage;
1278 uno::Sequence< uno::Any > aArgs( 2 );
1280 // the medium should be retrieved before temporary file creation
1281 // to let the MediaDescriptor be filled with the streams
1282 GetMedium_Impl();
1284 if ( bCreateTempIfNo )
1285 CreateTempFile( false );
1287 GetMedium_Impl();
1289 if ( GetError() )
1290 return pImp->xStorage;
1292 SFX_ITEMSET_ARG( GetItemSet(), pRepairItem, SfxBoolItem, SID_REPAIRPACKAGE, false);
1293 if ( pRepairItem && pRepairItem->GetValue() )
1295 // the storage should be created for repairing mode
1296 CreateTempFile( false );
1297 GetMedium_Impl();
1299 Reference< ::com::sun::star::ucb::XProgressHandler > xProgressHandler;
1300 Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
1302 SFX_ITEMSET_ARG( GetItemSet(), pxProgressItem, SfxUnoAnyItem, SID_PROGRESS_STATUSBAR_CONTROL, false );
1303 if( pxProgressItem && ( pxProgressItem->GetValue() >>= xStatusIndicator ) )
1304 xProgressHandler = Reference< ::com::sun::star::ucb::XProgressHandler >(
1305 new utl::ProgressHandlerWrap( xStatusIndicator ) );
1307 uno::Sequence< beans::PropertyValue > aAddProps( 2 );
1308 aAddProps[0].Name = OUString("RepairPackage");
1309 aAddProps[0].Value <<= (sal_Bool)true;
1310 aAddProps[1].Name = OUString("StatusIndicator");
1311 aAddProps[1].Value <<= xProgressHandler;
1313 // the first arguments will be filled later
1314 aArgs.realloc( 3 );
1315 aArgs[2] <<= aAddProps;
1318 if ( pImp->xStream.is() )
1320 // since the storage is based on temporary stream we open it always read-write
1321 aArgs[0] <<= pImp->xStream;
1322 aArgs[1] <<= embed::ElementModes::READWRITE;
1323 pImp->bStorageBasedOnInStream = true;
1325 else if ( pImp->xInputStream.is() )
1327 // since the storage is based on temporary stream we open it always read-write
1328 aArgs[0] <<= pImp->xInputStream;
1329 aArgs[1] <<= embed::ElementModes::READ;
1330 pImp->bStorageBasedOnInStream = true;
1332 else
1334 CloseStreams_Impl();
1335 aArgs[0] <<= pImp->m_aName;
1336 aArgs[1] <<= embed::ElementModes::READ;
1337 pImp->bStorageBasedOnInStream = false;
1342 pImp->xStorage = uno::Reference< embed::XStorage >(
1343 ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ),
1344 uno::UNO_QUERY );
1346 catch( const uno::Exception& )
1348 // impossibility to create the storage is no error
1351 if( ( pImp->nLastStorageError = GetError() ) != SVSTREAM_OK )
1353 pImp->xStorage = 0;
1354 if ( pImp->m_pInStream )
1355 pImp->m_pInStream->Seek(0);
1356 return uno::Reference< embed::XStorage >();
1359 pImp->m_bTriedStorage = true;
1361 // TODO/LATER: Get versionlist on demand
1362 if ( pImp->xStorage.is() )
1364 SetEncryptionDataToStorage_Impl();
1365 GetVersionList();
1368 SFX_ITEMSET_ARG( pImp->m_pSet, pVersion, SfxInt16Item, SID_VERSION, false);
1370 bool bResetStorage = false;
1371 if ( pVersion && pVersion->GetValue() )
1373 // Read all available versions
1374 if ( pImp->aVersions.getLength() )
1376 // Search for the version fits the comment
1377 // The versions are numbered startign with 1, versions with
1378 // negative versions numbers are counted backwards from the
1379 // current version
1380 short nVersion = pVersion ? pVersion->GetValue() : 0;
1381 if ( nVersion<0 )
1382 nVersion = ( (short) pImp->aVersions.getLength() ) + nVersion;
1383 else if ( nVersion )
1384 nVersion--;
1386 util::RevisionTag& rTag = pImp->aVersions[nVersion];
1388 // Open SubStorage for all versions
1389 uno::Reference < embed::XStorage > xSub = pImp->xStorage->openStorageElement( "Versions",
1390 embed::ElementModes::READ );
1392 DBG_ASSERT( xSub.is(), "Version list, but no Versions!" );
1394 // There the version is stored as packed Stream
1395 uno::Reference < io::XStream > xStr = xSub->openStreamElement( rTag.Identifier, embed::ElementModes::READ );
1396 SvStream* pStream = utl::UcbStreamHelper::CreateStream( xStr );
1397 if ( pStream && pStream->GetError() == SVSTREAM_OK )
1399 // Unpack Stream in TempDir
1400 ::utl::TempFile aTempFile;
1401 String aTmpName = aTempFile.GetURL();
1402 SvFileStream aTmpStream( aTmpName, SFX_STREAM_READWRITE );
1404 *pStream >> aTmpStream;
1405 aTmpStream.Close();
1407 // Open data as Storage
1408 pImp->m_nStorOpenMode = SFX_STREAM_READONLY;
1409 pImp->xStorage = comphelper::OStorageHelper::GetStorageFromURL( aTmpName, embed::ElementModes::READ );
1410 pImp->bStorageBasedOnInStream = false;
1411 OUString aTemp;
1412 ::utl::LocalFileHelper::ConvertURLToPhysicalName( aTmpName, aTemp );
1413 SetPhysicalName_Impl( aTemp );
1415 pImp->bIsTemp = true;
1416 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1417 // TODO/MBA
1418 pImp->aVersions.realloc(0);
1420 else
1421 bResetStorage = true;
1424 else
1425 bResetStorage = true;
1428 if ( bResetStorage )
1430 pImp->xStorage.clear();
1431 if ( pImp->m_pInStream )
1432 pImp->m_pInStream->Seek( 0L );
1435 pImp->bIsStorage = pImp->xStorage.is();
1436 return pImp->xStorage;
1439 //------------------------------------------------------------------
1440 uno::Reference< embed::XStorage > SfxMedium::GetZipStorageToSign_Impl( sal_Bool bReadOnly )
1442 if ( !GetError() && !pImp->m_xZipStorage.is() )
1444 GetMedium_Impl();
1448 // we can not sign document if there is no stream
1449 // should it be possible at all?
1450 if ( !bReadOnly && pImp->xStream.is() )
1452 pImp->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImp->xStream, embed::ElementModes::READWRITE );
1454 else if ( pImp->xInputStream.is() )
1456 pImp->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( ZIP_STORAGE_FORMAT_STRING, pImp->xInputStream );
1459 catch( const uno::Exception& )
1461 OSL_FAIL( "No possibility to get readonly version of storage from medium!\n" );
1464 if ( GetError() ) // do not remove warnings
1465 ResetError();
1468 return pImp->m_xZipStorage;
1471 //------------------------------------------------------------------
1472 void SfxMedium::CloseZipStorage_Impl()
1474 if ( pImp->m_xZipStorage.is() )
1476 try {
1477 pImp->m_xZipStorage->dispose();
1478 } catch( const uno::Exception& )
1481 pImp->m_xZipStorage.clear();
1485 void SfxMedium::CloseStorage()
1487 if ( pImp->xStorage.is() )
1489 uno::Reference < lang::XComponent > xComp( pImp->xStorage, uno::UNO_QUERY );
1490 // in the salvage mode the medium does not own the storage
1491 if ( pImp->bDisposeStorage && !pImp->m_bSalvageMode )
1493 try {
1494 xComp->dispose();
1495 } catch( const uno::Exception& )
1497 OSL_FAIL( "Medium's storage is already disposed!\n" );
1501 pImp->xStorage.clear();
1502 pImp->bStorageBasedOnInStream = false;
1505 pImp->m_bTriedStorage = false;
1506 pImp->bIsStorage = false;
1509 void SfxMedium::CanDisposeStorage_Impl( sal_Bool bDisposeStorage )
1511 pImp->bDisposeStorage = bDisposeStorage;
1514 sal_Bool SfxMedium::WillDisposeStorageOnClose_Impl()
1516 return pImp->bDisposeStorage;
1519 StreamMode SfxMedium::GetOpenMode() const
1521 return pImp->m_nStorOpenMode;
1524 void SfxMedium::SetOpenMode( StreamMode nStorOpen,
1525 sal_Bool bDontClose )
1527 if ( pImp->m_nStorOpenMode != nStorOpen )
1529 pImp->m_nStorOpenMode = nStorOpen;
1531 if( !bDontClose )
1533 if ( pImp->xStorage.is() )
1534 CloseStorage();
1536 CloseStreams_Impl();
1541 //------------------------------------------------------------------
1542 sal_Bool SfxMedium::UseBackupToRestore_Impl( ::ucbhelper::Content& aOriginalContent,
1543 const Reference< ::com::sun::star::ucb::XCommandEnvironment >& xComEnv )
1547 ::ucbhelper::Content aTransactCont( pImp->m_aBackupURL, xComEnv, comphelper::getProcessComponentContext() );
1549 Reference< XInputStream > aOrigInput = aTransactCont.openStream();
1550 aOriginalContent.writeStream( aOrigInput, true );
1551 return true;
1553 catch( const Exception& )
1555 // in case of failure here the backup file should not be removed
1556 // TODO/LATER: a message should be used to let user know about the backup
1557 pImp->m_bRemoveBackup = false;
1558 // TODO/LATER: needs a specific error code
1559 pImp->m_eError = ERRCODE_IO_GENERAL;
1562 return false;
1565 //------------------------------------------------------------------
1566 sal_Bool SfxMedium::StorageCommit_Impl()
1568 bool bResult = false;
1569 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1570 ::ucbhelper::Content aOriginalContent;
1572 if ( pImp->xStorage.is() )
1574 if ( !GetError() )
1576 uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY );
1577 if ( xTrans.is() )
1581 xTrans->commit();
1582 CloseZipStorage_Impl();
1583 bResult = true;
1585 catch ( const embed::UseBackupException& aBackupExc )
1587 // since the temporary file is created always now, the scenario is close to be impossible
1588 if ( !pImp->pTempFile )
1590 OSL_ENSURE( !pImp->m_aBackupURL.isEmpty(), "No backup on storage commit!\n" );
1591 if ( !pImp->m_aBackupURL.isEmpty()
1592 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ),
1593 xDummyEnv, comphelper::getProcessComponentContext(),
1594 aOriginalContent ) )
1596 // use backup to restore the file
1597 // the storage has already disconnected from original location
1598 CloseAndReleaseStreams_Impl();
1599 if ( !UseBackupToRestore_Impl( aOriginalContent, xDummyEnv ) )
1601 // connect the medium to the temporary file of the storage
1602 pImp->aContent = ::ucbhelper::Content();
1603 pImp->m_aName = aBackupExc.TemporaryFileURL;
1604 OSL_ENSURE( !pImp->m_aName.isEmpty(), "The exception _must_ contain the temporary URL!\n" );
1608 if ( !GetError() )
1609 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1612 catch ( const uno::Exception& )
1614 //TODO/LATER: improve error handling
1615 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1621 return bResult;
1624 //------------------------------------------------------------------
1625 sal_Bool SfxMedium::TransactedTransferForFS_Impl( const INetURLObject& aSource,
1626 const INetURLObject& aDest,
1627 const Reference< ::com::sun::star::ucb::XCommandEnvironment >& xComEnv )
1629 bool bResult = false;
1630 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1631 Reference< XOutputStream > aDestStream;
1632 ::ucbhelper::Content aOriginalContent;
1636 aOriginalContent = ::ucbhelper::Content( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext() );
1638 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
1640 pImp->m_eError = ERRCODE_ABORT;
1642 catch ( const ::com::sun::star::ucb::CommandFailedException& )
1644 pImp->m_eError = ERRCODE_ABORT;
1646 catch (const ::com::sun::star::ucb::ContentCreationException& ex)
1648 pImp->m_eError = ERRCODE_IO_GENERAL;
1649 if (
1650 (ex.eError == ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
1651 (ex.eError == ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
1654 pImp->m_eError = ERRCODE_IO_NOTEXISTSPATH;
1657 catch (const ::com::sun::star::uno::Exception&)
1659 pImp->m_eError = ERRCODE_IO_GENERAL;
1662 if( !pImp->m_eError || (pImp->m_eError & ERRCODE_WARNING_MASK) )
1664 if ( pImp->xStorage.is() )
1665 CloseStorage();
1667 CloseStreams_Impl();
1669 ::ucbhelper::Content aTempCont;
1670 if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, comphelper::getProcessComponentContext(), aTempCont ) )
1672 bool bTransactStarted = false;
1673 SFX_ITEMSET_ARG( GetItemSet(), pOverWrite, SfxBoolItem, SID_OVERWRITE, false );
1674 SFX_ITEMSET_ARG( GetItemSet(), pRename, SfxBoolItem, SID_RENAME, false );
1675 bool bRename = pRename ? pRename->GetValue() : false;
1676 bool bOverWrite = pOverWrite ? pOverWrite->GetValue() : !bRename;
1680 if( bOverWrite && ::utl::UCBContentHelper::IsDocument( aDest.GetMainURL( INetURLObject::NO_DECODE ) ) )
1682 if( pImp->m_aBackupURL.isEmpty() )
1683 DoInternalBackup_Impl( aOriginalContent );
1685 if( !pImp->m_aBackupURL.isEmpty() )
1687 Reference< XInputStream > aTempInput = aTempCont.openStream();
1688 bTransactStarted = true;
1689 aOriginalContent.setPropertyValue( "Size", uno::makeAny( (sal_Int64)0 ) );
1690 aOriginalContent.writeStream( aTempInput, bOverWrite );
1691 bResult = true;
1693 else
1695 pImp->m_eError = ERRCODE_SFX_CANTCREATEBACKUP;
1698 else
1700 Reference< XInputStream > aTempInput = aTempCont.openStream();
1701 aOriginalContent.writeStream( aTempInput, bOverWrite );
1702 bResult = true;
1705 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
1707 pImp->m_eError = ERRCODE_ABORT;
1709 catch ( const ::com::sun::star::ucb::CommandFailedException& )
1711 pImp->m_eError = ERRCODE_ABORT;
1713 catch ( const ::com::sun::star::ucb::InteractiveIOException& r )
1715 if ( r.Code == IOErrorCode_ACCESS_DENIED )
1716 pImp->m_eError = ERRCODE_IO_ACCESSDENIED;
1717 else if ( r.Code == IOErrorCode_NOT_EXISTING )
1718 pImp->m_eError = ERRCODE_IO_NOTEXISTS;
1719 else if ( r.Code == IOErrorCode_CANT_READ )
1720 pImp->m_eError = ERRCODE_IO_CANTREAD;
1721 else
1722 pImp->m_eError = ERRCODE_IO_GENERAL;
1724 catch ( const ::com::sun::star::uno::Exception& )
1726 pImp->m_eError = ERRCODE_IO_GENERAL;
1729 if ( bResult )
1731 if ( pImp->pTempFile )
1733 pImp->pTempFile->EnableKillingFile( true );
1734 delete pImp->pTempFile;
1735 pImp->pTempFile = NULL;
1738 else if ( bTransactStarted )
1740 UseBackupToRestore_Impl( aOriginalContent, xDummyEnv );
1743 else
1744 pImp->m_eError = ERRCODE_IO_CANTREAD;
1747 return bResult;
1750 //------------------------------------------------------------------
1751 sal_Bool SfxMedium::TryDirectTransfer( const OUString& aURL, SfxItemSet& aTargetSet )
1753 if ( GetError() )
1754 return false;
1756 // if the document had no password it should be stored without password
1757 // if the document had password it should be stored with the same password
1758 // otherwise the stream copying can not be done
1759 SFX_ITEMSET_ARG( &aTargetSet, pNewPassItem, SfxStringItem, SID_PASSWORD, false );
1760 SFX_ITEMSET_ARG( GetItemSet(), pOldPassItem, SfxStringItem, SID_PASSWORD, false );
1761 if ( ( !pNewPassItem && !pOldPassItem )
1762 || ( pNewPassItem && pOldPassItem && pNewPassItem->GetValue() == pOldPassItem->GetValue() ) )
1764 // the filter must be the same
1765 SFX_ITEMSET_ARG( &aTargetSet, pNewFilterItem, SfxStringItem, SID_FILTER_NAME, false );
1766 SFX_ITEMSET_ARG( GetItemSet(), pOldFilterItem, SfxStringItem, SID_FILTER_NAME, false );
1767 if ( pNewFilterItem && pOldFilterItem && pNewFilterItem->GetValue() == pOldFilterItem->GetValue() )
1769 // get the input stream and copy it
1770 // in case of success return true
1771 uno::Reference< io::XInputStream > xInStream = GetInputStream();
1773 ResetError();
1774 if ( xInStream.is() )
1778 uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
1779 sal_Int64 nPos = 0;
1780 if ( xSeek.is() )
1782 nPos = xSeek->getPosition();
1783 xSeek->seek( 0 );
1786 uno::Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
1787 ::ucbhelper::Content aTargetContent( aURL, xEnv, comphelper::getProcessComponentContext() );
1789 InsertCommandArgument aInsertArg;
1790 aInsertArg.Data = xInStream;
1791 SFX_ITEMSET_ARG( &aTargetSet, pRename, SfxBoolItem, SID_RENAME, false );
1792 SFX_ITEMSET_ARG( &aTargetSet, pOverWrite, SfxBoolItem, SID_OVERWRITE, false );
1793 if ( (pOverWrite && !pOverWrite->GetValue()) // argument says: never overwrite
1794 || (pRename && pRename->GetValue()) ) // argument says: rename file
1795 aInsertArg.ReplaceExisting = false;
1796 else
1797 aInsertArg.ReplaceExisting = true; // default is overwrite existing files
1799 Any aCmdArg;
1800 aCmdArg <<= aInsertArg;
1801 aTargetContent.executeCommand( OUString( "insert" ),
1802 aCmdArg );
1804 if ( xSeek.is() )
1805 xSeek->seek( nPos );
1807 return true;
1809 catch( const uno::Exception& )
1815 return false;
1818 //------------------------------------------------------------------
1819 void SfxMedium::Transfer_Impl()
1821 // The transfer is required only in two cases: either if there is a temporary file or if there is a salvage item
1822 OUString aNameURL;
1823 if ( pImp->pTempFile )
1824 aNameURL = pImp->pTempFile->GetURL();
1825 else if ( !pImp->m_aLogicName.isEmpty() && pImp->m_bSalvageMode )
1827 // makes sence only in case logic name is set
1828 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aNameURL ) )
1829 OSL_FAIL( "The medium name is not convertible!\n" );
1832 if ( !aNameURL.isEmpty() && ( !pImp->m_eError || (pImp->m_eError & ERRCODE_WARNING_MASK) ) )
1834 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::Transfer_Impl, copying to target" );
1836 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
1837 Reference< XOutputStream > rOutStream;
1839 // in case an output stream is provided from outside and the URL is correct
1840 // commit to the stream
1841 if (pImp->m_aLogicName.startsWith("private:stream"))
1843 // TODO/LATER: support storing to SID_STREAM
1844 SFX_ITEMSET_ARG( pImp->m_pSet, pOutStreamItem, SfxUnoAnyItem, SID_OUTPUTSTREAM, false);
1845 if( pOutStreamItem && ( pOutStreamItem->GetValue() >>= rOutStream ) )
1847 if ( pImp->xStorage.is() )
1848 CloseStorage();
1850 CloseStreams_Impl();
1852 INetURLObject aSource( aNameURL );
1853 ::ucbhelper::Content aTempCont;
1854 if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, comphelper::getProcessComponentContext(), aTempCont ) )
1858 sal_Int32 nRead;
1859 sal_Int32 nBufferSize = 32767;
1860 Sequence < sal_Int8 > aSequence ( nBufferSize );
1861 Reference< XInputStream > aTempInput = aTempCont.openStream();
1865 nRead = aTempInput->readBytes ( aSequence, nBufferSize );
1866 if ( nRead < nBufferSize )
1868 Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead );
1869 rOutStream->writeBytes ( aTempBuf );
1871 else
1872 rOutStream->writeBytes ( aSequence );
1874 while ( nRead == nBufferSize );
1876 // remove temporary file
1877 if ( pImp->pTempFile )
1879 pImp->pTempFile->EnableKillingFile( true );
1880 delete pImp->pTempFile;
1881 pImp->pTempFile = NULL;
1884 catch( const Exception& )
1888 else
1890 OSL_FAIL( "Illegal Output stream parameter!\n" );
1891 SetError( ERRCODE_IO_GENERAL, OUString( OSL_LOG_PREFIX ) );
1894 // free the reference
1895 if ( pImp->m_pSet )
1896 pImp->m_pSet->ClearItem( SID_OUTPUTSTREAM );
1898 return;
1901 GetContent();
1902 if ( !pImp->aContent.get().is() )
1904 pImp->m_eError = ERRCODE_IO_NOTEXISTS;
1905 return;
1908 SFX_ITEMSET_ARG( GetItemSet(), pSegmentSize, SfxInt32Item, SID_SEGMENTSIZE, false);
1909 if ( pSegmentSize )
1911 // this file must be stored into a disk spanned package
1914 uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetStorageFromURL( GetName(),
1915 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1917 // set segment size property; package will automatically be divided in pieces fitting
1918 // into this size
1919 ::com::sun::star::uno::Any aAny;
1920 aAny <<= pSegmentSize->GetValue();
1922 uno::Reference < beans::XPropertySet > xSet( pImp->xStorage, uno::UNO_QUERY );
1923 xSet->setPropertyValue( OUString("SegmentSize"), aAny );
1925 // copy the temporary storage into the disk spanned package
1926 GetStorage()->copyToStorage( xStor );
1927 uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY );
1928 if ( xTrans.is() )
1929 xTrans->commit();
1932 catch ( const uno::Exception& )
1934 //TODO/MBA: error handling
1936 return;
1939 INetURLObject aDest( GetURLObject() );
1941 // source is the temp file written so far
1942 INetURLObject aSource( aNameURL );
1944 // a special case, an interaction handler should be used for
1945 // authentication in case it is available
1946 Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
1947 Reference< ::com::sun::star::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
1948 if (xInteractionHandler.is())
1949 xComEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler,
1950 Reference< ::com::sun::star::ucb::XProgressHandler >() );
1952 OUString aDestURL( aDest.GetMainURL( INetURLObject::NO_DECODE ) );
1954 if ( ::utl::LocalFileHelper::IsLocalFile( aDestURL ) || !aDest.removeSegment() )
1956 TransactedTransferForFS_Impl( aSource, aDest, xComEnv );
1958 // Hideous - no clean way to do this, so we re-open the file just to fsync it
1959 osl::File aFile( aDestURL );
1960 if ( aFile.open( osl_File_OpenFlag_Write ) == osl::FileBase::E_None )
1962 aFile.sync();
1963 OSL_TRACE("fsync'd saved file '%s'\n",
1964 OUStringToOString( aDestURL, RTL_TEXTENCODING_UTF8 ).getStr() );
1965 aFile.close();
1968 else
1970 // create content for the parent folder and call transfer on that content with the source content
1971 // and the destination file name as parameters
1972 ::ucbhelper::Content aSourceContent;
1973 ::ucbhelper::Content aTransferContent;
1975 ::ucbhelper::Content aDestContent;
1976 ::ucbhelper::Content::create( aDestURL, xComEnv, comphelper::getProcessComponentContext(), aDestContent );
1977 // For checkin, we need the object URL, not the parent folder:
1978 if ( !IsInCheckIn( ) )
1980 // Get the parent URL from the XChild if possible: why would the URL necessarily have
1981 // a hierarchical path? It's not always the case for CMIS.
1982 Reference< ::com::sun::star::container::XChild> xChild( aDestContent.get(), uno::UNO_QUERY );
1983 OUString sParentUrl;
1984 if ( xChild.is( ) )
1986 Reference< ::com::sun::star::ucb::XContent > xParent( xChild->getParent( ), uno::UNO_QUERY );
1987 if ( xParent.is( ) )
1989 sParentUrl = xParent->getIdentifier( )->getContentIdentifier();
1993 if ( sParentUrl.isEmpty() )
1994 aDestURL = aDest.GetMainURL( INetURLObject::NO_DECODE );
1995 // adjust to above aDest.removeSegment()
1996 else
1997 aDestURL = sParentUrl;
2000 // LongName wasn't defined anywhere, only used here... get the Title instead
2001 // as it's less probably empty
2002 OUString aFileName;
2003 Any aAny = aDestContent.getPropertyValue( OUString("Title" ) );
2004 aAny >>= aFileName;
2005 if ( aFileName.isEmpty() )
2006 aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2010 aTransferContent = ::ucbhelper::Content( aDestURL, xComEnv, comphelper::getProcessComponentContext() );
2012 catch (const ::com::sun::star::ucb::ContentCreationException& ex)
2014 pImp->m_eError = ERRCODE_IO_GENERAL;
2015 if (
2016 (ex.eError == ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
2017 (ex.eError == ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
2020 pImp->m_eError = ERRCODE_IO_NOTEXISTSPATH;
2023 catch (const ::com::sun::star::uno::Exception&)
2025 pImp->m_eError = ERRCODE_IO_GENERAL;
2028 if ( !pImp->m_eError || (pImp->m_eError & ERRCODE_WARNING_MASK) )
2030 // free resources, otherwise the transfer may fail
2031 if ( pImp->xStorage.is() )
2032 CloseStorage();
2034 CloseStreams_Impl();
2036 ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, comphelper::getProcessComponentContext(), aSourceContent );
2038 // check for external parameters that may customize the handling of NameClash situations
2039 SFX_ITEMSET_ARG( GetItemSet(), pRename, SfxBoolItem, SID_RENAME, false );
2040 SFX_ITEMSET_ARG( GetItemSet(), pOverWrite, SfxBoolItem, SID_OVERWRITE, false );
2041 sal_Int32 nNameClash;
2042 if ( pOverWrite && !pOverWrite->GetValue() )
2043 // argument says: never overwrite
2044 nNameClash = NameClash::ERROR;
2045 else if ( pRename && pRename->GetValue() )
2046 // argument says: rename file
2047 nNameClash = NameClash::RENAME;
2048 else
2049 // default is overwrite existing files
2050 nNameClash = NameClash::OVERWRITE;
2054 OUString aMimeType = pImp->getFilterMimeType();
2055 ::ucbhelper::InsertOperation eOperation = ::ucbhelper::InsertOperation_COPY;
2056 bool bMajor = false;
2057 OUString sComment;
2058 if ( IsInCheckIn( ) )
2060 eOperation = ::ucbhelper::InsertOperation_CHECKIN;
2061 SFX_ITEMSET_ARG( GetItemSet(), pMajor, SfxBoolItem, SID_DOCINFO_MAJOR, false );
2062 bMajor = pMajor && pMajor->GetValue( );
2063 SFX_ITEMSET_ARG( GetItemSet(), pComments, SfxStringItem, SID_DOCINFO_COMMENTS, false );
2064 if ( pComments )
2065 sComment = pComments->GetValue( );
2067 OUString sResultURL;
2068 if (!aTransferContent.transferContent( aSourceContent, eOperation,
2069 aFileName, nNameClash, aMimeType, bMajor, sComment, &sResultURL ))
2070 pImp->m_eError = ERRCODE_IO_GENERAL;
2071 else if ( !sResultURL.isEmpty( ) ) // Likely to happen only for checkin
2072 SwitchDocumentToFile( sResultURL );
2074 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
2076 pImp->m_eError = ERRCODE_ABORT;
2078 catch ( const ::com::sun::star::ucb::CommandFailedException& )
2080 pImp->m_eError = ERRCODE_ABORT;
2082 catch ( const ::com::sun::star::ucb::InteractiveIOException& r )
2084 if ( r.Code == IOErrorCode_ACCESS_DENIED )
2085 pImp->m_eError = ERRCODE_IO_ACCESSDENIED;
2086 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2087 pImp->m_eError = ERRCODE_IO_NOTEXISTS;
2088 else if ( r.Code == IOErrorCode_CANT_READ )
2089 pImp->m_eError = ERRCODE_IO_CANTREAD;
2090 else
2091 pImp->m_eError = ERRCODE_IO_GENERAL;
2093 catch ( const ::com::sun::star::uno::Exception& )
2095 pImp->m_eError = ERRCODE_IO_GENERAL;
2098 // do not switch from temporary file in case of nonfile protocol
2102 if ( ( !pImp->m_eError || (pImp->m_eError & ERRCODE_WARNING_MASK) ) && !pImp->pTempFile )
2104 // without a TempFile the physical and logical name should be the same after successful transfer
2105 ::utl::LocalFileHelper::ConvertURLToPhysicalName(
2106 GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), pImp->m_aName );
2107 pImp->m_bSalvageMode = false;
2112 //------------------------------------------------------------------
2113 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent,
2114 const String& aPrefix,
2115 const String& aExtension,
2116 const String& aDestDir )
2118 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::DoInternalBackup_Impl( with destdir )" );
2120 if ( !pImp->m_aBackupURL.isEmpty() )
2121 return; // the backup was done already
2123 ::utl::TempFile aTransactTemp( aPrefix, &aExtension, &aDestDir );
2124 aTransactTemp.EnableKillingFile( false );
2126 INetURLObject aBackObj( aTransactTemp.GetURL() );
2127 OUString aBackupName = aBackObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2129 Reference < ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
2130 ::ucbhelper::Content aBackupCont;
2131 if( ::ucbhelper::Content::create( aDestDir, xDummyEnv, comphelper::getProcessComponentContext(), aBackupCont ) )
2135 OUString sMimeType = pImp->getFilterMimeType();
2136 if( aBackupCont.transferContent( aOriginalContent,
2137 ::ucbhelper::InsertOperation_COPY,
2138 aBackupName,
2139 NameClash::OVERWRITE,
2140 sMimeType ) )
2142 pImp->m_aBackupURL = aBackObj.GetMainURL( INetURLObject::NO_DECODE );
2143 pImp->m_bRemoveBackup = true;
2146 catch( const Exception& )
2150 if ( pImp->m_aBackupURL.isEmpty() )
2151 aTransactTemp.EnableKillingFile( true );
2154 //------------------------------------------------------------------
2155 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent )
2157 if ( !pImp->m_aBackupURL.isEmpty() )
2158 return; // the backup was done already
2160 OUString aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT,
2161 true,
2162 INetURLObject::NO_DECODE );
2164 sal_Int32 nPrefixLen = aFileName.lastIndexOf( '.' );
2165 String aPrefix = ( nPrefixLen == -1 ) ? aFileName : aFileName.copy( 0, nPrefixLen );
2166 String aExtension = ( nPrefixLen == -1 ) ? String() : String(aFileName.copy( nPrefixLen ));
2167 String aBakDir = SvtPathOptions().GetBackupPath();
2169 // create content for the parent folder ( = backup folder )
2170 ::ucbhelper::Content aContent;
2171 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
2172 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
2173 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aBakDir );
2175 if ( pImp->m_aBackupURL.isEmpty() )
2177 // the copiing to the backup catalog failed ( for example because
2178 // of using an encrypted partition as target catalog )
2179 // since the user did not specify to make backup explicitly
2180 // office should try to make backup in another place,
2181 // target catalog does not look bad for this case ( and looks
2182 // to be the only way for encrypted partitions )
2184 INetURLObject aDest = GetURLObject();
2185 if ( aDest.removeSegment() )
2186 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aDest.GetMainURL( INetURLObject::NO_DECODE ) );
2191 //------------------------------------------------------------------
2192 void SfxMedium::DoBackup_Impl()
2194 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::DoBackup_Impl" );
2196 // source file name is the logical name of this medium
2197 INetURLObject aSource( GetURLObject() );
2199 // there is nothing to backup in case source file does not exist
2200 if ( !::utl::UCBContentHelper::IsDocument( aSource.GetMainURL( INetURLObject::NO_DECODE ) ) )
2201 return;
2203 bool bSuccess = false;
2205 // get path for backups
2206 String aBakDir = SvtPathOptions().GetBackupPath();
2207 if( aBakDir.Len() )
2209 // create content for the parent folder ( = backup folder )
2210 ::ucbhelper::Content aContent;
2211 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
2212 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
2214 // save as ".bak" file
2215 INetURLObject aDest( aBakDir );
2216 aDest.insertName( aSource.getName() );
2217 aDest.setExtension( "bak" );
2218 String aFileName = aDest.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2220 // create a content for the source file
2221 ::ucbhelper::Content aSourceContent;
2222 if ( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, comphelper::getProcessComponentContext(), aSourceContent ) )
2226 // do the transfer ( copy source file to backup dir )
2227 OUString sMimeType = pImp->getFilterMimeType();
2228 bSuccess = aContent.transferContent( aSourceContent,
2229 ::ucbhelper::InsertOperation_COPY,
2230 aFileName,
2231 NameClash::OVERWRITE,
2232 sMimeType );
2233 if( bSuccess )
2235 pImp->m_aBackupURL = aDest.GetMainURL( INetURLObject::NO_DECODE );
2236 pImp->m_bRemoveBackup = false;
2239 catch ( const ::com::sun::star::uno::Exception& )
2246 if ( !bSuccess )
2248 pImp->m_eError = ERRCODE_SFX_CANTCREATEBACKUP;
2252 //------------------------------------------------------------------
2253 void SfxMedium::ClearBackup_Impl()
2255 if( pImp->m_bRemoveBackup )
2257 // currently a document is always stored in a new medium,
2258 // thus if a backup can not be removed the backup URL should not be cleaned
2259 if ( !pImp->m_aBackupURL.isEmpty() )
2261 if ( ::utl::UCBContentHelper::Kill( pImp->m_aBackupURL ) )
2263 pImp->m_bRemoveBackup = false;
2264 pImp->m_aBackupURL = OUString();
2266 else
2269 OSL_FAIL("Couldn't remove backup file!");
2273 else
2274 pImp->m_aBackupURL = OUString();
2277 //----------------------------------------------------------------
2278 void SfxMedium::GetLockingStream_Impl()
2280 if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
2281 && !pImp->m_xLockingStream.is() )
2283 SFX_ITEMSET_ARG( pImp->m_pSet, pWriteStreamItem, SfxUnoAnyItem, SID_STREAM, false);
2284 if ( pWriteStreamItem )
2285 pWriteStreamItem->GetValue() >>= pImp->m_xLockingStream;
2287 if ( !pImp->m_xLockingStream.is() )
2289 // open the original document
2290 uno::Sequence< beans::PropertyValue > xProps;
2291 TransformItems( SID_OPENDOC, *GetItemSet(), xProps );
2292 comphelper::MediaDescriptor aMedium( xProps );
2294 aMedium.addInputStreamOwnLock();
2296 uno::Reference< io::XInputStream > xInputStream;
2297 aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= pImp->m_xLockingStream;
2298 aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream;
2300 if ( !pImp->pTempFile && pImp->m_aName.isEmpty() )
2302 // the medium is still based on the original file, it makes sence to initialize the streams
2303 if ( pImp->m_xLockingStream.is() )
2304 pImp->xStream = pImp->m_xLockingStream;
2306 if ( xInputStream.is() )
2307 pImp->xInputStream = xInputStream;
2309 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2310 pImp->xInputStream = pImp->xStream->getInputStream();
2316 //----------------------------------------------------------------
2317 void SfxMedium::GetMedium_Impl()
2319 if ( !pImp->m_pInStream )
2321 pImp->bDownloadDone = false;
2322 Reference< ::com::sun::star::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
2324 //TODO/MBA: need support for SID_STREAM
2325 SFX_ITEMSET_ARG( pImp->m_pSet, pWriteStreamItem, SfxUnoAnyItem, SID_STREAM, false);
2326 SFX_ITEMSET_ARG( pImp->m_pSet, pInStreamItem, SfxUnoAnyItem, SID_INPUTSTREAM, false);
2327 if ( pWriteStreamItem )
2329 pWriteStreamItem->GetValue() >>= pImp->xStream;
2331 if ( pInStreamItem )
2332 pInStreamItem->GetValue() >>= pImp->xInputStream;
2334 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2335 pImp->xInputStream = pImp->xStream->getInputStream();
2337 else if ( pInStreamItem )
2339 pInStreamItem->GetValue() >>= pImp->xInputStream;
2341 else
2343 uno::Sequence < beans::PropertyValue > xProps;
2344 OUString aFileName;
2345 if (!pImp->m_aName.isEmpty())
2347 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aFileName ) )
2349 OSL_FAIL("Physical name not convertible!");
2352 else
2353 aFileName = GetName();
2355 // in case the temporary file exists the streams should be initialized from it,
2356 // but the original MediaDescriptor should not be changed
2357 bool bFromTempFile = ( pImp->pTempFile != NULL );
2359 if ( !bFromTempFile )
2361 GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, aFileName ) );
2362 if( !(pImp->m_nStorOpenMode & STREAM_WRITE) )
2363 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
2364 if (xInteractionHandler.is())
2365 GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny(xInteractionHandler) ) );
2368 if ( pImp->m_xInputStreamToLoadFrom.is() )
2370 pImp->xInputStream = pImp->m_xInputStreamToLoadFrom;
2371 pImp->xInputStream->skipBytes(0);
2372 if (pImp->m_bInputStreamIsReadOnly)
2373 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
2375 else
2377 TransformItems( SID_OPENDOC, *GetItemSet(), xProps );
2378 comphelper::MediaDescriptor aMedium( xProps );
2380 if ( pImp->m_xLockingStream.is() && !bFromTempFile )
2382 // the medium is not based on the temporary file, so the original stream can be used
2383 pImp->xStream = pImp->m_xLockingStream;
2385 else
2387 if ( bFromTempFile )
2389 aMedium[comphelper::MediaDescriptor::PROP_URL()] <<= OUString( aFileName );
2390 aMedium.erase( comphelper::MediaDescriptor::PROP_READONLY() );
2391 aMedium.addInputStream();
2393 else if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
2395 // use the special locking approach only for file URLs
2396 aMedium.addInputStreamOwnLock();
2398 else
2399 aMedium.addInputStream();
2401 // the ReadOnly property set in aMedium is ignored
2402 // the check is done in LockOrigFileOnDemand() for file and non-file URLs
2404 //TODO/MBA: what happens if property is not there?!
2405 aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= pImp->xStream;
2406 aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= pImp->xInputStream;
2409 GetContent();
2410 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2411 pImp->xInputStream = pImp->xStream->getInputStream();
2414 if ( !bFromTempFile )
2416 //TODO/MBA: need support for SID_STREAM
2417 if ( pImp->xStream.is() )
2418 GetItemSet()->Put( SfxUsrAnyItem( SID_STREAM, makeAny( pImp->xStream ) ) );
2420 GetItemSet()->Put( SfxUsrAnyItem( SID_INPUTSTREAM, makeAny( pImp->xInputStream ) ) );
2424 //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor
2425 if ( !GetError() && !pImp->xStream.is() && !pImp->xInputStream.is() )
2426 SetError( ERRCODE_IO_ACCESSDENIED, OUString( OSL_LOG_PREFIX ) );
2428 if ( !GetError() )
2430 if ( pImp->xStream.is() )
2431 pImp->m_pInStream = utl::UcbStreamHelper::CreateStream( pImp->xStream );
2432 else if ( pImp->xInputStream.is() )
2433 pImp->m_pInStream = utl::UcbStreamHelper::CreateStream( pImp->xInputStream );
2436 pImp->bDownloadDone = true;
2437 pImp->aDoneLink.ClearPendingCall();
2438 sal_uIntPtr nError = GetError();
2439 pImp->aDoneLink.Call( (void*)nError );
2443 //----------------------------------------------------------------
2444 sal_Bool SfxMedium::IsRemote()
2446 return pImp->m_bRemote;
2449 //------------------------------------------------------------------
2451 void SfxMedium::SetUpdatePickList(sal_Bool bVal)
2453 pImp->bUpdatePickList = bVal;
2455 //------------------------------------------------------------------
2457 sal_Bool SfxMedium::IsUpdatePickList() const
2459 return pImp->bUpdatePickList;
2462 void SfxMedium::SetLongName(const OUString &rName)
2464 pImp->m_aLongName = rName;
2467 const OUString& SfxMedium::GetLongName() const
2469 return pImp->m_aLongName;
2472 void SfxMedium::SetDoneLink( const Link& rLink )
2474 pImp->aDoneLink = rLink;
2477 void SfxMedium::DownLoad( const Link& aLink )
2479 SetDoneLink( aLink );
2480 GetInStream();
2481 if ( pImp->m_pInStream && !aLink.IsSet() )
2483 while( !pImp->bDownloadDone )
2484 Application::Yield();
2488 //------------------------------------------------------------------
2489 void SfxMedium::Init_Impl()
2490 /* [Description]
2491 Includes a valid:: sun:: com:: star:: util:: URL (If a file name was
2492 previously in there) in the logical name and if available sets the
2493 physical name as the file name.
2497 Reference< XOutputStream > rOutStream;
2499 // TODO/LATER: handle lifetime of storages
2500 pImp->bDisposeStorage = false;
2502 SFX_ITEMSET_ARG( pImp->m_pSet, pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, false);
2503 if ( pSalvageItem && pSalvageItem->GetValue().isEmpty() )
2505 pSalvageItem = NULL;
2506 pImp->m_pSet->ClearItem( SID_DOC_SALVAGE );
2509 if (!pImp->m_aLogicName.isEmpty())
2511 INetURLObject aUrl( pImp->m_aLogicName );
2512 INetProtocol eProt = aUrl.GetProtocol();
2513 if ( eProt == INET_PROT_NOT_VALID )
2515 OSL_FAIL( "Unknown protocol!" );
2517 else
2519 if ( aUrl.HasMark() )
2521 pImp->m_aLogicName = aUrl.GetURLNoMark( INetURLObject::NO_DECODE );
2522 GetItemSet()->Put( SfxStringItem( SID_JUMPMARK, aUrl.GetMark() ) );
2525 // try to convert the URL into a physical name - but never change a physical name
2526 // physical name may be set if the logical name is changed after construction
2527 if ( pImp->m_aName.isEmpty() )
2528 ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), pImp->m_aName );
2529 else
2531 DBG_ASSERT( pSalvageItem, "Suspicious change of logical name!" );
2536 if ( pSalvageItem && !pSalvageItem->GetValue().isEmpty() )
2538 pImp->m_aLogicName = pSalvageItem->GetValue();
2539 DELETEZ( pImp->m_pURLObj );
2540 pImp->m_bSalvageMode = true;
2543 // in case output stream is by mistake here
2544 // clear the reference
2545 SFX_ITEMSET_ARG( pImp->m_pSet, pOutStreamItem, SfxUnoAnyItem, SID_OUTPUTSTREAM, false);
2546 if( pOutStreamItem
2547 && ( !( pOutStreamItem->GetValue() >>= rOutStream )
2548 || !pImp->m_aLogicName.startsWith("private:stream")) )
2550 pImp->m_pSet->ClearItem( SID_OUTPUTSTREAM );
2551 OSL_FAIL( "Unexpected Output stream parameter!\n" );
2554 if (!pImp->m_aLogicName.isEmpty())
2556 // if the logic name is set it should be set in MediaDescriptor as well
2557 SFX_ITEMSET_ARG( pImp->m_pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, false );
2558 if ( !pFileNameItem )
2560 // let the ItemSet be created if necessary
2561 GetItemSet()->Put(
2562 SfxStringItem(
2563 SID_FILE_NAME, INetURLObject( pImp->m_aLogicName ).GetMainURL( INetURLObject::NO_DECODE ) ) );
2567 SetIsRemote_Impl();
2570 //------------------------------------------------------------------
2571 SfxMedium::SfxMedium() : pImp(new SfxMedium_Impl(this))
2573 Init_Impl();
2576 //------------------------------------------------------------------
2578 void SfxMedium::UseInteractionHandler( sal_Bool bUse )
2580 pImp->bAllowDefaultIntHdl = bUse;
2583 //------------------------------------------------------------------
2585 ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >
2586 SfxMedium::GetInteractionHandler()
2588 // if interaction isnt allowed explicitly ... return empty reference!
2589 if ( !pImp->bUseInteractionHandler )
2590 return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
2592 // search a possible existing handler inside cached item set
2593 if ( pImp->m_pSet )
2595 ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > xHandler;
2596 SFX_ITEMSET_ARG( pImp->m_pSet, pHandler, SfxUnoAnyItem, SID_INTERACTIONHANDLER, false);
2597 if ( pHandler && (pHandler->GetValue() >>= xHandler) && xHandler.is() )
2598 return xHandler;
2601 // if default interaction isnt allowed explicitly ... return empty reference!
2602 if ( !pImp->bAllowDefaultIntHdl )
2603 return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
2605 // otherwise return cached default handler ... if it exist.
2606 if ( pImp->xInteraction.is() )
2607 return pImp->xInteraction;
2609 // create default handler and cache it!
2610 Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2611 pImp->xInteraction.set(
2612 task::InteractionHandler::createWithParent(xContext, 0), UNO_QUERY_THROW );
2613 return pImp->xInteraction;
2616 //----------------------------------------------------------------
2618 void SfxMedium::SetFilter( const SfxFilter* pFilterP, sal_Bool /*bResetOrig*/ )
2620 pImp->m_pFilter = pFilterP;
2623 const SfxFilter* SfxMedium::GetFilter() const
2625 return pImp->m_pFilter;
2628 //----------------------------------------------------------------
2630 const SfxFilter* SfxMedium::GetOrigFilter( sal_Bool bNotCurrent ) const
2632 return ( pImp->pOrigFilter || bNotCurrent ) ? pImp->pOrigFilter : pImp->m_pFilter;
2635 //----------------------------------------------------------------
2637 sal_uInt32 SfxMedium::CreatePasswordToModifyHash( const OUString& aPasswd, sal_Bool bWriter )
2639 sal_uInt32 nHash = 0;
2641 if ( !aPasswd.isEmpty() )
2643 if ( bWriter )
2645 nHash = ::comphelper::DocPasswordHelper::GetWordHashAsUINT32( aPasswd );
2647 else
2649 rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
2650 nHash = ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd, nEncoding );
2654 return nHash;
2657 //------------------------------------------------------------------
2659 void SfxMedium::Close()
2661 if ( pImp->xStorage.is() )
2663 CloseStorage();
2666 CloseStreams_Impl();
2668 UnlockFile( false );
2671 void SfxMedium::CloseAndRelease()
2673 if ( pImp->xStorage.is() )
2675 CloseStorage();
2678 CloseAndReleaseStreams_Impl();
2680 UnlockFile( true );
2683 void SfxMedium::UnlockFile( sal_Bool bReleaseLockStream )
2685 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
2686 (void) bReleaseLockStream;
2687 #else
2688 if ( pImp->m_xLockingStream.is() )
2690 if ( bReleaseLockStream )
2694 uno::Reference< io::XInputStream > xInStream = pImp->m_xLockingStream->getInputStream();
2695 uno::Reference< io::XOutputStream > xOutStream = pImp->m_xLockingStream->getOutputStream();
2696 if ( xInStream.is() )
2697 xInStream->closeInput();
2698 if ( xOutStream.is() )
2699 xOutStream->closeOutput();
2701 catch( const uno::Exception& )
2705 pImp->m_xLockingStream.clear();
2708 if ( pImp->m_bLocked )
2712 pImp->m_bLocked = false;
2713 ::svt::DocumentLockFile aLockFile( pImp->m_aLogicName );
2714 // TODO/LATER: A warning could be shown in case the file is not the own one
2715 aLockFile.RemoveFile();
2717 catch( const uno::Exception& )
2720 #endif
2723 void SfxMedium::CloseAndReleaseStreams_Impl()
2725 CloseZipStorage_Impl();
2727 uno::Reference< io::XInputStream > xInToClose = pImp->xInputStream;
2728 uno::Reference< io::XOutputStream > xOutToClose;
2729 if ( pImp->xStream.is() )
2731 xOutToClose = pImp->xStream->getOutputStream();
2733 // if the locking stream is closed here the related member should be cleaned
2734 if ( pImp->xStream == pImp->m_xLockingStream )
2735 pImp->m_xLockingStream.clear();
2738 // The probably exsisting SvStream wrappers should be closed first
2739 CloseStreams_Impl();
2741 // in case of salvage mode the storage is based on the streams
2742 if ( !pImp->m_bSalvageMode )
2746 if ( xInToClose.is() )
2747 xInToClose->closeInput();
2748 if ( xOutToClose.is() )
2749 xOutToClose->closeOutput();
2751 catch ( const uno::Exception& )
2757 //------------------------------------------------------------------
2758 void SfxMedium::CloseStreams_Impl()
2760 CloseInStream_Impl();
2761 CloseOutStream_Impl();
2763 if ( pImp->m_pSet )
2764 pImp->m_pSet->ClearItem( SID_CONTENT );
2766 pImp->aContent = ::ucbhelper::Content();
2769 //------------------------------------------------------------------
2771 void SfxMedium::SetIsRemote_Impl()
2773 INetURLObject aObj( GetName() );
2774 switch( aObj.GetProtocol() )
2776 case INET_PROT_FTP:
2777 case INET_PROT_HTTP:
2778 case INET_PROT_HTTPS:
2779 case INET_PROT_POP3:
2780 case INET_PROT_NEWS:
2781 case INET_PROT_IMAP:
2782 case INET_PROT_VIM:
2783 pImp->m_bRemote = true;
2784 break;
2785 default:
2786 pImp->m_bRemote = GetName().startsWith("private:msgid");
2787 break;
2790 // As files that are written to the remote transmission must also be able
2791 // to be read.
2792 if (pImp->m_bRemote)
2793 pImp->m_nStorOpenMode |= STREAM_READ;
2798 void SfxMedium::SetName( const String& aNameP, sal_Bool bSetOrigURL )
2800 if (pImp->aOrigURL.isEmpty())
2801 pImp->aOrigURL = pImp->m_aLogicName;
2802 if( bSetOrigURL )
2803 pImp->aOrigURL = aNameP;
2804 pImp->m_aLogicName = aNameP;
2805 DELETEZ( pImp->m_pURLObj );
2806 pImp->aContent = ::ucbhelper::Content();
2807 Init_Impl();
2810 //----------------------------------------------------------------
2811 const OUString& SfxMedium::GetOrigURL() const
2813 return pImp->aOrigURL.isEmpty() ? pImp->m_aLogicName : pImp->aOrigURL;
2816 //----------------------------------------------------------------
2818 void SfxMedium::SetPhysicalName_Impl( const OUString& rNameP )
2820 if ( rNameP != pImp->m_aName )
2822 if( pImp->pTempFile )
2824 delete pImp->pTempFile;
2825 pImp->pTempFile = NULL;
2828 if ( !pImp->m_aName.isEmpty() || !rNameP.isEmpty() )
2829 pImp->aContent = ::ucbhelper::Content();
2831 pImp->m_aName = rNameP;
2832 pImp->m_bTriedStorage = false;
2833 pImp->bIsStorage = false;
2837 //------------------------------------------------------------------
2839 void SfxMedium::ReOpen()
2841 bool bUseInteractionHandler = pImp->bUseInteractionHandler;
2842 pImp->bUseInteractionHandler = false;
2843 GetMedium_Impl();
2844 pImp->bUseInteractionHandler = bUseInteractionHandler;
2847 //------------------------------------------------------------------
2849 void SfxMedium::CompleteReOpen()
2851 // do not use temporary file for reopen and in case of success throw the temporary file away
2852 bool bUseInteractionHandler = pImp->bUseInteractionHandler;
2853 pImp->bUseInteractionHandler = false;
2855 ::utl::TempFile* pTmpFile = NULL;
2856 if ( pImp->pTempFile )
2858 pTmpFile = pImp->pTempFile;
2859 pImp->pTempFile = NULL;
2860 pImp->m_aName = OUString();
2863 GetMedium_Impl();
2865 if ( GetError() )
2867 if ( pImp->pTempFile )
2869 pImp->pTempFile->EnableKillingFile( true );
2870 delete pImp->pTempFile;
2872 pImp->pTempFile = pTmpFile;
2873 if ( pImp->pTempFile )
2874 pImp->m_aName = pImp->pTempFile->GetFileName();
2876 else
2878 pTmpFile->EnableKillingFile( true );
2879 delete pTmpFile;
2883 pImp->bUseInteractionHandler = bUseInteractionHandler;
2886 SfxMedium::SfxMedium(const String &rName, StreamMode nOpenMode, const SfxFilter *pFlt, SfxItemSet *pInSet) :
2887 pImp(new SfxMedium_Impl(this))
2889 pImp->m_pSet = pInSet;
2890 pImp->m_pFilter = pFlt;
2891 pImp->m_aLogicName = rName;
2892 pImp->m_nStorOpenMode = nOpenMode;
2893 Init_Impl();
2896 SfxMedium::SfxMedium( const uno::Sequence<beans::PropertyValue>& aArgs ) :
2897 pImp(new SfxMedium_Impl(this))
2899 SfxAllItemSet *pParams = new SfxAllItemSet( SFX_APP()->GetPool() );
2900 pImp->m_pSet = pParams;
2901 TransformParameters( SID_OPENDOC, aArgs, *pParams );
2903 OUString aFilterProvider, aFilterName;
2905 const SfxPoolItem* pItem = NULL;
2906 if (pImp->m_pSet->HasItem(SID_FILTER_PROVIDER, &pItem))
2907 aFilterProvider = static_cast<const SfxStringItem*>(pItem)->GetValue();
2909 if (pImp->m_pSet->HasItem(SID_FILTER_NAME, &pItem))
2910 aFilterName = static_cast<const SfxStringItem*>(pItem)->GetValue();
2913 if (aFilterProvider.isEmpty())
2915 // This is a conventional filter type.
2916 pImp->m_pFilter = SFX_APP()->GetFilterMatcher().GetFilter4FilterName( aFilterName );
2918 else
2920 // This filter is from an external provider such as orcus.
2921 pImp->m_pCustomFilter.reset(new SfxFilter(aFilterProvider, aFilterName));
2922 pImp->m_pFilter = pImp->m_pCustomFilter.get();
2925 SFX_ITEMSET_ARG( pImp->m_pSet, pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, false );
2926 if( pSalvageItem )
2928 // QUESTION: there is some treatment of Salvage in Init_Impl; align!
2929 if ( !pSalvageItem->GetValue().isEmpty() )
2931 // if an URL is provided in SalvageItem that means that the FileName refers to a temporary file
2932 // that must be copied here
2934 SFX_ITEMSET_ARG( pImp->m_pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, false );
2935 if (!pFileNameItem) throw uno::RuntimeException();
2936 OUString aNewTempFileURL = SfxMedium::CreateTempCopyWithExt( pFileNameItem->GetValue() );
2937 if ( !aNewTempFileURL.isEmpty() )
2939 pImp->m_pSet->Put( SfxStringItem( SID_FILE_NAME, aNewTempFileURL ) );
2940 pImp->m_pSet->ClearItem( SID_INPUTSTREAM );
2941 pImp->m_pSet->ClearItem( SID_STREAM );
2942 pImp->m_pSet->ClearItem( SID_CONTENT );
2944 else
2946 OSL_FAIL( "Can not create a new temporary file for crash recovery!\n" );
2951 SFX_ITEMSET_ARG( pImp->m_pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, false );
2952 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
2953 pImp->m_bOriginallyReadOnly = true;
2955 SFX_ITEMSET_ARG( pImp->m_pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, false );
2956 if (!pFileNameItem) throw uno::RuntimeException();
2957 pImp->m_aLogicName = pFileNameItem->GetValue();
2958 pImp->m_nStorOpenMode = pImp->m_bOriginallyReadOnly ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
2959 Init_Impl();
2963 //------------------------------------------------------------------
2965 SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const String& rBaseURL, const SfxItemSet* p ) :
2966 pImp(new SfxMedium_Impl(this))
2968 OUString aType = SfxFilter::GetTypeFromStorage(rStor);
2969 pImp->m_pFilter = SFX_APP()->GetFilterMatcher().GetFilter4EA( aType );
2970 DBG_ASSERT( pImp->m_pFilter, "No Filter for storage found!" );
2972 Init_Impl();
2973 pImp->xStorage = rStor;
2974 pImp->bDisposeStorage = false;
2976 // always take BaseURL first, could be overwritten by ItemSet
2977 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
2978 if ( p )
2979 GetItemSet()->Put( *p );
2982 //------------------------------------------------------------------
2984 SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const String& rBaseURL, const String &rTypeName, const SfxItemSet* p ) :
2985 pImp(new SfxMedium_Impl(this))
2987 pImp->m_pFilter = SFX_APP()->GetFilterMatcher().GetFilter4EA( rTypeName );
2988 DBG_ASSERT( pImp->m_pFilter, "No Filter for storage found!" );
2990 Init_Impl();
2991 pImp->xStorage = rStor;
2992 pImp->bDisposeStorage = false;
2994 // always take BaseURL first, could be overwritten by ItemSet
2995 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
2996 if ( p )
2997 GetItemSet()->Put( *p );
3000 //------------------------------------------------------------------
3002 SfxMedium::~SfxMedium()
3004 // if there is a requirement to clean the backup this is the last possibility to do it
3005 ClearBackup_Impl();
3007 Close();
3009 if( pImp->bIsTemp && !pImp->m_aName.isEmpty() )
3011 OUString aTemp;
3012 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->m_aName, aTemp ))
3014 OSL_FAIL("Physical name not convertible!");
3017 if ( !::utl::UCBContentHelper::Kill( aTemp ) )
3019 OSL_FAIL("Couldn't remove temporary file!");
3023 delete pImp;
3026 const OUString& SfxMedium::GetName() const
3028 return pImp->m_aLogicName;
3031 const INetURLObject& SfxMedium::GetURLObject() const
3033 if (!pImp->m_pURLObj)
3035 pImp->m_pURLObj = new INetURLObject( pImp->m_aLogicName );
3036 if (pImp->m_pURLObj->HasMark())
3037 *pImp->m_pURLObj = INetURLObject( pImp->m_aLogicName ).GetURLNoMark();
3040 return *pImp->m_pURLObj;
3043 void SfxMedium::SetExpired_Impl( const DateTime& rDateTime )
3045 pImp->aExpireTime = rDateTime;
3047 //----------------------------------------------------------------
3049 sal_Bool SfxMedium::IsExpired() const
3051 return pImp->aExpireTime.IsValidAndGregorian() && pImp->aExpireTime < DateTime( DateTime::SYSTEM );
3053 //----------------------------------------------------------------
3055 void SfxMedium::ForceSynchronStream_Impl( sal_Bool bForce )
3057 if( pImp->m_pInStream )
3059 SvLockBytes* pBytes = pImp->m_pInStream->GetLockBytes();
3060 if( pBytes )
3061 pBytes->SetSynchronMode( bForce );
3065 //----------------------------------------------------------------
3066 SfxFrame* SfxMedium::GetLoadTargetFrame() const
3068 return pImp->wLoadTargetFrame;
3071 void SfxMedium::setStreamToLoadFrom(const com::sun::star::uno::Reference<com::sun::star::io::XInputStream>& xInputStream,sal_Bool bIsReadOnly )
3073 pImp->m_xInputStreamToLoadFrom = xInputStream;
3074 pImp->m_bInputStreamIsReadOnly = bIsReadOnly;
3077 void SfxMedium::SetLoadTargetFrame(SfxFrame* pFrame )
3079 pImp->wLoadTargetFrame = pFrame;
3081 //----------------------------------------------------------------
3083 void SfxMedium::SetStorage_Impl( const uno::Reference < embed::XStorage >& rStor )
3085 pImp->xStorage = rStor;
3087 //----------------------------------------------------------------
3089 SfxItemSet* SfxMedium::GetItemSet() const
3091 // this method *must* return an ItemSet, returning NULL can cause crashes
3092 if (!pImp->m_pSet)
3093 pImp->m_pSet = new SfxAllItemSet( SFX_APP()->GetPool() );
3094 return pImp->m_pSet;
3096 //----------------------------------------------------------------
3098 SvKeyValueIterator* SfxMedium::GetHeaderAttributes_Impl()
3100 if( !pImp->xAttributes.Is() )
3102 pImp->xAttributes = SvKeyValueIteratorRef( new SvKeyValueIterator );
3104 if ( GetContent().is() )
3108 Any aAny = pImp->aContent.getPropertyValue( OUString("MediaType") );
3109 OUString aContentType;
3110 aAny >>= aContentType;
3112 pImp->xAttributes->Append( SvKeyValue( OUString("content-type"), aContentType ) );
3114 catch ( const ::com::sun::star::uno::Exception& )
3120 return pImp->xAttributes;
3123 ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SfxMedium::GetInputStream()
3125 if ( !pImp->xInputStream.is() )
3126 GetMedium_Impl();
3127 return pImp->xInputStream;
3130 const uno::Sequence < util::RevisionTag >& SfxMedium::GetVersionList( bool _bNoReload )
3132 // if the medium has no name, then this medium should represent a new document and can have no version info
3133 if ( ( !_bNoReload || !pImp->m_bVersionsAlreadyLoaded ) && !pImp->aVersions.getLength() &&
3134 ( !pImp->m_aName.isEmpty() || !pImp->m_aLogicName.isEmpty() ) && GetStorage().is() )
3136 uno::Reference < document::XDocumentRevisionListPersistence > xReader =
3137 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3140 pImp->aVersions = xReader->load( GetStorage() );
3142 catch ( const uno::Exception& )
3147 if ( !pImp->m_bVersionsAlreadyLoaded )
3148 pImp->m_bVersionsAlreadyLoaded = true;
3150 return pImp->aVersions;
3153 uno::Sequence < util::RevisionTag > SfxMedium::GetVersionList( const uno::Reference < embed::XStorage >& xStorage )
3155 uno::Reference < document::XDocumentRevisionListPersistence > xReader =
3156 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3159 return xReader->load( xStorage );
3161 catch ( const uno::Exception& )
3165 return uno::Sequence < util::RevisionTag >();
3168 sal_uInt16 SfxMedium::AddVersion_Impl( util::RevisionTag& rRevision )
3170 if ( GetStorage().is() )
3172 // To determine a unique name for the stream
3173 std::vector<sal_uInt32> aLongs;
3174 sal_Int32 nLength = pImp->aVersions.getLength();
3175 for ( sal_Int32 m=0; m<nLength; m++ )
3177 sal_uInt32 nVer = static_cast<sal_uInt32>(String( pImp->aVersions[m].Identifier ).Copy(7).ToInt32());
3178 size_t n;
3179 for ( n=0; n<aLongs.size(); ++n )
3180 if ( nVer<aLongs[n] )
3181 break;
3183 aLongs.insert( aLongs.begin()+n, nVer );
3186 sal_uInt16 nKey;
3187 for ( nKey=0; nKey<aLongs.size(); ++nKey )
3188 if ( aLongs[nKey] > ( sal_uIntPtr ) nKey+1 )
3189 break;
3191 OUString aRevName = "Version" + OUString::number( nKey + 1 );
3192 pImp->aVersions.realloc( nLength+1 );
3193 rRevision.Identifier = aRevName;
3194 pImp->aVersions[nLength] = rRevision;
3195 return nKey;
3198 return 0;
3201 sal_Bool SfxMedium::RemoveVersion_Impl( const OUString& rName )
3203 if ( !pImp->aVersions.getLength() )
3204 return false;
3206 sal_Int32 nLength = pImp->aVersions.getLength();
3207 for ( sal_Int32 n=0; n<nLength; n++ )
3209 if ( pImp->aVersions[n].Identifier == rName )
3211 for ( sal_Int32 m=n; m<nLength-1; m++ )
3212 pImp->aVersions[m] = pImp->aVersions[m+1];
3213 pImp->aVersions.realloc(nLength-1);
3214 return true;
3218 return false;
3221 sal_Bool SfxMedium::TransferVersionList_Impl( SfxMedium& rMedium )
3223 if ( rMedium.pImp->aVersions.getLength() )
3225 pImp->aVersions = rMedium.pImp->aVersions;
3226 return true;
3229 return false;
3232 sal_Bool SfxMedium::SaveVersionList_Impl( sal_Bool /*bUseXML*/ )
3234 if ( GetStorage().is() )
3236 if ( !pImp->aVersions.getLength() )
3237 return true;
3239 uno::Reference < document::XDocumentRevisionListPersistence > xWriter =
3240 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3243 xWriter->store( GetStorage(), pImp->aVersions );
3244 return true;
3246 catch ( const uno::Exception& )
3251 return false;
3254 //----------------------------------------------------------------
3255 sal_Bool SfxMedium::IsReadOnly()
3257 // a) ReadOnly filter cant produce read/write contents!
3258 bool bReadOnly = (
3259 (pImp->m_pFilter ) &&
3260 ((pImp->m_pFilter->GetFilterFlags() & SFX_FILTER_OPENREADONLY) == SFX_FILTER_OPENREADONLY)
3263 // b) if filter allow read/write contents .. check open mode of the storage
3264 if (!bReadOnly)
3265 bReadOnly = !( GetOpenMode() & STREAM_WRITE );
3267 // c) the API can force the readonly state!
3268 if (!bReadOnly)
3270 SFX_ITEMSET_ARG( GetItemSet(), pItem, SfxBoolItem, SID_DOC_READONLY, false);
3271 if (pItem)
3272 bReadOnly = pItem->GetValue();
3275 return bReadOnly;
3278 bool SfxMedium::IsOriginallyReadOnly() const
3280 return pImp->m_bOriginallyReadOnly;
3283 //----------------------------------------------------------------
3284 sal_Bool SfxMedium::SetWritableForUserOnly( const OUString& aURL )
3286 // UCB does not allow to allow write access only for the user,
3287 // use osl API
3288 bool bResult = false;
3290 ::osl::DirectoryItem aDirItem;
3291 if ( ::osl::DirectoryItem::get( aURL, aDirItem ) == ::osl::FileBase::E_None )
3293 ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_Attributes );
3294 if ( aDirItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None
3295 && aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
3297 sal_uInt64 nAttributes = aFileStatus.getAttributes();
3299 nAttributes &= ~(osl_File_Attribute_OwnWrite |
3300 osl_File_Attribute_GrpWrite |
3301 osl_File_Attribute_OthWrite |
3302 osl_File_Attribute_ReadOnly);
3303 nAttributes |= (osl_File_Attribute_OwnWrite |
3304 osl_File_Attribute_OwnRead);
3306 bResult = ( osl::File::setAttributes( aURL, nAttributes ) == ::osl::FileBase::E_None );
3310 return bResult;
3313 //----------------------------------------------------------------
3314 void SfxMedium::CreateTempFile( sal_Bool bReplace )
3316 if ( pImp->pTempFile )
3318 if ( !bReplace )
3319 return;
3321 DELETEZ( pImp->pTempFile );
3322 pImp->m_aName = OUString();
3325 pImp->pTempFile = new ::utl::TempFile();
3326 pImp->pTempFile->EnableKillingFile( true );
3327 pImp->m_aName = pImp->pTempFile->GetFileName();
3328 OUString aTmpURL = pImp->pTempFile->GetURL();
3329 if ( pImp->m_aName.isEmpty() || aTmpURL.isEmpty() )
3331 SetError( ERRCODE_IO_CANTWRITE, OUString( OSL_LOG_PREFIX ) );
3332 return;
3335 if ( !(pImp->m_nStorOpenMode & STREAM_TRUNC) )
3337 bool bTransferSuccess = false;
3339 if ( GetContent().is()
3340 && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
3341 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
3343 // if there is already such a document, we should copy it
3344 // if it is a file system use OS copy process
3347 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
3348 INetURLObject aTmpURLObj( aTmpURL );
3349 OUString aFileName = aTmpURLObj.getName( INetURLObject::LAST_SEGMENT,
3350 true,
3351 INetURLObject::DECODE_WITH_CHARSET );
3352 if ( !aFileName.isEmpty() && aTmpURLObj.removeSegment() )
3354 ::ucbhelper::Content aTargetContent( aTmpURLObj.GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext() );
3355 OUString sMimeType = pImp->getFilterMimeType();
3356 if ( aTargetContent.transferContent( pImp->aContent, ::ucbhelper::InsertOperation_COPY, aFileName, NameClash::OVERWRITE, sMimeType ) )
3358 SetWritableForUserOnly( aTmpURL );
3359 bTransferSuccess = true;
3363 catch( const uno::Exception& )
3366 if ( bTransferSuccess )
3368 CloseOutStream();
3369 CloseInStream();
3373 if ( !bTransferSuccess && pImp->m_pInStream )
3375 // the case when there is no URL-access available or this is a remote protocoll
3376 // but there is an input stream
3377 GetOutStream();
3378 if ( pImp->m_pOutStream )
3380 char *pBuf = new char [8192];
3381 sal_uInt32 nErr = ERRCODE_NONE;
3383 pImp->m_pInStream->Seek(0);
3384 pImp->m_pOutStream->Seek(0);
3386 while( !pImp->m_pInStream->IsEof() && nErr == ERRCODE_NONE )
3388 sal_uInt32 nRead = pImp->m_pInStream->Read( pBuf, 8192 );
3389 nErr = pImp->m_pInStream->GetError();
3390 pImp->m_pOutStream->Write( pBuf, nRead );
3393 bTransferSuccess = true;
3394 delete[] pBuf;
3395 CloseInStream();
3397 CloseOutStream_Impl();
3399 else
3401 // Quite strange design, but currently it is expected that in this case no transfer happens
3402 // TODO/LATER: get rid of this inconsistent part of the call design
3403 bTransferSuccess = true;
3404 CloseInStream();
3407 if ( !bTransferSuccess )
3409 SetError( ERRCODE_IO_CANTWRITE, OUString( OSL_LOG_PREFIX ) );
3410 return;
3414 CloseStorage();
3417 //----------------------------------------------------------------
3418 void SfxMedium::CreateTempFileNoCopy()
3420 // this call always replaces the existing temporary file
3421 if ( pImp->pTempFile )
3422 delete pImp->pTempFile;
3424 pImp->pTempFile = new ::utl::TempFile();
3425 pImp->pTempFile->EnableKillingFile( true );
3426 pImp->m_aName = pImp->pTempFile->GetFileName();
3427 if ( pImp->m_aName.isEmpty() )
3429 SetError( ERRCODE_IO_CANTWRITE, OUString( OSL_LOG_PREFIX ) );
3430 return;
3433 CloseOutStream_Impl();
3434 CloseStorage();
3437 sal_Bool SfxMedium::SignContents_Impl( sal_Bool bScriptingContent, const OUString& aODFVersion, sal_Bool bHasValidDocumentSignature )
3439 bool bChanges = false;
3441 // the medium should be closed to be able to sign, the caller is responsible to close it
3442 if ( !IsOpen() && !GetError() )
3444 // The component should know if there was a valid document signature, since
3445 // it should show a warning in this case
3446 uno::Reference< security::XDocumentDigitalSignatures > xSigner(
3447 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
3448 comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
3450 uno::Reference< embed::XStorage > xWriteableZipStor;
3451 if ( !IsReadOnly() )
3453 // we can reuse the temporary file if there is one already
3454 CreateTempFile( false );
3455 GetMedium_Impl();
3459 if ( !pImp->xStream.is() )
3460 throw uno::RuntimeException();
3462 xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImp->xStream );
3463 if ( !xWriteableZipStor.is() )
3464 throw uno::RuntimeException();
3466 uno::Reference< embed::XStorage > xMetaInf = xWriteableZipStor->openStorageElement(
3467 OUString( "META-INF" ),
3468 embed::ElementModes::READWRITE );
3469 if ( !xMetaInf.is() )
3470 throw uno::RuntimeException();
3472 if ( bScriptingContent )
3474 // If the signature has already the document signature it will be removed
3475 // after the scripting signature is inserted.
3476 uno::Reference< io::XStream > xStream(
3477 xMetaInf->openStreamElement( xSigner->getScriptingContentSignatureDefaultStreamName(),
3478 embed::ElementModes::READWRITE ),
3479 uno::UNO_SET_THROW );
3481 if ( xSigner->signScriptingContent( GetZipStorageToSign_Impl(), xStream ) )
3483 // remove the document signature if any
3484 OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName();
3485 if ( !aDocSigName.isEmpty() && xMetaInf->hasByName( aDocSigName ) )
3486 xMetaInf->removeElement( aDocSigName );
3488 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
3489 xTransact->commit();
3490 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
3491 xTransact->commit();
3493 // the temporary file has been written, commit it to the original file
3494 Commit();
3495 bChanges = true;
3498 else
3500 uno::Reference< io::XStream > xStream(
3501 xMetaInf->openStreamElement( xSigner->getDocumentContentSignatureDefaultStreamName(),
3502 embed::ElementModes::READWRITE ),
3503 uno::UNO_SET_THROW );
3505 if ( xSigner->signDocumentContent( GetZipStorageToSign_Impl(), xStream ) )
3507 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
3508 xTransact->commit();
3509 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
3510 xTransact->commit();
3512 // the temporary file has been written, commit it to the original file
3513 Commit();
3514 bChanges = true;
3518 catch ( const uno::Exception& )
3520 OSL_FAIL( "Couldn't use signing functionality!\n" );
3523 CloseAndRelease();
3525 else
3529 if ( bScriptingContent )
3530 xSigner->showScriptingContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() );
3531 else
3532 xSigner->showDocumentContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() );
3534 catch( const uno::Exception& )
3536 OSL_FAIL( "Couldn't use signing functionality!\n" );
3540 ResetError();
3543 return bChanges;
3546 //----------------------------------------------------------------
3547 sal_uInt16 SfxMedium::GetCachedSignatureState_Impl()
3549 return pImp->m_nSignatureState;
3552 //----------------------------------------------------------------
3553 void SfxMedium::SetCachedSignatureState_Impl( sal_uInt16 nState )
3555 pImp->m_nSignatureState = nState;
3558 sal_Bool SfxMedium::HasStorage_Impl() const
3560 return pImp->xStorage.is();
3563 sal_Bool SfxMedium::IsOpen() const
3565 return pImp->m_pInStream || pImp->m_pOutStream || pImp->xStorage.is();
3568 OUString SfxMedium::CreateTempCopyWithExt( const OUString& aURL )
3570 OUString aResult;
3572 if ( !aURL.isEmpty() )
3574 sal_Int32 nPrefixLen = aURL.lastIndexOf( '.' );
3575 String aExt = ( nPrefixLen == -1 ) ? String() : String( aURL.copy( nPrefixLen ) );
3577 OUString aNewTempFileURL = ::utl::TempFile( String(), &aExt ).GetURL();
3578 if ( !aNewTempFileURL.isEmpty() )
3580 INetURLObject aSource( aURL );
3581 INetURLObject aDest( aNewTempFileURL );
3582 OUString aFileName = aDest.getName( INetURLObject::LAST_SEGMENT,
3583 true,
3584 INetURLObject::DECODE_WITH_CHARSET );
3585 if ( !aFileName.isEmpty() && aDest.removeSegment() )
3589 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
3590 ::ucbhelper::Content aTargetContent( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext() );
3591 ::ucbhelper::Content aSourceContent( aSource.GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext() );
3592 if ( aTargetContent.transferContent( aSourceContent,
3593 ::ucbhelper::InsertOperation_COPY,
3594 aFileName,
3595 NameClash::OVERWRITE ) )
3597 // Success
3598 aResult = aNewTempFileURL;
3601 catch( const uno::Exception& )
3607 return aResult;
3610 sal_Bool SfxMedium::CallApproveHandler( const uno::Reference< task::XInteractionHandler >& xHandler, uno::Any aRequest, sal_Bool bAllowAbort )
3612 bool bResult = false;
3614 if ( xHandler.is() )
3618 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( bAllowAbort ? 2 : 1 );
3620 ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( new ::comphelper::OInteractionApprove );
3621 aContinuations[ 0 ] = pApprove.get();
3623 if ( bAllowAbort )
3625 ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( new ::comphelper::OInteractionAbort );
3626 aContinuations[ 1 ] = pAbort.get();
3629 xHandler->handle(::framework::InteractionRequest::CreateRequest (aRequest,aContinuations));
3630 bResult = pApprove->wasSelected();
3632 catch( const Exception& )
3637 return bResult;
3640 OUString SfxMedium::SwitchDocumentToTempFile()
3642 // the method returns empty string in case of failure
3643 OUString aResult;
3644 OUString aOrigURL = pImp->m_aLogicName;
3646 if ( !aOrigURL.isEmpty() )
3648 sal_Int32 nPrefixLen = aOrigURL.lastIndexOf( '.' );
3649 String aExt = ( nPrefixLen == -1 ) ? String() : String( aOrigURL.copy( nPrefixLen ) );
3650 OUString aNewURL = ::utl::TempFile( String(), &aExt ).GetURL();
3652 // TODO/LATER: In future the aLogicName should be set to shared folder URL
3653 // and a temporary file should be created. Transport_Impl should be impossible then.
3654 if ( !aNewURL.isEmpty() )
3656 uno::Reference< embed::XStorage > xStorage = GetStorage();
3657 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
3659 if ( xOptStorage.is() )
3661 // TODO/LATER: reuse the pImp->pTempFile if it already exists
3662 CanDisposeStorage_Impl( false );
3663 Close();
3664 SetPhysicalName_Impl( String() );
3665 SetName( aNewURL );
3667 // remove the readonly state
3668 bool bWasReadonly = false;
3669 pImp->m_nStorOpenMode = SFX_STREAM_READWRITE;
3670 SFX_ITEMSET_ARG( pImp->m_pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, false );
3671 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
3672 bWasReadonly = true;
3673 GetItemSet()->ClearItem( SID_DOC_READONLY );
3675 GetMedium_Impl();
3676 LockOrigFileOnDemand( false, false );
3677 CreateTempFile( true );
3678 GetMedium_Impl();
3680 if ( pImp->xStream.is() )
3684 xOptStorage->writeAndAttachToStream( pImp->xStream );
3685 pImp->xStorage = xStorage;
3686 aResult = aNewURL;
3688 catch( const uno::Exception& )
3692 if ( aResult.isEmpty() )
3694 Close();
3695 SetPhysicalName_Impl( String() );
3696 SetName( aOrigURL );
3697 if ( bWasReadonly )
3699 // set the readonly state back
3700 pImp->m_nStorOpenMode = SFX_STREAM_READONLY;
3701 GetItemSet()->Put( SfxBoolItem(SID_DOC_READONLY, true));
3703 GetMedium_Impl();
3704 pImp->xStorage = xStorage;
3710 return aResult;
3713 sal_Bool SfxMedium::SwitchDocumentToFile( const OUString& aURL )
3715 // the method is only for storage based documents
3716 bool bResult = false;
3717 OUString aOrigURL = pImp->m_aLogicName;
3719 if ( !aURL.isEmpty() && !aOrigURL.isEmpty() )
3721 uno::Reference< embed::XStorage > xStorage = GetStorage();
3722 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
3724 if ( xOptStorage.is() )
3726 // TODO/LATER: reuse the pImp->pTempFile if it already exists
3727 CanDisposeStorage_Impl( false );
3728 Close();
3729 SetPhysicalName_Impl( String() );
3730 SetName( aURL );
3732 // open the temporary file based document
3733 GetMedium_Impl();
3734 LockOrigFileOnDemand( false, false );
3735 CreateTempFile( true );
3736 GetMedium_Impl();
3738 if ( pImp->xStream.is() )
3742 uno::Reference< io::XTruncate > xTruncate( pImp->xStream, uno::UNO_QUERY_THROW );
3743 if ( xTruncate.is() )
3744 xTruncate->truncate();
3746 xOptStorage->writeAndAttachToStream( pImp->xStream );
3747 pImp->xStorage = xStorage;
3748 bResult = true;
3750 catch( const uno::Exception& )
3754 if ( !bResult )
3756 Close();
3757 SetPhysicalName_Impl( String() );
3758 SetName( aOrigURL );
3759 GetMedium_Impl();
3760 pImp->xStorage = xStorage;
3765 return bResult;
3768 void SfxMedium::SetInCheckIn( bool bInCheckIn )
3770 pImp->m_bInCheckIn = bInCheckIn;
3773 bool SfxMedium::IsInCheckIn( )
3775 return pImp->m_bInCheckIn;
3778 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */