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