Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / sfx2 / source / doc / docfile.cxx
blob6271acd844931cbf530e0855877bb3bad98f207a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <sfx2/docfile.hxx>
30 #include "sfx2/signaturestate.hxx"
32 #include <uno/mapping.hxx>
33 #include <com/sun/star/task/XInteractionHandler.hpp>
34 #include <com/sun/star/uno/Reference.h>
35 #include <com/sun/star/ucb/XContent.hpp>
36 #include <com/sun/star/container/XChild.hpp>
37 #include <com/sun/star/document/XDocumentRevisionListPersistence.hpp>
38 #include <com/sun/star/document/LockedDocumentRequest.hpp>
39 #include <com/sun/star/document/OwnLockOnDocumentRequest.hpp>
40 #include <com/sun/star/document/LockedOnSavingRequest.hpp>
41 #include <com/sun/star/document/LockFileIgnoreRequest.hpp>
42 #include <com/sun/star/document/ChangedByOthersRequest.hpp>
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include <com/sun/star/embed/XTransactedObject.hpp>
45 #include <com/sun/star/embed/ElementModes.hpp>
46 #include <com/sun/star/embed/UseBackupException.hpp>
47 #include <com/sun/star/embed/XOptimizedStorage.hpp>
48 #include <com/sun/star/ucb/InteractiveIOException.hpp>
49 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
50 #include <com/sun/star/ucb/CommandFailedException.hpp>
51 #include <com/sun/star/ucb/CommandAbortedException.hpp>
52 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
53 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
54 #include <com/sun/star/ucb/XContentProvider.hpp>
55 #include <com/sun/star/ucb/XProgressHandler.hpp>
56 #include <com/sun/star/ucb/XCommandInfo.hpp>
57 #include <com/sun/star/util/XArchiver.hpp>
58 #include <com/sun/star/io/XOutputStream.hpp>
59 #include <com/sun/star/io/XInputStream.hpp>
60 #include <com/sun/star/io/XTruncate.hpp>
61 #include <com/sun/star/io/XStreamListener.hpp>
62 #include <com/sun/star/io/XSeekable.hpp>
63 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
64 #include <com/sun/star/lang/XInitialization.hpp>
65 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
66 #include <com/sun/star/ucb/NameClash.hpp>
67 #include <com/sun/star/ucb/TransferInfo.hpp>
68 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
69 #include <com/sun/star/ucb/OpenMode.hpp>
70 #include <com/sun/star/logging/XSimpleLogRing.hpp>
71 #include <cppuhelper/implbase1.hxx>
72 #include <com/sun/star/beans/PropertyValue.hpp>
73 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
74 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
75 #include <tools/urlobj.hxx>
76 #include <unotools/tempfile.hxx>
77 #include <comphelper/processfactory.hxx>
78 #include <comphelper/componentcontext.hxx>
79 #include <comphelper/interaction.hxx>
80 #include <framework/interaction.hxx>
81 #include <unotools/streamhelper.hxx>
82 #include <unotools/localedatawrapper.hxx>
83 #include <vcl/msgbox.hxx>
84 #include <svl/stritem.hxx>
85 #include <svl/eitem.hxx>
86 #include <svl/lckbitem.hxx>
87 #include <svtools/sfxecode.hxx>
88 #include <svl/itemset.hxx>
89 #include <svl/intitem.hxx>
90 #include <svtools/svparser.hxx> // SvKeyValue
91 #include <cppuhelper/weakref.hxx>
92 #include <svl/svstdarr.hxx>
94 #include <unotools/streamwrap.hxx>
96 #include <rtl/logfile.hxx>
97 #include <osl/file.hxx>
99 using namespace ::com::sun::star;
100 using namespace ::com::sun::star::uno;
101 using namespace ::com::sun::star::ucb;
102 using namespace ::com::sun::star::beans;
103 using namespace ::com::sun::star::io;
105 #include <comphelper/storagehelper.hxx>
106 #include <comphelper/mediadescriptor.hxx>
107 #include <comphelper/configurationhelper.hxx>
108 #include <comphelper/docpasswordhelper.hxx>
109 #include <tools/inetmime.hxx>
110 #include <unotools/ucblockbytes.hxx>
111 #include <unotools/pathoptions.hxx>
112 #include <svtools/asynclink.hxx>
113 #include <svl/inettype.hxx>
114 #include <ucbhelper/contentbroker.hxx>
115 #include <ucbhelper/commandenvironment.hxx>
116 #include <unotools/localfilehelper.hxx>
117 #include <unotools/ucbstreamhelper.hxx>
118 #include <unotools/ucbhelper.hxx>
119 #include <unotools/progresshandlerwrap.hxx>
120 #include <ucbhelper/content.hxx>
121 #include <ucbhelper/interactionrequest.hxx>
122 #include <sot/stg.hxx>
123 #include <unotools/saveopt.hxx>
124 #include <svl/documentlockfile.hxx>
126 #include "helper.hxx"
127 #include <sfx2/request.hxx> // SFX_ITEMSET_SET
128 #include <sfx2/app.hxx> // GetFilterMatcher
129 #include <sfx2/frame.hxx> // LoadTargetFrame
130 #include "fltfnc.hxx" // SfxFilterMatcher
131 #include <sfx2/docfilt.hxx> // SfxFilter
132 #include <sfx2/objsh.hxx> // CheckOpenMode
133 #include <sfx2/docfac.hxx> // GetFilterContainer
134 #include "doc.hrc"
135 #include "openflag.hxx" // SFX_STREAM_READONLY etc.
136 #include "sfx2/sfxresid.hxx"
137 #include <sfx2/appuno.hxx>
138 #include "sfxacldetect.hxx"
139 #include "officecfg/Office/Common.hxx"
141 //==========================================================
142 namespace {
144 static const sal_Int8 LOCK_UI_NOLOCK = 0;
145 static const sal_Int8 LOCK_UI_SUCCEEDED = 1;
146 static const sal_Int8 LOCK_UI_TRY = 2;
148 //----------------------------------------------------------------
149 sal_Bool IsSystemFileLockingUsed()
151 // check whether system file locking has been used, the default value is false
152 sal_Bool bUseSystemLock = sal_False;
156 uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig(
157 ::comphelper::getProcessServiceFactory(),
158 ::rtl::OUString( "/org.openoffice.Office.Common" ),
159 ::comphelper::ConfigurationHelper::E_STANDARD );
160 if ( !xCommonConfig.is() )
161 throw uno::RuntimeException();
163 ::comphelper::ConfigurationHelper::readRelativeKey(
164 xCommonConfig,
165 ::rtl::OUString( "Misc/" ),
166 ::rtl::OUString( "UseDocumentSystemFileLocking" ) ) >>= bUseSystemLock;
168 catch( const uno::Exception& )
172 return bUseSystemLock;
175 //----------------------------------------------------------------
176 sal_Bool IsOOoLockFileUsed()
178 // check whether system file locking has been used, the default value is false
179 sal_Bool bOOoLockFileUsed = sal_False;
183 uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig(
184 ::comphelper::getProcessServiceFactory(),
185 ::rtl::OUString( "/org.openoffice.Office.Common" ),
186 ::comphelper::ConfigurationHelper::E_STANDARD );
187 if ( !xCommonConfig.is() )
188 throw uno::RuntimeException();
190 ::comphelper::ConfigurationHelper::readRelativeKey(
191 xCommonConfig,
192 ::rtl::OUString( "Misc/" ),
193 ::rtl::OUString( "UseDocumentOOoLockFile" ) ) >>= bOOoLockFileUsed;
195 catch( const uno::Exception& )
199 return bOOoLockFileUsed;
202 bool IsLockingUsed()
204 return officecfg::Office::Common::Misc::UseLocking::get();
207 } // anonymous namespace
208 //==========================================================
211 //----------------------------------------------------------------
212 class SfxMediumHandler_Impl : public ::cppu::WeakImplHelper1< com::sun::star::task::XInteractionHandler >
214 com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > m_xInter;
216 public:
217 virtual void SAL_CALL handle( const com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest >& xRequest )
218 throw( com::sun::star::uno::RuntimeException );
220 SfxMediumHandler_Impl( com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > xInteraction )
221 : m_xInter( xInteraction )
224 ~SfxMediumHandler_Impl();
227 //----------------------------------------------------------------
228 SfxMediumHandler_Impl::~SfxMediumHandler_Impl()
232 //----------------------------------------------------------------
233 void SAL_CALL SfxMediumHandler_Impl::handle( const com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest >& xRequest )
234 throw( com::sun::star::uno::RuntimeException )
236 if( !m_xInter.is() )
237 return;
239 com::sun::star::uno::Any aRequest = xRequest->getRequest();
240 com::sun::star::ucb::InteractiveIOException aIoException;
241 com::sun::star::ucb::UnsupportedDataSinkException aSinkException;
242 if ( (aRequest >>= aIoException) && ( aIoException.Code == IOErrorCode_ACCESS_DENIED || aIoException.Code == IOErrorCode_LOCKING_VIOLATION ) )
243 return;
244 else
245 if ( aRequest >>= aSinkException )
246 return;
247 else
248 m_xInter->handle( xRequest );
251 //----------------------------------------------------------------
252 class SfxMedium_Impl
254 public:
255 ::ucbhelper::Content aContent;
256 sal_Bool bUpdatePickList : 1;
257 sal_Bool bIsTemp : 1;
258 sal_Bool bForceSynchron : 1;
259 sal_Bool bDownloadDone : 1;
260 sal_Bool bDontCallDoneLinkOnSharingError : 1;
261 sal_Bool bIsStorage: 1;
262 sal_Bool bUseInteractionHandler: 1;
263 sal_Bool bAllowDefaultIntHdl: 1;
264 sal_Bool bIsCharsetInitialized: 1;
265 sal_Bool bDisposeStorage: 1;
266 sal_Bool bStorageBasedOnInStream: 1;
267 sal_Bool m_bSalvageMode: 1;
268 sal_Bool m_bVersionsAlreadyLoaded: 1;
269 sal_Bool m_bLocked: 1;
270 sal_Bool m_bGotDateTime: 1;
272 uno::Reference < embed::XStorage > xStorage;
274 SfxMedium* pAntiImpl;
276 long nFileVersion;
278 const SfxFilter* pOrigFilter;
279 String aOrigURL;
280 String aPreRedirectionURL;
281 String aReferer;
282 DateTime aExpireTime;
283 SfxFrameWeak wLoadTargetFrame;
284 SvKeyValueIteratorRef xAttributes;
286 svtools::AsynchronLink aDoneLink;
287 svtools::AsynchronLink aAvailableLink;
289 uno::Sequence < util::RevisionTag > aVersions;
291 ::utl::TempFile* pTempFile;
293 uno::Reference < embed::XStorage > m_xZipStorage;
294 Reference < XInputStream > xInputStream;
295 Reference < XStream > xStream;
297 uno::Reference< io::XStream > m_xLockingStream;
299 sal_uInt32 nLastStorageError;
300 ::rtl::OUString aCharset;
302 ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > xInteraction;
304 sal_Bool m_bRemoveBackup;
305 ::rtl::OUString m_aBackupURL;
307 // the following member is changed and makes sence only during saving
308 // TODO/LATER: in future the signature state should be controlled by the medium not by the document
309 // in this case the member will hold this information
310 sal_uInt16 m_nSignatureState;
312 util::DateTime m_aDateTime;
314 uno::Reference< logging::XSimpleLogRing > m_xLogRing;
316 bool m_originallyReadOnly;
318 SfxMedium_Impl( SfxMedium* pAntiImplP );
319 ~SfxMedium_Impl();
322 //------------------------------------------------------------------
323 SfxMedium_Impl::SfxMedium_Impl( SfxMedium* pAntiImplP )
324 : bUpdatePickList(sal_True),
325 bIsTemp( sal_False ),
326 bForceSynchron( sal_False ),
327 bDownloadDone( sal_True ),
328 bDontCallDoneLinkOnSharingError( sal_False ),
329 bIsStorage( sal_False ),
330 bUseInteractionHandler( sal_True ),
331 bAllowDefaultIntHdl( sal_False ),
332 bIsCharsetInitialized( sal_False ),
333 bStorageBasedOnInStream( sal_False ),
334 m_bSalvageMode( sal_False ),
335 m_bVersionsAlreadyLoaded( sal_False ),
336 m_bLocked( sal_False ),
337 m_bGotDateTime( sal_False ),
338 pAntiImpl( pAntiImplP ),
339 nFileVersion( 0 ),
340 pOrigFilter( 0 ),
341 aExpireTime( Date( Date::SYSTEM ) + 10, Time( Time::SYSTEM ) ),
342 pTempFile( NULL ),
343 nLastStorageError( 0 ),
344 m_bRemoveBackup( sal_False ),
345 m_nSignatureState( SIGNATURESTATE_NOSIGNATURES ),
346 m_originallyReadOnly(false)
348 aDoneLink.CreateMutex();
351 //------------------------------------------------------------------
352 SfxMedium_Impl::~SfxMedium_Impl()
355 aDoneLink.ClearPendingCall();
356 aAvailableLink.ClearPendingCall();
358 if ( pTempFile )
359 delete pTempFile;
362 //================================================================
364 #define IMPL_CTOR(rootVal,URLVal) \
365 eError( SVSTREAM_OK ), \
367 bRoot( rootVal ), \
368 bSetFilter( sal_False ), \
369 bTriedStorage( sal_False ), \
371 nStorOpenMode( SFX_STREAM_READWRITE ), \
372 pURLObj( URLVal ), \
373 pInStream(0), \
374 pOutStream( 0 )
376 //------------------------------------------------------------------
377 void SfxMedium::ResetError()
379 eError = SVSTREAM_OK;
380 if( pInStream )
381 pInStream->ResetError();
382 if( pOutStream )
383 pOutStream->ResetError();
386 //------------------------------------------------------------------
387 sal_uInt32 SfxMedium::GetLastStorageCreationState()
389 return pImp->nLastStorageError;
392 //------------------------------------------------------------------
393 void SfxMedium::AddLog( const ::rtl::OUString& aMessage )
395 if ( !pImp->m_xLogRing.is() )
399 ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() );
400 if ( aContext.is() )
401 pImp->m_xLogRing.set( aContext.getSingleton( "com.sun.star.logging.DocumentIOLogRing" ), UNO_QUERY_THROW );
403 catch( const uno::Exception& )
407 if ( pImp->m_xLogRing.is() )
408 pImp->m_xLogRing->logString( aMessage );
411 //------------------------------------------------------------------
412 void SfxMedium::SetError( sal_uInt32 nError, const ::rtl::OUString& aLogMessage )
414 eError = nError;
415 if ( eError != ERRCODE_NONE && !aLogMessage.isEmpty() )
416 AddLog( aLogMessage );
419 //------------------------------------------------------------------
420 sal_uInt32 SfxMedium::GetErrorCode() const
422 sal_uInt32 lError=eError;
423 if(!lError && pInStream)
424 lError=pInStream->GetErrorCode();
425 if(!lError && pOutStream)
426 lError=pOutStream->GetErrorCode();
427 return lError;
430 //------------------------------------------------------------------
431 void SfxMedium::CheckFileDate( const util::DateTime& aInitDate )
433 GetInitFileDate( sal_True );
434 if ( pImp->m_aDateTime.Seconds != aInitDate.Seconds
435 || pImp->m_aDateTime.Minutes != aInitDate.Minutes
436 || pImp->m_aDateTime.Hours != aInitDate.Hours
437 || pImp->m_aDateTime.Day != aInitDate.Day
438 || pImp->m_aDateTime.Month != aInitDate.Month
439 || pImp->m_aDateTime.Year != aInitDate.Year )
441 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
443 if ( xHandler.is() )
447 ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
448 document::ChangedByOthersRequest() ) );
449 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 );
450 aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
451 aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
452 xInteractionRequestImpl->setContinuations( aContinuations );
454 xHandler->handle( xInteractionRequestImpl.get() );
456 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
457 if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() )
459 SetError( ERRCODE_ABORT, ::rtl::OUString( OSL_LOG_PREFIX ) );
462 catch ( const uno::Exception& )
468 //------------------------------------------------------------------
469 sal_Bool SfxMedium::DocNeedsFileDateCheck()
471 return ( !IsReadOnly() && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) );
474 //------------------------------------------------------------------
475 util::DateTime SfxMedium::GetInitFileDate( sal_Bool bIgnoreOldValue )
477 if ( ( bIgnoreOldValue || !pImp->m_bGotDateTime ) && aLogicName.Len() )
481 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
482 ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv );
484 aContent.getPropertyValue( ::rtl::OUString("DateModified" ) ) >>= pImp->m_aDateTime;
485 pImp->m_bGotDateTime = sal_True;
487 catch ( const ::com::sun::star::uno::Exception& )
492 return pImp->m_aDateTime;
495 //------------------------------------------------------------------
496 Reference < XContent > SfxMedium::GetContent() const
498 if ( !pImp->aContent.get().is() )
500 Reference < ::com::sun::star::ucb::XContent > xContent;
501 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
503 SFX_ITEMSET_ARG( pSet, pItem, SfxUnoAnyItem, SID_CONTENT, sal_False);
504 if ( pItem )
505 pItem->GetValue() >>= xContent;
507 if ( xContent.is() )
511 pImp->aContent = ::ucbhelper::Content( xContent, xEnv );
513 catch ( const Exception& )
517 else
519 // TODO: OSL_FAIL("SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why its used.");
520 rtl::OUString aURL;
521 if ( !aName.isEmpty() )
522 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aURL );
523 else if ( aLogicName.Len() )
524 aURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
525 if (!aURL.isEmpty() )
526 ::ucbhelper::Content::create( aURL, xEnv, pImp->aContent );
530 return pImp->aContent.get();
533 //------------------------------------------------------------------
534 ::rtl::OUString SfxMedium::GetBaseURL( bool bForSaving )
536 ::rtl::OUString aBaseURL;
537 const SfxStringItem* pBaseURLItem = static_cast<const SfxStringItem*>( GetItemSet()->GetItem(SID_DOC_BASEURL) );
538 if ( pBaseURLItem )
539 aBaseURL = pBaseURLItem->GetValue();
540 else if ( GetContent().is() )
544 Any aAny = pImp->aContent.getPropertyValue( ::rtl::OUString("BaseURI" ) );
545 aAny >>= aBaseURL;
547 catch ( const ::com::sun::star::uno::Exception& )
551 if ( aBaseURL.isEmpty() )
552 aBaseURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE );
555 if ( bForSaving )
557 SvtSaveOptions aOpt;
558 sal_Bool bIsRemote = IsRemote();
559 if( (bIsRemote && !aOpt.IsSaveRelINet()) || (!bRemote && !aOpt.IsSaveRelFSys()) )
560 return ::rtl::OUString();
563 return aBaseURL;
566 //------------------------------------------------------------------
567 SvStream* SfxMedium::GetInStream()
569 if ( pInStream )
570 return pInStream;
572 if ( pImp->pTempFile )
574 pInStream = new SvFileStream( aName, nStorOpenMode );
576 eError = pInStream->GetError();
578 if( !eError && (nStorOpenMode & STREAM_WRITE)
579 && ! pInStream->IsWritable() )
581 eError = ERRCODE_IO_ACCESSDENIED;
582 delete pInStream;
583 pInStream = NULL;
585 else
586 return pInStream;
589 GetMedium_Impl();
591 if ( GetError() )
592 return NULL;
594 return pInStream;
597 //------------------------------------------------------------------
598 void SfxMedium::CloseInStream()
600 CloseInStream_Impl();
603 void SfxMedium::CloseInStream_Impl()
605 // if there is a storage based on the InStream, we have to
606 // close the storage, too, because otherwise the storage
607 // would use an invalid ( deleted ) stream.
608 if ( pInStream && pImp->xStorage.is() )
610 if ( pImp->bStorageBasedOnInStream )
611 CloseStorage();
614 if ( pInStream && !GetContent().is() )
616 CreateTempFile( sal_True );
617 return;
620 DELETEZ( pInStream );
621 if ( pSet )
622 pSet->ClearItem( SID_INPUTSTREAM );
624 CloseZipStorage_Impl();
625 pImp->xInputStream = uno::Reference< io::XInputStream >();
627 if ( !pOutStream )
629 // output part of the stream is not used so the whole stream can be closed
630 // TODO/LATER: is it correct?
631 pImp->xStream = uno::Reference< io::XStream >();
632 if ( pSet )
633 pSet->ClearItem( SID_STREAM );
637 //------------------------------------------------------------------
638 SvStream* SfxMedium::GetOutStream()
640 if ( !pOutStream )
642 // Create a temp. file if there is none because we always
643 // need one.
644 CreateTempFile( sal_False );
646 if ( pImp->pTempFile )
648 pOutStream = new SvFileStream( aName, STREAM_STD_READWRITE );
649 CloseStorage();
653 return pOutStream;
656 //------------------------------------------------------------------
657 sal_Bool SfxMedium::CloseOutStream()
659 CloseOutStream_Impl();
660 return sal_True;
663 sal_Bool SfxMedium::CloseOutStream_Impl()
665 if ( pOutStream )
667 // if there is a storage based on the OutStream, we have to
668 // close the storage, too, because otherwise the storage
669 // would use an invalid ( deleted ) stream.
670 //TODO/MBA: how to deal with this?!
671 //maybe we need a new flag when the storage was created from the outstream
672 if ( pImp->xStorage.is() )
674 CloseStorage();
677 delete pOutStream;
678 pOutStream = NULL;
681 if ( !pInStream )
683 // input part of the stream is not used so the whole stream can be closed
684 // TODO/LATER: is it correct?
685 pImp->xStream = uno::Reference< io::XStream >();
686 if ( pSet )
687 pSet->ClearItem( SID_STREAM );
690 return sal_True;
693 //------------------------------------------------------------------
694 const rtl::OUString& SfxMedium::GetPhysicalName() const
696 if ( aName.isEmpty() && aLogicName.Len() )
697 (( SfxMedium*)this)->CreateFileStream();
699 // return the name then
700 return aName;
703 //------------------------------------------------------------------
704 void SfxMedium::CreateFileStream()
706 ForceSynchronStream_Impl( sal_True );
707 GetInStream();
708 if( pInStream )
710 CreateTempFile( sal_False );
711 pImp->bIsTemp = sal_True;
712 CloseInStream_Impl();
716 //------------------------------------------------------------------
717 sal_Bool SfxMedium::Commit()
719 if( pImp->xStorage.is() )
720 StorageCommit_Impl();
721 else if( pOutStream )
722 pOutStream->Flush();
723 else if( pInStream )
724 pInStream->Flush();
726 if ( GetError() == SVSTREAM_OK )
728 // does something only in case there is a temporary file ( means aName points to different location than aLogicName )
729 Transfer_Impl();
732 sal_Bool bResult = ( GetError() == SVSTREAM_OK );
734 if ( bResult && DocNeedsFileDateCheck() )
735 GetInitFileDate( sal_True );
737 // remove truncation mode from the flags
738 nStorOpenMode &= (~STREAM_TRUNC);
739 return bResult;
742 //------------------------------------------------------------------
743 sal_Bool SfxMedium::IsStorage()
745 if ( pImp->xStorage.is() )
746 return sal_True;
748 if ( bTriedStorage )
749 return pImp->bIsStorage;
751 if ( pImp->pTempFile )
753 rtl::OUString aURL;
754 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aURL ) )
756 OSL_FAIL("Physical name not convertable!");
758 pImp->bIsStorage = SotStorage::IsStorageFile( aURL ) && !SotStorage::IsOLEStorage( aURL);
759 if ( !pImp->bIsStorage )
760 bTriedStorage = sal_True;
762 else if ( GetInStream() )
764 pImp->bIsStorage = SotStorage::IsStorageFile( pInStream ) && !SotStorage::IsOLEStorage( pInStream );
765 if ( !pInStream->GetError() && !pImp->bIsStorage )
766 bTriedStorage = sal_True;
769 return pImp->bIsStorage;
772 //------------------------------------------------------------------
773 sal_Bool SfxMedium::IsPreview_Impl()
775 sal_Bool bPreview = sal_False;
776 SFX_ITEMSET_ARG( GetItemSet(), pPreview, SfxBoolItem, SID_PREVIEW, sal_False);
777 if ( pPreview )
778 bPreview = pPreview->GetValue();
779 else
781 SFX_ITEMSET_ARG( GetItemSet(), pFlags, SfxStringItem, SID_OPTIONS, sal_False);
782 if ( pFlags )
784 String aFileFlags = pFlags->GetValue();
785 aFileFlags.ToUpperAscii();
786 if ( STRING_NOTFOUND != aFileFlags.Search( 'B' ) )
787 bPreview = sal_True;
791 return bPreview;
794 //------------------------------------------------------------------
795 void SfxMedium::StorageBackup_Impl()
797 ::ucbhelper::Content aOriginalContent;
798 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
800 sal_Bool bBasedOnOriginalFile = ( !pImp->pTempFile && !( aLogicName.Len() && pImp->m_bSalvageMode )
801 && !GetURLObject().GetMainURL( INetURLObject::NO_DECODE ).isEmpty()
802 && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
803 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) );
805 if ( bBasedOnOriginalFile && pImp->m_aBackupURL.isEmpty()
806 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, aOriginalContent ) )
808 DoInternalBackup_Impl( aOriginalContent );
809 if( pImp->m_aBackupURL.isEmpty() )
810 SetError( ERRCODE_SFX_CANTCREATEBACKUP, ::rtl::OUString( OSL_LOG_PREFIX ) );
814 //------------------------------------------------------------------
815 ::rtl::OUString SfxMedium::GetBackup_Impl()
817 if ( pImp->m_aBackupURL.isEmpty() )
818 StorageBackup_Impl();
820 return pImp->m_aBackupURL;
823 //------------------------------------------------------------------
824 uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage()
826 if ( GetError() )
827 return uno::Reference< embed::XStorage >();
829 // if the medium was constructed with a Storage: use this one, not a temp. storage
830 // if a temporary storage already exists: use it
831 if ( pImp->xStorage.is() && ( !aLogicName.Len() || pImp->pTempFile ) )
832 return pImp->xStorage;
834 // if necessary close stream that was used for reading
835 if ( pInStream && !pInStream->IsWritable() )
836 CloseInStream();
838 DBG_ASSERT( !pOutStream, "OutStream in a readonly Medium?!" );
840 // TODO/LATER: The current solution is to store the document temporary and then copy it to the target location;
841 // in future it should be stored directly and then copied to the temporary location, since in this case no
842 // file attributes have to be preserved and system copying mechanics could be used instead of streaming.
843 CreateTempFileNoCopy();
845 return GetStorage();
848 //------------------------------------------------------------------
849 void SfxMedium::SetEncryptionDataToStorage_Impl()
851 // in case media-descriptor contains password it should be used on opening
852 if ( pImp->xStorage.is() && pSet )
854 uno::Sequence< beans::NamedValue > aEncryptionData;
855 if ( GetEncryptionData_Impl( pSet, aEncryptionData ) )
857 // replace the password with encryption data
858 pSet->ClearItem( SID_PASSWORD );
859 pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
863 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( pImp->xStorage, aEncryptionData );
865 catch( const uno::Exception& )
867 OSL_FAIL( "It must be possible to set a common password for the storage" );
868 // TODO/LATER: set the error code in case of problem
869 // SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
875 //------------------------------------------------------------------
876 sal_Int8 SfxMedium::ShowLockedDocumentDialog( const uno::Sequence< ::rtl::OUString >& aData, sal_Bool bIsLoading, sal_Bool bOwnLock )
878 sal_Int8 nResult = LOCK_UI_NOLOCK;
880 // show the interaction regarding the document opening
881 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
883 if ( ::svt::DocumentLockFile::IsInteractionAllowed() && xHandler.is() && ( bIsLoading || bOwnLock ) )
885 ::rtl::OUString aDocumentURL = GetURLObject().GetLastName();
886 ::rtl::OUString aInfo;
887 ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl;
889 if ( bOwnLock )
891 if ( aData.getLength() > LOCKFILE_EDITTIME_ID )
892 aInfo = aData[LOCKFILE_EDITTIME_ID];
894 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
895 document::OwnLockOnDocumentRequest( ::rtl::OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo, !bIsLoading ) ) );
897 else
899 if ( aData.getLength() > LOCKFILE_EDITTIME_ID )
901 if ( !aData[LOCKFILE_OOOUSERNAME_ID].isEmpty() )
902 aInfo = aData[LOCKFILE_OOOUSERNAME_ID];
903 else
904 aInfo = aData[LOCKFILE_SYSUSERNAME_ID];
906 if ( !aInfo.isEmpty() && !aData[LOCKFILE_EDITTIME_ID].isEmpty() )
908 aInfo += ::rtl::OUString( " ( " );
909 aInfo += aData[LOCKFILE_EDITTIME_ID];
910 aInfo += ::rtl::OUString( " )" );
914 if ( bIsLoading )
916 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
917 document::LockedDocumentRequest( ::rtl::OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
919 else
921 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
922 document::LockedOnSavingRequest( ::rtl::OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
927 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 );
928 aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
929 aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
930 aContinuations[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl.get() );
931 xInteractionRequestImpl->setContinuations( aContinuations );
933 xHandler->handle( xInteractionRequestImpl.get() );
935 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
936 if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() )
938 SetError( ERRCODE_ABORT, ::rtl::OUString( OSL_LOG_PREFIX ) );
940 else if ( uno::Reference< task::XInteractionDisapprove >( xSelected.get(), uno::UNO_QUERY ).is() )
942 // own lock on loading, user has selected to ignore the lock
943 // own lock on saving, user has selected to ignore the lock
944 // alien lock on loading, user has selected to edit a copy of document
945 // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location
946 if ( bIsLoading && !bOwnLock )
948 // means that a copy of the document should be opened
949 GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, sal_True ) );
951 else if ( bOwnLock )
952 nResult = LOCK_UI_SUCCEEDED;
954 else // if ( XSelected == aContinuations[1] )
956 // own lock on loading, user has selected to open readonly
957 // own lock on saving, user has selected to open readonly
958 // alien lock on loading, user has selected to retry saving
959 // TODO/LATER: alien lock on saving, user has selected to retry saving
961 if ( bIsLoading )
962 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) );
963 else
964 nResult = LOCK_UI_TRY;
967 else
969 if ( bIsLoading )
971 // if no interaction handler is provided the default answer is open readonly
972 // that usually happens in case the document is loaded per API
973 // so the document must be opened readonly for backward compatibility
974 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) );
976 else
977 SetError( ERRCODE_IO_ACCESSDENIED, ::rtl::OUString( OSL_LOG_PREFIX ) );
981 return nResult;
984 namespace
986 bool isSuitableProtocolForLocking(const String & rLogicName)
988 INetURLObject aUrl( rLogicName );
989 INetProtocol eProt = aUrl.GetProtocol();
990 return eProt == INET_PROT_FILE || eProt == INET_PROT_SFTP;
994 //------------------------------------------------------------------
995 sal_Bool SfxMedium::LockOrigFileOnDemand( sal_Bool bLoading, sal_Bool bNoUI )
997 // returns true if the document can be opened for editing ( even if it should be a copy )
998 // otherwise the document should be opened readonly
999 // if user cancel the loading the ERROR_ABORT is set
1000 sal_Bool bResult = sal_False;
1002 if (!IsLockingUsed())
1004 return sal_True;
1007 if ( !GetURLObject().HasError() ) try
1009 if ( pImp->m_bLocked && bLoading && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
1011 // if the document is already locked the system locking might be temporarely off after storing
1012 // check whether the system file locking should be taken again
1013 GetLockingStream_Impl();
1016 bResult = pImp->m_bLocked;
1018 if ( !bResult )
1020 // no read-write access is necessary on loading if the document is explicitly opened as copy
1021 SFX_ITEMSET_ARG( GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False);
1022 bResult = ( bLoading && pTemplateItem && pTemplateItem->GetValue() );
1025 if ( !bResult && !IsReadOnly() )
1027 sal_Bool bContentReadonly = sal_False;
1028 if ( bLoading && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
1030 // let the original document be opened to check the possibility to open it for editing
1031 // and to let the writable stream stay open to hold the lock on the document
1032 GetLockingStream_Impl();
1035 // "IsReadOnly" property does not allow to detect whether the file is readonly always
1036 // so we try always to open the file for editing
1037 // the file is readonly only in case the read-write stream can not be opened
1038 if ( bLoading && !pImp->m_xLockingStream.is() )
1042 // MediaDescriptor does this check also, the duplication should be avoided in future
1043 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1044 ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv );
1045 aContent.getPropertyValue( ::rtl::OUString( "IsReadOnly" ) ) >>= bContentReadonly;
1047 catch( const uno::Exception& )
1050 #if EXTRA_ACL_CHECK
1051 // This block was introduced as a fix to i#102464, but removing
1052 // this does not make the problem re-appear. But leaving this
1053 // part would interfere with documents saved in samba share. This
1054 // affects Windows only.
1055 if ( !bContentReadonly )
1057 // the file is not readonly, check the ACL
1059 String aPhysPath;
1060 if ( ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), aPhysPath ) )
1061 bContentReadonly = IsReadonlyAccordingACL( aPhysPath.GetBuffer() );
1063 #endif
1065 if ( bContentReadonly )
1067 pImp->m_originallyReadOnly = true;
1071 // do further checks only if the file not readonly in fs
1072 if ( !bContentReadonly )
1074 // the special file locking should be used only for suitable URLs
1075 if ( isSuitableProtocolForLocking( aLogicName ) )
1078 // in case of storing the document should request the output before locking
1079 if ( bLoading )
1081 // let the stream be opened to check the system file locking
1082 GetMedium_Impl();
1085 sal_Int8 bUIStatus = LOCK_UI_NOLOCK;
1087 // check whether system file locking has been used, the default value is false
1088 sal_Bool bUseSystemLock = ::utl::LocalFileHelper::IsLocalFile( aLogicName ) && IsSystemFileLockingUsed();
1090 // TODO/LATER: This implementation does not allow to detect the system lock on saving here, actually this is no big problem
1091 // if system lock is used the writeable stream should be available
1092 sal_Bool bHandleSysLocked = ( bLoading && bUseSystemLock && !pImp->xStream.is() && !pOutStream );
1098 ::svt::DocumentLockFile aLockFile( aLogicName );
1099 if ( !bHandleSysLocked )
1103 bResult = aLockFile.CreateOwnLockFile();
1105 catch ( const ucb::InteractiveIOException& e )
1107 // exception means that the lock file can not be successfuly accessed
1108 // in this case it should be ignored if system file locking is anyway active
1109 if ( bUseSystemLock || !IsOOoLockFileUsed() )
1111 bResult = sal_True;
1112 // take the ownership over the lock file
1113 aLockFile.OverwriteOwnLockFile();
1115 else if ( e.Code == IOErrorCode_INVALID_PARAMETER )
1117 // system file locking is not active, ask user whether he wants to open the document without any locking
1118 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
1120 if ( xHandler.is() )
1122 ::rtl::Reference< ::ucbhelper::InteractionRequest > xIgnoreRequestImpl
1123 = new ::ucbhelper::InteractionRequest( uno::makeAny( document::LockFileIgnoreRequest() ) );
1125 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 2 );
1126 aContinuations[0] = new ::ucbhelper::InteractionAbort( xIgnoreRequestImpl.get() );
1127 aContinuations[1] = new ::ucbhelper::InteractionApprove( xIgnoreRequestImpl.get() );
1128 xIgnoreRequestImpl->setContinuations( aContinuations );
1130 xHandler->handle( xIgnoreRequestImpl.get() );
1132 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xIgnoreRequestImpl->getSelection();
1133 bResult = ( uno::Reference< task::XInteractionApprove >( xSelected.get(), uno::UNO_QUERY ).is() );
1137 catch ( const uno::Exception& )
1139 // exception means that the lock file can not be successfuly accessed
1140 // in this case it should be ignored if system file locking is anyway active
1141 if ( bUseSystemLock || !IsOOoLockFileUsed() )
1143 bResult = sal_True;
1144 // take the ownership over the lock file
1145 aLockFile.OverwriteOwnLockFile();
1149 // in case OOo locking is turned off the lock file is still written if possible
1150 // but it is ignored while deciding whether the document should be opened for editing or not
1151 if ( !bResult && !IsOOoLockFileUsed() )
1153 bResult = sal_True;
1154 // take the ownership over the lock file
1155 aLockFile.OverwriteOwnLockFile();
1160 if ( !bResult )
1162 uno::Sequence< ::rtl::OUString > aData;
1165 // impossibility to get data is no real problem
1166 aData = aLockFile.GetLockData();
1168 catch( const uno::Exception& )
1172 sal_Bool bOwnLock = sal_False;
1174 if ( !bHandleSysLocked )
1176 uno::Sequence< ::rtl::OUString > aOwnData = aLockFile.GenerateOwnEntry();
1177 bOwnLock = ( aData.getLength() > LOCKFILE_USERURL_ID
1178 && aOwnData.getLength() > LOCKFILE_USERURL_ID
1179 && aOwnData[LOCKFILE_SYSUSERNAME_ID].equals( aData[LOCKFILE_SYSUSERNAME_ID] ) );
1181 if ( bOwnLock
1182 && aOwnData[LOCKFILE_LOCALHOST_ID].equals( aData[LOCKFILE_LOCALHOST_ID] )
1183 && aOwnData[LOCKFILE_USERURL_ID].equals( aData[LOCKFILE_USERURL_ID] ) )
1185 // this is own lock from the same installation, it could remain because of crash
1186 bResult = sal_True;
1190 if ( !bResult && !bNoUI )
1192 bUIStatus = ShowLockedDocumentDialog( aData, bLoading, bOwnLock );
1193 if ( bUIStatus == LOCK_UI_SUCCEEDED )
1195 // take the ownership over the lock file
1196 bResult = aLockFile.OverwriteOwnLockFile();
1200 bHandleSysLocked = sal_False;
1203 catch( const uno::Exception& )
1206 } while( !bResult && bUIStatus == LOCK_UI_TRY );
1208 pImp->m_bLocked = bResult;
1210 else
1212 // this is no file URL, check whether the file is readonly
1213 bResult = !bContentReadonly;
1218 if ( !bResult && GetError() == ERRCODE_NONE )
1220 // the error should be set in case it is storing process
1221 // or the document has been opened for editing explicitly
1223 SFX_ITEMSET_ARG( pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, sal_False );
1224 if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) )
1225 SetError( ERRCODE_IO_ACCESSDENIED, ::rtl::OUString( OSL_LOG_PREFIX ) );
1226 else
1227 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) );
1230 // when the file is locked, get the current file date
1231 if ( bResult && DocNeedsFileDateCheck() )
1232 GetInitFileDate( sal_True );
1234 catch( const uno::Exception& )
1236 OSL_FAIL( "Unexpected problem by locking, high probability, that the content could not be created" );
1238 return bResult;
1241 //------------------------------------------------------------------
1242 uno::Reference < embed::XStorage > SfxMedium::GetStorage( sal_Bool bCreateTempIfNo )
1244 if ( pImp->xStorage.is() || bTriedStorage )
1245 return pImp->xStorage;
1247 uno::Sequence< uno::Any > aArgs( 2 );
1249 // the medium should be retrieved before temporary file creation
1250 // to let the MediaDescriptor be filled with the streams
1251 GetMedium_Impl();
1253 if ( bCreateTempIfNo )
1254 CreateTempFile( sal_False );
1256 GetMedium_Impl();
1258 if ( GetError() )
1259 return pImp->xStorage;
1261 SFX_ITEMSET_ARG( GetItemSet(), pRepairItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False);
1262 if ( pRepairItem && pRepairItem->GetValue() )
1264 // the storage should be created for repairing mode
1265 CreateTempFile( sal_False );
1266 GetMedium_Impl();
1268 Reference< ::com::sun::star::ucb::XProgressHandler > xProgressHandler;
1269 Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
1271 SFX_ITEMSET_ARG( GetItemSet(), pxProgressItem, SfxUnoAnyItem, SID_PROGRESS_STATUSBAR_CONTROL, sal_False );
1272 if( pxProgressItem && ( pxProgressItem->GetValue() >>= xStatusIndicator ) )
1273 xProgressHandler = Reference< ::com::sun::star::ucb::XProgressHandler >(
1274 new utl::ProgressHandlerWrap( xStatusIndicator ) );
1276 uno::Sequence< beans::PropertyValue > aAddProps( 2 );
1277 aAddProps[0].Name = ::rtl::OUString("RepairPackage");
1278 aAddProps[0].Value <<= (sal_Bool)sal_True;
1279 aAddProps[1].Name = ::rtl::OUString("StatusIndicator");
1280 aAddProps[1].Value <<= xProgressHandler;
1282 // the first arguments will be filled later
1283 aArgs.realloc( 3 );
1284 aArgs[2] <<= aAddProps;
1287 if ( pImp->xStream.is() )
1289 // since the storage is based on temporary stream we open it always read-write
1290 aArgs[0] <<= pImp->xStream;
1291 aArgs[1] <<= embed::ElementModes::READWRITE;
1292 pImp->bStorageBasedOnInStream = sal_True;
1294 else if ( pImp->xInputStream.is() )
1296 // since the storage is based on temporary stream we open it always read-write
1297 aArgs[0] <<= pImp->xInputStream;
1298 aArgs[1] <<= embed::ElementModes::READ;
1299 pImp->bStorageBasedOnInStream = sal_True;
1301 else
1303 CloseStreams_Impl();
1304 aArgs[0] <<= ::rtl::OUString( aName );
1305 aArgs[1] <<= embed::ElementModes::READ;
1306 pImp->bStorageBasedOnInStream = sal_False;
1311 pImp->xStorage = uno::Reference< embed::XStorage >(
1312 ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ),
1313 uno::UNO_QUERY );
1315 catch( const uno::Exception& )
1317 // impossibility to create the storage is no error
1320 if( ( pImp->nLastStorageError = GetError() ) != SVSTREAM_OK )
1322 pImp->xStorage = 0;
1323 if ( pInStream )
1324 pInStream->Seek(0);
1325 return uno::Reference< embed::XStorage >();
1328 bTriedStorage = sal_True;
1330 // TODO/LATER: Get versionlist on demand
1331 if ( pImp->xStorage.is() )
1333 SetEncryptionDataToStorage_Impl();
1334 GetVersionList();
1337 SFX_ITEMSET_ARG( pSet, pVersion, SfxInt16Item, SID_VERSION, sal_False);
1339 sal_Bool bResetStorage = sal_False;
1340 if ( pVersion && pVersion->GetValue() )
1342 // Read all available versions
1343 if ( pImp->aVersions.getLength() )
1345 // Search for the version fits the comment
1346 // The versions are numbered startign with 1, versions with
1347 // negative versions numbers are counted backwards from the
1348 // current version
1349 short nVersion = pVersion ? pVersion->GetValue() : 0;
1350 if ( nVersion<0 )
1351 nVersion = ( (short) pImp->aVersions.getLength() ) + nVersion;
1352 else if ( nVersion )
1353 nVersion--;
1355 util::RevisionTag& rTag = pImp->aVersions[nVersion];
1357 // Open SubStorage for all versions
1358 uno::Reference < embed::XStorage > xSub = pImp->xStorage->openStorageElement( DEFINE_CONST_UNICODE( "Versions" ),
1359 embed::ElementModes::READ );
1361 DBG_ASSERT( xSub.is(), "Version list, but no Versions!" );
1363 // There the version is stored as packed Stream
1364 uno::Reference < io::XStream > xStr = xSub->openStreamElement( rTag.Identifier, embed::ElementModes::READ );
1365 SvStream* pStream = utl::UcbStreamHelper::CreateStream( xStr );
1366 if ( pStream && pStream->GetError() == SVSTREAM_OK )
1368 // Unpack Stream in TempDir
1369 ::utl::TempFile aTempFile;
1370 String aTmpName = aTempFile.GetURL();
1371 SvFileStream aTmpStream( aTmpName, SFX_STREAM_READWRITE );
1373 *pStream >> aTmpStream;
1374 aTmpStream.Close();
1376 // Open data as Storage
1377 nStorOpenMode = SFX_STREAM_READONLY;
1378 pImp->xStorage = comphelper::OStorageHelper::GetStorageFromURL( aTmpName, embed::ElementModes::READ );
1379 pImp->bStorageBasedOnInStream = sal_False;
1380 rtl::OUString aTemp;
1381 ::utl::LocalFileHelper::ConvertURLToPhysicalName( aTmpName, aTemp );
1382 SetPhysicalName_Impl( aTemp );
1384 pImp->bIsTemp = sal_True;
1385 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) );
1386 // TODO/MBA
1387 pImp->aVersions.realloc(0);
1389 else
1390 bResetStorage = sal_True;
1393 else
1394 bResetStorage = sal_True;
1397 if ( bResetStorage )
1399 pImp->xStorage = 0;
1400 if ( pInStream )
1401 pInStream->Seek( 0L );
1404 pImp->bIsStorage = pImp->xStorage.is();
1405 return pImp->xStorage;
1408 //------------------------------------------------------------------
1409 uno::Reference< embed::XStorage > SfxMedium::GetZipStorageToSign_Impl( sal_Bool bReadOnly )
1411 if ( !GetError() && !pImp->m_xZipStorage.is() )
1413 GetMedium_Impl();
1417 // we can not sign document if there is no stream
1418 // should it be possible at all?
1419 if ( !bReadOnly && pImp->xStream.is() )
1421 pImp->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImp->xStream, embed::ElementModes::READWRITE );
1423 else if ( pImp->xInputStream.is() )
1425 pImp->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( ZIP_STORAGE_FORMAT_STRING, pImp->xInputStream );
1428 catch( const uno::Exception& )
1430 OSL_FAIL( "No possibility to get readonly version of storage from medium!\n" );
1433 if ( GetError() ) // do not remove warnings
1434 ResetError();
1437 return pImp->m_xZipStorage;
1440 //------------------------------------------------------------------
1441 void SfxMedium::CloseZipStorage_Impl()
1443 if ( pImp->m_xZipStorage.is() )
1445 try {
1446 pImp->m_xZipStorage->dispose();
1447 } catch( const uno::Exception& )
1450 pImp->m_xZipStorage = uno::Reference< embed::XStorage >();
1454 //------------------------------------------------------------------
1455 void SfxMedium::CloseStorage()
1457 if ( pImp->xStorage.is() )
1459 uno::Reference < lang::XComponent > xComp( pImp->xStorage, uno::UNO_QUERY );
1460 // in the salvage mode the medium does not own the storage
1461 if ( pImp->bDisposeStorage && !pImp->m_bSalvageMode )
1463 try {
1464 xComp->dispose();
1465 } catch( const uno::Exception& )
1467 OSL_FAIL( "Medium's storage is already disposed!\n" );
1471 pImp->xStorage = 0;
1472 pImp->bStorageBasedOnInStream = sal_False;
1475 bTriedStorage = sal_False;
1476 pImp->bIsStorage = sal_False;
1479 void SfxMedium::CanDisposeStorage_Impl( sal_Bool bDisposeStorage )
1481 pImp->bDisposeStorage = bDisposeStorage;
1484 sal_Bool SfxMedium::WillDisposeStorageOnClose_Impl()
1486 return pImp->bDisposeStorage;
1489 //------------------------------------------------------------------
1490 void SfxMedium::SetOpenMode( StreamMode nStorOpen,
1491 sal_Bool bDontClose )
1493 if ( nStorOpenMode != nStorOpen )
1495 nStorOpenMode = nStorOpen;
1497 if( !bDontClose )
1499 if ( pImp->xStorage.is() )
1500 CloseStorage();
1502 CloseStreams_Impl();
1506 bSetFilter = sal_False;
1509 //------------------------------------------------------------------
1510 sal_Bool SfxMedium::UseBackupToRestore_Impl( ::ucbhelper::Content& aOriginalContent,
1511 const Reference< ::com::sun::star::ucb::XCommandEnvironment >& xComEnv )
1515 ::ucbhelper::Content aTransactCont( pImp->m_aBackupURL, xComEnv );
1517 Reference< XInputStream > aOrigInput = aTransactCont.openStream();
1518 aOriginalContent.writeStream( aOrigInput, sal_True );
1519 return sal_True;
1521 catch( const Exception& )
1523 // in case of failure here the backup file should not be removed
1524 // TODO/LATER: a message should be used to let user know about the backup
1525 pImp->m_bRemoveBackup = sal_False;
1526 // TODO/LATER: needs a specific error code
1527 eError = ERRCODE_IO_GENERAL;
1530 return sal_False;
1533 //------------------------------------------------------------------
1534 sal_Bool SfxMedium::StorageCommit_Impl()
1536 sal_Bool bResult = sal_False;
1537 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1538 ::ucbhelper::Content aOriginalContent;
1540 if ( pImp->xStorage.is() )
1542 if ( !GetError() )
1544 uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY );
1545 if ( xTrans.is() )
1549 xTrans->commit();
1550 CloseZipStorage_Impl();
1551 bResult = sal_True;
1553 catch ( const embed::UseBackupException& aBackupExc )
1555 // since the temporary file is created always now, the scenario is close to be impossible
1556 if ( !pImp->pTempFile )
1558 OSL_ENSURE( !pImp->m_aBackupURL.isEmpty(), "No backup on storage commit!\n" );
1559 if ( !pImp->m_aBackupURL.isEmpty()
1560 && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ),
1561 xDummyEnv,
1562 aOriginalContent ) )
1564 // use backup to restore the file
1565 // the storage has already disconnected from original location
1566 CloseAndReleaseStreams_Impl();
1567 if ( !UseBackupToRestore_Impl( aOriginalContent, xDummyEnv ) )
1569 // connect the medium to the temporary file of the storage
1570 pImp->aContent = ::ucbhelper::Content();
1571 aName = aBackupExc.TemporaryFileURL;
1572 OSL_ENSURE( !aName.isEmpty(), "The exception _must_ contain the temporary URL!\n" );
1576 if ( !GetError() )
1577 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1580 catch ( const uno::Exception& )
1582 //TODO/LATER: improve error handling
1583 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1589 return bResult;
1592 //------------------------------------------------------------------
1593 sal_Bool SfxMedium::TransactedTransferForFS_Impl( const INetURLObject& aSource,
1594 const INetURLObject& aDest,
1595 const Reference< ::com::sun::star::ucb::XCommandEnvironment >& xComEnv )
1597 sal_Bool bResult = sal_False;
1598 Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
1599 Reference< XOutputStream > aDestStream;
1600 ::ucbhelper::Content aOriginalContent;
1604 aOriginalContent = ::ucbhelper::Content( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv );
1606 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
1608 eError = ERRCODE_ABORT;
1610 catch ( const ::com::sun::star::ucb::CommandFailedException& )
1612 eError = ERRCODE_ABORT;
1614 catch (const ::com::sun::star::ucb::ContentCreationException& ex)
1616 eError = ERRCODE_IO_GENERAL;
1617 if (
1618 (ex.eError == ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
1619 (ex.eError == ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
1622 eError = ERRCODE_IO_NOTEXISTSPATH;
1625 catch (const ::com::sun::star::uno::Exception&)
1627 eError = ERRCODE_IO_GENERAL;
1630 if( !eError || (eError & ERRCODE_WARNING_MASK) )
1632 if ( pImp->xStorage.is() )
1633 CloseStorage();
1635 CloseStreams_Impl();
1637 ::ucbhelper::Content aTempCont;
1638 if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, aTempCont ) )
1640 sal_Bool bTransactStarted = sal_False;
1641 SFX_ITEMSET_ARG( GetItemSet(), pOverWrite, SfxBoolItem, SID_OVERWRITE, sal_False );
1642 SFX_ITEMSET_ARG( GetItemSet(), pRename, SfxBoolItem, SID_RENAME, sal_False );
1643 sal_Bool bRename = pRename ? pRename->GetValue() : sal_False;
1644 sal_Bool bOverWrite = pOverWrite ? pOverWrite->GetValue() : !bRename;
1648 if( bOverWrite && ::utl::UCBContentHelper::IsDocument( aDest.GetMainURL( INetURLObject::NO_DECODE ) ) )
1650 if( pImp->m_aBackupURL.isEmpty() )
1651 DoInternalBackup_Impl( aOriginalContent );
1653 if( !pImp->m_aBackupURL.isEmpty() )
1655 Reference< XInputStream > aTempInput = aTempCont.openStream();
1656 bTransactStarted = sal_True;
1657 aOriginalContent.setPropertyValue( ::rtl::OUString("Size"),
1658 uno::makeAny( (sal_Int64)0 ) );
1659 aOriginalContent.writeStream( aTempInput, bOverWrite );
1660 bResult = sal_True;
1662 else
1664 eError = ERRCODE_SFX_CANTCREATEBACKUP;
1667 else
1669 Reference< XInputStream > aTempInput = aTempCont.openStream();
1670 aOriginalContent.writeStream( aTempInput, bOverWrite );
1671 bResult = sal_True;
1674 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
1676 eError = ERRCODE_ABORT;
1678 catch ( const ::com::sun::star::ucb::CommandFailedException& )
1680 eError = ERRCODE_ABORT;
1682 catch ( const ::com::sun::star::ucb::InteractiveIOException& r )
1684 if ( r.Code == IOErrorCode_ACCESS_DENIED )
1685 eError = ERRCODE_IO_ACCESSDENIED;
1686 else if ( r.Code == IOErrorCode_NOT_EXISTING )
1687 eError = ERRCODE_IO_NOTEXISTS;
1688 else if ( r.Code == IOErrorCode_CANT_READ )
1689 eError = ERRCODE_IO_CANTREAD;
1690 else
1691 eError = ERRCODE_IO_GENERAL;
1693 catch ( const ::com::sun::star::uno::Exception& )
1695 eError = ERRCODE_IO_GENERAL;
1698 if ( bResult )
1700 if ( pImp->pTempFile )
1702 pImp->pTempFile->EnableKillingFile( sal_True );
1703 delete pImp->pTempFile;
1704 pImp->pTempFile = NULL;
1707 else if ( bTransactStarted )
1709 UseBackupToRestore_Impl( aOriginalContent, xDummyEnv );
1712 else
1713 eError = ERRCODE_IO_CANTREAD;
1716 return bResult;
1719 //------------------------------------------------------------------
1720 sal_Bool SfxMedium::TryDirectTransfer( const ::rtl::OUString& aURL, SfxItemSet& aTargetSet )
1722 if ( GetError() )
1723 return sal_False;
1725 // if the document had no password it should be stored without password
1726 // if the document had password it should be stored with the same password
1727 // otherwise the stream copying can not be done
1728 SFX_ITEMSET_ARG( &aTargetSet, pNewPassItem, SfxStringItem, SID_PASSWORD, sal_False );
1729 SFX_ITEMSET_ARG( GetItemSet(), pOldPassItem, SfxStringItem, SID_PASSWORD, sal_False );
1730 if ( ( !pNewPassItem && !pOldPassItem )
1731 || ( pNewPassItem && pOldPassItem && pNewPassItem->GetValue().Equals( pOldPassItem->GetValue() ) ) )
1733 // the filter must be the same
1734 SFX_ITEMSET_ARG( &aTargetSet, pNewFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False );
1735 SFX_ITEMSET_ARG( GetItemSet(), pOldFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False );
1736 if ( pNewFilterItem && pOldFilterItem && pNewFilterItem->GetValue().Equals( pOldFilterItem->GetValue() ) )
1738 // get the input stream and copy it
1739 // in case of success return true
1740 uno::Reference< io::XInputStream > xInStream = GetInputStream();
1742 ResetError();
1743 if ( xInStream.is() )
1747 uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
1748 sal_Int64 nPos = 0;
1749 if ( xSeek.is() )
1751 nPos = xSeek->getPosition();
1752 xSeek->seek( 0 );
1755 uno::Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
1756 ::ucbhelper::Content aTargetContent( aURL, xEnv );
1758 InsertCommandArgument aInsertArg;
1759 aInsertArg.Data = xInStream;
1760 SFX_ITEMSET_ARG( &aTargetSet, pRename, SfxBoolItem, SID_RENAME, sal_False );
1761 SFX_ITEMSET_ARG( &aTargetSet, pOverWrite, SfxBoolItem, SID_OVERWRITE, sal_False );
1762 if ( (pOverWrite && !pOverWrite->GetValue()) // argument says: never overwrite
1763 || (pRename && pRename->GetValue()) ) // argument says: rename file
1764 aInsertArg.ReplaceExisting = sal_False;
1765 else
1766 aInsertArg.ReplaceExisting = sal_True; // default is overwrite existing files
1768 Any aCmdArg;
1769 aCmdArg <<= aInsertArg;
1770 aTargetContent.executeCommand( ::rtl::OUString( "insert" ),
1771 aCmdArg );
1773 if ( xSeek.is() )
1774 xSeek->seek( nPos );
1776 return sal_True;
1778 catch( const uno::Exception& )
1784 return sal_False;
1787 //------------------------------------------------------------------
1788 void SfxMedium::Transfer_Impl()
1790 // The transfer is required only in two cases: either if there is a temporary file or if there is a salvage item
1791 rtl::OUString aNameURL;
1792 if ( pImp->pTempFile )
1793 aNameURL = pImp->pTempFile->GetURL();
1794 else if ( aLogicName.Len() && pImp->m_bSalvageMode )
1796 // makes sence only in case logic name is set
1797 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aNameURL ) )
1798 OSL_FAIL( "The medium name is not convertable!\n" );
1801 if ( !aNameURL.isEmpty() && ( !eError || (eError & ERRCODE_WARNING_MASK) ) )
1803 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::Transfer_Impl, copying to target" );
1805 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
1806 Reference< XOutputStream > rOutStream;
1808 // in case an output stream is provided from outside and the URL is correct
1809 // commit to the stream
1810 if( aLogicName.CompareToAscii( "private:stream", 14 ) == COMPARE_EQUAL )
1812 // TODO/LATER: support storing to SID_STREAM
1813 SFX_ITEMSET_ARG( pSet, pOutStreamItem, SfxUnoAnyItem, SID_OUTPUTSTREAM, sal_False);
1814 if( pOutStreamItem && ( pOutStreamItem->GetValue() >>= rOutStream ) )
1816 if ( pImp->xStorage.is() )
1817 CloseStorage();
1819 CloseStreams_Impl();
1821 INetURLObject aSource( aNameURL );
1822 ::ucbhelper::Content aTempCont;
1823 if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aTempCont ) )
1827 sal_Int32 nRead;
1828 sal_Int32 nBufferSize = 32767;
1829 Sequence < sal_Int8 > aSequence ( nBufferSize );
1830 Reference< XInputStream > aTempInput = aTempCont.openStream();
1834 nRead = aTempInput->readBytes ( aSequence, nBufferSize );
1835 if ( nRead < nBufferSize )
1837 Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead );
1838 rOutStream->writeBytes ( aTempBuf );
1840 else
1841 rOutStream->writeBytes ( aSequence );
1843 while ( nRead == nBufferSize );
1845 // remove temporary file
1846 if ( pImp->pTempFile )
1848 pImp->pTempFile->EnableKillingFile( sal_True );
1849 delete pImp->pTempFile;
1850 pImp->pTempFile = NULL;
1853 catch( const Exception& )
1857 else
1859 OSL_FAIL( "Illegal Output stream parameter!\n" );
1860 SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( OSL_LOG_PREFIX ) );
1863 // free the reference
1864 if ( pSet )
1865 pSet->ClearItem( SID_OUTPUTSTREAM );
1867 return;
1870 GetContent();
1871 if ( !pImp->aContent.get().is() )
1873 eError = ERRCODE_IO_NOTEXISTS;
1874 return;
1877 SFX_ITEMSET_ARG( GetItemSet(), pSegmentSize, SfxInt32Item, SID_SEGMENTSIZE, sal_False);
1878 if ( pSegmentSize )
1880 // this file must be stored into a disk spanned package
1883 uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetStorageFromURL( GetName(),
1884 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
1886 // set segment size property; package will automatically be divided in pieces fitting
1887 // into this size
1888 ::com::sun::star::uno::Any aAny;
1889 aAny <<= pSegmentSize->GetValue();
1891 uno::Reference < beans::XPropertySet > xSet( pImp->xStorage, uno::UNO_QUERY );
1892 xSet->setPropertyValue( String::CreateFromAscii("SegmentSize"), aAny );
1894 // copy the temporary storage into the disk spanned package
1895 GetStorage()->copyToStorage( xStor );
1896 uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY );
1897 if ( xTrans.is() )
1898 xTrans->commit();
1901 catch ( const uno::Exception& )
1903 //TODO/MBA: error handling
1905 return;
1908 INetURLObject aDest( GetURLObject() );
1910 // source is the temp file written so far
1911 INetURLObject aSource( aNameURL );
1913 // a special case, an interaction handler should be used for
1914 // authentication in case it is available
1915 Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
1916 Reference< ::com::sun::star::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
1917 if (xInteractionHandler.is())
1918 xComEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler,
1919 Reference< ::com::sun::star::ucb::XProgressHandler >() );
1921 rtl::OUString aDestURL( aDest.GetMainURL( INetURLObject::NO_DECODE ) );
1923 if ( ::utl::LocalFileHelper::IsLocalFile( aDestURL ) || !aDest.removeSegment() )
1925 TransactedTransferForFS_Impl( aSource, aDest, xComEnv );
1927 // Hideous - no clean way to do this, so we re-open the file just to fsync it
1928 osl::File aFile( aDestURL );
1929 if ( aFile.open( osl_File_OpenFlag_Write ) == osl::FileBase::E_None )
1931 aFile.sync();
1932 OSL_TRACE("fsync'd saved file '%s'\n",
1933 rtl::OUStringToOString( aDestURL, RTL_TEXTENCODING_UTF8 ).getStr() );
1934 aFile.close();
1937 else
1939 // create content for the parent folder and call transfer on that content with the source content
1940 // and the destination file name as parameters
1941 ::ucbhelper::Content aSourceContent;
1942 ::ucbhelper::Content aTransferContent;
1944 // Get the parent URL from the XChild if possible: why would the URL necessarily have
1945 // a hierarchical path? It's not the case for CMIS.
1946 ::ucbhelper::Content aDestContent;
1947 ::ucbhelper::Content::create( aDestURL, xComEnv, aDestContent );
1948 Reference< ::com::sun::star::container::XChild> xChild( aDestContent.get(), uno::UNO_QUERY );
1949 rtl::OUString sParentUrl;
1950 if ( xChild.is( ) )
1952 Reference< ::com::sun::star::ucb::XContent > xParent( xChild->getParent( ), uno::UNO_QUERY );
1953 if ( xParent.is( ) )
1955 sParentUrl = xParent->getIdentifier( )->getContentIdentifier();
1959 if ( !sParentUrl.isEmpty() )
1960 aDest = INetURLObject( sParentUrl );
1962 // LongName wasn't defined anywhere, only used here... get the Title instead
1963 // as it's less probably empty
1964 rtl::OUString aFileName;
1965 Any aAny = aDestContent.getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Title" )) );
1966 aAny >>= aFileName;
1967 if ( aFileName.isEmpty() )
1968 aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
1972 aTransferContent = ::ucbhelper::Content( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv );
1974 catch (const ::com::sun::star::ucb::ContentCreationException& ex)
1976 eError = ERRCODE_IO_GENERAL;
1977 if (
1978 (ex.eError == ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
1979 (ex.eError == ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
1982 eError = ERRCODE_IO_NOTEXISTSPATH;
1985 catch (const ::com::sun::star::uno::Exception&)
1987 eError = ERRCODE_IO_GENERAL;
1990 if ( !eError || (eError & ERRCODE_WARNING_MASK) )
1992 // free resources, otherwise the transfer may fail
1993 if ( pImp->xStorage.is() )
1994 CloseStorage();
1996 CloseStreams_Impl();
1998 ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aSourceContent );
2000 // check for external parameters that may customize the handling of NameClash situations
2001 SFX_ITEMSET_ARG( GetItemSet(), pRename, SfxBoolItem, SID_RENAME, sal_False );
2002 SFX_ITEMSET_ARG( GetItemSet(), pOverWrite, SfxBoolItem, SID_OVERWRITE, sal_False );
2003 sal_Int32 nNameClash;
2004 if ( pOverWrite && !pOverWrite->GetValue() )
2005 // argument says: never overwrite
2006 nNameClash = NameClash::ERROR;
2007 else if ( pRename && pRename->GetValue() )
2008 // argument says: rename file
2009 nNameClash = NameClash::RENAME;
2010 else
2011 // default is overwrite existing files
2012 nNameClash = NameClash::OVERWRITE;
2016 if (!aTransferContent.transferContent( aSourceContent, ::ucbhelper::InsertOperation_COPY, aFileName, nNameClash ))
2017 eError = ERRCODE_IO_GENERAL;
2019 catch ( const ::com::sun::star::ucb::CommandAbortedException& )
2021 eError = ERRCODE_ABORT;
2023 catch ( const ::com::sun::star::ucb::CommandFailedException& )
2025 eError = ERRCODE_ABORT;
2027 catch ( const ::com::sun::star::ucb::InteractiveIOException& r )
2029 if ( r.Code == IOErrorCode_ACCESS_DENIED )
2030 eError = ERRCODE_IO_ACCESSDENIED;
2031 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2032 eError = ERRCODE_IO_NOTEXISTS;
2033 else if ( r.Code == IOErrorCode_CANT_READ )
2034 eError = ERRCODE_IO_CANTREAD;
2035 else
2036 eError = ERRCODE_IO_GENERAL;
2038 catch ( const ::com::sun::star::uno::Exception& )
2040 eError = ERRCODE_IO_GENERAL;
2043 // do not switch from temporary file in case of nonfile protocol
2047 if ( ( !eError || (eError & ERRCODE_WARNING_MASK) ) && !pImp->pTempFile )
2049 // without a TempFile the physical and logical name should be the same after successful transfer
2050 ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ),
2051 aName );
2052 pImp->m_bSalvageMode = sal_False;
2057 //------------------------------------------------------------------
2058 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent,
2059 const String& aPrefix,
2060 const String& aExtension,
2061 const String& aDestDir )
2063 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::DoInternalBackup_Impl( with destdir )" );
2065 if ( !pImp->m_aBackupURL.isEmpty() )
2066 return; // the backup was done already
2068 ::utl::TempFile aTransactTemp( aPrefix, &aExtension, &aDestDir );
2069 aTransactTemp.EnableKillingFile( sal_False );
2071 INetURLObject aBackObj( aTransactTemp.GetURL() );
2072 ::rtl::OUString aBackupName = aBackObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2074 Reference < ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
2075 ::ucbhelper::Content aBackupCont;
2076 if( ::ucbhelper::Content::create( aDestDir, xDummyEnv, aBackupCont ) )
2080 if( aBackupCont.transferContent( aOriginalContent,
2081 ::ucbhelper::InsertOperation_COPY,
2082 aBackupName,
2083 NameClash::OVERWRITE ) )
2085 pImp->m_aBackupURL = aBackObj.GetMainURL( INetURLObject::NO_DECODE );
2086 pImp->m_bRemoveBackup = sal_True;
2089 catch( const Exception& )
2093 if ( pImp->m_aBackupURL.isEmpty() )
2094 aTransactTemp.EnableKillingFile( sal_True );
2097 //------------------------------------------------------------------
2098 void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent )
2100 if ( !pImp->m_aBackupURL.isEmpty() )
2101 return; // the backup was done already
2103 ::rtl::OUString aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT,
2104 true,
2105 INetURLObject::NO_DECODE );
2107 sal_Int32 nPrefixLen = aFileName.lastIndexOf( '.' );
2108 String aPrefix = ( nPrefixLen == -1 ) ? aFileName : aFileName.copy( 0, nPrefixLen );
2109 String aExtension = ( nPrefixLen == -1 ) ? String() : String(aFileName.copy( nPrefixLen ));
2110 String aBakDir = SvtPathOptions().GetBackupPath();
2112 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aBakDir );
2114 if ( pImp->m_aBackupURL.isEmpty() )
2116 // the copiing to the backup catalog failed ( for example because
2117 // of using an encrypted partition as target catalog )
2118 // since the user did not specify to make backup explicitly
2119 // office should try to make backup in another place,
2120 // target catalog does not look bad for this case ( and looks
2121 // to be the only way for encrypted partitions )
2123 INetURLObject aDest = GetURLObject();
2124 if ( aDest.removeSegment() )
2125 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aDest.GetMainURL( INetURLObject::NO_DECODE ) );
2130 //------------------------------------------------------------------
2131 void SfxMedium::DoBackup_Impl()
2133 RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::DoBackup_Impl" );
2135 // source file name is the logical name of this medium
2136 INetURLObject aSource( GetURLObject() );
2138 // there is nothing to backup in case source file does not exist
2139 if ( !::utl::UCBContentHelper::IsDocument( aSource.GetMainURL( INetURLObject::NO_DECODE ) ) )
2140 return;
2142 sal_Bool bSuccess = sal_False;
2144 // get path for backups
2145 String aBakDir = SvtPathOptions().GetBackupPath();
2146 if( aBakDir.Len() )
2148 // create content for the parent folder ( = backup folder )
2149 ::ucbhelper::Content aContent;
2150 Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv;
2151 if( ::ucbhelper::Content::create( aBakDir, xEnv, aContent ) )
2153 // save as ".bak" file
2154 INetURLObject aDest( aBakDir );
2155 aDest.insertName( aSource.getName() );
2156 aDest.setExtension( DEFINE_CONST_UNICODE( "bak" ) );
2157 String aFileName = aDest.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
2159 // create a content for the source file
2160 ::ucbhelper::Content aSourceContent;
2161 if ( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aSourceContent ) )
2165 // do the transfer ( copy source file to backup dir )
2166 bSuccess = aContent.transferContent( aSourceContent,
2167 ::ucbhelper::InsertOperation_COPY,
2168 aFileName,
2169 NameClash::OVERWRITE );
2170 if( bSuccess )
2172 pImp->m_aBackupURL = aDest.GetMainURL( INetURLObject::NO_DECODE );
2173 pImp->m_bRemoveBackup = sal_False;
2176 catch ( const ::com::sun::star::uno::Exception& )
2183 if ( !bSuccess )
2185 eError = ERRCODE_SFX_CANTCREATEBACKUP;
2189 //------------------------------------------------------------------
2190 void SfxMedium::ClearBackup_Impl()
2192 if( pImp->m_bRemoveBackup )
2194 // currently a document is always stored in a new medium,
2195 // thus if a backup can not be removed the backup URL should not be cleaned
2196 if ( !pImp->m_aBackupURL.isEmpty() )
2198 if ( ::utl::UCBContentHelper::Kill( pImp->m_aBackupURL ) )
2200 pImp->m_bRemoveBackup = sal_False;
2201 pImp->m_aBackupURL = ::rtl::OUString();
2203 else
2206 OSL_FAIL("Couldn't remove backup file!");
2210 else
2211 pImp->m_aBackupURL = ::rtl::OUString();
2214 //----------------------------------------------------------------
2215 void SfxMedium::GetLockingStream_Impl()
2217 if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
2218 && !pImp->m_xLockingStream.is() )
2220 SFX_ITEMSET_ARG( pSet, pWriteStreamItem, SfxUnoAnyItem, SID_STREAM, sal_False);
2221 if ( pWriteStreamItem )
2222 pWriteStreamItem->GetValue() >>= pImp->m_xLockingStream;
2224 if ( !pImp->m_xLockingStream.is() )
2226 // open the original document
2227 uno::Sequence< beans::PropertyValue > xProps;
2228 TransformItems( SID_OPENDOC, *GetItemSet(), xProps );
2229 comphelper::MediaDescriptor aMedium( xProps );
2231 aMedium.addInputStreamOwnLock();
2233 uno::Reference< io::XInputStream > xInputStream;
2234 aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= pImp->m_xLockingStream;
2235 aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream;
2237 if ( !pImp->pTempFile && aName.isEmpty() )
2239 // the medium is still based on the original file, it makes sence to initialize the streams
2240 if ( pImp->m_xLockingStream.is() )
2241 pImp->xStream = pImp->m_xLockingStream;
2243 if ( xInputStream.is() )
2244 pImp->xInputStream = xInputStream;
2246 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2247 pImp->xInputStream = pImp->xStream->getInputStream();
2253 //----------------------------------------------------------------
2254 void SfxMedium::GetMedium_Impl()
2256 if ( !pInStream )
2258 pImp->bDownloadDone = sal_False;
2259 Reference< ::com::sun::star::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
2261 //TODO/MBA: need support for SID_STREAM
2262 SFX_ITEMSET_ARG( pSet, pWriteStreamItem, SfxUnoAnyItem, SID_STREAM, sal_False);
2263 SFX_ITEMSET_ARG( pSet, pInStreamItem, SfxUnoAnyItem, SID_INPUTSTREAM, sal_False);
2264 if ( pWriteStreamItem )
2266 pWriteStreamItem->GetValue() >>= pImp->xStream;
2268 if ( pInStreamItem )
2269 pInStreamItem->GetValue() >>= pImp->xInputStream;
2271 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2272 pImp->xInputStream = pImp->xStream->getInputStream();
2274 else if ( pInStreamItem )
2276 pInStreamItem->GetValue() >>= pImp->xInputStream;
2278 else
2280 uno::Sequence < beans::PropertyValue > xProps;
2281 rtl::OUString aFileName;
2282 if (!aName.isEmpty())
2284 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aFileName ) )
2286 OSL_FAIL("Physical name not convertable!");
2289 else
2290 aFileName = GetName();
2292 // in case the temporary file exists the streams should be initialized from it,
2293 // but the original MediaDescriptor should not be changed
2294 sal_Bool bFromTempFile = ( pImp->pTempFile != NULL );
2296 if ( !bFromTempFile )
2298 GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, aFileName ) );
2299 if( !(nStorOpenMode & STREAM_WRITE ) )
2300 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) );
2301 if (xInteractionHandler.is())
2302 GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny(xInteractionHandler) ) );
2305 if ( m_xInputStreamToLoadFrom.is() )
2307 pImp->xInputStream = m_xInputStreamToLoadFrom;
2308 pImp->xInputStream->skipBytes(0);
2309 if(m_bInputStreamIsReadOnly)
2310 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) );
2312 else
2314 TransformItems( SID_OPENDOC, *GetItemSet(), xProps );
2315 comphelper::MediaDescriptor aMedium( xProps );
2317 if ( pImp->m_xLockingStream.is() && !bFromTempFile )
2319 // the medium is not based on the temporary file, so the original stream can be used
2320 pImp->xStream = pImp->m_xLockingStream;
2322 else
2324 if ( bFromTempFile )
2326 aMedium[comphelper::MediaDescriptor::PROP_URL()] <<= ::rtl::OUString( aFileName );
2327 aMedium.erase( comphelper::MediaDescriptor::PROP_READONLY() );
2328 aMedium.addInputStream();
2330 else if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
2332 // use the special locking approach only for file URLs
2333 aMedium.addInputStreamOwnLock();
2335 else
2336 aMedium.addInputStream();
2338 // the ReadOnly property set in aMedium is ignored
2339 // the check is done in LockOrigFileOnDemand() for file and non-file URLs
2341 //TODO/MBA: what happens if property is not there?!
2342 aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= pImp->xStream;
2343 aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= pImp->xInputStream;
2346 GetContent();
2347 if ( !pImp->xInputStream.is() && pImp->xStream.is() )
2348 pImp->xInputStream = pImp->xStream->getInputStream();
2351 if ( !bFromTempFile )
2353 //TODO/MBA: need support for SID_STREAM
2354 if ( pImp->xStream.is() )
2355 GetItemSet()->Put( SfxUsrAnyItem( SID_STREAM, makeAny( pImp->xStream ) ) );
2357 GetItemSet()->Put( SfxUsrAnyItem( SID_INPUTSTREAM, makeAny( pImp->xInputStream ) ) );
2361 //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor
2362 if ( !GetError() && !pImp->xStream.is() && !pImp->xInputStream.is() )
2363 SetError( ERRCODE_IO_ACCESSDENIED, ::rtl::OUString( OSL_LOG_PREFIX ) );
2365 if ( !GetError() )
2367 if ( pImp->xStream.is() )
2368 pInStream = utl::UcbStreamHelper::CreateStream( pImp->xStream );
2369 else if ( pImp->xInputStream.is() )
2370 pInStream = utl::UcbStreamHelper::CreateStream( pImp->xInputStream );
2373 pImp->bDownloadDone = sal_True;
2374 pImp->aDoneLink.ClearPendingCall();
2375 sal_uIntPtr nError = GetError();
2376 pImp->aDoneLink.Call( (void*)nError );
2380 //----------------------------------------------------------------
2381 sal_Bool SfxMedium::IsRemote()
2383 return bRemote;
2386 //------------------------------------------------------------------
2388 void SfxMedium::SetUpdatePickList(sal_Bool bVal)
2390 if(!pImp)
2391 pImp = new SfxMedium_Impl( this );
2392 pImp->bUpdatePickList = bVal;
2394 //------------------------------------------------------------------
2396 sal_Bool SfxMedium::IsUpdatePickList() const
2398 return pImp? pImp->bUpdatePickList: sal_True;
2400 //----------------------------------------------------------------
2402 void SfxMedium::SetDoneLink( const Link& rLink )
2404 pImp->aDoneLink = rLink;
2407 //----------------------------------------------------------------
2409 void SfxMedium::SetDataAvailableLink( const Link& rLink )
2411 pImp->aAvailableLink = rLink;
2414 void SfxMedium::DownLoad( const Link& aLink )
2416 SetDoneLink( aLink );
2417 GetInStream();
2418 if ( pInStream && !aLink.IsSet() )
2420 while( !pImp->bDownloadDone )
2421 Application::Yield();
2425 //------------------------------------------------------------------
2426 void SfxMedium::Init_Impl()
2427 /* [Description]
2428 Includes a valid:: sun:: com:: star:: util:: URL (If a file name was
2429 previously in there) in the logical name and if available sets the
2430 physical name as the file name.
2434 Reference< XOutputStream > rOutStream;
2436 // TODO/LATER: handle lifetime of storages
2437 pImp->bDisposeStorage = sal_False;
2439 SFX_ITEMSET_ARG( pSet, pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
2440 if ( pSalvageItem && !pSalvageItem->GetValue().Len() )
2442 pSalvageItem = NULL;
2443 pSet->ClearItem( SID_DOC_SALVAGE );
2446 if( aLogicName.Len() )
2448 INetURLObject aUrl( aLogicName );
2449 INetProtocol eProt = aUrl.GetProtocol();
2450 if ( eProt == INET_PROT_NOT_VALID )
2452 OSL_FAIL( "Unknown protocol!" );
2454 else
2456 if ( aUrl.HasMark() )
2458 aLogicName = aUrl.GetURLNoMark( INetURLObject::NO_DECODE );
2459 GetItemSet()->Put( SfxStringItem( SID_JUMPMARK, aUrl.GetMark() ) );
2462 // try to convert the URL into a physical name - but never change a physical name
2463 // physical name may be set if the logical name is changed after construction
2464 if ( aName.isEmpty() )
2465 ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), aName );
2466 else
2468 DBG_ASSERT( pSalvageItem, "Suspicious change of logical name!" );
2473 if ( pSalvageItem && pSalvageItem->GetValue().Len() )
2475 aLogicName = pSalvageItem->GetValue();
2476 DELETEZ( pURLObj );
2477 pImp->m_bSalvageMode = sal_True;
2480 // in case output stream is by mistake here
2481 // clear the reference
2482 SFX_ITEMSET_ARG( pSet, pOutStreamItem, SfxUnoAnyItem, SID_OUTPUTSTREAM, sal_False);
2483 if( pOutStreamItem
2484 && ( !( pOutStreamItem->GetValue() >>= rOutStream )
2485 || !aLogicName.CompareToAscii( "private:stream", 14 ) == COMPARE_EQUAL ) )
2487 pSet->ClearItem( SID_OUTPUTSTREAM );
2488 OSL_FAIL( "Unexpected Output stream parameter!\n" );
2491 if ( aLogicName.Len() )
2493 // if the logic name is set it should be set in MediaDescriptor as well
2494 SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, sal_False );
2495 if ( !pFileNameItem )
2497 // let the ItemSet be created if necessary
2498 GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, INetURLObject( aLogicName ).GetMainURL( INetURLObject::NO_DECODE ) ) );
2502 SetIsRemote_Impl();
2505 //------------------------------------------------------------------
2506 SfxMedium::SfxMedium()
2507 : IMPL_CTOR( sal_False, 0 ), // bRoot, pURLObj
2509 pFilter(0),
2510 pSet(0),
2511 pImp(new SfxMedium_Impl( this ))
2513 Init_Impl();
2516 //------------------------------------------------------------------
2518 void SfxMedium::UseInteractionHandler( sal_Bool bUse )
2520 pImp->bAllowDefaultIntHdl = bUse;
2523 //------------------------------------------------------------------
2525 ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >
2526 SfxMedium::GetInteractionHandler()
2528 // if interaction isnt allowed explicitly ... return empty reference!
2529 if ( !pImp->bUseInteractionHandler )
2530 return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
2532 // search a possible existing handler inside cached item set
2533 if ( pSet )
2535 ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > xHandler;
2536 SFX_ITEMSET_ARG( pSet, pHandler, SfxUnoAnyItem, SID_INTERACTIONHANDLER, sal_False);
2537 if ( pHandler && (pHandler->GetValue() >>= xHandler) && xHandler.is() )
2538 return xHandler;
2541 // if default interaction isnt allowed explicitly ... return empty reference!
2542 if ( !pImp->bAllowDefaultIntHdl )
2543 return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
2545 // otherwhise return cached default handler ... if it exist.
2546 if ( pImp->xInteraction.is() )
2547 return pImp->xInteraction;
2549 // create default handler and cache it!
2550 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
2551 if ( xFactory.is() )
2553 pImp->xInteraction = ::com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler >( xFactory->createInstance( DEFINE_CONST_UNICODE("com.sun.star.task.InteractionHandler") ), ::com::sun::star::uno::UNO_QUERY );
2554 return pImp->xInteraction;
2557 return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
2560 //----------------------------------------------------------------
2562 void SfxMedium::SetFilter( const SfxFilter* pFilterP, sal_Bool /*bResetOrig*/ )
2564 pFilter = pFilterP;
2565 pImp->nFileVersion = 0;
2568 //----------------------------------------------------------------
2570 const SfxFilter* SfxMedium::GetOrigFilter( sal_Bool bNotCurrent ) const
2572 return ( pImp->pOrigFilter || bNotCurrent ) ? pImp->pOrigFilter : pFilter;
2575 //----------------------------------------------------------------
2577 sal_uInt32 SfxMedium::CreatePasswordToModifyHash( const ::rtl::OUString& aPasswd, sal_Bool bWriter )
2579 sal_uInt32 nHash = 0;
2581 if ( !aPasswd.isEmpty() )
2583 if ( bWriter )
2585 nHash = ::comphelper::DocPasswordHelper::GetWordHashAsUINT32( aPasswd );
2587 else
2589 rtl_TextEncoding nEncoding = RTL_TEXTENCODING_UTF8;
2591 // if the MS-filter should be used
2592 // use the inconsistent algorithm to find the encoding specified by MS
2593 nEncoding = osl_getThreadTextEncoding();
2594 switch( nEncoding )
2596 case RTL_TEXTENCODING_ISO_8859_15:
2597 case RTL_TEXTENCODING_MS_874:
2598 case RTL_TEXTENCODING_MS_1250:
2599 case RTL_TEXTENCODING_MS_1251:
2600 case RTL_TEXTENCODING_MS_1252:
2601 case RTL_TEXTENCODING_MS_1253:
2602 case RTL_TEXTENCODING_MS_1254:
2603 case RTL_TEXTENCODING_MS_1255:
2604 case RTL_TEXTENCODING_MS_1256:
2605 case RTL_TEXTENCODING_MS_1257:
2606 case RTL_TEXTENCODING_MS_1258:
2607 case RTL_TEXTENCODING_SHIFT_JIS:
2608 case RTL_TEXTENCODING_GB_2312:
2609 case RTL_TEXTENCODING_BIG5:
2610 // in case the system uses an encoding from the list above, it should be used
2611 break;
2613 default:
2614 // in case other encoding is used, use one of the encodings from the list
2615 nEncoding = RTL_TEXTENCODING_MS_1250;
2616 break;
2619 nHash = ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd, nEncoding );
2623 return nHash;
2626 //------------------------------------------------------------------
2628 void SfxMedium::Close()
2630 if ( pImp->xStorage.is() )
2632 CloseStorage();
2635 CloseStreams_Impl();
2637 UnlockFile( sal_False );
2640 void SfxMedium::CloseAndRelease()
2642 if ( pImp->xStorage.is() )
2644 CloseStorage();
2647 CloseAndReleaseStreams_Impl();
2649 UnlockFile( sal_True );
2652 void SfxMedium::UnlockFile( sal_Bool bReleaseLockStream )
2654 if ( pImp->m_xLockingStream.is() )
2656 if ( bReleaseLockStream )
2660 uno::Reference< io::XInputStream > xInStream = pImp->m_xLockingStream->getInputStream();
2661 uno::Reference< io::XOutputStream > xOutStream = pImp->m_xLockingStream->getOutputStream();
2662 if ( xInStream.is() )
2663 xInStream->closeInput();
2664 if ( xOutStream.is() )
2665 xOutStream->closeOutput();
2667 catch( const uno::Exception& )
2671 pImp->m_xLockingStream = uno::Reference< io::XStream >();
2674 if ( pImp->m_bLocked )
2678 pImp->m_bLocked = sal_False;
2679 ::svt::DocumentLockFile aLockFile( aLogicName );
2680 // TODO/LATER: A warning could be shown in case the file is not the own one
2681 aLockFile.RemoveFile();
2683 catch( const uno::Exception& )
2688 void SfxMedium::CloseAndReleaseStreams_Impl()
2690 CloseZipStorage_Impl();
2692 uno::Reference< io::XInputStream > xInToClose = pImp->xInputStream;
2693 uno::Reference< io::XOutputStream > xOutToClose;
2694 if ( pImp->xStream.is() )
2696 xOutToClose = pImp->xStream->getOutputStream();
2698 // if the locking stream is closed here the related member should be cleaned
2699 if ( pImp->xStream == pImp->m_xLockingStream )
2700 pImp->m_xLockingStream = uno::Reference< io::XStream >();
2703 // The probably exsisting SvStream wrappers should be closed first
2704 CloseStreams_Impl();
2706 // in case of salvage mode the storage is based on the streams
2707 if ( !pImp->m_bSalvageMode )
2711 if ( xInToClose.is() )
2712 xInToClose->closeInput();
2713 if ( xOutToClose.is() )
2714 xOutToClose->closeOutput();
2716 catch ( const uno::Exception& )
2722 //------------------------------------------------------------------
2723 void SfxMedium::CloseStreams_Impl()
2725 CloseInStream_Impl();
2726 CloseOutStream_Impl();
2728 if ( pSet )
2729 pSet->ClearItem( SID_CONTENT );
2731 pImp->aContent = ::ucbhelper::Content();
2734 //------------------------------------------------------------------
2736 void SfxMedium::SetIsRemote_Impl()
2738 INetURLObject aObj( GetName() );
2739 switch( aObj.GetProtocol() )
2741 case INET_PROT_FTP:
2742 case INET_PROT_HTTP:
2743 case INET_PROT_HTTPS:
2744 case INET_PROT_POP3:
2745 case INET_PROT_NEWS:
2746 case INET_PROT_IMAP:
2747 case INET_PROT_VIM:
2748 bRemote = sal_True; break;
2749 default:
2750 bRemote = ( GetName().CompareToAscii( "private:msgid", 13 ) == COMPARE_EQUAL );
2751 break;
2754 // As files that are written to the remote transmission must also be able
2755 // to be read.
2756 if( bRemote )
2757 nStorOpenMode |= STREAM_READ;
2762 void SfxMedium::SetName( const String& aNameP, sal_Bool bSetOrigURL )
2764 if( !pImp->aOrigURL.Len() )
2765 pImp->aOrigURL = aLogicName;
2766 if( bSetOrigURL )
2767 pImp->aOrigURL = aNameP;
2768 aLogicName = aNameP;
2769 DELETEZ( pURLObj );
2770 pImp->aContent = ::ucbhelper::Content();
2771 Init_Impl();
2774 //----------------------------------------------------------------
2775 const String& SfxMedium::GetOrigURL() const
2777 return !pImp->aOrigURL.Len() ? (String &)aLogicName : pImp->aOrigURL;
2780 //----------------------------------------------------------------
2782 void SfxMedium::SetPhysicalName_Impl( const rtl::OUString& rNameP )
2784 if ( rNameP != aName )
2786 if( pImp->pTempFile )
2788 delete pImp->pTempFile;
2789 pImp->pTempFile = NULL;
2792 if ( !aName.isEmpty() || !rNameP.isEmpty() )
2793 pImp->aContent = ::ucbhelper::Content();
2795 aName = rNameP;
2796 bTriedStorage = sal_False;
2797 pImp->bIsStorage = sal_False;
2801 //------------------------------------------------------------------
2803 void SfxMedium::ReOpen()
2805 sal_Bool bUseInteractionHandler = pImp->bUseInteractionHandler;
2806 pImp->bUseInteractionHandler = sal_False;
2807 GetMedium_Impl();
2808 pImp->bUseInteractionHandler = bUseInteractionHandler;
2811 //------------------------------------------------------------------
2813 void SfxMedium::CompleteReOpen()
2815 // do not use temporary file for reopen and in case of success throw the temporary file away
2816 sal_Bool bUseInteractionHandler = pImp->bUseInteractionHandler;
2817 pImp->bUseInteractionHandler = sal_False;
2819 ::utl::TempFile* pTmpFile = NULL;
2820 if ( pImp->pTempFile )
2822 pTmpFile = pImp->pTempFile;
2823 pImp->pTempFile = NULL;
2824 aName = String();
2827 GetMedium_Impl();
2829 if ( GetError() )
2831 if ( pImp->pTempFile )
2833 pImp->pTempFile->EnableKillingFile( sal_True );
2834 delete pImp->pTempFile;
2836 pImp->pTempFile = pTmpFile;
2837 if ( pImp->pTempFile )
2838 aName = pImp->pTempFile->GetFileName();
2840 else
2842 pTmpFile->EnableKillingFile( sal_True );
2843 delete pTmpFile;
2847 pImp->bUseInteractionHandler = bUseInteractionHandler;
2850 //------------------------------------------------------------------
2851 SfxMedium::SfxMedium
2853 const String &rName, StreamMode nOpenMode,
2854 const SfxFilter *pFlt, SfxItemSet *pInSet
2856 : IMPL_CTOR( sal_False, 0 ), // bRoot, pURLObj
2857 pFilter(pFlt),
2858 pSet( pInSet ),
2859 pImp(new SfxMedium_Impl( this ))
2861 aLogicName = rName;
2862 nStorOpenMode = nOpenMode;
2863 Init_Impl();
2867 SfxMedium::SfxMedium( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs )
2868 : IMPL_CTOR( sal_False, 0 ), // bRoot, pURLObj
2869 pFilter(0),
2870 pSet(0),
2871 pImp(new SfxMedium_Impl( this ))
2873 SfxAllItemSet *pParams = new SfxAllItemSet( SFX_APP()->GetPool() );
2874 pSet = pParams;
2875 TransformParameters( SID_OPENDOC, aArgs, *pParams );
2877 String aFilterName;
2878 SFX_ITEMSET_ARG( pSet, pFilterNameItem, SfxStringItem, SID_FILTER_NAME, sal_False );
2879 if( pFilterNameItem )
2880 aFilterName = pFilterNameItem->GetValue();
2881 pFilter = SFX_APP()->GetFilterMatcher().GetFilter4FilterName( aFilterName );
2883 SFX_ITEMSET_ARG( pSet, pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False );
2884 if( pSalvageItem )
2886 // QUESTION: there is some treatment of Salvage in Init_Impl; align!
2887 if ( pSalvageItem->GetValue().Len() )
2889 // if an URL is provided in SalvageItem that means that the FileName refers to a temporary file
2890 // that must be copied here
2892 SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, sal_False );
2893 if (!pFileNameItem) throw uno::RuntimeException();
2894 ::rtl::OUString aNewTempFileURL = SfxMedium::CreateTempCopyWithExt( pFileNameItem->GetValue() );
2895 if ( !aNewTempFileURL.isEmpty() )
2897 pSet->Put( SfxStringItem( SID_FILE_NAME, aNewTempFileURL ) );
2898 pSet->ClearItem( SID_INPUTSTREAM );
2899 pSet->ClearItem( SID_STREAM );
2900 pSet->ClearItem( SID_CONTENT );
2902 else
2904 OSL_FAIL( "Can not create a new temporary file for crash recovery!\n" );
2909 SFX_ITEMSET_ARG( pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, sal_False );
2910 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
2911 pImp->m_originallyReadOnly = true;
2913 SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, sal_False );
2914 if (!pFileNameItem) throw uno::RuntimeException();
2915 aLogicName = pFileNameItem->GetValue();
2916 nStorOpenMode = pImp->m_originallyReadOnly ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
2917 Init_Impl();
2921 //------------------------------------------------------------------
2923 SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const String& rBaseURL, const SfxItemSet* p, sal_Bool bRootP )
2924 : IMPL_CTOR( bRootP, 0 ), // bRoot, pURLObj
2925 pSet(0),
2926 pImp( new SfxMedium_Impl( this ))
2928 String aType = SfxFilter::GetTypeFromStorage( rStor );
2929 pFilter = SFX_APP()->GetFilterMatcher().GetFilter4EA( aType );
2930 DBG_ASSERT( pFilter, "No Filter for storage found!" );
2932 Init_Impl();
2933 pImp->xStorage = rStor;
2934 pImp->bDisposeStorage = sal_False;
2936 // always take BaseURL first, could be overwritten by ItemSet
2937 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
2938 if ( p )
2939 GetItemSet()->Put( *p );
2942 //------------------------------------------------------------------
2944 SfxMedium::~SfxMedium()
2946 // if there is a requirement to clean the backup this is the last possibility to do it
2947 ClearBackup_Impl();
2949 Close();
2951 delete pSet;
2953 if( pImp->bIsTemp && !aName.isEmpty() )
2955 rtl::OUString aTemp;
2956 if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aTemp ))
2958 OSL_FAIL("Physical name not convertable!");
2961 if ( !::utl::UCBContentHelper::Kill( aTemp ) )
2963 OSL_FAIL("Couldn't remove temporary file!");
2967 pFilter = 0;
2969 delete pURLObj;
2970 delete pImp;
2973 //----------------------------------------------------------------
2974 const INetURLObject& SfxMedium::GetURLObject() const
2976 if( !pURLObj )
2978 SfxMedium* pThis = const_cast < SfxMedium* > (this);
2979 pThis->pURLObj = new INetURLObject( aLogicName );
2980 if ( pThis->pURLObj->HasMark() )
2981 (*pThis->pURLObj) = INetURLObject( aLogicName ).GetURLNoMark();
2984 return *pURLObj;
2987 //----------------------------------------------------------------
2989 void SfxMedium::SetReferer( const String& rRefer )
2991 pImp->aReferer = rRefer;
2994 //----------------------------------------------------------------
2996 void SfxMedium::SetExpired_Impl( const DateTime& rDateTime )
2998 pImp->aExpireTime = rDateTime;
3000 //----------------------------------------------------------------
3002 sal_Bool SfxMedium::IsExpired() const
3004 return pImp->aExpireTime.IsValidAndGregorian() && pImp->aExpireTime < DateTime( DateTime::SYSTEM );
3006 //----------------------------------------------------------------
3008 void SfxMedium::ForceSynchronStream_Impl( sal_Bool bForce )
3010 if( pInStream )
3012 SvLockBytes* pBytes = pInStream->GetLockBytes();
3013 if( pBytes )
3014 pBytes->SetSynchronMode( bForce );
3016 pImp->bForceSynchron = bForce;
3019 //----------------------------------------------------------------
3020 SfxFrame* SfxMedium::GetLoadTargetFrame() const
3022 return pImp->wLoadTargetFrame;
3024 //----------------------------------------------------------------
3026 void SfxMedium::SetLoadTargetFrame(SfxFrame* pFrame )
3028 pImp->wLoadTargetFrame = pFrame;
3030 //----------------------------------------------------------------
3032 void SfxMedium::SetStorage_Impl( const uno::Reference < embed::XStorage >& rStor )
3034 pImp->xStorage = rStor;
3036 //----------------------------------------------------------------
3038 SfxItemSet* SfxMedium::GetItemSet() const
3040 // this method *must* return an ItemSet, returning NULL can cause crashes
3041 if( !pSet )
3042 ((SfxMedium*)this)->pSet = new SfxAllItemSet( SFX_APP()->GetPool() );
3043 return pSet;
3045 //----------------------------------------------------------------
3047 SvKeyValueIterator* SfxMedium::GetHeaderAttributes_Impl()
3049 if( !pImp->xAttributes.Is() )
3051 pImp->xAttributes = SvKeyValueIteratorRef( new SvKeyValueIterator );
3053 if ( GetContent().is() )
3055 pImp->bIsCharsetInitialized = sal_True;
3059 Any aAny = pImp->aContent.getPropertyValue( ::rtl::OUString("MediaType") );
3060 ::rtl::OUString aContentType;
3061 aAny >>= aContentType;
3063 pImp->xAttributes->Append( SvKeyValue( ::rtl::OUString("content-type"), aContentType ) );
3065 catch ( const ::com::sun::star::uno::Exception& )
3071 return pImp->xAttributes;
3074 ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SfxMedium::GetInputStream()
3076 if ( !pImp->xInputStream.is() )
3077 GetMedium_Impl();
3078 return pImp->xInputStream;
3081 const uno::Sequence < util::RevisionTag >& SfxMedium::GetVersionList( bool _bNoReload )
3083 // if the medium has no name, then this medium should represent a new document and can have no version info
3084 if ( ( !_bNoReload || !pImp->m_bVersionsAlreadyLoaded ) && !pImp->aVersions.getLength() &&
3085 ( !aName.isEmpty() || aLogicName.Len() ) && GetStorage().is() )
3087 uno::Reference < document::XDocumentRevisionListPersistence > xReader( comphelper::getProcessServiceFactory()->createInstance(
3088 ::rtl::OUString("com.sun.star.document.DocumentRevisionListPersistence") ), uno::UNO_QUERY );
3089 if ( xReader.is() )
3093 pImp->aVersions = xReader->load( GetStorage() );
3095 catch ( const uno::Exception& )
3101 if ( !pImp->m_bVersionsAlreadyLoaded )
3102 pImp->m_bVersionsAlreadyLoaded = sal_True;
3104 return pImp->aVersions;
3107 uno::Sequence < util::RevisionTag > SfxMedium::GetVersionList( const uno::Reference < embed::XStorage >& xStorage )
3109 uno::Reference < document::XDocumentRevisionListPersistence > xReader( comphelper::getProcessServiceFactory()->createInstance(
3110 ::rtl::OUString("com.sun.star.document.DocumentRevisionListPersistence") ), uno::UNO_QUERY );
3111 if ( xReader.is() )
3115 return xReader->load( xStorage );
3117 catch ( const uno::Exception& )
3122 return uno::Sequence < util::RevisionTag >();
3125 sal_uInt16 SfxMedium::AddVersion_Impl( util::RevisionTag& rRevision )
3127 if ( GetStorage().is() )
3129 // To determine a unique name for the stream
3130 std::vector<sal_uInt32> aLongs;
3131 sal_Int32 nLength = pImp->aVersions.getLength();
3132 for ( sal_Int32 m=0; m<nLength; m++ )
3134 sal_uInt32 nVer = static_cast<sal_uInt32>(String( pImp->aVersions[m].Identifier ).Copy(7).ToInt32());
3135 size_t n;
3136 for ( n=0; n<aLongs.size(); ++n )
3137 if ( nVer<aLongs[n] )
3138 break;
3140 aLongs.insert( aLongs.begin()+n, nVer );
3143 sal_uInt16 nKey;
3144 for ( nKey=0; nKey<aLongs.size(); ++nKey )
3145 if ( aLongs[nKey] > ( sal_uIntPtr ) nKey+1 )
3146 break;
3148 String aRevName = DEFINE_CONST_UNICODE( "Version" );
3149 aRevName += String::CreateFromInt32( nKey + 1 );
3150 pImp->aVersions.realloc( nLength+1 );
3151 rRevision.Identifier = aRevName;
3152 pImp->aVersions[nLength] = rRevision;
3153 return nKey;
3156 return 0;
3159 sal_Bool SfxMedium::RemoveVersion_Impl( const ::rtl::OUString& rName )
3161 if ( !pImp->aVersions.getLength() )
3162 return sal_False;
3164 sal_Int32 nLength = pImp->aVersions.getLength();
3165 for ( sal_Int32 n=0; n<nLength; n++ )
3167 if ( pImp->aVersions[n].Identifier == rName )
3169 for ( sal_Int32 m=n; m<nLength-1; m++ )
3170 pImp->aVersions[m] = pImp->aVersions[m+1];
3171 pImp->aVersions.realloc(nLength-1);
3172 return sal_True;
3176 return sal_False;
3179 sal_Bool SfxMedium::TransferVersionList_Impl( SfxMedium& rMedium )
3181 if ( rMedium.pImp->aVersions.getLength() )
3183 pImp->aVersions = rMedium.pImp->aVersions;
3184 return sal_True;
3187 return sal_False;
3190 sal_Bool SfxMedium::SaveVersionList_Impl( sal_Bool /*bUseXML*/ )
3192 if ( GetStorage().is() )
3194 if ( !pImp->aVersions.getLength() )
3195 return sal_True;
3197 uno::Reference < document::XDocumentRevisionListPersistence > xWriter( comphelper::getProcessServiceFactory()->createInstance(
3198 ::rtl::OUString("com.sun.star.document.DocumentRevisionListPersistence") ), uno::UNO_QUERY );
3199 if ( xWriter.is() )
3203 xWriter->store( GetStorage(), pImp->aVersions );
3204 return sal_True;
3206 catch ( const uno::Exception& )
3212 return sal_False;
3215 //----------------------------------------------------------------
3216 sal_Bool SfxMedium::IsReadOnly()
3218 sal_Bool bReadOnly = sal_False;
3220 // a) ReadOnly filter cant produce read/write contents!
3221 bReadOnly = (
3222 (pFilter ) &&
3223 ((pFilter->GetFilterFlags() & SFX_FILTER_OPENREADONLY) == SFX_FILTER_OPENREADONLY)
3226 // b) if filter allow read/write contents .. check open mode of the storage
3227 if (!bReadOnly)
3228 bReadOnly = !( GetOpenMode() & STREAM_WRITE );
3230 // c) the API can force the readonly state!
3231 if (!bReadOnly)
3233 SFX_ITEMSET_ARG( GetItemSet(), pItem, SfxBoolItem, SID_DOC_READONLY, sal_False);
3234 if (pItem)
3235 bReadOnly = pItem->GetValue();
3238 return bReadOnly;
3241 bool SfxMedium::IsOriginallyReadOnly() const
3243 return pImp->m_originallyReadOnly;
3246 //----------------------------------------------------------------
3247 sal_Bool SfxMedium::SetWritableForUserOnly( const ::rtl::OUString& aURL )
3249 // UCB does not allow to allow write access only for the user,
3250 // use osl API
3251 sal_Bool bResult = sal_False;
3253 ::osl::DirectoryItem aDirItem;
3254 if ( ::osl::DirectoryItem::get( aURL, aDirItem ) == ::osl::FileBase::E_None )
3256 ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_Attributes );
3257 if ( aDirItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None
3258 && aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
3260 sal_uInt64 nAttributes = aFileStatus.getAttributes();
3262 nAttributes &= ~(osl_File_Attribute_OwnWrite |
3263 osl_File_Attribute_GrpWrite |
3264 osl_File_Attribute_OthWrite |
3265 osl_File_Attribute_ReadOnly);
3266 nAttributes |= (osl_File_Attribute_OwnWrite |
3267 osl_File_Attribute_OwnRead);
3269 bResult = ( osl::File::setAttributes( aURL, nAttributes ) == ::osl::FileBase::E_None );
3273 return bResult;
3276 //----------------------------------------------------------------
3277 void SfxMedium::CreateTempFile( sal_Bool bReplace )
3279 if ( pImp->pTempFile )
3281 if ( !bReplace )
3282 return;
3284 DELETEZ( pImp->pTempFile );
3285 aName = String();
3288 pImp->pTempFile = new ::utl::TempFile();
3289 pImp->pTempFile->EnableKillingFile( sal_True );
3290 aName = pImp->pTempFile->GetFileName();
3291 ::rtl::OUString aTmpURL = pImp->pTempFile->GetURL();
3292 if ( aName.isEmpty() || aTmpURL.isEmpty() )
3294 SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( OSL_LOG_PREFIX ) );
3295 return;
3298 if ( !( nStorOpenMode & STREAM_TRUNC ) )
3300 sal_Bool bTransferSuccess = sal_False;
3302 if ( GetContent().is()
3303 && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
3304 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) )
3306 // if there is already such a document, we should copy it
3307 // if it is a file system use OS copy process
3310 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
3311 INetURLObject aTmpURLObj( aTmpURL );
3312 ::rtl::OUString aFileName = aTmpURLObj.getName( INetURLObject::LAST_SEGMENT,
3313 true,
3314 INetURLObject::DECODE_WITH_CHARSET );
3315 if ( !aFileName.isEmpty() && aTmpURLObj.removeSegment() )
3317 ::ucbhelper::Content aTargetContent( aTmpURLObj.GetMainURL( INetURLObject::NO_DECODE ), xComEnv );
3318 if ( aTargetContent.transferContent( pImp->aContent, ::ucbhelper::InsertOperation_COPY, aFileName, NameClash::OVERWRITE ) )
3320 SetWritableForUserOnly( aTmpURL );
3321 bTransferSuccess = sal_True;
3325 catch( const uno::Exception& )
3328 if ( bTransferSuccess )
3330 CloseOutStream();
3331 CloseInStream();
3335 if ( !bTransferSuccess && pInStream )
3337 // the case when there is no URL-access available or this is a remote protocoll
3338 // but there is an input stream
3339 GetOutStream();
3340 if ( pOutStream )
3342 char *pBuf = new char [8192];
3343 sal_uInt32 nErr = ERRCODE_NONE;
3345 pInStream->Seek(0);
3346 pOutStream->Seek(0);
3348 while( !pInStream->IsEof() && nErr == ERRCODE_NONE )
3350 sal_uInt32 nRead = pInStream->Read( pBuf, 8192 );
3351 nErr = pInStream->GetError();
3352 pOutStream->Write( pBuf, nRead );
3355 bTransferSuccess = sal_True;
3356 delete[] pBuf;
3357 CloseInStream();
3359 CloseOutStream_Impl();
3361 else
3363 // Quite strange design, but currently it is expected that in this case no transfer happens
3364 // TODO/LATER: get rid of this inconsistent part of the call design
3365 bTransferSuccess = sal_True;
3366 CloseInStream();
3369 if ( !bTransferSuccess )
3371 SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( OSL_LOG_PREFIX ) );
3372 return;
3376 CloseStorage();
3379 //----------------------------------------------------------------
3380 void SfxMedium::CreateTempFileNoCopy()
3382 // this call always replaces the existing temporary file
3383 if ( pImp->pTempFile )
3384 delete pImp->pTempFile;
3386 pImp->pTempFile = new ::utl::TempFile();
3387 pImp->pTempFile->EnableKillingFile( sal_True );
3388 aName = pImp->pTempFile->GetFileName();
3389 if ( aName.isEmpty() )
3391 SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( OSL_LOG_PREFIX ) );
3392 return;
3395 CloseOutStream_Impl();
3396 CloseStorage();
3399 void SfxMedium::SetCharset( ::rtl::OUString aChs )
3401 pImp->bIsCharsetInitialized = sal_True;
3402 pImp->aCharset = aChs;
3405 sal_Bool SfxMedium::SignContents_Impl( sal_Bool bScriptingContent, const ::rtl::OUString& aODFVersion, sal_Bool bHasValidDocumentSignature )
3407 sal_Bool bChanges = sal_False;
3409 // the medium should be closed to be able to sign, the caller is responsible to close it
3410 if ( !IsOpen() && !GetError() )
3412 // The component should know if there was a valid document signature, since
3413 // it should show a warning in this case
3414 uno::Sequence< uno::Any > aArgs( 2 );
3415 aArgs[0] <<= aODFVersion;
3416 aArgs[1] <<= bHasValidDocumentSignature;
3417 ::com::sun::star::uno::Reference< ::com::sun::star::security::XDocumentDigitalSignatures > xSigner(
3418 comphelper::getProcessServiceFactory()->createInstanceWithArguments(
3419 rtl::OUString( "com.sun.star.security.DocumentDigitalSignatures" ),
3420 aArgs ),
3421 ::com::sun::star::uno::UNO_QUERY );
3423 if ( xSigner.is() )
3425 uno::Reference< embed::XStorage > xWriteableZipStor;
3426 if ( !IsReadOnly() )
3428 // we can reuse the temporary file if there is one already
3429 CreateTempFile( sal_False );
3430 GetMedium_Impl();
3434 if ( !pImp->xStream.is() )
3435 throw uno::RuntimeException();
3437 xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImp->xStream );
3438 if ( !xWriteableZipStor.is() )
3439 throw uno::RuntimeException();
3441 uno::Reference< embed::XStorage > xMetaInf = xWriteableZipStor->openStorageElement(
3442 ::rtl::OUString( "META-INF" ),
3443 embed::ElementModes::READWRITE );
3444 if ( !xMetaInf.is() )
3445 throw uno::RuntimeException();
3447 if ( bScriptingContent )
3449 // If the signature has already the document signature it will be removed
3450 // after the scripting signature is inserted.
3451 uno::Reference< io::XStream > xStream(
3452 xMetaInf->openStreamElement( xSigner->getScriptingContentSignatureDefaultStreamName(),
3453 embed::ElementModes::READWRITE ),
3454 uno::UNO_SET_THROW );
3456 if ( xSigner->signScriptingContent( GetZipStorageToSign_Impl(), xStream ) )
3458 // remove the document signature if any
3459 ::rtl::OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName();
3460 if ( !aDocSigName.isEmpty() && xMetaInf->hasByName( aDocSigName ) )
3461 xMetaInf->removeElement( aDocSigName );
3463 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
3464 xTransact->commit();
3465 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
3466 xTransact->commit();
3468 // the temporary file has been written, commit it to the original file
3469 Commit();
3470 bChanges = sal_True;
3473 else
3475 uno::Reference< io::XStream > xStream(
3476 xMetaInf->openStreamElement( xSigner->getDocumentContentSignatureDefaultStreamName(),
3477 embed::ElementModes::READWRITE ),
3478 uno::UNO_SET_THROW );
3480 if ( xSigner->signDocumentContent( GetZipStorageToSign_Impl(), xStream ) )
3482 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
3483 xTransact->commit();
3484 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
3485 xTransact->commit();
3487 // the temporary file has been written, commit it to the original file
3488 Commit();
3489 bChanges = sal_True;
3493 catch ( const uno::Exception& )
3495 OSL_FAIL( "Couldn't use signing functionality!\n" );
3498 CloseAndRelease();
3500 else
3504 if ( bScriptingContent )
3505 xSigner->showScriptingContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() );
3506 else
3507 xSigner->showDocumentContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() );
3509 catch( const uno::Exception& )
3511 OSL_FAIL( "Couldn't use signing functionality!\n" );
3516 ResetError();
3519 return bChanges;
3522 //----------------------------------------------------------------
3523 sal_uInt16 SfxMedium::GetCachedSignatureState_Impl()
3525 return pImp->m_nSignatureState;
3528 //----------------------------------------------------------------
3529 void SfxMedium::SetCachedSignatureState_Impl( sal_uInt16 nState )
3531 pImp->m_nSignatureState = nState;
3534 sal_Bool SfxMedium::HasStorage_Impl() const
3536 return pImp->xStorage.is();
3539 sal_Bool SfxMedium::IsOpen() const
3541 return pInStream || pOutStream || pImp->xStorage.is();
3544 ::rtl::OUString SfxMedium::CreateTempCopyWithExt( const ::rtl::OUString& aURL )
3546 ::rtl::OUString aResult;
3548 if ( !aURL.isEmpty() )
3550 sal_Int32 nPrefixLen = aURL.lastIndexOf( '.' );
3551 String aExt = ( nPrefixLen == -1 ) ? String() : String( aURL.copy( nPrefixLen ) );
3553 ::rtl::OUString aNewTempFileURL = ::utl::TempFile( String(), &aExt ).GetURL();
3554 if ( !aNewTempFileURL.isEmpty() )
3556 INetURLObject aSource( aURL );
3557 INetURLObject aDest( aNewTempFileURL );
3558 ::rtl::OUString aFileName = aDest.getName( INetURLObject::LAST_SEGMENT,
3559 true,
3560 INetURLObject::DECODE_WITH_CHARSET );
3561 if ( !aFileName.isEmpty() && aDest.removeSegment() )
3565 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
3566 ::ucbhelper::Content aTargetContent( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv );
3567 ::ucbhelper::Content aSourceContent( aSource.GetMainURL( INetURLObject::NO_DECODE ), xComEnv );
3568 if ( aTargetContent.transferContent( aSourceContent,
3569 ::ucbhelper::InsertOperation_COPY,
3570 aFileName,
3571 NameClash::OVERWRITE ) )
3573 // Success
3574 aResult = aNewTempFileURL;
3577 catch( const uno::Exception& )
3583 return aResult;
3586 sal_Bool SfxMedium::CallApproveHandler( const uno::Reference< task::XInteractionHandler >& xHandler, uno::Any aRequest, sal_Bool bAllowAbort )
3588 sal_Bool bResult = sal_False;
3590 if ( xHandler.is() )
3594 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( bAllowAbort ? 2 : 1 );
3596 ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( new ::comphelper::OInteractionApprove );
3597 aContinuations[ 0 ] = pApprove.get();
3599 if ( bAllowAbort )
3601 ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( new ::comphelper::OInteractionAbort );
3602 aContinuations[ 1 ] = pAbort.get();
3605 xHandler->handle(::framework::InteractionRequest::CreateRequest (aRequest,aContinuations));
3606 bResult = pApprove->wasSelected();
3608 catch( const Exception& )
3613 return bResult;
3616 ::rtl::OUString SfxMedium::SwitchDocumentToTempFile()
3618 // the method returns empty string in case of failure
3619 ::rtl::OUString aResult;
3620 ::rtl::OUString aOrigURL = aLogicName;
3622 if ( !aOrigURL.isEmpty() )
3624 sal_Int32 nPrefixLen = aOrigURL.lastIndexOf( '.' );
3625 String aExt = ( nPrefixLen == -1 ) ? String() : String( aOrigURL.copy( nPrefixLen ) );
3626 ::rtl::OUString aNewURL = ::utl::TempFile( String(), &aExt ).GetURL();
3628 // TODO/LATER: In future the aLogicName should be set to shared folder URL
3629 // and a temporary file should be created. Transport_Impl should be impossible then.
3630 if ( !aNewURL.isEmpty() )
3632 uno::Reference< embed::XStorage > xStorage = GetStorage();
3633 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
3635 if ( xOptStorage.is() )
3637 // TODO/LATER: reuse the pImp->pTempFile if it already exists
3638 CanDisposeStorage_Impl( sal_False );
3639 Close();
3640 SetPhysicalName_Impl( String() );
3641 SetName( aNewURL );
3643 // remove the readonly state
3644 sal_Bool bWasReadonly = sal_False;
3645 nStorOpenMode = SFX_STREAM_READWRITE;
3646 SFX_ITEMSET_ARG( pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, sal_False );
3647 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
3648 bWasReadonly = sal_True;
3649 GetItemSet()->ClearItem( SID_DOC_READONLY );
3651 GetMedium_Impl();
3652 LockOrigFileOnDemand( sal_False, sal_False );
3653 CreateTempFile( sal_True );
3654 GetMedium_Impl();
3656 if ( pImp->xStream.is() )
3660 xOptStorage->writeAndAttachToStream( pImp->xStream );
3661 pImp->xStorage = xStorage;
3662 aResult = aNewURL;
3664 catch( const uno::Exception& )
3668 if ( aResult.isEmpty() )
3670 Close();
3671 SetPhysicalName_Impl( String() );
3672 SetName( aOrigURL );
3673 if ( bWasReadonly )
3675 // set the readonly state back
3676 nStorOpenMode = SFX_STREAM_READONLY;
3677 GetItemSet()->Put( SfxBoolItem(SID_DOC_READONLY, sal_True));
3679 GetMedium_Impl();
3680 pImp->xStorage = xStorage;
3686 return aResult;
3689 sal_Bool SfxMedium::SwitchDocumentToFile( ::rtl::OUString aURL )
3691 // the method is only for storage based documents
3692 sal_Bool bResult = sal_False;
3693 ::rtl::OUString aOrigURL = aLogicName;
3695 if ( !aURL.isEmpty() && !aOrigURL.isEmpty() )
3697 uno::Reference< embed::XStorage > xStorage = GetStorage();
3698 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
3700 if ( xOptStorage.is() )
3702 // TODO/LATER: reuse the pImp->pTempFile if it already exists
3703 CanDisposeStorage_Impl( sal_False );
3704 Close();
3705 SetPhysicalName_Impl( String() );
3706 SetName( aURL );
3708 // open the temporary file based document
3709 GetMedium_Impl();
3710 LockOrigFileOnDemand( sal_False, sal_False );
3711 CreateTempFile( sal_True );
3712 GetMedium_Impl();
3714 if ( pImp->xStream.is() )
3718 uno::Reference< io::XTruncate > xTruncate( pImp->xStream, uno::UNO_QUERY_THROW );
3719 if ( xTruncate.is() )
3720 xTruncate->truncate();
3722 xOptStorage->writeAndAttachToStream( pImp->xStream );
3723 pImp->xStorage = xStorage;
3724 bResult = sal_True;
3726 catch( const uno::Exception& )
3730 if ( !bResult )
3732 Close();
3733 SetPhysicalName_Impl( String() );
3734 SetName( aOrigURL );
3735 GetMedium_Impl();
3736 pImp->xStorage = xStorage;
3741 return bResult;
3744 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */