fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / sot / source / sdstor / ucbstorage.cxx
blobcdaf433187db2cf043a4161ccfcde86c9fa50dd1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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>
65 #include <vector>
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
76 #include <stdio.h>
77 static int nOpenFiles=0;
78 static int nOpenStreams=0;
79 #endif
81 typedef ::cppu::WeakImplHelper2 < XInputStream, XSeekable > FileInputStreamWrapper_Base;
82 class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
84 protected:
85 ::osl::Mutex m_aMutex;
86 String m_aURL;
87 SvStream* m_pSvStream;
89 public:
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 );
102 protected:
103 void checkConnected();
104 void checkError();
107 //------------------------------------------------------------------
108 FileStreamWrapper_Impl::FileStreamWrapper_Impl( const String& rName )
109 : m_aURL( rName )
110 , m_pSvStream(0)
112 // if no URL is provided the stream is empty
115 //------------------------------------------------------------------
116 FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
118 if ( m_pSvStream )
120 delete m_pSvStream;
121 #if OSL_DEBUG_LEVEL > 1
122 --nOpenFiles;
123 #endif
126 if ( m_aURL.Len() )
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 )
134 if ( !m_aURL.Len() )
136 aData.realloc( 0 );
137 return 0;
140 checkConnected();
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);
150 checkError();
152 // Wenn gelesene Zeichen < MaxLength, Sequence anpassen
153 if (nRead < (sal_uInt32)nBytesToRead)
154 aData.realloc( nRead );
156 return nRead;
159 //------------------------------------------------------------------------------
160 sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
162 if ( !m_aURL.Len() )
164 aData.realloc( 0 );
165 return 0;
168 checkError();
170 if (nMaxBytesToRead < 0)
171 throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
173 if (m_pSvStream->IsEof())
175 aData.realloc(0);
176 return 0;
178 else
179 return readBytes(aData, nMaxBytesToRead);
182 //------------------------------------------------------------------------------
183 void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
185 if ( !m_aURL.Len() )
186 return;
188 ::osl::MutexGuard aGuard( m_aMutex );
189 checkError();
191 m_pSvStream->SeekRel(nBytesToSkip);
192 checkError();
195 //------------------------------------------------------------------------------
196 sal_Int32 SAL_CALL FileStreamWrapper_Impl::available() throw( NotConnectedException, RuntimeException )
198 if ( !m_aURL.Len() )
199 return 0;
201 ::osl::MutexGuard aGuard( m_aMutex );
202 checkConnected();
204 sal_uInt32 nPos = m_pSvStream->Tell();
205 checkError();
207 m_pSvStream->Seek(STREAM_SEEK_TO_END);
208 checkError();
210 sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos;
211 m_pSvStream->Seek(nPos);
212 checkError();
214 return nAvailable;
217 //------------------------------------------------------------------------------
218 void SAL_CALL FileStreamWrapper_Impl::closeInput() throw( NotConnectedException, RuntimeException )
220 if ( !m_aURL.Len() )
221 return;
223 ::osl::MutexGuard aGuard( m_aMutex );
224 checkConnected();
225 DELETEZ( m_pSvStream );
226 #if OSL_DEBUG_LEVEL > 1
227 --nOpenFiles;
228 #endif
229 ::utl::UCBContentHelper::Kill( m_aURL );
230 m_aURL.Erase();
233 //------------------------------------------------------------------------------
234 void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException)
236 if ( !m_aURL.Len() )
237 return;
239 ::osl::MutexGuard aGuard( m_aMutex );
240 checkConnected();
242 m_pSvStream->Seek((sal_uInt32)_nLocation);
243 checkError();
246 //------------------------------------------------------------------------------
247 sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition( ) throw (IOException, RuntimeException)
249 if ( !m_aURL.Len() )
250 return 0;
252 ::osl::MutexGuard aGuard( m_aMutex );
253 checkConnected();
255 sal_uInt32 nPos = m_pSvStream->Tell();
256 checkError();
257 return (sal_Int64)nPos;
260 //------------------------------------------------------------------------------
261 sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength( ) throw (IOException, RuntimeException)
263 if ( !m_aURL.Len() )
264 return 0;
266 ::osl::MutexGuard aGuard( m_aMutex );
267 checkConnected();
269 sal_uInt32 nCurrentPos = m_pSvStream->Tell();
270 checkError();
272 m_pSvStream->Seek(STREAM_SEEK_TO_END);
273 sal_uInt32 nEndPos = m_pSvStream->Tell();
274 m_pSvStream->Seek(nCurrentPos);
276 checkError();
278 return (sal_Int64)nEndPos;
281 //------------------------------------------------------------------------------
282 void FileStreamWrapper_Impl::checkConnected()
284 if ( !m_aURL.Len() )
285 throw NotConnectedException(OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
286 if ( !m_pSvStream )
288 m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, STREAM_STD_READ );
289 #if OSL_DEBUG_LEVEL > 1
290 ++nOpenFiles;
291 #endif
295 //------------------------------------------------------------------------------
296 void FileStreamWrapper_Impl::checkError()
298 checkConnected();
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
337 return 0;
338 else
340 OSL_FAIL( "Unknown UCB storage format!" );
341 return 0;
346 SvGlobalName GetClassId_Impl( sal_Int32 nFormat )
348 switch ( 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 );
388 default :
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 {
397 nonset,
398 svstream,
399 xinputstream
402 class UCBStorageStream_Impl : public SvRefBase, public SvStream
404 ~UCBStorageStream_Impl();
405 public:
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;
421 OString m_aKey;
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
428 long m_nError;
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 >() );
440 void Free();
441 sal_Bool Init();
442 sal_Bool Clear();
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
446 sal_uLong GetSize();
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
467 ~UCBStorage_Impl();
468 public:
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
479 long m_nError;
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;
490 sal_uLong m_nFormat;
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 );
502 void Init();
503 sal_Int16 Commit();
504 sal_Bool Revert();
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();
511 void ReadContent();
512 void CreateContent();
513 ::ucbhelper::Content* GetContent()
514 { if ( !m_pContent ) CreateContent(); return m_pContent; }
515 UCBStorageElementList_Impl& GetChildrenList()
517 long nError = m_nError;
518 ReadContent();
519 if ( m_nMode & STREAM_WRITE )
521 m_nError = nError;
522 if ( m_pAntiImpl )
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
542 sal_uLong m_nSize;
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 )
552 : m_aName( rName )
553 , m_aOriginalName( rName )
554 , m_nSize( nSize )
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();
567 sal_Bool IsLoaded()
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();
577 else
578 return NULL;
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;
587 else
589 OSL_FAIL("Element not loaded!");
590 return String();
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;
602 else {
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;
613 else
614 return String();
617 sal_Bool UCBStorageElement_Impl::IsModified()
619 sal_Bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
620 if ( bModified )
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;
628 return bModified;
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 )
633 , m_aURL( rName )
634 , m_pContent( NULL )
635 , m_pStream( NULL )
636 , m_nRepresentMode( nonset )
637 , m_nError( 0 )
638 , m_nMode( nMode )
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 );
655 if ( bRepair )
657 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
658 xProgress );
659 aTemp += OUString("?repairpackage");
662 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
664 if ( pKey )
666 m_aKey = *pKey;
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;
676 aAny <<= aSequ;
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()
695 if( m_rSource.is() )
696 m_rSource = Reference< XInputStream >();
698 if( m_pStream )
699 delete m_pStream;
701 if ( m_aTempURL.Len() )
702 ::utl::UCBContentHelper::Kill( m_aTempURL );
704 if( m_pContent )
705 delete m_pContent;
709 sal_Bool UCBStorageStream_Impl::Init()
711 if( m_nRepresentMode == xinputstream )
713 OSL_FAIL( "XInputStream misuse!" );
714 SetError( ERRCODE_IO_ACCESSDENIED );
715 return sal_False;
718 if( !m_pStream )
720 // no temporary stream was created
721 // create one
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
730 ++nOpenFiles;
731 #endif
733 if( !m_pStream )
735 OSL_FAIL( "Suspicious temporary stream creation!" );
736 SetError( SVSTREAM_CANNOT_MAKE );
737 return sal_False;
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
757 if( m_rSource.is() )
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 );
780 else
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!" );
790 return sal_True;
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;
800 if( m_bSourceRead )
802 Sequence<sal_Int8> aData(32000);
806 sal_uLong aReaded;
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() );
816 (void)e;
820 m_bSourceRead = sal_False;
822 return aResult;
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;
833 if( m_bSourceRead )
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() );
855 (void)e;
859 return aResult;
862 sal_uLong UCBStorageStream_Impl::CopySourceToTemporary()
864 // current position of the temporary stream is not changed
865 sal_uLong aResult = 0;
867 if( m_bSourceRead )
869 sal_uLong aPos = m_pStream->Tell();
870 m_pStream->Seek( STREAM_SEEK_TO_END );
871 aResult = ReadSourceWriteTemporary();
872 m_pStream->Seek( aPos );
875 return aResult;
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;
885 if( !Init() )
886 return 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() );
909 (void)e;
912 if( aResult < nSize )
913 m_bSourceRead = sal_False;
916 return aResult;
919 sal_uLong UCBStorageStream_Impl::PutData( const void* pData, sal_uLong nSize )
921 if ( !(m_nMode & STREAM_WRITE) )
923 SetError( ERRCODE_IO_ACCESSDENIED );
924 return 0; // ?mav?
927 if( !nSize || !Init() )
928 return 0;
930 sal_uLong aResult = m_pStream->Write( pData, nSize );
932 m_bModified = aResult > 0;
934 return aResult;
938 sal_uLong UCBStorageStream_Impl::SeekPos( sal_uLong nPos )
940 if( !Init() )
941 return 0;
943 sal_uLong aResult;
945 if( nPos == STREAM_SEEK_TO_END )
947 m_pStream->Seek( STREAM_SEEK_TO_END );
948 ReadSourceWriteTemporary();
949 aResult = m_pStream->Tell();
951 else
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 );
963 else
965 // the temp stream pointer points to the end now
966 aResult = m_pStream->Tell();
968 if( aResult < nPos )
970 if( m_bSourceRead )
972 aResult += ReadSourceWriteTemporary( nPos - aResult );
973 if( aResult < nPos )
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" );
992 return aResult;
995 void UCBStorageStream_Impl::SetSize( sal_uLong nSize )
997 if ( !(m_nMode & STREAM_WRITE) )
999 SetError( ERRCODE_IO_ACCESSDENIED );
1000 return;
1003 if( !Init() )
1004 return;
1006 m_bModified = sal_True;
1008 if( m_bSourceRead )
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()
1023 if( m_pStream )
1025 CopySourceToTemporary();
1026 m_pStream->Flush();
1029 m_bCommited = sal_True;
1032 void UCBStorageStream_Impl::SetError( sal_uInt32 nErr )
1034 if ( !m_nError )
1036 m_nError = nErr;
1037 SvStream::SetError( nErr );
1038 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
1042 void UCBStorageStream_Impl::ResetError()
1044 m_nError = 0;
1045 SvStream::ResetError();
1046 if ( m_pAntiImpl )
1047 m_pAntiImpl->ResetError();
1050 sal_uLong UCBStorageStream_Impl::GetSize()
1052 if( !Init() )
1053 return 0;
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 );
1061 return nRet;
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 )
1088 if ( m_bModified )
1092 CopySourceToTemporary();
1094 // release all stream handles
1095 Free();
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 );
1105 Any aAny;
1106 InsertCommandArgument aArg;
1107 aArg.Data = xStream;
1108 aArg.ReplaceExisting = sal_True;
1109 aAny <<= aArg;
1110 m_pContent->executeCommand( OUString("insert"), aAny );
1112 // wrapper now controls lifetime of temporary file
1113 m_aTempURL.Erase();
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" !
1151 if ( m_bCommited )
1153 OSL_FAIL("Revert while commit is in progress!" );
1154 return sal_False; // ???
1157 Free();
1158 if ( m_aTempURL.Len() )
1160 ::utl::UCBContentHelper::Kill( m_aTempURL );
1161 m_aTempURL.Erase();
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;
1173 else
1175 m_nMode &= ~STREAM_TRUNC;
1176 m_bSourceRead = sal_True;
1179 else
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!" );
1204 if( bRet )
1206 Free();
1209 return bRet;
1212 void UCBStorageStream_Impl::Free()
1214 #if OSL_DEBUG_LEVEL > 1
1215 if ( m_pStream )
1217 if ( m_aTempURL.Len() )
1218 --nOpenFiles;
1219 else
1220 --nOpenStreams;
1222 #endif
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 );
1232 if ( isWritable )
1234 // once stream was writable, never reset to readonly
1235 nMode |= STREAM_WRITE;
1238 m_nMode = nMode;
1239 Free();
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 );
1248 m_aTempURL.Erase();
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 )
1263 : pImp( 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 )
1274 pImp->Flush();
1275 pImp->m_pAntiImpl = NULL;
1276 pImp->Free();
1277 pImp->ReleaseRef();
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()
1299 if( !pImp->Init() )
1300 return 0;
1301 return pImp->m_pStream->Tell();
1304 void UCBStorageStream::Flush()
1306 // streams are never really transacted, so flush also means commit !
1307 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
1323 // ???
1324 if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
1325 return sal_True;
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 ) ) )
1334 return sal_True;
1336 else
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 ) )
1343 return sal_True;
1346 return sal_True;
1349 const SvStream* UCBStorageStream::GetSvStream() const
1351 if( !pImp->Init() )
1352 return NULL;
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
1365 // ???
1366 return ((BaseStorageStream*) this ) == &rStream;
1369 sal_Bool UCBStorageStream::Commit()
1371 // mark this stream for sending it on root commit
1372 pImp->FlushData();
1373 return sal_True;
1376 sal_Bool UCBStorageStream::Revert()
1378 return pImp->Revert();
1381 sal_Bool UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
1383 if( !pImp->Init() )
1384 return sal_False;
1386 UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pDestStm );
1387 if ( pStg )
1388 pStg->pImp->m_aContentType = pImp->m_aContentType;
1390 pDestStm->SetSize( 0 );
1391 Seek( STREAM_SEEK_TO_END );
1392 sal_Int32 n = Tell();
1393 if( n < 0 )
1394 return sal_False;
1396 if( pDestStm->SetSize( n ) && n )
1398 sal_uInt8* p = new sal_uInt8[ 4096 ];
1399 Seek( 0L );
1400 pDestStm->Seek( 0L );
1401 while( n )
1403 sal_uInt32 nn = n;
1404 if( nn > 4096 )
1405 nn = 4096;
1406 if( Read( p, nn ) != nn )
1407 break;
1408 if( pDestStm->Write( p, nn ) != nn )
1409 break;
1410 n -= nn;
1413 delete[] p;
1416 return sal_True;
1419 sal_Bool UCBStorageStream::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
1421 if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
1422 return sal_False;
1424 if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
1426 OUString aTmp;
1427 rValue >>= aTmp;
1428 pImp->m_aContentType = aTmp;
1433 if ( pImp->m_pContent )
1435 pImp->m_pContent->setPropertyValue( rName, rValue );
1436 return sal_True;
1439 catch (const Exception&)
1443 return sal_False;
1446 sal_uLong UCBStorageStream::GetSize() const
1448 return pImp->GetSize();
1451 UCBStorage::UCBStorage( SvStream& rStrm, sal_Bool bDirect )
1453 String aURL = GetLinkedFile( rStrm );
1454 if ( aURL.Len() )
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 );
1463 else
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 );
1470 pImp->AddRef();
1471 pImp->Init();
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 );
1480 pImp->AddRef();
1481 pImp->Init();
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 );
1490 pImp->AddRef();
1491 pImp->Init();
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 >() );
1500 pImp->AddRef();
1501 pImp->Init();
1502 StorageBase::m_nMode = pImp->m_nMode;
1505 UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
1506 : pImp( 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
1518 Commit();
1520 pImp->m_pAntiImpl = NULL;
1521 pImp->ReleaseRef();
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 )
1528 , m_pSource( NULL )
1529 //, m_pStream( NULL )
1530 , m_nError( 0 )
1531 , m_nMode( nMode )
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 )
1539 , m_nFormat( 0 )
1540 , m_aClassId( SvGlobalName() )
1541 , m_bRepairPackage( bIsRepair )
1542 , m_xProgressHandler( xProgressHandler )
1544 String aName( rName );
1545 if( !aName.Len() )
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();
1554 m_aURL = rName;
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 )
1561 , m_pSource( NULL )
1562 //, m_pStream( NULL )
1563 , m_nError( 0 )
1564 , m_nMode( nMode )
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 )
1572 , m_nFormat( 0 )
1573 , m_aClassId( SvGlobalName() )
1574 , m_bRepairPackage( bIsRepair )
1575 , m_xProgressHandler( xProgressHandler )
1577 String aName( rName );
1578 if( !aName.Len() )
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();
1587 if ( m_bIsRoot )
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 ));
1592 m_aURL = aTemp;
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 */ );
1598 delete pStream;
1601 else
1603 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1604 m_aURL = rName;
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 )
1615 , m_nError( 0 )
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 )
1623 , m_nFormat( 0 )
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 ));
1637 m_aURL = aTemp;
1639 // copy data into the temporary file
1640 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READWRITE, sal_True /* bFileExists */ );
1641 if ( pStream )
1643 rStream.Seek(0);
1644 rStream >> *pStream;
1645 pStream->Flush();
1646 DELETEZ( pStream );
1649 // close stream and let content access the file
1650 m_pSource->Seek(0);
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 ) )
1668 CreateContent();
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 )
1678 if ( m_bIsLinked )
1680 if( m_bIsRoot )
1682 ReadContent();
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
1692 if ( pStream )
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 );
1705 // cleanup
1706 xReader = NULL;
1707 xInputStream = NULL;
1708 SetProps( aProps, String() );
1711 delete pStream;
1715 else
1716 ReadContent();
1718 else
1720 // get the manifest information from the package
1721 try {
1722 Any aAny = m_pContent->getPropertyValue( OUString("MediaType") );
1723 OUString aTmp;
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() )
1750 ReadContent();
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 )
1787 return;
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;
1802 GetContent();
1803 if ( !m_pContent )
1804 return;
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;
1816 if ( m_bIsLinked )
1818 // unpacked storages have to deal with the meta-inf folder by themselves
1819 if ( aTitle == "META-INF" )
1820 continue;
1822 else
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() );
1833 if ( bIsFolder )
1835 if ( m_bIsLinked )
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 );
1844 aName += '/';
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;
1867 else
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 )
1910 if ( !m_nError )
1912 m_nError = 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();
1928 return nCount;
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];
1937 OUString aType;
1939 for ( sal_Int32 nProps=0; nProps<rMyProps.getLength(); nProps++ )
1941 const PropertyValue& rAny = rMyProps[nProps];
1942 if ( rAny.Name == "FullPath" )
1944 OUString aTmp;
1945 if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
1946 bFound = sal_True;
1947 if ( !aType.isEmpty() )
1948 break;
1950 else if ( rAny.Name == "MediaType" )
1952 if ( ( rAny.Value >>= aType ) && !aType.isEmpty() && bFound )
1953 break;
1957 if ( bFound )
1958 return aType;
1961 return OUString();
1964 void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
1966 String aPath( rPath );
1967 if ( !m_bIsRoot )
1968 aPath += m_aName;
1969 aPath += '/';
1971 m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
1973 if ( m_bIsRoot )
1974 // the "FullPath" of a child always starts without '/'
1975 aPath.Erase();
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 );
1983 else
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 );
2015 if ( !m_bIsRoot )
2016 aPath += m_aName;
2017 aPath += '/';
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;
2024 if ( m_bIsRoot )
2025 // the "FullPath" of a child always starts without '/'
2026 aPath.Erase();
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 );
2036 else
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();
2057 delete m_pContent;
2058 delete m_pTempFile;
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();
2071 if ( nCount == 0 )
2072 return sal_False;
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 )
2083 continue;
2085 if ( rProps[ 0 ].Name != "Title" )
2086 continue;
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 ) );
2095 Content aNewFolder;
2096 if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
2097 continue;
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 );
2102 bRet = sal_True;
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 );
2122 return bRet;
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 );
2147 aName += '/';
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;
2163 else
2164 // couldn't release stream because there are external references to it
2165 nRet = COMMIT_RESULT_FAILURE;
2168 else
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");
2192 Any aValue;
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;
2204 Any aAny;
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;
2213 Any aAny;
2214 aAny <<= (OUString) pElement->GetContentType();
2215 pContent->setPropertyValue( OUString("MediaType"), aAny );
2218 if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO )
2219 nRet = nLocalRet;
2222 if ( bDeleteContent )
2223 // content was created inside the loop
2224 delete pContent;
2226 if ( nRet == COMMIT_RESULT_FAILURE )
2227 break;
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
2264 Any aType;
2265 aType <<= (OUString) m_aContentType;
2266 m_pContent->setPropertyValue( OUString("MediaType"), aType );
2268 if ( m_bIsLinked )
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 );
2274 if ( bRet )
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() );
2297 xWriter = NULL;
2298 xOutputStream = NULL;
2299 DELETEZ( pTempFile );
2300 aNewSubFolder.transferContent( aSource, InsertOperation_MOVE, OUString("manifest.xml"), NameClash::OVERWRITE );
2303 else
2305 #if OSL_DEBUG_LEVEL > 1
2306 fprintf ( stderr, "Files: %i\n", nOpenFiles );
2307 fprintf ( stderr, "Streams: %i\n", nOpenStreams );
2308 #endif
2309 // force writing
2310 Any aAny;
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;
2318 DELETEZ( pStream );
2319 m_pSource->Seek(0);
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 );
2349 else
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 );
2367 return nRet;
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 );
2379 delete *it;
2380 m_aChildrenList.erase( it );
2382 else
2384 pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2385 pInnerElement->m_bIsInserted = sal_False;
2386 ++i;
2391 m_bCommited = sal_False;
2394 return nRet;
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 );
2407 delete *it;
2408 m_aChildrenList.erase( it );
2410 else
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;
2425 ++i;
2428 return sal_True;
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() )
2463 return;
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
2469 // the content type
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*/ )
2487 // ???
2490 sal_Bool UCBStorage::ShouldConvert()
2492 // ???
2493 return sal_False;
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;
2546 if ( !pStream )
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() );
2556 else
2557 pOtherStream->Commit();
2559 if ( bDeleteStream )
2560 delete pStream;
2561 delete pOtherStream;
2563 else
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;
2573 if ( !pStorage )
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 );
2593 else
2594 pOtherStorage->SetClassId( pStorage->GetClassId() );
2595 pStorage->CopyTo( pOtherStorage );
2596 SetError( pStorage->GetError() );
2597 if( pOtherStorage->GetError() )
2598 pDest->SetError( pOtherStorage->GetError() );
2599 else
2600 pOtherStorage->Commit();
2602 if ( bDeleteStorage )
2603 delete pStorage;
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 )
2617 return pElement;
2619 return NULL;
2622 sal_Bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2624 DBG_ASSERT( pDestStg != ((BaseStorage*)this), "Self-Copying is not possible!" );
2625 if ( pDestStg == ((BaseStorage*)this) )
2626 return sal_False;
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 );
2636 else
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 );
2648 if( !bRet )
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() )
2656 return sal_False;
2658 if ( pDest == ((BaseStorage*) this) )
2660 // can't double an element
2661 return sal_False;
2663 else
2665 // for copying no optimization is useful, because in every case the stream data must be copied
2666 UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2667 if ( pElement )
2668 return CopyStorageElement_Impl( *pElement, pDest, rNew );
2669 else
2671 SetError( SVSTREAM_FILE_NOT_FOUND );
2672 return sal_False;
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 );
2684 else
2685 return sal_True;
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() )
2696 return NULL;
2698 // try to find the storage element
2699 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2700 if ( !pElement )
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 );
2707 aName += '/';
2708 aName += rEleName;
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;
2712 return pStream;
2714 else
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 ); // ???
2733 return NULL;
2735 else
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!
2739 OString aKey;
2740 if ( pKey )
2741 aKey = *pKey;
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 );
2759 return NULL;
2762 UCBStorageStream_Impl* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect, const OString* pKey )
2764 String aName( m_aURL );
2765 aName += '/';
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() )
2774 return NULL;
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() )
2782 return NULL;
2784 return OpenStorage_Impl( rEleName, nMode, bDirect, sal_False );
2787 BaseStorage* UCBStorage::OpenStorage( const String& rEleName, StreamMode nMode, bool bDirect )
2789 if( !rEleName.Len() )
2790 return NULL;
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 );
2799 if ( !pElement )
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 );
2806 aName += '/';
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() );
2812 return pStorage;
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 );
2833 if ( !pStream )
2835 SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2836 return NULL;
2839 pElement->m_xStream = pStream->pImp;
2840 delete pStream;
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 ); // ???
2857 else
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 );
2863 aName += '/';
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;
2867 return pStorage;
2869 else
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 );
2888 if ( !bRet )
2890 SetError( SVSTREAM_CANNOT_MAKE );
2891 return NULL;
2895 UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
2896 if ( pStor )
2898 if ( pElement->m_bIsInserted )
2899 pStor->m_bListCreated = sal_True; // the storage is pretty new, nothing to read
2901 return new UCBStorage( pStor );
2905 return NULL;
2908 UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2910 UCBStorage_Impl* pRet = NULL;
2911 String aName( m_aURL );
2912 aName += '/';
2913 aName += pElement->m_aOriginalName; // ???
2915 pElement->m_bIsStorage = pElement->m_bIsFolder = sal_True;
2917 if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
2919 Content aNewFolder;
2920 sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
2921 if ( bRet )
2922 pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler );
2924 else
2926 pRet = new UCBStorage_Impl( aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler );
2929 if ( pRet )
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;
2939 if ( pRet )
2940 pRet->Init();
2942 return pRet;
2945 sal_Bool UCBStorage::IsStorage( const String& rEleName ) const
2947 if( !rEleName.Len() )
2948 return sal_False;
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() )
2957 return sal_False;
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() )
2966 return sal_False;
2967 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2968 return ( pElement != NULL );
2971 sal_Bool UCBStorage::Remove( const String& rEleName )
2973 if( !rEleName.Len() )
2974 return sal_False;
2976 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2977 if ( pElement )
2979 pElement->m_bIsRemoved = sal_True;
2981 else
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() )
2990 return sal_False;
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 );
3000 if ( pElement )
3002 pElement->m_aName = rNewName;
3004 else
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() )
3013 return sal_False;
3015 if ( pNewSt == ((BaseStorage*) this) && !FindElement_Impl( rNewName ) )
3017 return Rename( rEleName, rNewName );
3019 else
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 );
3038 if ( bRet )
3039 bRet = Remove( rEleName );
3040 return bRet;
3044 sal_Bool UCBStorage::ValidateFAT()
3046 // ???
3047 return sal_True;
3050 sal_Bool UCBStorage::Validate( sal_Bool bWrite ) const
3052 // ???
3053 return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
3056 sal_Bool UCBStorage::ValidateMode( StreamMode m ) const
3058 // ???
3059 if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
3060 return sal_True;
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 ) ) )
3069 return sal_True;
3071 else
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 ) )
3078 return sal_True;
3081 return sal_True;
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
3093 // ???
3094 return ((BaseStorage*)this) == &rStorage;
3097 sal_Bool UCBStorage::IsStorageFile( SvStream* pFile )
3099 if ( !pFile )
3100 return sal_False;
3102 sal_uLong nPos = pFile->Tell();
3103 pFile->Seek( STREAM_SEEK_TO_END );
3104 if ( pFile->Tell() < 4 )
3105 return sal_False;
3107 pFile->Seek(0);
3108 sal_uInt32 nBytes(0);
3109 *pFile >> nBytes;
3111 // search for the magic bytes
3112 sal_Bool bRet = ( nBytes == 0x04034b50 );
3113 if ( !bRet )
3115 // disk spanned file have an additional header in front of the usual one
3116 bRet = ( nBytes == 0x08074b50 );
3117 if ( bRet )
3119 nBytes = 0;
3120 *pFile >> nBytes;
3121 bRet = ( nBytes == 0x04034b50 );
3125 pFile->Seek( nPos );
3126 return bRet;
3129 sal_Bool UCBStorage::IsDiskSpannedFile( SvStream* pFile )
3131 if ( !pFile )
3132 return sal_False;
3134 sal_uLong nPos = pFile->Tell();
3135 pFile->Seek( STREAM_SEEK_TO_END );
3136 if ( !pFile->Tell() )
3137 return sal_False;
3139 pFile->Seek(0);
3140 sal_uInt32 nBytes;
3141 *pFile >> nBytes;
3143 // disk spanned file have an additional header in front of the usual one
3144 sal_Bool bRet = ( nBytes == 0x08074b50 );
3145 if ( bRet )
3147 *pFile >> nBytes;
3148 bRet = ( nBytes == 0x04034b50 );
3151 pFile->Seek( nPos );
3152 return bRet;
3155 String UCBStorage::GetLinkedFile( SvStream &rStream )
3157 String aString;
3158 sal_uLong nPos = rStream.Tell();
3159 rStream.Seek( STREAM_SEEK_TO_END );
3160 if ( !rStream.Tell() )
3161 return aString;
3163 rStream.Seek(0);
3164 sal_uInt32 nBytes;
3165 rStream >> nBytes;
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 );
3176 return aString;
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 );
3191 // write header
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." );
3198 aTitle += aTmpName;
3200 // create a folder and store its URL
3201 Content aFolder( aFolderURL, Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
3202 Content aNewFolder;
3203 sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTitle, aNewFolder );
3204 if ( !bRet )
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
3211 aTitle += '.';
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 );
3217 if ( bRet )
3218 aTitle = aTmp;
3219 else
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 !
3224 break;
3230 if ( bRet )
3232 // get the URL
3233 aObj.SetName( aTitle );
3234 String aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
3236 // store it as key/value pair
3237 String aLink = OUString("ContentURL=");
3238 aLink += aURL;
3239 write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(*pStream, aLink, RTL_TEXTENCODING_UTF8);
3240 pStream->Flush();
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 );
3246 return aURL;
3249 pTempFile->EnableKillingFile( sal_True );
3250 delete pTempFile;
3251 return String();
3254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */