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 <rtl/digest.h>
47 #include <tools/ref.hxx>
48 #include <tools/debug.hxx>
49 #include <unotools/streamhelper.hxx>
50 #include <unotools/streamwrap.hxx>
51 #include <unotools/ucbhelper.hxx>
52 #include <unotools/localfilehelper.hxx>
53 #include <tools/urlobj.hxx>
54 #include <comphelper/processfactory.hxx>
55 #include <cppuhelper/implbase2.hxx>
56 #include <ucbhelper/commandenvironment.hxx>
58 #include "sot/stg.hxx"
59 #include "sot/storinfo.hxx"
60 #include <sot/storage.hxx>
61 #include <sot/exchange.hxx>
62 #include <sot/formats.hxx>
63 #include <comphelper/classids.hxx>
67 using namespace ::com::sun::star::lang
;
68 using namespace ::com::sun::star::beans
;
69 using namespace ::com::sun::star::uno
;
70 using namespace ::com::sun::star::ucb
;
71 using namespace ::com::sun::star::io
;
72 using namespace ::com::sun::star::sdbc
;
73 using namespace ::ucbhelper
;
75 #if OSL_DEBUG_LEVEL > 1
77 static int nOpenFiles
=0;
78 static int nOpenStreams
=0;
81 typedef ::cppu::WeakImplHelper2
< XInputStream
, XSeekable
> FileInputStreamWrapper_Base
;
82 class FileStreamWrapper_Impl
: public FileInputStreamWrapper_Base
85 ::osl::Mutex m_aMutex
;
87 SvStream
* m_pSvStream
;
90 FileStreamWrapper_Impl( const String
& rName
);
91 virtual ~FileStreamWrapper_Impl();
93 virtual void SAL_CALL
seek( sal_Int64 _nLocation
) throw ( IllegalArgumentException
, IOException
, RuntimeException
);
94 virtual sal_Int64 SAL_CALL
getPosition( ) throw ( IOException
, RuntimeException
);
95 virtual sal_Int64 SAL_CALL
getLength( ) throw ( IOException
, RuntimeException
);
96 virtual sal_Int32 SAL_CALL
readBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
97 virtual sal_Int32 SAL_CALL
readSomeBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
98 virtual void SAL_CALL
skipBytes(sal_Int32 nBytesToSkip
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
);
99 virtual sal_Int32 SAL_CALL
available() throw( NotConnectedException
, RuntimeException
);
100 virtual void SAL_CALL
closeInput() throw( NotConnectedException
, RuntimeException
);
103 void checkConnected();
107 //------------------------------------------------------------------
108 FileStreamWrapper_Impl::FileStreamWrapper_Impl( const String
& rName
)
112 // if no URL is provided the stream is empty
115 //------------------------------------------------------------------
116 FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
121 #if OSL_DEBUG_LEVEL > 1
127 ::utl::UCBContentHelper::Kill( m_aURL
);
130 //------------------------------------------------------------------------------
131 sal_Int32 SAL_CALL
FileStreamWrapper_Impl::readBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
)
132 throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
142 if (nBytesToRead
< 0)
143 throw BufferSizeExceededException(OUString(),static_cast<XWeak
*>(this));
145 ::osl::MutexGuard
aGuard( m_aMutex
);
147 aData
.realloc(nBytesToRead
);
149 sal_uInt32 nRead
= m_pSvStream
->Read((void*)aData
.getArray(), nBytesToRead
);
152 // Wenn gelesene Zeichen < MaxLength, Sequence anpassen
153 if (nRead
< (sal_uInt32
)nBytesToRead
)
154 aData
.realloc( nRead
);
159 //------------------------------------------------------------------------------
160 sal_Int32 SAL_CALL
FileStreamWrapper_Impl::readSomeBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
170 if (nMaxBytesToRead
< 0)
171 throw BufferSizeExceededException(OUString(),static_cast<XWeak
*>(this));
173 if (m_pSvStream
->IsEof())
179 return readBytes(aData
, nMaxBytesToRead
);
182 //------------------------------------------------------------------------------
183 void SAL_CALL
FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
188 ::osl::MutexGuard
aGuard( m_aMutex
);
191 m_pSvStream
->SeekRel(nBytesToSkip
);
195 //------------------------------------------------------------------------------
196 sal_Int32 SAL_CALL
FileStreamWrapper_Impl::available() throw( NotConnectedException
, RuntimeException
)
201 ::osl::MutexGuard
aGuard( m_aMutex
);
204 sal_uInt32 nPos
= m_pSvStream
->Tell();
207 m_pSvStream
->Seek(STREAM_SEEK_TO_END
);
210 sal_Int32 nAvailable
= (sal_Int32
)m_pSvStream
->Tell() - nPos
;
211 m_pSvStream
->Seek(nPos
);
217 //------------------------------------------------------------------------------
218 void SAL_CALL
FileStreamWrapper_Impl::closeInput() throw( NotConnectedException
, RuntimeException
)
223 ::osl::MutexGuard
aGuard( m_aMutex
);
225 DELETEZ( m_pSvStream
);
226 #if OSL_DEBUG_LEVEL > 1
229 ::utl::UCBContentHelper::Kill( m_aURL
);
233 //------------------------------------------------------------------------------
234 void SAL_CALL
FileStreamWrapper_Impl::seek( sal_Int64 _nLocation
) throw (IllegalArgumentException
, IOException
, RuntimeException
)
239 ::osl::MutexGuard
aGuard( m_aMutex
);
242 m_pSvStream
->Seek((sal_uInt32
)_nLocation
);
246 //------------------------------------------------------------------------------
247 sal_Int64 SAL_CALL
FileStreamWrapper_Impl::getPosition( ) throw (IOException
, RuntimeException
)
252 ::osl::MutexGuard
aGuard( m_aMutex
);
255 sal_uInt32 nPos
= m_pSvStream
->Tell();
257 return (sal_Int64
)nPos
;
260 //------------------------------------------------------------------------------
261 sal_Int64 SAL_CALL
FileStreamWrapper_Impl::getLength( ) throw (IOException
, RuntimeException
)
266 ::osl::MutexGuard
aGuard( m_aMutex
);
269 sal_uInt32 nCurrentPos
= m_pSvStream
->Tell();
272 m_pSvStream
->Seek(STREAM_SEEK_TO_END
);
273 sal_uInt32 nEndPos
= m_pSvStream
->Tell();
274 m_pSvStream
->Seek(nCurrentPos
);
278 return (sal_Int64
)nEndPos
;
281 //------------------------------------------------------------------------------
282 void FileStreamWrapper_Impl::checkConnected()
285 throw NotConnectedException(OUString(), const_cast<XWeak
*>(static_cast<const XWeak
*>(this)));
288 m_pSvStream
= ::utl::UcbStreamHelper::CreateStream( m_aURL
, STREAM_STD_READ
);
289 #if OSL_DEBUG_LEVEL > 1
295 //------------------------------------------------------------------------------
296 void FileStreamWrapper_Impl::checkError()
300 if (m_pSvStream
->SvStream::GetError() != ERRCODE_NONE
)
301 // TODO: really evaluate the error
302 throw NotConnectedException(OUString(), const_cast<XWeak
*>(static_cast<const XWeak
*>(this)));
305 TYPEINIT1( UCBStorageStream
, BaseStorageStream
);
306 TYPEINIT1( UCBStorage
, BaseStorage
);
308 #define COMMIT_RESULT_FAILURE 0
309 #define COMMIT_RESULT_NOTHING_TO_DO 1
310 #define COMMIT_RESULT_SUCCESS 2
312 #define min( x, y ) (( x < y ) ? x : y)
314 sal_Int32
GetFormatId_Impl( SvGlobalName aName
)
316 if ( aName
== SvGlobalName( SO3_SW_CLASSID_60
) )
317 return SOT_FORMATSTR_ID_STARWRITER_60
;
318 if ( aName
== SvGlobalName( SO3_SWWEB_CLASSID_60
) )
319 return SOT_FORMATSTR_ID_STARWRITERWEB_60
;
320 if ( aName
== SvGlobalName( SO3_SWGLOB_CLASSID_60
) )
321 return SOT_FORMATSTR_ID_STARWRITERGLOB_60
;
322 if ( aName
== SvGlobalName( SO3_SDRAW_CLASSID_60
) )
323 return SOT_FORMATSTR_ID_STARDRAW_60
;
324 if ( aName
== SvGlobalName( SO3_SIMPRESS_CLASSID_60
) )
325 return SOT_FORMATSTR_ID_STARIMPRESS_60
;
326 if ( aName
== SvGlobalName( SO3_SC_CLASSID_60
) )
327 return SOT_FORMATSTR_ID_STARCALC_60
;
328 if ( aName
== SvGlobalName( SO3_SCH_CLASSID_60
) )
329 return SOT_FORMATSTR_ID_STARCHART_60
;
330 if ( aName
== SvGlobalName( SO3_SM_CLASSID_60
) )
331 return SOT_FORMATSTR_ID_STARMATH_60
;
332 if ( aName
== SvGlobalName( SO3_OUT_CLASSID
) ||
333 aName
== SvGlobalName( SO3_APPLET_CLASSID
) ||
334 aName
== SvGlobalName( SO3_PLUGIN_CLASSID
) ||
335 aName
== SvGlobalName( SO3_IFRAME_CLASSID
) )
336 // allowed, but not supported
340 OSL_FAIL( "Unknown UCB storage format!" );
346 SvGlobalName
GetClassId_Impl( sal_Int32 nFormat
)
350 case SOT_FORMATSTR_ID_STARWRITER_8
:
351 case SOT_FORMATSTR_ID_STARWRITER_8_TEMPLATE
:
352 return SvGlobalName( SO3_SW_CLASSID_60
);
353 case SOT_FORMATSTR_ID_STARWRITERWEB_8
:
354 return SvGlobalName( SO3_SWWEB_CLASSID_60
);
355 case SOT_FORMATSTR_ID_STARWRITERGLOB_8
:
356 return SvGlobalName( SO3_SWGLOB_CLASSID_60
);
357 case SOT_FORMATSTR_ID_STARDRAW_8
:
358 case SOT_FORMATSTR_ID_STARDRAW_8_TEMPLATE
:
359 return SvGlobalName( SO3_SDRAW_CLASSID_60
);
360 case SOT_FORMATSTR_ID_STARIMPRESS_8
:
361 case SOT_FORMATSTR_ID_STARIMPRESS_8_TEMPLATE
:
362 return SvGlobalName( SO3_SIMPRESS_CLASSID_60
);
363 case SOT_FORMATSTR_ID_STARCALC_8
:
364 case SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE
:
365 return SvGlobalName( SO3_SC_CLASSID_60
);
366 case SOT_FORMATSTR_ID_STARCHART_8
:
367 case SOT_FORMATSTR_ID_STARCHART_8_TEMPLATE
:
368 return SvGlobalName( SO3_SCH_CLASSID_60
);
369 case SOT_FORMATSTR_ID_STARMATH_8
:
370 case SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE
:
371 return SvGlobalName( SO3_SM_CLASSID_60
);
372 case SOT_FORMATSTR_ID_STARWRITER_60
:
373 return SvGlobalName( SO3_SW_CLASSID_60
);
374 case SOT_FORMATSTR_ID_STARWRITERWEB_60
:
375 return SvGlobalName( SO3_SWWEB_CLASSID_60
);
376 case SOT_FORMATSTR_ID_STARWRITERGLOB_60
:
377 return SvGlobalName( SO3_SWGLOB_CLASSID_60
);
378 case SOT_FORMATSTR_ID_STARDRAW_60
:
379 return SvGlobalName( SO3_SDRAW_CLASSID_60
);
380 case SOT_FORMATSTR_ID_STARIMPRESS_60
:
381 return SvGlobalName( SO3_SIMPRESS_CLASSID_60
);
382 case SOT_FORMATSTR_ID_STARCALC_60
:
383 return SvGlobalName( SO3_SC_CLASSID_60
);
384 case SOT_FORMATSTR_ID_STARCHART_60
:
385 return SvGlobalName( SO3_SCH_CLASSID_60
);
386 case SOT_FORMATSTR_ID_STARMATH_60
:
387 return SvGlobalName( SO3_SM_CLASSID_60
);
389 return SvGlobalName();
393 // All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
394 // class, that uses the refcounted object as impl-class.
396 enum RepresentModes
{
402 class UCBStorageStream_Impl
: public SvRefBase
, public SvStream
404 ~UCBStorageStream_Impl();
407 virtual sal_uLong
GetData( void* pData
, sal_uLong nSize
);
408 virtual sal_uLong
PutData( const void* pData
, sal_uLong nSize
);
409 virtual sal_uLong
SeekPos( sal_uLong nPos
);
410 virtual void SetSize( sal_uLong nSize
);
411 virtual void FlushData();
412 virtual void ResetError();
414 UCBStorageStream
* m_pAntiImpl
; // only valid if an external reference exists
416 String m_aOriginalName
;// the original name before accessing the stream
417 String m_aName
; // the actual name ( changed with a Rename command at the parent )
418 String m_aURL
; // the full path name to create the content
419 String m_aContentType
;
420 String m_aOriginalContentType
;
422 ::ucbhelper::Content
* m_pContent
; // the content that provides the data
423 Reference
<XInputStream
> m_rSource
; // the stream covering the original data of the content
424 SvStream
* m_pStream
; // the stream worked on; for readonly streams it is the original stream of the content
425 // for read/write streams it's a copy into a temporary file
426 String m_aTempURL
; // URL of this temporary stream
427 RepresentModes m_nRepresentMode
; // should it be used as XInputStream or as SvStream
429 StreamMode m_nMode
; // open mode ( read/write/trunc/nocreate/sharing )
430 sal_Bool m_bSourceRead
; // Source still contains useful information
431 sal_Bool m_bModified
; // only modified streams will be sent to the original content
432 sal_Bool m_bCommited
; // sending the streams is coordinated by the root storage of the package
433 sal_Bool m_bDirect
; // the storage and its streams are opened in direct mode; for UCBStorages
434 // this means that the root storage does an autocommit when its external
435 // reference is destroyed
436 sal_Bool m_bIsOLEStorage
;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
438 UCBStorageStream_Impl( const String
&, StreamMode
, UCBStorageStream
*, sal_Bool
, const OString
* pKey
=0, sal_Bool bRepair
= sal_False
, Reference
< XProgressHandler
> xProgress
= Reference
< XProgressHandler
>() );
443 sal_Int16
Commit(); // if modified and commited: transfer an XInputStream to the content
444 sal_Bool
Revert(); // discard all changes
445 BaseStorage
* CreateStorage();// create an OLE Storage on the UCBStorageStream
448 sal_uLong
ReadSourceWriteTemporary( sal_uLong aLength
); // read aLength from source and copy to temporary,
449 // no seeking is produced
450 sal_uLong
ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
452 sal_uLong
CopySourceToTemporary(); // same as ReadSourceWriteToTemporary()
453 // but the writing is done at the end of temporary
454 // pointer position is not changed
455 using SvStream::SetError
;
456 void SetError( sal_uInt32 nError
);
457 void PrepareCachedForReopen( StreamMode nMode
);
460 SV_DECL_IMPL_REF( UCBStorageStream_Impl
);
462 struct UCBStorageElement_Impl
;
463 typedef ::std::vector
< UCBStorageElement_Impl
* > UCBStorageElementList_Impl
;
465 class UCBStorage_Impl
: public SvRefBase
469 UCBStorage
* m_pAntiImpl
; // only valid if external references exists
471 String m_aOriginalName
;// the original name before accessing the storage
472 String m_aName
; // the actual name ( changed with a Rename command at the parent )
473 String m_aURL
; // the full path name to create the content
474 String m_aContentType
;
475 String m_aOriginalContentType
;
476 ::ucbhelper::Content
* m_pContent
; // the content that provides the storage elements
477 ::utl::TempFile
* m_pTempFile
; // temporary file, only for storages on stream
478 SvStream
* m_pSource
; // original stream, only for storages on a stream
480 StreamMode m_nMode
; // open mode ( read/write/trunc/nocreate/sharing )
481 sal_Bool m_bModified
; // only modified elements will be sent to the original content
482 sal_Bool m_bCommited
; // sending the streams is coordinated by the root storage of the package
483 sal_Bool m_bDirect
; // the storage and its streams are opened in direct mode; for UCBStorages
484 // this means that the root storage does an autocommit when its external
485 // reference is destroyed
486 sal_Bool m_bIsRoot
; // marks this storage as root storages that manages all oommits and reverts
487 sal_Bool m_bDirty
; // ???
488 sal_Bool m_bIsLinked
;
489 sal_Bool m_bListCreated
;
491 String m_aUserTypeName
;
492 SvGlobalName m_aClassId
;
494 UCBStorageElementList_Impl m_aChildrenList
;
496 sal_Bool m_bRepairPackage
;
497 Reference
< XProgressHandler
> m_xProgressHandler
;
499 UCBStorage_Impl( const ::ucbhelper::Content
&, const String
&, StreamMode
, UCBStorage
*, sal_Bool
, sal_Bool
, sal_Bool
= sal_False
, Reference
< XProgressHandler
> = Reference
< XProgressHandler
>() );
500 UCBStorage_Impl( const String
&, StreamMode
, UCBStorage
*, sal_Bool
, sal_Bool
, sal_Bool
= sal_False
, Reference
< XProgressHandler
> = Reference
< XProgressHandler
>() );
501 UCBStorage_Impl( SvStream
&, UCBStorage
*, sal_Bool
);
505 sal_Bool
Insert( ::ucbhelper::Content
*pContent
);
506 UCBStorage_Impl
* OpenStorage( UCBStorageElement_Impl
* pElement
, StreamMode nMode
, bool bDirect
);
507 UCBStorageStream_Impl
* OpenStream( UCBStorageElement_Impl
*, StreamMode
, sal_Bool
, const OString
* pKey
=0 );
508 void SetProps( const Sequence
< Sequence
< PropertyValue
> >& rSequence
, const String
& );
509 void GetProps( sal_Int32
&, Sequence
< Sequence
< PropertyValue
> >& rSequence
, const String
& );
510 sal_Int32
GetObjectCount();
512 void CreateContent();
513 ::ucbhelper::Content
* GetContent()
514 { if ( !m_pContent
) CreateContent(); return m_pContent
; }
515 UCBStorageElementList_Impl
& GetChildrenList()
517 long nError
= m_nError
;
519 if ( m_nMode
& STREAM_WRITE
)
524 m_pAntiImpl
->ResetError();
525 m_pAntiImpl
->SetError( nError
);
529 return m_aChildrenList
;
532 void SetError( long nError
);
535 SV_DECL_IMPL_REF( UCBStorage_Impl
);
537 // this struct contains all necessary information on an element inside a UCBStorage
538 struct UCBStorageElement_Impl
540 String m_aName
; // the actual URL relative to the root "folder"
541 String m_aOriginalName
;// the original name in the content
543 sal_Bool m_bIsFolder
; // Only sal_True when it is a UCBStorage !
544 sal_Bool m_bIsStorage
; // Also sal_True when it is an OLEStorage !
545 sal_Bool m_bIsRemoved
; // element will be removed on commit
546 sal_Bool m_bIsInserted
; // element will be removed on revert
547 UCBStorage_ImplRef m_xStorage
; // reference to the "real" storage
548 UCBStorageStream_ImplRef m_xStream
; // reference to the "real" stream
550 UCBStorageElement_Impl( const OUString
& rName
,
551 sal_Bool bIsFolder
= sal_False
, sal_uLong nSize
= 0 )
553 , m_aOriginalName( rName
)
555 , m_bIsFolder( bIsFolder
)
556 , m_bIsStorage( bIsFolder
)
557 , m_bIsRemoved( sal_False
)
558 , m_bIsInserted( sal_False
)
562 ::ucbhelper::Content
* GetContent();
563 sal_Bool
IsModified();
564 String
GetContentType();
565 void SetContentType( const String
& );
566 String
GetOriginalContentType();
568 { return m_xStream
.Is() || m_xStorage
.Is(); }
571 ::ucbhelper::Content
* UCBStorageElement_Impl::GetContent()
573 if ( m_xStream
.Is() )
574 return m_xStream
->m_pContent
;
575 else if ( m_xStorage
.Is() )
576 return m_xStorage
->GetContent();
581 String
UCBStorageElement_Impl::GetContentType()
583 if ( m_xStream
.Is() )
584 return m_xStream
->m_aContentType
;
585 else if ( m_xStorage
.Is() )
586 return m_xStorage
->m_aContentType
;
589 OSL_FAIL("Element not loaded!");
594 void UCBStorageElement_Impl::SetContentType( const String
& rType
)
596 if ( m_xStream
.Is() ) {
597 m_xStream
->m_aContentType
= m_xStream
->m_aOriginalContentType
= rType
;
599 else if ( m_xStorage
.Is() ) {
600 m_xStorage
->m_aContentType
= m_xStorage
->m_aOriginalContentType
= rType
;
603 OSL_FAIL("Element not loaded!");
607 String
UCBStorageElement_Impl::GetOriginalContentType()
609 if ( m_xStream
.Is() )
610 return m_xStream
->m_aOriginalContentType
;
611 else if ( m_xStorage
.Is() )
612 return m_xStorage
->m_aOriginalContentType
;
617 sal_Bool
UCBStorageElement_Impl::IsModified()
619 sal_Bool bModified
= m_bIsRemoved
|| m_bIsInserted
|| m_aName
!= m_aOriginalName
;
622 if ( m_xStream
.Is() )
623 bModified
= m_xStream
->m_aContentType
!= m_xStream
->m_aOriginalContentType
;
624 else if ( m_xStorage
.Is() )
625 bModified
= m_xStorage
->m_aContentType
!= m_xStorage
->m_aOriginalContentType
;
631 UCBStorageStream_Impl::UCBStorageStream_Impl( const String
& rName
, StreamMode nMode
, UCBStorageStream
* pStream
, sal_Bool bDirect
, const OString
* pKey
, sal_Bool bRepair
, Reference
< XProgressHandler
> xProgress
)
632 : m_pAntiImpl( pStream
)
636 , m_nRepresentMode( nonset
)
639 , m_bSourceRead( !( nMode
& STREAM_TRUNC
) )
640 , m_bModified( sal_False
)
641 , m_bCommited( sal_False
)
642 , m_bDirect( bDirect
)
643 , m_bIsOLEStorage( sal_False
)
645 // name is last segment in URL
646 INetURLObject
aObj( rName
);
647 m_aName
= m_aOriginalName
= aObj
.GetLastName();
650 // create the content
651 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
653 OUString
aTemp( rName
);
657 xComEnv
= new ::ucbhelper::CommandEnvironment( Reference
< ::com::sun::star::task::XInteractionHandler
>(),
659 aTemp
+= OUString("?repairpackage");
662 m_pContent
= new ::ucbhelper::Content( aTemp
, xComEnv
, comphelper::getProcessComponentContext() );
668 // stream is encrypted and should be decrypted (without setting the key we'll get the raw data)
669 sal_uInt8 aBuffer
[RTL_DIGEST_LENGTH_SHA1
];
670 rtlDigestError nErr
= rtl_digest_SHA1( pKey
->getStr(), pKey
->getLength(), aBuffer
, RTL_DIGEST_LENGTH_SHA1
);
671 if ( nErr
== rtl_Digest_E_None
)
673 sal_uInt8
* pBuffer
= aBuffer
;
674 ::com::sun::star::uno::Sequence
< sal_Int8
> aSequ( (sal_Int8
*) pBuffer
, RTL_DIGEST_LENGTH_SHA1
);
675 ::com::sun::star::uno::Any aAny
;
677 m_pContent
->setPropertyValue( OUString("EncryptionKey"), aAny
);
681 catch (const ContentCreationException
&)
683 // content could not be created
684 SetError( SVSTREAM_CANNOT_MAKE
);
686 catch (const RuntimeException
&)
688 // any other error - not specified
689 SetError( ERRCODE_IO_GENERAL
);
693 UCBStorageStream_Impl::~UCBStorageStream_Impl()
696 m_rSource
= Reference
< XInputStream
>();
701 if ( m_aTempURL
.Len() )
702 ::utl::UCBContentHelper::Kill( m_aTempURL
);
709 sal_Bool
UCBStorageStream_Impl::Init()
711 if( m_nRepresentMode
== xinputstream
)
713 OSL_FAIL( "XInputStream misuse!" );
714 SetError( ERRCODE_IO_ACCESSDENIED
);
720 // no temporary stream was created
723 m_nRepresentMode
= svstream
; // can not be used as XInputStream
725 if ( !m_aTempURL
.Len() )
726 m_aTempURL
= ::utl::TempFile().GetURL();
728 m_pStream
= ::utl::UcbStreamHelper::CreateStream( m_aTempURL
, STREAM_STD_READWRITE
, sal_True
/* bFileExists */ );
729 #if OSL_DEBUG_LEVEL > 1
735 OSL_FAIL( "Suspicious temporary stream creation!" );
736 SetError( SVSTREAM_CANNOT_MAKE
);
740 SetError( m_pStream
->GetError() );
743 if( m_bSourceRead
&& !m_rSource
.is() )
745 // source file contain useful information and is not opened
746 // open it from the point of noncopied data
750 m_rSource
= m_pContent
->openStream();
752 catch (const Exception
&)
754 // usually means that stream could not be opened
759 m_pStream
->Seek( STREAM_SEEK_TO_END
);
763 m_rSource
->skipBytes( m_pStream
->Tell() );
765 catch (const BufferSizeExceededException
&)
767 // the temporary stream already contain all the data
768 m_bSourceRead
= sal_False
;
770 catch (const Exception
&)
772 // something is really wrong
773 m_bSourceRead
= sal_False
;
774 OSL_FAIL( "Can not operate original stream!" );
775 SetError( SVSTREAM_CANNOT_MAKE
);
778 m_pStream
->Seek( 0 );
782 // if the new file is edited than no source exist
783 m_bSourceRead
= sal_False
;
784 //SetError( SVSTREAM_CANNOT_MAKE );
788 DBG_ASSERT( m_rSource
.is() || !m_bSourceRead
, "Unreadable source stream!" );
793 sal_uLong
UCBStorageStream_Impl::ReadSourceWriteTemporary()
795 // read source stream till the end and copy all the data to
796 // the current position of the temporary stream
798 sal_uLong aResult
= 0;
802 Sequence
<sal_Int8
> aData(32000);
809 aReaded
= m_rSource
->readBytes( aData
, 32000 );
810 aResult
+= m_pStream
->Write( aData
.getArray(), aReaded
);
811 } while( aReaded
== 32000 );
813 catch (const Exception
&e
)
815 OSL_FAIL( OUStringToOString( e
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr() );
820 m_bSourceRead
= sal_False
;
826 sal_uLong
UCBStorageStream_Impl::ReadSourceWriteTemporary( sal_uLong aLength
)
828 // read aLength bite from the source stream and copy them to the current
829 // position of the temporary stream
831 sal_uLong aResult
= 0;
835 Sequence
<sal_Int8
> aData(32000);
840 sal_uLong aReaded
= 32000;
842 for( sal_uLong pInd
= 0; pInd
< aLength
&& aReaded
== 32000 ; pInd
+= 32000 )
844 sal_uLong aToCopy
= min( aLength
- pInd
, 32000 );
845 aReaded
= m_rSource
->readBytes( aData
, aToCopy
);
846 aResult
+= m_pStream
->Write( aData
.getArray(), aReaded
);
849 if( aResult
< aLength
)
850 m_bSourceRead
= sal_False
;
852 catch( const Exception
& e
)
854 OSL_FAIL( OUStringToOString( e
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr() );
862 sal_uLong
UCBStorageStream_Impl::CopySourceToTemporary()
864 // current position of the temporary stream is not changed
865 sal_uLong aResult
= 0;
869 sal_uLong aPos
= m_pStream
->Tell();
870 m_pStream
->Seek( STREAM_SEEK_TO_END
);
871 aResult
= ReadSourceWriteTemporary();
872 m_pStream
->Seek( aPos
);
879 // UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
880 // of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
881 sal_uLong
UCBStorageStream_Impl::GetData( void* pData
, sal_uLong nSize
)
883 sal_uLong aResult
= 0;
889 // read data that is in temporary stream
890 aResult
= m_pStream
->Read( pData
, nSize
);
891 if( m_bSourceRead
&& aResult
< nSize
)
893 // read the tail of the data from original stream
894 // copy this tail to the temporary stream
896 sal_uLong aToRead
= nSize
- aResult
;
897 pData
= (void*)( (char*)pData
+ aResult
);
901 Sequence
<sal_Int8
> aData( aToRead
);
902 sal_uLong aReaded
= m_rSource
->readBytes( aData
, aToRead
);
903 aResult
+= m_pStream
->Write( (void*)aData
.getArray(), aReaded
);
904 memcpy( pData
, aData
.getArray(), aReaded
);
906 catch (const Exception
&e
)
908 OSL_FAIL( OUStringToOString( e
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr() );
912 if( aResult
< nSize
)
913 m_bSourceRead
= sal_False
;
919 sal_uLong
UCBStorageStream_Impl::PutData( const void* pData
, sal_uLong nSize
)
921 if ( !(m_nMode
& STREAM_WRITE
) )
923 SetError( ERRCODE_IO_ACCESSDENIED
);
927 if( !nSize
|| !Init() )
930 sal_uLong aResult
= m_pStream
->Write( pData
, nSize
);
932 m_bModified
= aResult
> 0;
938 sal_uLong
UCBStorageStream_Impl::SeekPos( sal_uLong nPos
)
945 if( nPos
== STREAM_SEEK_TO_END
)
947 m_pStream
->Seek( STREAM_SEEK_TO_END
);
948 ReadSourceWriteTemporary();
949 aResult
= m_pStream
->Tell();
953 // the problem is that even if nPos is larger the length
954 // of the stream the stream pointer will be moved to this position
955 // so we have to check if temporary stream does not contain required position
957 if( m_pStream
->Tell() > nPos
958 || m_pStream
->Seek( STREAM_SEEK_TO_END
) > nPos
)
960 // no copiing is required
961 aResult
= m_pStream
->Seek( nPos
);
965 // the temp stream pointer points to the end now
966 aResult
= m_pStream
->Tell();
972 aResult
+= ReadSourceWriteTemporary( nPos
- aResult
);
974 m_bSourceRead
= sal_False
;
976 DBG_ASSERT( aResult
== m_pStream
->Tell(), "Error in stream arithmetic!\n" );
979 if( (m_nMode
& STREAM_WRITE
) && !m_bSourceRead
&& aResult
< nPos
)
981 // it means that all the Source stream was copied already
982 // but the required position still was not reached
983 // for writable streams it should be done
984 m_pStream
->SetStreamSize( nPos
);
985 aResult
= m_pStream
->Seek( STREAM_SEEK_TO_END
);
986 DBG_ASSERT( aResult
== nPos
, "Error in stream arithmetic!\n" );
995 void UCBStorageStream_Impl::SetSize( sal_uLong nSize
)
997 if ( !(m_nMode
& STREAM_WRITE
) )
999 SetError( ERRCODE_IO_ACCESSDENIED
);
1006 m_bModified
= sal_True
;
1010 sal_uLong aPos
= m_pStream
->Tell();
1011 m_pStream
->Seek( STREAM_SEEK_TO_END
);
1012 if( m_pStream
->Tell() < nSize
)
1013 ReadSourceWriteTemporary( nSize
- m_pStream
->Tell() );
1014 m_pStream
->Seek( aPos
);
1017 m_pStream
->SetStreamSize( nSize
);
1018 m_bSourceRead
= sal_False
;
1021 void UCBStorageStream_Impl::FlushData()
1025 CopySourceToTemporary();
1029 m_bCommited
= sal_True
;
1032 void UCBStorageStream_Impl::SetError( sal_uInt32 nErr
)
1037 SvStream::SetError( nErr
);
1038 if ( m_pAntiImpl
) m_pAntiImpl
->SetError( nErr
);
1042 void UCBStorageStream_Impl::ResetError()
1045 SvStream::ResetError();
1047 m_pAntiImpl
->ResetError();
1050 sal_uLong
UCBStorageStream_Impl::GetSize()
1055 sal_uLong nPos
= m_pStream
->Tell();
1056 m_pStream
->Seek( STREAM_SEEK_TO_END
);
1057 ReadSourceWriteTemporary();
1058 sal_uLong nRet
= m_pStream
->Tell();
1059 m_pStream
->Seek( nPos
);
1064 BaseStorage
* UCBStorageStream_Impl::CreateStorage()
1066 // create an OLEStorage on a SvStream ( = this )
1067 // it gets the root attribute because otherwise it would probably not write before my root is commited
1068 UCBStorageStream
* pNewStorageStream
= new UCBStorageStream( this );
1069 Storage
*pStorage
= new Storage( *pNewStorageStream
, m_bDirect
);
1071 // GetError() call cleares error code for OLE storages, must be changed in future
1072 long nTmpErr
= pStorage
->GetError();
1073 pStorage
->SetError( nTmpErr
);
1075 m_bIsOLEStorage
= !nTmpErr
;
1076 return static_cast< BaseStorage
* > ( pStorage
);
1079 sal_Int16
UCBStorageStream_Impl::Commit()
1081 // send stream to the original content
1082 // the parent storage is responsible for the correct handling of deleted contents
1083 if ( m_bCommited
|| m_bIsOLEStorage
|| m_bDirect
)
1085 // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1086 // was commited as well ( if not opened in direct mode )
1092 CopySourceToTemporary();
1094 // release all stream handles
1097 // the temporary file does not exist only for truncated streams
1098 DBG_ASSERT( m_aTempURL
.Len() || ( m_nMode
& STREAM_TRUNC
), "No temporary file to read from!");
1099 if ( !m_aTempURL
.Len() && !( m_nMode
& STREAM_TRUNC
) )
1100 throw RuntimeException();
1102 // create wrapper to stream that is only used while reading inside package component
1103 Reference
< XInputStream
> xStream
= new FileStreamWrapper_Impl( m_aTempURL
);
1106 InsertCommandArgument aArg
;
1107 aArg
.Data
= xStream
;
1108 aArg
.ReplaceExisting
= sal_True
;
1110 m_pContent
->executeCommand( OUString("insert"), aAny
);
1112 // wrapper now controls lifetime of temporary file
1115 INetURLObject
aObj( m_aURL
);
1116 aObj
.SetName( m_aName
);
1117 m_aURL
= aObj
.GetMainURL( INetURLObject::NO_DECODE
);
1118 m_bModified
= sal_False
;
1119 m_bSourceRead
= sal_True
;
1121 catch (const CommandAbortedException
&)
1123 // any command wasn't executed successfully - not specified
1124 SetError( ERRCODE_IO_GENERAL
);
1125 return COMMIT_RESULT_FAILURE
;
1127 catch (const RuntimeException
&)
1129 // any other error - not specified
1130 SetError( ERRCODE_IO_GENERAL
);
1131 return COMMIT_RESULT_FAILURE
;
1133 catch (const Exception
&)
1135 // any other error - not specified
1136 SetError( ERRCODE_IO_GENERAL
);
1137 return COMMIT_RESULT_FAILURE
;
1140 m_bCommited
= sal_False
;
1141 return COMMIT_RESULT_SUCCESS
;
1145 return COMMIT_RESULT_NOTHING_TO_DO
;
1148 sal_Bool
UCBStorageStream_Impl::Revert()
1150 // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
1153 OSL_FAIL("Revert while commit is in progress!" );
1154 return sal_False
; // ???
1158 if ( m_aTempURL
.Len() )
1160 ::utl::UCBContentHelper::Kill( m_aTempURL
);
1164 m_bSourceRead
= sal_False
;
1167 m_rSource
= m_pContent
->openStream();
1168 if( m_rSource
.is() )
1170 if ( m_pAntiImpl
&& ( m_nMode
& STREAM_TRUNC
) )
1171 // stream is in use and should be truncated
1172 m_bSourceRead
= sal_False
;
1175 m_nMode
&= ~STREAM_TRUNC
;
1176 m_bSourceRead
= sal_True
;
1180 SetError( SVSTREAM_CANNOT_MAKE
);
1182 catch (const ContentCreationException
&)
1184 SetError( ERRCODE_IO_GENERAL
);
1186 catch (const RuntimeException
&)
1188 SetError( ERRCODE_IO_GENERAL
);
1190 catch (const Exception
&)
1194 m_bModified
= sal_False
;
1195 m_aName
= m_aOriginalName
;
1196 m_aContentType
= m_aOriginalContentType
;
1197 return ( GetError() == ERRCODE_NONE
);
1200 sal_Bool
UCBStorageStream_Impl::Clear()
1202 sal_Bool bRet
= ( m_pAntiImpl
== NULL
);
1203 DBG_ASSERT( bRet
, "Removing used stream!" );
1212 void UCBStorageStream_Impl::Free()
1214 #if OSL_DEBUG_LEVEL > 1
1217 if ( m_aTempURL
.Len() )
1224 m_nRepresentMode
= nonset
;
1225 m_rSource
= Reference
< XInputStream
>();
1226 DELETEZ( m_pStream
);
1229 void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode
)
1231 sal_Bool isWritable
= (( m_nMode
& STREAM_WRITE
) != 0 );
1234 // once stream was writable, never reset to readonly
1235 nMode
|= STREAM_WRITE
;
1241 if ( nMode
& STREAM_TRUNC
)
1243 m_bSourceRead
= 0; // usually it should be 0 already but just in case...
1245 if ( m_aTempURL
.Len() )
1247 ::utl::UCBContentHelper::Kill( m_aTempURL
);
1253 UCBStorageStream::UCBStorageStream( const String
& rName
, StreamMode nMode
, sal_Bool bDirect
, const OString
* pKey
, sal_Bool bRepair
, Reference
< XProgressHandler
> xProgress
)
1255 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1256 // to class UCBStorageStream !
1257 pImp
= new UCBStorageStream_Impl( rName
, nMode
, this, bDirect
, pKey
, bRepair
, xProgress
);
1258 pImp
->AddRef(); // use direct refcounting because in header file only a pointer should be used
1259 StorageBase::m_nMode
= pImp
->m_nMode
;
1262 UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl
*pImpl
)
1265 pImp
->AddRef(); // use direct refcounting because in header file only a pointer should be used
1266 pImp
->m_pAntiImpl
= this;
1267 SetError( pImp
->m_nError
);
1268 StorageBase::m_nMode
= pImp
->m_nMode
;
1271 UCBStorageStream::~UCBStorageStream()
1273 if ( pImp
->m_nMode
& STREAM_WRITE
)
1275 pImp
->m_pAntiImpl
= NULL
;
1280 sal_uLong
UCBStorageStream::Read( void * pData
, sal_uLong nSize
)
1282 //return pImp->m_pStream->Read( pData, nSize );
1283 return pImp
->GetData( pData
, nSize
);
1286 sal_uLong
UCBStorageStream::Write( const void* pData
, sal_uLong nSize
)
1288 return pImp
->PutData( pData
, nSize
);
1291 sal_uLong
UCBStorageStream::Seek( sal_uLong nPos
)
1293 //return pImp->m_pStream->Seek( nPos );
1294 return pImp
->Seek( nPos
);
1297 sal_uLong
UCBStorageStream::Tell()
1301 return pImp
->m_pStream
->Tell();
1304 void UCBStorageStream::Flush()
1306 // streams are never really transacted, so flush also means commit !
1310 sal_Bool
UCBStorageStream::SetSize( sal_uLong nNewSize
)
1312 pImp
->SetSize( nNewSize
);
1313 return !pImp
->GetError();
1316 sal_Bool
UCBStorageStream::Validate( sal_Bool bWrite
) const
1318 return ( !bWrite
|| ( pImp
->m_nMode
& STREAM_WRITE
) );
1321 sal_Bool
UCBStorageStream::ValidateMode( StreamMode m
) const
1324 if( m
== ( STREAM_READ
| STREAM_TRUNC
) ) // from stg.cxx
1326 sal_uInt16 nCurMode
= 0xFFFF;
1327 if( ( m
& 3 ) == STREAM_READ
)
1329 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1330 if( ( ( m
& STREAM_SHARE_DENYWRITE
)
1331 && ( nCurMode
& STREAM_SHARE_DENYWRITE
) )
1332 || ( ( m
& STREAM_SHARE_DENYALL
)
1333 && ( nCurMode
& STREAM_SHARE_DENYALL
) ) )
1338 // only SHARE_DENYALL allowed
1339 // storages open in r/o mode are OK, since only
1340 // the commit may fail
1341 if( ( m
& STREAM_SHARE_DENYALL
)
1342 && ( nCurMode
& STREAM_SHARE_DENYALL
) )
1349 const SvStream
* UCBStorageStream::GetSvStream() const
1354 pImp
->CopySourceToTemporary();
1355 return pImp
->m_pStream
; // should not live longer then pImp!!!
1358 SvStream
* UCBStorageStream::GetModifySvStream()
1360 return (SvStream
*)pImp
;
1363 sal_Bool
UCBStorageStream::Equals( const BaseStorageStream
& rStream
) const
1366 return ((BaseStorageStream
*) this ) == &rStream
;
1369 sal_Bool
UCBStorageStream::Commit()
1371 // mark this stream for sending it on root commit
1376 sal_Bool
UCBStorageStream::Revert()
1378 return pImp
->Revert();
1381 sal_Bool
UCBStorageStream::CopyTo( BaseStorageStream
* pDestStm
)
1386 UCBStorageStream
* pStg
= PTR_CAST( UCBStorageStream
, pDestStm
);
1388 pStg
->pImp
->m_aContentType
= pImp
->m_aContentType
;
1390 pDestStm
->SetSize( 0 );
1391 Seek( STREAM_SEEK_TO_END
);
1392 sal_Int32 n
= Tell();
1396 if( pDestStm
->SetSize( n
) && n
)
1398 sal_uInt8
* p
= new sal_uInt8
[ 4096 ];
1400 pDestStm
->Seek( 0L );
1406 if( Read( p
, nn
) != nn
)
1408 if( pDestStm
->Write( p
, nn
) != nn
)
1419 sal_Bool
UCBStorageStream::SetProperty( const String
& rName
, const ::com::sun::star::uno::Any
& rValue
)
1421 if ( rName
.CompareToAscii("Title") == COMPARE_EQUAL
)
1424 if ( rName
.CompareToAscii("MediaType") == COMPARE_EQUAL
)
1428 pImp
->m_aContentType
= aTmp
;
1433 if ( pImp
->m_pContent
)
1435 pImp
->m_pContent
->setPropertyValue( rName
, rValue
);
1439 catch (const Exception
&)
1446 sal_uLong
UCBStorageStream::GetSize() const
1448 return pImp
->GetSize();
1451 UCBStorage::UCBStorage( SvStream
& rStrm
, sal_Bool bDirect
)
1453 String aURL
= GetLinkedFile( rStrm
);
1456 StreamMode nMode
= STREAM_READ
;
1457 if( rStrm
.IsWritable() )
1458 nMode
= STREAM_READ
| STREAM_WRITE
;
1460 ::ucbhelper::Content
aContent( aURL
, Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
1461 pImp
= new UCBStorage_Impl( aContent
, aURL
, nMode
, this, bDirect
, sal_True
);
1465 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1466 // to class UCBStorage !
1467 pImp
= new UCBStorage_Impl( rStrm
, this, bDirect
);
1472 StorageBase::m_nMode
= pImp
->m_nMode
;
1475 UCBStorage::UCBStorage( const ::ucbhelper::Content
& rContent
, const String
& rName
, StreamMode nMode
, sal_Bool bDirect
, sal_Bool bIsRoot
)
1477 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1478 // to class UCBStorage !
1479 pImp
= new UCBStorage_Impl( rContent
, rName
, nMode
, this, bDirect
, bIsRoot
);
1482 StorageBase::m_nMode
= pImp
->m_nMode
;
1485 UCBStorage::UCBStorage( const String
& rName
, StreamMode nMode
, sal_Bool bDirect
, sal_Bool bIsRoot
, sal_Bool bIsRepair
, Reference
< XProgressHandler
> xProgressHandler
)
1487 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1488 // to class UCBStorage !
1489 pImp
= new UCBStorage_Impl( rName
, nMode
, this, bDirect
, bIsRoot
, bIsRepair
, xProgressHandler
);
1492 StorageBase::m_nMode
= pImp
->m_nMode
;
1495 UCBStorage::UCBStorage( const String
& rName
, StreamMode nMode
, sal_Bool bDirect
, sal_Bool bIsRoot
)
1497 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1498 // to class UCBStorage !
1499 pImp
= new UCBStorage_Impl( rName
, nMode
, this, bDirect
, bIsRoot
, sal_False
, Reference
< XProgressHandler
>() );
1502 StorageBase::m_nMode
= pImp
->m_nMode
;
1505 UCBStorage::UCBStorage( UCBStorage_Impl
*pImpl
)
1508 pImp
->m_pAntiImpl
= this;
1509 SetError( pImp
->m_nError
);
1510 pImp
->AddRef(); // use direct refcounting because in header file only a pointer should be used
1511 StorageBase::m_nMode
= pImp
->m_nMode
;
1514 UCBStorage::~UCBStorage()
1516 if ( pImp
->m_bIsRoot
&& pImp
->m_bDirect
&& ( !pImp
->m_pTempFile
|| pImp
->m_pSource
) )
1517 // DirectMode is simulated with an AutoCommit
1520 pImp
->m_pAntiImpl
= NULL
;
1524 UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content
& rContent
, const String
& rName
, StreamMode nMode
, UCBStorage
* pStorage
, sal_Bool bDirect
, sal_Bool bIsRoot
, sal_Bool bIsRepair
, Reference
< XProgressHandler
> xProgressHandler
)
1525 : m_pAntiImpl( pStorage
)
1526 , m_pContent( new ::ucbhelper::Content( rContent
) )
1527 , m_pTempFile( NULL
)
1529 //, m_pStream( NULL )
1532 , m_bModified( sal_False
)
1533 , m_bCommited( sal_False
)
1534 , m_bDirect( bDirect
)
1535 , m_bIsRoot( bIsRoot
)
1536 , m_bDirty( sal_False
)
1537 , m_bIsLinked( sal_True
)
1538 , m_bListCreated( sal_False
)
1540 , m_aClassId( SvGlobalName() )
1541 , m_bRepairPackage( bIsRepair
)
1542 , m_xProgressHandler( xProgressHandler
)
1544 String
aName( rName
);
1547 // no name given = use temporary name!
1548 DBG_ASSERT( m_bIsRoot
, "SubStorage must have a name!" );
1549 m_pTempFile
= new ::utl::TempFile
;
1550 m_pTempFile
->EnableKillingFile( sal_True
);
1551 m_aName
= m_aOriginalName
= aName
= m_pTempFile
->GetURL();
1557 UCBStorage_Impl::UCBStorage_Impl( const String
& rName
, StreamMode nMode
, UCBStorage
* pStorage
, sal_Bool bDirect
, sal_Bool bIsRoot
, sal_Bool bIsRepair
, Reference
< XProgressHandler
> xProgressHandler
)
1558 : m_pAntiImpl( pStorage
)
1559 , m_pContent( NULL
)
1560 , m_pTempFile( NULL
)
1562 //, m_pStream( NULL )
1565 , m_bModified( sal_False
)
1566 , m_bCommited( sal_False
)
1567 , m_bDirect( bDirect
)
1568 , m_bIsRoot( bIsRoot
)
1569 , m_bDirty( sal_False
)
1570 , m_bIsLinked( sal_False
)
1571 , m_bListCreated( sal_False
)
1573 , m_aClassId( SvGlobalName() )
1574 , m_bRepairPackage( bIsRepair
)
1575 , m_xProgressHandler( xProgressHandler
)
1577 String
aName( rName
);
1580 // no name given = use temporary name!
1581 DBG_ASSERT( m_bIsRoot
, "SubStorage must have a name!" );
1582 m_pTempFile
= new ::utl::TempFile
;
1583 m_pTempFile
->EnableKillingFile( sal_True
);
1584 m_aName
= m_aOriginalName
= aName
= m_pTempFile
->GetURL();
1589 // create the special package URL for the package content
1590 String aTemp
= OUString("vnd.sun.star.pkg://");
1591 aTemp
+= String(INetURLObject::encode( aName
, INetURLObject::PART_AUTHORITY
, '%', INetURLObject::ENCODE_ALL
));
1594 if ( m_nMode
& STREAM_WRITE
)
1596 // the root storage opens the package, so make sure that there is any
1597 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( aName
, STREAM_STD_READWRITE
, m_pTempFile
!= 0 /* bFileExists */ );
1603 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1605 if ( m_aURL
.CompareToAscii( "vnd.sun.star.pkg://", 19 ) != 0 )
1606 m_bIsLinked
= sal_True
;
1610 UCBStorage_Impl::UCBStorage_Impl( SvStream
& rStream
, UCBStorage
* pStorage
, sal_Bool bDirect
)
1611 : m_pAntiImpl( pStorage
)
1612 , m_pContent( NULL
)
1613 , m_pTempFile( new ::utl::TempFile
)
1614 , m_pSource( &rStream
)
1616 , m_bModified( sal_False
)
1617 , m_bCommited( sal_False
)
1618 , m_bDirect( bDirect
)
1619 , m_bIsRoot( sal_True
)
1620 , m_bDirty( sal_False
)
1621 , m_bIsLinked( sal_False
)
1622 , m_bListCreated( sal_False
)
1624 , m_aClassId( SvGlobalName() )
1625 , m_bRepairPackage( sal_False
)
1627 // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1628 // which will be called in the storages' dtor
1629 m_pTempFile
->EnableKillingFile( sal_True
);
1630 DBG_ASSERT( !bDirect
, "Storage on a stream must not be opened in direct mode!" );
1632 // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1633 // accessed readonly
1634 // the root storage opens the package; create the special package URL for the package content
1635 String aTemp
= OUString("vnd.sun.star.pkg://");
1636 aTemp
+= String(INetURLObject::encode( m_pTempFile
->GetURL(), INetURLObject::PART_AUTHORITY
, '%', INetURLObject::ENCODE_ALL
));
1639 // copy data into the temporary file
1640 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( m_pTempFile
->GetURL(), STREAM_STD_READWRITE
, sal_True
/* bFileExists */ );
1644 rStream
>> *pStream
;
1649 // close stream and let content access the file
1652 // check opening mode
1653 m_nMode
= STREAM_READ
;
1654 if( rStream
.IsWritable() )
1655 m_nMode
= STREAM_READ
| STREAM_WRITE
;
1658 void UCBStorage_Impl::Init()
1660 // name is last segment in URL
1661 INetURLObject
aObj( m_aURL
);
1662 if ( !m_aName
.Len() )
1663 // if the name was not already set to a temp name
1664 m_aName
= m_aOriginalName
= aObj
.GetLastName();
1666 // don't create the content for disk spanned files, avoid too early access to directory and/or manifest
1667 if ( !m_pContent
&& !( m_nMode
& STORAGE_DISKSPANNED_MODE
) )
1670 if ( m_nMode
& STORAGE_DISKSPANNED_MODE
)
1672 // Hack! Avoid access to the manifest file until mediatype is not available in the first segment of a
1673 // disk spanned file
1674 m_aContentType
= m_aOriginalContentType
= OUString( "application/vnd.sun.xml.impress" );
1676 else if ( m_pContent
)
1683 if ( m_nError
== ERRCODE_NONE
)
1685 // read the manifest.xml file
1686 aObj
.Append( String( "META-INF" ) );
1687 aObj
.Append( String( "manifest.xml" ) );
1689 // create input stream
1690 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( aObj
.GetMainURL( INetURLObject::NO_DECODE
), STREAM_STD_READ
);
1691 // no stream means no manifest.xml
1694 if ( !pStream
->GetError() )
1696 ::utl::OInputStreamWrapper
* pHelper
= new ::utl::OInputStreamWrapper( *pStream
);
1697 com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> xInputStream( pHelper
);
1699 // create a manifest reader object that will read in the manifest from the stream
1700 Reference
< ::com::sun::star::packages::manifest::XManifestReader
> xReader
=
1701 ::com::sun::star::packages::manifest::ManifestReader::create(
1702 ::comphelper::getProcessComponentContext() ) ;
1703 Sequence
< Sequence
< PropertyValue
> > aProps
= xReader
->readManifestSequence( xInputStream
);
1707 xInputStream
= NULL
;
1708 SetProps( aProps
, String() );
1720 // get the manifest information from the package
1722 Any aAny
= m_pContent
->getPropertyValue( OUString("MediaType") );
1724 if ( ( aAny
>>= aTmp
) && !aTmp
.isEmpty() )
1725 m_aContentType
= m_aOriginalContentType
= aTmp
;
1727 catch (const Exception
&)
1729 DBG_ASSERT( sal_False
,
1730 "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1735 if ( m_aContentType
.Len() )
1737 // get the clipboard format using the content type
1738 ::com::sun::star::datatransfer::DataFlavor aDataFlavor
;
1739 aDataFlavor
.MimeType
= m_aContentType
;
1740 m_nFormat
= SotExchange::GetFormat( aDataFlavor
);
1742 // get the ClassId using the clipboard format ( internal table )
1743 m_aClassId
= GetClassId_Impl( m_nFormat
);
1745 // get human presentable name using the clipboard format
1746 SotExchange::GetFormatDataFlavor( m_nFormat
, aDataFlavor
);
1747 m_aUserTypeName
= aDataFlavor
.HumanPresentableName
;
1749 if( m_pContent
&& !m_bIsLinked
&& m_aClassId
!= SvGlobalName() )
1754 void UCBStorage_Impl::CreateContent()
1758 // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1759 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
1761 OUString
aTemp( m_aURL
);
1763 if ( m_bRepairPackage
)
1765 xComEnv
= new ::ucbhelper::CommandEnvironment( Reference
< ::com::sun::star::task::XInteractionHandler
>(),
1766 m_xProgressHandler
);
1767 aTemp
+= OUString("?repairpackage");
1770 m_pContent
= new ::ucbhelper::Content( aTemp
, xComEnv
, comphelper::getProcessComponentContext() );
1772 catch (const ContentCreationException
&)
1774 // content could not be created
1775 SetError( SVSTREAM_CANNOT_MAKE
);
1777 catch (const RuntimeException
&)
1779 // any other error - not specified
1780 SetError( SVSTREAM_CANNOT_MAKE
);
1784 void UCBStorage_Impl::ReadContent()
1786 if ( m_bListCreated
)
1789 m_bListCreated
= sal_True
;
1791 // create cursor for access to children
1792 Sequence
< OUString
> aProps(4);
1793 OUString
* pProps
= aProps
.getArray();
1794 pProps
[0] = OUString("Title");
1795 pProps
[1] = OUString("IsFolder");
1796 pProps
[2] = OUString("MediaType");
1797 pProps
[3] = OUString("Size");
1798 ::ucbhelper::ResultSetInclude eInclude
= ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS
;
1806 Reference
< XResultSet
> xResultSet
= m_pContent
->createCursor( aProps
, eInclude
);
1807 Reference
< XContentAccess
> xContentAccess( xResultSet
, UNO_QUERY
);
1808 Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
1809 if ( xResultSet
.is() )
1811 while ( xResultSet
->next() )
1813 // insert all into the children list
1814 OUString
aTitle( xRow
->getString(1) );
1815 OUString aContentType
;
1818 // unpacked storages have to deal with the meta-inf folder by themselves
1819 if ( aTitle
== "META-INF" )
1824 aContentType
= xRow
->getString(3);
1827 sal_Bool
bIsFolder( xRow
->getBoolean(2) );
1828 sal_Int64 nSize
= xRow
->getLong(4);
1829 UCBStorageElement_Impl
* pElement
= new UCBStorageElement_Impl( aTitle
, bIsFolder
, (sal_uLong
) nSize
);
1830 m_aChildrenList
.push_back( pElement
);
1832 sal_Bool bIsOfficeDocument
= m_bIsLinked
|| ( m_aClassId
!= SvGlobalName() );
1836 OpenStorage( pElement
, m_nMode
, m_bDirect
);
1837 if ( pElement
->m_xStorage
.Is() )
1838 pElement
->m_xStorage
->Init();
1840 else if ( bIsOfficeDocument
)
1842 // streams can be external OLE objects, so they are now folders, but storages!
1843 String
aName( m_aURL
);
1845 aName
+= String( xRow
->getString(1) );
1847 Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xComEnv
;
1848 if ( m_bRepairPackage
)
1850 xComEnv
= new ::ucbhelper::CommandEnvironment( Reference
< ::com::sun::star::task::XInteractionHandler
>(),
1851 m_xProgressHandler
);
1852 aName
+= String( "?repairpackage" );
1855 ::ucbhelper::Content
aContent( aName
, xComEnv
, comphelper::getProcessComponentContext() );
1857 OUString aMediaType
;
1858 Any aAny
= aContent
.getPropertyValue( OUString("MediaType") );
1859 if ( ( aAny
>>= aMediaType
) && ( aMediaType
.compareToAscii("application/vnd.sun.star.oleobject") == 0 ) )
1860 pElement
->m_bIsStorage
= sal_True
;
1861 else if ( aMediaType
.isEmpty() )
1863 // older files didn't have that special content type, so they must be detected
1864 OpenStream( pElement
, STREAM_STD_READ
, m_bDirect
);
1865 if ( Storage::IsStorageFile( pElement
->m_xStream
) )
1866 pElement
->m_bIsStorage
= sal_True
;
1868 pElement
->m_xStream
->Free();
1874 catch (const InteractiveIOException
& r
)
1876 if ( r
.Code
!= IOErrorCode_NOT_EXISTING
)
1877 SetError( ERRCODE_IO_GENERAL
);
1879 catch (const CommandAbortedException
&)
1881 // any command wasn't executed successfully - not specified
1882 if ( !( m_nMode
& STREAM_WRITE
) )
1883 // if the folder was just inserted and not already commited, this is not an error!
1884 SetError( ERRCODE_IO_GENERAL
);
1886 catch (const RuntimeException
&)
1888 // any other error - not specified
1889 SetError( ERRCODE_IO_GENERAL
);
1891 catch (const ResultSetException
&)
1893 // means that the package file is broken
1894 SetError( ERRCODE_IO_BROKENPACKAGE
);
1896 catch (const SQLException
&)
1898 // means that the file can be broken
1899 SetError( ERRCODE_IO_WRONGFORMAT
);
1901 catch (const Exception
&)
1903 // any other error - not specified
1904 SetError( ERRCODE_IO_GENERAL
);
1908 void UCBStorage_Impl::SetError( long nError
)
1913 if ( m_pAntiImpl
) m_pAntiImpl
->SetError( nError
);
1917 sal_Int32
UCBStorage_Impl::GetObjectCount()
1919 sal_Int32 nCount
= m_aChildrenList
.size();
1920 for ( size_t i
= 0; i
< m_aChildrenList
.size(); ++i
)
1922 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
1923 DBG_ASSERT( !pElement
->m_bIsFolder
|| pElement
->m_xStorage
.Is(), "Storage should be open!" );
1924 if ( pElement
->m_bIsFolder
&& pElement
->m_xStorage
.Is() )
1925 nCount
+= pElement
->m_xStorage
->GetObjectCount();
1931 OUString
Find_Impl( const Sequence
< Sequence
< PropertyValue
> >& rSequence
, const OUString
& rPath
)
1933 sal_Bool bFound
= sal_False
;
1934 for ( sal_Int32 nSeqs
=0; nSeqs
<rSequence
.getLength(); nSeqs
++ )
1936 const Sequence
< PropertyValue
>& rMyProps
= rSequence
[nSeqs
];
1939 for ( sal_Int32 nProps
=0; nProps
<rMyProps
.getLength(); nProps
++ )
1941 const PropertyValue
& rAny
= rMyProps
[nProps
];
1942 if ( rAny
.Name
== "FullPath" )
1945 if ( ( rAny
.Value
>>= aTmp
) && aTmp
== rPath
)
1947 if ( !aType
.isEmpty() )
1950 else if ( rAny
.Name
== "MediaType" )
1952 if ( ( rAny
.Value
>>= aType
) && !aType
.isEmpty() && bFound
)
1964 void UCBStorage_Impl::SetProps( const Sequence
< Sequence
< PropertyValue
> >& rSequence
, const String
& rPath
)
1966 String
aPath( rPath
);
1971 m_aContentType
= m_aOriginalContentType
= Find_Impl( rSequence
, aPath
);
1974 // the "FullPath" of a child always starts without '/'
1977 for ( size_t i
= 0; i
< m_aChildrenList
.size(); ++i
)
1979 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
1980 DBG_ASSERT( !pElement
->m_bIsFolder
|| pElement
->m_xStorage
.Is(), "Storage should be open!" );
1981 if ( pElement
->m_bIsFolder
&& pElement
->m_xStorage
.Is() )
1982 pElement
->m_xStorage
->SetProps( rSequence
, aPath
);
1985 String
aElementPath( aPath
);
1986 aElementPath
+= pElement
->m_aName
;
1987 pElement
->SetContentType( Find_Impl( rSequence
, aElementPath
) );
1991 if ( m_aContentType
.Len() )
1993 // get the clipboard format using the content type
1994 ::com::sun::star::datatransfer::DataFlavor aDataFlavor
;
1995 aDataFlavor
.MimeType
= m_aContentType
;
1996 m_nFormat
= SotExchange::GetFormat( aDataFlavor
);
1998 // get the ClassId using the clipboard format ( internal table )
1999 m_aClassId
= GetClassId_Impl( m_nFormat
);
2001 // get human presentable name using the clipboard format
2002 SotExchange::GetFormatDataFlavor( m_nFormat
, aDataFlavor
);
2003 m_aUserTypeName
= aDataFlavor
.HumanPresentableName
;
2007 void UCBStorage_Impl::GetProps( sal_Int32
& nProps
, Sequence
< Sequence
< PropertyValue
> >& rSequence
, const String
& rPath
)
2009 // first my own properties
2010 Sequence
< PropertyValue
> aProps(2);
2012 // first property is the "FullPath" name
2013 // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
2014 String
aPath( rPath
);
2018 aProps
[0].Name
= OUString("MediaType");
2019 aProps
[0].Value
<<= (OUString
) m_aContentType
;
2020 aProps
[1].Name
= OUString("FullPath");
2021 aProps
[1].Value
<<= (OUString
) aPath
;
2022 rSequence
[ nProps
++ ] = aProps
;
2025 // the "FullPath" of a child always starts without '/'
2028 // now the properties of my elements
2029 for ( size_t i
= 0; i
< m_aChildrenList
.size(); ++i
)
2031 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
2032 DBG_ASSERT( !pElement
->m_bIsFolder
|| pElement
->m_xStorage
.Is(), "Storage should be open!" );
2033 if ( pElement
->m_bIsFolder
&& pElement
->m_xStorage
.Is() )
2034 // storages add there properties by themselves ( see above )
2035 pElement
->m_xStorage
->GetProps( nProps
, rSequence
, aPath
);
2038 // properties of streams
2039 String
aElementPath( aPath
);
2040 aElementPath
+= pElement
->m_aName
;
2041 aProps
[0].Name
= OUString("MediaType");
2042 aProps
[0].Value
<<= (OUString
) pElement
->GetContentType();
2043 aProps
[1].Name
= OUString("FullPath");
2044 aProps
[1].Value
<<= (OUString
) aElementPath
;
2045 rSequence
[ nProps
++ ] = aProps
;
2050 UCBStorage_Impl::~UCBStorage_Impl()
2052 // first delete elements!
2053 for ( size_t i
= 0, n
= m_aChildrenList
.size(); i
< n
; ++i
)
2054 delete m_aChildrenList
[ i
];
2055 m_aChildrenList
.clear();
2061 sal_Bool
UCBStorage_Impl::Insert( ::ucbhelper::Content
*pContent
)
2063 // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
2064 // it must be inserted with a title and a type
2065 sal_Bool bRet
= sal_False
;
2069 Sequence
< ContentInfo
> aInfo
= pContent
->queryCreatableContentsInfo();
2070 sal_Int32 nCount
= aInfo
.getLength();
2074 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
2076 // Simply look for the first KIND_FOLDER...
2077 const ContentInfo
& rCurr
= aInfo
[i
];
2078 if ( rCurr
.Attributes
& ContentInfoAttribute::KIND_FOLDER
)
2080 // Make sure the only required bootstrap property is "Title",
2081 const Sequence
< Property
> & rProps
= rCurr
.Properties
;
2082 if ( rProps
.getLength() != 1 )
2085 if ( rProps
[ 0 ].Name
!= "Title" )
2088 Sequence
< OUString
> aNames(1);
2089 OUString
* pNames
= aNames
.getArray();
2090 pNames
[0] = OUString( "Title" );
2091 Sequence
< Any
> aValues(1);
2092 Any
* pValues
= aValues
.getArray();
2093 pValues
[0] = makeAny( OUString( m_aName
) );
2096 if ( !pContent
->insertNewContent( rCurr
.Type
, aNames
, aValues
, aNewFolder
) )
2099 // remove old content, create an "empty" new one and initialize it with the new inserted
2100 DELETEZ( m_pContent
);
2101 m_pContent
= new ::ucbhelper::Content( aNewFolder
);
2106 catch (const CommandAbortedException
&)
2108 // any command wasn't executed successfully - not specified
2109 SetError( ERRCODE_IO_GENERAL
);
2111 catch (const RuntimeException
&)
2113 // any other error - not specified
2114 SetError( ERRCODE_IO_GENERAL
);
2116 catch (const Exception
&)
2118 // any other error - not specified
2119 SetError( ERRCODE_IO_GENERAL
);
2125 sal_Int16
UCBStorage_Impl::Commit()
2127 // send all changes to the package
2128 sal_Int16 nRet
= COMMIT_RESULT_NOTHING_TO_DO
;
2130 // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
2131 // commit command has been sent
2132 if ( ( m_nMode
& STREAM_WRITE
) && ( m_bCommited
|| m_bDirect
) )
2136 // all errors will be caught in the "catch" statement outside the loop
2137 for ( size_t i
= 0; i
< m_aChildrenList
.size() && nRet
; ++i
)
2139 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
2140 ::ucbhelper::Content
* pContent
= pElement
->GetContent();
2141 sal_Bool bDeleteContent
= sal_False
;
2142 if ( !pContent
&& pElement
->IsModified() )
2144 // if the element has never been opened, no content has been created until now
2145 bDeleteContent
= sal_True
; // remember to delete it later
2146 String
aName( m_aURL
);
2148 aName
+= pElement
->m_aOriginalName
;
2149 pContent
= new ::ucbhelper::Content( aName
, Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
2152 if ( pElement
->m_bIsRemoved
)
2154 // was it inserted, then removed (so there would be nothing to do!)
2155 if ( !pElement
->m_bIsInserted
)
2157 // first remove all open stream handles
2158 if( !pElement
->m_xStream
.Is() || pElement
->m_xStream
->Clear() )
2160 pContent
->executeCommand( OUString("delete"), makeAny( sal_Bool( sal_True
) ) );
2161 nRet
= COMMIT_RESULT_SUCCESS
;
2164 // couldn't release stream because there are external references to it
2165 nRet
= COMMIT_RESULT_FAILURE
;
2170 sal_Int16 nLocalRet
= COMMIT_RESULT_NOTHING_TO_DO
;
2171 if ( pElement
->m_xStorage
.Is() )
2173 // element is a storage
2174 // do a commit in the following cases:
2175 // - if storage is already inserted, and changed
2176 // - storage is not in a package
2177 // - it's a new storage, try to insert and commit if successful inserted
2178 if ( !pElement
->m_bIsInserted
|| m_bIsLinked
|| pElement
->m_xStorage
->Insert( m_pContent
) )
2180 nLocalRet
= pElement
->m_xStorage
->Commit();
2181 pContent
= pElement
->GetContent();
2184 else if ( pElement
->m_xStream
.Is() )
2186 // element is a stream
2187 nLocalRet
= pElement
->m_xStream
->Commit();
2188 if ( pElement
->m_xStream
->m_bIsOLEStorage
)
2190 // OLE storage should be stored encrytped, if the storage uses encryption
2191 pElement
->m_xStream
->m_aContentType
= OUString("application/vnd.sun.star.oleobject");
2193 aValue
<<= (sal_Bool
) sal_True
;
2194 pElement
->m_xStream
->m_pContent
->setPropertyValue(OUString("Encrypted"), aValue
);
2197 pContent
= pElement
->GetContent();
2200 if ( pElement
->m_aName
!= pElement
->m_aOriginalName
)
2202 // name ( title ) of the element was changed
2203 nLocalRet
= COMMIT_RESULT_SUCCESS
;
2205 aAny
<<= (OUString
) pElement
->m_aName
;
2206 pContent
->setPropertyValue( OUString("Title"), aAny
);
2209 if ( pElement
->IsLoaded() && pElement
->GetContentType() != pElement
->GetOriginalContentType() )
2211 // mediatype of the element was changed
2212 nLocalRet
= COMMIT_RESULT_SUCCESS
;
2214 aAny
<<= (OUString
) pElement
->GetContentType();
2215 pContent
->setPropertyValue( OUString("MediaType"), aAny
);
2218 if ( nLocalRet
!= COMMIT_RESULT_NOTHING_TO_DO
)
2222 if ( bDeleteContent
)
2223 // content was created inside the loop
2226 if ( nRet
== COMMIT_RESULT_FAILURE
)
2230 catch (const ContentCreationException
&)
2232 // content could not be created
2233 SetError( ERRCODE_IO_NOTEXISTS
);
2234 return COMMIT_RESULT_FAILURE
;
2236 catch (const CommandAbortedException
&)
2238 // any command wasn't executed successfully - not specified
2239 SetError( ERRCODE_IO_GENERAL
);
2240 return COMMIT_RESULT_FAILURE
;
2242 catch (const RuntimeException
&)
2244 // any other error - not specified
2245 SetError( ERRCODE_IO_GENERAL
);
2246 return COMMIT_RESULT_FAILURE
;
2248 catch (const Exception
&)
2250 // any other error - not specified
2251 SetError( ERRCODE_IO_GENERAL
);
2252 return COMMIT_RESULT_FAILURE
;
2255 if ( m_bIsRoot
&& m_pContent
)
2257 // the root storage must flush the root package content
2258 if ( nRet
== COMMIT_RESULT_SUCCESS
)
2262 // commit the media type to the JAR file
2263 // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2265 aType
<<= (OUString
) m_aContentType
;
2266 m_pContent
->setPropertyValue( OUString("MediaType"), aType
);
2270 // write a manifest file
2271 // first create a subfolder "META-inf"
2272 Content aNewSubFolder
;
2273 sal_Bool bRet
= ::utl::UCBContentHelper::MakeFolder( *m_pContent
, OUString("META-INF"), aNewSubFolder
);
2276 // create a stream to write the manifest file - use a temp file
2277 String
aURL( aNewSubFolder
.getURL() );
2278 ::utl::TempFile
* pTempFile
= new ::utl::TempFile( &aURL
);
2280 // get the stream from the temp file and create an output stream wrapper
2281 SvStream
* pStream
= pTempFile
->GetStream( STREAM_STD_READWRITE
);
2282 ::utl::OOutputStreamWrapper
* pHelper
= new ::utl::OOutputStreamWrapper( *pStream
);
2283 com::sun::star::uno::Reference
< ::com::sun::star::io::XOutputStream
> xOutputStream( pHelper
);
2285 // create a manifest writer object that will fill the stream
2286 Reference
< ::com::sun::star::packages::manifest::XManifestWriter
> xWriter
=
2287 ::com::sun::star::packages::manifest::ManifestWriter::create(
2288 ::comphelper::getProcessComponentContext() );
2289 sal_Int32 nCount
= GetObjectCount() + 1;
2290 Sequence
< Sequence
< PropertyValue
> > aProps( nCount
);
2291 sal_Int32 nProps
= 0;
2292 GetProps( nProps
, aProps
, String() );
2293 xWriter
->writeManifestSequence( xOutputStream
, aProps
);
2295 // move the stream to its desired location
2296 Content
aSource( pTempFile
->GetURL(), Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
2298 xOutputStream
= NULL
;
2299 DELETEZ( pTempFile
);
2300 aNewSubFolder
.transferContent( aSource
, InsertOperation_MOVE
, OUString("manifest.xml"), NameClash::OVERWRITE
);
2305 #if OSL_DEBUG_LEVEL > 1
2306 fprintf ( stderr
, "Files: %i\n", nOpenFiles
);
2307 fprintf ( stderr
, "Streams: %i\n", nOpenStreams
);
2311 m_pContent
->executeCommand( OUString("flush"), aAny
);
2312 if ( m_pSource
!= 0 )
2314 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( m_pTempFile
->GetURL(), STREAM_STD_READ
);
2315 m_pSource
->SetStreamSize(0);
2316 // m_pSource->Seek(0);
2317 *pStream
>> *m_pSource
;
2323 catch (const CommandAbortedException
&)
2325 // how to tell the content : forget all changes ?!
2326 // or should we assume that the content does it by itself because he throwed an exception ?!
2327 // any command wasn't executed successfully - not specified
2328 SetError( ERRCODE_IO_GENERAL
);
2329 return COMMIT_RESULT_FAILURE
;
2331 catch (const RuntimeException
&)
2333 // how to tell the content : forget all changes ?!
2334 // or should we assume that the content does it by itself because he throwed an exception ?!
2335 // any other error - not specified
2336 SetError( ERRCODE_IO_GENERAL
);
2337 return COMMIT_RESULT_FAILURE
;
2339 catch (const InteractiveIOException
& r
)
2341 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
|| r
.Code
== IOErrorCode_LOCKING_VIOLATION
)
2342 SetError( ERRCODE_IO_ACCESSDENIED
);
2343 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
2344 SetError( ERRCODE_IO_NOTEXISTS
);
2345 else if ( r
.Code
== IOErrorCode_CANT_READ
)
2346 SetError( ERRCODE_IO_CANTREAD
);
2347 else if ( r
.Code
== IOErrorCode_CANT_WRITE
)
2348 SetError( ERRCODE_IO_CANTWRITE
);
2350 SetError( ERRCODE_IO_GENERAL
);
2352 return COMMIT_RESULT_FAILURE
;
2354 catch (const Exception
&)
2356 // how to tell the content : forget all changes ?!
2357 // or should we assume that the content does it by itself because he throwed an exception ?!
2358 // any other error - not specified
2359 SetError( ERRCODE_IO_GENERAL
);
2360 return COMMIT_RESULT_FAILURE
;
2363 else if ( nRet
!= COMMIT_RESULT_NOTHING_TO_DO
)
2365 // how to tell the content : forget all changes ?! Should we ?!
2366 SetError( ERRCODE_IO_GENERAL
);
2370 // after successful root commit all elements names and types are adjusted and all removed elements
2371 // are also removed from the lists
2372 for ( size_t i
= 0; i
< m_aChildrenList
.size(); )
2374 UCBStorageElement_Impl
* pInnerElement
= m_aChildrenList
[ i
];
2375 if ( pInnerElement
->m_bIsRemoved
)
2377 UCBStorageElementList_Impl::iterator it
= m_aChildrenList
.begin();
2378 ::std::advance( it
, i
);
2380 m_aChildrenList
.erase( it
);
2384 pInnerElement
->m_aOriginalName
= pInnerElement
->m_aName
;
2385 pInnerElement
->m_bIsInserted
= sal_False
;
2391 m_bCommited
= sal_False
;
2397 sal_Bool
UCBStorage_Impl::Revert()
2399 for ( size_t i
= 0; i
< m_aChildrenList
.size(); )
2401 UCBStorageElement_Impl
* pElement
= m_aChildrenList
[ i
];
2402 pElement
->m_bIsRemoved
= sal_False
;
2403 if ( pElement
->m_bIsInserted
)
2405 UCBStorageElementList_Impl::iterator it
= m_aChildrenList
.begin();
2406 ::std::advance( it
, i
);
2408 m_aChildrenList
.erase( it
);
2412 if ( pElement
->m_xStream
.Is() )
2414 pElement
->m_xStream
->m_bCommited
= sal_False
;
2415 pElement
->m_xStream
->Revert();
2417 else if ( pElement
->m_xStorage
.Is() )
2419 pElement
->m_xStorage
->m_bCommited
= sal_False
;
2420 pElement
->m_xStorage
->Revert();
2423 pElement
->m_aName
= pElement
->m_aOriginalName
;
2424 pElement
->m_bIsRemoved
= sal_False
;
2431 const String
& UCBStorage::GetName() const
2433 return pImp
->m_aName
; // pImp->m_aURL ?!
2436 sal_Bool
UCBStorage::IsRoot() const
2438 return pImp
->m_bIsRoot
;
2441 void UCBStorage::SetDirty()
2443 pImp
->m_bDirty
= sal_True
;
2446 void UCBStorage::SetClass( const SvGlobalName
& rClass
, sal_uLong nOriginalClipFormat
, const String
& rUserTypeName
)
2448 pImp
->m_aClassId
= rClass
;
2449 pImp
->m_nFormat
= nOriginalClipFormat
;
2450 pImp
->m_aUserTypeName
= rUserTypeName
;
2452 // in UCB storages only the content type will be stored, all other information can be reconstructed
2453 // ( see the UCBStorage_Impl::Init() method )
2454 ::com::sun::star::datatransfer::DataFlavor aDataFlavor
;
2455 SotExchange::GetFormatDataFlavor( pImp
->m_nFormat
, aDataFlavor
);
2456 pImp
->m_aContentType
= aDataFlavor
.MimeType
;
2459 void UCBStorage::SetClassId( const ClsId
& rClsId
)
2461 pImp
->m_aClassId
= SvGlobalName( (const CLSID
&) rClsId
);
2462 if ( pImp
->m_aClassId
== SvGlobalName() )
2465 // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are
2466 // stored in one the substreams
2467 // UCB storages store the content type information as content type in the manifest file and so this information must be
2468 // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2470 pImp
->m_nFormat
= GetFormatId_Impl( pImp
->m_aClassId
);
2471 if ( pImp
->m_nFormat
)
2473 ::com::sun::star::datatransfer::DataFlavor aDataFlavor
;
2474 SotExchange::GetFormatDataFlavor( pImp
->m_nFormat
, aDataFlavor
);
2475 pImp
->m_aUserTypeName
= aDataFlavor
.HumanPresentableName
;
2476 pImp
->m_aContentType
= aDataFlavor
.MimeType
;
2480 const ClsId
& UCBStorage::GetClassId() const
2482 return ( const ClsId
& ) pImp
->m_aClassId
.GetCLSID();
2485 void UCBStorage::SetConvertClass( const SvGlobalName
& /*rConvertClass*/, sal_uLong
/*nOriginalClipFormat*/, const String
& /*rUserTypeName*/ )
2490 sal_Bool
UCBStorage::ShouldConvert()
2496 SvGlobalName
UCBStorage::GetClassName()
2498 return pImp
->m_aClassId
;
2501 sal_uLong
UCBStorage::GetFormat()
2503 return pImp
->m_nFormat
;
2506 String
UCBStorage::GetUserName()
2508 OSL_FAIL("UserName is not implemented in UCB storages!" );
2509 return pImp
->m_aUserTypeName
;
2512 void UCBStorage::FillInfoList( SvStorageInfoList
* pList
) const
2514 // put information in childrenlist into StorageInfoList
2515 for ( size_t i
= 0; i
< pImp
->GetChildrenList().size(); ++i
)
2517 UCBStorageElement_Impl
* pElement
= pImp
->GetChildrenList()[ i
];
2518 if ( !pElement
->m_bIsRemoved
)
2520 // problem: what about the size of a substorage ?!
2521 sal_uLong nSize
= pElement
->m_nSize
;
2522 if ( pElement
->m_xStream
.Is() )
2523 nSize
= pElement
->m_xStream
->GetSize();
2524 SvStorageInfo
aInfo( pElement
->m_aName
, nSize
, pElement
->m_bIsStorage
);
2525 pList
->push_back( aInfo
);
2530 sal_Bool
UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl
& rElement
, BaseStorage
* pDest
, const String
& rNew
) const
2532 // insert stream or storage into the list or stream of the destination storage
2533 // not into the content, this will be done on commit !
2534 // be aware of name changes !
2535 if ( !rElement
.m_bIsStorage
)
2537 // copy the streams data
2538 // the destination stream must not be open
2539 BaseStorageStream
* pOtherStream
= pDest
->OpenStream( rNew
, STREAM_WRITE
| STREAM_SHARE_DENYALL
, pImp
->m_bDirect
);
2540 BaseStorageStream
* pStream
= NULL
;
2541 sal_Bool bDeleteStream
= sal_False
;
2543 // if stream is already open, it is allowed to copy it, so be aware of this
2544 if ( rElement
.m_xStream
.Is() )
2545 pStream
= rElement
.m_xStream
->m_pAntiImpl
;
2548 pStream
= ( const_cast < UCBStorage
* > (this) )->OpenStream( rElement
.m_aName
, STREAM_STD_READ
, pImp
->m_bDirect
);
2549 bDeleteStream
= sal_True
;
2552 pStream
->CopyTo( pOtherStream
);
2553 SetError( pStream
->GetError() );
2554 if( pOtherStream
->GetError() )
2555 pDest
->SetError( pOtherStream
->GetError() );
2557 pOtherStream
->Commit();
2559 if ( bDeleteStream
)
2561 delete pOtherStream
;
2565 // copy the storage content
2566 // the destination storage must not be open
2567 BaseStorage
* pStorage
= NULL
;
2569 // if stream is already open, it is allowed to copy it, so be aware of this
2570 sal_Bool bDeleteStorage
= sal_False
;
2571 if ( rElement
.m_xStorage
.Is() )
2572 pStorage
= rElement
.m_xStorage
->m_pAntiImpl
;
2575 pStorage
= ( const_cast < UCBStorage
* > (this) )->OpenStorage( rElement
.m_aName
, pImp
->m_nMode
, pImp
->m_bDirect
);
2576 bDeleteStorage
= sal_True
;
2579 UCBStorage
* pUCBDest
= PTR_CAST( UCBStorage
, pDest
);
2580 UCBStorage
* pUCBCopy
= PTR_CAST( UCBStorage
, pStorage
);
2582 sal_Bool bOpenUCBStorage
= pUCBDest
&& pUCBCopy
;
2583 BaseStorage
* pOtherStorage
= bOpenUCBStorage
?
2584 pDest
->OpenUCBStorage( rNew
, STREAM_WRITE
| STREAM_SHARE_DENYALL
, pImp
->m_bDirect
) :
2585 pDest
->OpenOLEStorage( rNew
, STREAM_WRITE
| STREAM_SHARE_DENYALL
, pImp
->m_bDirect
);
2587 // For UCB storages, the class id and the format id may differ,
2588 // do passing the class id is not sufficient.
2589 if( bOpenUCBStorage
)
2590 pOtherStorage
->SetClass( pStorage
->GetClassName(),
2591 pStorage
->GetFormat(),
2592 pUCBCopy
->pImp
->m_aUserTypeName
);
2594 pOtherStorage
->SetClassId( pStorage
->GetClassId() );
2595 pStorage
->CopyTo( pOtherStorage
);
2596 SetError( pStorage
->GetError() );
2597 if( pOtherStorage
->GetError() )
2598 pDest
->SetError( pOtherStorage
->GetError() );
2600 pOtherStorage
->Commit();
2602 if ( bDeleteStorage
)
2604 delete pOtherStorage
;
2607 return sal_Bool( Good() && pDest
->Good() );
2610 UCBStorageElement_Impl
* UCBStorage::FindElement_Impl( const String
& rName
) const
2612 DBG_ASSERT( rName
.Len(), "Name is empty!" );
2613 for ( size_t i
= 0, n
= pImp
->GetChildrenList().size(); i
< n
; ++i
)
2615 UCBStorageElement_Impl
* pElement
= pImp
->GetChildrenList()[ i
];
2616 if ( pElement
->m_aName
== rName
&& !pElement
->m_bIsRemoved
)
2622 sal_Bool
UCBStorage::CopyTo( BaseStorage
* pDestStg
) const
2624 DBG_ASSERT( pDestStg
!= ((BaseStorage
*)this), "Self-Copying is not possible!" );
2625 if ( pDestStg
== ((BaseStorage
*)this) )
2628 // perhaps it's also a problem if one storage is a parent of the other ?!
2629 // or if not: could be optimized ?!
2631 // For UCB storages, the class id and the format id may differ,
2632 // do passing the class id is not sufficient.
2633 if( pDestStg
->ISA( UCBStorage
) )
2634 pDestStg
->SetClass( pImp
->m_aClassId
, pImp
->m_nFormat
,
2635 pImp
->m_aUserTypeName
);
2637 pDestStg
->SetClassId( GetClassId() );
2638 pDestStg
->SetDirty();
2640 sal_Bool bRet
= sal_True
;
2641 for ( size_t i
= 0; i
< pImp
->GetChildrenList().size() && bRet
; ++i
)
2643 UCBStorageElement_Impl
* pElement
= pImp
->GetChildrenList()[ i
];
2644 if ( !pElement
->m_bIsRemoved
)
2645 bRet
= CopyStorageElement_Impl( *pElement
, pDestStg
, pElement
->m_aName
);
2649 SetError( pDestStg
->GetError() );
2650 return sal_Bool( Good() && pDestStg
->Good() );
2653 sal_Bool
UCBStorage::CopyTo( const String
& rElemName
, BaseStorage
* pDest
, const String
& rNew
)
2655 if( !rElemName
.Len() )
2658 if ( pDest
== ((BaseStorage
*) this) )
2660 // can't double an element
2665 // for copying no optimization is useful, because in every case the stream data must be copied
2666 UCBStorageElement_Impl
* pElement
= FindElement_Impl( rElemName
);
2668 return CopyStorageElement_Impl( *pElement
, pDest
, rNew
);
2671 SetError( SVSTREAM_FILE_NOT_FOUND
);
2677 sal_Bool
UCBStorage::Commit()
2679 // mark this storage for sending it on root commit
2680 pImp
->m_bCommited
= sal_True
;
2681 if ( pImp
->m_bIsRoot
)
2682 // the root storage coordinates commiting by sending a Commit command to its content
2683 return ( pImp
->Commit() != COMMIT_RESULT_FAILURE
);
2688 sal_Bool
UCBStorage::Revert()
2690 return pImp
->Revert();
2693 BaseStorageStream
* UCBStorage::OpenStream( const String
& rEleName
, StreamMode nMode
, sal_Bool bDirect
, const OString
* pKey
)
2695 if( !rEleName
.Len() )
2698 // try to find the storage element
2699 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2702 // element does not exist, check if creation is allowed
2703 if( ( nMode
& STREAM_NOCREATE
) )
2705 SetError( ( nMode
& STREAM_WRITE
) ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
2706 String
aName( pImp
->m_aURL
);
2709 UCBStorageStream
* pStream
= new UCBStorageStream( aName
, nMode
, bDirect
, pKey
, pImp
->m_bRepairPackage
, pImp
->m_xProgressHandler
);
2710 pStream
->SetError( GetError() );
2711 pStream
->pImp
->m_aName
= rEleName
;
2716 // create a new UCBStorageElement and insert it into the list
2717 pElement
= new UCBStorageElement_Impl( rEleName
);
2718 pElement
->m_bIsInserted
= sal_True
;
2719 pImp
->m_aChildrenList
.push_back( pElement
);
2723 if ( pElement
&& !pElement
->m_bIsFolder
)
2725 // check if stream is already created
2726 if ( pElement
->m_xStream
.Is() )
2728 // stream has already been created; if it has no external reference, it may be opened another time
2729 if ( pElement
->m_xStream
->m_pAntiImpl
)
2731 OSL_FAIL("Stream is already open!" );
2732 SetError( SVSTREAM_ACCESS_DENIED
); // ???
2737 // check if stream is opened with the same keyword as before
2738 // if not, generate a new stream because it could be encrypted vs. decrypted!
2742 if ( pElement
->m_xStream
->m_aKey
== aKey
)
2744 pElement
->m_xStream
->PrepareCachedForReopen( nMode
);
2746 return new UCBStorageStream( pElement
->m_xStream
);
2751 // stream is opened the first time
2752 pImp
->OpenStream( pElement
, nMode
, bDirect
, pKey
);
2754 // if name has been changed before creating the stream: set name!
2755 pElement
->m_xStream
->m_aName
= rEleName
;
2756 return new UCBStorageStream( pElement
->m_xStream
);
2762 UCBStorageStream_Impl
* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl
* pElement
, StreamMode nMode
, sal_Bool bDirect
, const OString
* pKey
)
2764 String
aName( m_aURL
);
2766 aName
+= pElement
->m_aOriginalName
;
2767 pElement
->m_xStream
= new UCBStorageStream_Impl( aName
, nMode
, NULL
, bDirect
, pKey
, m_bRepairPackage
, m_xProgressHandler
);
2768 return pElement
->m_xStream
;
2771 BaseStorage
* UCBStorage::OpenUCBStorage( const String
& rEleName
, StreamMode nMode
, sal_Bool bDirect
)
2773 if( !rEleName
.Len() )
2776 return OpenStorage_Impl( rEleName
, nMode
, bDirect
, sal_True
);
2779 BaseStorage
* UCBStorage::OpenOLEStorage( const String
& rEleName
, StreamMode nMode
, sal_Bool bDirect
)
2781 if( !rEleName
.Len() )
2784 return OpenStorage_Impl( rEleName
, nMode
, bDirect
, sal_False
);
2787 BaseStorage
* UCBStorage::OpenStorage( const String
& rEleName
, StreamMode nMode
, bool bDirect
)
2789 if( !rEleName
.Len() )
2792 return OpenStorage_Impl( rEleName
, nMode
, bDirect
, sal_True
);
2795 BaseStorage
* UCBStorage::OpenStorage_Impl( const String
& rEleName
, StreamMode nMode
, sal_Bool bDirect
, sal_Bool bForceUCBStorage
)
2797 // try to find the storage element
2798 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2801 // element does not exist, check if creation is allowed
2802 if( ( nMode
& STREAM_NOCREATE
) )
2804 SetError( ( nMode
& STREAM_WRITE
) ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
2805 String
aName( pImp
->m_aURL
);
2807 aName
+= rEleName
; // ???
2808 UCBStorage
*pStorage
= new UCBStorage( aName
, nMode
, bDirect
, sal_False
, pImp
->m_bRepairPackage
, pImp
->m_xProgressHandler
);
2809 pStorage
->pImp
->m_bIsRoot
= sal_False
;
2810 pStorage
->pImp
->m_bListCreated
= sal_True
; // the storage is pretty new, nothing to read
2811 pStorage
->SetError( GetError() );
2815 // create a new UCBStorageElement and insert it into the list
2816 // problem: perhaps an OLEStorage should be created ?!
2817 // Because nothing is known about the element that should be created, an external parameter is needed !
2818 pElement
= new UCBStorageElement_Impl( rEleName
);
2819 pElement
->m_bIsInserted
= sal_True
;
2820 pImp
->m_aChildrenList
.push_back( pElement
);
2823 if ( !pElement
->m_bIsFolder
&& ( pElement
->m_bIsStorage
|| !bForceUCBStorage
) )
2825 // create OLE storages on a stream ( see ctor of SotStorage )
2826 // Such a storage will be created on a UCBStorageStream; it will write into the stream
2827 // if it is opened in direct mode or when it is committed. In this case the stream will be
2828 // modified and then it MUST be treated as commited.
2829 if ( !pElement
->m_xStream
.Is() )
2831 BaseStorageStream
* pStr
= OpenStream( rEleName
, nMode
, bDirect
);
2832 UCBStorageStream
* pStream
= PTR_CAST( UCBStorageStream
, pStr
);
2835 SetError( ( nMode
& STREAM_WRITE
) ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
2839 pElement
->m_xStream
= pStream
->pImp
;
2843 pElement
->m_xStream
->PrepareCachedForReopen( nMode
);
2844 pElement
->m_xStream
->Init();
2846 pElement
->m_bIsStorage
= sal_True
;
2847 return pElement
->m_xStream
->CreateStorage(); // can only be created in transacted mode
2849 else if ( pElement
->m_xStorage
.Is() )
2851 // storage has already been opened; if it has no external reference, it may be opened another time
2852 if ( pElement
->m_xStorage
->m_pAntiImpl
)
2854 OSL_FAIL("Storage is already open!" );
2855 SetError( SVSTREAM_ACCESS_DENIED
); // ???
2859 sal_Bool bIsWritable
= (( pElement
->m_xStorage
->m_nMode
& STREAM_WRITE
) != 0);
2860 if ( !bIsWritable
&& (( nMode
& STREAM_WRITE
) != 0 ))
2862 String
aName( pImp
->m_aURL
);
2864 aName
+= pElement
->m_aOriginalName
;
2865 UCBStorage
* pStorage
= new UCBStorage( aName
, nMode
, bDirect
, sal_False
, pImp
->m_bRepairPackage
, pImp
->m_xProgressHandler
);
2866 pElement
->m_xStorage
= pStorage
->pImp
;
2871 return new UCBStorage( pElement
->m_xStorage
);
2875 else if ( !pElement
->m_xStream
.Is() )
2877 // storage is opened the first time
2878 sal_Bool bIsWritable
= (( pImp
->m_nMode
& STREAM_WRITE
) != 0 );
2879 if ( pImp
->m_bIsLinked
&& pImp
->m_bIsRoot
&& bIsWritable
)
2881 // make sure that the root storage object has been created before substorages will be created
2882 INetURLObject
aFolderObj( pImp
->m_aURL
);
2883 aFolderObj
.removeSegment();
2885 Content
aFolder( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
), Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
2886 pImp
->m_pContent
= new Content
;
2887 sal_Bool bRet
= ::utl::UCBContentHelper::MakeFolder( aFolder
, pImp
->m_aName
, *pImp
->m_pContent
);
2890 SetError( SVSTREAM_CANNOT_MAKE
);
2895 UCBStorage_Impl
* pStor
= pImp
->OpenStorage( pElement
, nMode
, bDirect
);
2898 if ( pElement
->m_bIsInserted
)
2899 pStor
->m_bListCreated
= sal_True
; // the storage is pretty new, nothing to read
2901 return new UCBStorage( pStor
);
2908 UCBStorage_Impl
* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl
* pElement
, StreamMode nMode
, bool bDirect
)
2910 UCBStorage_Impl
* pRet
= NULL
;
2911 String
aName( m_aURL
);
2913 aName
+= pElement
->m_aOriginalName
; // ???
2915 pElement
->m_bIsStorage
= pElement
->m_bIsFolder
= sal_True
;
2917 if ( m_bIsLinked
&& !::utl::UCBContentHelper::Exists( aName
) )
2920 sal_Bool bRet
= ::utl::UCBContentHelper::MakeFolder( *m_pContent
, pElement
->m_aOriginalName
, aNewFolder
);
2922 pRet
= new UCBStorage_Impl( aNewFolder
, aName
, nMode
, NULL
, bDirect
, sal_False
, m_bRepairPackage
, m_xProgressHandler
);
2926 pRet
= new UCBStorage_Impl( aName
, nMode
, NULL
, bDirect
, sal_False
, m_bRepairPackage
, m_xProgressHandler
);
2931 pRet
->m_bIsLinked
= m_bIsLinked
;
2932 pRet
->m_bIsRoot
= sal_False
;
2934 // if name has been changed before creating the stream: set name!
2935 pRet
->m_aName
= pElement
->m_aOriginalName
;
2936 pElement
->m_xStorage
= pRet
;
2945 sal_Bool
UCBStorage::IsStorage( const String
& rEleName
) const
2947 if( !rEleName
.Len() )
2950 const UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2951 return ( pElement
&& pElement
->m_bIsStorage
);
2954 sal_Bool
UCBStorage::IsStream( const String
& rEleName
) const
2956 if( !rEleName
.Len() )
2959 const UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2960 return ( pElement
&& !pElement
->m_bIsStorage
);
2963 sal_Bool
UCBStorage::IsContained( const String
& rEleName
) const
2965 if( !rEleName
.Len() )
2967 const UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2968 return ( pElement
!= NULL
);
2971 sal_Bool
UCBStorage::Remove( const String
& rEleName
)
2973 if( !rEleName
.Len() )
2976 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
2979 pElement
->m_bIsRemoved
= sal_True
;
2982 SetError( SVSTREAM_FILE_NOT_FOUND
);
2984 return ( pElement
!= NULL
);
2987 sal_Bool
UCBStorage::Rename( const String
& rEleName
, const String
& rNewName
)
2989 if( !rEleName
.Len()|| !rNewName
.Len() )
2992 UCBStorageElement_Impl
*pAlreadyExisting
= FindElement_Impl( rNewName
);
2993 if ( pAlreadyExisting
)
2995 SetError( SVSTREAM_ACCESS_DENIED
);
2996 return sal_False
; // can't change to a name that is already used
2999 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
3002 pElement
->m_aName
= rNewName
;
3005 SetError( SVSTREAM_FILE_NOT_FOUND
);
3007 return pElement
!= NULL
;
3010 sal_Bool
UCBStorage::MoveTo( const String
& rEleName
, BaseStorage
* pNewSt
, const String
& rNewName
)
3012 if( !rEleName
.Len() || !rNewName
.Len() )
3015 if ( pNewSt
== ((BaseStorage
*) this) && !FindElement_Impl( rNewName
) )
3017 return Rename( rEleName
, rNewName
);
3022 if ( PTR_CAST( UCBStorage, pNewSt ) )
3024 // because the element is moved, not copied, a special optimization is possible :
3025 // first copy the UCBStorageElement; flag old element as "Removed" and new as "Inserted",
3026 // clear original name/type of the new element
3027 // if moved element is open: copy content, but change absolute URL ( and those of all children of the element! ),
3028 // clear original name/type of new content, keep the old original stream/storage, but forget its working streams,
3029 // close original UCBContent and original stream, only the TempFile and its stream may remain unchanged, but now
3030 // belong to the new content
3031 // if original and editable stream are identical ( readonly element ), it has to be copied to the editable
3032 // stream of the destination object
3033 // Not implemented at the moment ( risky?! ), perhaps later
3036 // MoveTo is done by first copying to the new destination and then removing the old element
3037 sal_Bool bRet
= CopyTo( rEleName
, pNewSt
, rNewName
);
3039 bRet
= Remove( rEleName
);
3044 sal_Bool
UCBStorage::ValidateFAT()
3050 sal_Bool
UCBStorage::Validate( sal_Bool bWrite
) const
3053 return ( !bWrite
|| ( pImp
->m_nMode
& STREAM_WRITE
) );
3056 sal_Bool
UCBStorage::ValidateMode( StreamMode m
) const
3059 if( m
== ( STREAM_READ
| STREAM_TRUNC
) ) // from stg.cxx
3061 sal_uInt16 nCurMode
= 0xFFFF;
3062 if( ( m
& 3 ) == STREAM_READ
)
3064 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
3065 if( ( ( m
& STREAM_SHARE_DENYWRITE
)
3066 && ( nCurMode
& STREAM_SHARE_DENYWRITE
) )
3067 || ( ( m
& STREAM_SHARE_DENYALL
)
3068 && ( nCurMode
& STREAM_SHARE_DENYALL
) ) )
3073 // only SHARE_DENYALL allowed
3074 // storages open in r/o mode are OK, since only
3075 // the commit may fail
3076 if( ( m
& STREAM_SHARE_DENYALL
)
3077 && ( nCurMode
& STREAM_SHARE_DENYALL
) )
3084 const SvStream
* UCBStorage::GetSvStream() const
3086 // this would cause a complete download of the file
3087 // as it looks, this method is NOT used inside of SOT, only exported by class SotStorage - but for what ???
3088 return pImp
->m_pSource
;
3091 sal_Bool
UCBStorage::Equals( const BaseStorage
& rStorage
) const
3094 return ((BaseStorage
*)this) == &rStorage
;
3097 sal_Bool
UCBStorage::IsStorageFile( SvStream
* pFile
)
3102 sal_uLong nPos
= pFile
->Tell();
3103 pFile
->Seek( STREAM_SEEK_TO_END
);
3104 if ( pFile
->Tell() < 4 )
3108 sal_uInt32
nBytes(0);
3111 // search for the magic bytes
3112 sal_Bool bRet
= ( nBytes
== 0x04034b50 );
3115 // disk spanned file have an additional header in front of the usual one
3116 bRet
= ( nBytes
== 0x08074b50 );
3121 bRet
= ( nBytes
== 0x04034b50 );
3125 pFile
->Seek( nPos
);
3129 sal_Bool
UCBStorage::IsDiskSpannedFile( SvStream
* pFile
)
3134 sal_uLong nPos
= pFile
->Tell();
3135 pFile
->Seek( STREAM_SEEK_TO_END
);
3136 if ( !pFile
->Tell() )
3143 // disk spanned file have an additional header in front of the usual one
3144 sal_Bool bRet
= ( nBytes
== 0x08074b50 );
3148 bRet
= ( nBytes
== 0x04034b50 );
3151 pFile
->Seek( nPos
);
3155 String
UCBStorage::GetLinkedFile( SvStream
&rStream
)
3158 sal_uLong nPos
= rStream
.Tell();
3159 rStream
.Seek( STREAM_SEEK_TO_END
);
3160 if ( !rStream
.Tell() )
3166 if( nBytes
== 0x04034b50 )
3168 OString aTmp
= read_lenPrefixed_uInt8s_ToOString
<sal_uInt16
>(rStream
);
3169 if (aTmp
.match("ContentURL="))
3171 aString
= OStringToOUString(aTmp
.copy(11), RTL_TEXTENCODING_UTF8
);
3175 rStream
.Seek( nPos
);
3179 String
UCBStorage::CreateLinkFile( const String
& rName
)
3181 // create a stream to write the link file - use a temp file, because it may be no file content
3182 INetURLObject
aFolderObj( rName
);
3183 String aName
= aFolderObj
.GetName();
3184 aFolderObj
.removeSegment();
3185 String
aFolderURL( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
) );
3186 ::utl::TempFile
* pTempFile
= new ::utl::TempFile( &aFolderURL
);
3188 // get the stream from the temp file
3189 SvStream
* pStream
= pTempFile
->GetStream( STREAM_STD_READWRITE
| STREAM_TRUNC
);
3192 *pStream
<< ( sal_uInt32
) 0x04034b50;
3194 // assemble a new folder name in the destination folder
3195 INetURLObject
aObj( rName
);
3196 String aTmpName
= aObj
.GetName();
3197 String aTitle
= OUString( "content." );
3200 // create a folder and store its URL
3201 Content
aFolder( aFolderURL
, Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
3203 sal_Bool bRet
= ::utl::UCBContentHelper::MakeFolder( aFolder
, aTitle
, aNewFolder
);
3206 aFolderObj
.insertName( aTitle
);
3207 if ( ::utl::UCBContentHelper::Exists( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
) ) )
3209 // Hack, because already existing files give the same CommandAbortedException as any other error !
3210 // append a number until the name can be used for a new folder
3212 for ( sal_Int32 i
=0; !bRet
; i
++ )
3214 String
aTmp( aTitle
);
3215 aTmp
+= OUString::number( i
);
3216 bRet
= ::utl::UCBContentHelper::MakeFolder( aFolder
, aTmp
, aNewFolder
);
3221 aFolderObj
.SetName( aTmp
);
3222 if ( !::utl::UCBContentHelper::Exists( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
) ) )
3223 // Hack, because already existing files give the same CommandAbortedException as any other error !
3233 aObj
.SetName( aTitle
);
3234 String aURL
= aObj
.GetMainURL( INetURLObject::NO_DECODE
);
3236 // store it as key/value pair
3237 String aLink
= OUString("ContentURL=");
3239 write_lenPrefixed_uInt8s_FromOUString
<sal_uInt16
>(*pStream
, aLink
, RTL_TEXTENCODING_UTF8
);
3242 // move the stream to its desired location
3243 Content
aSource( pTempFile
->GetURL(), Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
3244 DELETEZ( pTempFile
);
3245 aFolder
.transferContent( aSource
, InsertOperation_MOVE
, aName
, NameClash::OVERWRITE
);
3249 pTempFile
->EnableKillingFile( sal_True
);
3254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */