summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/excel/xestream.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/excel/xestream.cxx')
-rw-r--r--sc/source/filter/excel/xestream.cxx1259
1 files changed, 1259 insertions, 0 deletions
diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx
new file mode 100644
index 000000000..f0486cc37
--- /dev/null
+++ b/sc/source/filter/excel/xestream.cxx
@@ -0,0 +1,1259 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <utility>
+
+#include <filter/msfilter/util.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/random.h>
+#include <sax/fshelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <sot/storage.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <officecfg/Office/Calc.hxx>
+
+#include <docuno.hxx>
+#include <xestream.hxx>
+#include <xladdress.hxx>
+#include <xlstring.hxx>
+#include <xltools.hxx>
+#include <xeroot.hxx>
+#include <xestring.hxx>
+#include <xlstyle.hxx>
+#include <rangelst.hxx>
+#include <compiler.hxx>
+#include <formulacell.hxx>
+#include <tokenarray.hxx>
+#include <tokenstringcontext.hxx>
+#include <refreshtimerprotector.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <root.hxx>
+#include <sfx2/app.hxx>
+
+#include <docsh.hxx>
+#include <viewdata.hxx>
+#include <excdoc.hxx>
+
+#include <oox/token/tokens.hxx>
+#include <oox/token/relationship.hxx>
+#include <oox/export/drawingml.hxx>
+#include <oox/export/utils.hxx>
+#include <formula/grammar.hxx>
+#include <oox/ole/vbaexport.hxx>
+#include <excelvbaproject.hxx>
+
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <memory>
+#include <comphelper/storagehelper.hxx>
+
+#include <externalrefmgr.hxx>
+
+#define DEBUG_XL_ENCRYPTION 0
+
+using ::com::sun::star::uno::XInterface;
+using ::std::vector;
+
+using namespace com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+using namespace ::formula;
+using namespace ::oox;
+
+XclExpStream::XclExpStream( SvStream& rOutStrm, const XclExpRoot& rRoot, sal_uInt16 nMaxRecSize ) :
+ mrStrm( rOutStrm ),
+ mrRoot( rRoot ),
+ mbUseEncrypter( false ),
+ mnMaxRecSize( nMaxRecSize ),
+ mnCurrMaxSize( 0 ),
+ mnMaxSliceSize( 0 ),
+ mnHeaderSize( 0 ),
+ mnCurrSize( 0 ),
+ mnSliceSize( 0 ),
+ mnPredictSize( 0 ),
+ mnLastSizePos( 0 ),
+ mbInRec( false )
+{
+ if( mnMaxRecSize == 0 )
+ mnMaxRecSize = (mrRoot.GetBiff() <= EXC_BIFF5) ? EXC_MAXRECSIZE_BIFF5 : EXC_MAXRECSIZE_BIFF8;
+ mnMaxContSize = mnMaxRecSize;
+}
+
+XclExpStream::~XclExpStream()
+{
+ mrStrm.FlushBuffer();
+}
+
+void XclExpStream::StartRecord( sal_uInt16 nRecId, std::size_t nRecSize )
+{
+ OSL_ENSURE( !mbInRec, "XclExpStream::StartRecord - another record still open" );
+ DisableEncryption();
+ mnMaxContSize = mnCurrMaxSize = mnMaxRecSize;
+ mnPredictSize = nRecSize;
+ mbInRec = true;
+ InitRecord( nRecId );
+ SetSliceSize( 0 );
+ EnableEncryption();
+}
+
+void XclExpStream::EndRecord()
+{
+ OSL_ENSURE( mbInRec, "XclExpStream::EndRecord - no record open" );
+ DisableEncryption();
+ UpdateRecSize();
+ mrStrm.Seek( STREAM_SEEK_TO_END );
+ mbInRec = false;
+}
+
+void XclExpStream::SetSliceSize( sal_uInt16 nSize )
+{
+ mnMaxSliceSize = nSize;
+ mnSliceSize = 0;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_Int8 nValue )
+{
+ PrepareWrite( 1 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm.WriteSChar( nValue );
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue )
+{
+ PrepareWrite( 1 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm.WriteUChar( nValue );
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_Int16 nValue )
+{
+ PrepareWrite( 2 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm.WriteInt16( nValue );
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue )
+{
+ PrepareWrite( 2 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm.WriteUInt16( nValue );
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_Int32 nValue )
+{
+ PrepareWrite( 4 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm.WriteInt32( nValue );
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue )
+{
+ PrepareWrite( 4 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm.WriteUInt32( nValue );
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( float fValue )
+{
+ PrepareWrite( 4 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, fValue);
+ else
+ mrStrm.WriteFloat( fValue );
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( double fValue )
+{
+ PrepareWrite( 8 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, fValue);
+ else
+ mrStrm.WriteDouble( fValue );
+ return *this;
+}
+
+std::size_t XclExpStream::Write( const void* pData, std::size_t nBytes )
+{
+ std::size_t nRet = 0;
+ if( pData && (nBytes > 0) )
+ {
+ if( mbInRec )
+ {
+ const sal_uInt8* pBuffer = static_cast< const sal_uInt8* >( pData );
+ std::size_t nBytesLeft = nBytes;
+ bool bValid = true;
+
+ while( bValid && (nBytesLeft > 0) )
+ {
+ std::size_t nWriteLen = ::std::min< std::size_t >( PrepareWrite(), nBytesLeft );
+ std::size_t nWriteRet = nWriteLen;
+ if (mbUseEncrypter && HasValidEncrypter())
+ {
+ OSL_ENSURE(nWriteLen > 0, "XclExpStream::Write: write length is 0!");
+ vector<sal_uInt8> aBytes(nWriteLen);
+ memcpy(aBytes.data(), pBuffer, nWriteLen);
+ mxEncrypter->EncryptBytes(mrStrm, aBytes);
+ // TODO: How do I check if all the bytes have been successfully written ?
+ }
+ else
+ {
+ nWriteRet = mrStrm.WriteBytes(pBuffer, nWriteLen);
+ bValid = (nWriteLen == nWriteRet);
+ OSL_ENSURE( bValid, "XclExpStream::Write - stream write error" );
+ }
+ pBuffer += nWriteRet;
+ nRet += nWriteRet;
+ nBytesLeft -= nWriteRet;
+ UpdateSizeVars( nWriteRet );
+ }
+ }
+ else
+ nRet = mrStrm.WriteBytes(pData, nBytes);
+ }
+ return nRet;
+}
+
+void XclExpStream::WriteZeroBytes( std::size_t nBytes )
+{
+ if( mbInRec )
+ {
+ std::size_t nBytesLeft = nBytes;
+ while( nBytesLeft > 0 )
+ {
+ std::size_t nWriteLen = ::std::min< std::size_t >( PrepareWrite(), nBytesLeft );
+ WriteRawZeroBytes( nWriteLen );
+ nBytesLeft -= nWriteLen;
+ UpdateSizeVars( nWriteLen );
+ }
+ }
+ else
+ WriteRawZeroBytes( nBytes );
+}
+
+void XclExpStream::WriteZeroBytesToRecord( std::size_t nBytes )
+{
+ if (!mbInRec)
+ // not in record.
+ return;
+
+ for (std::size_t i = 0; i < nBytes; ++i)
+ *this << sal_uInt8(0)/*nZero*/;
+}
+
+void XclExpStream::CopyFromStream(SvStream& rInStrm, sal_uInt64 const nBytes)
+{
+ sal_uInt64 const nRemaining(rInStrm.remainingSize());
+ sal_uInt64 nBytesLeft = ::std::min(nBytes, nRemaining);
+ if( nBytesLeft <= 0 )
+ return;
+
+ const std::size_t nMaxBuffer = 4096;
+ std::unique_ptr<sal_uInt8[]> pBuffer(
+ new sal_uInt8[ ::std::min<std::size_t>(nBytesLeft, nMaxBuffer) ]);
+ bool bValid = true;
+
+ while( bValid && (nBytesLeft > 0) )
+ {
+ std::size_t nWriteLen = ::std::min<std::size_t>(nBytesLeft, nMaxBuffer);
+ rInStrm.ReadBytes(pBuffer.get(), nWriteLen);
+ std::size_t nWriteRet = Write( pBuffer.get(), nWriteLen );
+ bValid = (nWriteLen == nWriteRet);
+ nBytesLeft -= nWriteRet;
+ }
+}
+
+void XclExpStream::WriteUnicodeBuffer( const ScfUInt16Vec& rBuffer, sal_uInt8 nFlags )
+{
+ SetSliceSize( 0 );
+ nFlags &= EXC_STRF_16BIT; // repeat only 16bit flag
+ sal_uInt16 nCharLen = nFlags ? 2 : 1;
+
+ for( const auto& rItem : rBuffer )
+ {
+ if( mbInRec && (mnCurrSize + nCharLen > mnCurrMaxSize) )
+ {
+ StartContinue();
+ operator<<( nFlags );
+ }
+ if( nCharLen == 2 )
+ operator<<( rItem );
+ else
+ operator<<( static_cast< sal_uInt8 >( rItem ) );
+ }
+}
+
+// Xcl has an obscure sense of whether starting a new record or not,
+// and crashes if it encounters the string header at the very end of a record.
+// Thus we add 1 to give some room, seems like they do it that way but with another count (10?)
+void XclExpStream::WriteByteString( const OString& rString )
+{
+ SetSliceSize( 0 );
+ std::size_t nLen = ::std::min< std::size_t >( rString.getLength(), 0x00FF );
+ nLen = ::std::min< std::size_t >( nLen, 0xFF );
+
+ sal_uInt16 nLeft = PrepareWrite();
+ if( mbInRec && (nLeft <= 1) )
+ StartContinue();
+
+ operator<<( static_cast< sal_uInt8 >( nLen ) );
+ Write( rString.getStr(), nLen );
+}
+
+void XclExpStream::WriteCharBuffer( const ScfUInt8Vec& rBuffer )
+{
+ SetSliceSize( 0 );
+ Write( rBuffer.data(), rBuffer.size() );
+}
+
+void XclExpStream::SetEncrypter( XclExpEncrypterRef const & xEncrypter )
+{
+ mxEncrypter = xEncrypter;
+}
+
+bool XclExpStream::HasValidEncrypter() const
+{
+ return mxEncrypter && mxEncrypter->IsValid();
+}
+
+void XclExpStream::EnableEncryption( bool bEnable )
+{
+ mbUseEncrypter = bEnable && HasValidEncrypter();
+}
+
+void XclExpStream::DisableEncryption()
+{
+ EnableEncryption(false);
+}
+
+void XclExpStream::SetSvStreamPos(sal_uInt64 const nPos)
+{
+ OSL_ENSURE( !mbInRec, "XclExpStream::SetSvStreamPos - not allowed inside of a record" );
+ mbInRec ? 0 : mrStrm.Seek( nPos );
+}
+
+// private --------------------------------------------------------------------
+
+void XclExpStream::InitRecord( sal_uInt16 nRecId )
+{
+ mrStrm.Seek( STREAM_SEEK_TO_END );
+ mrStrm.WriteUInt16( nRecId );
+
+ mnLastSizePos = mrStrm.Tell();
+ mnHeaderSize = static_cast< sal_uInt16 >( ::std::min< std::size_t >( mnPredictSize, mnCurrMaxSize ) );
+ mrStrm.WriteUInt16( mnHeaderSize );
+ mnCurrSize = mnSliceSize = 0;
+}
+
+void XclExpStream::UpdateRecSize()
+{
+ if( mnCurrSize != mnHeaderSize )
+ {
+ mrStrm.Seek( mnLastSizePos );
+ mrStrm.WriteUInt16( mnCurrSize );
+ }
+}
+
+void XclExpStream::UpdateSizeVars( std::size_t nSize )
+{
+ OSL_ENSURE( mnCurrSize + nSize <= mnCurrMaxSize, "XclExpStream::UpdateSizeVars - record overwritten" );
+ mnCurrSize = mnCurrSize + static_cast< sal_uInt16 >( nSize );
+
+ if( mnMaxSliceSize > 0 )
+ {
+ OSL_ENSURE( mnSliceSize + nSize <= mnMaxSliceSize, "XclExpStream::UpdateSizeVars - slice overwritten" );
+ mnSliceSize = mnSliceSize + static_cast< sal_uInt16 >( nSize );
+ if( mnSliceSize >= mnMaxSliceSize )
+ mnSliceSize = 0;
+ }
+}
+
+void XclExpStream::StartContinue()
+{
+ UpdateRecSize();
+ mnCurrMaxSize = mnMaxContSize;
+ mnPredictSize -= mnCurrSize;
+ InitRecord( EXC_ID_CONT );
+}
+
+void XclExpStream::PrepareWrite( sal_uInt16 nSize )
+{
+ if( mbInRec )
+ {
+ if( (mnCurrSize + nSize > mnCurrMaxSize) ||
+ ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
+ StartContinue();
+ UpdateSizeVars( nSize );
+ }
+}
+
+sal_uInt16 XclExpStream::PrepareWrite()
+{
+ sal_uInt16 nRet = 0;
+ if( mbInRec )
+ {
+ if( (mnCurrSize >= mnCurrMaxSize) ||
+ ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
+ StartContinue();
+ UpdateSizeVars( 0 );
+
+ nRet = (mnMaxSliceSize > 0) ? (mnMaxSliceSize - mnSliceSize) : (mnCurrMaxSize - mnCurrSize);
+ }
+ return nRet;
+}
+
+void XclExpStream::WriteRawZeroBytes( std::size_t nBytes )
+{
+ const sal_uInt32 nData = 0;
+ std::size_t nBytesLeft = nBytes;
+ while( nBytesLeft >= sizeof( nData ) )
+ {
+ mrStrm.WriteUInt32( nData );
+ nBytesLeft -= sizeof( nData );
+ }
+ if( nBytesLeft )
+ mrStrm.WriteBytes(&nData, nBytesLeft);
+}
+
+XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot& rRoot ) :
+ mnOldPos(STREAM_SEEK_TO_END),
+ mbValid(false)
+{
+ Sequence< NamedValue > aEncryptionData = rRoot.GetEncryptionData();
+ if( !aEncryptionData.hasElements() )
+ // Empty password. Get the default biff8 password.
+ aEncryptionData = XclExpRoot::GenerateDefaultEncryptionData();
+ Init( aEncryptionData );
+}
+
+XclExpBiff8Encrypter::~XclExpBiff8Encrypter()
+{
+}
+
+void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 pnSaltDigest[16] ) const
+{
+ if ( sizeof( mpnSaltDigest ) == 16 )
+ memcpy( pnSaltDigest, mpnSaltDigest, 16 );
+}
+
+void XclExpBiff8Encrypter::GetSalt( sal_uInt8 pnSalt[16] ) const
+{
+ if ( sizeof( mpnSalt ) == 16 )
+ memcpy( pnSalt, mpnSalt, 16 );
+}
+
+void XclExpBiff8Encrypter::GetDocId( sal_uInt8 pnDocId[16] ) const
+{
+ if ( sizeof( mpnDocId ) == 16 )
+ memcpy( pnDocId, mpnDocId, 16 );
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt8 nData )
+{
+ vector<sal_uInt8> aByte { nData };
+ EncryptBytes(rStrm, aByte);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt16 nData )
+{
+ ::std::vector<sal_uInt8> pnBytes
+ {
+ o3tl::narrowing<sal_uInt8>(nData & 0xFF),
+ o3tl::narrowing<sal_uInt8>((nData >> 8) & 0xFF)
+ };
+ EncryptBytes(rStrm, pnBytes);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt32 nData )
+{
+ ::std::vector<sal_uInt8> pnBytes
+ {
+ o3tl::narrowing<sal_uInt8>(nData & 0xFF),
+ o3tl::narrowing<sal_uInt8>((nData >> 8) & 0xFF),
+ o3tl::narrowing<sal_uInt8>((nData >> 16) & 0xFF),
+ o3tl::narrowing<sal_uInt8>((nData >> 24) & 0xFF)
+ };
+ EncryptBytes(rStrm, pnBytes);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, float fValue )
+{
+ ::std::vector<sal_uInt8> pnBytes(4);
+ memcpy(pnBytes.data(), &fValue, 4);
+ EncryptBytes(rStrm, pnBytes);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, double fValue )
+{
+ ::std::vector<sal_uInt8> pnBytes(8);
+ memcpy(pnBytes.data(), &fValue, 8);
+ EncryptBytes(rStrm, pnBytes);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int8 nData )
+{
+ Encrypt(rStrm, static_cast<sal_uInt8>(nData));
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int16 nData )
+{
+ Encrypt(rStrm, static_cast<sal_uInt16>(nData));
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int32 nData )
+{
+ Encrypt(rStrm, static_cast<sal_uInt32>(nData));
+}
+
+void XclExpBiff8Encrypter::Init( const Sequence< NamedValue >& rEncryptionData )
+{
+ mbValid = false;
+
+ if( !maCodec.InitCodec( rEncryptionData ) )
+ return;
+
+ maCodec.GetDocId( mpnDocId );
+
+ // generate the salt here
+ rtlRandomPool aRandomPool = rtl_random_createPool ();
+ rtl_random_getBytes( aRandomPool, mpnSalt, 16 );
+ rtl_random_destroyPool( aRandomPool );
+
+ memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) );
+
+ // generate salt hash.
+ ::msfilter::MSCodec_Std97 aCodec;
+ aCodec.InitCodec( rEncryptionData );
+ aCodec.CreateSaltDigest( mpnSalt, mpnSaltDigest );
+
+ // verify to make sure it's in good shape.
+ mbValid = maCodec.VerifyKey( mpnSalt, mpnSaltDigest );
+}
+
+sal_uInt32 XclExpBiff8Encrypter::GetBlockPos( std::size_t nStrmPos )
+{
+ return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
+}
+
+sal_uInt16 XclExpBiff8Encrypter::GetOffsetInBlock( std::size_t nStrmPos )
+{
+ return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
+}
+
+void XclExpBiff8Encrypter::EncryptBytes( SvStream& rStrm, vector<sal_uInt8>& aBytes )
+{
+ sal_uInt64 nStrmPos = rStrm.Tell();
+ sal_uInt16 nBlockOffset = GetOffsetInBlock(nStrmPos);
+ sal_uInt32 nBlockPos = GetBlockPos(nStrmPos);
+
+#if DEBUG_XL_ENCRYPTION
+ fprintf(stdout, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld offset in block = %d block pos = %ld\n",
+ nStrmPos, nBlockOffset, nBlockPos);
+#endif
+
+ sal_uInt16 nSize = static_cast< sal_uInt16 >( aBytes.size() );
+ if (nSize == 0)
+ return;
+
+#if DEBUG_XL_ENCRYPTION
+ fprintf(stdout, "RAW: ");
+ for (sal_uInt16 i = 0; i < nSize; ++i)
+ fprintf(stdout, "%2.2X ", aBytes[i]);
+ fprintf(stdout, "\n");
+#endif
+
+ if (mnOldPos != nStrmPos)
+ {
+ sal_uInt16 nOldOffset = GetOffsetInBlock(mnOldPos);
+ sal_uInt32 nOldBlockPos = GetBlockPos(mnOldPos);
+
+ if ( (nBlockPos != nOldBlockPos) || (nBlockOffset < nOldOffset) )
+ {
+ maCodec.InitCipher(nBlockPos);
+ nOldOffset = 0;
+ }
+
+ if (nBlockOffset > nOldOffset)
+ maCodec.Skip(nBlockOffset - nOldOffset);
+ }
+
+ sal_uInt16 nBytesLeft = nSize;
+ sal_uInt16 nPos = 0;
+ while (nBytesLeft > 0)
+ {
+ sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - nBlockOffset;
+ sal_uInt16 nEncBytes = ::std::min(nBlockLeft, nBytesLeft);
+
+ bool bRet = maCodec.Encode(&aBytes[nPos], nEncBytes, &aBytes[nPos], nEncBytes);
+ OSL_ENSURE(bRet, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!");
+
+ std::size_t nRet = rStrm.WriteBytes(&aBytes[nPos], nEncBytes);
+ OSL_ENSURE(nRet == nEncBytes, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!");
+
+ nStrmPos = rStrm.Tell();
+ nBlockOffset = GetOffsetInBlock(nStrmPos);
+ nBlockPos = GetBlockPos(nStrmPos);
+ if (nBlockOffset == 0)
+ maCodec.InitCipher(nBlockPos);
+
+ nBytesLeft -= nEncBytes;
+ nPos += nEncBytes;
+ }
+ mnOldPos = nStrmPos;
+}
+
+static const char* lcl_GetErrorString( FormulaError nScErrCode )
+{
+ sal_uInt8 nXclErrCode = XclTools::GetXclErrorCode( nScErrCode );
+ switch( nXclErrCode )
+ {
+ case EXC_ERR_NULL: return "#NULL!";
+ case EXC_ERR_DIV0: return "#DIV/0!";
+ case EXC_ERR_VALUE: return "#VALUE!";
+ case EXC_ERR_REF: return "#REF!";
+ case EXC_ERR_NAME: return "#NAME?";
+ case EXC_ERR_NUM: return "#NUM!";
+ case EXC_ERR_NA:
+ default: return "#N/A";
+ }
+}
+
+void XclXmlUtils::GetFormulaTypeAndValue( ScFormulaCell& rCell, const char*& rsType, OUString& rsValue )
+{
+ sc::FormulaResultValue aResValue = rCell.GetResult();
+
+ switch (aResValue.meType)
+ {
+ case sc::FormulaResultValue::Error:
+ rsType = "e";
+ rsValue = ToOUString(lcl_GetErrorString(aResValue.mnError));
+ break;
+ case sc::FormulaResultValue::Value:
+ rsType = rCell.GetFormatType() == SvNumFormatType::LOGICAL
+ && (aResValue.mfValue == 0.0 || aResValue.mfValue == 1.0)
+ ? "b"
+ : "n";
+ rsValue = OUString::number(aResValue.mfValue);
+ break;
+ case sc::FormulaResultValue::String:
+ rsType = "str";
+ rsValue = rCell.GetString().getString();
+ break;
+ case sc::FormulaResultValue::Invalid:
+ default:
+ // TODO : double-check this to see if this is correct.
+ rsType = "inlineStr";
+ rsValue = rCell.GetString().getString();
+ }
+}
+
+OUString XclXmlUtils::GetStreamName( const char* sStreamDir, const char* sStream, sal_Int32 nId )
+{
+ OUStringBuffer sBuf;
+ if( sStreamDir )
+ sBuf.appendAscii( sStreamDir );
+ sBuf.appendAscii( sStream );
+ if( nId )
+ sBuf.append( nId );
+ if( strstr(sStream, "vml") )
+ sBuf.append( ".vml" );
+ else
+ sBuf.append( ".xml" );
+ return sBuf.makeStringAndClear();
+}
+
+OString XclXmlUtils::ToOString( const Color& rColor )
+{
+ char buf[9];
+ sprintf( buf, "%.2X%.2X%.2X%.2X", rColor.GetAlpha(), rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
+ buf[8] = '\0';
+ return OString(buf);
+}
+
+OStringBuffer& XclXmlUtils::ToOString( OStringBuffer& s, const ScAddress& rAddress )
+{
+ rAddress.Format(s, ScRefFlags::VALID, nullptr, ScAddress::Details( FormulaGrammar::CONV_XL_A1));
+ return s;
+}
+
+OString XclXmlUtils::ToOString( const ScfUInt16Vec& rBuffer )
+{
+ if(rBuffer.empty())
+ return OString();
+
+ const sal_uInt16* pBuffer = rBuffer.data();
+ return OString(
+ reinterpret_cast<sal_Unicode const *>(pBuffer), rBuffer.size(),
+ RTL_TEXTENCODING_UTF8);
+}
+
+OString XclXmlUtils::ToOString( const ScDocument& rDoc, const ScRange& rRange, bool bFullAddressNotation )
+{
+ OUString sRange(rRange.Format( rDoc, ScRefFlags::VALID,
+ ScAddress::Details( FormulaGrammar::CONV_XL_A1 ),
+ bFullAddressNotation ) );
+ return sRange.toUtf8();
+}
+
+OString XclXmlUtils::ToOString( const ScDocument& rDoc, const ScRangeList& rRangeList )
+{
+ OUString s;
+ rRangeList.Format(s, ScRefFlags::VALID, rDoc, FormulaGrammar::CONV_XL_OOX, ' ');
+ return s.toUtf8();
+}
+
+static ScAddress lcl_ToAddress( const XclAddress& rAddress )
+{
+ return ScAddress( rAddress.mnCol, rAddress.mnRow, 0 );
+}
+
+OStringBuffer& XclXmlUtils::ToOString( OStringBuffer& s, const XclAddress& rAddress )
+{
+ return ToOString( s, lcl_ToAddress( rAddress ));
+}
+
+OString XclXmlUtils::ToOString( const XclExpString& s )
+{
+ OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
+ return ToOString( s.GetUnicodeBuffer() );
+}
+
+static ScRange lcl_ToRange( const XclRange& rRange )
+{
+ ScRange aRange;
+
+ aRange.aStart = lcl_ToAddress( rRange.maFirst );
+ aRange.aEnd = lcl_ToAddress( rRange.maLast );
+
+ return aRange;
+}
+
+OString XclXmlUtils::ToOString( const ScDocument& rDoc, const XclRangeList& rRanges )
+{
+ ScRangeList aRanges;
+ for( const auto& rRange : rRanges )
+ {
+ aRanges.push_back( lcl_ToRange( rRange ) );
+ }
+ return ToOString( rDoc, aRanges );
+}
+
+OUString XclXmlUtils::ToOUString( const char* s )
+{
+ return OUString( s, static_cast<sal_Int32>(strlen( s )), RTL_TEXTENCODING_ASCII_US );
+}
+
+OUString XclXmlUtils::ToOUString( const ScfUInt16Vec& rBuf, sal_Int32 nStart, sal_Int32 nLength )
+{
+ if( nLength == -1 || ( nLength > (static_cast<sal_Int32>(rBuf.size()) - nStart) ) )
+ nLength = (rBuf.size() - nStart);
+
+ return nLength > 0
+ ? OUString(
+ reinterpret_cast<sal_Unicode const *>(&rBuf[nStart]), nLength)
+ : OUString();
+}
+
+OUString XclXmlUtils::ToOUString(
+ sc::CompileFormulaContext& rCtx, const ScAddress& rAddress, const ScTokenArray* pTokenArray,
+ FormulaError nErrCode )
+{
+ ScCompiler aCompiler( rCtx, rAddress, const_cast<ScTokenArray&>(*pTokenArray));
+
+ /* TODO: isn't this the same as passed in rCtx and thus superfluous? */
+ aCompiler.SetGrammar(FormulaGrammar::GRAM_OOXML);
+
+ sal_Int32 nLen = pTokenArray->GetLen();
+ OUStringBuffer aBuffer( nLen ? (nLen * 5) : 8 );
+ if (nLen)
+ aCompiler.CreateStringFromTokenArray( aBuffer );
+ else
+ {
+ if (nErrCode != FormulaError::NONE)
+ aCompiler.AppendErrorConstant( aBuffer, nErrCode);
+ else
+ {
+ // No code SHOULD be an "error cell", assert caller thought of that
+ // and it really is.
+ assert(!"No code and no error.");
+ }
+ }
+
+ return aBuffer.makeStringAndClear();
+}
+
+OUString XclXmlUtils::ToOUString( const XclExpString& s )
+{
+ OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
+ return ToOUString( s.GetUnicodeBuffer() );
+}
+
+static void lcl_WriteValue( const sax_fastparser::FSHelperPtr& rStream, sal_Int32 nElement, const char* pValue )
+{
+ if( !pValue )
+ return;
+ rStream->singleElement(nElement, XML_val, pValue);
+}
+
+static const char* lcl_GetUnderlineStyle( FontLineStyle eUnderline, bool& bHaveUnderline )
+{
+ bHaveUnderline = true;
+ switch( eUnderline )
+ {
+ // OOXTODO: doubleAccounting, singleAccounting
+ // OOXTODO: what should be done with the other FontLineStyle values?
+ case LINESTYLE_SINGLE: return "single";
+ case LINESTYLE_DOUBLE: return "double";
+ case LINESTYLE_NONE:
+ default: bHaveUnderline = false; return "none";
+ }
+}
+
+static const char* lcl_ToVerticalAlignmentRun( SvxEscapement eEscapement, bool& bHaveAlignment )
+{
+ bHaveAlignment = true;
+ switch( eEscapement )
+ {
+ case SvxEscapement::Superscript: return "superscript";
+ case SvxEscapement::Subscript: return "subscript";
+ case SvxEscapement::Off:
+ default: bHaveAlignment = false; return "baseline";
+ }
+}
+
+sax_fastparser::FSHelperPtr XclXmlUtils::WriteFontData( sax_fastparser::FSHelperPtr pStream, const XclFontData& rFontData, sal_Int32 nFontId )
+{
+ bool bHaveUnderline, bHaveVertAlign;
+ const char* pUnderline = lcl_GetUnderlineStyle( rFontData.GetScUnderline(), bHaveUnderline );
+ const char* pVertAlign = lcl_ToVerticalAlignmentRun( rFontData.GetScEscapement(), bHaveVertAlign );
+
+ lcl_WriteValue( pStream, XML_b, rFontData.mnWeight > 400 ? ToPsz( true ) : nullptr );
+ lcl_WriteValue( pStream, XML_i, rFontData.mbItalic ? ToPsz( true ) : nullptr );
+ lcl_WriteValue( pStream, XML_strike, rFontData.mbStrikeout ? ToPsz( true ) : nullptr );
+ // OOXTODO: lcl_WriteValue( rStream, XML_condense, ); // mac compatibility setting
+ // OOXTODO: lcl_WriteValue( rStream, XML_extend, ); // compatibility setting
+ lcl_WriteValue( pStream, XML_outline, rFontData.mbOutline ? ToPsz( true ) : nullptr );
+ lcl_WriteValue( pStream, XML_shadow, rFontData.mbShadow ? ToPsz( true ) : nullptr );
+ lcl_WriteValue( pStream, XML_u, bHaveUnderline ? pUnderline : nullptr );
+ lcl_WriteValue( pStream, XML_vertAlign, bHaveVertAlign ? pVertAlign : nullptr );
+ lcl_WriteValue( pStream, XML_sz, OString::number( rFontData.mnHeight / 20.0 ).getStr() ); // Twips->Pt
+ if( rFontData.maColor != Color( ColorAlpha, 0, 0xFF, 0xFF, 0xFF ) )
+ pStream->singleElement( XML_color,
+ // OOXTODO: XML_auto, bool
+ // OOXTODO: XML_indexed, uint
+ XML_rgb, XclXmlUtils::ToOString(rFontData.maColor)
+ // OOXTODO: XML_theme, index into <clrScheme/>
+ // OOXTODO: XML_tint, double
+ );
+ lcl_WriteValue( pStream, nFontId, rFontData.maName.toUtf8().getStr() );
+ lcl_WriteValue( pStream, XML_family, OString::number( rFontData.mnFamily ).getStr() );
+ lcl_WriteValue( pStream, XML_charset, rFontData.mnCharSet != 0 ? OString::number( rFontData.mnCharSet ).getStr() : nullptr );
+
+ return pStream;
+}
+
+XclExpXmlStream::XclExpXmlStream( const uno::Reference< XComponentContext >& rCC, bool bExportVBA, bool bExportTemplate )
+ : XmlFilterBase( rCC ),
+ mpRoot( nullptr ),
+ mbExportVBA(bExportVBA),
+ mbExportTemplate(bExportTemplate)
+{
+}
+
+XclExpXmlStream::~XclExpXmlStream()
+{
+ assert(maStreams.empty() && "Forgotten PopStream()?");
+}
+
+sax_fastparser::FSHelperPtr& XclExpXmlStream::GetCurrentStream()
+{
+ OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::GetCurrentStream - no current stream" );
+ return maStreams.top();
+}
+
+void XclExpXmlStream::PushStream( sax_fastparser::FSHelperPtr const & aStream )
+{
+ maStreams.push( aStream );
+}
+
+void XclExpXmlStream::PopStream()
+{
+ OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::PopStream - stack is empty!" );
+ maStreams.pop();
+}
+
+sax_fastparser::FSHelperPtr XclExpXmlStream::GetStreamForPath( const OUString& sPath )
+{
+ if( maOpenedStreamMap.find( sPath ) == maOpenedStreamMap.end() )
+ return sax_fastparser::FSHelperPtr();
+ return maOpenedStreamMap[ sPath ].second;
+}
+
+void XclExpXmlStream::WriteAttribute(sal_Int32 nAttr, std::u16string_view sVal)
+{
+ GetCurrentStream()->write(" ")->writeId(nAttr)->write("=\"")->writeEscaped(sVal)->write("\"");
+}
+
+sax_fastparser::FSHelperPtr XclExpXmlStream::CreateOutputStream (
+ const OUString& sFullStream,
+ std::u16string_view sRelativeStream,
+ const uno::Reference< XOutputStream >& xParentRelation,
+ const char* sContentType,
+ std::u16string_view sRelationshipType,
+ OUString* pRelationshipId )
+{
+ OUString sRelationshipId;
+ if (xParentRelation.is())
+ sRelationshipId = addRelation( xParentRelation, OUString(sRelationshipType), sRelativeStream );
+ else
+ sRelationshipId = addRelation( OUString(sRelationshipType), sRelativeStream );
+
+ if( pRelationshipId )
+ *pRelationshipId = sRelationshipId;
+
+ sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) );
+
+ maOpenedStreamMap[ sFullStream ] = std::make_pair( sRelationshipId, p );
+
+ return p;
+}
+
+bool XclExpXmlStream::importDocument() noexcept
+{
+ return false;
+}
+
+oox::vml::Drawing* XclExpXmlStream::getVmlDrawing()
+{
+ return nullptr;
+}
+
+const oox::drawingml::Theme* XclExpXmlStream::getCurrentTheme() const
+{
+ return nullptr;
+}
+
+oox::drawingml::table::TableStyleListPtr XclExpXmlStream::getTableStyles()
+{
+ return oox::drawingml::table::TableStyleListPtr();
+}
+
+oox::drawingml::chart::ChartConverter* XclExpXmlStream::getChartConverter()
+{
+ // DO NOT CALL
+ return nullptr;
+}
+
+ScDocShell* XclExpXmlStream::getDocShell()
+{
+ uno::Reference< XInterface > xModel( getModel(), UNO_QUERY );
+
+ ScModelObj *pObj = dynamic_cast < ScModelObj* >( xModel.get() );
+
+ if ( pObj )
+ return static_cast < ScDocShell* >( pObj->GetEmbeddedObject() );
+
+ return nullptr;
+}
+
+bool XclExpXmlStream::exportDocument()
+{
+ ScDocShell* pShell = getDocShell();
+ ScDocument& rDoc = pShell->GetDocument();
+ ScRefreshTimerProtector aProt(rDoc.GetRefreshTimerControlAddress());
+
+ const bool bValidateTabNames = officecfg::Office::Calc::Filter::Export::MS_Excel::TruncateLongSheetNames::get();
+ std::vector<OUString> aOriginalTabNames;
+ if (bValidateTabNames)
+ {
+ validateTabNames(aOriginalTabNames);
+ }
+
+ uno::Reference<task::XStatusIndicator> xStatusIndicator = getStatusIndicator();
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->start(ScResId(STR_SAVE_DOC), 100);
+
+ // NOTE: Don't use SotStorage or SvStream any more, and never call
+ // SfxMedium::GetOutStream() anywhere in the xlsx export filter code!
+ // Instead, write via XOutputStream instance.
+ tools::SvRef<SotStorage> rStorage = static_cast<SotStorage*>(nullptr);
+ drawingml::DrawingML::ResetMlCounters();
+ drawingml::DrawingML::PushExportGraphics();
+
+ XclExpRootData aData(
+ EXC_BIFF8, *pShell->GetMedium (), rStorage, rDoc,
+ msfilter::util::getBestTextEncodingFromLocale(
+ Application::GetSettings().GetLanguageTag().getLocale()));
+ aData.meOutput = EXC_OUTPUT_XML_2007;
+ aData.maXclMaxPos.Set( EXC_MAXCOL_XML_2007, EXC_MAXROW_XML_2007, EXC_MAXTAB_XML_2007 );
+ aData.maMaxPos.SetCol( ::std::min( aData.maScMaxPos.Col(), aData.maXclMaxPos.Col() ) );
+ aData.maMaxPos.SetRow( ::std::min( aData.maScMaxPos.Row(), aData.maXclMaxPos.Row() ) );
+ aData.maMaxPos.SetTab( ::std::min( aData.maScMaxPos.Tab(), aData.maXclMaxPos.Tab() ) );
+ aData.mpCompileFormulaCxt = std::make_shared<sc::CompileFormulaContext>(rDoc);
+ // set target path to get correct relative links to target document, not source
+ INetURLObject aPath(getFileUrl());
+ aData.maBasePath = OUString("file:///" + aPath.GetPath() + "\\").replace('\\', '/')
+ // fix for Linux
+ .replaceFirst("file:////", "file:///");
+
+ XclExpRoot aRoot( aData );
+
+ mpRoot = &aRoot;
+ aRoot.GetOldRoot().pER = &aRoot;
+ aRoot.GetOldRoot().eDateiTyp = Biff8;
+ // Get the viewsettings before processing
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ pViewData->WriteExtOptions( mpRoot->GetExtDocOptions() );
+
+ OUString const workbook = "xl/workbook.xml";
+ const char* pWorkbookContentType = nullptr;
+ if (mbExportVBA)
+ {
+ if (mbExportTemplate)
+ {
+ pWorkbookContentType = "application/vnd.ms-excel.template.macroEnabled.main+xml";
+ }
+ else
+ {
+ pWorkbookContentType = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
+ }
+ }
+ else
+ {
+ if (mbExportTemplate)
+ {
+ pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml";
+ }
+ else
+ {
+ pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
+ }
+ }
+
+ PushStream( CreateOutputStream( workbook, workbook,
+ uno::Reference <XOutputStream>(),
+ pWorkbookContentType,
+ oox::getRelationship(Relationship::OFFICEDOCUMENT) ) );
+
+ if (mbExportVBA)
+ {
+ VbaExport aExport(getModel());
+ if (aExport.containsVBAProject())
+ {
+ SvMemoryStream aVbaStream(4096, 4096);
+ tools::SvRef<SotStorage> pVBAStorage(new SotStorage(aVbaStream));
+ aExport.exportVBA( pVBAStorage.get() );
+ aVbaStream.Seek(0);
+ css::uno::Reference<css::io::XInputStream> xVBAStream(
+ new utl::OInputStreamWrapper(aVbaStream));
+ css::uno::Reference<css::io::XOutputStream> xVBAOutput =
+ openFragmentStream("xl/vbaProject.bin", "application/vnd.ms-office.vbaProject");
+ comphelper::OStorageHelper::CopyInputToOutput(xVBAStream, xVBAOutput);
+
+ addRelation(GetCurrentStream()->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), u"vbaProject.bin");
+ }
+ }
+
+ // destruct at the end of the block
+ {
+ ExcDocument aDocRoot( aRoot );
+ if (xStatusIndicator.is())
+ xStatusIndicator->setValue(10);
+ aDocRoot.ReadDoc();
+ if (xStatusIndicator.is())
+ xStatusIndicator->setValue(40);
+ aDocRoot.WriteXml( *this );
+ rDoc.GetExternalRefManager()->disableSkipUnusedFileIds();
+ }
+
+ PopStream();
+ // Free all FSHelperPtr, to flush data before committing storage
+ maOpenedStreamMap.clear();
+
+ commitStorage();
+
+ if (bValidateTabNames)
+ {
+ restoreTabNames(aOriginalTabNames);
+ }
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->end();
+ mpRoot = nullptr;
+
+ drawingml::DrawingML::PopExportGraphics();
+
+ return true;
+}
+
+::oox::ole::VbaProject* XclExpXmlStream::implCreateVbaProject() const
+{
+ return new ::oox::xls::ExcelVbaProject( getComponentContext(), uno::Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
+}
+
+OUString XclExpXmlStream::getImplementationName()
+{
+ return "TODO";
+}
+
+void XclExpXmlStream::validateTabNames(std::vector<OUString>& aOriginalTabNames)
+{
+ const int MAX_TAB_NAME_LENGTH = 31;
+
+ ScDocShell* pShell = getDocShell();
+ ScDocument& rDoc = pShell->GetDocument();
+
+ // get original names
+ aOriginalTabNames.resize(rDoc.GetTableCount());
+ for (SCTAB nTab=0; nTab < rDoc.GetTableCount(); nTab++)
+ {
+ rDoc.GetName(nTab, aOriginalTabNames[nTab]);
+ }
+
+ // new tab names
+ std::vector<OUString> aNewTabNames;
+ aNewTabNames.reserve(rDoc.GetTableCount());
+
+ // check and rename
+ for (SCTAB nTab=0; nTab < rDoc.GetTableCount(); nTab++)
+ {
+ const OUString& rOriginalName = aOriginalTabNames[nTab];
+ if (rOriginalName.getLength() > MAX_TAB_NAME_LENGTH)
+ {
+ OUString aNewName;
+
+ // let's try just truncate "<first 31 chars>"
+ if (aNewName.isEmpty())
+ {
+ aNewName = rOriginalName.copy(0, MAX_TAB_NAME_LENGTH);
+ if (aNewTabNames.end() != std::find(aNewTabNames.begin(), aNewTabNames.end(), aNewName) ||
+ aOriginalTabNames.end() != std::find(aOriginalTabNames.begin(), aOriginalTabNames.end(), aNewName))
+ {
+ // was found => let's use another tab name
+ aNewName.clear();
+ }
+ }
+
+ // let's try "<first N chars>-XXX" template
+ for (int digits=1; digits<10 && aNewName.isEmpty(); digits++)
+ {
+ const int rangeStart = pow(10, digits - 1);
+ const int rangeEnd = pow(10, digits);
+
+ for (int i=rangeStart; i<rangeEnd && aNewName.isEmpty(); i++)
+ {
+ aNewName = OUString::Concat(rOriginalName.subView(0, MAX_TAB_NAME_LENGTH - 1 - digits)) + "-" + OUString::number(i);
+ if (aNewTabNames.end() != std::find(aNewTabNames.begin(), aNewTabNames.end(), aNewName) ||
+ aOriginalTabNames.end() != std::find(aOriginalTabNames.begin(), aOriginalTabNames.end(), aNewName))
+ {
+ // was found => let's use another tab name
+ aNewName.clear();
+ }
+ }
+ }
+
+ if (!aNewName.isEmpty())
+ {
+ // new name was created => rename
+ renameTab(nTab, aNewName);
+ aNewTabNames.push_back(aNewName);
+ }
+ else
+ {
+ // default: do not rename
+ aNewTabNames.push_back(rOriginalName);
+ }
+ }
+ else
+ {
+ // default: do not rename
+ aNewTabNames.push_back(rOriginalName);
+ }
+ }
+}
+
+void XclExpXmlStream::restoreTabNames(const std::vector<OUString>& aOriginalTabNames)
+{
+ ScDocShell* pShell = getDocShell();
+ ScDocument& rDoc = pShell->GetDocument();
+
+ for (SCTAB nTab=0; nTab < rDoc.GetTableCount(); nTab++)
+ {
+ const OUString& rOriginalName = aOriginalTabNames[nTab];
+
+ OUString rModifiedName;
+ rDoc.GetName(nTab, rModifiedName);
+
+ if (rOriginalName != rModifiedName)
+ {
+ renameTab(nTab, rOriginalName);
+ }
+ }
+}
+
+void XclExpXmlStream::renameTab(SCTAB aTab, OUString aNewName)
+{
+ ScDocShell* pShell = getDocShell();
+ ScDocument& rDoc = pShell->GetDocument();
+
+ bool bAutoCalcShellDisabled = rDoc.IsAutoCalcShellDisabled();
+ bool bIdleEnabled = rDoc.IsIdleEnabled();
+
+ rDoc.SetAutoCalcShellDisabled( true );
+ rDoc.EnableIdle(false);
+
+ if (rDoc.RenameTab(aTab, aNewName))
+ {
+ SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScTablesChanged));
+ }
+
+ rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
+ rDoc.EnableIdle(bIdleEnabled);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */