lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / sot / source / sdstor / ucbstorage.cxx
blob98633c9fec728090a1b4d557a530e1c32ddca072
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>
45 #include <com/sun/star/ucb/ContentCreationException.hpp>
47 #include <memory>
48 #include <rtl/digest.h>
49 #include <osl/diagnose.h>
50 #include <osl/file.hxx>
51 #include <sal/log.hxx>
52 #include <tools/ref.hxx>
53 #include <tools/debug.hxx>
54 #include <unotools/streamhelper.hxx>
55 #include <unotools/streamwrap.hxx>
56 #include <unotools/ucbhelper.hxx>
57 #include <unotools/localfilehelper.hxx>
58 #include <tools/urlobj.hxx>
59 #include <comphelper/processfactory.hxx>
60 #include <cppuhelper/implbase.hxx>
61 #include <ucbhelper/commandenvironment.hxx>
63 #include <sot/stg.hxx>
64 #include <sot/storinfo.hxx>
65 #include <sot/storage.hxx>
66 #include <sot/exchange.hxx>
67 #include <sot/formats.hxx>
68 #include <comphelper/classids.hxx>
70 #include <vector>
72 using namespace ::com::sun::star::lang;
73 using namespace ::com::sun::star::beans;
74 using namespace ::com::sun::star::uno;
75 using namespace ::com::sun::star::ucb;
76 using namespace ::com::sun::star::io;
77 using namespace ::com::sun::star::sdbc;
78 using namespace ::ucbhelper;
80 #if OSL_DEBUG_LEVEL > 0
81 static int nOpenFiles=0;
82 static int nOpenStreams=0;
83 #endif
85 typedef ::cppu::WeakImplHelper < XInputStream, XSeekable > FileInputStreamWrapper_Base;
86 class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
88 protected:
89 ::osl::Mutex m_aMutex;
90 OUString m_aURL;
91 std::unique_ptr<SvStream> m_pSvStream;
93 public:
94 explicit FileStreamWrapper_Impl(const OUString& rName);
95 virtual ~FileStreamWrapper_Impl() override;
97 virtual void SAL_CALL seek( sal_Int64 _nLocation ) override;
98 virtual sal_Int64 SAL_CALL getPosition( ) override;
99 virtual sal_Int64 SAL_CALL getLength( ) override;
100 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override;
101 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
102 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
103 virtual sal_Int32 SAL_CALL available() override;
104 virtual void SAL_CALL closeInput() override;
106 protected:
107 void checkConnected();
108 void checkError();
112 FileStreamWrapper_Impl::FileStreamWrapper_Impl( const OUString& rName )
113 : m_aURL( rName )
115 // if no URL is provided the stream is empty
119 FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
121 if ( m_pSvStream )
123 m_pSvStream.reset();
124 #if OSL_DEBUG_LEVEL > 0
125 --nOpenFiles;
126 #endif
129 if (!m_aURL.isEmpty())
130 osl::File::remove(m_aURL);
134 sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
136 if ( m_aURL.isEmpty() )
138 aData.realloc( 0 );
139 return 0;
142 checkConnected();
144 if (nBytesToRead < 0)
145 throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
147 ::osl::MutexGuard aGuard( m_aMutex );
149 if (aData.getLength() < nBytesToRead)
150 aData.realloc(nBytesToRead);
152 sal_uInt32 nRead = m_pSvStream->ReadBytes(static_cast<void*>(aData.getArray()), nBytesToRead);
153 checkError();
155 // if read characters < MaxLength, adjust sequence
156 if (static_cast<sal_Int32>(nRead) < aData.getLength())
157 aData.realloc( nRead );
159 return nRead;
163 sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
165 if ( m_aURL.isEmpty() )
167 aData.realloc( 0 );
168 return 0;
171 checkError();
173 if (nMaxBytesToRead < 0)
174 throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
176 if (m_pSvStream->eof())
178 aData.realloc(0);
179 return 0;
181 else
182 return readBytes(aData, nMaxBytesToRead);
186 void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip)
188 if ( m_aURL.isEmpty() )
189 return;
191 ::osl::MutexGuard aGuard( m_aMutex );
192 checkError();
194 m_pSvStream->SeekRel(nBytesToSkip);
195 checkError();
199 sal_Int32 SAL_CALL FileStreamWrapper_Impl::available()
201 if ( m_aURL.isEmpty() )
202 return 0;
204 ::osl::MutexGuard aGuard( m_aMutex );
205 checkConnected();
207 sal_Int64 nAvailable = m_pSvStream->remainingSize();
208 checkError();
210 return std::min<sal_Int64>(SAL_MAX_INT32, nAvailable);
214 void SAL_CALL FileStreamWrapper_Impl::closeInput()
216 if ( m_aURL.isEmpty() )
217 return;
219 ::osl::MutexGuard aGuard( m_aMutex );
220 checkConnected();
221 m_pSvStream.reset();
222 #if OSL_DEBUG_LEVEL > 0
223 --nOpenFiles;
224 #endif
225 osl::File::remove(m_aURL);
226 m_aURL.clear();
230 void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation )
232 if ( m_aURL.isEmpty() )
233 return;
235 ::osl::MutexGuard aGuard( m_aMutex );
236 checkConnected();
238 m_pSvStream->Seek(static_cast<sal_uInt32>(_nLocation));
239 checkError();
243 sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition( )
245 if ( m_aURL.isEmpty() )
246 return 0;
248 ::osl::MutexGuard aGuard( m_aMutex );
249 checkConnected();
251 sal_uInt32 nPos = m_pSvStream->Tell();
252 checkError();
253 return static_cast<sal_Int64>(nPos);
257 sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength( )
259 if ( m_aURL.isEmpty() )
260 return 0;
262 ::osl::MutexGuard aGuard( m_aMutex );
263 checkConnected();
265 checkError();
267 sal_Int64 nEndPos = m_pSvStream->TellEnd();
269 return nEndPos;
273 void FileStreamWrapper_Impl::checkConnected()
275 if ( m_aURL.isEmpty() )
276 throw NotConnectedException(OUString(), static_cast<XWeak*>(this));
277 if ( !m_pSvStream )
279 m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, StreamMode::STD_READ );
280 #if OSL_DEBUG_LEVEL > 0
281 ++nOpenFiles;
282 #endif
287 void FileStreamWrapper_Impl::checkError()
289 checkConnected();
291 if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
292 // TODO: really evaluate the error
293 throw NotConnectedException(OUString(), static_cast<XWeak*>(this));
297 #define COMMIT_RESULT_FAILURE 0
298 #define COMMIT_RESULT_NOTHING_TO_DO 1
299 #define COMMIT_RESULT_SUCCESS 2
301 static SotClipboardFormatId GetFormatId_Impl( const SvGlobalName& aName )
303 if ( aName == SvGlobalName( SO3_SW_CLASSID_60 ) )
304 return SotClipboardFormatId::STARWRITER_60;
305 if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_60 ) )
306 return SotClipboardFormatId::STARWRITERWEB_60;
307 if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_60 ) )
308 return SotClipboardFormatId::STARWRITERGLOB_60;
309 if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) )
310 return SotClipboardFormatId::STARDRAW_60;
311 if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) )
312 return SotClipboardFormatId::STARIMPRESS_60;
313 if ( aName == SvGlobalName( SO3_SC_CLASSID_60 ) )
314 return SotClipboardFormatId::STARCALC_60;
315 if ( aName == SvGlobalName( SO3_SCH_CLASSID_60 ) )
316 return SotClipboardFormatId::STARCHART_60;
317 if ( aName == SvGlobalName( SO3_SM_CLASSID_60 ) )
318 return SotClipboardFormatId::STARMATH_60;
319 if ( aName == SvGlobalName( SO3_OUT_CLASSID ) ||
320 aName == SvGlobalName( SO3_APPLET_CLASSID ) ||
321 aName == SvGlobalName( SO3_PLUGIN_CLASSID ) ||
322 aName == SvGlobalName( SO3_IFRAME_CLASSID ) )
323 // allowed, but not supported
324 return SotClipboardFormatId::NONE;
325 else
327 OSL_FAIL( "Unknown UCB storage format!" );
328 return SotClipboardFormatId::NONE;
333 static SvGlobalName GetClassId_Impl( SotClipboardFormatId nFormat )
335 switch ( nFormat )
337 case SotClipboardFormatId::STARWRITER_8 :
338 case SotClipboardFormatId::STARWRITER_8_TEMPLATE :
339 return SvGlobalName( SO3_SW_CLASSID_60 );
340 case SotClipboardFormatId::STARWRITERWEB_8 :
341 return SvGlobalName( SO3_SWWEB_CLASSID_60 );
342 case SotClipboardFormatId::STARWRITERGLOB_8 :
343 case SotClipboardFormatId::STARWRITERGLOB_8_TEMPLATE :
344 return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
345 case SotClipboardFormatId::STARDRAW_8 :
346 case SotClipboardFormatId::STARDRAW_8_TEMPLATE :
347 return SvGlobalName( SO3_SDRAW_CLASSID_60 );
348 case SotClipboardFormatId::STARIMPRESS_8 :
349 case SotClipboardFormatId::STARIMPRESS_8_TEMPLATE :
350 return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
351 case SotClipboardFormatId::STARCALC_8 :
352 case SotClipboardFormatId::STARCALC_8_TEMPLATE :
353 return SvGlobalName( SO3_SC_CLASSID_60 );
354 case SotClipboardFormatId::STARCHART_8 :
355 case SotClipboardFormatId::STARCHART_8_TEMPLATE :
356 return SvGlobalName( SO3_SCH_CLASSID_60 );
357 case SotClipboardFormatId::STARMATH_8 :
358 case SotClipboardFormatId::STARMATH_8_TEMPLATE :
359 return SvGlobalName( SO3_SM_CLASSID_60 );
360 case SotClipboardFormatId::STARWRITER_60 :
361 return SvGlobalName( SO3_SW_CLASSID_60 );
362 case SotClipboardFormatId::STARWRITERWEB_60 :
363 return SvGlobalName( SO3_SWWEB_CLASSID_60 );
364 case SotClipboardFormatId::STARWRITERGLOB_60 :
365 return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
366 case SotClipboardFormatId::STARDRAW_60 :
367 return SvGlobalName( SO3_SDRAW_CLASSID_60 );
368 case SotClipboardFormatId::STARIMPRESS_60 :
369 return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
370 case SotClipboardFormatId::STARCALC_60 :
371 return SvGlobalName( SO3_SC_CLASSID_60 );
372 case SotClipboardFormatId::STARCHART_60 :
373 return SvGlobalName( SO3_SCH_CLASSID_60 );
374 case SotClipboardFormatId::STARMATH_60 :
375 return SvGlobalName( SO3_SM_CLASSID_60 );
376 default :
377 return SvGlobalName();
381 // All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
382 // class, that uses the refcounted object as impl-class.
384 class UCBStorageStream_Impl : public SvRefBase, public SvStream
386 virtual ~UCBStorageStream_Impl() override;
387 public:
389 virtual std::size_t GetData(void* pData, std::size_t nSize) override;
390 virtual std::size_t PutData(const void* pData, std::size_t nSize) override;
391 virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override;
392 virtual void SetSize( sal_uInt64 nSize ) override;
393 virtual void FlushData() override;
394 virtual void ResetError() override;
396 UCBStorageStream* m_pAntiImpl; // only valid if an external reference exists
398 OUString m_aOriginalName;// the original name before accessing the stream
399 OUString m_aName; // the actual name ( changed with a Rename command at the parent )
400 OUString m_aURL; // the full path name to create the content
401 OUString m_aContentType;
402 OUString m_aOriginalContentType;
403 OString const m_aKey;
404 ::ucbhelper::Content* m_pContent; // the content that provides the data
405 Reference<XInputStream> m_rSource; // the stream covering the original data of the content
406 std::unique_ptr<SvStream> m_pStream; // the stream worked on; for readonly streams it is the original stream of the content
407 // for read/write streams it's a copy into a temporary file
408 OUString m_aTempURL; // URL of this temporary stream
409 ErrCode m_nError;
410 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
411 bool m_bSourceRead; // Source still contains useful information
412 bool m_bModified; // only modified streams will be sent to the original content
413 bool m_bCommited; // sending the streams is coordinated by the root storage of the package
414 bool const m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
415 // this means that the root storage does an autocommit when its external
416 // reference is destroyed
417 bool m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
419 UCBStorageStream_Impl( const OUString&, StreamMode, UCBStorageStream*, bool,
420 bool bRepair, Reference< XProgressHandler > const & xProgress );
422 void Free();
423 bool Init();
424 bool Clear();
425 sal_Int16 Commit(); // if modified and committed: transfer an XInputStream to the content
426 void Revert(); // discard all changes
427 BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream
428 sal_uLong GetSize();
430 sal_uInt64 ReadSourceWriteTemporary( sal_uInt64 aLength ); // read aLength from source and copy to temporary,
431 // no seeking is produced
432 void ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
434 void CopySourceToTemporary(); // same as ReadSourceWriteToTemporary()
435 // but the writing is done at the end of temporary
436 // pointer position is not changed
437 using SvStream::SetError;
438 void SetError( ErrCode nError );
439 void PrepareCachedForReopen( StreamMode nMode );
442 typedef tools::SvRef<UCBStorageStream_Impl> UCBStorageStream_ImplRef;
444 struct UCBStorageElement_Impl;
445 typedef std::vector<std::unique_ptr<UCBStorageElement_Impl>> UCBStorageElementList_Impl;
447 class UCBStorage_Impl : public SvRefBase
449 virtual ~UCBStorage_Impl() override;
450 public:
451 UCBStorage* m_pAntiImpl; // only valid if external references exists
453 OUString m_aOriginalName;// the original name before accessing the storage
454 OUString m_aName; // the actual name ( changed with a Rename command at the parent )
455 OUString m_aURL; // the full path name to create the content
456 OUString m_aContentType;
457 OUString m_aOriginalContentType;
458 ::ucbhelper::Content* m_pContent; // the content that provides the storage elements
459 ::utl::TempFile* m_pTempFile; // temporary file, only for storages on stream
460 SvStream* m_pSource; // original stream, only for storages on a stream
461 ErrCode m_nError;
462 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
463 bool m_bCommited; // sending the streams is coordinated by the root storage of the package
464 bool const m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
465 // this means that the root storage does an autocommit when its external
466 // reference is destroyed
467 bool m_bIsRoot; // marks this storage as root storages that manages all commits and reverts
468 bool m_bIsLinked;
469 bool m_bListCreated;
470 SotClipboardFormatId m_nFormat;
471 OUString m_aUserTypeName;
472 SvGlobalName m_aClassId;
474 UCBStorageElementList_Impl m_aChildrenList;
476 bool const m_bRepairPackage;
477 Reference< XProgressHandler > m_xProgressHandler;
479 UCBStorage_Impl( const ::ucbhelper::Content&, const OUString&, StreamMode, UCBStorage*, bool,
480 bool, bool = false, Reference< XProgressHandler > const & = Reference< XProgressHandler >() );
481 UCBStorage_Impl( const OUString&, StreamMode, UCBStorage*, bool, bool,
482 bool, Reference< XProgressHandler > const & );
483 UCBStorage_Impl( SvStream&, UCBStorage*, bool );
484 void Init();
485 sal_Int16 Commit();
486 void Revert();
487 bool Insert( ::ucbhelper::Content *pContent );
488 UCBStorage_Impl* OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect );
489 void OpenStream( UCBStorageElement_Impl*, StreamMode, bool );
490 void SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
491 void GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
492 sal_Int32 GetObjectCount();
493 void ReadContent();
494 void CreateContent();
495 ::ucbhelper::Content* GetContent()
497 if ( !m_pContent )
498 CreateContent();
499 return m_pContent;
501 UCBStorageElementList_Impl& GetChildrenList()
503 const ErrCode nError = m_nError;
504 ReadContent();
505 if ( m_nMode & StreamMode::WRITE )
507 m_nError = nError;
508 if ( m_pAntiImpl )
510 m_pAntiImpl->ResetError();
511 m_pAntiImpl->SetError( nError );
514 return m_aChildrenList;
517 void SetError( ErrCode nError );
520 typedef tools::SvRef<UCBStorage_Impl> UCBStorage_ImplRef;
522 // this struct contains all necessary information on an element inside a UCBStorage
523 struct UCBStorageElement_Impl
525 OUString m_aName; // the actual URL relative to the root "folder"
526 OUString m_aOriginalName;// the original name in the content
527 sal_uLong const m_nSize;
528 bool m_bIsFolder; // Only true when it is a UCBStorage !
529 bool m_bIsStorage; // Also true when it is an OLEStorage !
530 bool m_bIsRemoved; // element will be removed on commit
531 bool m_bIsInserted; // element will be removed on revert
532 UCBStorage_ImplRef m_xStorage; // reference to the "real" storage
533 UCBStorageStream_ImplRef m_xStream; // reference to the "real" stream
535 UCBStorageElement_Impl( const OUString& rName,
536 bool bIsFolder = false, sal_uLong nSize = 0 )
537 : m_aName( rName )
538 , m_aOriginalName( rName )
539 , m_nSize( nSize )
540 , m_bIsFolder( bIsFolder )
541 , m_bIsStorage( bIsFolder )
542 , m_bIsRemoved( false )
543 , m_bIsInserted( false )
547 ::ucbhelper::Content* GetContent();
548 bool IsModified() const;
549 OUString GetContentType() const;
550 void SetContentType( const OUString& );
551 OUString GetOriginalContentType() const;
552 bool IsLoaded() const
553 { return m_xStream.is() || m_xStorage.is(); }
556 ::ucbhelper::Content* UCBStorageElement_Impl::GetContent()
558 if ( m_xStream.is() )
559 return m_xStream->m_pContent;
560 else if ( m_xStorage.is() )
561 return m_xStorage->GetContent();
562 else
563 return nullptr;
566 OUString UCBStorageElement_Impl::GetContentType() const
568 if ( m_xStream.is() )
569 return m_xStream->m_aContentType;
570 else if ( m_xStorage.is() )
571 return m_xStorage->m_aContentType;
572 else
574 OSL_FAIL("Element not loaded!");
575 return OUString();
579 void UCBStorageElement_Impl::SetContentType( const OUString& rType )
581 if ( m_xStream.is() ) {
582 m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
584 else if ( m_xStorage.is() ) {
585 m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
587 else {
588 OSL_FAIL("Element not loaded!");
592 OUString UCBStorageElement_Impl::GetOriginalContentType() const
594 if ( m_xStream.is() )
595 return m_xStream->m_aOriginalContentType;
596 else if ( m_xStorage.is() )
597 return m_xStorage->m_aOriginalContentType;
598 else
599 return OUString();
602 bool UCBStorageElement_Impl::IsModified() const
604 bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
605 if ( bModified )
607 if ( m_xStream.is() )
608 bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
609 else if ( m_xStorage.is() )
610 bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
613 return bModified;
616 UCBStorageStream_Impl::UCBStorageStream_Impl( const OUString& rName, StreamMode nMode, UCBStorageStream* pStream, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
617 : m_pAntiImpl( pStream )
618 , m_aURL( rName )
619 , m_pContent( nullptr )
620 , m_nError( ERRCODE_NONE )
621 , m_nMode( nMode )
622 , m_bSourceRead( !( nMode & StreamMode::TRUNC ) )
623 , m_bModified( false )
624 , m_bCommited( false )
625 , m_bDirect( bDirect )
626 , m_bIsOLEStorage( false )
628 // name is last segment in URL
629 INetURLObject aObj( rName );
630 m_aName = m_aOriginalName = aObj.GetLastName();
633 // create the content
634 Reference< css::ucb::XCommandEnvironment > xComEnv;
636 OUString aTemp( rName );
638 if ( bRepair )
640 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(), xProgress );
641 aTemp += "?repairpackage";
644 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
646 catch (const ContentCreationException&)
648 // content could not be created
649 SetError( SVSTREAM_CANNOT_MAKE );
651 catch (const RuntimeException&)
653 // any other error - not specified
654 SetError( ERRCODE_IO_GENERAL );
658 UCBStorageStream_Impl::~UCBStorageStream_Impl()
660 if( m_rSource.is() )
661 m_rSource.clear();
663 m_pStream.reset();
665 if (!m_aTempURL.isEmpty())
666 osl::File::remove(m_aTempURL);
668 delete m_pContent;
672 bool UCBStorageStream_Impl::Init()
674 if( !m_pStream )
676 // no temporary stream was created
677 // create one
679 if ( m_aTempURL.isEmpty() )
680 m_aTempURL = ::utl::TempFile().GetURL();
682 m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, StreamMode::STD_READWRITE, true /* bFileExists */ );
683 #if OSL_DEBUG_LEVEL > 0
684 ++nOpenFiles;
685 #endif
687 if( !m_pStream )
689 OSL_FAIL( "Suspicious temporary stream creation!" );
690 SetError( SVSTREAM_CANNOT_MAKE );
691 return false;
694 SetError( m_pStream->GetError() );
697 if( m_bSourceRead && !m_rSource.is() )
699 // source file contain useful information and is not opened
700 // open it from the point of noncopied data
704 m_rSource = m_pContent->openStream();
706 catch (const Exception&)
708 // usually means that stream could not be opened
711 if( m_rSource.is() )
713 m_pStream->Seek( STREAM_SEEK_TO_END );
717 m_rSource->skipBytes( m_pStream->Tell() );
719 catch (const BufferSizeExceededException&)
721 // the temporary stream already contain all the data
722 m_bSourceRead = false;
724 catch (const Exception&)
726 // something is really wrong
727 m_bSourceRead = false;
728 OSL_FAIL( "Can not operate original stream!" );
729 SetError( SVSTREAM_CANNOT_MAKE );
732 m_pStream->Seek( 0 );
734 else
736 // if the new file is edited then no source exist
737 m_bSourceRead = false;
738 //SetError( SVSTREAM_CANNOT_MAKE );
742 DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" );
744 return true;
747 void UCBStorageStream_Impl::ReadSourceWriteTemporary()
749 // read source stream till the end and copy all the data to
750 // the current position of the temporary stream
752 if( m_bSourceRead )
754 Sequence<sal_Int8> aData(32000);
758 sal_uLong aReaded;
761 aReaded = m_rSource->readBytes( aData, 32000 );
762 m_pStream->WriteBytes(aData.getArray(), aReaded);
763 } while( aReaded == 32000 );
765 catch (const Exception &e)
767 SAL_WARN( "sot", e );
771 m_bSourceRead = false;
774 sal_uInt64 UCBStorageStream_Impl::ReadSourceWriteTemporary(sal_uInt64 aLength)
776 // read aLength bite from the source stream and copy them to the current
777 // position of the temporary stream
779 sal_uInt64 aResult = 0;
781 if( m_bSourceRead )
783 Sequence<sal_Int8> aData(32000);
788 sal_uLong aReaded = 32000;
790 for (sal_uInt64 nInd = 0; nInd < aLength && aReaded == 32000 ; nInd += 32000)
792 sal_uLong aToCopy = std::min<sal_uInt64>( aLength - nInd, 32000 );
793 aReaded = m_rSource->readBytes( aData, aToCopy );
794 aResult += m_pStream->WriteBytes(aData.getArray(), aReaded);
797 if( aResult < aLength )
798 m_bSourceRead = false;
800 catch( const Exception & e )
802 SAL_WARN( "sot", e );
806 return aResult;
809 void UCBStorageStream_Impl::CopySourceToTemporary()
811 // current position of the temporary stream is not changed
812 if( m_bSourceRead )
814 sal_uInt64 aPos = m_pStream->Tell();
815 m_pStream->Seek( STREAM_SEEK_TO_END );
816 ReadSourceWriteTemporary();
817 m_pStream->Seek( aPos );
821 // UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
822 // of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
823 std::size_t UCBStorageStream_Impl::GetData(void* pData, std::size_t const nSize)
825 std::size_t aResult = 0;
827 if( !Init() )
828 return 0;
831 // read data that is in temporary stream
832 aResult = m_pStream->ReadBytes( pData, nSize );
833 if( m_bSourceRead && aResult < nSize )
835 // read the tail of the data from original stream
836 // copy this tail to the temporary stream
838 std::size_t aToRead = nSize - aResult;
839 pData = static_cast<void*>( static_cast<char*>(pData) + aResult );
843 Sequence<sal_Int8> aData( aToRead );
844 std::size_t aReaded = m_rSource->readBytes( aData, aToRead );
845 aResult += m_pStream->WriteBytes(static_cast<void*>(aData.getArray()), aReaded);
846 memcpy( pData, aData.getArray(), aReaded );
848 catch (const Exception &e)
850 SAL_WARN( "sot", e );
853 if( aResult < nSize )
854 m_bSourceRead = false;
857 return aResult;
860 std::size_t UCBStorageStream_Impl::PutData(const void* pData, std::size_t const nSize)
862 if ( !(m_nMode & StreamMode::WRITE) )
864 SetError( ERRCODE_IO_ACCESSDENIED );
865 return 0; // ?mav?
868 if( !nSize || !Init() )
869 return 0;
871 std::size_t aResult = m_pStream->WriteBytes( pData, nSize );
873 m_bModified = aResult > 0;
875 return aResult;
879 sal_uInt64 UCBStorageStream_Impl::SeekPos(sal_uInt64 const nPos)
881 // check if a truncated STREAM_SEEK_TO_END was passed
882 assert(nPos != SAL_MAX_UINT32);
884 if( !Init() )
885 return 0;
887 sal_uInt64 aResult;
889 if( nPos == STREAM_SEEK_TO_END )
891 m_pStream->Seek( STREAM_SEEK_TO_END );
892 ReadSourceWriteTemporary();
893 aResult = m_pStream->Tell();
895 else
897 // the problem is that even if nPos is larger the length
898 // of the stream, the stream pointer will be moved to this position
899 // so we have to check if temporary stream does not contain required position
901 if( m_pStream->Tell() > nPos
902 || m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos )
904 // no copiing is required
905 aResult = m_pStream->Seek( nPos );
907 else
909 // the temp stream pointer points to the end now
910 aResult = m_pStream->Tell();
912 if( aResult < nPos )
914 if( m_bSourceRead )
916 aResult += ReadSourceWriteTemporary( nPos - aResult );
917 if( aResult < nPos )
918 m_bSourceRead = false;
920 DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" );
923 if( (m_nMode & StreamMode::WRITE) && !m_bSourceRead && aResult < nPos )
925 // it means that all the Source stream was copied already
926 // but the required position still was not reached
927 // for writable streams it should be done
928 m_pStream->SetStreamSize( nPos );
929 aResult = m_pStream->Seek( STREAM_SEEK_TO_END );
930 DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" );
936 return aResult;
939 void UCBStorageStream_Impl::SetSize(sal_uInt64 const nSize)
941 if ( !(m_nMode & StreamMode::WRITE) )
943 SetError( ERRCODE_IO_ACCESSDENIED );
944 return;
947 if( !Init() )
948 return;
950 m_bModified = true;
952 if( m_bSourceRead )
954 sal_uInt64 const aPos = m_pStream->Tell();
955 m_pStream->Seek( STREAM_SEEK_TO_END );
956 if( m_pStream->Tell() < nSize )
957 ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
958 m_pStream->Seek( aPos );
961 m_pStream->SetStreamSize( nSize );
962 m_bSourceRead = false;
965 void UCBStorageStream_Impl::FlushData()
967 if( m_pStream )
969 CopySourceToTemporary();
970 m_pStream->Flush();
973 m_bCommited = true;
976 void UCBStorageStream_Impl::SetError( ErrCode nErr )
978 if ( !m_nError )
980 m_nError = nErr;
981 SvStream::SetError( nErr );
982 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
986 void UCBStorageStream_Impl::ResetError()
988 m_nError = ERRCODE_NONE;
989 SvStream::ResetError();
990 if ( m_pAntiImpl )
991 m_pAntiImpl->ResetError();
994 sal_uLong UCBStorageStream_Impl::GetSize()
996 if( !Init() )
997 return 0;
999 sal_uInt64 nPos = m_pStream->Tell();
1000 m_pStream->Seek( STREAM_SEEK_TO_END );
1001 ReadSourceWriteTemporary();
1002 sal_uInt64 nRet = m_pStream->Tell();
1003 m_pStream->Seek( nPos );
1005 return nRet;
1008 BaseStorage* UCBStorageStream_Impl::CreateStorage()
1010 // create an OLEStorage on a SvStream ( = this )
1011 // it gets the root attribute because otherwise it would probably not write before my root is committed
1012 UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
1013 Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
1015 // GetError() call cleares error code for OLE storages, must be changed in future
1016 const ErrCode nTmpErr = pStorage->GetError();
1017 pStorage->SetError( nTmpErr );
1019 m_bIsOLEStorage = !nTmpErr;
1020 return static_cast< BaseStorage* > ( pStorage );
1023 sal_Int16 UCBStorageStream_Impl::Commit()
1025 // send stream to the original content
1026 // the parent storage is responsible for the correct handling of deleted contents
1027 if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
1029 // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1030 // was committed as well ( if not opened in direct mode )
1032 if ( m_bModified )
1036 CopySourceToTemporary();
1038 // release all stream handles
1039 Free();
1041 // the temporary file does not exist only for truncated streams
1042 DBG_ASSERT( !m_aTempURL.isEmpty() || ( m_nMode & StreamMode::TRUNC ), "No temporary file to read from!");
1043 if ( m_aTempURL.isEmpty() && !( m_nMode & StreamMode::TRUNC ) )
1044 throw RuntimeException();
1046 // create wrapper to stream that is only used while reading inside package component
1047 Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL );
1049 InsertCommandArgument aArg;
1050 aArg.Data = xStream;
1051 aArg.ReplaceExisting = true;
1052 m_pContent->executeCommand( "insert", Any(aArg) );
1054 // wrapper now controls lifetime of temporary file
1055 m_aTempURL.clear();
1057 INetURLObject aObj( m_aURL );
1058 aObj.SetName( m_aName );
1059 m_aURL = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1060 m_bModified = false;
1061 m_bSourceRead = true;
1063 catch (const CommandAbortedException&)
1065 // any command wasn't executed successfully - not specified
1066 SetError( ERRCODE_IO_GENERAL );
1067 return COMMIT_RESULT_FAILURE;
1069 catch (const RuntimeException&)
1071 // any other error - not specified
1072 SetError( ERRCODE_IO_GENERAL );
1073 return COMMIT_RESULT_FAILURE;
1075 catch (const Exception&)
1077 // any other error - not specified
1078 SetError( ERRCODE_IO_GENERAL );
1079 return COMMIT_RESULT_FAILURE;
1082 m_bCommited = false;
1083 return COMMIT_RESULT_SUCCESS;
1087 return COMMIT_RESULT_NOTHING_TO_DO;
1090 void UCBStorageStream_Impl::Revert()
1092 // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
1093 if ( m_bCommited )
1095 OSL_FAIL("Revert while commit is in progress!" );
1096 return; // ???
1099 Free();
1100 if ( !m_aTempURL.isEmpty() )
1102 osl::File::remove(m_aTempURL);
1103 m_aTempURL.clear();
1106 m_bSourceRead = false;
1109 m_rSource = m_pContent->openStream();
1110 if( m_rSource.is() )
1112 if ( m_pAntiImpl && ( m_nMode & StreamMode::TRUNC ) )
1113 // stream is in use and should be truncated
1114 m_bSourceRead = false;
1115 else
1117 m_nMode &= ~StreamMode::TRUNC;
1118 m_bSourceRead = true;
1121 else
1122 SetError( SVSTREAM_CANNOT_MAKE );
1124 catch (const ContentCreationException&)
1126 SetError( ERRCODE_IO_GENERAL );
1128 catch (const RuntimeException&)
1130 SetError( ERRCODE_IO_GENERAL );
1132 catch (const Exception&)
1136 m_bModified = false;
1137 m_aName = m_aOriginalName;
1138 m_aContentType = m_aOriginalContentType;
1141 bool UCBStorageStream_Impl::Clear()
1143 bool bRet = ( m_pAntiImpl == nullptr );
1144 DBG_ASSERT( bRet, "Removing used stream!" );
1145 if( bRet )
1147 Free();
1150 return bRet;
1153 void UCBStorageStream_Impl::Free()
1155 #if OSL_DEBUG_LEVEL > 0
1156 if ( m_pStream )
1158 if ( !m_aTempURL.isEmpty() )
1159 --nOpenFiles;
1160 else
1161 --nOpenStreams;
1163 #endif
1165 m_rSource.clear();
1166 m_pStream.reset();
1169 void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
1171 bool isWritable = bool( m_nMode & StreamMode::WRITE );
1172 if ( isWritable )
1174 // once stream was writable, never reset to readonly
1175 nMode |= StreamMode::WRITE;
1178 m_nMode = nMode;
1179 Free();
1181 if ( nMode & StreamMode::TRUNC )
1183 m_bSourceRead = false; // usually it should be 0 already but just in case...
1185 if ( !m_aTempURL.isEmpty() )
1187 osl::File::remove(m_aTempURL);
1188 m_aTempURL.clear();
1193 UCBStorageStream::UCBStorageStream( const OUString& rName, StreamMode nMode, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
1195 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1196 // to class UCBStorageStream !
1197 pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, bRepair, xProgress );
1198 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1199 StorageBase::m_nMode = pImp->m_nMode;
1202 UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
1203 : pImp( pImpl )
1205 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1206 pImp->m_pAntiImpl = this;
1207 SetError( pImp->m_nError );
1208 StorageBase::m_nMode = pImp->m_nMode;
1211 UCBStorageStream::~UCBStorageStream()
1213 if ( pImp->m_nMode & StreamMode::WRITE )
1214 pImp->Flush();
1215 pImp->m_pAntiImpl = nullptr;
1216 pImp->Free();
1217 pImp->ReleaseRef();
1220 sal_uLong UCBStorageStream::Read( void * pData, sal_uLong nSize )
1222 //return pImp->m_pStream->Read( pData, nSize );
1223 return pImp->GetData( pData, nSize );
1226 sal_uLong UCBStorageStream::Write( const void* pData, sal_uLong nSize )
1228 return pImp->PutData( pData, nSize );
1231 sal_uInt64 UCBStorageStream::Seek( sal_uInt64 nPos )
1233 //return pImp->m_pStream->Seek( nPos );
1234 return pImp->Seek( nPos );
1237 sal_uLong UCBStorageStream::Tell()
1239 if( !pImp->Init() )
1240 return 0;
1241 return pImp->m_pStream->Tell();
1244 void UCBStorageStream::Flush()
1246 // streams are never really transacted, so flush also means commit !
1247 Commit();
1250 bool UCBStorageStream::SetSize( sal_uLong nNewSize )
1252 pImp->SetSize( nNewSize );
1253 return !pImp->GetError();
1256 bool UCBStorageStream::Validate( bool bWrite ) const
1258 return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
1261 bool UCBStorageStream::ValidateMode( StreamMode m ) const
1263 // ???
1264 if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx
1265 return true;
1266 if( ( m & StreamMode::READWRITE) == StreamMode::READ )
1268 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1269 if( ( m & StreamMode::SHARE_DENYWRITE )
1270 || ( m & StreamMode::SHARE_DENYALL ) )
1271 return true;
1273 else
1275 // only SHARE_DENYALL allowed
1276 // storages open in r/o mode are OK, since only
1277 // the commit may fail
1278 if( m & StreamMode::SHARE_DENYALL )
1279 return true;
1282 return true;
1285 SvStream* UCBStorageStream::GetModifySvStream()
1287 return static_cast<SvStream*>(pImp);
1290 bool UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
1292 // ???
1293 return static_cast<BaseStorageStream const *>(this) == &rStream;
1296 bool UCBStorageStream::Commit()
1298 // mark this stream for sending it on root commit
1299 pImp->FlushData();
1300 return true;
1303 void UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
1305 if( !pImp->Init() )
1306 return;
1308 UCBStorageStream* pStg = dynamic_cast<UCBStorageStream*>( pDestStm );
1309 if ( pStg )
1310 pStg->pImp->m_aContentType = pImp->m_aContentType;
1312 pDestStm->SetSize( 0 );
1313 Seek( STREAM_SEEK_TO_END );
1314 sal_Int32 n = Tell();
1315 if( n < 0 )
1316 return;
1318 if( pDestStm->SetSize( n ) && n )
1320 std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[ 4096 ]);
1321 Seek( 0 );
1322 pDestStm->Seek( 0 );
1323 while( n )
1325 sal_uInt32 nn = n;
1326 if( nn > 4096 )
1327 nn = 4096;
1328 if( Read( p.get(), nn ) != nn )
1329 break;
1330 if( pDestStm->Write( p.get(), nn ) != nn )
1331 break;
1332 n -= nn;
1337 bool UCBStorageStream::SetProperty( const OUString& rName, const css::uno::Any& rValue )
1339 if ( rName == "Title")
1340 return false;
1342 if ( rName == "MediaType")
1344 OUString aTmp;
1345 rValue >>= aTmp;
1346 pImp->m_aContentType = aTmp;
1351 if ( pImp->m_pContent )
1353 pImp->m_pContent->setPropertyValue( rName, rValue );
1354 return true;
1357 catch (const Exception&)
1361 return false;
1364 sal_uLong UCBStorageStream::GetSize() const
1366 return pImp->GetSize();
1369 UCBStorage::UCBStorage( SvStream& rStrm, bool bDirect )
1371 OUString aURL = GetLinkedFile( rStrm );
1372 if ( !aURL.isEmpty() )
1374 StreamMode nMode = StreamMode::READ;
1375 if( rStrm.IsWritable() )
1376 nMode = StreamMode::READ | StreamMode::WRITE;
1378 ::ucbhelper::Content aContent( aURL, Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
1379 pImp = new UCBStorage_Impl( aContent, aURL, nMode, this, bDirect, true );
1381 else
1383 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1384 // to class UCBStorage !
1385 pImp = new UCBStorage_Impl( rStrm, this, bDirect );
1388 pImp->AddFirstRef();
1389 pImp->Init();
1390 StorageBase::m_nMode = pImp->m_nMode;
1393 UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1395 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1396 // to class UCBStorage !
1397 pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
1398 pImp->AddFirstRef();
1399 pImp->Init();
1400 StorageBase::m_nMode = pImp->m_nMode;
1403 UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1405 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1406 // to class UCBStorage !
1407 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
1408 pImp->AddFirstRef();
1409 pImp->Init();
1410 StorageBase::m_nMode = pImp->m_nMode;
1413 UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1415 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1416 // to class UCBStorage !
1417 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, false, Reference< XProgressHandler >() );
1418 pImp->AddFirstRef();
1419 pImp->Init();
1420 StorageBase::m_nMode = pImp->m_nMode;
1423 UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
1424 : pImp( pImpl )
1426 pImp->m_pAntiImpl = this;
1427 SetError( pImp->m_nError );
1428 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1429 StorageBase::m_nMode = pImp->m_nMode;
1432 UCBStorage::~UCBStorage()
1434 if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
1435 // DirectMode is simulated with an AutoCommit
1436 Commit();
1438 pImp->m_pAntiImpl = nullptr;
1439 pImp->ReleaseRef();
1442 UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1443 : m_pAntiImpl( pStorage )
1444 , m_pContent( new ::ucbhelper::Content( rContent ) )
1445 , m_pTempFile( nullptr )
1446 , m_pSource( nullptr )
1447 //, m_pStream( NULL )
1448 , m_nError( ERRCODE_NONE )
1449 , m_nMode( nMode )
1450 , m_bCommited( false )
1451 , m_bDirect( bDirect )
1452 , m_bIsRoot( bIsRoot )
1453 , m_bIsLinked( true )
1454 , m_bListCreated( false )
1455 , m_nFormat( SotClipboardFormatId::NONE )
1456 , m_aClassId( SvGlobalName() )
1457 , m_bRepairPackage( bIsRepair )
1458 , m_xProgressHandler( xProgressHandler )
1460 OUString aName( rName );
1461 if( aName.isEmpty() )
1463 // no name given = use temporary name!
1464 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1465 m_pTempFile = new ::utl::TempFile;
1466 m_pTempFile->EnableKillingFile();
1467 m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
1470 m_aURL = rName;
1473 UCBStorage_Impl::UCBStorage_Impl( const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1474 : m_pAntiImpl( pStorage )
1475 , m_pContent( nullptr )
1476 , m_pTempFile( nullptr )
1477 , m_pSource( nullptr )
1478 //, m_pStream( NULL )
1479 , m_nError( ERRCODE_NONE )
1480 , m_nMode( nMode )
1481 , m_bCommited( false )
1482 , m_bDirect( bDirect )
1483 , m_bIsRoot( bIsRoot )
1484 , m_bIsLinked( false )
1485 , m_bListCreated( false )
1486 , m_nFormat( SotClipboardFormatId::NONE )
1487 , m_aClassId( SvGlobalName() )
1488 , m_bRepairPackage( bIsRepair )
1489 , m_xProgressHandler( xProgressHandler )
1491 OUString aName( rName );
1492 if( aName.isEmpty() )
1494 // no name given = use temporary name!
1495 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1496 m_pTempFile = new ::utl::TempFile;
1497 m_pTempFile->EnableKillingFile();
1498 m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
1501 if ( m_bIsRoot )
1503 // create the special package URL for the package content
1504 OUString aTemp = "vnd.sun.star.pkg://";
1505 aTemp += INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
1506 m_aURL = aTemp;
1508 if ( m_nMode & StreamMode::WRITE )
1510 // the root storage opens the package, so make sure that there is any
1511 ::utl::UcbStreamHelper::CreateStream( aName, StreamMode::STD_READWRITE, m_pTempFile != nullptr /* bFileExists */ );
1514 else
1516 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1517 m_aURL = rName;
1518 if ( !m_aURL.startsWith( "vnd.sun.star.pkg://") )
1519 m_bIsLinked = true;
1523 UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, bool bDirect )
1524 : m_pAntiImpl( pStorage )
1525 , m_pContent( nullptr )
1526 , m_pTempFile( new ::utl::TempFile )
1527 , m_pSource( &rStream )
1528 , m_nError( ERRCODE_NONE )
1529 , m_bCommited( false )
1530 , m_bDirect( bDirect )
1531 , m_bIsRoot( true )
1532 , m_bIsLinked( false )
1533 , m_bListCreated( false )
1534 , m_nFormat( SotClipboardFormatId::NONE )
1535 , m_aClassId( SvGlobalName() )
1536 , m_bRepairPackage( false )
1538 // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1539 // which will be called in the storages' dtor
1540 m_pTempFile->EnableKillingFile();
1541 DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" );
1543 // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1544 // accessed readonly
1545 // the root storage opens the package; create the special package URL for the package content
1546 OUString aTemp = "vnd.sun.star.pkg://";
1547 aTemp += INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
1548 m_aURL = aTemp;
1550 // copy data into the temporary file
1551 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READWRITE, true /* bFileExists */ ));
1552 if ( pStream )
1554 rStream.Seek(0);
1555 rStream.ReadStream( *pStream );
1556 pStream->Flush();
1557 pStream.reset();
1560 // close stream and let content access the file
1561 m_pSource->Seek(0);
1563 // check opening mode
1564 m_nMode = StreamMode::READ;
1565 if( rStream.IsWritable() )
1566 m_nMode = StreamMode::READ | StreamMode::WRITE;
1569 void UCBStorage_Impl::Init()
1571 // name is last segment in URL
1572 INetURLObject aObj( m_aURL );
1573 if ( m_aName.isEmpty() )
1574 // if the name was not already set to a temp name
1575 m_aName = m_aOriginalName = aObj.GetLastName();
1577 if ( !m_pContent )
1578 CreateContent();
1580 if ( m_pContent )
1582 if ( m_bIsLinked )
1584 if( m_bIsRoot )
1586 ReadContent();
1587 if ( m_nError == ERRCODE_NONE )
1589 // read the manifest.xml file
1590 aObj.Append( "META-INF" );
1591 aObj.Append( "manifest.xml" );
1593 // create input stream
1594 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::STD_READ ));
1595 // no stream means no manifest.xml
1596 if ( pStream )
1598 if ( !pStream->GetError() )
1600 ::utl::OInputStreamWrapper* pHelper = new ::utl::OInputStreamWrapper( *pStream );
1601 css::uno::Reference < css::io::XInputStream > xInputStream( pHelper );
1603 // create a manifest reader object that will read in the manifest from the stream
1604 Reference < css::packages::manifest::XManifestReader > xReader =
1605 css::packages::manifest::ManifestReader::create(
1606 ::comphelper::getProcessComponentContext() ) ;
1607 Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream );
1609 // cleanup
1610 xReader = nullptr;
1611 xInputStream = nullptr;
1612 SetProps( aProps, OUString() );
1617 else
1618 ReadContent();
1620 else
1622 // get the manifest information from the package
1623 try {
1624 Any aAny = m_pContent->getPropertyValue("MediaType");
1625 OUString aTmp;
1626 if ( ( aAny >>= aTmp ) && !aTmp.isEmpty() )
1627 m_aContentType = m_aOriginalContentType = aTmp;
1629 catch (const Exception&)
1631 SAL_WARN( "sot",
1632 "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1637 if ( !m_aContentType.isEmpty() )
1639 // get the clipboard format using the content type
1640 css::datatransfer::DataFlavor aDataFlavor;
1641 aDataFlavor.MimeType = m_aContentType;
1642 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1644 // get the ClassId using the clipboard format ( internal table )
1645 m_aClassId = GetClassId_Impl( m_nFormat );
1647 // get human presentable name using the clipboard format
1648 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1649 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1651 if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
1652 ReadContent();
1656 void UCBStorage_Impl::CreateContent()
1660 // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1661 Reference< css::ucb::XCommandEnvironment > xComEnv;
1663 OUString aTemp( m_aURL );
1665 if ( m_bRepairPackage )
1667 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1668 m_xProgressHandler );
1669 aTemp += "?repairpackage";
1672 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
1674 catch (const ContentCreationException&)
1676 // content could not be created
1677 SetError( SVSTREAM_CANNOT_MAKE );
1679 catch (const RuntimeException&)
1681 // any other error - not specified
1682 SetError( SVSTREAM_CANNOT_MAKE );
1686 void UCBStorage_Impl::ReadContent()
1688 if ( m_bListCreated )
1689 return;
1691 m_bListCreated = true;
1693 // create cursor for access to children
1694 Sequence< OUString > aProps(4);
1695 aProps[0] = "Title";
1696 aProps[1] = "IsFolder";
1697 aProps[2] = "MediaType";
1698 aProps[3] = "Size";
1702 GetContent();
1703 if ( !m_pContent )
1704 return;
1706 Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS );
1707 Reference< XRow > xRow( xResultSet, UNO_QUERY );
1708 if ( xResultSet.is() )
1710 while ( xResultSet->next() )
1712 // insert all into the children list
1713 OUString aTitle( xRow->getString(1) );
1714 if ( m_bIsLinked )
1716 // unpacked storages have to deal with the meta-inf folder by themselves
1717 if ( aTitle == "META-INF" )
1718 continue;
1721 bool bIsFolder( xRow->getBoolean(2) );
1722 sal_Int64 nSize = xRow->getLong(4);
1723 UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, static_cast<sal_uLong>(nSize) );
1724 m_aChildrenList.emplace_back( pElement );
1726 bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
1727 if ( bIsFolder )
1729 if ( m_bIsLinked )
1730 OpenStorage( pElement, m_nMode, m_bDirect );
1731 if ( pElement->m_xStorage.is() )
1732 pElement->m_xStorage->Init();
1734 else if ( bIsOfficeDocument )
1736 // streams can be external OLE objects, so they are now folders, but storages!
1737 OUString aName( m_aURL + "/" + xRow->getString(1));
1739 Reference< css::ucb::XCommandEnvironment > xComEnv;
1740 if ( m_bRepairPackage )
1742 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1743 m_xProgressHandler );
1744 aName += "?repairpackage";
1747 ::ucbhelper::Content aContent( aName, xComEnv, comphelper::getProcessComponentContext() );
1749 OUString aMediaType;
1750 Any aAny = aContent.getPropertyValue("MediaType");
1751 if ( ( aAny >>= aMediaType ) && ( aMediaType == "application/vnd.sun.star.oleobject" ) )
1752 pElement->m_bIsStorage = true;
1753 else if ( aMediaType.isEmpty() )
1755 // older files didn't have that special content type, so they must be detected
1756 OpenStream( pElement, StreamMode::STD_READ, m_bDirect );
1757 if ( Storage::IsStorageFile( pElement->m_xStream.get() ) )
1758 pElement->m_bIsStorage = true;
1759 else
1760 pElement->m_xStream->Free();
1766 catch (const InteractiveIOException& r)
1768 if ( r.Code != IOErrorCode_NOT_EXISTING )
1769 SetError( ERRCODE_IO_GENERAL );
1771 catch (const CommandAbortedException&)
1773 // any command wasn't executed successfully - not specified
1774 if ( !( m_nMode & StreamMode::WRITE ) )
1775 // if the folder was just inserted and not already committed, this is not an error!
1776 SetError( ERRCODE_IO_GENERAL );
1778 catch (const RuntimeException&)
1780 // any other error - not specified
1781 SetError( ERRCODE_IO_GENERAL );
1783 catch (const ResultSetException&)
1785 // means that the package file is broken
1786 SetError( ERRCODE_IO_BROKENPACKAGE );
1788 catch (const SQLException&)
1790 // means that the file can be broken
1791 SetError( ERRCODE_IO_WRONGFORMAT );
1793 catch (const Exception&)
1795 // any other error - not specified
1796 SetError( ERRCODE_IO_GENERAL );
1800 void UCBStorage_Impl::SetError( ErrCode nError )
1802 if ( !m_nError )
1804 m_nError = nError;
1805 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
1809 sal_Int32 UCBStorage_Impl::GetObjectCount()
1811 sal_Int32 nCount = m_aChildrenList.size();
1812 for (auto& pElement : m_aChildrenList)
1814 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1815 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1816 nCount += pElement->m_xStorage->GetObjectCount();
1819 return nCount;
1822 static OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1824 bool bFound = false;
1825 for ( sal_Int32 nSeqs=0; nSeqs<rSequence.getLength(); nSeqs++ )
1827 const Sequence < PropertyValue >& rMyProps = rSequence[nSeqs];
1828 OUString aType;
1830 for ( sal_Int32 nProps=0; nProps<rMyProps.getLength(); nProps++ )
1832 const PropertyValue& rAny = rMyProps[nProps];
1833 if ( rAny.Name == "FullPath" )
1835 OUString aTmp;
1836 if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
1837 bFound = true;
1838 if ( !aType.isEmpty() )
1839 break;
1841 else if ( rAny.Name == "MediaType" )
1843 if ( ( rAny.Value >>= aType ) && !aType.isEmpty() && bFound )
1844 break;
1848 if ( bFound )
1849 return aType;
1852 return OUString();
1855 void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1857 OUString aPath( rPath );
1858 if ( !m_bIsRoot )
1859 aPath += m_aName;
1860 aPath += "/";
1862 m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
1864 if ( m_bIsRoot )
1865 // the "FullPath" of a child always starts without '/'
1866 aPath.clear();
1868 for (auto& pElement : m_aChildrenList)
1870 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1871 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1872 pElement->m_xStorage->SetProps( rSequence, aPath );
1873 else
1875 OUString aElementPath( aPath );
1876 aElementPath += pElement->m_aName;
1877 pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
1881 if ( !m_aContentType.isEmpty() )
1883 // get the clipboard format using the content type
1884 css::datatransfer::DataFlavor aDataFlavor;
1885 aDataFlavor.MimeType = m_aContentType;
1886 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1888 // get the ClassId using the clipboard format ( internal table )
1889 m_aClassId = GetClassId_Impl( m_nFormat );
1891 // get human presentable name using the clipboard format
1892 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1893 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1897 void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1899 // first my own properties
1900 Sequence < PropertyValue > aProps(2);
1902 // first property is the "FullPath" name
1903 // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
1904 OUString aPath( rPath );
1905 if ( !m_bIsRoot )
1906 aPath += m_aName;
1907 aPath += "/";
1908 aProps[0].Name = "MediaType";
1909 aProps[0].Value <<= m_aContentType;
1910 aProps[1].Name = "FullPath";
1911 aProps[1].Value <<= aPath;
1912 rSequence[ nProps++ ] = aProps;
1914 if ( m_bIsRoot )
1915 // the "FullPath" of a child always starts without '/'
1916 aPath.clear();
1918 // now the properties of my elements
1919 for (auto& pElement : m_aChildrenList)
1921 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1922 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1923 // storages add there properties by themselves ( see above )
1924 pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
1925 else
1927 // properties of streams
1928 OUString aElementPath( aPath );
1929 aElementPath += pElement->m_aName;
1930 aProps[0].Name = "MediaType";
1931 aProps[0].Value <<= pElement->GetContentType();
1932 aProps[1].Name = "FullPath";
1933 aProps[1].Value <<= aElementPath;
1934 rSequence[ nProps++ ] = aProps;
1939 UCBStorage_Impl::~UCBStorage_Impl()
1941 m_aChildrenList.clear();
1943 delete m_pContent;
1944 delete m_pTempFile;
1947 bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
1949 // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
1950 // it must be inserted with a title and a type
1951 bool bRet = false;
1955 Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
1956 sal_Int32 nCount = aInfo.getLength();
1957 if ( nCount == 0 )
1958 return false;
1960 for ( sal_Int32 i = 0; i < nCount; ++i )
1962 // Simply look for the first KIND_FOLDER...
1963 const ContentInfo & rCurr = aInfo[i];
1964 if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
1966 // Make sure the only required bootstrap property is "Title",
1967 const Sequence< Property > & rProps = rCurr.Properties;
1968 if ( rProps.getLength() != 1 )
1969 continue;
1971 if ( rProps[ 0 ].Name != "Title" )
1972 continue;
1974 Sequence < OUString > aNames { "Title" };
1975 Sequence < Any > aValues(1);
1976 aValues[0] <<= m_aName;
1978 Content aNewFolder;
1979 if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
1980 continue;
1982 // remove old content, create an "empty" new one and initialize it with the new inserted
1983 DELETEZ( m_pContent );
1984 m_pContent = new ::ucbhelper::Content( aNewFolder );
1985 bRet = true;
1989 catch (const CommandAbortedException&)
1991 // any command wasn't executed successfully - not specified
1992 SetError( ERRCODE_IO_GENERAL );
1994 catch (const RuntimeException&)
1996 // any other error - not specified
1997 SetError( ERRCODE_IO_GENERAL );
1999 catch (const Exception&)
2001 // any other error - not specified
2002 SetError( ERRCODE_IO_GENERAL );
2005 return bRet;
2008 sal_Int16 UCBStorage_Impl::Commit()
2010 // send all changes to the package
2011 sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO;
2013 // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
2014 // commit command has been sent
2015 if ( ( m_nMode & StreamMode::WRITE ) && ( m_bCommited || m_bDirect ) )
2019 // all errors will be caught in the "catch" statement outside the loop
2020 for ( size_t i = 0; i < m_aChildrenList.size() && nRet; ++i )
2022 auto& pElement = m_aChildrenList[ i ];
2023 ::ucbhelper::Content* pContent = pElement->GetContent();
2024 std::unique_ptr< ::ucbhelper::Content > xDeleteContent;
2025 if ( !pContent && pElement->IsModified() )
2027 // if the element has never been opened, no content has been created until now
2028 OUString aName( m_aURL );
2029 aName += "/";
2030 aName += pElement->m_aOriginalName;
2031 pContent = new ::ucbhelper::Content( aName, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2032 xDeleteContent.reset(pContent); // delete it later on exit scope
2035 if ( pElement->m_bIsRemoved )
2037 // was it inserted, then removed (so there would be nothing to do!)
2038 if ( !pElement->m_bIsInserted )
2040 // first remove all open stream handles
2041 if (pContent && (!pElement->m_xStream.is() || pElement->m_xStream->Clear()))
2043 pContent->executeCommand( "delete", makeAny( true ) );
2044 nRet = COMMIT_RESULT_SUCCESS;
2046 else
2047 // couldn't release stream because there are external references to it
2048 nRet = COMMIT_RESULT_FAILURE;
2051 else
2053 sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO;
2054 if ( pElement->m_xStorage.is() )
2056 // element is a storage
2057 // do a commit in the following cases:
2058 // - if storage is already inserted, and changed
2059 // - storage is not in a package
2060 // - it's a new storage, try to insert and commit if successful inserted
2061 if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent ) )
2063 nLocalRet = pElement->m_xStorage->Commit();
2064 pContent = pElement->GetContent();
2067 else if ( pElement->m_xStream.is() )
2069 // element is a stream
2070 nLocalRet = pElement->m_xStream->Commit();
2071 if ( pElement->m_xStream->m_bIsOLEStorage )
2073 // OLE storage should be stored encrypted, if the storage uses encryption
2074 pElement->m_xStream->m_aContentType = "application/vnd.sun.star.oleobject";
2075 Any aValue;
2076 aValue <<= true;
2077 pElement->m_xStream->m_pContent->setPropertyValue("Encrypted", aValue );
2080 pContent = pElement->GetContent();
2083 if (pContent && pElement->m_aName != pElement->m_aOriginalName)
2085 // name ( title ) of the element was changed
2086 nLocalRet = COMMIT_RESULT_SUCCESS;
2087 pContent->setPropertyValue("Title", Any(pElement->m_aName) );
2090 if (pContent && pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType())
2092 // mediatype of the element was changed
2093 nLocalRet = COMMIT_RESULT_SUCCESS;
2094 pContent->setPropertyValue("MediaType", Any(pElement->GetContentType()) );
2097 if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO )
2098 nRet = nLocalRet;
2101 if ( nRet == COMMIT_RESULT_FAILURE )
2102 break;
2105 catch (const ContentCreationException&)
2107 // content could not be created
2108 SetError( ERRCODE_IO_NOTEXISTS );
2109 return COMMIT_RESULT_FAILURE;
2111 catch (const CommandAbortedException&)
2113 // any command wasn't executed successfully - not specified
2114 SetError( ERRCODE_IO_GENERAL );
2115 return COMMIT_RESULT_FAILURE;
2117 catch (const RuntimeException&)
2119 // any other error - not specified
2120 SetError( ERRCODE_IO_GENERAL );
2121 return COMMIT_RESULT_FAILURE;
2123 catch (const Exception&)
2125 // any other error - not specified
2126 SetError( ERRCODE_IO_GENERAL );
2127 return COMMIT_RESULT_FAILURE;
2130 if ( m_bIsRoot && m_pContent )
2132 // the root storage must flush the root package content
2133 if ( nRet == COMMIT_RESULT_SUCCESS )
2137 // commit the media type to the JAR file
2138 // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2139 Any aType;
2140 aType <<= m_aContentType;
2141 m_pContent->setPropertyValue("MediaType", aType );
2143 if ( m_bIsLinked )
2145 // write a manifest file
2146 // first create a subfolder "META-inf"
2147 Content aNewSubFolder;
2148 bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, "META-INF", aNewSubFolder );
2149 if ( bRet )
2151 // create a stream to write the manifest file - use a temp file
2152 OUString aURL( aNewSubFolder.getURL() );
2153 std::unique_ptr< ::utl::TempFile> pTempFile(new ::utl::TempFile( &aURL ));
2155 // get the stream from the temp file and create an output stream wrapper
2156 SvStream* pStream = pTempFile->GetStream( StreamMode::STD_READWRITE );
2157 ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream );
2158 css::uno::Reference < css::io::XOutputStream > xOutputStream( pHelper );
2160 // create a manifest writer object that will fill the stream
2161 Reference < css::packages::manifest::XManifestWriter > xWriter =
2162 css::packages::manifest::ManifestWriter::create(
2163 ::comphelper::getProcessComponentContext() );
2164 sal_Int32 nCount = GetObjectCount() + 1;
2165 Sequence < Sequence < PropertyValue > > aProps( nCount );
2166 sal_Int32 nProps = 0;
2167 GetProps( nProps, aProps, OUString() );
2168 xWriter->writeManifestSequence( xOutputStream, aProps );
2170 // move the stream to its desired location
2171 Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2172 xWriter = nullptr;
2173 xOutputStream = nullptr;
2174 pTempFile.reset();
2175 aNewSubFolder.transferContent( aSource, InsertOperation::Move, "manifest.xml", NameClash::OVERWRITE );
2178 else
2180 #if OSL_DEBUG_LEVEL > 0
2181 SAL_INFO("sot", "Files: " << nOpenFiles);
2182 SAL_INFO("sot", "Streams: " << nOpenStreams);
2183 #endif
2184 // force writing
2185 Any aAny;
2186 m_pContent->executeCommand( "flush", aAny );
2187 if ( m_pSource != nullptr )
2189 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READ ));
2190 m_pSource->SetStreamSize(0);
2191 // m_pSource->Seek(0);
2192 pStream->ReadStream( *m_pSource );
2193 pStream.reset();
2194 m_pSource->Seek(0);
2198 catch (const CommandAbortedException&)
2200 // how to tell the content : forget all changes ?!
2201 // or should we assume that the content does it by itself because he threw an exception ?!
2202 // any command wasn't executed successfully - not specified
2203 SetError( ERRCODE_IO_GENERAL );
2204 return COMMIT_RESULT_FAILURE;
2206 catch (const RuntimeException&)
2208 // how to tell the content : forget all changes ?!
2209 // or should we assume that the content does it by itself because he threw an exception ?!
2210 // any other error - not specified
2211 SetError( ERRCODE_IO_GENERAL );
2212 return COMMIT_RESULT_FAILURE;
2214 catch (const InteractiveIOException& r)
2216 if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2217 SetError( ERRCODE_IO_ACCESSDENIED );
2218 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2219 SetError( ERRCODE_IO_NOTEXISTS );
2220 else if ( r.Code == IOErrorCode_CANT_READ )
2221 SetError( ERRCODE_IO_CANTREAD );
2222 else if ( r.Code == IOErrorCode_CANT_WRITE )
2223 SetError( ERRCODE_IO_CANTWRITE );
2224 else
2225 SetError( ERRCODE_IO_GENERAL );
2227 return COMMIT_RESULT_FAILURE;
2229 catch (const Exception&)
2231 // how to tell the content : forget all changes ?!
2232 // or should we assume that the content does it by itself because he threw an exception ?!
2233 // any other error - not specified
2234 SetError( ERRCODE_IO_GENERAL );
2235 return COMMIT_RESULT_FAILURE;
2238 else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO )
2240 // how to tell the content : forget all changes ?! Should we ?!
2241 SetError( ERRCODE_IO_GENERAL );
2242 return nRet;
2245 // after successful root commit all elements names and types are adjusted and all removed elements
2246 // are also removed from the lists
2247 for ( size_t i = 0; i < m_aChildrenList.size(); )
2249 auto& pInnerElement = m_aChildrenList[ i ];
2250 if ( pInnerElement->m_bIsRemoved )
2251 m_aChildrenList.erase( m_aChildrenList.begin() + i );
2252 else
2254 pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2255 pInnerElement->m_bIsInserted = false;
2256 ++i;
2261 m_bCommited = false;
2264 return nRet;
2267 void UCBStorage_Impl::Revert()
2269 for ( size_t i = 0; i < m_aChildrenList.size(); )
2271 auto& pElement = m_aChildrenList[ i ];
2272 pElement->m_bIsRemoved = false;
2273 if ( pElement->m_bIsInserted )
2274 m_aChildrenList.erase( m_aChildrenList.begin() + i );
2275 else
2277 if ( pElement->m_xStream.is() )
2279 pElement->m_xStream->m_bCommited = false;
2280 pElement->m_xStream->Revert();
2282 else if ( pElement->m_xStorage.is() )
2284 pElement->m_xStorage->m_bCommited = false;
2285 pElement->m_xStorage->Revert();
2288 pElement->m_aName = pElement->m_aOriginalName;
2289 pElement->m_bIsRemoved = false;
2290 ++i;
2295 const OUString& UCBStorage::GetName() const
2297 return pImp->m_aName; // pImp->m_aURL ?!
2300 bool UCBStorage::IsRoot() const
2302 return pImp->m_bIsRoot;
2305 void UCBStorage::SetDirty()
2309 void UCBStorage::SetClass( const SvGlobalName & rClass, SotClipboardFormatId nOriginalClipFormat, const OUString & rUserTypeName )
2311 pImp->m_aClassId = rClass;
2312 pImp->m_nFormat = nOriginalClipFormat;
2313 pImp->m_aUserTypeName = rUserTypeName;
2315 // in UCB storages only the content type will be stored, all other information can be reconstructed
2316 // ( see the UCBStorage_Impl::Init() method )
2317 css::datatransfer::DataFlavor aDataFlavor;
2318 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2319 pImp->m_aContentType = aDataFlavor.MimeType;
2322 void UCBStorage::SetClassId( const ClsId& rClsId )
2324 pImp->m_aClassId = SvGlobalName( rClsId );
2325 if ( pImp->m_aClassId == SvGlobalName() )
2326 return;
2328 // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are
2329 // stored in one the substreams
2330 // UCB storages store the content type information as content type in the manifest file and so this information must be
2331 // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2332 // the content type
2333 pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
2334 if ( pImp->m_nFormat != SotClipboardFormatId::NONE )
2336 css::datatransfer::DataFlavor aDataFlavor;
2337 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2338 pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2339 pImp->m_aContentType = aDataFlavor.MimeType;
2343 const ClsId& UCBStorage::GetClassId() const
2345 return pImp->m_aClassId.GetCLSID();
2348 SvGlobalName UCBStorage::GetClassName()
2350 return pImp->m_aClassId;
2353 SotClipboardFormatId UCBStorage::GetFormat()
2355 return pImp->m_nFormat;
2358 OUString UCBStorage::GetUserName()
2360 OSL_FAIL("UserName is not implemented in UCB storages!" );
2361 return pImp->m_aUserTypeName;
2364 void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
2366 // put information in childrenlist into StorageInfoList
2367 for (auto& pElement : pImp->GetChildrenList())
2369 if ( !pElement->m_bIsRemoved )
2371 // problem: what about the size of a substorage ?!
2372 sal_uLong nSize = pElement->m_nSize;
2373 if ( pElement->m_xStream.is() )
2374 nSize = pElement->m_xStream->GetSize();
2375 SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2376 pList->push_back( aInfo );
2381 bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl const & rElement, BaseStorage* pDest, const OUString& rNew ) const
2383 // insert stream or storage into the list or stream of the destination storage
2384 // not into the content, this will be done on commit !
2385 // be aware of name changes !
2386 if ( !rElement.m_bIsStorage )
2388 // copy the streams data
2389 // the destination stream must not be open
2390 tools::SvRef<BaseStorageStream> pOtherStream(pDest->OpenStream( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2391 BaseStorageStream* pStream = nullptr;
2392 bool bDeleteStream = false;
2394 // if stream is already open, it is allowed to copy it, so be aware of this
2395 if ( rElement.m_xStream.is() )
2396 pStream = rElement.m_xStream->m_pAntiImpl;
2397 if ( !pStream )
2399 pStream = const_cast< UCBStorage* >(this)->OpenStream( rElement.m_aName, StreamMode::STD_READ, pImp->m_bDirect );
2400 bDeleteStream = true;
2403 pStream->CopyTo( pOtherStream.get() );
2404 SetError( pStream->GetError() );
2405 if( pOtherStream->GetError() )
2406 pDest->SetError( pOtherStream->GetError() );
2407 else
2408 pOtherStream->Commit();
2410 if ( bDeleteStream )
2411 delete pStream;
2413 else
2415 // copy the storage content
2416 // the destination storage must not be open
2417 BaseStorage* pStorage = nullptr;
2419 // if stream is already open, it is allowed to copy it, so be aware of this
2420 bool bDeleteStorage = false;
2421 if ( rElement.m_xStorage.is() )
2422 pStorage = rElement.m_xStorage->m_pAntiImpl;
2423 if ( !pStorage )
2425 pStorage = const_cast<UCBStorage*>(this)->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2426 bDeleteStorage = true;
2429 UCBStorage* pUCBDest = dynamic_cast<UCBStorage*>( pDest );
2430 UCBStorage* pUCBCopy = dynamic_cast<UCBStorage*>( pStorage );
2432 bool bOpenUCBStorage = pUCBDest && pUCBCopy;
2433 tools::SvRef<BaseStorage> pOtherStorage(bOpenUCBStorage ?
2434 pDest->OpenUCBStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ) :
2435 pDest->OpenOLEStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2437 // For UCB storages, the class id and the format id may differ,
2438 // do passing the class id is not sufficient.
2439 if( bOpenUCBStorage )
2440 pOtherStorage->SetClass( pStorage->GetClassName(),
2441 pStorage->GetFormat(),
2442 pUCBCopy->pImp->m_aUserTypeName );
2443 else
2444 pOtherStorage->SetClassId( pStorage->GetClassId() );
2445 pStorage->CopyTo( pOtherStorage.get() );
2446 SetError( pStorage->GetError() );
2447 if( pOtherStorage->GetError() )
2448 pDest->SetError( pOtherStorage->GetError() );
2449 else
2450 pOtherStorage->Commit();
2452 if ( bDeleteStorage )
2453 delete pStorage;
2456 return Good() && pDest->Good();
2459 UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const OUString& rName ) const
2461 DBG_ASSERT( !rName.isEmpty(), "Name is empty!" );
2462 for (auto& pElement : pImp->GetChildrenList())
2464 if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2465 return pElement.get();
2467 return nullptr;
2470 bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2472 DBG_ASSERT( pDestStg != static_cast<BaseStorage const *>(this), "Self-Copying is not possible!" );
2473 if ( pDestStg == static_cast<BaseStorage const *>(this) )
2474 return false;
2476 // perhaps it's also a problem if one storage is a parent of the other ?!
2477 // or if not: could be optimized ?!
2479 // For UCB storages, the class id and the format id may differ,
2480 // do passing the class id is not sufficient.
2481 if( dynamic_cast<const UCBStorage *>(pDestStg) != nullptr )
2482 pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
2483 pImp->m_aUserTypeName );
2484 else
2485 pDestStg->SetClassId( GetClassId() );
2486 pDestStg->SetDirty();
2488 bool bRet = true;
2489 for ( size_t i = 0; i < pImp->GetChildrenList().size() && bRet; ++i )
2491 auto& pElement = pImp->GetChildrenList()[ i ];
2492 if ( !pElement->m_bIsRemoved )
2493 bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
2496 if( !bRet )
2497 SetError( pDestStg->GetError() );
2498 return Good() && pDestStg->Good();
2501 bool UCBStorage::CopyTo( const OUString& rElemName, BaseStorage* pDest, const OUString& rNew )
2503 if( rElemName.isEmpty() )
2504 return false;
2506 if ( pDest == static_cast<BaseStorage*>(this) )
2508 // can't double an element
2509 return false;
2511 else
2513 // for copying no optimization is useful, because in every case the stream data must be copied
2514 UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2515 if ( pElement )
2516 return CopyStorageElement_Impl( *pElement, pDest, rNew );
2517 else
2519 SetError( SVSTREAM_FILE_NOT_FOUND );
2520 return false;
2525 bool UCBStorage::Commit()
2527 // mark this storage for sending it on root commit
2528 pImp->m_bCommited = true;
2529 if ( pImp->m_bIsRoot )
2530 // the root storage coordinates committing by sending a Commit command to its content
2531 return ( pImp->Commit() != COMMIT_RESULT_FAILURE );
2532 else
2533 return true;
2536 bool UCBStorage::Revert()
2538 pImp->Revert();
2539 return true;
2542 BaseStorageStream* UCBStorage::OpenStream( const OUString& rEleName, StreamMode nMode, bool bDirect )
2544 if( rEleName.isEmpty() )
2545 return nullptr;
2547 // try to find the storage element
2548 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2549 if ( !pElement )
2551 // element does not exist, check if creation is allowed
2552 if( nMode & StreamMode::NOCREATE )
2554 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2555 OUString aName( pImp->m_aURL );
2556 aName += "/";
2557 aName += rEleName;
2558 UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2559 pStream->SetError( GetError() );
2560 pStream->pImp->m_aName = rEleName;
2561 return pStream;
2563 else
2565 // create a new UCBStorageElement and insert it into the list
2566 pElement = new UCBStorageElement_Impl( rEleName );
2567 pElement->m_bIsInserted = true;
2568 pImp->m_aChildrenList.emplace_back( pElement );
2572 if ( !pElement->m_bIsFolder )
2574 // check if stream is already created
2575 if ( pElement->m_xStream.is() )
2577 // stream has already been created; if it has no external reference, it may be opened another time
2578 if ( pElement->m_xStream->m_pAntiImpl )
2580 OSL_FAIL("Stream is already open!" );
2581 SetError( SVSTREAM_ACCESS_DENIED ); // ???
2582 return nullptr;
2584 else
2586 // check if stream is opened with the same keyword as before
2587 // if not, generate a new stream because it could be encrypted vs. decrypted!
2588 if ( pElement->m_xStream->m_aKey.isEmpty() )
2590 pElement->m_xStream->PrepareCachedForReopen( nMode );
2592 return new UCBStorageStream( pElement->m_xStream.get() );
2597 // stream is opened the first time
2598 pImp->OpenStream( pElement, nMode, bDirect );
2600 // if name has been changed before creating the stream: set name!
2601 pElement->m_xStream->m_aName = rEleName;
2602 return new UCBStorageStream( pElement->m_xStream.get() );
2605 return nullptr;
2608 void UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2610 OUString aName( m_aURL );
2611 aName += "/";
2612 aName += pElement->m_aOriginalName;
2613 pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, nullptr, bDirect, m_bRepairPackage, m_xProgressHandler );
2616 BaseStorage* UCBStorage::OpenUCBStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2618 if( rEleName.isEmpty() )
2619 return nullptr;
2621 return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2624 BaseStorage* UCBStorage::OpenOLEStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2626 if( rEleName.isEmpty() )
2627 return nullptr;
2629 return OpenStorage_Impl( rEleName, nMode, bDirect, false );
2632 BaseStorage* UCBStorage::OpenStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2634 if( rEleName.isEmpty() )
2635 return nullptr;
2637 return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2640 BaseStorage* UCBStorage::OpenStorage_Impl( const OUString& rEleName, StreamMode nMode, bool bDirect, bool bForceUCBStorage )
2642 // try to find the storage element
2643 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2644 if ( !pElement )
2646 // element does not exist, check if creation is allowed
2647 if( nMode & StreamMode::NOCREATE )
2649 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2650 OUString aName( pImp->m_aURL );
2651 aName += "/";
2652 aName += rEleName; // ???
2653 UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2654 pStorage->pImp->m_bIsRoot = false;
2655 pStorage->pImp->m_bListCreated = true; // the storage is pretty new, nothing to read
2656 pStorage->SetError( GetError() );
2657 return pStorage;
2660 // create a new UCBStorageElement and insert it into the list
2661 // problem: perhaps an OLEStorage should be created ?!
2662 // Because nothing is known about the element that should be created, an external parameter is needed !
2663 pElement = new UCBStorageElement_Impl( rEleName );
2664 pElement->m_bIsInserted = true;
2665 pImp->m_aChildrenList.emplace_back( pElement );
2668 if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
2670 // create OLE storages on a stream ( see ctor of SotStorage )
2671 // Such a storage will be created on a UCBStorageStream; it will write into the stream
2672 // if it is opened in direct mode or when it is committed. In this case the stream will be
2673 // modified and then it MUST be treated as committed.
2674 if ( !pElement->m_xStream.is() )
2676 BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
2677 UCBStorageStream* pStream = dynamic_cast<UCBStorageStream*>( pStr );
2678 if ( !pStream )
2680 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2681 return nullptr;
2684 pElement->m_xStream = pStream->pImp;
2685 delete pStream;
2688 pElement->m_xStream->PrepareCachedForReopen( nMode );
2689 bool bInited = pElement->m_xStream->Init();
2690 if (!bInited)
2692 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2693 return nullptr;
2696 pElement->m_bIsStorage = true;
2697 return pElement->m_xStream->CreateStorage(); // can only be created in transacted mode
2699 else if ( pElement->m_xStorage.is() )
2701 // storage has already been opened; if it has no external reference, it may be opened another time
2702 if ( pElement->m_xStorage->m_pAntiImpl )
2704 OSL_FAIL("Storage is already open!" );
2705 SetError( SVSTREAM_ACCESS_DENIED ); // ???
2707 else
2709 bool bIsWritable = bool( pElement->m_xStorage->m_nMode & StreamMode::WRITE );
2710 if ( !bIsWritable && ( nMode & StreamMode::WRITE ) )
2712 OUString aName( pImp->m_aURL );
2713 aName += "/";
2714 aName += pElement->m_aOriginalName;
2715 UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2716 pElement->m_xStorage = pStorage->pImp;
2717 return pStorage;
2719 else
2721 return new UCBStorage( pElement->m_xStorage.get() );
2725 else if ( !pElement->m_xStream.is() )
2727 // storage is opened the first time
2728 bool bIsWritable = bool(pImp->m_nMode & StreamMode::WRITE);
2729 if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
2731 // make sure that the root storage object has been created before substorages will be created
2732 INetURLObject aFolderObj( pImp->m_aURL );
2733 aFolderObj.removeSegment();
2735 Content aFolder( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2736 pImp->m_pContent = new Content;
2737 bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent );
2738 if ( !bRet )
2740 SetError( SVSTREAM_CANNOT_MAKE );
2741 return nullptr;
2745 UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
2746 if ( pStor )
2748 if ( pElement->m_bIsInserted )
2749 pStor->m_bListCreated = true; // the storage is pretty new, nothing to read
2751 return new UCBStorage( pStor );
2755 return nullptr;
2758 UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2760 UCBStorage_Impl* pRet = nullptr;
2761 OUString aName( m_aURL );
2762 aName += "/";
2763 aName += pElement->m_aOriginalName; // ???
2765 pElement->m_bIsStorage = pElement->m_bIsFolder = true;
2767 if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
2769 Content aNewFolder;
2770 bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
2771 if ( bRet )
2772 pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2774 else
2776 pRet = new UCBStorage_Impl( aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2779 if ( pRet )
2781 pRet->m_bIsLinked = m_bIsLinked;
2782 pRet->m_bIsRoot = false;
2784 // if name has been changed before creating the stream: set name!
2785 pRet->m_aName = pElement->m_aOriginalName;
2786 pElement->m_xStorage = pRet;
2789 if ( pRet )
2790 pRet->Init();
2792 return pRet;
2795 bool UCBStorage::IsStorage( const OUString& rEleName ) const
2797 if( rEleName.isEmpty() )
2798 return false;
2800 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2801 return ( pElement && pElement->m_bIsStorage );
2804 bool UCBStorage::IsStream( const OUString& rEleName ) const
2806 if( rEleName.isEmpty() )
2807 return false;
2809 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2810 return ( pElement && !pElement->m_bIsStorage );
2813 bool UCBStorage::IsContained( const OUString & rEleName ) const
2815 if( rEleName.isEmpty() )
2816 return false;
2817 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2818 return ( pElement != nullptr );
2821 void UCBStorage::Remove( const OUString& rEleName )
2823 if( rEleName.isEmpty() )
2824 return;
2826 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2827 if ( pElement )
2829 pElement->m_bIsRemoved = true;
2831 else
2832 SetError( SVSTREAM_FILE_NOT_FOUND );
2835 bool UCBStorage::ValidateFAT()
2837 // ???
2838 return true;
2841 bool UCBStorage::Validate( bool bWrite ) const
2843 // ???
2844 return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
2847 bool UCBStorage::ValidateMode( StreamMode m ) const
2849 // ???
2850 if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx
2851 return true;
2852 // only SHARE_DENYALL allowed
2853 // storages open in r/o mode are OK, since only
2854 // the commit may fail
2855 if( m & StreamMode::SHARE_DENYALL )
2856 return true;
2858 return true;
2861 bool UCBStorage::Equals( const BaseStorage& rStorage ) const
2863 // ???
2864 return static_cast<BaseStorage const *>(this) == &rStorage;
2867 bool UCBStorage::IsStorageFile( SvStream* pFile )
2869 if ( !pFile )
2870 return false;
2872 sal_uInt64 nPos = pFile->Tell();
2873 if ( pFile->TellEnd() < 4 )
2874 return false;
2876 pFile->Seek(0);
2877 sal_uInt32 nBytes(0);
2878 pFile->ReadUInt32( nBytes );
2880 // search for the magic bytes
2881 bool bRet = ( nBytes == 0x04034b50 );
2882 if ( !bRet )
2884 // disk spanned file have an additional header in front of the usual one
2885 bRet = ( nBytes == 0x08074b50 );
2886 if ( bRet )
2888 nBytes = 0;
2889 pFile->ReadUInt32( nBytes );
2890 bRet = ( nBytes == 0x04034b50 );
2894 pFile->Seek( nPos );
2895 return bRet;
2898 OUString UCBStorage::GetLinkedFile( SvStream &rStream )
2900 OUString aString;
2901 sal_uInt64 nPos = rStream.Tell();
2902 if ( !rStream.TellEnd() )
2903 return aString;
2905 rStream.Seek(0);
2906 sal_uInt32 nBytes;
2907 rStream.ReadUInt32( nBytes );
2908 if( nBytes == 0x04034b50 )
2910 OString aTmp = read_uInt16_lenPrefixed_uInt8s_ToOString(rStream);
2911 if (aTmp.match("ContentURL="))
2913 aString = OStringToOUString(aTmp.copy(11), RTL_TEXTENCODING_UTF8);
2917 rStream.Seek( nPos );
2918 return aString;
2921 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */