sw: layout: fix bad split table resulting in empty cell
[LibreOffice.git] / sot / source / sdstor / storage.cxx
blobcb9569db498e93c0e46a3eda99cc849324bcd7cd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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>
41 #include <memory>
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 );
51 else
53 return std::make_unique<SvMemoryStream>();
57 SotStorageStream::SotStorageStream( BaseStorageStream * pStm )
58 : pOwnStm(pStm)
60 assert( pStm );
61 if( StreamMode::WRITE & pStm->GetMode() )
62 m_isWritable = true;
63 else
64 m_isWritable = false;
66 SetError( pStm->GetError() );
67 pStm->ResetError();
70 SotStorageStream::~SotStorageStream()
72 Flush();
73 delete pOwnStm;
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() );
86 return nRet;
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() );
93 return nRet;
96 sal_uInt64 SotStorageStream::SeekPos(sal_uInt64 nPos)
98 sal_uInt64 nRet = pOwnStm->Seek( nPos );
99 SetError( pOwnStm->GetError() );
100 return nRet;
103 void SotStorageStream::FlushData()
105 pOwnStm->Flush();
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 )
116 // jump to the end
117 Seek( nNewSize );
120 sal_uInt32 SotStorageStream::GetSize() const
122 sal_uInt64 nSize = const_cast<SotStorageStream*>(this)->TellEnd();
123 return nSize;
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
130 FlushBuffer();
132 return pOwnStm->GetSize();
135 void SotStorageStream::Commit()
137 pOwnStm->Flush();
138 if( pOwnStm->GetError() == ERRCODE_NONE )
139 pOwnStm->Commit();
140 SetError( pOwnStm->GetError() );
143 bool SotStorageStream::SetProperty( const OUString& rName, const css::uno::Any& rValue )
145 UCBStorageStream* pStg = dynamic_cast<UCBStorageStream*>( pOwnStm );
146 if ( pStg )
148 return pStg->SetProperty( rName, rValue );
150 else
152 OSL_FAIL("Not implemented!");
153 return false;
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
169 * incremented.
170 * The transfer is done in pStorageCTor and the variable is NULL, if it didn't
171 * work.
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 )
184 INIT_SotStorage()
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() )
197 // named storage
198 if( ( nMode & ERASEMASK ) == ERASEMASK )
199 ::utl::UCBContentHelper::Kill( m_aName );
201 INetURLObject aObj( m_aName );
202 if ( aObj.GetProtocol() == INetProtocol::NotValid )
204 OUString aURL;
205 osl::FileBase::getFileURLFromSystemPath( m_aName, aURL );
206 aObj.SetURL( aURL );
207 m_aName = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
210 // check the stream
211 m_pStorStm = ::utl::UcbStreamHelper::CreateStream( m_aName, nMode ).release();
212 if ( m_pStorStm && m_pStorStm->GetError() )
214 delete m_pStorStm;
215 m_pStorStm = nullptr;
218 if ( m_pStorStm )
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 );
226 if ( bIsUCBStorage )
228 // UCBStorage always works directly on the UCB content, so discard the stream first
229 delete m_pStorStm;
230 m_pStorStm = nullptr;
231 m_pOwnStg = new UCBStorage( m_aName, nMode, true, true/*bIsRoot*/ );
233 else
235 // OLEStorage can be opened with a stream
236 m_pOwnStg = new Storage( *m_pStorStm, true );
237 m_bDelStm = true;
240 else if ( bForceUCBStorage )
242 m_pOwnStg = new UCBStorage( m_aName, nMode, true, true/*bIsRoot*/ );
243 SetError( ERRCODE_IO_NOTSUPPORTED );
245 else
247 m_pOwnStg = new Storage( m_aName, nMode, true );
248 SetError( ERRCODE_IO_NOTSUPPORTED );
251 else
253 // temporary storage
254 if ( bForceUCBStorage )
255 m_pOwnStg = new UCBStorage( m_aName, nMode, true, true/*bIsRoot*/ );
256 else
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 )
267 INIT_SotStorage()
269 m_aName = rName;
270 CreateStorage( bUCBStorage, nMode );
271 if ( IsOLEStorage() )
272 m_nVersion = SOFFICE_FILEFORMAT_50;
275 SotStorage::SotStorage( BaseStorage * pStor )
276 INIT_SotStorage()
278 if ( pStor )
280 m_aName = pStor->GetName(); // save name
281 SignAsRoot( pStor->IsRoot() );
282 SetError( pStor->GetError() );
285 m_pOwnStg = pStor;
286 const ErrCode nErr = m_pOwnStg ? m_pOwnStg->GetError() : SVSTREAM_CANNOT_MAKE;
287 SetError( nErr );
288 if ( IsOLEStorage() )
289 m_nVersion = SOFFICE_FILEFORMAT_50;
292 SotStorage::SotStorage( bool bUCBStorage, SvStream & rStm )
293 INIT_SotStorage()
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 );
300 else
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 )
312 INIT_SotStorage()
314 SetError( rStm.GetError() );
316 // try as UCBStorage, next try as OLEStorage
317 if ( UCBStorage::IsStorageFile( &rStm ) )
318 m_pOwnStg = new UCBStorage( rStm, false );
319 else
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 )
331 INIT_SotStorage()
333 SetError( pStm->GetError() );
335 // try as UCBStorage, next try as OLEStorage
336 if ( UCBStorage::IsStorageFile( pStm ) )
337 m_pOwnStg = new UCBStorage( *pStm, false );
338 else
339 m_pOwnStg = new Storage( *pStm, false );
341 SetError( m_pOwnStg->GetError() );
343 m_pStorStm = pStm;
344 m_bDelStm = bDelete;
345 if ( IsOLEStorage() )
346 m_nVersion = SOFFICE_FILEFORMAT_50;
348 SignAsRoot( m_pOwnStg->IsRoot() );
351 SotStorage::~SotStorage()
353 delete m_pOwnStg;
354 if( m_bDelStm )
355 delete m_pStorStm;
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() ) )
364 aStg->Commit();
366 else
368 aStg.clear(); // release storage beforehand
369 pStm.reset();
371 return pStm;
374 bool SotStorage::IsStorageFile( const OUString & rFileName )
376 OUString aName( rFileName );
377 INetURLObject aObj( aName );
378 if ( aObj.GetProtocol() == INetProtocol::NotValid )
380 OUString aURL;
381 osl::FileBase::getFileURLFromSystemPath( aName, aURL );
382 aObj.SetURL( 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() );
388 return bRet;
391 bool SotStorage::IsStorageFile( SvStream* pStream )
393 /** code for new storages must come first! **/
394 if ( pStream )
396 sal_uInt64 nPos = pStream->Tell();
397 bool bRet = UCBStorage::IsStorageFile( pStream );
398 if ( !bRet )
399 bRet = Storage::IsStorageFile( pStream );
400 pStream->Seek( nPos );
401 return bRet;
403 else
404 return false;
407 const OUString & SotStorage::GetName() const
409 if( m_aName.isEmpty() && m_pOwnStg )
410 const_cast<SotStorage *>(this)->m_aName = m_pOwnStg->GetName();
411 return m_aName;
414 void SotStorage::SetClass( const SvGlobalName & rName,
415 SotClipboardFormatId nOriginalClipFormat,
416 const OUString & rUserTypeName )
418 if( m_pOwnStg )
419 m_pOwnStg->SetClass( rName, nOriginalClipFormat, rUserTypeName );
420 else
421 SetError( SVSTREAM_GENERALERROR );
424 SvGlobalName SotStorage::GetClassName()
426 SvGlobalName aGN;
427 if( m_pOwnStg )
428 aGN = m_pOwnStg->GetClassName();
429 else
430 SetError( SVSTREAM_GENERALERROR );
431 return aGN;
434 SotClipboardFormatId SotStorage::GetFormat()
436 SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
437 if( m_pOwnStg )
438 nFormat = m_pOwnStg->GetFormat();
439 else
440 SetError( SVSTREAM_GENERALERROR );
441 return nFormat;
444 OUString SotStorage::GetUserName()
446 OUString aName;
447 if( m_pOwnStg )
448 aName = m_pOwnStg->GetUserName();
449 else
450 SetError( SVSTREAM_GENERALERROR );
451 return aName;
454 void SotStorage::FillInfoList( SvStorageInfoList * pFillList ) const
456 if( m_pOwnStg )
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;
469 else
470 SetError( SVSTREAM_GENERALERROR );
472 return ERRCODE_NONE == GetError();
475 bool SotStorage::Commit()
477 if( m_pOwnStg )
479 if( !m_pOwnStg->Commit() )
480 SetError( m_pOwnStg->GetError() );
482 else
483 SetError( SVSTREAM_GENERALERROR );
485 return ERRCODE_NONE == GetError();
488 rtl::Reference<SotStorageStream> SotStorage::OpenSotStream(const OUString& rEleName,
489 StreamMode nMode )
491 rtl::Reference<SotStorageStream> pStm;
492 if( m_pOwnStg )
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);
501 if( !nE )
502 m_pOwnStg->ResetError(); // don't set error
503 if( nMode & StreamMode::TRUNC )
504 pStm->SetSize( 0 );
506 else
507 SetError( SVSTREAM_GENERALERROR );
509 return pStm;
512 rtl::Reference<SotStorage> SotStorage::OpenSotStorage( const OUString & rEleName,
513 StreamMode nMode,
514 bool transacted )
516 if( m_pOwnStg )
518 nMode |= StreamMode::SHARE_DENYALL;
519 ErrCode nE = m_pOwnStg->GetError();
520 BaseStorage * p = m_pOwnStg->OpenStorage(rEleName, nMode, !transacted);
521 if( p )
523 rtl::Reference<SotStorage> pStor = new SotStorage( p );
524 if( !nE )
525 m_pOwnStg->ResetError(); // don't set error
527 return pStor;
531 SetError( SVSTREAM_GENERALERROR );
533 return nullptr;
536 bool SotStorage::IsStorage( const OUString & rEleName ) const
538 // a little bit faster
539 if( m_pOwnStg )
540 return m_pOwnStg->IsStorage( rEleName );
542 return false;
545 bool SotStorage::IsStream( const OUString & rEleName ) const
547 // a little bit faster
548 if( m_pOwnStg )
549 return m_pOwnStg->IsStream( rEleName );
551 return false;
554 bool SotStorage::IsContained( const OUString & rEleName ) const
556 // a little bit faster
557 if( m_pOwnStg )
558 return m_pOwnStg->IsContained( rEleName );
560 return false;
563 bool SotStorage::Remove( const OUString & rEleName )
565 if( m_pOwnStg )
567 m_pOwnStg->Remove( rEleName );
568 SetError( m_pOwnStg->GetError() );
570 else
571 SetError( SVSTREAM_GENERALERROR );
573 return ERRCODE_NONE == GetError();
576 bool SotStorage::CopyTo( const OUString & rEleName,
577 SotStorage * pNewSt, const OUString & rNewName )
579 if( m_pOwnStg )
581 m_pOwnStg->CopyTo( rEleName, pNewSt->m_pOwnStg, rNewName );
582 SetError( m_pOwnStg->GetError() );
583 SetError( pNewSt->GetError() );
585 else
586 SetError( SVSTREAM_GENERALERROR );
588 return ERRCODE_NONE == GetError();
591 bool SotStorage::Validate()
593 DBG_ASSERT( m_bIsRoot, "Validate only if root storage" );
594 if( m_pOwnStg )
595 return m_pOwnStg->ValidateFAT();
596 else
597 return true;
600 bool SotStorage::IsOLEStorage() const
602 UCBStorage* pStg = dynamic_cast<UCBStorage*>( m_pOwnStg );
603 return !pStg;
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 );
655 if ( !xProps.is() )
656 return SotClipboardFormatId::NONE;
658 OUString aMediaType;
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;
708 default: break;
711 return 0;
714 namespace
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)
724 if (info.IsStream())
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);
752 catch (...)
754 return false;
756 return true;
759 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */