LibreOffice Module sot (master) 1
ucbstorage.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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 <ucbhelper/content.hxx>
24#include <com/sun/star/uno/Reference.h>
25#include <com/sun/star/ucb/NameClash.hpp>
26#include <unotools/tempfile.hxx>
28#include <com/sun/star/io/XInputStream.hpp>
29#include <com/sun/star/ucb/InsertCommandArgument.hpp>
30#include <com/sun/star/ucb/ResultSetException.hpp>
31#include <com/sun/star/uno/Sequence.h>
32#include <com/sun/star/sdbc/XResultSet.hpp>
33#include <com/sun/star/sdbc/XRow.hpp>
34#include <com/sun/star/ucb/CommandAbortedException.hpp>
35#include <com/sun/star/datatransfer/DataFlavor.hpp>
36#include <com/sun/star/ucb/ContentInfo.hpp>
37#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
38#include <com/sun/star/beans/Property.hpp>
39#include <com/sun/star/packages/manifest/ManifestWriter.hpp>
40#include <com/sun/star/packages/manifest/ManifestReader.hpp>
41#include <com/sun/star/ucb/InteractiveIOException.hpp>
42#include <com/sun/star/ucb/ContentCreationException.hpp>
43
44#include <memory>
45#include <optional>
46#include <o3tl/safeint.hxx>
47#include <osl/diagnose.h>
48#include <osl/file.hxx>
49#include <sal/log.hxx>
51#include <tools/ref.hxx>
52#include <tools/debug.hxx>
55#include <tools/urlobj.hxx>
60
61#include <sot/stg.hxx>
62#include <sot/storinfo.hxx>
63#include <sot/exchange.hxx>
64#include <sot/formats.hxx>
66
67#include <mutex>
68#include <utility>
69#include <vector>
70
71namespace com::sun::star::ucb { class XCommandEnvironment; }
72
73using namespace ::com::sun::star::lang;
74using namespace ::com::sun::star::beans;
75using namespace ::com::sun::star::uno;
76using namespace ::com::sun::star::ucb;
77using namespace ::com::sun::star::io;
78using namespace ::com::sun::star::sdbc;
79using namespace ::ucbhelper;
80
81#if OSL_DEBUG_LEVEL > 0
82static int nOpenFiles=0;
83static int nOpenStreams=0;
84#endif
85
86typedef ::cppu::WeakImplHelper < XInputStream, XSeekable > FileInputStreamWrapper_Base;
87
88namespace {
89
90class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
91{
92protected:
93 std::mutex m_aMutex;
94 OUString m_aURL;
95 std::unique_ptr<SvStream> m_pSvStream;
96
97public:
98 explicit FileStreamWrapper_Impl(OUString aName);
99 virtual ~FileStreamWrapper_Impl() override;
100
101 virtual void SAL_CALL seek( sal_Int64 _nLocation ) override;
102 virtual sal_Int64 SAL_CALL getPosition( ) override;
103 virtual sal_Int64 SAL_CALL getLength( ) override;
104 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override;
105 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
106 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
107 virtual sal_Int32 SAL_CALL available() override;
108 virtual void SAL_CALL closeInput() override;
109
110protected:
111 void checkConnected();
112 void checkError();
113};
114
115}
116
117FileStreamWrapper_Impl::FileStreamWrapper_Impl( OUString aName )
118 : m_aURL(std::move( aName ))
119{
120 // if no URL is provided the stream is empty
121}
122
123
124FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
125{
126 if ( m_pSvStream )
127 {
128 m_pSvStream.reset();
129#if OSL_DEBUG_LEVEL > 0
130 --nOpenFiles;
131#endif
132 }
133
134 if (!m_aURL.isEmpty())
135 osl::File::remove(m_aURL);
136}
137
138
139sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
140{
141 if ( m_aURL.isEmpty() )
142 {
143 aData.realloc( 0 );
144 return 0;
145 }
146
147 checkConnected();
148
149 if (nBytesToRead < 0)
150 throw BufferSizeExceededException(OUString(), getXWeak());
151
152 std::scoped_lock aGuard( m_aMutex );
153
154 if (aData.getLength() < nBytesToRead)
155 aData.realloc(nBytesToRead);
156
157 sal_uInt32 nRead = m_pSvStream->ReadBytes(static_cast<void*>(aData.getArray()), nBytesToRead);
158 checkError();
159
160 // if read characters < MaxLength, adjust sequence
161 if (nRead < o3tl::make_unsigned(aData.getLength()))
162 aData.realloc( nRead );
163
164 return nRead;
165}
166
167
168sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
169{
170 if ( m_aURL.isEmpty() )
171 {
172 aData.realloc( 0 );
173 return 0;
174 }
175
176 checkError();
177
178 if (nMaxBytesToRead < 0)
179 throw BufferSizeExceededException(OUString(), getXWeak());
180
181 if (m_pSvStream->eof())
182 {
183 aData.realloc(0);
184 return 0;
185 }
186 else
187 return readBytes(aData, nMaxBytesToRead);
188}
189
190
191void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip)
192{
193 if ( m_aURL.isEmpty() )
194 return;
195
196 std::scoped_lock aGuard( m_aMutex );
197 checkError();
198
199 m_pSvStream->SeekRel(nBytesToSkip);
200 checkError();
201}
202
203
204sal_Int32 SAL_CALL FileStreamWrapper_Impl::available()
205{
206 if ( m_aURL.isEmpty() )
207 return 0;
208
209 std::scoped_lock aGuard( m_aMutex );
210 checkConnected();
211
212 sal_Int64 nAvailable = m_pSvStream->remainingSize();
213 checkError();
214
215 return std::min<sal_Int64>(SAL_MAX_INT32, nAvailable);
216}
217
218
219void SAL_CALL FileStreamWrapper_Impl::closeInput()
220{
221 if ( m_aURL.isEmpty() )
222 return;
223
224 std::scoped_lock aGuard( m_aMutex );
225 checkConnected();
226 m_pSvStream.reset();
227#if OSL_DEBUG_LEVEL > 0
228 --nOpenFiles;
229#endif
230 osl::File::remove(m_aURL);
231 m_aURL.clear();
232}
233
234
235void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation )
236{
237 if ( m_aURL.isEmpty() )
238 return;
239
240 std::scoped_lock aGuard( m_aMutex );
241 checkConnected();
242
243 m_pSvStream->Seek(static_cast<sal_uInt32>(_nLocation));
244 checkError();
245}
246
247
248sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition( )
249{
250 if ( m_aURL.isEmpty() )
251 return 0;
252
253 std::scoped_lock aGuard( m_aMutex );
254 checkConnected();
255
256 sal_uInt32 nPos = m_pSvStream->Tell();
257 checkError();
258 return static_cast<sal_Int64>(nPos);
259}
260
261
262sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength( )
263{
264 if ( m_aURL.isEmpty() )
265 return 0;
266
267 std::scoped_lock aGuard( m_aMutex );
268 checkConnected();
269
270 checkError();
271
272 sal_Int64 nEndPos = m_pSvStream->TellEnd();
273
274 return nEndPos;
275}
276
277
278void FileStreamWrapper_Impl::checkConnected()
279{
280 if ( m_aURL.isEmpty() )
281 throw NotConnectedException(OUString(), getXWeak());
282 if ( !m_pSvStream )
283 {
284 m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, StreamMode::STD_READ );
285#if OSL_DEBUG_LEVEL > 0
286 ++nOpenFiles;
287#endif
288 }
289}
290
291
292void FileStreamWrapper_Impl::checkError()
293{
294 checkConnected();
295
296 if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
297 // TODO: really evaluate the error
298 throw NotConnectedException(OUString(), getXWeak());
299}
300
301
302#define COMMIT_RESULT_FAILURE 0
303#define COMMIT_RESULT_NOTHING_TO_DO 1
304#define COMMIT_RESULT_SUCCESS 2
305
307{
328 // allowed, but not supported
330 else
331 {
332 OSL_FAIL( "Unknown UCB storage format!" );
334 }
335}
336
337
339{
340 switch ( nFormat )
341 {
381 default :
382 return SvGlobalName();
383 }
384}
385
386// All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
387// class, that uses the refcounted object as impl-class.
388
390{
391 virtual ~UCBStorageStream_Impl() override;
392public:
393
394 virtual std::size_t GetData(void* pData, std::size_t nSize) override;
395 virtual std::size_t PutData(const void* pData, std::size_t nSize) override;
396 virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override;
397 virtual void SetSize( sal_uInt64 nSize ) override;
398 virtual void FlushData() override;
399 virtual void ResetError() override;
400
401 UCBStorageStream* m_pAntiImpl; // only valid if an external reference exists
402
403 OUString m_aOriginalName;// the original name before accessing the stream
404 OUString m_aName; // the actual name ( changed with a Rename command at the parent )
405 OUString m_aURL; // the full path name to create the content
408 OString m_aKey;
409 ::ucbhelper::Content* m_pContent; // the content that provides the data
410 Reference<XInputStream> m_rSource; // the stream covering the original data of the content
411 std::unique_ptr<SvStream> m_pStream; // the stream worked on; for readonly streams it is the original stream of the content
412 // for read/write streams it's a copy into a temporary file
413 OUString m_aTempURL; // URL of this temporary stream
415 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
416 bool m_bSourceRead; // Source still contains useful information
417 bool m_bModified; // only modified streams will be sent to the original content
418 bool m_bCommited; // sending the streams is coordinated by the root storage of the package
419 bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
420 // this means that the root storage does an autocommit when its external
421 // reference is destroyed
422 bool m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
423
424 UCBStorageStream_Impl( const OUString&, StreamMode, UCBStorageStream*, bool,
425 bool bRepair, Reference< XProgressHandler > const & xProgress );
426
427 void Free();
428 bool Init();
429 bool Clear();
430 sal_Int16 Commit(); // if modified and committed: transfer an XInputStream to the content
431 void Revert(); // discard all changes
432 BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream
433 sal_uInt64 GetSize();
434
435 sal_uInt64 ReadSourceWriteTemporary( sal_uInt64 aLength ); // read aLength from source and copy to temporary,
436 // no seeking is produced
437 void ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
438
439 void CopySourceToTemporary(); // same as ReadSourceWriteToTemporary()
440 // but the writing is done at the end of temporary
441 // pointer position is not changed
442 using SvStream::SetError;
443 void SetError( ErrCode nError );
445};
446
448
450typedef std::vector<std::unique_ptr<UCBStorageElement_Impl>> UCBStorageElementList_Impl;
451
453{
454 virtual ~UCBStorage_Impl() override;
455public:
456 UCBStorage* m_pAntiImpl; // only valid if external references exists
457
458 OUString m_aName; // the actual name ( changed with a Rename command at the parent )
459 OUString m_aURL; // the full path name to create the content
462 std::optional<::ucbhelper::Content> m_oContent; // the content that provides the storage elements
463 std::unique_ptr<::utl::TempFileNamed> m_pTempFile; // temporary file, only for storages on stream
464 SvStream* m_pSource; // original stream, only for storages on a stream
466 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
467 bool m_bCommited; // sending the streams is coordinated by the root storage of the package
468 bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
469 // this means that the root storage does an autocommit when its external
470 // reference is destroyed
471 bool m_bIsRoot; // marks this storage as root storages that manages all commits and reverts
477
479
481 Reference< XProgressHandler > m_xProgressHandler;
482
483 UCBStorage_Impl( const ::ucbhelper::Content&, const OUString&, StreamMode, UCBStorage*, bool,
484 bool, bool = false, Reference< XProgressHandler > const & = Reference< XProgressHandler >() );
485 UCBStorage_Impl( const OUString&, StreamMode, UCBStorage*, bool, bool,
486 bool, Reference< XProgressHandler > const & );
488 void Init();
489 sal_Int16 Commit();
490 void Revert();
491 bool Insert( ::ucbhelper::Content *pContent );
492 UCBStorage_Impl* OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect );
494 void SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
495 void GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
496 sal_Int32 GetObjectCount();
497 void ReadContent();
498 void CreateContent();
500 {
501 if ( !m_oContent )
503 return m_oContent ? &*m_oContent : nullptr;
504 }
506 {
507 const ErrCode nError = m_nError;
508 ReadContent();
509 if ( m_nMode & StreamMode::WRITE )
510 {
511 m_nError = nError;
512 if ( m_pAntiImpl )
513 {
515 m_pAntiImpl->SetError( nError );
516 }
517 }
518 return m_aChildrenList;
519 }
520
521 void SetError( ErrCode nError );
522};
523
525
526// this struct contains all necessary information on an element inside a UCBStorage
528{
529 OUString m_aName; // the actual URL relative to the root "folder"
530 OUString m_aOriginalName;// the original name in the content
531 sal_uInt64 m_nSize;
532 bool m_bIsFolder; // Only true when it is a UCBStorage !
533 bool m_bIsStorage; // Also true when it is an OLEStorage !
534 bool m_bIsRemoved; // element will be removed on commit
535 bool m_bIsInserted; // element will be removed on revert
536 UCBStorage_ImplRef m_xStorage; // reference to the "real" storage
537 UCBStorageStream_ImplRef m_xStream; // reference to the "real" stream
538
539 UCBStorageElement_Impl( const OUString& rName,
540 bool bIsFolder = false, sal_uInt64 nSize = 0 )
541 : m_aName( rName )
542 , m_aOriginalName( rName )
543 , m_nSize( nSize )
544 , m_bIsFolder( bIsFolder )
545 , m_bIsStorage( bIsFolder )
546 , m_bIsRemoved( false )
547 , m_bIsInserted( false )
548 {
549 }
550
552 bool IsModified() const;
553 OUString GetContentType() const;
554 void SetContentType( const OUString& );
555 OUString GetOriginalContentType() const;
556 bool IsLoaded() const
557 { return m_xStream.is() || m_xStorage.is(); }
558};
559
561{
562 if ( m_xStream.is() )
563 return m_xStream->m_pContent;
564 else if ( m_xStorage.is() )
565 return m_xStorage->GetContent();
566 else
567 return nullptr;
568}
569
571{
572 if ( m_xStream.is() )
573 return m_xStream->m_aContentType;
574 else if ( m_xStorage.is() )
575 return m_xStorage->m_aContentType;
576 else
577 {
578 OSL_FAIL("Element not loaded!");
579 return OUString();
580 }
581}
582
583void UCBStorageElement_Impl::SetContentType( const OUString& rType )
584{
585 if ( m_xStream.is() ) {
586 m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
587 }
588 else if ( m_xStorage.is() ) {
589 m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
590 }
591 else {
592 OSL_FAIL("Element not loaded!");
593 }
594}
595
597{
598 if ( m_xStream.is() )
599 return m_xStream->m_aOriginalContentType;
600 else if ( m_xStorage.is() )
601 return m_xStorage->m_aOriginalContentType;
602 else
603 return OUString();
604}
605
607{
608 bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
609 if ( bModified )
610 {
611 if ( m_xStream.is() )
612 bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
613 else if ( m_xStorage.is() )
614 bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
615 }
616
617 return bModified;
618}
619
620UCBStorageStream_Impl::UCBStorageStream_Impl( const OUString& rName, StreamMode nMode, UCBStorageStream* pStream, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
621 : m_pAntiImpl( pStream )
622 , m_aURL( rName )
623 , m_pContent( nullptr )
624 , m_nError( ERRCODE_NONE )
625 , m_nMode( nMode )
626 , m_bSourceRead( !( nMode & StreamMode::TRUNC ) )
627 , m_bModified( false )
628 , m_bCommited( false )
629 , m_bDirect( bDirect )
630 , m_bIsOLEStorage( false )
631{
632 // name is last segment in URL
633 INetURLObject aObj( rName );
635 try
636 {
637 // create the content
638 Reference< css::ucb::XCommandEnvironment > xComEnv;
639
640 OUString aTemp( rName );
641
642 if ( bRepair )
643 {
644 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(), xProgress );
645 aTemp += "?repairpackage";
646 }
647
648 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
649 }
650 catch (const ContentCreationException&)
651 {
652 // content could not be created
654 }
655 catch (const RuntimeException&)
656 {
657 // any other error - not specified
659 }
660}
661
663{
664 if( m_rSource.is() )
665 m_rSource.clear();
666
667 m_pStream.reset();
668
669 if (!m_aTempURL.isEmpty())
670 osl::File::remove(m_aTempURL);
671
672 delete m_pContent;
673}
674
675
677{
678 if( !m_pStream )
679 {
680 // no temporary stream was created
681 // create one
682
683 if ( m_aTempURL.isEmpty() )
684 m_aTempURL = ::utl::CreateTempURL();
685
686 m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, StreamMode::STD_READWRITE, true /* bFileExists */ );
687#if OSL_DEBUG_LEVEL > 0
688 ++nOpenFiles;
689#endif
690
691 if( !m_pStream )
692 {
693 OSL_FAIL( "Suspicious temporary stream creation!" );
695 return false;
696 }
697
698 SetError( m_pStream->GetError() );
699 }
700
701 if( m_bSourceRead && !m_rSource.is() )
702 {
703 // source file contain useful information and is not opened
704 // open it from the point of noncopied data
705
706 try
707 {
709 }
710 catch (const Exception&)
711 {
712 // usually means that stream could not be opened
713 }
714
715 if( m_rSource.is() )
716 {
718
719 try
720 {
721 m_rSource->skipBytes( m_pStream->Tell() );
722 }
723 catch (const BufferSizeExceededException&)
724 {
725 // the temporary stream already contain all the data
726 m_bSourceRead = false;
727 }
728 catch (const Exception&)
729 {
730 // something is really wrong
731 m_bSourceRead = false;
732 OSL_FAIL( "Can not operate original stream!" );
734 }
735
736 m_pStream->Seek( 0 );
737 }
738 else
739 {
740 // if the new file is edited then no source exist
741 m_bSourceRead = false;
742 //SetError( SVSTREAM_CANNOT_MAKE );
743 }
744 }
745
746 DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" );
747
748 return true;
749}
750
752{
753 // read source stream till the end and copy all the data to
754 // the current position of the temporary stream
755
756 if( m_bSourceRead )
757 {
758 Sequence<sal_Int8> aData(32000);
759
760 try
761 {
762 sal_Int32 aReaded;
763 do
764 {
765 aReaded = m_rSource->readBytes( aData, 32000 );
766 m_pStream->WriteBytes(aData.getConstArray(), aReaded);
767 } while( aReaded == 32000 );
768 }
769 catch (const Exception &)
770 {
771 TOOLS_WARN_EXCEPTION("sot", "");
772 }
773 }
774
775 m_bSourceRead = false;
776}
777
779{
780 // read aLength bite from the source stream and copy them to the current
781 // position of the temporary stream
782
783 sal_uInt64 aResult = 0;
784
785 if( m_bSourceRead )
786 {
787 Sequence<sal_Int8> aData(32000);
788
789 try
790 {
791
792 sal_Int32 aReaded = 32000;
793
794 for (sal_uInt64 nInd = 0; nInd < aLength && aReaded == 32000 ; nInd += 32000)
795 {
796 sal_Int32 aToCopy = std::min<sal_Int32>( aLength - nInd, 32000 );
797 aReaded = m_rSource->readBytes( aData, aToCopy );
798 aResult += m_pStream->WriteBytes(aData.getConstArray(), aReaded);
799 }
800
801 if( aResult < aLength )
802 m_bSourceRead = false;
803 }
804 catch( const Exception & )
805 {
806 TOOLS_WARN_EXCEPTION("sot", "");
807 }
808 }
809
810 return aResult;
811}
812
814{
815 // current position of the temporary stream is not changed
816 if( m_bSourceRead )
817 {
818 sal_uInt64 aPos = m_pStream->Tell();
821 m_pStream->Seek( aPos );
822 }
823}
824
825// UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
826// of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
827std::size_t UCBStorageStream_Impl::GetData(void* pData, std::size_t const nSize)
828{
829 std::size_t aResult = 0;
830
831 if( !Init() )
832 return 0;
833
834
835 // read data that is in temporary stream
836 aResult = m_pStream->ReadBytes( pData, nSize );
837 if( m_bSourceRead && aResult < nSize )
838 {
839 // read the tail of the data from original stream
840 // copy this tail to the temporary stream
841
842 std::size_t aToRead = nSize - aResult;
843 pData = static_cast<void*>( static_cast<char*>(pData) + aResult );
844
845 try
846 {
847 Sequence<sal_Int8> aData( aToRead );
848 std::size_t aReaded = m_rSource->readBytes( aData, aToRead );
849 aResult += m_pStream->WriteBytes(static_cast<const void*>(aData.getConstArray()), aReaded);
850 memcpy( pData, aData.getArray(), aReaded );
851 }
852 catch (const Exception &)
853 {
854 TOOLS_WARN_EXCEPTION("sot", "");
855 }
856
857 if( aResult < nSize )
858 m_bSourceRead = false;
859 }
860
861 return aResult;
862}
863
864std::size_t UCBStorageStream_Impl::PutData(const void* pData, std::size_t const nSize)
865{
866 if ( !(m_nMode & StreamMode::WRITE) )
867 {
869 return 0; // ?mav?
870 }
871
872 if( !nSize || !Init() )
873 return 0;
874
875 std::size_t aResult = m_pStream->WriteBytes( pData, nSize );
876
877 m_bModified = aResult > 0;
878
879 return aResult;
880
881}
882
883sal_uInt64 UCBStorageStream_Impl::SeekPos(sal_uInt64 const nPos)
884{
885 // check if a truncated STREAM_SEEK_TO_END was passed
886 assert(nPos != SAL_MAX_UINT32);
887
888 if( !Init() )
889 return 0;
890
891 sal_uInt64 aResult;
892
893 if( nPos == STREAM_SEEK_TO_END )
894 {
897 aResult = m_pStream->Tell();
898 }
899 else
900 {
901 // the problem is that even if nPos is larger the length
902 // of the stream, the stream pointer will be moved to this position
903 // so we have to check if temporary stream does not contain required position
904
905 if( m_pStream->Tell() > nPos
906 || m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos )
907 {
908 // no copying is required
909 aResult = m_pStream->Seek( nPos );
910 }
911 else
912 {
913 // the temp stream pointer points to the end now
914 aResult = m_pStream->Tell();
915
916 if( aResult < nPos )
917 {
918 if( m_bSourceRead )
919 {
920 aResult += ReadSourceWriteTemporary( nPos - aResult );
921 if( aResult < nPos )
922 m_bSourceRead = false;
923
924 DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" );
925 }
926
927 if( (m_nMode & StreamMode::WRITE) && !m_bSourceRead && aResult < nPos )
928 {
929 // it means that all the Source stream was copied already
930 // but the required position still was not reached
931 // for writable streams it should be done
932 m_pStream->SetStreamSize( nPos );
933 aResult = m_pStream->Seek( STREAM_SEEK_TO_END );
934 DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" );
935 }
936 }
937 }
938 }
939
940 return aResult;
941}
942
943void UCBStorageStream_Impl::SetSize(sal_uInt64 const nSize)
944{
945 if ( !(m_nMode & StreamMode::WRITE) )
946 {
948 return;
949 }
950
951 if( !Init() )
952 return;
953
954 m_bModified = true;
955
956 if( m_bSourceRead )
957 {
958 sal_uInt64 const aPos = m_pStream->Tell();
960 if( m_pStream->Tell() < nSize )
961 ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
962 m_pStream->Seek( aPos );
963 }
964
965 m_pStream->SetStreamSize( nSize );
966 m_bSourceRead = false;
967}
968
970{
971 if( m_pStream )
972 {
974 m_pStream->Flush();
975 }
976
977 m_bCommited = true;
978}
979
981{
982 if ( !m_nError )
983 {
984 m_nError = nErr;
985 SvStream::SetError( nErr );
986 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
987 }
988}
989
991{
994 if ( m_pAntiImpl )
996}
997
999{
1000 if( !Init() )
1001 return 0;
1002
1003 sal_uInt64 nPos = m_pStream->Tell();
1006 sal_uInt64 nRet = m_pStream->Tell();
1007 m_pStream->Seek( nPos );
1008
1009 return nRet;
1010}
1011
1013{
1014 // create an OLEStorage on a SvStream ( = this )
1015 // it gets the root attribute because otherwise it would probably not write before my root is committed
1016 UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
1017 Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
1018
1019 // GetError() call clears error code for OLE storages, must be changed in future
1020 const ErrCode nTmpErr = pStorage->GetError();
1021 pStorage->SetError( nTmpErr );
1022
1023 m_bIsOLEStorage = !nTmpErr;
1024 return static_cast< BaseStorage* > ( pStorage );
1025}
1026
1028{
1029 // send stream to the original content
1030 // the parent storage is responsible for the correct handling of deleted contents
1032 {
1033 // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1034 // was committed as well ( if not opened in direct mode )
1035
1036 if ( m_bModified )
1037 {
1038 try
1039 {
1041
1042 // release all stream handles
1043 Free();
1044
1045 // the temporary file does not exist only for truncated streams
1046 DBG_ASSERT( !m_aTempURL.isEmpty() || ( m_nMode & StreamMode::TRUNC ), "No temporary file to read from!");
1047 if ( m_aTempURL.isEmpty() && !( m_nMode & StreamMode::TRUNC ) )
1048 throw RuntimeException();
1049
1050 // create wrapper to stream that is only used while reading inside package component
1051 Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL );
1052
1053 InsertCommandArgument aArg;
1054 aArg.Data = xStream;
1055 aArg.ReplaceExisting = true;
1056 m_pContent->executeCommand( "insert", Any(aArg) );
1057
1058 // wrapper now controls lifetime of temporary file
1059 m_aTempURL.clear();
1060
1061 INetURLObject aObj( m_aURL );
1062 aObj.setName( m_aName );
1064 m_bModified = false;
1065 m_bSourceRead = true;
1066 }
1067 catch (const CommandAbortedException&)
1068 {
1069 // any command wasn't executed successfully - not specified
1071 return COMMIT_RESULT_FAILURE;
1072 }
1073 catch (const RuntimeException&)
1074 {
1075 // any other error - not specified
1077 return COMMIT_RESULT_FAILURE;
1078 }
1079 catch (const Exception&)
1080 {
1081 // any other error - not specified
1083 return COMMIT_RESULT_FAILURE;
1084 }
1085
1086 m_bCommited = false;
1087 return COMMIT_RESULT_SUCCESS;
1088 }
1089 }
1090
1092}
1093
1095{
1096 // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
1097 if ( m_bCommited )
1098 {
1099 OSL_FAIL("Revert while commit is in progress!" );
1100 return; // ???
1101 }
1102
1103 Free();
1104 if ( !m_aTempURL.isEmpty() )
1105 {
1106 osl::File::remove(m_aTempURL);
1107 m_aTempURL.clear();
1108 }
1109
1110 m_bSourceRead = false;
1111 try
1112 {
1114 if( m_rSource.is() )
1115 {
1116 if ( m_pAntiImpl && ( m_nMode & StreamMode::TRUNC ) )
1117 // stream is in use and should be truncated
1118 m_bSourceRead = false;
1119 else
1120 {
1121 m_nMode &= ~StreamMode::TRUNC;
1122 m_bSourceRead = true;
1123 }
1124 }
1125 else
1127 }
1128 catch (const ContentCreationException&)
1129 {
1131 }
1132 catch (const RuntimeException&)
1133 {
1135 }
1136 catch (const Exception&)
1137 {
1138 }
1139
1140 m_bModified = false;
1143}
1144
1146{
1147 bool bRet = ( m_pAntiImpl == nullptr );
1148 DBG_ASSERT( bRet, "Removing used stream!" );
1149 if( bRet )
1150 {
1151 Free();
1152 }
1153
1154 return bRet;
1155}
1156
1158{
1159#if OSL_DEBUG_LEVEL > 0
1160 if ( m_pStream )
1161 {
1162 if ( !m_aTempURL.isEmpty() )
1163 --nOpenFiles;
1164 else
1165 --nOpenStreams;
1166 }
1167#endif
1168
1169 m_rSource.clear();
1170 m_pStream.reset();
1171}
1172
1174{
1175 bool isWritable = bool( m_nMode & StreamMode::WRITE );
1176 if ( isWritable )
1177 {
1178 // once stream was writable, never reset to readonly
1179 nMode |= StreamMode::WRITE;
1180 }
1181
1182 m_nMode = nMode;
1183 Free();
1184
1185 if ( nMode & StreamMode::TRUNC )
1186 {
1187 m_bSourceRead = false; // usually it should be 0 already but just in case...
1188
1189 if ( !m_aTempURL.isEmpty() )
1190 {
1191 osl::File::remove(m_aTempURL);
1192 m_aTempURL.clear();
1193 }
1194 }
1195}
1196
1197UCBStorageStream::UCBStorageStream( const OUString& rName, StreamMode nMode, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
1198{
1199 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1200 // to class UCBStorageStream !
1201 pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, bRepair, xProgress );
1202 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1204}
1205
1207 : pImp( pImpl )
1208{
1209 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1210 pImp->m_pAntiImpl = this;
1213}
1214
1216{
1217 if ( pImp->m_nMode & StreamMode::WRITE )
1218 pImp->Flush();
1219 pImp->m_pAntiImpl = nullptr;
1220 pImp->Free();
1221 pImp->ReleaseRef();
1222}
1223
1224sal_Int32 UCBStorageStream::Read( void * pData, sal_Int32 nSize )
1225{
1226 //return pImp->m_pStream->Read( pData, nSize );
1227 return pImp->GetData( pData, nSize );
1228}
1229
1230sal_Int32 UCBStorageStream::Write( const void* pData, sal_Int32 nSize )
1231{
1232 return pImp->PutData( pData, nSize );
1233}
1234
1235sal_uInt64 UCBStorageStream::Seek( sal_uInt64 nPos )
1236{
1237 //return pImp->m_pStream->Seek( nPos );
1238 return pImp->Seek( nPos );
1239}
1240
1242{
1243 if( !pImp->Init() )
1244 return 0;
1245 return pImp->m_pStream->Tell();
1246}
1247
1249{
1250 // streams are never really transacted, so flush also means commit !
1251 Commit();
1252}
1253
1254bool UCBStorageStream::SetSize( sal_uInt64 nNewSize )
1255{
1256 pImp->SetSize( nNewSize );
1257 return !pImp->GetError();
1258}
1259
1260bool UCBStorageStream::Validate( bool bWrite ) const
1261{
1262 return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
1263}
1264
1266{
1267 // ???
1268 if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx
1269 return true;
1270 if( ( m & StreamMode::READWRITE) == StreamMode::READ )
1271 {
1272 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1273 if( ( m & StreamMode::SHARE_DENYWRITE )
1274 || ( m & StreamMode::SHARE_DENYALL ) )
1275 return true;
1276 }
1277 else
1278 {
1279 // only SHARE_DENYALL allowed
1280 // storages open in r/o mode are OK, since only
1281 // the commit may fail
1282 if( m & StreamMode::SHARE_DENYALL )
1283 return true;
1284 }
1285
1286 return true;
1287}
1288
1290{
1291 return static_cast<SvStream*>(pImp);
1292}
1293
1295{
1296 // ???
1297 return static_cast<BaseStorageStream const *>(this) == &rStream;
1298}
1299
1301{
1302 // mark this stream for sending it on root commit
1303 pImp->FlushData();
1304 return true;
1305}
1306
1308{
1309 if( !pImp->Init() )
1310 return;
1311
1312 UCBStorageStream* pStg = dynamic_cast<UCBStorageStream*>( pDestStm );
1313 if ( pStg )
1315
1316 pDestStm->SetSize( 0 );
1318 sal_Int32 n = Tell();
1319 if( n < 0 )
1320 return;
1321
1322 if( !pDestStm->SetSize( n ) || !n )
1323 return;
1324
1325 std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[ 4096 ]);
1326 Seek( 0 );
1327 pDestStm->Seek( 0 );
1328 while( n )
1329 {
1330 sal_Int32 nn = n;
1331 if( nn > 4096 )
1332 nn = 4096;
1333 if( Read( p.get(), nn ) != nn )
1334 break;
1335 if( pDestStm->Write( p.get(), nn ) != nn )
1336 break;
1337 n -= nn;
1338 }
1339}
1340
1341bool UCBStorageStream::SetProperty( const OUString& rName, const css::uno::Any& rValue )
1342{
1343 if ( rName == "Title")
1344 return false;
1345
1346 if ( rName == "MediaType")
1347 {
1348 OUString aTmp;
1349 rValue >>= aTmp;
1350 pImp->m_aContentType = aTmp;
1351 }
1352
1353 try
1354 {
1355 if ( pImp->m_pContent )
1356 {
1357 pImp->m_pContent->setPropertyValue( rName, rValue );
1358 return true;
1359 }
1360 }
1361 catch (const Exception&)
1362 {
1363 }
1364
1365 return false;
1366}
1367
1369{
1370 return pImp->GetSize();
1371}
1372
1373UCBStorage::UCBStorage( SvStream& rStrm, bool bDirect )
1374{
1375 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1376 // to class UCBStorage !
1377 pImp = new UCBStorage_Impl( rStrm, this, bDirect );
1378
1379 pImp->AddFirstRef();
1380 pImp->Init();
1382}
1383
1384UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1385{
1386 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1387 // to class UCBStorage !
1388 pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
1389 pImp->AddFirstRef();
1390 pImp->Init();
1392}
1393
1394UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1395{
1396 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1397 // to class UCBStorage !
1398 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
1399 pImp->AddFirstRef();
1400 pImp->Init();
1402}
1403
1404UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1405{
1406 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1407 // to class UCBStorage !
1408 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, false, Reference< XProgressHandler >() );
1409 pImp->AddFirstRef();
1410 pImp->Init();
1412}
1413
1415 : pImp( pImpl )
1416{
1417 pImp->m_pAntiImpl = this;
1419 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1421}
1422
1424{
1425 if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
1426 // DirectMode is simulated with an AutoCommit
1427 Commit();
1428
1429 pImp->m_pAntiImpl = nullptr;
1430 pImp->ReleaseRef();
1431}
1432
1433UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1434 : m_pAntiImpl( pStorage )
1435 , m_oContent( rContent )
1436 , m_pSource( nullptr )
1437 //, m_pStream( NULL )
1438 , m_nError( ERRCODE_NONE )
1439 , m_nMode( nMode )
1440 , m_bCommited( false )
1441 , m_bDirect( bDirect )
1442 , m_bIsRoot( bIsRoot )
1443 , m_bIsLinked( true )
1444 , m_bListCreated( false )
1446 , m_bRepairPackage( bIsRepair )
1447 , m_xProgressHandler( xProgressHandler )
1448{
1449 OUString aName( rName );
1450 if( aName.isEmpty() )
1451 {
1452 // no name given = use temporary name!
1453 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1454 m_pTempFile.reset(new ::utl::TempFileNamed);
1455 m_pTempFile->EnableKillingFile();
1456 m_aName = aName = m_pTempFile->GetURL();
1457 }
1458
1459 m_aURL = rName;
1460}
1461
1462UCBStorage_Impl::UCBStorage_Impl( const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1463 : m_pAntiImpl( pStorage )
1464 , m_pSource( nullptr )
1465 //, m_pStream( NULL )
1466 , m_nError( ERRCODE_NONE )
1467 , m_nMode( nMode )
1468 , m_bCommited( false )
1469 , m_bDirect( bDirect )
1470 , m_bIsRoot( bIsRoot )
1471 , m_bIsLinked( false )
1472 , m_bListCreated( false )
1474 , m_bRepairPackage( bIsRepair )
1475 , m_xProgressHandler( xProgressHandler )
1476{
1477 OUString aName( rName );
1478 if( aName.isEmpty() )
1479 {
1480 // no name given = use temporary name!
1481 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1482 m_pTempFile.reset(new ::utl::TempFileNamed);
1483 m_pTempFile->EnableKillingFile();
1484 m_aName = aName = m_pTempFile->GetURL();
1485 }
1486
1487 if ( m_bIsRoot )
1488 {
1489 // create the special package URL for the package content
1490 m_aURL = "vnd.sun.star.pkg://" +
1492
1493 if ( m_nMode & StreamMode::WRITE )
1494 {
1495 // the root storage opens the package, so make sure that there is any
1496 ::utl::UcbStreamHelper::CreateStream( aName, StreamMode::STD_READWRITE, m_pTempFile != nullptr /* bFileExists */ );
1497 }
1498 }
1499 else
1500 {
1501 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1502 m_aURL = rName;
1503 if ( !m_aURL.startsWith( "vnd.sun.star.pkg://") )
1504 m_bIsLinked = true;
1505 }
1506}
1507
1508UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, bool bDirect )
1509 : m_pAntiImpl( pStorage )
1510 , m_pTempFile( new ::utl::TempFileNamed )
1511 , m_pSource( &rStream )
1512 , m_nError( ERRCODE_NONE )
1513 , m_bCommited( false )
1514 , m_bDirect( bDirect )
1515 , m_bIsRoot( true )
1516 , m_bIsLinked( false )
1517 , m_bListCreated( false )
1519 , m_bRepairPackage( false )
1520{
1521 // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1522 // which will be called in the storages' dtor
1523 m_pTempFile->EnableKillingFile();
1524 DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" );
1525
1526 // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1527 // accessed readonly
1528 // the root storage opens the package; create the special package URL for the package content
1529 m_aURL = "vnd.sun.star.pkg://" +
1531
1532 // copy data into the temporary file
1533 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READWRITE, true /* bFileExists */ ));
1534 if ( pStream )
1535 {
1536 rStream.Seek(0);
1537 rStream.ReadStream( *pStream );
1538 pStream->Flush();
1539 pStream.reset();
1540 }
1541
1542 // close stream and let content access the file
1543 m_pSource->Seek(0);
1544
1545 // check opening mode
1546 m_nMode = StreamMode::READ;
1547 if( rStream.IsWritable() )
1548 m_nMode = StreamMode::READ | StreamMode::WRITE;
1549}
1550
1552{
1553 // name is last segment in URL
1554 INetURLObject aObj( m_aURL );
1555 if ( m_aName.isEmpty() )
1556 // if the name was not already set to a temp name
1557 m_aName = aObj.GetLastName();
1558
1559 if ( !m_oContent )
1560 CreateContent();
1561
1562 if ( m_oContent )
1563 {
1564 if ( m_bIsLinked )
1565 {
1566 if( m_bIsRoot )
1567 {
1568 ReadContent();
1569 if ( m_nError == ERRCODE_NONE )
1570 {
1571 // read the manifest.xml file
1572 aObj.Append( u"META-INF" );
1573 aObj.Append( u"manifest.xml" );
1574
1575 // create input stream
1576 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::STD_READ ));
1577 // no stream means no manifest.xml
1578 if ( pStream )
1579 {
1580 if ( !pStream->GetError() )
1581 {
1582 rtl::Reference<::utl::OInputStreamWrapper> pHelper = new ::utl::OInputStreamWrapper( *pStream );
1583
1584 // create a manifest reader object that will read in the manifest from the stream
1585 Reference < css::packages::manifest::XManifestReader > xReader =
1586 css::packages::manifest::ManifestReader::create(
1587 ::comphelper::getProcessComponentContext() ) ;
1588 Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( pHelper );
1589
1590 // cleanup
1591 xReader = nullptr;
1592 pHelper = nullptr;
1593 SetProps( aProps, OUString() );
1594 }
1595 }
1596 }
1597 }
1598 else
1599 ReadContent();
1600 }
1601 else
1602 {
1603 // get the manifest information from the package
1604 try {
1605 Any aAny = m_oContent->getPropertyValue("MediaType");
1606 OUString aTmp;
1607 if ( ( aAny >>= aTmp ) && !aTmp.isEmpty() )
1609 }
1610 catch (const Exception&)
1611 {
1612 SAL_WARN( "sot",
1613 "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1614 }
1615 }
1616 }
1617
1618 if ( m_aContentType.isEmpty() )
1619 return;
1620
1621 // get the clipboard format using the content type
1622 css::datatransfer::DataFlavor aDataFlavor;
1623 aDataFlavor.MimeType = m_aContentType;
1624 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1625
1626 // get the ClassId using the clipboard format ( internal table )
1628
1629 // get human presentable name using the clipboard format
1631 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1632
1634 ReadContent();
1635}
1636
1638{
1639 try
1640 {
1641 // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1642 Reference< css::ucb::XCommandEnvironment > xComEnv;
1643
1644 OUString aTemp( m_aURL );
1645
1646 if ( m_bRepairPackage )
1647 {
1648 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1650 aTemp += "?repairpackage";
1651 }
1652
1653 m_oContent.emplace( aTemp, xComEnv, comphelper::getProcessComponentContext() );
1654 }
1655 catch (const ContentCreationException&)
1656 {
1657 // content could not be created
1659 }
1660 catch (const RuntimeException&)
1661 {
1662 // any other error - not specified
1664 }
1665}
1666
1668{
1669 if ( m_bListCreated )
1670 return;
1671
1672 m_bListCreated = true;
1673
1674 try
1675 {
1676 GetContent();
1677 if ( !m_oContent )
1678 return;
1679
1680 // create cursor for access to children
1681 Reference< XResultSet > xResultSet = m_oContent->createCursor( { "Title", "IsFolder", "MediaType", "Size" }, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS );
1682 Reference< XRow > xRow( xResultSet, UNO_QUERY );
1683 if ( xResultSet.is() )
1684 {
1685 while ( xResultSet->next() )
1686 {
1687 // insert all into the children list
1688 OUString aTitle( xRow->getString(1) );
1689 if ( m_bIsLinked )
1690 {
1691 // unpacked storages have to deal with the meta-inf folder by themselves
1692 if ( aTitle == "META-INF" )
1693 continue;
1694 }
1695
1696 bool bIsFolder( xRow->getBoolean(2) );
1697 sal_Int64 nSize = xRow->getLong(4);
1698 UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, nSize );
1699 m_aChildrenList.emplace_back( pElement );
1700
1701 bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
1702 if ( bIsFolder )
1703 {
1704 if ( m_bIsLinked )
1705 OpenStorage( pElement, m_nMode, m_bDirect );
1706 if ( pElement->m_xStorage.is() )
1707 pElement->m_xStorage->Init();
1708 }
1709 else if ( bIsOfficeDocument )
1710 {
1711 // streams can be external OLE objects, so they are now folders, but storages!
1712 OUString aName( m_aURL + "/" + xRow->getString(1));
1713
1714 Reference< css::ucb::XCommandEnvironment > xComEnv;
1715 if ( m_bRepairPackage )
1716 {
1717 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1719 aName += "?repairpackage";
1720 }
1721
1723
1724 OUString aMediaType;
1725 Any aAny = aContent.getPropertyValue("MediaType");
1726 if ( ( aAny >>= aMediaType ) && ( aMediaType == "application/vnd.sun.star.oleobject" ) )
1727 pElement->m_bIsStorage = true;
1728 else if ( aMediaType.isEmpty() )
1729 {
1730 // older files didn't have that special content type, so they must be detected
1731 OpenStream( pElement, StreamMode::STD_READ, m_bDirect );
1732 if ( Storage::IsStorageFile( pElement->m_xStream.get() ) )
1733 pElement->m_bIsStorage = true;
1734 else
1735 pElement->m_xStream->Free();
1736 }
1737 }
1738 }
1739 }
1740 }
1741 catch (const InteractiveIOException& r)
1742 {
1743 if ( r.Code != IOErrorCode_NOT_EXISTING )
1745 }
1746 catch (const CommandAbortedException&)
1747 {
1748 // any command wasn't executed successfully - not specified
1749 if ( !( m_nMode & StreamMode::WRITE ) )
1750 // if the folder was just inserted and not already committed, this is not an error!
1752 }
1753 catch (const RuntimeException&)
1754 {
1755 // any other error - not specified
1757 }
1758 catch (const ResultSetException&)
1759 {
1760 // means that the package file is broken
1762 }
1763 catch (const SQLException&)
1764 {
1765 // means that the file can be broken
1767 }
1768 catch (const Exception&)
1769 {
1770 // any other error - not specified
1772 }
1773}
1774
1776{
1777 if ( !m_nError )
1778 {
1779 m_nError = nError;
1780 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
1781 }
1782}
1783
1785{
1786 sal_Int32 nCount = m_aChildrenList.size();
1787 for (auto& pElement : m_aChildrenList)
1788 {
1789 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1790 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1791 nCount += pElement->m_xStorage->GetObjectCount();
1792 }
1793
1794 return nCount;
1795}
1796
1797static OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, std::u16string_view rPath )
1798{
1799 bool bFound = false;
1800 for ( const Sequence < PropertyValue >& rMyProps : rSequence )
1801 {
1802 OUString aType;
1803
1804 for ( const PropertyValue& rAny : rMyProps )
1805 {
1806 if ( rAny.Name == "FullPath" )
1807 {
1808 OUString aTmp;
1809 if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
1810 bFound = true;
1811 if ( !aType.isEmpty() )
1812 break;
1813 }
1814 else if ( rAny.Name == "MediaType" )
1815 {
1816 if ( ( rAny.Value >>= aType ) && !aType.isEmpty() && bFound )
1817 break;
1818 }
1819 }
1820
1821 if ( bFound )
1822 return aType;
1823 }
1824
1825 return OUString();
1826}
1827
1828void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1829{
1830 OUString aPath( rPath );
1831 if ( !m_bIsRoot )
1832 aPath += m_aName;
1833 aPath += "/";
1834
1835 m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
1836
1837 if ( m_bIsRoot )
1838 // the "FullPath" of a child always starts without '/'
1839 aPath.clear();
1840
1841 for (auto& pElement : m_aChildrenList)
1842 {
1843 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1844 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1845 pElement->m_xStorage->SetProps( rSequence, aPath );
1846 else
1847 {
1848 OUString aElementPath = aPath + pElement->m_aName;
1849 pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
1850 }
1851 }
1852
1853 if ( m_aContentType.isEmpty() )
1854 return;
1855
1856 // get the clipboard format using the content type
1857 css::datatransfer::DataFlavor aDataFlavor;
1858 aDataFlavor.MimeType = m_aContentType;
1859 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1860
1861 // get the ClassId using the clipboard format ( internal table )
1863
1864 // get human presentable name using the clipboard format
1866 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1867}
1868
1869void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1870{
1871 auto pSequence = rSequence.getArray();
1872
1873 // first my own properties
1874 // first property is the "FullPath" name
1875 // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
1876 OUString aPath( rPath );
1877 if ( !m_bIsRoot )
1878 aPath += m_aName;
1879 aPath += "/";
1880 Sequence < PropertyValue > aProps{ comphelper::makePropertyValue("MediaType", m_aContentType),
1881 comphelper::makePropertyValue("FullPath", aPath) };
1882 pSequence[nProps++] = aProps;
1883
1884 if ( m_bIsRoot )
1885 // the "FullPath" of a child always starts without '/'
1886 aPath.clear();
1887
1888 // now the properties of my elements
1889 for (auto& pElement : m_aChildrenList)
1890 {
1891 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" );
1892 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1893 // storages add there properties by themselves ( see above )
1894 pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
1895 else
1896 {
1897 // properties of streams
1898 OUString aElementPath = aPath + pElement->m_aName;
1899 aProps = { comphelper::makePropertyValue("MediaType", pElement->GetContentType()),
1900 comphelper::makePropertyValue("FullPath", aElementPath) };
1901 pSequence[ nProps++ ] = aProps;
1902 }
1903 }
1904}
1905
1907{
1908 m_aChildrenList.clear();
1909
1910 m_oContent.reset();
1911 m_pTempFile.reset();
1912}
1913
1915{
1916 // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
1917 // it must be inserted with a title and a type
1918 bool bRet = false;
1919
1920 try
1921 {
1922 const Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
1923 if ( !aInfo.hasElements() )
1924 return false;
1925
1926 for ( const ContentInfo & rCurr : aInfo )
1927 {
1928 // Simply look for the first KIND_FOLDER...
1929 if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
1930 {
1931 // Make sure the only required bootstrap property is "Title",
1932 const Sequence< Property > & rProps = rCurr.Properties;
1933 if ( rProps.getLength() != 1 )
1934 continue;
1935
1936 if ( rProps[ 0 ].Name != "Title" )
1937 continue;
1938
1939 Content aNewFolder;
1940 if ( !pContent->insertNewContent( rCurr.Type, { "Title" }, { Any(m_aName) }, aNewFolder ) )
1941 continue;
1942
1943 // remove old content, create an "empty" new one and initialize it with the new inserted
1944 m_oContent.emplace( aNewFolder );
1945 bRet = true;
1946 }
1947 }
1948 }
1949 catch (const CommandAbortedException&)
1950 {
1951 // any command wasn't executed successfully - not specified
1953 }
1954 catch (const RuntimeException&)
1955 {
1956 // any other error - not specified
1958 }
1959 catch (const Exception&)
1960 {
1961 // any other error - not specified
1963 }
1964
1965 return bRet;
1966}
1967
1969{
1970 // send all changes to the package
1971 sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO;
1972
1973 // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
1974 // commit command has been sent
1975 if ( ( m_nMode & StreamMode::WRITE ) && ( m_bCommited || m_bDirect ) )
1976 {
1977 try
1978 {
1979 // all errors will be caught in the "catch" statement outside the loop
1980 for ( size_t i = 0; i < m_aChildrenList.size() && nRet; ++i )
1981 {
1982 auto& pElement = m_aChildrenList[ i ];
1983 ::ucbhelper::Content* pContent = pElement->GetContent();
1984 std::unique_ptr< ::ucbhelper::Content > xDeleteContent;
1985 if ( !pContent && pElement->IsModified() )
1986 {
1987 // if the element has never been opened, no content has been created until now
1988 OUString aName = m_aURL + "/" + pElement->m_aOriginalName;
1989 pContent = new ::ucbhelper::Content( aName, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
1990 xDeleteContent.reset(pContent); // delete it later on exit scope
1991 }
1992
1993 if ( pElement->m_bIsRemoved )
1994 {
1995 // was it inserted, then removed (so there would be nothing to do!)
1996 if ( !pElement->m_bIsInserted )
1997 {
1998 // first remove all open stream handles
1999 if (pContent && (!pElement->m_xStream.is() || pElement->m_xStream->Clear()))
2000 {
2001 pContent->executeCommand( "delete", Any( true ) );
2002 nRet = COMMIT_RESULT_SUCCESS;
2003 }
2004 else
2005 // couldn't release stream because there are external references to it
2006 nRet = COMMIT_RESULT_FAILURE;
2007 }
2008 }
2009 else
2010 {
2011 sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO;
2012 if ( pElement->m_xStorage.is() )
2013 {
2014 // element is a storage
2015 // do a commit in the following cases:
2016 // - if storage is already inserted, and changed
2017 // - storage is not in a package
2018 // - it's a new storage, try to insert and commit if successful inserted
2019 if ( !pElement->m_bIsInserted || m_bIsLinked
2020 || pElement->m_xStorage->Insert( m_oContent ? &*m_oContent : nullptr ) )
2021 {
2022 nLocalRet = pElement->m_xStorage->Commit();
2023 pContent = pElement->GetContent();
2024 }
2025 }
2026 else if ( pElement->m_xStream.is() )
2027 {
2028 // element is a stream
2029 nLocalRet = pElement->m_xStream->Commit();
2030 if ( pElement->m_xStream->m_bIsOLEStorage )
2031 {
2032 // OLE storage should be stored encrypted, if the storage uses encryption
2033 pElement->m_xStream->m_aContentType = "application/vnd.sun.star.oleobject";
2034 Any aValue;
2035 aValue <<= true;
2036 pElement->m_xStream->m_pContent->setPropertyValue("Encrypted", aValue );
2037 }
2038
2039 pContent = pElement->GetContent();
2040 }
2041
2042 if (pContent && pElement->m_aName != pElement->m_aOriginalName)
2043 {
2044 // name ( title ) of the element was changed
2045 nLocalRet = COMMIT_RESULT_SUCCESS;
2046 pContent->setPropertyValue("Title", Any(pElement->m_aName) );
2047 }
2048
2049 if (pContent && pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType())
2050 {
2051 // mediatype of the element was changed
2052 nLocalRet = COMMIT_RESULT_SUCCESS;
2053 pContent->setPropertyValue("MediaType", Any(pElement->GetContentType()) );
2054 }
2055
2056 if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO )
2057 nRet = nLocalRet;
2058 }
2059
2060 if ( nRet == COMMIT_RESULT_FAILURE )
2061 break;
2062 }
2063 }
2064 catch (const ContentCreationException&)
2065 {
2066 // content could not be created
2068 return COMMIT_RESULT_FAILURE;
2069 }
2070 catch (const CommandAbortedException&)
2071 {
2072 // any command wasn't executed successfully - not specified
2074 return COMMIT_RESULT_FAILURE;
2075 }
2076 catch (const RuntimeException&)
2077 {
2078 // any other error - not specified
2080 return COMMIT_RESULT_FAILURE;
2081 }
2082 catch (const Exception&)
2083 {
2084 // any other error - not specified
2086 return COMMIT_RESULT_FAILURE;
2087 }
2088
2089 if ( m_bIsRoot && m_oContent )
2090 {
2091 // the root storage must flush the root package content
2092 if ( nRet == COMMIT_RESULT_SUCCESS )
2093 {
2094 try
2095 {
2096 // commit the media type to the JAR file
2097 // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2098 Any aType;
2099 aType <<= m_aContentType;
2100 m_oContent->setPropertyValue("MediaType", aType );
2101
2102 if ( m_bIsLinked )
2103 {
2104 // write a manifest file
2105 // first create a subfolder "META-inf"
2106 Content aNewSubFolder;
2107 bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_oContent, "META-INF", aNewSubFolder );
2108 if ( bRet )
2109 {
2110 // create a stream to write the manifest file - use a temp file
2111 OUString aURL( aNewSubFolder.getURL() );
2112 std::optional< ::utl::TempFileNamed > pTempFile(&aURL );
2113
2114 // get the stream from the temp file and create an output stream wrapper
2115 SvStream* pStream = pTempFile->GetStream( StreamMode::STD_READWRITE );
2116 rtl::Reference<::utl::OOutputStreamWrapper> xOutputStream = new ::utl::OOutputStreamWrapper( *pStream );
2117
2118 // create a manifest writer object that will fill the stream
2119 Reference < css::packages::manifest::XManifestWriter > xWriter =
2120 css::packages::manifest::ManifestWriter::create(
2121 ::comphelper::getProcessComponentContext() );
2122 sal_Int32 nCount = GetObjectCount() + 1;
2123 Sequence < Sequence < PropertyValue > > aProps( nCount );
2124 sal_Int32 nProps = 0;
2125 GetProps( nProps, aProps, OUString() );
2126 xWriter->writeManifestSequence( xOutputStream, aProps );
2127
2128 // move the stream to its desired location
2129 Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2130 xWriter = nullptr;
2131 xOutputStream = nullptr;
2132 pTempFile.reset();
2133 aNewSubFolder.transferContent( aSource, InsertOperation::Move, "manifest.xml", NameClash::OVERWRITE );
2134 }
2135 }
2136 else
2137 {
2138#if OSL_DEBUG_LEVEL > 0
2139 SAL_INFO("sot", "Files: " << nOpenFiles);
2140 SAL_INFO("sot", "Streams: " << nOpenStreams);
2141#endif
2142 // force writing
2143 Any aAny;
2144 m_oContent->executeCommand( "flush", aAny );
2145 if ( m_pSource != nullptr )
2146 {
2147 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READ ));
2149 // m_pSource->Seek(0);
2150 pStream->ReadStream( *m_pSource );
2151 pStream.reset();
2152 m_pSource->Seek(0);
2153 }
2154 }
2155 }
2156 catch (const CommandAbortedException&)
2157 {
2158 // how to tell the content : forget all changes ?!
2159 // or should we assume that the content does it by itself because he threw an exception ?!
2160 // any command wasn't executed successfully - not specified
2162 return COMMIT_RESULT_FAILURE;
2163 }
2164 catch (const RuntimeException&)
2165 {
2166 // how to tell the content : forget all changes ?!
2167 // or should we assume that the content does it by itself because he threw an exception ?!
2168 // any other error - not specified
2170 return COMMIT_RESULT_FAILURE;
2171 }
2172 catch (const InteractiveIOException& r)
2173 {
2174 if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2176 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2178 else if ( r.Code == IOErrorCode_CANT_READ )
2180 else if ( r.Code == IOErrorCode_CANT_WRITE )
2182 else
2184
2185 return COMMIT_RESULT_FAILURE;
2186 }
2187 catch (const Exception&)
2188 {
2189 // how to tell the content : forget all changes ?!
2190 // or should we assume that the content does it by itself because he threw an exception ?!
2191 // any other error - not specified
2193 return COMMIT_RESULT_FAILURE;
2194 }
2195 }
2196 else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO )
2197 {
2198 // how to tell the content : forget all changes ?! Should we ?!
2200 return nRet;
2201 }
2202
2203 // after successful root commit all elements names and types are adjusted and all removed elements
2204 // are also removed from the lists
2205 for ( size_t i = 0; i < m_aChildrenList.size(); )
2206 {
2207 auto& pInnerElement = m_aChildrenList[ i ];
2208 if ( pInnerElement->m_bIsRemoved )
2209 m_aChildrenList.erase( m_aChildrenList.begin() + i );
2210 else
2211 {
2212 pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2213 pInnerElement->m_bIsInserted = false;
2214 ++i;
2215 }
2216 }
2217 }
2218
2219 m_bCommited = false;
2220 }
2221
2222 return nRet;
2223}
2224
2226{
2227 for ( size_t i = 0; i < m_aChildrenList.size(); )
2228 {
2229 auto& pElement = m_aChildrenList[ i ];
2230 pElement->m_bIsRemoved = false;
2231 if ( pElement->m_bIsInserted )
2232 m_aChildrenList.erase( m_aChildrenList.begin() + i );
2233 else
2234 {
2235 if ( pElement->m_xStream.is() )
2236 {
2237 pElement->m_xStream->m_bCommited = false;
2238 pElement->m_xStream->Revert();
2239 }
2240 else if ( pElement->m_xStorage.is() )
2241 {
2242 pElement->m_xStorage->m_bCommited = false;
2243 pElement->m_xStorage->Revert();
2244 }
2245
2246 pElement->m_aName = pElement->m_aOriginalName;
2247 pElement->m_bIsRemoved = false;
2248 ++i;
2249 }
2250 }
2251}
2252
2253const OUString& UCBStorage::GetName() const
2254{
2255 return pImp->m_aName; // pImp->m_aURL ?!
2256}
2257
2259{
2260 return pImp->m_bIsRoot;
2261}
2262
2264{
2265}
2266
2267void UCBStorage::SetClass( const SvGlobalName & rClass, SotClipboardFormatId nOriginalClipFormat, const OUString & rUserTypeName )
2268{
2269 pImp->m_aClassId = rClass;
2270 pImp->m_nFormat = nOriginalClipFormat;
2271 pImp->m_aUserTypeName = rUserTypeName;
2272
2273 // in UCB storages only the content type will be stored, all other information can be reconstructed
2274 // ( see the UCBStorage_Impl::Init() method )
2275 css::datatransfer::DataFlavor aDataFlavor;
2277 pImp->m_aContentType = aDataFlavor.MimeType;
2278}
2279
2280void UCBStorage::SetClassId( const ClsId& rClsId )
2281{
2282 pImp->m_aClassId = SvGlobalName( rClsId );
2283 if ( pImp->m_aClassId == SvGlobalName() )
2284 return;
2285
2286 // in OLE storages the clipboard format and the user name will be transferred when a storage is copied because both are
2287 // stored in one the substreams
2288 // UCB storages store the content type information as content type in the manifest file and so this information must be
2289 // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2290 // the content type
2293 {
2294 css::datatransfer::DataFlavor aDataFlavor;
2296 pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2297 pImp->m_aContentType = aDataFlavor.MimeType;
2298 }
2299}
2300
2302{
2303 return pImp->m_aClassId.GetCLSID();
2304}
2305
2307{
2308 return pImp->m_aClassId;
2309}
2310
2312{
2313 return pImp->m_nFormat;
2314}
2315
2317{
2318 OSL_FAIL("UserName is not implemented in UCB storages!" );
2319 return pImp->m_aUserTypeName;
2320}
2321
2323{
2324 // put information in childrenlist into StorageInfoList
2325 for (auto& pElement : pImp->GetChildrenList())
2326 {
2327 if ( !pElement->m_bIsRemoved )
2328 {
2329 // problem: what about the size of a substorage ?!
2330 sal_uInt64 nSize = pElement->m_nSize;
2331 if ( pElement->m_xStream.is() )
2332 nSize = pElement->m_xStream->GetSize();
2333 SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2334 pList->push_back( aInfo );
2335 }
2336 }
2337}
2338
2339bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl const & rElement, BaseStorage* pDest, const OUString& rNew ) const
2340{
2341 // insert stream or storage into the list or stream of the destination storage
2342 // not into the content, this will be done on commit !
2343 // be aware of name changes !
2344 if ( !rElement.m_bIsStorage )
2345 {
2346 // copy the streams data
2347 // the destination stream must not be open
2348 tools::SvRef<BaseStorageStream> pOtherStream(pDest->OpenStream( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2349 BaseStorageStream* pStream = nullptr;
2350 bool bDeleteStream = false;
2351
2352 // if stream is already open, it is allowed to copy it, so be aware of this
2353 if ( rElement.m_xStream.is() )
2354 pStream = rElement.m_xStream->m_pAntiImpl;
2355 if ( !pStream )
2356 {
2357 pStream = const_cast< UCBStorage* >(this)->OpenStream( rElement.m_aName, StreamMode::STD_READ, pImp->m_bDirect );
2358 bDeleteStream = true;
2359 }
2360
2361 pStream->CopyTo( pOtherStream.get() );
2362 SetError( pStream->GetError() );
2363 if( pOtherStream->GetError() )
2364 pDest->SetError( pOtherStream->GetError() );
2365 else
2366 pOtherStream->Commit();
2367
2368 if ( bDeleteStream )
2369 delete pStream;
2370 }
2371 else
2372 {
2373 // copy the storage content
2374 // the destination storage must not be open
2375 BaseStorage* pStorage = nullptr;
2376
2377 // if stream is already open, it is allowed to copy it, so be aware of this
2378 bool bDeleteStorage = false;
2379 if ( rElement.m_xStorage.is() )
2380 pStorage = rElement.m_xStorage->m_pAntiImpl;
2381 if ( !pStorage )
2382 {
2383 pStorage = const_cast<UCBStorage*>(this)->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2384 bDeleteStorage = true;
2385 }
2386
2387 UCBStorage* pUCBDest = dynamic_cast<UCBStorage*>( pDest );
2388 UCBStorage* pUCBCopy = dynamic_cast<UCBStorage*>( pStorage );
2389
2390 bool bOpenUCBStorage = pUCBDest && pUCBCopy;
2391 tools::SvRef<BaseStorage> pOtherStorage(bOpenUCBStorage ?
2392 pDest->OpenUCBStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ) :
2393 pDest->OpenOLEStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2394
2395 // For UCB storages, the class id and the format id may differ,
2396 // do passing the class id is not sufficient.
2397 if( bOpenUCBStorage )
2398 pOtherStorage->SetClass( pStorage->GetClassName(),
2399 pStorage->GetFormat(),
2400 pUCBCopy->pImp->m_aUserTypeName );
2401 else
2402 pOtherStorage->SetClassId( pStorage->GetClassId() );
2403 pStorage->CopyTo( pOtherStorage.get() );
2404 SetError( pStorage->GetError() );
2405 if( pOtherStorage->GetError() )
2406 pDest->SetError( pOtherStorage->GetError() );
2407 else
2408 pOtherStorage->Commit();
2409
2410 if ( bDeleteStorage )
2411 delete pStorage;
2412 }
2413
2414 return Good() && pDest->Good();
2415}
2416
2417UCBStorageElement_Impl* UCBStorage::FindElement_Impl( std::u16string_view rName ) const
2418{
2419 DBG_ASSERT( !rName.empty(), "Name is empty!" );
2420 for (const auto& pElement : pImp->GetChildrenList())
2421 {
2422 if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2423 return pElement.get();
2424 }
2425 return nullptr;
2426}
2427
2428bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2429{
2430 DBG_ASSERT( pDestStg != static_cast<BaseStorage const *>(this), "Self-Copying is not possible!" );
2431 if ( pDestStg == static_cast<BaseStorage const *>(this) )
2432 return false;
2433
2434 // perhaps it's also a problem if one storage is a parent of the other ?!
2435 // or if not: could be optimized ?!
2436
2437 // For UCB storages, the class id and the format id may differ,
2438 // do passing the class id is not sufficient.
2439 if( dynamic_cast<const UCBStorage *>(pDestStg) != nullptr )
2440 pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
2442 else
2443 pDestStg->SetClassId( GetClassId() );
2444 pDestStg->SetDirty();
2445
2446 bool bRet = true;
2447 for ( size_t i = 0; i < pImp->GetChildrenList().size() && bRet; ++i )
2448 {
2449 auto& pElement = pImp->GetChildrenList()[ i ];
2450 if ( !pElement->m_bIsRemoved )
2451 bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
2452 }
2453
2454 if( !bRet )
2455 SetError( pDestStg->GetError() );
2456 return Good() && pDestStg->Good();
2457}
2458
2459bool UCBStorage::CopyTo( const OUString& rElemName, BaseStorage* pDest, const OUString& rNew )
2460{
2461 if( rElemName.isEmpty() )
2462 return false;
2463
2464 if ( pDest == static_cast<BaseStorage*>(this) )
2465 {
2466 // can't double an element
2467 return false;
2468 }
2469 else
2470 {
2471 // for copying no optimization is useful, because in every case the stream data must be copied
2472 UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2473 if ( pElement )
2474 return CopyStorageElement_Impl( *pElement, pDest, rNew );
2475 else
2476 {
2478 return false;
2479 }
2480 }
2481}
2482
2484{
2485 // mark this storage for sending it on root commit
2486 pImp->m_bCommited = true;
2487 if ( pImp->m_bIsRoot )
2488 // the root storage coordinates committing by sending a Commit command to its content
2489 return ( pImp->Commit() != COMMIT_RESULT_FAILURE );
2490 else
2491 return true;
2492}
2493
2495{
2496 pImp->Revert();
2497 return true;
2498}
2499
2500BaseStorageStream* UCBStorage::OpenStream( const OUString& rEleName, StreamMode nMode, bool bDirect )
2501{
2502 if( rEleName.isEmpty() )
2503 return nullptr;
2504
2505 // try to find the storage element
2506 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2507 if ( !pElement )
2508 {
2509 // element does not exist, check if creation is allowed
2510 if( nMode & StreamMode::NOCREATE )
2511 {
2512 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2513 OUString aName = pImp->m_aURL + "/" + rEleName;
2515 pStream->SetError( GetError() );
2516 pStream->pImp->m_aName = rEleName;
2517 return pStream;
2518 }
2519 else
2520 {
2521 // create a new UCBStorageElement and insert it into the list
2522 pElement = new UCBStorageElement_Impl( rEleName );
2523 pElement->m_bIsInserted = true;
2524 pImp->m_aChildrenList.emplace_back( pElement );
2525 }
2526 }
2527
2528 if ( !pElement->m_bIsFolder )
2529 {
2530 // check if stream is already created
2531 if ( pElement->m_xStream.is() )
2532 {
2533 // stream has already been created; if it has no external reference, it may be opened another time
2534 if ( pElement->m_xStream->m_pAntiImpl )
2535 {
2536 OSL_FAIL("Stream is already open!" );
2538 return nullptr;
2539 }
2540 else
2541 {
2542 // check if stream is opened with the same keyword as before
2543 // if not, generate a new stream because it could be encrypted vs. decrypted!
2544 if ( pElement->m_xStream->m_aKey.isEmpty() )
2545 {
2546 pElement->m_xStream->PrepareCachedForReopen( nMode );
2547
2548 return new UCBStorageStream( pElement->m_xStream.get() );
2549 }
2550 }
2551 }
2552
2553 // stream is opened the first time
2554 pImp->OpenStream( pElement, nMode, bDirect );
2555
2556 // if name has been changed before creating the stream: set name!
2557 pElement->m_xStream->m_aName = rEleName;
2558 return new UCBStorageStream( pElement->m_xStream.get() );
2559 }
2560
2561 return nullptr;
2562}
2563
2565{
2566 OUString aName = m_aURL + "/" +pElement->m_aOriginalName;
2567 pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, nullptr, bDirect, m_bRepairPackage, m_xProgressHandler );
2568}
2569
2570BaseStorage* UCBStorage::OpenUCBStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2571{
2572 if( rEleName.isEmpty() )
2573 return nullptr;
2574
2575 return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2576}
2577
2578BaseStorage* UCBStorage::OpenOLEStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2579{
2580 if( rEleName.isEmpty() )
2581 return nullptr;
2582
2583 return OpenStorage_Impl( rEleName, nMode, bDirect, false );
2584}
2585
2586BaseStorage* UCBStorage::OpenStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2587{
2588 if( rEleName.isEmpty() )
2589 return nullptr;
2590
2591 return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2592}
2593
2594BaseStorage* UCBStorage::OpenStorage_Impl( const OUString& rEleName, StreamMode nMode, bool bDirect, bool bForceUCBStorage )
2595{
2596 // try to find the storage element
2597 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2598 if ( !pElement )
2599 {
2600 // element does not exist, check if creation is allowed
2601 if( nMode & StreamMode::NOCREATE )
2602 {
2603 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2604 OUString aName = pImp->m_aURL + "/" + rEleName; // ???
2605 UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2606 pStorage->pImp->m_bIsRoot = false;
2607 pStorage->pImp->m_bListCreated = true; // the storage is pretty new, nothing to read
2608 pStorage->SetError( GetError() );
2609 return pStorage;
2610 }
2611
2612 // create a new UCBStorageElement and insert it into the list
2613 // problem: perhaps an OLEStorage should be created ?!
2614 // Because nothing is known about the element that should be created, an external parameter is needed !
2615 pElement = new UCBStorageElement_Impl( rEleName );
2616 pElement->m_bIsInserted = true;
2617 pImp->m_aChildrenList.emplace_back( pElement );
2618 }
2619
2620 if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
2621 {
2622 // create OLE storages on a stream ( see ctor of SotStorage )
2623 // Such a storage will be created on a UCBStorageStream; it will write into the stream
2624 // if it is opened in direct mode or when it is committed. In this case the stream will be
2625 // modified and then it MUST be treated as committed.
2626 if ( !pElement->m_xStream.is() )
2627 {
2628 BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
2629 UCBStorageStream* pStream = dynamic_cast<UCBStorageStream*>( pStr );
2630 if ( !pStream )
2631 {
2632 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2633 return nullptr;
2634 }
2635
2636 pElement->m_xStream = pStream->pImp;
2637 delete pStream;
2638 }
2639
2640 pElement->m_xStream->PrepareCachedForReopen( nMode );
2641 bool bInited = pElement->m_xStream->Init();
2642 if (!bInited)
2643 {
2644 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2645 return nullptr;
2646 }
2647
2648 pElement->m_bIsStorage = true;
2649 return pElement->m_xStream->CreateStorage(); // can only be created in transacted mode
2650 }
2651 else if ( pElement->m_xStorage.is() )
2652 {
2653 // storage has already been opened; if it has no external reference, it may be opened another time
2654 if ( pElement->m_xStorage->m_pAntiImpl )
2655 {
2656 OSL_FAIL("Storage is already open!" );
2658 }
2659 else
2660 {
2661 bool bIsWritable = bool( pElement->m_xStorage->m_nMode & StreamMode::WRITE );
2662 if ( !bIsWritable && ( nMode & StreamMode::WRITE ) )
2663 {
2664 OUString aName = pImp->m_aURL + "/" + pElement->m_aOriginalName;
2665 UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2666 pElement->m_xStorage = pStorage->pImp;
2667 return pStorage;
2668 }
2669 else
2670 {
2671 return new UCBStorage( pElement->m_xStorage.get() );
2672 }
2673 }
2674 }
2675 else if ( !pElement->m_xStream.is() )
2676 {
2677 // storage is opened the first time
2678 bool bIsWritable = bool(pImp->m_nMode & StreamMode::WRITE);
2679 if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
2680 {
2681 // make sure that the root storage object has been created before substorages will be created
2682 INetURLObject aFolderObj( pImp->m_aURL );
2683 aFolderObj.removeSegment();
2684
2685 Content aFolder( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2686 pImp->m_oContent.emplace();
2687 bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_oContent );
2688 if ( !bRet )
2689 {
2691 return nullptr;
2692 }
2693 }
2694
2695 UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
2696 if ( pStor )
2697 {
2698 if ( pElement->m_bIsInserted )
2699 pStor->m_bListCreated = true; // the storage is pretty new, nothing to read
2700
2701 return new UCBStorage( pStor );
2702 }
2703 }
2704
2705 return nullptr;
2706}
2707
2709{
2710 UCBStorage_Impl* pRet = nullptr;
2711 OUString aName = m_aURL + "/" + pElement->m_aOriginalName; // ???
2712
2713 pElement->m_bIsStorage = pElement->m_bIsFolder = true;
2714
2715 if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
2716 {
2717 Content aNewFolder;
2718 bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_oContent, pElement->m_aOriginalName, aNewFolder );
2719 if ( bRet )
2720 pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2721 }
2722 else
2723 {
2724 pRet = new UCBStorage_Impl( aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2725 }
2726
2727 if ( pRet )
2728 {
2729 pRet->m_bIsLinked = m_bIsLinked;
2730 pRet->m_bIsRoot = false;
2731
2732 // if name has been changed before creating the stream: set name!
2733 pRet->m_aName = pElement->m_aOriginalName;
2734 pElement->m_xStorage = pRet;
2735 }
2736
2737 if ( pRet )
2738 pRet->Init();
2739
2740 return pRet;
2741}
2742
2743bool UCBStorage::IsStorage( const OUString& rEleName ) const
2744{
2745 if( rEleName.isEmpty() )
2746 return false;
2747
2748 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2749 return ( pElement && pElement->m_bIsStorage );
2750}
2751
2752bool UCBStorage::IsStream( const OUString& rEleName ) const
2753{
2754 if( rEleName.isEmpty() )
2755 return false;
2756
2757 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2758 return ( pElement && !pElement->m_bIsStorage );
2759}
2760
2761bool UCBStorage::IsContained( const OUString & rEleName ) const
2762{
2763 if( rEleName.isEmpty() )
2764 return false;
2765 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2766 return ( pElement != nullptr );
2767}
2768
2769void UCBStorage::Remove( const OUString& rEleName )
2770{
2771 if( rEleName.isEmpty() )
2772 return;
2773
2774 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2775 if ( pElement )
2776 {
2777 pElement->m_bIsRemoved = true;
2778 }
2779 else
2781}
2782
2784{
2785 // ???
2786 return true;
2787}
2788
2789bool UCBStorage::Validate( bool bWrite ) const
2790{
2791 // ???
2792 return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
2793}
2794
2796{
2797 // ???
2798 if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx
2799 return true;
2800 // only SHARE_DENYALL allowed
2801 // storages open in r/o mode are OK, since only
2802 // the commit may fail
2803 if( m & StreamMode::SHARE_DENYALL )
2804 return true;
2805
2806 return true;
2807}
2808
2809bool UCBStorage::Equals( const BaseStorage& rStorage ) const
2810{
2811 // ???
2812 return static_cast<BaseStorage const *>(this) == &rStorage;
2813}
2814
2816{
2817 if ( !pFile )
2818 return false;
2819
2820 sal_uInt64 nPos = pFile->Tell();
2821 if ( pFile->TellEnd() < 4 )
2822 return false;
2823
2824 pFile->Seek(0);
2825 sal_uInt32 nBytes(0);
2826 pFile->ReadUInt32( nBytes );
2827
2828 // search for the magic bytes
2829 bool bRet = ( nBytes == 0x04034b50 );
2830 if ( !bRet )
2831 {
2832 // disk spanned file have an additional header in front of the usual one
2833 bRet = ( nBytes == 0x08074b50 );
2834 if ( bRet )
2835 {
2836 nBytes = 0;
2837 pFile->ReadUInt32( nBytes );
2838 bRet = ( nBytes == 0x04034b50 );
2839 }
2840 }
2841
2842 pFile->Seek( nPos );
2843 return bRet;
2844}
2845
2846/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
css::util::URL m_aURL
virtual sal_uInt64 Seek(sal_uInt64 nPos)=0
virtual sal_Int32 Write(const void *pData, sal_Int32 nSize)=0
virtual bool SetSize(sal_uInt64 nNewSize)=0
virtual void CopyTo(BaseStorageStream *pDestStm)=0
virtual void SetClass(const SvGlobalName &rClass, SotClipboardFormatId nOriginalClipFormat, const OUString &rUserTypeName)=0
virtual const ClsId & GetClassId() const =0
virtual BaseStorageStream * OpenStream(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE, bool bDirect=true)=0
virtual BaseStorage * OpenOLEStorage(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE, bool bDirect=false)=0
virtual void SetDirty()=0
virtual BaseStorage * OpenUCBStorage(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE, bool bDirect=false)=0
virtual SvGlobalName GetClassName()=0
virtual bool CopyTo(BaseStorage *pDestStg) const =0
virtual void SetClassId(const ClsId &)=0
virtual SotClipboardFormatId GetFormat()=0
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool removeSegment(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true)
OUString GetLastName(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool setName(std::u16string_view rTheName, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
bool Append(std::u16string_view rTheSegment, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
static OUString encode(std::u16string_view rText, Part ePart, EncodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
static bool GetFormatDataFlavor(SotClipboardFormatId nFormat, css::datatransfer::DataFlavor &rFlavor)
Definition: exchange.cxx:316
static SotClipboardFormatId GetFormat(const css::datatransfer::DataFlavor &rFlavor)
Definition: exchange.cxx:419
StreamMode m_nMode
Definition: stg.hxx:41
void SetError(ErrCode) const
Definition: stg.cxx:67
bool Good() const
Definition: stg.hxx:51
void ResetError() const
Definition: stg.cxx:73
ErrCode GetError() const
Definition: stg.cxx:60
const SvGUID & GetCLSID() const
void ReleaseRef()
void AddFirstRef()
virtual void ResetError()
bool IsWritable() const
SvStream & ReadStream(SvStream &rStream)
sal_uInt64 Tell() const
virtual sal_uInt64 TellEnd()
bool SetStreamSize(sal_uInt64 nSize)
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
void SetError(ErrCode nErrorCode)
sal_uInt64 Seek(sal_uInt64 nPos)
void Flush()
ErrCode GetError() const
::ucbhelper::Content * m_pContent
Definition: ucbstorage.cxx:409
virtual void ResetError() override
Definition: ucbstorage.cxx:990
virtual std::size_t GetData(void *pData, std::size_t nSize) override
Definition: ucbstorage.cxx:827
void SetError(ErrCode nError)
Definition: ucbstorage.cxx:980
UCBStorageStream * m_pAntiImpl
Definition: ucbstorage.cxx:401
std::unique_ptr< SvStream > m_pStream
Definition: ucbstorage.cxx:411
sal_uInt64 GetSize()
Definition: ucbstorage.cxx:998
virtual sal_uInt64 SeekPos(sal_uInt64 nPos) override
Definition: ucbstorage.cxx:883
OUString m_aOriginalContentType
Definition: ucbstorage.cxx:407
virtual void SetSize(sal_uInt64 nSize) override
Definition: ucbstorage.cxx:943
virtual void FlushData() override
Definition: ucbstorage.cxx:969
virtual std::size_t PutData(const void *pData, std::size_t nSize) override
Definition: ucbstorage.cxx:864
void PrepareCachedForReopen(StreamMode nMode)
Reference< XInputStream > m_rSource
Definition: ucbstorage.cxx:410
UCBStorageStream_Impl(const OUString &, StreamMode, UCBStorageStream *, bool, bool bRepair, Reference< XProgressHandler > const &xProgress)
Definition: ucbstorage.cxx:620
BaseStorage * CreateStorage()
virtual ~UCBStorageStream_Impl() override
Definition: ucbstorage.cxx:662
SvStream * GetModifySvStream()
UCBStorageStream(const OUString &rName, StreamMode nMode, bool bDirect, bool bRepair, css::uno::Reference< css::ucb::XProgressHandler > const &xProgress)
virtual void Flush() override
virtual ~UCBStorageStream() override
virtual void CopyTo(BaseStorageStream *pDestStm) override
virtual sal_uInt64 Seek(sal_uInt64 nPos) override
virtual bool Commit() override
virtual bool Validate(bool=false) const override
virtual bool ValidateMode(StreamMode) const override
virtual sal_uInt64 Tell() override
virtual sal_uInt64 GetSize() const override
virtual bool Equals(const BaseStorageStream &rStream) const override
virtual bool SetSize(sal_uInt64 nNewSize) override
UCBStorageStream_Impl * pImp
Definition: stg.hxx:209
virtual sal_Int32 Read(void *pData, sal_Int32 nSize) override
bool SetProperty(const OUString &rName, const css::uno::Any &rValue)
virtual sal_Int32 Write(const void *pData, sal_Int32 nSize) override
OUString m_aContentType
Definition: ucbstorage.cxx:460
StreamMode m_nMode
Definition: ucbstorage.cxx:466
SotClipboardFormatId m_nFormat
Definition: ucbstorage.cxx:474
SvGlobalName m_aClassId
Definition: ucbstorage.cxx:476
UCBStorageElementList_Impl m_aChildrenList
Definition: ucbstorage.cxx:478
::ucbhelper::Content * GetContent()
Definition: ucbstorage.cxx:499
SvStream * m_pSource
Definition: ucbstorage.cxx:464
std::unique_ptr<::utl::TempFileNamed > m_pTempFile
Definition: ucbstorage.cxx:463
virtual ~UCBStorage_Impl() override
UCBStorage_Impl * OpenStorage(UCBStorageElement_Impl *pElement, StreamMode nMode, bool bDirect)
sal_Int32 GetObjectCount()
OUString m_aOriginalContentType
Definition: ucbstorage.cxx:461
void SetProps(const Sequence< Sequence< PropertyValue > > &rSequence, const OUString &)
void GetProps(sal_Int32 &, Sequence< Sequence< PropertyValue > > &rSequence, const OUString &)
UCBStorage * m_pAntiImpl
Definition: ucbstorage.cxx:456
Reference< XProgressHandler > m_xProgressHandler
Definition: ucbstorage.cxx:481
UCBStorageElementList_Impl & GetChildrenList()
Definition: ucbstorage.cxx:505
void SetError(ErrCode nError)
OUString m_aUserTypeName
Definition: ucbstorage.cxx:475
sal_Int16 Commit()
bool Insert(::ucbhelper::Content *pContent)
void OpenStream(UCBStorageElement_Impl *, StreamMode, bool)
OUString m_aName
Definition: ucbstorage.cxx:458
UCBStorage_Impl(const ::ucbhelper::Content &, const OUString &, StreamMode, UCBStorage *, bool, bool, bool=false, Reference< XProgressHandler > const &=Reference< XProgressHandler >())
std::optional<::ucbhelper::Content > m_oContent
Definition: ucbstorage.cxx:462
virtual bool IsStream(const OUString &rEleName) const override
virtual bool ValidateFAT() override
virtual const OUString & GetName() const override
virtual void SetDirty() override
virtual void Remove(const OUString &rEleName) override
virtual bool Revert() override
virtual void SetClass(const SvGlobalName &rClass, SotClipboardFormatId nOriginalClipFormat, const OUString &rUserTypeName) override
virtual const ClsId & GetClassId() const override
virtual bool CopyTo(BaseStorage *pDestStg) const override
UCBStorageElement_Impl * FindElement_Impl(std::u16string_view rName) const
bool CopyStorageElement_Impl(UCBStorageElement_Impl const &rElement, BaseStorage *pDest, const OUString &rNew) const
virtual void SetClassId(const ClsId &) override
virtual BaseStorage * OpenUCBStorage(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE, bool bDirect=false) override
virtual bool Validate(bool=false) const override
static bool IsStorageFile(SvStream *)
virtual BaseStorageStream * OpenStream(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE, bool bDirect=true) override
virtual BaseStorage * OpenStorage(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE, bool bDirect=false) override
virtual bool ValidateMode(StreamMode) const override
virtual bool IsRoot() const override
virtual SvGlobalName GetClassName() override
virtual bool IsStorage(const OUString &rEleName) const override
UCBStorage_Impl * pImp
Definition: stg.hxx:241
virtual bool IsContained(const OUString &rEleName) const override
UCBStorage(const ::ucbhelper::Content &rContent, const OUString &rName, StreamMode nMode, bool bDirect, bool bIsRoot)
virtual ~UCBStorage() override
virtual OUString GetUserName() override
BaseStorage * OpenStorage_Impl(const OUString &rEleName, StreamMode, bool bDirect, bool bForceUCBStorage)
virtual bool Equals(const BaseStorage &rStream) const override
virtual bool Commit() final override
virtual BaseStorage * OpenOLEStorage(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE, bool bDirect=false) override
virtual void FillInfoList(SvStorageInfoList *) const override
virtual SotClipboardFormatId GetFormat() override
#define SO3_PLUGIN_CLASSID
#define SO3_SDRAW_CLASSID_60
#define SO3_IFRAME_CLASSID
#define SO3_SC_CLASSID_60
#define SO3_OUT_CLASSID
#define SO3_SM_CLASSID_60
#define SO3_SW_CLASSID_60
#define SO3_SWGLOB_CLASSID_60
#define SO3_SCH_CLASSID_60
#define SO3_SIMPRESS_CLASSID_60
#define SO3_SWWEB_CLASSID_60
#define SO3_APPLET_CLASSID
T * get() const
bool is() const
css::uno::Any setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue)
css::uno::Any getPropertyValue(const OUString &rPropertyName)
css::uno::Any executeCommand(const OUString &rCommandName, const css::uno::Any &rCommandArgument)
bool insertNewContent(const OUString &rContentType, const css::uno::Sequence< OUString > &rPropertyNames, const css::uno::Sequence< css::uno::Any > &rPropertyValues, Content &rNewContent)
css::uno::Sequence< css::ucb::ContentInfo > queryCreatableContentsInfo()
css::uno::Reference< css::io::XInputStream > openStream()
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
int nCount
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
URL aURL
float u
#define ERRCODE_IO_ACCESSDENIED
#define SVSTREAM_ACCESS_DENIED
#define ERRCODE_IO_CANTREAD
#define ERRCODE_IO_GENERAL
#define ERRCODE_IO_BROKENPACKAGE
#define ERRCODE_IO_CANTWRITE
#define ERRCODE_IO_WRONGFORMAT
#define ERRCODE_IO_NOTEXISTS
#define ERRCODE_NONE
#define SVSTREAM_CANNOT_MAKE
#define SVSTREAM_FILE_NOT_FOUND
SotClipboardFormatId
Definition: formats.hxx:28
std::mutex m_aMutex
OUString aName
void * p
sal_Int64 n
sal_uInt16 nPos
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
NONE
double getLength(const B2DPolygon &rCandidate)
size
@ Exception
Reference< XComponentContext > getProcessComponentContext()
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
int i
void SvStream & rStrm
m
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
sal_uInt16 const m_nFormat
std::vector< SvStorageInfo > SvStorageInfoList
Definition: storinfo.hxx:56
#define STREAM_SEEK_TO_END
StreamMode
UCBStorageElement_Impl(const OUString &rName, bool bIsFolder=false, sal_uInt64 nSize=0)
Definition: ucbstorage.cxx:539
bool IsModified() const
Definition: ucbstorage.cxx:606
UCBStorage_ImplRef m_xStorage
Definition: ucbstorage.cxx:536
OUString GetContentType() const
Definition: ucbstorage.cxx:570
::ucbhelper::Content * GetContent()
Definition: ucbstorage.cxx:560
UCBStorageStream_ImplRef m_xStream
Definition: ucbstorage.cxx:537
void SetContentType(const OUString &)
Definition: ucbstorage.cxx:583
OUString GetOriginalContentType() const
Definition: ucbstorage.cxx:596
OUString Name
unsigned char sal_uInt8
#define SAL_MAX_UINT32
Reference< XProgressHandler > m_xProgressHandler
tools::SvRef< UCBStorage_Impl > UCBStorage_ImplRef
Definition: ucbstorage.cxx:524
std::vector< std::unique_ptr< UCBStorageElement_Impl > > UCBStorageElementList_Impl
Definition: ucbstorage.cxx:449
static OUString Find_Impl(const Sequence< Sequence< PropertyValue > > &rSequence, std::u16string_view rPath)
static SotClipboardFormatId GetFormatId_Impl(const SvGlobalName &aName)
Definition: ucbstorage.cxx:306
::cppu::WeakImplHelper< XInputStream, XSeekable > FileInputStreamWrapper_Base
Definition: ucbstorage.cxx:86
static SvGlobalName GetClassId_Impl(SotClipboardFormatId nFormat)
Definition: ucbstorage.cxx:338
static int nOpenFiles
Definition: ucbstorage.cxx:82
#define COMMIT_RESULT_FAILURE
Definition: ucbstorage.cxx:302
#define COMMIT_RESULT_NOTHING_TO_DO
Definition: ucbstorage.cxx:303
static int nOpenStreams
Definition: ucbstorage.cxx:83
tools::SvRef< UCBStorageStream_Impl > UCBStorageStream_ImplRef
Definition: ucbstorage.cxx:447
#define COMMIT_RESULT_SUCCESS
Definition: ucbstorage.cxx:304