1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/io/NotConnectedException.hpp>
21 #include <com/sun/star/io/BufferSizeExceededException.hpp>
22 #include <com/sun/star/uno/RuntimeException.hpp>
23 #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 #include <ucbhelper/content.hxx>
25 #include <com/sun/star/uno/Reference.h>
26 #include <com/sun/star/ucb/NameClash.hpp>
27 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
28 #include <unotools/tempfile.hxx>
29 #include <unotools/ucbstreamhelper.hxx>
30 #include <com/sun/star/io/XInputStream.hpp>
31 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
32 #include <com/sun/star/ucb/ResultSetException.hpp>
33 #include <com/sun/star/uno/Sequence.h>
34 #include <com/sun/star/sdbc/XResultSet.hpp>
35 #include <com/sun/star/ucb/XContentAccess.hpp>
36 #include <com/sun/star/sdbc/XRow.hpp>
37 #include <com/sun/star/ucb/CommandAbortedException.hpp>
38 #include <com/sun/star/datatransfer/DataFlavor.hpp>
39 #include <com/sun/star/ucb/ContentInfo.hpp>
40 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
41 #include <com/sun/star/beans/Property.hpp>
42 #include <com/sun/star/packages/manifest/ManifestWriter.hpp>
43 #include <com/sun/star/packages/manifest/ManifestReader.hpp>
44 #include <com/sun/star/ucb/InteractiveIOException.hpp>
46 #include <boost/scoped_ptr.hpp>
47 #include <rtl/digest.h>
48 #include <tools/ref.hxx>
49 #include <tools/debug.hxx>
50 #include <unotools/streamhelper.hxx>
51 #include <unotools/streamwrap.hxx>
52 #include <unotools/ucbhelper.hxx>
53 #include <unotools/localfilehelper.hxx>
54 #include <tools/urlobj.hxx>
55 #include <comphelper/processfactory.hxx>
56 #include <cppuhelper/implbase2.hxx>
57 #include <ucbhelper/commandenvironment.hxx>
59 #include "sot/stg.hxx"
60 #include "sot/storinfo.hxx"
61 #include <sot/storage.hxx>
62 #include <sot/exchange.hxx>
63 #include <sot/formats.hxx>
64 #include <comphelper/classids.hxx>
68 using namespace ::com::sun::star::lang
;
69 using namespace ::com::sun::star::beans
;
70 using namespace ::com::sun::star::uno
;
71 using namespace ::com::sun::star::ucb
;
72 using namespace ::com::sun::star::io
;
73 using namespace ::com::sun::star::sdbc
;
74 using namespace ::ucbhelper
;
76 #if OSL_DEBUG_LEVEL > 1
78 static int nOpenFiles
=0;
79 static int nOpenStreams
=0;
82 typedef ::cppu::WeakImplHelper2
< XInputStream
, XSeekable
> FileInputStreamWrapper_Base
;
83 class FileStreamWrapper_Impl
: public FileInputStreamWrapper_Base
86 ::osl::Mutex m_aMutex
;
88 SvStream
* m_pSvStream
;
91 FileStreamWrapper_Impl( const OUString
& rName
);
92 virtual ~FileStreamWrapper_Impl();
94 virtual void SAL_CALL
seek( sal_Int64 _nLocation
) throw ( IllegalArgumentException
, IOException
, RuntimeException
);
95 virtual sal_Int64 SAL_CALL
getPosition( ) throw ( IOException
, RuntimeException
);
96 virtual sal_Int64 SAL_CALL
getLength( ) throw ( IOException
, RuntimeException
);
97 virtual sal_Int32 SAL_CALL
readBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
98 virtual sal_Int32 SAL_CALL
readSomeBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
99 virtual void SAL_CALL
skipBytes(sal_Int32 nBytesToSkip
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
100 virtual sal_Int32 SAL_CALL
available() throw( NotConnectedException
, RuntimeException
);
101 virtual void SAL_CALL
closeInput() throw( NotConnectedException
, RuntimeException
);
104 void checkConnected();
108 //------------------------------------------------------------------
109 FileStreamWrapper_Impl::FileStreamWrapper_Impl( const OUString
& rName
)
113 // if no URL is provided the stream is empty
116 //------------------------------------------------------------------
117 FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
122 #if OSL_DEBUG_LEVEL > 1
127 if ( !m_aURL
.isEmpty() )
128 ::utl::UCBContentHelper::Kill( m_aURL
);
131 //------------------------------------------------------------------------------
132 sal_Int32 SAL_CALL
FileStreamWrapper_Impl::readBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
)
133 throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
135 if ( m_aURL
.isEmpty() )
143 if (nBytesToRead
< 0)
144 throw BufferSizeExceededException(OUString(),static_cast<XWeak
*>(this));
146 ::osl::MutexGuard
aGuard( m_aMutex
);
148 aData
.realloc(nBytesToRead
);
150 sal_uInt32 nRead
= m_pSvStream
->Read((void*)aData
.getArray(), nBytesToRead
);
153 // Wenn gelesene Zeichen < MaxLength, Sequence anpassen
154 if (nRead
< (sal_uInt32
)nBytesToRead
)
155 aData
.realloc( nRead
);
160 //------------------------------------------------------------------------------
161 sal_Int32 SAL_CALL
FileStreamWrapper_Impl::readSomeBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
163 if ( m_aURL
.isEmpty() )
171 if (nMaxBytesToRead
< 0)
172 throw BufferSizeExceededException(OUString(),static_cast<XWeak
*>(this));
174 if (m_pSvStream
->IsEof())
180 return readBytes(aData
, nMaxBytesToRead
);
183 //------------------------------------------------------------------------------
184 void SAL_CALL
FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
186 if ( m_aURL
.isEmpty() )
189 ::osl::MutexGuard
aGuard( m_aMutex
);
192 m_pSvStream
->SeekRel(nBytesToSkip
);
196 //------------------------------------------------------------------------------
197 sal_Int32 SAL_CALL
FileStreamWrapper_Impl::available() throw( NotConnectedException
, RuntimeException
)
199 if ( m_aURL
.isEmpty() )
202 ::osl::MutexGuard
aGuard( m_aMutex
);
205 sal_uInt32 nPos
= m_pSvStream
->Tell();
208 m_pSvStream
->Seek(STREAM_SEEK_TO_END
);
211 sal_Int32 nAvailable
= (sal_Int32
)m_pSvStream
->Tell() - nPos
;
212 m_pSvStream
->Seek(nPos
);
218 //------------------------------------------------------------------------------
219 void SAL_CALL
FileStreamWrapper_Impl::closeInput() throw( NotConnectedException
, RuntimeException
)
221 if ( m_aURL
.isEmpty() )
224 ::osl::MutexGuard
aGuard( m_aMutex
);
226 DELETEZ( m_pSvStream
);
227 #if OSL_DEBUG_LEVEL > 1
230 ::utl::UCBContentHelper::Kill( m_aURL
);
234 //------------------------------------------------------------------------------
235 void SAL_CALL
FileStreamWrapper_Impl::seek( sal_Int64 _nLocation
) throw (IllegalArgumentException
, IOException
, RuntimeException
)
237 if ( m_aURL
.isEmpty() )
240 ::osl::MutexGuard
aGuard( m_aMutex
);
243 m_pSvStream
->Seek((sal_uInt32
)_nLocation
);
247 //------------------------------------------------------------------------------
248 sal_Int64 SAL_CALL
FileStreamWrapper_Impl::getPosition( ) throw (IOException
, RuntimeException
)
250 if ( m_aURL
.isEmpty() )
253 ::osl::MutexGuard
aGuard( m_aMutex
);
256 sal_uInt32 nPos
= m_pSvStream
->Tell();
258 return (sal_Int64
)nPos
;
261 //------------------------------------------------------------------------------
262 sal_Int64 SAL_CALL
FileStreamWrapper_Impl::getLength( ) throw (IOException
, RuntimeException
)
264 if ( m_aURL
.isEmpty() )
267 ::osl::MutexGuard
aGuard( m_aMutex
);
270 sal_uInt32 nCurrentPos
= m_pSvStream
->Tell();
273 m_pSvStream
->Seek(STREAM_SEEK_TO_END
);
274 sal_uInt32 nEndPos
= m_pSvStream
->Tell();
275 m_pSvStream
->Seek(nCurrentPos
);
279 return (sal_Int64
)nEndPos
;
282 //------------------------------------------------------------------------------
283 void FileStreamWrapper_Impl::checkConnected()
285 if ( m_aURL
.isEmpty() )
286 throw NotConnectedException(OUString(), const_cast<XWeak
*>(static_cast<const XWeak
*>(this)));
289 m_pSvStream
= ::utl::UcbStreamHelper::CreateStream( m_aURL
, STREAM_STD_READ
);
290 #if OSL_DEBUG_LEVEL > 1
296 //------------------------------------------------------------------------------
297 void FileStreamWrapper_Impl::checkError()
301 if (m_pSvStream
->SvStream::GetError() != ERRCODE_NONE
)
302 // TODO: really evaluate the error
303 throw NotConnectedException(OUString(), const_cast<XWeak
*>(static_cast<const XWeak
*>(this)));
306 TYPEINIT1( UCBStorageStream
, BaseStorageStream
);
307 TYPEINIT1( UCBStorage
, BaseStorage
);
309 #define COMMIT_RESULT_FAILURE 0
310 #define COMMIT_RESULT_NOTHING_TO_DO 1
311 #define COMMIT_RESULT_SUCCESS 2
313 #define min( x, y ) (( x < y ) ? x : y)
315 sal_Int32
GetFormatId_Impl( SvGlobalName aName
)
317 if ( aName
== SvGlobalName( SO3_SW_CLASSID_60
) )
318 return SOT_FORMATSTR_ID_STARWRITER_60
;
319 if ( aName
== SvGlobalName( SO3_SWWEB_CLASSID_60
) )
320 return SOT_FORMATSTR_ID_STARWRITERWEB_60
;
321 if ( aName
== SvGlobalName( SO3_SWGLOB_CLASSID_60
) )
322 return SOT_FORMATSTR_ID_STARWRITERGLOB_60
;
323 if ( aName
== SvGlobalName( SO3_SDRAW_CLASSID_60
) )
324 return SOT_FORMATSTR_ID_STARDRAW_60
;
325 if ( aName
== SvGlobalName( SO3_SIMPRESS_CLASSID_60
) )
326 return SOT_FORMATSTR_ID_STARIMPRESS_60
;
327 if ( aName
== SvGlobalName( SO3_SC_CLASSID_60
) )
328 return SOT_FORMATSTR_ID_STARCALC_60
;
329 if ( aName
== SvGlobalName( SO3_SCH_CLASSID_60
) )
330 return SOT_FORMATSTR_ID_STARCHART_60
;
331 if ( aName
== SvGlobalName( SO3_SM_CLASSID_60
) )
332 return SOT_FORMATSTR_ID_STARMATH_60
;
333 if ( aName
== SvGlobalName( SO3_OUT_CLASSID
) ||
334 aName
== SvGlobalName( SO3_APPLET_CLASSID
) ||
335 aName
== SvGlobalName( SO3_PLUGIN_CLASSID
) ||
336 aName
== SvGlobalName( SO3_IFRAME_CLASSID
) )
337 // allowed, but not supported
341 OSL_FAIL( "Unknown UCB storage format!" );
347 SvGlobalName
GetClassId_Impl( sal_Int32 nFormat
)
351 case SOT_FORMATSTR_ID_STARWRITER_8
:
352 case SOT_FORMATSTR_ID_STARWRITER_8_TEMPLATE
:
353 return SvGlobalName( SO3_SW_CLASSID_60
);
354 case SOT_FORMATSTR_ID_STARWRITERWEB_8
:
355 return SvGlobalName( SO3_SWWEB_CLASSID_60
);
356 case SOT_FORMATSTR_ID_STARWRITERGLOB_8
:
357 return SvGlobalName( SO3_SWGLOB_CLASSID_60
);
358 case SOT_FORMATSTR_ID_STARDRAW_8
:
359 case SOT_FORMATSTR_ID_STARDRAW_8_TEMPLATE
:
360 return SvGlobalName( SO3_SDRAW_CLASSID_60
);
361 case SOT_FORMATSTR_ID_STARIMPRESS_8
:
362 case SOT_FORMATSTR_ID_STARIMPRESS_8_TEMPLATE
:
363 return SvGlobalName( SO3_SIMPRESS_CLASSID_60
);
364 case SOT_FORMATSTR_ID_STARCALC_8
:
365 case SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE
:
366 return SvGlobalName( SO3_SC_CLASSID_60
);
367 case SOT_FORMATSTR_ID_STARCHART_8
:
368 case SOT_FORMATSTR_ID_STARCHART_8_TEMPLATE
:
369 return SvGlobalName( SO3_SCH_CLASSID_60
);
370 case SOT_FORMATSTR_ID_STARMATH_8
:
371 case SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE
:
372 return SvGlobalName( SO3_SM_CLASSID_60
);
373 case SOT_FORMATSTR_ID_STARWRITER_60
:
374 return SvGlobalName( SO3_SW_CLASSID_60
);
375 case SOT_FORMATSTR_ID_STARWRITERWEB_60
:
376 return SvGlobalName( SO3_SWWEB_CLASSID_60
);
377 case SOT_FORMATSTR_ID_STARWRITERGLOB_60
:
378 return SvGlobalName( SO3_SWGLOB_CLASSID_60
);
379 case SOT_FORMATSTR_ID_STARDRAW_60
:
380 return SvGlobalName( SO3_SDRAW_CLASSID_60
);
381 case SOT_FORMATSTR_ID_STARIMPRESS_60
:
382 return SvGlobalName( SO3_SIMPRESS_CLASSID_60
);
383 case SOT_FORMATSTR_ID_STARCALC_60
:
384 return SvGlobalName( SO3_SC_CLASSID_60
);
385 case SOT_FORMATSTR_ID_STARCHART_60
:
386 return SvGlobalName( SO3_SCH_CLASSID_60
);
387 case SOT_FORMATSTR_ID_STARMATH_60
:
388 return SvGlobalName( SO3_SM_CLASSID_60
);
390 return SvGlobalName();
394 // All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
395 // class, that uses the refcounted object as impl-class.
397 enum RepresentModes
{
403 class UCBStorageStream_Impl
: public SvRefBase
, public SvStream
405 ~UCBStorageStream_Impl();
408 virtual sal_uLong
GetData( void* pData
, sal_uLong nSize
);
409 virtual sal_uLong
PutData( const void* pData
, sal_uLong nSize
);
410 virtual sal_uLong
SeekPos( sal_uLong nPos
);
411 virtual void SetSize( sal_uLong nSize
);
412 virtual void FlushData();
413 virtual void ResetError();
415 UCBStorageStream
* m_pAntiImpl
; // only valid if an external reference exists
417 OUString m_aOriginalName
;// the original name before accessing the stream
418 OUString m_aName
; // the actual name ( changed with a Rename command at the parent )
419 OUString m_aURL
; // the full path name to create the content
420 OUString m_aContentType
;
421 OUString m_aOriginalContentType
;
423 ::ucbhelper::Content
* m_pContent
; // the content that provides the data
424 Reference
<XInputStream
> m_rSource
; // the stream covering the original data of the content
425 SvStream
* m_pStream
; // the stream worked on; for readonly streams it is the original stream of the content
426 // for read/write streams it's a copy into a temporary file
427 OUString m_aTempURL
; // URL of this temporary stream
428 RepresentModes m_nRepresentMode
; // should it be used as XInputStream or as SvStream
430 StreamMode m_nMode
; // open mode ( read/write/trunc/nocreate/sharing )
431 bool m_bSourceRead
; // Source still contains useful information
432 bool m_bModified
; // only modified streams will be sent to the original content
433 bool m_bCommited
; // sending the streams is coordinated by the root storage of the package
434 bool m_bDirect
; // the storage and its streams are opened in direct mode; for UCBStorages
435 // this means that the root storage does an autocommit when its external
436 // reference is destroyed
437 bool m_bIsOLEStorage
;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
439 UCBStorageStream_Impl( const OUString
&, StreamMode
, UCBStorageStream
*, bool, const OString
* pKey
=0,
440 bool bRepair
= false, Reference
< XProgressHandler
> xProgress
= Reference
< XProgressHandler
>() );
445 sal_Int16
Commit(); // if modified and commited: transfer an XInputStream to the content
446 bool Revert(); // discard all changes
447 BaseStorage
* CreateStorage();// create an OLE Storage on the UCBStorageStream
450 sal_uLong
ReadSourceWriteTemporary( sal_uLong aLength
); // read aLength from source and copy to temporary,
451 // no seeking is produced
452 sal_uLong
ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
454 sal_uLong
CopySourceToTemporary(); // same as ReadSourceWriteToTemporary()
455 // but the writing is done at the end of temporary
456 // pointer position is not changed
457 using SvStream::SetError
;
458 void SetError( sal_uInt32 nError
);
459 void PrepareCachedForReopen( StreamMode nMode
);
462 SV_DECL_IMPL_REF( UCBStorageStream_Impl
);
464 struct UCBStorageElement_Impl
;
465 typedef ::std::vector
< UCBStorageElement_Impl
* > UCBStorageElementList_Impl
;
467 class UCBStorage_Impl
: public SvRefBase
471 UCBStorage
* m_pAntiImpl
; // only valid if external references exists
473 OUString m_aOriginalName
;// the original name before accessing the storage
474 OUString m_aName
; // the actual name ( changed with a Rename command at the parent )
475 OUString m_aURL
; // the full path name to create the content
476 OUString m_aContentType
;
477 OUString m_aOriginalContentType
;
478 ::ucbhelper::Content
* m_pContent
; // the content that provides the storage elements
479 ::utl::TempFile
* m_pTempFile
; // temporary file, only for storages on stream
480 SvStream
* m_pSource
; // original stream, only for storages on a stream
482 StreamMode m_nMode
; // open mode ( read/write/trunc/nocreate/sharing )
483 bool m_bModified
; // only modified elements will be sent to the original content
484 bool m_bCommited
; // sending the streams is coordinated by the root storage of the package
485 bool m_bDirect
; // the storage and its streams are opened in direct mode; for UCBStorages
486 // this means that the root storage does an autocommit when its external
487 // reference is destroyed
488 bool m_bIsRoot
; // marks this storage as root storages that manages all oommits and reverts
489 bool m_bDirty
; // ???
493 OUString m_aUserTypeName
;
494 SvGlobalName m_aClassId
;
496 UCBStorageElementList_Impl m_aChildrenList
;
498 bool m_bRepairPackage
;
499 Reference
< XProgressHandler
> m_xProgressHandler
;
501 UCBStorage_Impl( const ::ucbhelper::Content
&, const OUString
&, StreamMode
, UCBStorage
*, bool,
502 bool, bool = false, Reference
< XProgressHandler
> = Reference
< XProgressHandler
>() );
503 UCBStorage_Impl( const OUString
&, StreamMode
, UCBStorage
*, bool, bool,
504 bool = false, Reference
< XProgressHandler
> = Reference
< XProgressHandler
>() );
505 UCBStorage_Impl( SvStream
&, UCBStorage
*, bool );
509 bool Insert( ::ucbhelper::Content
*pContent
);
510 UCBStorage_Impl
* OpenStorage( UCBStorageElement_Impl
* pElement
, StreamMode nMode
, bool bDirect
);
511 UCBStorageStream_Impl
* OpenStream( UCBStorageElement_Impl
*, StreamMode
, bool, const OString
* pKey
=0 );
512 void SetProps( const Sequence
< Sequence
< PropertyValue
> >& rSequence
, const OUString
& );
513 void GetProps( sal_Int32
&, Sequence
< Sequence
< PropertyValue
> >& rSequence
, const OUString
& );
514 sal_Int32
GetObjectCount();
516 void CreateContent();
517 ::ucbhelper::Content
* GetContent()
518 { if ( !m_pContent
) CreateContent(); return m_pContent
; }
519 UCBStorageElementList_Impl
& GetChildrenList()
521 long nError
= m_nError
;
523 if ( m_nMode
& STREAM_WRITE
)
528 m_pAntiImpl
->ResetError();
529 m_pAntiImpl
->SetError( nError
);
533 return m_aChildrenList
;
536 void SetError( long nError
);
539 SV_DECL_IMPL_REF( UCBStorage_Impl
);
541 // this struct contains all necessary information on an element inside a UCBStorage
542 struct UCBStorageElement_Impl
544 OUString m_aName
; // the actual URL relative to the root "folder"
545 OUString m_aOriginalName
;// the original name in the content
547 bool m_bIsFolder
; // Only true when it is a UCBStorage !
548 bool m_bIsStorage
; // Also true when it is an OLEStorage !
549 bool m_bIsRemoved
; // element will be removed on commit
550 bool m_bIsInserted
; // element will be removed on revert
551 UCBStorage_ImplRef m_xStorage
; // reference to the "real" storage
552 UCBStorageStream_ImplRef m_xStream
; // reference to the "real" stream
554 UCBStorageElement_Impl( const OUString
& rName
,
555 bool bIsFolder
= false, sal_uLong nSize
= 0 )
557 , m_aOriginalName( rName
)
559 , m_bIsFolder( bIsFolder
)
560 , m_bIsStorage( bIsFolder
)
561 , m_bIsRemoved( false )
562 , m_bIsInserted( false )
566 ::ucbhelper::Content
* GetContent();
568 OUString
GetContentType();
569 void SetContentType( const OUString
& );
570 OUString
GetOriginalContentType();
572 { return m_xStream
.Is() || m_xStorage
.Is(); }
575 ::ucbhelper::Content
* UCBStorageElement_Impl::GetContent()
577 if ( m_xStream
.Is() )
578 return m_xStream
->m_pContent
;
579 else if ( m_xStorage
.Is() )
580 return m_xStorage
->GetContent();
585 OUString
UCBStorageElement_Impl::GetContentType()
587 if ( m_xStream
.Is() )
588 return m_xStream
->m_aContentType
;
589 else if ( m_xStorage
.Is() )
590 return m_xStorage
->m_aContentType
;
593 OSL_FAIL("Element not loaded!");
598 void UCBStorageElement_Impl::SetContentType( const OUString
& rType
)
600 if ( m_xStream
.Is() ) {
601 m_xStream
->m_aContentType
= m_xStream
->m_aOriginalContentType
= rType
;
603 else if ( m_xStorage
.Is() ) {
604 m_xStorage
->m_aContentType
= m_xStorage
->m_aOriginalContentType
= rType
;
607 OSL_FAIL("Element not loaded!");
611 OUString
UCBStorageElement_Impl::GetOriginalContentType()
613 if ( m_xStream
.Is() )
614 return m_xStream
->m_aOriginalContentType
;
615 else if ( m_xStorage
.Is() )
616 return m_xStorage
->m_aOriginalContentType
;
621 bool UCBStorageElement_Impl::IsModified()
623 bool bModified
= m_bIsRemoved
|| m_bIsInserted
|| m_aName
!= m_aOriginalName
;
626 if ( m_xStream
.Is() )
627 bModified
= m_xStream
->m_aContentType
!= m_xStream
->m_aOriginalContentType
;
628 else if ( m_xStorage
.Is() )
629 bModified
= m_xStorage
->m_aContentType
!= m_xStorage
->m_aOriginalContentType
;
635 UCBStorageStream_Impl::UCBStorageStream_Impl( const OUString
& rName
, StreamMode nMode
, UCBStorageStream
* pStream
, bool bDirect
, const OString
* pKey
, bool bRepair
, Reference
< XProgressHandler
> xProgress
)
636 : m_pAntiImpl( pStream
)
640 , m_nRepresentMode( nonset
)
643 , m_bSourceRead( !( nMode
& STREAM_TRUNC
) )
644 , m_bModified( false )
645 , m_bCommited( false )
646 , m_bDirect( bDirect
)
647 , m_bIsOLEStorage( false )
649 // name is last segment in URL
650 INetURLObject
aObj( rName
);
651 m_aName
= m_aOriginalName
= aObj
.GetLastName();
654 // create the content
655 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
657 OUString
aTemp( rName
);
661 xComEnv
= new ::ucbhelper::CommandEnvironment( Reference
< ::com::sun::star::task::XInteractionHandler
>(),
663 aTemp
+= "?repairpackage";
666 m_pContent
= new ::ucbhelper::Content( aTemp
, xComEnv
, comphelper::getProcessComponentContext() );
672 // stream is encrypted and should be decrypted (without setting the key we'll get the raw data)
673 sal_uInt8 aBuffer
[RTL_DIGEST_LENGTH_SHA1
];
674 rtlDigestError nErr
= rtl_digest_SHA1( pKey
->getStr(), pKey
->getLength(), aBuffer
, RTL_DIGEST_LENGTH_SHA1
);
675 if ( nErr
== rtl_Digest_E_None
)
677 sal_uInt8
* pBuffer
= aBuffer
;
678 ::com::sun::star::uno::Sequence
< sal_Int8
> aSequ( (sal_Int8
*) pBuffer
, RTL_DIGEST_LENGTH_SHA1
);
679 ::com::sun::star::uno::Any aAny
;
681 m_pContent
->setPropertyValue("EncryptionKey", aAny
);
685 catch (const ContentCreationException
&)
687 // content could not be created
688 SetError( SVSTREAM_CANNOT_MAKE
);
690 catch (const RuntimeException
&)
692 // any other error - not specified
693 SetError( ERRCODE_IO_GENERAL
);
697 UCBStorageStream_Impl::~UCBStorageStream_Impl()
705 if ( !m_aTempURL
.isEmpty() )
706 ::utl::UCBContentHelper::Kill( m_aTempURL
);
713 bool UCBStorageStream_Impl::Init()
715 if( m_nRepresentMode
== xinputstream
)
717 OSL_FAIL( "XInputStream misuse!" );
718 SetError( ERRCODE_IO_ACCESSDENIED
);
724 // no temporary stream was created
727 m_nRepresentMode
= svstream
; // can not be used as XInputStream
729 if ( m_aTempURL
.isEmpty() )
730 m_aTempURL
= ::utl::TempFile().GetURL();
732 m_pStream
= ::utl::UcbStreamHelper::CreateStream( m_aTempURL
, STREAM_STD_READWRITE
, true /* bFileExists */ );
733 #if OSL_DEBUG_LEVEL > 1
739 OSL_FAIL( "Suspicious temporary stream creation!" );
740 SetError( SVSTREAM_CANNOT_MAKE
);
744 SetError( m_pStream
->GetError() );
747 if( m_bSourceRead
&& !m_rSource
.is() )
749 // source file contain useful information and is not opened
750 // open it from the point of noncopied data
754 m_rSource
= m_pContent
->openStream();
756 catch (const Exception
&)
758 // usually means that stream could not be opened
763 m_pStream
->Seek( STREAM_SEEK_TO_END
);
767 m_rSource
->skipBytes( m_pStream
->Tell() );
769 catch (const BufferSizeExceededException
&)
771 // the temporary stream already contain all the data
772 m_bSourceRead
= false;
774 catch (const Exception
&)
776 // something is really wrong
777 m_bSourceRead
= false;
778 OSL_FAIL( "Can not operate original stream!" );
779 SetError( SVSTREAM_CANNOT_MAKE
);
782 m_pStream
->Seek( 0 );
786 // if the new file is edited than no source exist
787 m_bSourceRead
= false;
788 //SetError( SVSTREAM_CANNOT_MAKE );
792 DBG_ASSERT( m_rSource
.is() || !m_bSourceRead
, "Unreadable source stream!" );
797 sal_uLong
UCBStorageStream_Impl::ReadSourceWriteTemporary()
799 // read source stream till the end and copy all the data to
800 // the current position of the temporary stream
802 sal_uLong aResult
= 0;
806 Sequence
<sal_Int8
> aData(32000);
813 aReaded
= m_rSource
->readBytes( aData
, 32000 );
814 aResult
+= m_pStream
->Write( aData
.getArray(), aReaded
);
815 } while( aReaded
== 32000 );
817 catch (const Exception
&e
)
819 OSL_FAIL( OUStringToOString( e
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr() );
824 m_bSourceRead
= false;
830 sal_uLong
UCBStorageStream_Impl::ReadSourceWriteTemporary( sal_uLong aLength
)
832 // read aLength bite from the source stream and copy them to the current
833 // position of the temporary stream
835 sal_uLong aResult
= 0;
839 Sequence
<sal_Int8
> aData(32000);
844 sal_uLong aReaded
= 32000;
846 for( sal_uLong pInd
= 0; pInd
< aLength
&& aReaded
== 32000 ; pInd
+= 32000 )
848 sal_uLong aToCopy
= min( aLength
- pInd
, 32000 );
849 aReaded
= m_rSource
->readBytes( aData
, aToCopy
);
850 aResult
+= m_pStream
->Write( aData
.getArray(), aReaded
);
853 if( aResult
< aLength
)
854 m_bSourceRead
= false;
856 catch( const Exception
& e
)
858 OSL_FAIL( OUStringToOString( e
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr() );
866 sal_uLong
UCBStorageStream_Impl::CopySourceToTemporary()
868 // current position of the temporary stream is not changed
869 sal_uLong aResult
= 0;
873 sal_uLong aPos
= m_pStream
->Tell();
874 m_pStream
->Seek( STREAM_SEEK_TO_END
);
875 aResult
= ReadSourceWriteTemporary();
876 m_pStream
->Seek( aPos
);
883 // UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
884 // of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
885 sal_uLong
UCBStorageStream_Impl::GetData( void* pData
, sal_uLong nSize
)
887 sal_uLong aResult
= 0;
893 // read data that is in temporary stream
894 aResult
= m_pStream
->Read( pData
, nSize
);
895 if( m_bSourceRead
&& aResult
< nSize
)
897 // read the tail of the data from original stream
898 // copy this tail to the temporary stream
900 sal_uLong aToRead
= nSize
- aResult
;
901 pData
= (void*)( (char*)pData
+ aResult
);
905 Sequence
<sal_Int8
> aData( aToRead
);
906 sal_uLong aReaded
= m_rSource
->readBytes( aData
, aToRead
);
907 aResult
+= m_pStream
->Write( (void*)aData
.getArray(), aReaded
);
908 memcpy( pData
, aData
.getArray(), aReaded
);
910 catch (const Exception
&e
)
912 OSL_FAIL( OUStringToOString( e
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr() );
916 if( aResult
< nSize
)
917 m_bSourceRead
= false;
923 sal_uLong
UCBStorageStream_Impl::PutData( const void* pData
, sal_uLong nSize
)
925 if ( !(m_nMode
& STREAM_WRITE
) )
927 SetError( ERRCODE_IO_ACCESSDENIED
);
931 if( !nSize
|| !Init() )
934 sal_uLong aResult
= m_pStream
->Write( pData
, nSize
);
936 m_bModified
= aResult
> 0;
942 sal_uLong
UCBStorageStream_Impl::SeekPos( sal_uLong nPos
)
949 if( nPos
== STREAM_SEEK_TO_END
)
951 m_pStream
->Seek( STREAM_SEEK_TO_END
);
952 ReadSourceWriteTemporary();
953 aResult
= m_pStream
->Tell();
957 // the problem is that even if nPos is larger the length
958 // of the stream the stream pointer will be moved to this position
959 // so we have to check if temporary stream does not contain required position
961 if( m_pStream
->Tell() > nPos
962 || m_pStream
->Seek( STREAM_SEEK_TO_END
) > nPos
)
964 // no copiing is required
965 aResult
= m_pStream
->Seek( nPos
);
969 // the temp stream pointer points to the end now
970 aResult
= m_pStream
->Tell();
976 aResult
+= ReadSourceWriteTemporary( nPos
- aResult
);
978 m_bSourceRead
= false;
980 DBG_ASSERT( aResult
== m_pStream
->Tell(), "Error in stream arithmetic!\n" );
983 if( (m_nMode
& STREAM_WRITE
) && !m_bSourceRead
&& aResult
< nPos
)
985 // it means that all the Source stream was copied already
986 // but the required position still was not reached
987 // for writable streams it should be done
988 m_pStream
->SetStreamSize( nPos
);
989 aResult
= m_pStream
->Seek( STREAM_SEEK_TO_END
);
990 DBG_ASSERT( aResult
== nPos
, "Error in stream arithmetic!\n" );
999 void UCBStorageStream_Impl::SetSize( sal_uLong nSize
)
1001 if ( !(m_nMode
& STREAM_WRITE
) )
1003 SetError( ERRCODE_IO_ACCESSDENIED
);
1014 sal_uLong aPos
= m_pStream
->Tell();
1015 m_pStream
->Seek( STREAM_SEEK_TO_END
);
1016 if( m_pStream
->Tell() < nSize
)
1017 ReadSourceWriteTemporary( nSize
- m_pStream
->Tell() );
1018 m_pStream
->Seek( aPos
);
1021 m_pStream
->SetStreamSize( nSize
);
1022 m_bSourceRead
= false;
1025 void UCBStorageStream_Impl::FlushData()
1029 CopySourceToTemporary();
1036 void UCBStorageStream_Impl::SetError( sal_uInt32 nErr
)
1041 SvStream::SetError( nErr
);
1042 if ( m_pAntiImpl
) m_pAntiImpl
->SetError( nErr
);
1046 void UCBStorageStream_Impl::ResetError()
1049 SvStream::ResetError();
1051 m_pAntiImpl
->ResetError();
1054 sal_uLong
UCBStorageStream_Impl::GetSize()
1059 sal_uLong nPos
= m_pStream
->Tell();
1060 m_pStream
->Seek( STREAM_SEEK_TO_END
);
1061 ReadSourceWriteTemporary();
1062 sal_uLong nRet
= m_pStream
->Tell();
1063 m_pStream
->Seek( nPos
);
1068 BaseStorage
* UCBStorageStream_Impl::CreateStorage()
1070 // create an OLEStorage on a SvStream ( = this )
1071 // it gets the root attribute because otherwise it would probably not write before my root is commited
1072 UCBStorageStream
* pNewStorageStream
= new UCBStorageStream( this );
1073 Storage
*pStorage
= new Storage( *pNewStorageStream
, m_bDirect
);
1075 // GetError() call cleares error code for OLE storages, must be changed in future
1076 long nTmpErr
= pStorage
->GetError();
1077 pStorage
->SetError( nTmpErr
);
1079 m_bIsOLEStorage
= !nTmpErr
;
1080 return static_cast< BaseStorage
* > ( pStorage
);
1083 sal_Int16
UCBStorageStream_Impl::Commit()
1085 // send stream to the original content
1086 // the parent storage is responsible for the correct handling of deleted contents
1087 if ( m_bCommited
|| m_bIsOLEStorage
|| m_bDirect
)
1089 // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1090 // was commited as well ( if not opened in direct mode )
1096 CopySourceToTemporary();
1098 // release all stream handles
1101 // the temporary file does not exist only for truncated streams
1102 DBG_ASSERT( !m_aTempURL
.isEmpty() || ( m_nMode
& STREAM_TRUNC
), "No temporary file to read from!");
1103 if ( m_aTempURL
.isEmpty() && !( m_nMode
& STREAM_TRUNC
) )
1104 throw RuntimeException();
1106 // create wrapper to stream that is only used while reading inside package component
1107 Reference
< XInputStream
> xStream
= new FileStreamWrapper_Impl( m_aTempURL
);
1110 InsertCommandArgument aArg
;
1111 aArg
.Data
= xStream
;
1112 aArg
.ReplaceExisting
= true;
1114 m_pContent
->executeCommand( OUString("insert"), aAny
);
1116 // wrapper now controls lifetime of temporary file
1119 INetURLObject
aObj( m_aURL
);
1120 aObj
.SetName( m_aName
);
1121 m_aURL
= aObj
.GetMainURL( INetURLObject::NO_DECODE
);
1122 m_bModified
= false;
1123 m_bSourceRead
= true;
1125 catch (const CommandAbortedException
&)
1127 // any command wasn't executed successfully - not specified
1128 SetError( ERRCODE_IO_GENERAL
);
1129 return COMMIT_RESULT_FAILURE
;
1131 catch (const RuntimeException
&)
1133 // any other error - not specified
1134 SetError( ERRCODE_IO_GENERAL
);
1135 return COMMIT_RESULT_FAILURE
;
1137 catch (const Exception
&)
1139 // any other error - not specified
1140 SetError( ERRCODE_IO_GENERAL
);
1141 return COMMIT_RESULT_FAILURE
;
1144 m_bCommited
= false;
1145 return COMMIT_RESULT_SUCCESS
;
1149 return COMMIT_RESULT_NOTHING_TO_DO
;
1152 bool UCBStorageStream_Impl::Revert()
1154 // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
1157 OSL_FAIL("Revert while commit is in progress!" );
1158 return false; // ???
1162 if ( !m_aTempURL
.isEmpty() )
1164 ::utl::UCBContentHelper::Kill( m_aTempURL
);
1168 m_bSourceRead
= false;
1171 m_rSource
= m_pContent
->openStream();
1172 if( m_rSource
.is() )
1174 if ( m_pAntiImpl
&& ( m_nMode
& STREAM_TRUNC
) )
1175 // stream is in use and should be truncated
1176 m_bSourceRead
= false;
1179 m_nMode
&= ~STREAM_TRUNC
;
1180 m_bSourceRead
= true;
1184 SetError( SVSTREAM_CANNOT_MAKE
);
1186 catch (const ContentCreationException
&)
1188 SetError( ERRCODE_IO_GENERAL
);
1190 catch (const RuntimeException
&)
1192 SetError( ERRCODE_IO_GENERAL
);
1194 catch (const Exception
&)
1198 m_bModified
= false;
1199 m_aName
= m_aOriginalName
;
1200 m_aContentType
= m_aOriginalContentType
;
1201 return ( GetError() == ERRCODE_NONE
);
1204 bool UCBStorageStream_Impl::Clear()
1206 bool bRet
= ( m_pAntiImpl
== NULL
);
1207 DBG_ASSERT( bRet
, "Removing used stream!" );
1216 void UCBStorageStream_Impl::Free()
1218 #if OSL_DEBUG_LEVEL > 1
1221 if ( !m_aTempURL
.isEmpty() )
1228 m_nRepresentMode
= nonset
;
1230 DELETEZ( m_pStream
);
1233 void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode
)
1235 bool isWritable
= (( m_nMode
& STREAM_WRITE
) != 0 );
1238 // once stream was writable, never reset to readonly
1239 nMode
|= STREAM_WRITE
;
1245 if ( nMode
& STREAM_TRUNC
)
1247 m_bSourceRead
= 0; // usually it should be 0 already but just in case...
1249 if ( !m_aTempURL
.isEmpty() )
1251 ::utl::UCBContentHelper::Kill( m_aTempURL
);
1257 UCBStorageStream::UCBStorageStream( const OUString
& rName
, StreamMode nMode
, bool bDirect
, const OString
* pKey
, bool bRepair
, Reference
< XProgressHandler
> xProgress
)
1259 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1260 // to class UCBStorageStream !
1261 pImp
= new UCBStorageStream_Impl( rName
, nMode
, this, bDirect
, pKey
, bRepair
, xProgress
);
1262 pImp
->AddRef(); // use direct refcounting because in header file only a pointer should be used
1263 StorageBase::m_nMode
= pImp
->m_nMode
;
1266 UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl
*pImpl
)
1269 pImp
->AddRef(); // use direct refcounting because in header file only a pointer should be used
1270 pImp
->m_pAntiImpl
= this;
1271 SetError( pImp
->m_nError
);
1272 StorageBase::m_nMode
= pImp
->m_nMode
;
1275 UCBStorageStream::~UCBStorageStream()
1277 if ( pImp
->m_nMode
& STREAM_WRITE
)
1279 pImp
->m_pAntiImpl
= NULL
;
1284 sal_uLong
UCBStorageStream::Read( void * pData
, sal_uLong nSize
)
1286 //return pImp->m_pStream->Read( pData, nSize );
1287 return pImp
->GetData( pData
, nSize
);
1290 sal_uLong
UCBStorageStream::Write( const void* pData
, sal_uLong nSize
)
1292 return pImp
->PutData( pData
, nSize
);
1295 sal_uLong
UCBStorageStream::Seek( sal_uLong nPos
)
1297 //return pImp->m_pStream->Seek( nPos );
1298 return pImp
->Seek( nPos
);
1301 sal_uLong
UCBStorageStream::Tell()
1305 return pImp
->m_pStream
->Tell();
1308 void UCBStorageStream::Flush()
1310 // streams are never really transacted, so flush also means commit !
1314 bool UCBStorageStream::SetSize( sal_uLong nNewSize
)
1316 pImp
->SetSize( nNewSize
);
1317 return !pImp
->GetError();
1320 bool UCBStorageStream::Validate( bool bWrite
) const
1322 return ( !bWrite
|| ( pImp
->m_nMode
& STREAM_WRITE
) );
1325 bool UCBStorageStream::ValidateMode( StreamMode m
) const
1328 if( m
== ( STREAM_READ
| STREAM_TRUNC
) ) // from stg.cxx
1330 sal_uInt16 nCurMode
= 0xFFFF;
1331 if( ( m
& 3 ) == STREAM_READ
)
1333 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1334 if( ( ( m
& STREAM_SHARE_DENYWRITE
)
1335 && ( nCurMode
& STREAM_SHARE_DENYWRITE
) )
1336 || ( ( m
& STREAM_SHARE_DENYALL
)
1337 && ( nCurMode
& STREAM_SHARE_DENYALL
) ) )
1342 // only SHARE_DENYALL allowed
1343 // storages open in r/o mode are OK, since only
1344 // the commit may fail
1345 if( ( m
& STREAM_SHARE_DENYALL
)
1346 && ( nCurMode
& STREAM_SHARE_DENYALL
) )
1353 const SvStream
* UCBStorageStream::GetSvStream() const
1358 pImp
->CopySourceToTemporary();
1359 return pImp
->m_pStream
; // should not live longer then pImp!!!
1362 SvStream
* UCBStorageStream::GetModifySvStream()
1364 return (SvStream
*)pImp
;
1367 bool UCBStorageStream::Equals( const BaseStorageStream
& rStream
) const
1370 return ((BaseStorageStream
*) this ) == &rStream
;
1373 bool UCBStorageStream::Commit()
1375 // mark this stream for sending it on root commit
1380 bool UCBStorageStream::Revert()
1382 return pImp
->Revert();
1385 bool UCBStorageStream::CopyTo( BaseStorageStream
* pDestStm
)
1390 UCBStorageStream
* pStg
= PTR_CAST( UCBStorageStream
, pDestStm
);
1392 pStg
->pImp
->m_aContentType
= pImp
->m_aContentType
;
1394 pDestStm
->SetSize( 0 );
1395 Seek( STREAM_SEEK_TO_END
);
1396 sal_Int32 n
= Tell();
1400 if( pDestStm
->SetSize( n
) && n
)
1402 sal_uInt8
* p
= new sal_uInt8
[ 4096 ];
1404 pDestStm
->Seek( 0L );
1410 if( Read( p
, nn
) != nn
)
1412 if( pDestStm
->Write( p
, nn
) != nn
)
1423 bool UCBStorageStream::SetProperty( const OUString
& rName
, const ::com::sun::star::uno::Any
& rValue
)
1425 if ( rName
== "Title")
1428 if ( rName
== "MediaType")
1432 pImp
->m_aContentType
= aTmp
;
1437 if ( pImp
->m_pContent
)
1439 pImp
->m_pContent
->setPropertyValue( rName
, rValue
);
1443 catch (const Exception
&)
1450 sal_uLong
UCBStorageStream::GetSize() const
1452 return pImp
->GetSize();
1455 UCBStorage::UCBStorage( SvStream
& rStrm
, bool bDirect
)
1457 OUString aURL
= GetLinkedFile( rStrm
);
1458 if ( !aURL
.isEmpty() )
1460 StreamMode nMode
= STREAM_READ
;
1461 if( rStrm
.IsWritable() )
1462 nMode
= STREAM_READ
| STREAM_WRITE
;
1464 ::ucbhelper::Content
aContent( aURL
, Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
1465 pImp
= new UCBStorage_Impl( aContent
, aURL
, nMode
, this, bDirect
, true );
1469 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1470 // to class UCBStorage !
1471 pImp
= new UCBStorage_Impl( rStrm
, this, bDirect
);
1476 StorageBase::m_nMode
= pImp
->m_nMode
;
1479 UCBStorage::UCBStorage( const ::ucbhelper::Content
& rContent
, const OUString
& rName
, StreamMode nMode
, bool bDirect
, bool bIsRoot
)
1481 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1482 // to class UCBStorage !
1483 pImp
= new UCBStorage_Impl( rContent
, rName
, nMode
, this, bDirect
, bIsRoot
);
1486 StorageBase::m_nMode
= pImp
->m_nMode
;
1489 UCBStorage::UCBStorage( const OUString
& rName
, StreamMode nMode
, bool bDirect
, bool bIsRoot
, bool bIsRepair
, Reference
< XProgressHandler
> xProgressHandler
)
1491 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1492 // to class UCBStorage !
1493 pImp
= new UCBStorage_Impl( rName
, nMode
, this, bDirect
, bIsRoot
, bIsRepair
, xProgressHandler
);
1496 StorageBase::m_nMode
= pImp
->m_nMode
;
1499 UCBStorage::UCBStorage( const OUString
& rName
, StreamMode nMode
, bool bDirect
, bool bIsRoot
)
1501 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1502 // to class UCBStorage !
1503 pImp
= new UCBStorage_Impl( rName
, nMode
, this, bDirect
, bIsRoot
, false, Reference
< XProgressHandler
>() );
1506 StorageBase::m_nMode
= pImp
->m_nMode
;
1509 UCBStorage::UCBStorage( UCBStorage_Impl
*pImpl
)
1512 pImp
->m_pAntiImpl
= this;
1513 SetError( pImp
->m_nError
);
1514 pImp
->AddRef(); // use direct refcounting because in header file only a pointer should be used
1515 StorageBase::m_nMode
= pImp
->m_nMode
;
1518 UCBStorage::~UCBStorage()
1520 if ( pImp
->m_bIsRoot
&& pImp
->m_bDirect
&& ( !pImp
->m_pTempFile
|| pImp
->m_pSource
) )
1521 // DirectMode is simulated with an AutoCommit
1524 pImp
->m_pAntiImpl
= NULL
;
1528 UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content
& rContent
, const OUString
& rName
, StreamMode nMode
, UCBStorage
* pStorage
, bool bDirect
, bool bIsRoot
, bool bIsRepair
, Reference
< XProgressHandler
> xProgressHandler
)
1529 : m_pAntiImpl( pStorage
)
1530 , m_pContent( new ::ucbhelper::Content( rContent
) )
1531 , m_pTempFile( NULL
)
1533 //, m_pStream( NULL )
1536 , m_bModified( false )
1537 , m_bCommited( false )
1538 , m_bDirect( bDirect
)
1539 , m_bIsRoot( bIsRoot
)
1541 , m_bIsLinked( true )
1542 , m_bListCreated( false )
1544 , m_aClassId( SvGlobalName() )
1545 , m_bRepairPackage( bIsRepair
)
1546 , m_xProgressHandler( xProgressHandler
)
1548 OUString
aName( rName
);
1549 if( aName
.isEmpty() )
1551 // no name given = use temporary name!
1552 DBG_ASSERT( m_bIsRoot
, "SubStorage must have a name!" );
1553 m_pTempFile
= new ::utl::TempFile
;
1554 m_pTempFile
->EnableKillingFile( true );
1555 m_aName
= m_aOriginalName
= aName
= m_pTempFile
->GetURL();
1561 UCBStorage_Impl::UCBStorage_Impl( const OUString
& rName
, StreamMode nMode
, UCBStorage
* pStorage
, bool bDirect
, bool bIsRoot
, bool bIsRepair
, Reference
< XProgressHandler
> xProgressHandler
)
1562 : m_pAntiImpl( pStorage
)
1563 , m_pContent( NULL
)
1564 , m_pTempFile( NULL
)
1566 //, m_pStream( NULL )
1569 , m_bModified( false )
1570 , m_bCommited( false )
1571 , m_bDirect( bDirect
)
1572 , m_bIsRoot( bIsRoot
)
1574 , m_bIsLinked( false )
1575 , m_bListCreated( false )
1577 , m_aClassId( SvGlobalName() )
1578 , m_bRepairPackage( bIsRepair
)
1579 , m_xProgressHandler( xProgressHandler
)
1581 OUString
aName( rName
);
1582 if( aName
.isEmpty() )
1584 // no name given = use temporary name!
1585 DBG_ASSERT( m_bIsRoot
, "SubStorage must have a name!" );
1586 m_pTempFile
= new ::utl::TempFile
;
1587 m_pTempFile
->EnableKillingFile( true );
1588 m_aName
= m_aOriginalName
= aName
= m_pTempFile
->GetURL();
1593 // create the special package URL for the package content
1594 OUString aTemp
= "vnd.sun.star.pkg://";
1595 aTemp
+= INetURLObject::encode( aName
, INetURLObject::PART_AUTHORITY
, '%', INetURLObject::ENCODE_ALL
);
1598 if ( m_nMode
& STREAM_WRITE
)
1600 // the root storage opens the package, so make sure that there is any
1601 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( aName
, STREAM_STD_READWRITE
, m_pTempFile
!= 0 /* bFileExists */ );
1607 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1609 if ( !m_aURL
.startsWith( "vnd.sun.star.pkg://") )
1614 UCBStorage_Impl::UCBStorage_Impl( SvStream
& rStream
, UCBStorage
* pStorage
, bool bDirect
)
1615 : m_pAntiImpl( pStorage
)
1616 , m_pContent( NULL
)
1617 , m_pTempFile( new ::utl::TempFile
)
1618 , m_pSource( &rStream
)
1620 , m_bModified( false )
1621 , m_bCommited( false )
1622 , m_bDirect( bDirect
)
1625 , m_bIsLinked( false )
1626 , m_bListCreated( false )
1628 , m_aClassId( SvGlobalName() )
1629 , m_bRepairPackage( false )
1631 // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1632 // which will be called in the storages' dtor
1633 m_pTempFile
->EnableKillingFile( true );
1634 DBG_ASSERT( !bDirect
, "Storage on a stream must not be opened in direct mode!" );
1636 // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1637 // accessed readonly
1638 // the root storage opens the package; create the special package URL for the package content
1639 OUString aTemp
= "vnd.sun.star.pkg://";
1640 aTemp
+= INetURLObject::encode( m_pTempFile
->GetURL(), INetURLObject::PART_AUTHORITY
, '%', INetURLObject::ENCODE_ALL
);
1643 // copy data into the temporary file
1644 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( m_pTempFile
->GetURL(), STREAM_STD_READWRITE
, true /* bFileExists */ );
1648 rStream
>> *pStream
;
1653 // close stream and let content access the file
1656 // check opening mode
1657 m_nMode
= STREAM_READ
;
1658 if( rStream
.IsWritable() )
1659 m_nMode
= STREAM_READ
| STREAM_WRITE
;
1662 void UCBStorage_Impl::Init()
1664 // name is last segment in URL
1665 INetURLObject
aObj( m_aURL
);
1666 if ( m_aName
.isEmpty() )
1667 // if the name was not already set to a temp name
1668 m_aName
= m_aOriginalName
= aObj
.GetLastName();
1670 // don't create the content for disk spanned files, avoid too early access to directory and/or manifest
1671 if ( !m_pContent
&& !( m_nMode
& STORAGE_DISKSPANNED_MODE
) )
1674 if ( m_nMode
& STORAGE_DISKSPANNED_MODE
)
1676 // Hack! Avoid access to the manifest file until mediatype is not available in the first segment of a
1677 // disk spanned file
1678 m_aContentType
= m_aOriginalContentType
= "application/vnd.sun.xml.impress";
1680 else if ( m_pContent
)
1687 if ( m_nError
== ERRCODE_NONE
)
1689 // read the manifest.xml file
1690 aObj
.Append( OUString( "META-INF" ) );
1691 aObj
.Append( OUString( "manifest.xml" ) );
1693 // create input stream
1694 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( aObj
.GetMainURL( INetURLObject::NO_DECODE
), STREAM_STD_READ
);
1695 // no stream means no manifest.xml
1698 if ( !pStream
->GetError() )
1700 ::utl::OInputStreamWrapper
* pHelper
= new ::utl::OInputStreamWrapper( *pStream
);
1701 com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> xInputStream( pHelper
);
1703 // create a manifest reader object that will read in the manifest from the stream
1704 Reference
< ::com::sun::star::packages::manifest::XManifestReader
> xReader
=
1705 ::com::sun::star::packages::manifest::ManifestReader::create(
1706 ::comphelper::getProcessComponentContext() ) ;
1707 Sequence
< Sequence
< PropertyValue
> > aProps
= xReader
->readManifestSequence( xInputStream
);
1711 xInputStream
= NULL
;
1712 SetProps( aProps
, OUString() );
1724 // get the manifest information from the package
1726 Any aAny
= m_pContent
->getPropertyValue("MediaType");
1728 if ( ( aAny
>>= aTmp
) && !aTmp
.isEmpty() )
1729 m_aContentType
= m_aOriginalContentType
= aTmp
;
1731 catch (const Exception
&)
1734 "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1739 if ( !m_aContentType
.isEmpty() )
1741 // get the clipboard format using the content type
1742 ::com::sun::star::datatransfer::DataFlavor aDataFlavor
;
1743 aDataFlavor
.MimeType
= m_aContentType
;
1744 m_nFormat
= SotExchange::GetFormat( aDataFlavor
);
1746 // get the ClassId using the clipboard format ( internal table )
1747 m_aClassId
= GetClassId_Impl( m_nFormat
);
1749 // get human presentable name using the clipboard format
1750 SotExchange::GetFormatDataFlavor( m_nFormat
, aDataFlavor
);
1751 m_aUserTypeName
= aDataFlavor
.HumanPresentableName
;
1753 if( m_pContent
&& !m_bIsLinked
&& m_aClassId
!= SvGlobalName() )
1758 void UCBStorage_Impl::CreateContent()
1762 // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1763 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
1765 OUString
aTemp( m_aURL
);
1767 if ( m_bRepairPackage
)
1769 xComEnv
= new ::ucbhelper::CommandEnvironment( Reference
< ::com::sun::star::task::XInteractionHandler
>(),
1770 m_xProgressHandler
);
1771 aTemp
+= "?repairpackage";
1774 m_pContent
= new ::ucbhelper::Content( aTemp
, xComEnv
, comphelper::getProcessComponentContext() );
1776 catch (const ContentCreationException
&)
1778 // content could not be created
1779 SetError( SVSTREAM_CANNOT_MAKE
);
1781 catch (const RuntimeException
&)
1783 // any other error - not specified
1784 SetError( SVSTREAM_CANNOT_MAKE
);
1788 void UCBStorage_Impl::ReadContent()
1790 if ( m_bListCreated
)
1793 m_bListCreated
= true;
1795 // create cursor for access to children
1796 Sequence
< OUString
> aProps(4);
1797 aProps
[0] = "Title";
1798 aProps
[1] = "IsFolder";
1799 aProps
[2] = "MediaType";
1801 ::ucbhelper::ResultSetInclude eInclude
= ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS
;
1809 Reference
< XResultSet
> xResultSet
= m_pContent
->createCursor( aProps
, eInclude
);
1810 Reference
< XContentAccess
> xContentAccess( xResultSet
, UNO_QUERY
);
1811 Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
1812 if ( xResultSet
.is() )
1814 while ( xResultSet
->next() )
1816 // insert all into the children list
1817 OUString
aTitle( xRow
->getString(1) );
1818 OUString aContentType
;
1821 // unpacked storages have to deal with the meta-inf folder by themselves
1822 if ( aTitle
== "META-INF" )
1827 aContentType
= xRow
->getString(3);
1830 bool bIsFolder( xRow
->getBoolean(2) );
1831 sal_Int64 nSize
= xRow
->getLong(4);
1832 UCBStorageElement_Impl
* pElement
= new UCBStorageElement_Impl( aTitle
, bIsFolder
, (sal_uLong
) nSize
);
1833 m_aChildrenList
.push_back( pElement
);
1835 bool bIsOfficeDocument
= m_bIsLinked
|| ( m_aClassId
!= SvGlobalName() );
1839 OpenStorage( pElement
, m_nMode
, m_bDirect
);
1840 if ( pElement
->m_xStorage
.Is() )
1841 pElement
->m_xStorage
->Init();
1843 else if ( bIsOfficeDocument
)
1845 // streams can be external OLE objects, so they are now folders, but storages!
1846 OUString
aName( m_aURL
+ OUString("/") + xRow
->getString(1));
1848 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
1849 if ( m_bRepairPackage
)
1851 xComEnv
= new ::ucbhelper::CommandEnvironment( Reference
< ::com::sun::star::task::XInteractionHandler
>(),
1852 m_xProgressHandler
);
1853 aName
+= "?repairpackage";
1856 ::ucbhelper::Content
aContent( aName
, xComEnv
, comphelper::getProcessComponentContext() );
1858 OUString aMediaType
;
1859 Any aAny
= aContent
.getPropertyValue("MediaType");
1860 if ( ( aAny
>>= aMediaType
) && ( aMediaType
== "application/vnd.sun.star.oleobject" ) )
1861 pElement
->m_bIsStorage
= true;
1862 else if ( aMediaType
.isEmpty() )
1864 // older files didn't have that special content type, so they must be detected
1865 OpenStream( pElement
, STREAM_STD_READ
, m_bDirect
);
1866 if ( Storage::IsStorageFile( pElement
->m_xStream
) )
1867 pElement
->m_bIsStorage
= true;
1869 pElement
->m_xStream
->Free();
1875 catch (const InteractiveIOException
& r
)
1877 if ( r
.Code
!= IOErrorCode_NOT_EXISTING
)
1878 SetError( ERRCODE_IO_GENERAL
);
1880 catch (const CommandAbortedException
&)
1882 // any command wasn't executed successfully - not specified
1883 if ( !( m_nMode
& STREAM_WRITE
) )
1884 // if the folder was just inserted and not already commited, this is not an error!
1885 SetError( ERRCODE_IO_GENERAL
);
1887 catch (const RuntimeException
&)
1889 // any other error - not specified
1890 SetError( ERRCODE_IO_GENERAL
);
1892 catch (const ResultSetException
&)
1894 // means that the package file is broken
1895 SetError( ERRCODE_IO_BROKENPACKAGE
);
1897 catch (const SQLException
&)
1899 // means that the file can be broken
1900 SetError( ERRCODE_IO_WRONGFORMAT
);
1902 catch (const Exception
&)
1904 // any other error - not specified
1905 SetError( ERRCODE_IO_GENERAL
);
1909 void UCBStorage_Impl::SetError( long nError
)
1914 if ( m_pAntiImpl
) m_pAntiImpl
->SetError( nError
);
1918 sal_Int32
UCBStorage_Impl::GetObjectCount()
1920 sal_Int32 nCount
= m_aChildrenList
.size();
1921 for ( size_t i
= 0; i
< m_aChildrenList
.size(); ++i
)
1923 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
1924 DBG_ASSERT( !pElement
->m_bIsFolder
|| pElement
->m_xStorage
.Is(), "Storage should be open!" );
1925 if ( pElement
->m_bIsFolder
&& pElement
->m_xStorage
.Is() )
1926 nCount
+= pElement
->m_xStorage
->GetObjectCount();
1932 OUString
Find_Impl( const Sequence
< Sequence
< PropertyValue
> >& rSequence
, const OUString
& rPath
)
1934 bool bFound
= false;
1935 for ( sal_Int32 nSeqs
=0; nSeqs
<rSequence
.getLength(); nSeqs
++ )
1937 const Sequence
< PropertyValue
>& rMyProps
= rSequence
[nSeqs
];
1940 for ( sal_Int32 nProps
=0; nProps
<rMyProps
.getLength(); nProps
++ )
1942 const PropertyValue
& rAny
= rMyProps
[nProps
];
1943 if ( rAny
.Name
== "FullPath" )
1946 if ( ( rAny
.Value
>>= aTmp
) && aTmp
== rPath
)
1948 if ( !aType
.isEmpty() )
1951 else if ( rAny
.Name
== "MediaType" )
1953 if ( ( rAny
.Value
>>= aType
) && !aType
.isEmpty() && bFound
)
1965 void UCBStorage_Impl::SetProps( const Sequence
< Sequence
< PropertyValue
> >& rSequence
, const OUString
& rPath
)
1967 OUString
aPath( rPath
);
1972 m_aContentType
= m_aOriginalContentType
= Find_Impl( rSequence
, aPath
);
1975 // the "FullPath" of a child always starts without '/'
1978 for ( size_t i
= 0; i
< m_aChildrenList
.size(); ++i
)
1980 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
1981 DBG_ASSERT( !pElement
->m_bIsFolder
|| pElement
->m_xStorage
.Is(), "Storage should be open!" );
1982 if ( pElement
->m_bIsFolder
&& pElement
->m_xStorage
.Is() )
1983 pElement
->m_xStorage
->SetProps( rSequence
, aPath
);
1986 OUString
aElementPath( aPath
);
1987 aElementPath
+= pElement
->m_aName
;
1988 pElement
->SetContentType( Find_Impl( rSequence
, aElementPath
) );
1992 if ( !m_aContentType
.isEmpty() )
1994 // get the clipboard format using the content type
1995 ::com::sun::star::datatransfer::DataFlavor aDataFlavor
;
1996 aDataFlavor
.MimeType
= m_aContentType
;
1997 m_nFormat
= SotExchange::GetFormat( aDataFlavor
);
1999 // get the ClassId using the clipboard format ( internal table )
2000 m_aClassId
= GetClassId_Impl( m_nFormat
);
2002 // get human presentable name using the clipboard format
2003 SotExchange::GetFormatDataFlavor( m_nFormat
, aDataFlavor
);
2004 m_aUserTypeName
= aDataFlavor
.HumanPresentableName
;
2008 void UCBStorage_Impl::GetProps( sal_Int32
& nProps
, Sequence
< Sequence
< PropertyValue
> >& rSequence
, const OUString
& rPath
)
2010 // first my own properties
2011 Sequence
< PropertyValue
> aProps(2);
2013 // first property is the "FullPath" name
2014 // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
2015 OUString
aPath( rPath
);
2019 aProps
[0].Name
= "MediaType";
2020 aProps
[0].Value
<<= (OUString
) m_aContentType
;
2021 aProps
[1].Name
= "FullPath";
2022 aProps
[1].Value
<<= (OUString
) aPath
;
2023 rSequence
[ nProps
++ ] = aProps
;
2026 // the "FullPath" of a child always starts without '/'
2029 // now the properties of my elements
2030 for ( size_t i
= 0; i
< m_aChildrenList
.size(); ++i
)
2032 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
2033 DBG_ASSERT( !pElement
->m_bIsFolder
|| pElement
->m_xStorage
.Is(), "Storage should be open!" );
2034 if ( pElement
->m_bIsFolder
&& pElement
->m_xStorage
.Is() )
2035 // storages add there properties by themselves ( see above )
2036 pElement
->m_xStorage
->GetProps( nProps
, rSequence
, aPath
);
2039 // properties of streams
2040 OUString
aElementPath( aPath
);
2041 aElementPath
+= pElement
->m_aName
;
2042 aProps
[0].Name
= "MediaType";
2043 aProps
[0].Value
<<= (OUString
) pElement
->GetContentType();
2044 aProps
[1].Name
= "FullPath";
2045 aProps
[1].Value
<<= (OUString
) aElementPath
;
2046 rSequence
[ nProps
++ ] = aProps
;
2051 UCBStorage_Impl::~UCBStorage_Impl()
2053 // first delete elements!
2054 for ( size_t i
= 0, n
= m_aChildrenList
.size(); i
< n
; ++i
)
2055 delete m_aChildrenList
[ i
];
2056 m_aChildrenList
.clear();
2062 bool UCBStorage_Impl::Insert( ::ucbhelper::Content
*pContent
)
2064 // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
2065 // it must be inserted with a title and a type
2070 Sequence
< ContentInfo
> aInfo
= pContent
->queryCreatableContentsInfo();
2071 sal_Int32 nCount
= aInfo
.getLength();
2075 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
2077 // Simply look for the first KIND_FOLDER...
2078 const ContentInfo
& rCurr
= aInfo
[i
];
2079 if ( rCurr
.Attributes
& ContentInfoAttribute::KIND_FOLDER
)
2081 // Make sure the only required bootstrap property is "Title",
2082 const Sequence
< Property
> & rProps
= rCurr
.Properties
;
2083 if ( rProps
.getLength() != 1 )
2086 if ( rProps
[ 0 ].Name
!= "Title" )
2089 Sequence
< OUString
> aNames(1);
2090 aNames
[0] = "Title";
2091 Sequence
< Any
> aValues(1);
2092 aValues
[0] = makeAny( OUString( m_aName
) );
2095 if ( !pContent
->insertNewContent( rCurr
.Type
, aNames
, aValues
, aNewFolder
) )
2098 // remove old content, create an "empty" new one and initialize it with the new inserted
2099 DELETEZ( m_pContent
);
2100 m_pContent
= new ::ucbhelper::Content( aNewFolder
);
2105 catch (const CommandAbortedException
&)
2107 // any command wasn't executed successfully - not specified
2108 SetError( ERRCODE_IO_GENERAL
);
2110 catch (const RuntimeException
&)
2112 // any other error - not specified
2113 SetError( ERRCODE_IO_GENERAL
);
2115 catch (const Exception
&)
2117 // any other error - not specified
2118 SetError( ERRCODE_IO_GENERAL
);
2124 sal_Int16
UCBStorage_Impl::Commit()
2126 // send all changes to the package
2127 sal_Int16 nRet
= COMMIT_RESULT_NOTHING_TO_DO
;
2129 // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
2130 // commit command has been sent
2131 if ( ( m_nMode
& STREAM_WRITE
) && ( m_bCommited
|| m_bDirect
) )
2135 // all errors will be caught in the "catch" statement outside the loop
2136 for ( size_t i
= 0; i
< m_aChildrenList
.size() && nRet
; ++i
)
2138 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
2139 ::ucbhelper::Content
* pContent
= pElement
->GetContent();
2140 boost::scoped_ptr
< ::ucbhelper::Content
> xDeleteContent
;
2141 if ( !pContent
&& pElement
->IsModified() )
2143 // if the element has never been opened, no content has been created until now
2144 OUString
aName( m_aURL
);
2146 aName
+= pElement
->m_aOriginalName
;
2147 pContent
= new ::ucbhelper::Content( aName
, Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
2148 xDeleteContent
.reset(pContent
); // delete it later on exit scope
2151 if ( pElement
->m_bIsRemoved
)
2153 // was it inserted, then removed (so there would be nothing to do!)
2154 if ( !pElement
->m_bIsInserted
)
2156 // first remove all open stream handles
2157 if( !pElement
->m_xStream
.Is() || pElement
->m_xStream
->Clear() )
2159 pContent
->executeCommand( OUString("delete"), makeAny( sal_Bool( sal_True
) ) );
2160 nRet
= COMMIT_RESULT_SUCCESS
;
2163 // couldn't release stream because there are external references to it
2164 nRet
= COMMIT_RESULT_FAILURE
;
2169 sal_Int16 nLocalRet
= COMMIT_RESULT_NOTHING_TO_DO
;
2170 if ( pElement
->m_xStorage
.Is() )
2172 // element is a storage
2173 // do a commit in the following cases:
2174 // - if storage is already inserted, and changed
2175 // - storage is not in a package
2176 // - it's a new storage, try to insert and commit if successful inserted
2177 if ( !pElement
->m_bIsInserted
|| m_bIsLinked
|| pElement
->m_xStorage
->Insert( m_pContent
) )
2179 nLocalRet
= pElement
->m_xStorage
->Commit();
2180 pContent
= pElement
->GetContent();
2183 else if ( pElement
->m_xStream
.Is() )
2185 // element is a stream
2186 nLocalRet
= pElement
->m_xStream
->Commit();
2187 if ( pElement
->m_xStream
->m_bIsOLEStorage
)
2189 // OLE storage should be stored encrytped, if the storage uses encryption
2190 pElement
->m_xStream
->m_aContentType
= "application/vnd.sun.star.oleobject";
2192 aValue
<<= (sal_Bool
)sal_True
;
2193 pElement
->m_xStream
->m_pContent
->setPropertyValue("Encrypted", aValue
);
2196 pContent
= pElement
->GetContent();
2199 if ( pElement
->m_aName
!= pElement
->m_aOriginalName
)
2201 // name ( title ) of the element was changed
2202 nLocalRet
= COMMIT_RESULT_SUCCESS
;
2204 aAny
<<= (OUString
) pElement
->m_aName
;
2205 pContent
->setPropertyValue("Title", aAny
);
2208 if ( pElement
->IsLoaded() && pElement
->GetContentType() != pElement
->GetOriginalContentType() )
2210 // mediatype of the element was changed
2211 nLocalRet
= COMMIT_RESULT_SUCCESS
;
2213 aAny
<<= (OUString
) pElement
->GetContentType();
2214 pContent
->setPropertyValue("MediaType", aAny
);
2217 if ( nLocalRet
!= COMMIT_RESULT_NOTHING_TO_DO
)
2221 if ( nRet
== COMMIT_RESULT_FAILURE
)
2225 catch (const ContentCreationException
&)
2227 // content could not be created
2228 SetError( ERRCODE_IO_NOTEXISTS
);
2229 return COMMIT_RESULT_FAILURE
;
2231 catch (const CommandAbortedException
&)
2233 // any command wasn't executed successfully - not specified
2234 SetError( ERRCODE_IO_GENERAL
);
2235 return COMMIT_RESULT_FAILURE
;
2237 catch (const RuntimeException
&)
2239 // any other error - not specified
2240 SetError( ERRCODE_IO_GENERAL
);
2241 return COMMIT_RESULT_FAILURE
;
2243 catch (const Exception
&)
2245 // any other error - not specified
2246 SetError( ERRCODE_IO_GENERAL
);
2247 return COMMIT_RESULT_FAILURE
;
2250 if ( m_bIsRoot
&& m_pContent
)
2252 // the root storage must flush the root package content
2253 if ( nRet
== COMMIT_RESULT_SUCCESS
)
2257 // commit the media type to the JAR file
2258 // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2260 aType
<<= (OUString
) m_aContentType
;
2261 m_pContent
->setPropertyValue("MediaType", aType
);
2265 // write a manifest file
2266 // first create a subfolder "META-inf"
2267 Content aNewSubFolder
;
2268 bool bRet
= ::utl::UCBContentHelper::MakeFolder( *m_pContent
, OUString("META-INF"), aNewSubFolder
);
2271 // create a stream to write the manifest file - use a temp file
2272 OUString
aURL( aNewSubFolder
.getURL() );
2273 ::utl::TempFile
* pTempFile
= new ::utl::TempFile( &aURL
);
2275 // get the stream from the temp file and create an output stream wrapper
2276 SvStream
* pStream
= pTempFile
->GetStream( STREAM_STD_READWRITE
);
2277 ::utl::OOutputStreamWrapper
* pHelper
= new ::utl::OOutputStreamWrapper( *pStream
);
2278 com::sun::star::uno::Reference
< ::com::sun::star::io::XOutputStream
> xOutputStream( pHelper
);
2280 // create a manifest writer object that will fill the stream
2281 Reference
< ::com::sun::star::packages::manifest::XManifestWriter
> xWriter
=
2282 ::com::sun::star::packages::manifest::ManifestWriter::create(
2283 ::comphelper::getProcessComponentContext() );
2284 sal_Int32 nCount
= GetObjectCount() + 1;
2285 Sequence
< Sequence
< PropertyValue
> > aProps( nCount
);
2286 sal_Int32 nProps
= 0;
2287 GetProps( nProps
, aProps
, OUString() );
2288 xWriter
->writeManifestSequence( xOutputStream
, aProps
);
2290 // move the stream to its desired location
2291 Content
aSource( pTempFile
->GetURL(), Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
2293 xOutputStream
= NULL
;
2294 DELETEZ( pTempFile
);
2295 aNewSubFolder
.transferContent( aSource
, InsertOperation_MOVE
, OUString("manifest.xml"), NameClash::OVERWRITE
);
2300 #if OSL_DEBUG_LEVEL > 1
2301 fprintf ( stderr
, "Files: %i\n", nOpenFiles
);
2302 fprintf ( stderr
, "Streams: %i\n", nOpenStreams
);
2306 m_pContent
->executeCommand( OUString("flush"), aAny
);
2307 if ( m_pSource
!= 0 )
2309 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( m_pTempFile
->GetURL(), STREAM_STD_READ
);
2310 m_pSource
->SetStreamSize(0);
2311 // m_pSource->Seek(0);
2312 *pStream
>> *m_pSource
;
2318 catch (const CommandAbortedException
&)
2320 // how to tell the content : forget all changes ?!
2321 // or should we assume that the content does it by itself because he throwed an exception ?!
2322 // any command wasn't executed successfully - not specified
2323 SetError( ERRCODE_IO_GENERAL
);
2324 return COMMIT_RESULT_FAILURE
;
2326 catch (const RuntimeException
&)
2328 // how to tell the content : forget all changes ?!
2329 // or should we assume that the content does it by itself because he throwed an exception ?!
2330 // any other error - not specified
2331 SetError( ERRCODE_IO_GENERAL
);
2332 return COMMIT_RESULT_FAILURE
;
2334 catch (const InteractiveIOException
& r
)
2336 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
|| r
.Code
== IOErrorCode_LOCKING_VIOLATION
)
2337 SetError( ERRCODE_IO_ACCESSDENIED
);
2338 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
2339 SetError( ERRCODE_IO_NOTEXISTS
);
2340 else if ( r
.Code
== IOErrorCode_CANT_READ
)
2341 SetError( ERRCODE_IO_CANTREAD
);
2342 else if ( r
.Code
== IOErrorCode_CANT_WRITE
)
2343 SetError( ERRCODE_IO_CANTWRITE
);
2345 SetError( ERRCODE_IO_GENERAL
);
2347 return COMMIT_RESULT_FAILURE
;
2349 catch (const Exception
&)
2351 // how to tell the content : forget all changes ?!
2352 // or should we assume that the content does it by itself because he throwed an exception ?!
2353 // any other error - not specified
2354 SetError( ERRCODE_IO_GENERAL
);
2355 return COMMIT_RESULT_FAILURE
;
2358 else if ( nRet
!= COMMIT_RESULT_NOTHING_TO_DO
)
2360 // how to tell the content : forget all changes ?! Should we ?!
2361 SetError( ERRCODE_IO_GENERAL
);
2365 // after successful root commit all elements names and types are adjusted and all removed elements
2366 // are also removed from the lists
2367 for ( size_t i
= 0; i
< m_aChildrenList
.size(); )
2369 UCBStorageElement_Impl
* pInnerElement
= m_aChildrenList
[ i
];
2370 if ( pInnerElement
->m_bIsRemoved
)
2372 UCBStorageElementList_Impl::iterator it
= m_aChildrenList
.begin();
2373 ::std::advance( it
, i
);
2375 m_aChildrenList
.erase( it
);
2379 pInnerElement
->m_aOriginalName
= pInnerElement
->m_aName
;
2380 pInnerElement
->m_bIsInserted
= false;
2386 m_bCommited
= false;
2392 bool UCBStorage_Impl::Revert()
2394 for ( size_t i
= 0; i
< m_aChildrenList
.size(); )
2396 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
2397 pElement
->m_bIsRemoved
= false;
2398 if ( pElement
->m_bIsInserted
)
2400 UCBStorageElementList_Impl::iterator it
= m_aChildrenList
.begin();
2401 ::std::advance( it
, i
);
2403 m_aChildrenList
.erase( it
);
2407 if ( pElement
->m_xStream
.Is() )
2409 pElement
->m_xStream
->m_bCommited
= false;
2410 pElement
->m_xStream
->Revert();
2412 else if ( pElement
->m_xStorage
.Is() )
2414 pElement
->m_xStorage
->m_bCommited
= false;
2415 pElement
->m_xStorage
->Revert();
2418 pElement
->m_aName
= pElement
->m_aOriginalName
;
2419 pElement
->m_bIsRemoved
= false;
2426 const OUString
& UCBStorage::GetName() const
2428 return pImp
->m_aName
; // pImp->m_aURL ?!
2431 bool UCBStorage::IsRoot() const
2433 return pImp
->m_bIsRoot
;
2436 void UCBStorage::SetDirty()
2438 pImp
->m_bDirty
= true;
2441 void UCBStorage::SetClass( const SvGlobalName
& rClass
, sal_uLong nOriginalClipFormat
, const OUString
& rUserTypeName
)
2443 pImp
->m_aClassId
= rClass
;
2444 pImp
->m_nFormat
= nOriginalClipFormat
;
2445 pImp
->m_aUserTypeName
= rUserTypeName
;
2447 // in UCB storages only the content type will be stored, all other information can be reconstructed
2448 // ( see the UCBStorage_Impl::Init() method )
2449 ::com::sun::star::datatransfer::DataFlavor aDataFlavor
;
2450 SotExchange::GetFormatDataFlavor( pImp
->m_nFormat
, aDataFlavor
);
2451 pImp
->m_aContentType
= aDataFlavor
.MimeType
;
2454 void UCBStorage::SetClassId( const ClsId
& rClsId
)
2456 pImp
->m_aClassId
= SvGlobalName( (const CLSID
&) rClsId
);
2457 if ( pImp
->m_aClassId
== SvGlobalName() )
2460 // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are
2461 // stored in one the substreams
2462 // UCB storages store the content type information as content type in the manifest file and so this information must be
2463 // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2465 pImp
->m_nFormat
= GetFormatId_Impl( pImp
->m_aClassId
);
2466 if ( pImp
->m_nFormat
)
2468 ::com::sun::star::datatransfer::DataFlavor aDataFlavor
;
2469 SotExchange::GetFormatDataFlavor( pImp
->m_nFormat
, aDataFlavor
);
2470 pImp
->m_aUserTypeName
= aDataFlavor
.HumanPresentableName
;
2471 pImp
->m_aContentType
= aDataFlavor
.MimeType
;
2475 const ClsId
& UCBStorage::GetClassId() const
2477 return ( const ClsId
& ) pImp
->m_aClassId
.GetCLSID();
2480 void UCBStorage::SetConvertClass( const SvGlobalName
& /*rConvertClass*/, sal_uLong
/*nOriginalClipFormat*/, const OUString
& /*rUserTypeName*/ )
2485 bool UCBStorage::ShouldConvert()
2491 SvGlobalName
UCBStorage::GetClassName()
2493 return pImp
->m_aClassId
;
2496 sal_uLong
UCBStorage::GetFormat()
2498 return pImp
->m_nFormat
;
2501 OUString
UCBStorage::GetUserName()
2503 OSL_FAIL("UserName is not implemented in UCB storages!" );
2504 return pImp
->m_aUserTypeName
;
2507 void UCBStorage::FillInfoList( SvStorageInfoList
* pList
) const
2509 // put information in childrenlist into StorageInfoList
2510 for ( size_t i
= 0; i
< pImp
->GetChildrenList().size(); ++i
)
2512 UCBStorageElement_Impl
* pElement
= pImp
->GetChildrenList()[ i
];
2513 if ( !pElement
->m_bIsRemoved
)
2515 // problem: what about the size of a substorage ?!
2516 sal_uLong nSize
= pElement
->m_nSize
;
2517 if ( pElement
->m_xStream
.Is() )
2518 nSize
= pElement
->m_xStream
->GetSize();
2519 SvStorageInfo
aInfo( pElement
->m_aName
, nSize
, pElement
->m_bIsStorage
);
2520 pList
->push_back( aInfo
);
2525 bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl
& rElement
, BaseStorage
* pDest
, const OUString
& rNew
) const
2527 // insert stream or storage into the list or stream of the destination storage
2528 // not into the content, this will be done on commit !
2529 // be aware of name changes !
2530 if ( !rElement
.m_bIsStorage
)
2532 // copy the streams data
2533 // the destination stream must not be open
2534 BaseStorageStream
* pOtherStream
= pDest
->OpenStream( rNew
, STREAM_WRITE
| STREAM_SHARE_DENYALL
, pImp
->m_bDirect
);
2535 BaseStorageStream
* pStream
= NULL
;
2536 bool bDeleteStream
= false;
2538 // if stream is already open, it is allowed to copy it, so be aware of this
2539 if ( rElement
.m_xStream
.Is() )
2540 pStream
= rElement
.m_xStream
->m_pAntiImpl
;
2543 pStream
= ( const_cast < UCBStorage
* > (this) )->OpenStream( rElement
.m_aName
, STREAM_STD_READ
, pImp
->m_bDirect
);
2544 bDeleteStream
= true;
2547 pStream
->CopyTo( pOtherStream
);
2548 SetError( pStream
->GetError() );
2549 if( pOtherStream
->GetError() )
2550 pDest
->SetError( pOtherStream
->GetError() );
2552 pOtherStream
->Commit();
2554 if ( bDeleteStream
)
2556 delete pOtherStream
;
2560 // copy the storage content
2561 // the destination storage must not be open
2562 BaseStorage
* pStorage
= NULL
;
2564 // if stream is already open, it is allowed to copy it, so be aware of this
2565 bool bDeleteStorage
= false;
2566 if ( rElement
.m_xStorage
.Is() )
2567 pStorage
= rElement
.m_xStorage
->m_pAntiImpl
;
2570 pStorage
= ( const_cast < UCBStorage
* > (this) )->OpenStorage( rElement
.m_aName
, pImp
->m_nMode
, pImp
->m_bDirect
);
2571 bDeleteStorage
= true;
2574 UCBStorage
* pUCBDest
= PTR_CAST( UCBStorage
, pDest
);
2575 UCBStorage
* pUCBCopy
= PTR_CAST( UCBStorage
, pStorage
);
2577 bool bOpenUCBStorage
= pUCBDest
&& pUCBCopy
;
2578 BaseStorage
* pOtherStorage
= bOpenUCBStorage
?
2579 pDest
->OpenUCBStorage( rNew
, STREAM_WRITE
| STREAM_SHARE_DENYALL
, pImp
->m_bDirect
) :
2580 pDest
->OpenOLEStorage( rNew
, STREAM_WRITE
| STREAM_SHARE_DENYALL
, pImp
->m_bDirect
);
2582 // For UCB storages, the class id and the format id may differ,
2583 // do passing the class id is not sufficient.
2584 if( bOpenUCBStorage
)
2585 pOtherStorage
->SetClass( pStorage
->GetClassName(),
2586 pStorage
->GetFormat(),
2587 pUCBCopy
->pImp
->m_aUserTypeName
);
2589 pOtherStorage
->SetClassId( pStorage
->GetClassId() );
2590 pStorage
->CopyTo( pOtherStorage
);
2591 SetError( pStorage
->GetError() );
2592 if( pOtherStorage
->GetError() )
2593 pDest
->SetError( pOtherStorage
->GetError() );
2595 pOtherStorage
->Commit();
2597 if ( bDeleteStorage
)
2599 delete pOtherStorage
;
2602 return Good() && pDest
->Good();
2605 UCBStorageElement_Impl
* UCBStorage::FindElement_Impl( const OUString
& rName
) const
2607 DBG_ASSERT( !rName
.isEmpty(), "Name is empty!" );
2608 for ( size_t i
= 0, n
= pImp
->GetChildrenList().size(); i
< n
; ++i
)
2610 UCBStorageElement_Impl
* pElement
= pImp
->GetChildrenList()[ i
];
2611 if ( pElement
->m_aName
== rName
&& !pElement
->m_bIsRemoved
)
2617 bool UCBStorage::CopyTo( BaseStorage
* pDestStg
) const
2619 DBG_ASSERT( pDestStg
!= ((BaseStorage
*)this), "Self-Copying is not possible!" );
2620 if ( pDestStg
== ((BaseStorage
*)this) )
2623 // perhaps it's also a problem if one storage is a parent of the other ?!
2624 // or if not: could be optimized ?!
2626 // For UCB storages, the class id and the format id may differ,
2627 // do passing the class id is not sufficient.
2628 if( pDestStg
->ISA( UCBStorage
) )
2629 pDestStg
->SetClass( pImp
->m_aClassId
, pImp
->m_nFormat
,
2630 pImp
->m_aUserTypeName
);
2632 pDestStg
->SetClassId( GetClassId() );
2633 pDestStg
->SetDirty();
2636 for ( size_t i
= 0; i
< pImp
->GetChildrenList().size() && bRet
; ++i
)
2638 UCBStorageElement_Impl
* pElement
= pImp
->GetChildrenList()[ i
];
2639 if ( !pElement
->m_bIsRemoved
)
2640 bRet
= CopyStorageElement_Impl( *pElement
, pDestStg
, pElement
->m_aName
);
2644 SetError( pDestStg
->GetError() );
2645 return Good() && pDestStg
->Good();
2648 bool UCBStorage::CopyTo( const OUString
& rElemName
, BaseStorage
* pDest
, const OUString
& rNew
)
2650 if( rElemName
.isEmpty() )
2653 if ( pDest
== ((BaseStorage
*) this) )
2655 // can't double an element
2660 // for copying no optimization is useful, because in every case the stream data must be copied
2661 UCBStorageElement_Impl
* pElement
= FindElement_Impl( rElemName
);
2663 return CopyStorageElement_Impl( *pElement
, pDest
, rNew
);
2666 SetError( SVSTREAM_FILE_NOT_FOUND
);
2672 bool UCBStorage::Commit()
2674 // mark this storage for sending it on root commit
2675 pImp
->m_bCommited
= true;
2676 if ( pImp
->m_bIsRoot
)
2677 // the root storage coordinates commiting by sending a Commit command to its content
2678 return ( pImp
->Commit() != COMMIT_RESULT_FAILURE
);
2683 bool UCBStorage::Revert()
2685 return pImp
->Revert();
2688 BaseStorageStream
* UCBStorage::OpenStream( const OUString
& rEleName
, StreamMode nMode
, bool bDirect
, const OString
* pKey
)
2690 if( rEleName
.isEmpty() )
2693 // try to find the storage element
2694 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2697 // element does not exist, check if creation is allowed
2698 if( ( nMode
& STREAM_NOCREATE
) )
2700 SetError( ( nMode
& STREAM_WRITE
) ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
2701 OUString
aName( pImp
->m_aURL
);
2704 UCBStorageStream
* pStream
= new UCBStorageStream( aName
, nMode
, bDirect
, pKey
, pImp
->m_bRepairPackage
, pImp
->m_xProgressHandler
);
2705 pStream
->SetError( GetError() );
2706 pStream
->pImp
->m_aName
= rEleName
;
2711 // create a new UCBStorageElement and insert it into the list
2712 pElement
= new UCBStorageElement_Impl( rEleName
);
2713 pElement
->m_bIsInserted
= true;
2714 pImp
->m_aChildrenList
.push_back( pElement
);
2718 if ( pElement
&& !pElement
->m_bIsFolder
)
2720 // check if stream is already created
2721 if ( pElement
->m_xStream
.Is() )
2723 // stream has already been created; if it has no external reference, it may be opened another time
2724 if ( pElement
->m_xStream
->m_pAntiImpl
)
2726 OSL_FAIL("Stream is already open!" );
2727 SetError( SVSTREAM_ACCESS_DENIED
); // ???
2732 // check if stream is opened with the same keyword as before
2733 // if not, generate a new stream because it could be encrypted vs. decrypted!
2737 if ( pElement
->m_xStream
->m_aKey
== aKey
)
2739 pElement
->m_xStream
->PrepareCachedForReopen( nMode
);
2741 return new UCBStorageStream( pElement
->m_xStream
);
2746 // stream is opened the first time
2747 pImp
->OpenStream( pElement
, nMode
, bDirect
, pKey
);
2749 // if name has been changed before creating the stream: set name!
2750 pElement
->m_xStream
->m_aName
= rEleName
;
2751 return new UCBStorageStream( pElement
->m_xStream
);
2757 UCBStorageStream_Impl
* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl
* pElement
, StreamMode nMode
, bool bDirect
, const OString
* pKey
)
2759 OUString
aName( m_aURL
);
2761 aName
+= pElement
->m_aOriginalName
;
2762 pElement
->m_xStream
= new UCBStorageStream_Impl( aName
, nMode
, NULL
, bDirect
, pKey
, m_bRepairPackage
, m_xProgressHandler
);
2763 return pElement
->m_xStream
;
2766 BaseStorage
* UCBStorage::OpenUCBStorage( const OUString
& rEleName
, StreamMode nMode
, bool bDirect
)
2768 if( rEleName
.isEmpty() )
2771 return OpenStorage_Impl( rEleName
, nMode
, bDirect
, true );
2774 BaseStorage
* UCBStorage::OpenOLEStorage( const OUString
& rEleName
, StreamMode nMode
, bool bDirect
)
2776 if( rEleName
.isEmpty() )
2779 return OpenStorage_Impl( rEleName
, nMode
, bDirect
, false );
2782 BaseStorage
* UCBStorage::OpenStorage( const OUString
& rEleName
, StreamMode nMode
, bool bDirect
)
2784 if( rEleName
.isEmpty() )
2787 return OpenStorage_Impl( rEleName
, nMode
, bDirect
, true );
2790 BaseStorage
* UCBStorage::OpenStorage_Impl( const OUString
& rEleName
, StreamMode nMode
, bool bDirect
, bool bForceUCBStorage
)
2792 // try to find the storage element
2793 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2796 // element does not exist, check if creation is allowed
2797 if( ( nMode
& STREAM_NOCREATE
) )
2799 SetError( ( nMode
& STREAM_WRITE
) ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
2800 OUString
aName( pImp
->m_aURL
);
2802 aName
+= rEleName
; // ???
2803 UCBStorage
*pStorage
= new UCBStorage( aName
, nMode
, bDirect
, false, pImp
->m_bRepairPackage
, pImp
->m_xProgressHandler
);
2804 pStorage
->pImp
->m_bIsRoot
= false;
2805 pStorage
->pImp
->m_bListCreated
= true; // the storage is pretty new, nothing to read
2806 pStorage
->SetError( GetError() );
2810 // create a new UCBStorageElement and insert it into the list
2811 // problem: perhaps an OLEStorage should be created ?!
2812 // Because nothing is known about the element that should be created, an external parameter is needed !
2813 pElement
= new UCBStorageElement_Impl( rEleName
);
2814 pElement
->m_bIsInserted
= true;
2815 pImp
->m_aChildrenList
.push_back( pElement
);
2818 if ( !pElement
->m_bIsFolder
&& ( pElement
->m_bIsStorage
|| !bForceUCBStorage
) )
2820 // create OLE storages on a stream ( see ctor of SotStorage )
2821 // Such a storage will be created on a UCBStorageStream; it will write into the stream
2822 // if it is opened in direct mode or when it is committed. In this case the stream will be
2823 // modified and then it MUST be treated as commited.
2824 if ( !pElement
->m_xStream
.Is() )
2826 BaseStorageStream
* pStr
= OpenStream( rEleName
, nMode
, bDirect
);
2827 UCBStorageStream
* pStream
= PTR_CAST( UCBStorageStream
, pStr
);
2830 SetError( ( nMode
& STREAM_WRITE
) ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
2834 pElement
->m_xStream
= pStream
->pImp
;
2838 pElement
->m_xStream
->PrepareCachedForReopen( nMode
);
2839 pElement
->m_xStream
->Init();
2841 pElement
->m_bIsStorage
= true;
2842 return pElement
->m_xStream
->CreateStorage(); // can only be created in transacted mode
2844 else if ( pElement
->m_xStorage
.Is() )
2846 // storage has already been opened; if it has no external reference, it may be opened another time
2847 if ( pElement
->m_xStorage
->m_pAntiImpl
)
2849 OSL_FAIL("Storage is already open!" );
2850 SetError( SVSTREAM_ACCESS_DENIED
); // ???
2854 bool bIsWritable
= (( pElement
->m_xStorage
->m_nMode
& STREAM_WRITE
) != 0);
2855 if ( !bIsWritable
&& (( nMode
& STREAM_WRITE
) != 0 ))
2857 OUString
aName( pImp
->m_aURL
);
2859 aName
+= pElement
->m_aOriginalName
;
2860 UCBStorage
* pStorage
= new UCBStorage( aName
, nMode
, bDirect
, false, pImp
->m_bRepairPackage
, pImp
->m_xProgressHandler
);
2861 pElement
->m_xStorage
= pStorage
->pImp
;
2866 return new UCBStorage( pElement
->m_xStorage
);
2870 else if ( !pElement
->m_xStream
.Is() )
2872 // storage is opened the first time
2873 bool bIsWritable
= (( pImp
->m_nMode
& STREAM_WRITE
) != 0 );
2874 if ( pImp
->m_bIsLinked
&& pImp
->m_bIsRoot
&& bIsWritable
)
2876 // make sure that the root storage object has been created before substorages will be created
2877 INetURLObject
aFolderObj( pImp
->m_aURL
);
2878 aFolderObj
.removeSegment();
2880 Content
aFolder( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
), Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
2881 pImp
->m_pContent
= new Content
;
2882 bool bRet
= ::utl::UCBContentHelper::MakeFolder( aFolder
, pImp
->m_aName
, *pImp
->m_pContent
);
2885 SetError( SVSTREAM_CANNOT_MAKE
);
2890 UCBStorage_Impl
* pStor
= pImp
->OpenStorage( pElement
, nMode
, bDirect
);
2893 if ( pElement
->m_bIsInserted
)
2894 pStor
->m_bListCreated
= true; // the storage is pretty new, nothing to read
2896 return new UCBStorage( pStor
);
2903 UCBStorage_Impl
* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl
* pElement
, StreamMode nMode
, bool bDirect
)
2905 UCBStorage_Impl
* pRet
= NULL
;
2906 OUString
aName( m_aURL
);
2908 aName
+= pElement
->m_aOriginalName
; // ???
2910 pElement
->m_bIsStorage
= pElement
->m_bIsFolder
= true;
2912 if ( m_bIsLinked
&& !::utl::UCBContentHelper::Exists( aName
) )
2915 bool bRet
= ::utl::UCBContentHelper::MakeFolder( *m_pContent
, pElement
->m_aOriginalName
, aNewFolder
);
2917 pRet
= new UCBStorage_Impl( aNewFolder
, aName
, nMode
, NULL
, bDirect
, false, m_bRepairPackage
, m_xProgressHandler
);
2921 pRet
= new UCBStorage_Impl( aName
, nMode
, NULL
, bDirect
, false, m_bRepairPackage
, m_xProgressHandler
);
2926 pRet
->m_bIsLinked
= m_bIsLinked
;
2927 pRet
->m_bIsRoot
= false;
2929 // if name has been changed before creating the stream: set name!
2930 pRet
->m_aName
= pElement
->m_aOriginalName
;
2931 pElement
->m_xStorage
= pRet
;
2940 bool UCBStorage::IsStorage( const OUString
& rEleName
) const
2942 if( rEleName
.isEmpty() )
2945 const UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2946 return ( pElement
&& pElement
->m_bIsStorage
);
2949 bool UCBStorage::IsStream( const OUString
& rEleName
) const
2951 if( rEleName
.isEmpty() )
2954 const UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2955 return ( pElement
&& !pElement
->m_bIsStorage
);
2958 bool UCBStorage::IsContained( const OUString
& rEleName
) const
2960 if( rEleName
.isEmpty() )
2962 const UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2963 return ( pElement
!= NULL
);
2966 bool UCBStorage::Remove( const OUString
& rEleName
)
2968 if( rEleName
.isEmpty() )
2971 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2974 pElement
->m_bIsRemoved
= true;
2977 SetError( SVSTREAM_FILE_NOT_FOUND
);
2979 return ( pElement
!= NULL
);
2982 bool UCBStorage::Rename( const OUString
& rEleName
, const OUString
& rNewName
)
2984 if( rEleName
.isEmpty()|| rNewName
.isEmpty() )
2987 UCBStorageElement_Impl
*pAlreadyExisting
= FindElement_Impl( rNewName
);
2988 if ( pAlreadyExisting
)
2990 SetError( SVSTREAM_ACCESS_DENIED
);
2991 return false; // can't change to a name that is already used
2994 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2997 pElement
->m_aName
= rNewName
;
3000 SetError( SVSTREAM_FILE_NOT_FOUND
);
3002 return pElement
!= NULL
;
3005 bool UCBStorage::MoveTo( const OUString
& rEleName
, BaseStorage
* pNewSt
, const OUString
& rNewName
)
3007 if( rEleName
.isEmpty() || rNewName
.isEmpty() )
3010 if ( pNewSt
== ((BaseStorage
*) this) && !FindElement_Impl( rNewName
) )
3012 return Rename( rEleName
, rNewName
);
3017 if ( PTR_CAST( UCBStorage, pNewSt ) )
3019 // because the element is moved, not copied, a special optimization is possible :
3020 // first copy the UCBStorageElement; flag old element as "Removed" and new as "Inserted",
3021 // clear original name/type of the new element
3022 // if moved element is open: copy content, but change absolute URL ( and those of all children of the element! ),
3023 // clear original name/type of new content, keep the old original stream/storage, but forget its working streams,
3024 // close original UCBContent and original stream, only the TempFile and its stream may remain unchanged, but now
3025 // belong to the new content
3026 // if original and editable stream are identical ( readonly element ), it has to be copied to the editable
3027 // stream of the destination object
3028 // Not implemented at the moment ( risky?! ), perhaps later
3031 // MoveTo is done by first copying to the new destination and then removing the old element
3032 bool bRet
= CopyTo( rEleName
, pNewSt
, rNewName
);
3034 bRet
= Remove( rEleName
);
3039 bool UCBStorage::ValidateFAT()
3045 bool UCBStorage::Validate( bool bWrite
) const
3048 return ( !bWrite
|| ( pImp
->m_nMode
& STREAM_WRITE
) );
3051 bool UCBStorage::ValidateMode( StreamMode m
) const
3054 if( m
== ( STREAM_READ
| STREAM_TRUNC
) ) // from stg.cxx
3056 sal_uInt16 nCurMode
= 0xFFFF;
3057 if( ( m
& 3 ) == STREAM_READ
)
3059 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
3060 if( ( ( m
& STREAM_SHARE_DENYWRITE
)
3061 && ( nCurMode
& STREAM_SHARE_DENYWRITE
) )
3062 || ( ( m
& STREAM_SHARE_DENYALL
)
3063 && ( nCurMode
& STREAM_SHARE_DENYALL
) ) )
3068 // only SHARE_DENYALL allowed
3069 // storages open in r/o mode are OK, since only
3070 // the commit may fail
3071 if( ( m
& STREAM_SHARE_DENYALL
)
3072 && ( nCurMode
& STREAM_SHARE_DENYALL
) )
3079 const SvStream
* UCBStorage::GetSvStream() const
3081 // this would cause a complete download of the file
3082 // as it looks, this method is NOT used inside of SOT, only exported by class SotStorage - but for what ???
3083 return pImp
->m_pSource
;
3086 bool UCBStorage::Equals( const BaseStorage
& rStorage
) const
3089 return ((BaseStorage
*)this) == &rStorage
;
3092 bool UCBStorage::IsStorageFile( SvStream
* pFile
)
3097 sal_uLong nPos
= pFile
->Tell();
3098 pFile
->Seek( STREAM_SEEK_TO_END
);
3099 if ( pFile
->Tell() < 4 )
3103 sal_uInt32
nBytes(0);
3106 // search for the magic bytes
3107 bool bRet
= ( nBytes
== 0x04034b50 );
3110 // disk spanned file have an additional header in front of the usual one
3111 bRet
= ( nBytes
== 0x08074b50 );
3116 bRet
= ( nBytes
== 0x04034b50 );
3120 pFile
->Seek( nPos
);
3124 bool UCBStorage::IsDiskSpannedFile( SvStream
* pFile
)
3129 sal_uLong nPos
= pFile
->Tell();
3130 pFile
->Seek( STREAM_SEEK_TO_END
);
3131 if ( !pFile
->Tell() )
3138 // disk spanned file have an additional header in front of the usual one
3139 bool bRet
= ( nBytes
== 0x08074b50 );
3143 bRet
= ( nBytes
== 0x04034b50 );
3146 pFile
->Seek( nPos
);
3150 OUString
UCBStorage::GetLinkedFile( SvStream
&rStream
)
3153 sal_uLong nPos
= rStream
.Tell();
3154 rStream
.Seek( STREAM_SEEK_TO_END
);
3155 if ( !rStream
.Tell() )
3161 if( nBytes
== 0x04034b50 )
3163 OString aTmp
= read_lenPrefixed_uInt8s_ToOString
<sal_uInt16
>(rStream
);
3164 if (aTmp
.match("ContentURL="))
3166 aString
= OStringToOUString(aTmp
.copy(11), RTL_TEXTENCODING_UTF8
);
3170 rStream
.Seek( nPos
);
3174 OUString
UCBStorage::CreateLinkFile( const OUString
& rName
)
3176 // create a stream to write the link file - use a temp file, because it may be no file content
3177 INetURLObject
aFolderObj( rName
);
3178 OUString aName
= aFolderObj
.GetName();
3179 aFolderObj
.removeSegment();
3180 OUString
aFolderURL( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
) );
3181 ::utl::TempFile
* pTempFile
= new ::utl::TempFile( &aFolderURL
);
3183 // get the stream from the temp file
3184 SvStream
* pStream
= pTempFile
->GetStream( STREAM_STD_READWRITE
| STREAM_TRUNC
);
3187 *pStream
<< ( sal_uInt32
) 0x04034b50;
3189 // assemble a new folder name in the destination folder
3190 INetURLObject
aObj( rName
);
3191 OUString aTmpName
= aObj
.GetName();
3192 OUString aTitle
= "content." + aTmpName
;
3194 // create a folder and store its URL
3195 Content
aFolder( aFolderURL
, Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
3197 bool bRet
= ::utl::UCBContentHelper::MakeFolder( aFolder
, aTitle
, aNewFolder
);
3200 aFolderObj
.insertName( aTitle
);
3201 if ( ::utl::UCBContentHelper::Exists( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
) ) )
3203 // Hack, because already existing files give the same CommandAbortedException as any other error !
3204 // append a number until the name can be used for a new folder
3206 for ( sal_Int32 i
=0; !bRet
; i
++ )
3208 OUString aTmp
= aTitle
+ OUString::number( i
);
3209 bRet
= ::utl::UCBContentHelper::MakeFolder( aFolder
, aTmp
, aNewFolder
);
3214 aFolderObj
.SetName( aTmp
);
3215 if ( !::utl::UCBContentHelper::Exists( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
) ) )
3216 // Hack, because already existing files give the same CommandAbortedException as any other error !
3226 aObj
.SetName( aTitle
);
3227 OUString aURL
= aObj
.GetMainURL( INetURLObject::NO_DECODE
);
3229 // store it as key/value pair
3230 OUString aLink
= "ContentURL=" + aURL
;
3231 write_lenPrefixed_uInt8s_FromOUString
<sal_uInt16
>(*pStream
, aLink
, RTL_TEXTENCODING_UTF8
);
3234 // move the stream to its desired location
3235 Content
aSource( pTempFile
->GetURL(), Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
3236 DELETEZ( pTempFile
);
3237 aFolder
.transferContent( aSource
, InsertOperation_MOVE
, aName
, NameClash::OVERWRITE
);
3241 pTempFile
->EnableKillingFile( true );
3246 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */