1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <com/sun/star/embed/XStorage.hpp>
24 #include <com/sun/star/embed/ElementModes.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <osl/file.hxx>
28 #include <sot/stg.hxx>
29 #include <sot/storinfo.hxx>
30 #include <sot/storage.hxx>
31 #include <sot/formats.hxx>
32 #include <sot/exchange.hxx>
33 #include <unotools/ucbstreamhelper.hxx>
34 #include <comphelper/diagnose_ex.hxx>
35 #include <tools/debug.hxx>
36 #include <tools/urlobj.hxx>
37 #include <unotools/ucbhelper.hxx>
38 #include <comphelper/fileformat.h>
39 #include <com/sun/star/uno/Reference.h>
43 using namespace ::com::sun::star
;
45 std::unique_ptr
<SvStream
> SotTempStream::Create( const OUString
& rName
, StreamMode nMode
)
47 if( !rName
.isEmpty() )
49 return std::make_unique
<SvFileStream
>( rName
, nMode
);
53 return std::make_unique
<SvMemoryStream
>();
57 SotStorageStream::SotStorageStream( BaseStorageStream
* pStm
)
61 if( StreamMode::WRITE
& pStm
->GetMode() )
66 SetError( pStm
->GetError() );
70 SotStorageStream::~SotStorageStream()
76 void SotStorageStream::ResetError()
78 SvStream::ResetError();
79 pOwnStm
->ResetError();
82 std::size_t SotStorageStream::GetData(void* pData
, std::size_t const nSize
)
84 std::size_t nRet
= pOwnStm
->Read( pData
, nSize
);
85 SetError( pOwnStm
->GetError() );
89 std::size_t SotStorageStream::PutData(const void* pData
, std::size_t const nSize
)
91 std::size_t nRet
= pOwnStm
->Write( pData
, nSize
);
92 SetError( pOwnStm
->GetError() );
96 sal_uInt64
SotStorageStream::SeekPos(sal_uInt64 nPos
)
98 sal_uInt64 nRet
= pOwnStm
->Seek( nPos
);
99 SetError( pOwnStm
->GetError() );
103 void SotStorageStream::FlushData()
106 SetError( pOwnStm
->GetError() );
109 void SotStorageStream::SetSize(sal_uInt64
const nNewSize
)
111 sal_uInt64
const nPos
= Tell();
112 pOwnStm
->SetSize( nNewSize
);
113 SetError( pOwnStm
->GetError() );
115 if( nNewSize
< nPos
)
120 sal_uInt32
SotStorageStream::GetSize() const
122 sal_uInt64 nSize
= const_cast<SotStorageStream
*>(this)->TellEnd();
126 sal_uInt64
SotStorageStream::TellEnd()
128 // Need to flush the buffer so we materialise the stream and return the correct answer
129 // otherwise we return a 0 value from StgEntry::GetSize
132 return pOwnStm
->GetSize();
135 void SotStorageStream::Commit()
138 if( pOwnStm
->GetError() == ERRCODE_NONE
)
140 SetError( pOwnStm
->GetError() );
143 bool SotStorageStream::SetProperty( const OUString
& rName
, const css::uno::Any
& rValue
)
145 UCBStorageStream
* pStg
= dynamic_cast<UCBStorageStream
*>( pOwnStm
);
148 return pStg
->SetProperty( rName
, rValue
);
152 OSL_FAIL("Not implemented!");
158 * SotStorage::SotStorage()
160 * A I... object must be passed to SvObject, because otherwise itself will
161 * create and define an IUnknown, so that all other I... objects would be
162 * destroyed with delete (Owner() == true).
163 * But IStorage objects are only used and not implemented by ourselves,
164 * therefore we pretend the IStorage object was passed from the outside
165 * and it will be freed with Release().
166 * The CreateStorage methods are needed to create an IStorage object before the
167 * call of SvObject (Own, !Own automatic).
168 * If CreateStorage has created an object, then the RefCounter was already
170 * The transfer is done in pStorageCTor and the variable is NULL, if it didn't
173 #define INIT_SotStorage() \
174 : m_pOwnStg( nullptr ) \
175 , m_pStorStm( nullptr ) \
176 , m_nError( ERRCODE_NONE ) \
177 , m_bIsRoot( false ) \
178 , m_bDelStm( false ) \
179 , m_nVersion( SOFFICE_FILEFORMAT_CURRENT )
181 #define ERASEMASK ( StreamMode::TRUNC | StreamMode::WRITE | StreamMode::SHARE_DENYALL )
183 SotStorage::SotStorage( const OUString
& rName
, StreamMode nMode
)
186 m_aName
= rName
; // save name
187 CreateStorage( true, nMode
);
188 if ( IsOLEStorage() )
189 m_nVersion
= SOFFICE_FILEFORMAT_50
;
192 void SotStorage::CreateStorage( bool bForceUCBStorage
, StreamMode nMode
)
194 DBG_ASSERT( !m_pStorStm
&& !m_pOwnStg
, "Use only in ctor!" );
195 if( !m_aName
.isEmpty() )
198 if( ( nMode
& ERASEMASK
) == ERASEMASK
)
199 ::utl::UCBContentHelper::Kill( m_aName
);
201 INetURLObject
aObj( m_aName
);
202 if ( aObj
.GetProtocol() == INetProtocol::NotValid
)
205 osl::FileBase::getFileURLFromSystemPath( m_aName
, aURL
);
207 m_aName
= aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
211 m_pStorStm
= ::utl::UcbStreamHelper::CreateStream( m_aName
, nMode
).release();
212 if ( m_pStorStm
&& m_pStorStm
->GetError() )
215 m_pStorStm
= nullptr;
220 // try as UCBStorage, next try as OLEStorage
221 bool bIsUCBStorage
= UCBStorage::IsStorageFile( m_pStorStm
);
222 if ( !bIsUCBStorage
&& bForceUCBStorage
)
223 // if UCBStorage has priority, it should not be used only if it is really an OLEStorage
224 bIsUCBStorage
= !Storage::IsStorageFile( m_pStorStm
);
228 // UCBStorage always works directly on the UCB content, so discard the stream first
230 m_pStorStm
= nullptr;
231 m_pOwnStg
= new UCBStorage( m_aName
, nMode
, true, true/*bIsRoot*/ );
235 // OLEStorage can be opened with a stream
236 m_pOwnStg
= new Storage( *m_pStorStm
, true );
240 else if ( bForceUCBStorage
)
242 m_pOwnStg
= new UCBStorage( m_aName
, nMode
, true, true/*bIsRoot*/ );
243 SetError( ERRCODE_IO_NOTSUPPORTED
);
247 m_pOwnStg
= new Storage( m_aName
, nMode
, true );
248 SetError( ERRCODE_IO_NOTSUPPORTED
);
254 if ( bForceUCBStorage
)
255 m_pOwnStg
= new UCBStorage( m_aName
, nMode
, true, true/*bIsRoot*/ );
257 m_pOwnStg
= new Storage( m_aName
, nMode
, true );
258 m_aName
= m_pOwnStg
->GetName();
261 SetError( m_pOwnStg
->GetError() );
263 SignAsRoot( m_pOwnStg
->IsRoot() );
266 SotStorage::SotStorage( bool bUCBStorage
, const OUString
& rName
, StreamMode nMode
)
270 CreateStorage( bUCBStorage
, nMode
);
271 if ( IsOLEStorage() )
272 m_nVersion
= SOFFICE_FILEFORMAT_50
;
275 SotStorage::SotStorage( BaseStorage
* pStor
)
280 m_aName
= pStor
->GetName(); // save name
281 SignAsRoot( pStor
->IsRoot() );
282 SetError( pStor
->GetError() );
286 const ErrCode nErr
= m_pOwnStg
? m_pOwnStg
->GetError() : SVSTREAM_CANNOT_MAKE
;
288 if ( IsOLEStorage() )
289 m_nVersion
= SOFFICE_FILEFORMAT_50
;
292 SotStorage::SotStorage( bool bUCBStorage
, SvStream
& rStm
)
295 SetError( rStm
.GetError() );
297 // try as UCBStorage, next try as OLEStorage
298 if ( UCBStorage::IsStorageFile( &rStm
) || bUCBStorage
)
299 m_pOwnStg
= new UCBStorage( rStm
, false );
301 m_pOwnStg
= new Storage( rStm
, false );
303 SetError( m_pOwnStg
->GetError() );
305 if ( IsOLEStorage() )
306 m_nVersion
= SOFFICE_FILEFORMAT_50
;
308 SignAsRoot( m_pOwnStg
->IsRoot() );
311 SotStorage::SotStorage( SvStream
& rStm
)
314 SetError( rStm
.GetError() );
316 // try as UCBStorage, next try as OLEStorage
317 if ( UCBStorage::IsStorageFile( &rStm
) )
318 m_pOwnStg
= new UCBStorage( rStm
, false );
320 m_pOwnStg
= new Storage( rStm
, false );
322 SetError( m_pOwnStg
->GetError() );
324 if ( IsOLEStorage() )
325 m_nVersion
= SOFFICE_FILEFORMAT_50
;
327 SignAsRoot( m_pOwnStg
->IsRoot() );
330 SotStorage::SotStorage( SvStream
* pStm
, bool bDelete
)
333 SetError( pStm
->GetError() );
335 // try as UCBStorage, next try as OLEStorage
336 if ( UCBStorage::IsStorageFile( pStm
) )
337 m_pOwnStg
= new UCBStorage( *pStm
, false );
339 m_pOwnStg
= new Storage( *pStm
, false );
341 SetError( m_pOwnStg
->GetError() );
345 if ( IsOLEStorage() )
346 m_nVersion
= SOFFICE_FILEFORMAT_50
;
348 SignAsRoot( m_pOwnStg
->IsRoot() );
351 SotStorage::~SotStorage()
358 std::unique_ptr
<SvMemoryStream
> SotStorage::CreateMemoryStream()
360 std::unique_ptr
<SvMemoryStream
> pStm(new SvMemoryStream( 0x8000, 0x8000 ));
361 rtl::Reference
<SotStorage
> aStg
= new SotStorage(*pStm
);
362 if( CopyTo( aStg
.get() ) )
368 aStg
.clear(); // release storage beforehand
374 bool SotStorage::IsStorageFile( const OUString
& rFileName
)
376 OUString
aName( rFileName
);
377 INetURLObject
aObj( aName
);
378 if ( aObj
.GetProtocol() == INetProtocol::NotValid
)
381 osl::FileBase::getFileURLFromSystemPath( aName
, aURL
);
383 aName
= aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
386 std::unique_ptr
<SvStream
> pStm(::utl::UcbStreamHelper::CreateStream( aName
, StreamMode::STD_READ
));
387 bool bRet
= SotStorage::IsStorageFile( pStm
.get() );
391 bool SotStorage::IsStorageFile( SvStream
* pStream
)
393 /** code for new storages must come first! **/
396 sal_uInt64 nPos
= pStream
->Tell();
397 bool bRet
= UCBStorage::IsStorageFile( pStream
);
399 bRet
= Storage::IsStorageFile( pStream
);
400 pStream
->Seek( nPos
);
407 const OUString
& SotStorage::GetName() const
409 if( m_aName
.isEmpty() && m_pOwnStg
)
410 const_cast<SotStorage
*>(this)->m_aName
= m_pOwnStg
->GetName();
414 void SotStorage::SetClass( const SvGlobalName
& rName
,
415 SotClipboardFormatId nOriginalClipFormat
,
416 const OUString
& rUserTypeName
)
419 m_pOwnStg
->SetClass( rName
, nOriginalClipFormat
, rUserTypeName
);
421 SetError( SVSTREAM_GENERALERROR
);
424 SvGlobalName
SotStorage::GetClassName()
428 aGN
= m_pOwnStg
->GetClassName();
430 SetError( SVSTREAM_GENERALERROR
);
434 SotClipboardFormatId
SotStorage::GetFormat()
436 SotClipboardFormatId nFormat
= SotClipboardFormatId::NONE
;
438 nFormat
= m_pOwnStg
->GetFormat();
440 SetError( SVSTREAM_GENERALERROR
);
444 OUString
SotStorage::GetUserName()
448 aName
= m_pOwnStg
->GetUserName();
450 SetError( SVSTREAM_GENERALERROR
);
454 void SotStorage::FillInfoList( SvStorageInfoList
* pFillList
) const
457 m_pOwnStg
->FillInfoList( pFillList
);
460 bool SotStorage::CopyTo( SotStorage
* pDestStg
)
462 if( m_pOwnStg
&& pDestStg
->m_pOwnStg
)
464 m_pOwnStg
->CopyTo( *pDestStg
->m_pOwnStg
);
465 SetError( m_pOwnStg
->GetError() );
466 pDestStg
->m_aKey
= m_aKey
;
467 pDestStg
->m_nVersion
= m_nVersion
;
470 SetError( SVSTREAM_GENERALERROR
);
472 return ERRCODE_NONE
== GetError();
475 bool SotStorage::Commit()
479 if( !m_pOwnStg
->Commit() )
480 SetError( m_pOwnStg
->GetError() );
483 SetError( SVSTREAM_GENERALERROR
);
485 return ERRCODE_NONE
== GetError();
488 rtl::Reference
<SotStorageStream
> SotStorage::OpenSotStream(const OUString
& rEleName
,
491 rtl::Reference
<SotStorageStream
> pStm
;
494 // enable full Ole patches,
495 // regardless what is coming, only exclusively allowed
496 nMode
|= StreamMode::SHARE_DENYALL
;
497 ErrCode nE
= m_pOwnStg
->GetError();
498 BaseStorageStream
* p
= m_pOwnStg
->OpenStream( rEleName
, nMode
);
499 pStm
= new SotStorageStream(p
);
502 m_pOwnStg
->ResetError(); // don't set error
503 if( nMode
& StreamMode::TRUNC
)
507 SetError( SVSTREAM_GENERALERROR
);
512 rtl::Reference
<SotStorage
> SotStorage::OpenSotStorage( const OUString
& rEleName
,
518 nMode
|= StreamMode::SHARE_DENYALL
;
519 ErrCode nE
= m_pOwnStg
->GetError();
520 BaseStorage
* p
= m_pOwnStg
->OpenStorage(rEleName
, nMode
, !transacted
);
523 rtl::Reference
<SotStorage
> pStor
= new SotStorage( p
);
525 m_pOwnStg
->ResetError(); // don't set error
531 SetError( SVSTREAM_GENERALERROR
);
536 bool SotStorage::IsStorage( const OUString
& rEleName
) const
538 // a little bit faster
540 return m_pOwnStg
->IsStorage( rEleName
);
545 bool SotStorage::IsStream( const OUString
& rEleName
) const
547 // a little bit faster
549 return m_pOwnStg
->IsStream( rEleName
);
554 bool SotStorage::IsContained( const OUString
& rEleName
) const
556 // a little bit faster
558 return m_pOwnStg
->IsContained( rEleName
);
563 bool SotStorage::Remove( const OUString
& rEleName
)
567 m_pOwnStg
->Remove( rEleName
);
568 SetError( m_pOwnStg
->GetError() );
571 SetError( SVSTREAM_GENERALERROR
);
573 return ERRCODE_NONE
== GetError();
576 bool SotStorage::CopyTo( const OUString
& rEleName
,
577 SotStorage
* pNewSt
, const OUString
& rNewName
)
581 m_pOwnStg
->CopyTo( rEleName
, pNewSt
->m_pOwnStg
, rNewName
);
582 SetError( m_pOwnStg
->GetError() );
583 SetError( pNewSt
->GetError() );
586 SetError( SVSTREAM_GENERALERROR
);
588 return ERRCODE_NONE
== GetError();
591 bool SotStorage::Validate()
593 DBG_ASSERT( m_bIsRoot
, "Validate only if root storage" );
595 return m_pOwnStg
->ValidateFAT();
600 bool SotStorage::IsOLEStorage() const
602 UCBStorage
* pStg
= dynamic_cast<UCBStorage
*>( m_pOwnStg
);
606 bool SotStorage::IsOLEStorage( const OUString
& rFileName
)
608 return Storage::IsStorageFile( rFileName
);
611 bool SotStorage::IsOLEStorage( SvStream
* pStream
)
613 return Storage::IsStorageFile( pStream
);
616 rtl::Reference
<SotStorage
> SotStorage::OpenOLEStorage( const css::uno::Reference
< css::embed::XStorage
>& xStorage
,
617 const OUString
& rEleName
, StreamMode nMode
)
619 sal_Int32 nEleMode
= embed::ElementModes::SEEKABLEREAD
;
620 if ( nMode
& StreamMode::WRITE
)
621 nEleMode
|= embed::ElementModes::WRITE
;
622 if ( nMode
& StreamMode::TRUNC
)
623 nEleMode
|= embed::ElementModes::TRUNCATE
;
624 if ( nMode
& StreamMode::NOCREATE
)
625 nEleMode
|= embed::ElementModes::NOCREATE
;
627 std::unique_ptr
<SvStream
> pStream
;
630 uno::Reference
< io::XStream
> xStream
= xStorage
->openStreamElement( rEleName
, nEleMode
);
632 // TODO/LATER: should it be done this way?
633 if ( nMode
& StreamMode::WRITE
)
635 uno::Reference
< beans::XPropertySet
> xStreamProps( xStream
, uno::UNO_QUERY_THROW
);
636 xStreamProps
->setPropertyValue( u
"MediaType"_ustr
,
637 uno::Any( u
"application/vnd.sun.star.oleobject"_ustr
) );
640 pStream
= utl::UcbStreamHelper::CreateStream( xStream
);
642 catch ( uno::Exception
& )
644 //TODO/LATER: ErrorHandling
645 pStream
.reset( new SvMemoryStream
);
646 pStream
->SetError( ERRCODE_IO_GENERAL
);
649 return new SotStorage( pStream
.release(), true );
652 SotClipboardFormatId
SotStorage::GetFormatID( const css::uno::Reference
< css::embed::XStorage
>& xStorage
)
654 uno::Reference
< beans::XPropertySet
> xProps( xStorage
, uno::UNO_QUERY
);
656 return SotClipboardFormatId::NONE
;
661 xProps
->getPropertyValue(u
"MediaType"_ustr
) >>= aMediaType
;
663 catch (uno::Exception
const&)
665 TOOLS_INFO_EXCEPTION("sot", "SotStorage::GetFormatID");
668 if ( !aMediaType
.isEmpty() )
670 css::datatransfer::DataFlavor aDataFlavor
;
671 aDataFlavor
.MimeType
= aMediaType
;
672 return SotExchange::GetFormat( aDataFlavor
);
675 return SotClipboardFormatId::NONE
;
678 sal_Int32
SotStorage::GetVersion( const css::uno::Reference
< css::embed::XStorage
>& xStorage
)
680 SotClipboardFormatId nSotFormatID
= SotStorage::GetFormatID( xStorage
);
681 switch( nSotFormatID
)
683 case SotClipboardFormatId::STARWRITER_8
:
684 case SotClipboardFormatId::STARWRITER_8_TEMPLATE
:
685 case SotClipboardFormatId::STARWRITERWEB_8
:
686 case SotClipboardFormatId::STARWRITERGLOB_8
:
687 case SotClipboardFormatId::STARWRITERGLOB_8_TEMPLATE
:
688 case SotClipboardFormatId::STARDRAW_8
:
689 case SotClipboardFormatId::STARDRAW_8_TEMPLATE
:
690 case SotClipboardFormatId::STARIMPRESS_8
:
691 case SotClipboardFormatId::STARIMPRESS_8_TEMPLATE
:
692 case SotClipboardFormatId::STARCALC_8
:
693 case SotClipboardFormatId::STARCALC_8_TEMPLATE
:
694 case SotClipboardFormatId::STARCHART_8
:
695 case SotClipboardFormatId::STARCHART_8_TEMPLATE
:
696 case SotClipboardFormatId::STARMATH_8
:
697 case SotClipboardFormatId::STARMATH_8_TEMPLATE
:
698 return SOFFICE_FILEFORMAT_8
;
699 case SotClipboardFormatId::STARWRITER_60
:
700 case SotClipboardFormatId::STARWRITERWEB_60
:
701 case SotClipboardFormatId::STARWRITERGLOB_60
:
702 case SotClipboardFormatId::STARDRAW_60
:
703 case SotClipboardFormatId::STARIMPRESS_60
:
704 case SotClipboardFormatId::STARCALC_60
:
705 case SotClipboardFormatId::STARCHART_60
:
706 case SotClipboardFormatId::STARMATH_60
:
707 return SOFFICE_FILEFORMAT_60
;
716 void traverse(const rtl::Reference
<SotStorage
>& rStorage
, std::vector
<unsigned char>& rBuf
)
718 SvStorageInfoList infos
;
720 rStorage
->FillInfoList(&infos
);
722 for (const auto& info
: infos
)
726 // try to open and read all content
727 rtl::Reference
<SotStorageStream
> xStream(rStorage
->OpenSotStream(info
.GetName(), StreamMode::STD_READ
));
728 const size_t nSize
= xStream
->GetSize();
729 const size_t nRead
= xStream
->ReadBytes(rBuf
.data(), nSize
);
730 SAL_INFO("sot", "Read " << nRead
<< "bytes");
732 else if (info
.IsStorage())
734 rtl::Reference
<SotStorage
> xStorage(rStorage
->OpenSotStorage(info
.GetName(), StreamMode::STD_READ
));
736 // continue with children
737 traverse(xStorage
, rBuf
);
743 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportOLE2(SvStream
&rStream
)
747 size_t nSize
= rStream
.remainingSize();
748 rtl::Reference
<SotStorage
> xRootStorage(new SotStorage(&rStream
, false));
749 std::vector
<unsigned char> aTmpBuf(nSize
);
750 traverse(xRootStorage
, aTmpBuf
);
759 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */