Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / excel / xestream.cxx
blob19115bc86d68e928c07e540743542f097958a788
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 <stdarg.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <utility>
25 #include <filter/msfilter/util.hxx>
26 #include <rtl/ustring.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <rtl/random.h>
29 #include <sax/fshelper.hxx>
30 #include <unotools/streamwrap.hxx>
31 #include <sot/storage.hxx>
32 #include <tools/urlobj.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/settings.hxx>
36 #include <docuno.hxx>
37 #include <xestream.hxx>
38 #include <xladdress.hxx>
39 #include <xlstring.hxx>
40 #include <xltools.hxx>
41 #include <xeroot.hxx>
42 #include <xcl97rec.hxx>
43 #include <rangelst.hxx>
44 #include <compiler.hxx>
45 #include <formulacell.hxx>
46 #include <tokenarray.hxx>
47 #include <tokenstringcontext.hxx>
48 #include <refreshtimerprotector.hxx>
49 #include <globstr.hrc>
50 #include <scresid.hxx>
51 #include <root.hxx>
53 #include <docsh.hxx>
54 #include <viewdata.hxx>
55 #include <excdoc.hxx>
57 #include <oox/token/tokens.hxx>
58 #include <oox/token/relationship.hxx>
59 #include <oox/export/utils.hxx>
60 #include <formula/grammar.hxx>
61 #include <oox/ole/vbaexport.hxx>
62 #include <excelvbaproject.hxx>
64 #include <com/sun/star/task/XStatusIndicator.hpp>
65 #include <memory>
66 #include <comphelper/storagehelper.hxx>
68 #define DEBUG_XL_ENCRYPTION 0
70 using ::com::sun::star::uno::XInterface;
71 using ::std::vector;
73 using namespace com::sun::star;
74 using namespace ::com::sun::star::beans;
75 using namespace ::com::sun::star::io;
76 using namespace ::com::sun::star::lang;
77 using namespace ::com::sun::star::sheet;
78 using namespace ::com::sun::star::uno;
79 using namespace ::formula;
80 using namespace ::oox;
82 XclExpStream::XclExpStream( SvStream& rOutStrm, const XclExpRoot& rRoot, sal_uInt16 nMaxRecSize ) :
83 mrStrm( rOutStrm ),
84 mrRoot( rRoot ),
85 mbUseEncrypter( false ),
86 mnMaxRecSize( nMaxRecSize ),
87 mnCurrMaxSize( 0 ),
88 mnMaxSliceSize( 0 ),
89 mnHeaderSize( 0 ),
90 mnCurrSize( 0 ),
91 mnSliceSize( 0 ),
92 mnPredictSize( 0 ),
93 mnLastSizePos( 0 ),
94 mbInRec( false )
96 if( mnMaxRecSize == 0 )
97 mnMaxRecSize = (mrRoot.GetBiff() <= EXC_BIFF5) ? EXC_MAXRECSIZE_BIFF5 : EXC_MAXRECSIZE_BIFF8;
98 mnMaxContSize = mnMaxRecSize;
101 XclExpStream::~XclExpStream()
103 mrStrm.Flush();
106 void XclExpStream::StartRecord( sal_uInt16 nRecId, std::size_t nRecSize )
108 OSL_ENSURE( !mbInRec, "XclExpStream::StartRecord - another record still open" );
109 DisableEncryption();
110 mnMaxContSize = mnCurrMaxSize = mnMaxRecSize;
111 mnPredictSize = nRecSize;
112 mbInRec = true;
113 InitRecord( nRecId );
114 SetSliceSize( 0 );
115 EnableEncryption();
118 void XclExpStream::EndRecord()
120 OSL_ENSURE( mbInRec, "XclExpStream::EndRecord - no record open" );
121 DisableEncryption();
122 UpdateRecSize();
123 mrStrm.Seek( STREAM_SEEK_TO_END );
124 mbInRec = false;
127 void XclExpStream::SetSliceSize( sal_uInt16 nSize )
129 mnMaxSliceSize = nSize;
130 mnSliceSize = 0;
133 XclExpStream& XclExpStream::operator<<( sal_Int8 nValue )
135 PrepareWrite( 1 );
136 if (mbUseEncrypter && HasValidEncrypter())
137 mxEncrypter->Encrypt(mrStrm, nValue);
138 else
139 mrStrm.WriteSChar( nValue );
140 return *this;
143 XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue )
145 PrepareWrite( 1 );
146 if (mbUseEncrypter && HasValidEncrypter())
147 mxEncrypter->Encrypt(mrStrm, nValue);
148 else
149 mrStrm.WriteUChar( nValue );
150 return *this;
153 XclExpStream& XclExpStream::operator<<( sal_Int16 nValue )
155 PrepareWrite( 2 );
156 if (mbUseEncrypter && HasValidEncrypter())
157 mxEncrypter->Encrypt(mrStrm, nValue);
158 else
159 mrStrm.WriteInt16( nValue );
160 return *this;
163 XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue )
165 PrepareWrite( 2 );
166 if (mbUseEncrypter && HasValidEncrypter())
167 mxEncrypter->Encrypt(mrStrm, nValue);
168 else
169 mrStrm.WriteUInt16( nValue );
170 return *this;
173 XclExpStream& XclExpStream::operator<<( sal_Int32 nValue )
175 PrepareWrite( 4 );
176 if (mbUseEncrypter && HasValidEncrypter())
177 mxEncrypter->Encrypt(mrStrm, nValue);
178 else
179 mrStrm.WriteInt32( nValue );
180 return *this;
183 XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue )
185 PrepareWrite( 4 );
186 if (mbUseEncrypter && HasValidEncrypter())
187 mxEncrypter->Encrypt(mrStrm, nValue);
188 else
189 mrStrm.WriteUInt32( nValue );
190 return *this;
193 XclExpStream& XclExpStream::operator<<( float fValue )
195 PrepareWrite( 4 );
196 if (mbUseEncrypter && HasValidEncrypter())
197 mxEncrypter->Encrypt(mrStrm, fValue);
198 else
199 mrStrm.WriteFloat( fValue );
200 return *this;
203 XclExpStream& XclExpStream::operator<<( double fValue )
205 PrepareWrite( 8 );
206 if (mbUseEncrypter && HasValidEncrypter())
207 mxEncrypter->Encrypt(mrStrm, fValue);
208 else
209 mrStrm.WriteDouble( fValue );
210 return *this;
213 std::size_t XclExpStream::Write( const void* pData, std::size_t nBytes )
215 std::size_t nRet = 0;
216 if( pData && (nBytes > 0) )
218 if( mbInRec )
220 const sal_uInt8* pBuffer = static_cast< const sal_uInt8* >( pData );
221 std::size_t nBytesLeft = nBytes;
222 bool bValid = true;
224 while( bValid && (nBytesLeft > 0) )
226 std::size_t nWriteLen = ::std::min< std::size_t >( PrepareWrite(), nBytesLeft );
227 std::size_t nWriteRet = nWriteLen;
228 if (mbUseEncrypter && HasValidEncrypter())
230 OSL_ENSURE(nWriteLen > 0, "XclExpStream::Write: write length is 0!");
231 vector<sal_uInt8> aBytes(nWriteLen);
232 memcpy(aBytes.data(), pBuffer, nWriteLen);
233 mxEncrypter->EncryptBytes(mrStrm, aBytes);
234 // TODO: How do I check if all the bytes have been successfully written ?
236 else
238 nWriteRet = mrStrm.WriteBytes(pBuffer, nWriteLen);
239 bValid = (nWriteLen == nWriteRet);
240 OSL_ENSURE( bValid, "XclExpStream::Write - stream write error" );
242 pBuffer += nWriteRet;
243 nRet += nWriteRet;
244 nBytesLeft -= nWriteRet;
245 UpdateSizeVars( nWriteRet );
248 else
249 nRet = mrStrm.WriteBytes(pData, nBytes);
251 return nRet;
254 void XclExpStream::WriteZeroBytes( std::size_t nBytes )
256 if( mbInRec )
258 std::size_t nBytesLeft = nBytes;
259 while( nBytesLeft > 0 )
261 std::size_t nWriteLen = ::std::min< std::size_t >( PrepareWrite(), nBytesLeft );
262 WriteRawZeroBytes( nWriteLen );
263 nBytesLeft -= nWriteLen;
264 UpdateSizeVars( nWriteLen );
267 else
268 WriteRawZeroBytes( nBytes );
271 void XclExpStream::WriteZeroBytesToRecord( std::size_t nBytes )
273 if (!mbInRec)
274 // not in record.
275 return;
277 for (std::size_t i = 0; i < nBytes; ++i)
278 *this << sal_uInt8(0)/*nZero*/;
281 void XclExpStream::CopyFromStream(SvStream& rInStrm, sal_uInt64 const nBytes)
283 sal_uInt64 const nRemaining(rInStrm.remainingSize());
284 sal_uInt64 nBytesLeft = ::std::min(nBytes, nRemaining);
285 if( nBytesLeft > 0 )
287 const std::size_t nMaxBuffer = 4096;
288 std::unique_ptr<sal_uInt8[]> pBuffer(
289 new sal_uInt8[ ::std::min<std::size_t>(nBytesLeft, nMaxBuffer) ]);
290 bool bValid = true;
292 while( bValid && (nBytesLeft > 0) )
294 std::size_t nWriteLen = ::std::min<std::size_t>(nBytesLeft, nMaxBuffer);
295 rInStrm.ReadBytes(pBuffer.get(), nWriteLen);
296 std::size_t nWriteRet = Write( pBuffer.get(), nWriteLen );
297 bValid = (nWriteLen == nWriteRet);
298 nBytesLeft -= nWriteRet;
303 void XclExpStream::WriteUnicodeBuffer( const ScfUInt16Vec& rBuffer, sal_uInt8 nFlags )
305 SetSliceSize( 0 );
306 nFlags &= EXC_STRF_16BIT; // repeat only 16bit flag
307 sal_uInt16 nCharLen = nFlags ? 2 : 1;
309 for( const auto& rItem : rBuffer )
311 if( mbInRec && (mnCurrSize + nCharLen > mnCurrMaxSize) )
313 StartContinue();
314 operator<<( nFlags );
316 if( nCharLen == 2 )
317 operator<<( rItem );
318 else
319 operator<<( static_cast< sal_uInt8 >( rItem ) );
323 // Xcl has an obscure sense of whether starting a new record or not,
324 // and crashes if it encounters the string header at the very end of a record.
325 // Thus we add 1 to give some room, seems like they do it that way but with another count (10?)
326 void XclExpStream::WriteByteString( const OString& rString )
328 SetSliceSize( 0 );
329 std::size_t nLen = ::std::min< std::size_t >( rString.getLength(), 0x00FF );
330 nLen = ::std::min< std::size_t >( nLen, 0xFF );
332 sal_uInt16 nLeft = PrepareWrite();
333 if( mbInRec && (nLeft <= 1) )
334 StartContinue();
336 operator<<( static_cast< sal_uInt8 >( nLen ) );
337 Write( rString.getStr(), nLen );
340 void XclExpStream::WriteCharBuffer( const ScfUInt8Vec& rBuffer )
342 SetSliceSize( 0 );
343 Write( rBuffer.data(), rBuffer.size() );
346 void XclExpStream::SetEncrypter( XclExpEncrypterRef const & xEncrypter )
348 mxEncrypter = xEncrypter;
351 bool XclExpStream::HasValidEncrypter() const
353 return mxEncrypter && mxEncrypter->IsValid();
356 void XclExpStream::EnableEncryption( bool bEnable )
358 mbUseEncrypter = bEnable && HasValidEncrypter();
361 void XclExpStream::DisableEncryption()
363 EnableEncryption(false);
366 void XclExpStream::SetSvStreamPos(sal_uInt64 const nPos)
368 OSL_ENSURE( !mbInRec, "XclExpStream::SetSvStreamPos - not allowed inside of a record" );
369 mbInRec ? 0 : mrStrm.Seek( nPos );
372 // private --------------------------------------------------------------------
374 void XclExpStream::InitRecord( sal_uInt16 nRecId )
376 mrStrm.Seek( STREAM_SEEK_TO_END );
377 mrStrm.WriteUInt16( nRecId );
379 mnLastSizePos = mrStrm.Tell();
380 mnHeaderSize = static_cast< sal_uInt16 >( ::std::min< std::size_t >( mnPredictSize, mnCurrMaxSize ) );
381 mrStrm.WriteUInt16( mnHeaderSize );
382 mnCurrSize = mnSliceSize = 0;
385 void XclExpStream::UpdateRecSize()
387 if( mnCurrSize != mnHeaderSize )
389 mrStrm.Seek( mnLastSizePos );
390 mrStrm.WriteUInt16( mnCurrSize );
394 void XclExpStream::UpdateSizeVars( std::size_t nSize )
396 OSL_ENSURE( mnCurrSize + nSize <= mnCurrMaxSize, "XclExpStream::UpdateSizeVars - record overwritten" );
397 mnCurrSize = mnCurrSize + static_cast< sal_uInt16 >( nSize );
399 if( mnMaxSliceSize > 0 )
401 OSL_ENSURE( mnSliceSize + nSize <= mnMaxSliceSize, "XclExpStream::UpdateSizeVars - slice overwritten" );
402 mnSliceSize = mnSliceSize + static_cast< sal_uInt16 >( nSize );
403 if( mnSliceSize >= mnMaxSliceSize )
404 mnSliceSize = 0;
408 void XclExpStream::StartContinue()
410 UpdateRecSize();
411 mnCurrMaxSize = mnMaxContSize;
412 mnPredictSize -= mnCurrSize;
413 InitRecord( EXC_ID_CONT );
416 void XclExpStream::PrepareWrite( sal_uInt16 nSize )
418 if( mbInRec )
420 if( (mnCurrSize + nSize > mnCurrMaxSize) ||
421 ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
422 StartContinue();
423 UpdateSizeVars( nSize );
427 sal_uInt16 XclExpStream::PrepareWrite()
429 sal_uInt16 nRet = 0;
430 if( mbInRec )
432 if( (mnCurrSize >= mnCurrMaxSize) ||
433 ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
434 StartContinue();
435 UpdateSizeVars( 0 );
437 nRet = (mnMaxSliceSize > 0) ? (mnMaxSliceSize - mnSliceSize) : (mnCurrMaxSize - mnCurrSize);
439 return nRet;
442 void XclExpStream::WriteRawZeroBytes( std::size_t nBytes )
444 const sal_uInt32 nData = 0;
445 std::size_t nBytesLeft = nBytes;
446 while( nBytesLeft >= sizeof( nData ) )
448 mrStrm.WriteUInt32( nData );
449 nBytesLeft -= sizeof( nData );
451 if( nBytesLeft )
452 mrStrm.WriteBytes(&nData, nBytesLeft);
455 XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot& rRoot ) :
456 mnOldPos(STREAM_SEEK_TO_END),
457 mbValid(false)
459 Sequence< NamedValue > aEncryptionData = rRoot.GetEncryptionData();
460 if( !aEncryptionData.hasElements() )
461 // Empty password. Get the default biff8 password.
462 aEncryptionData = XclExpRoot::GenerateDefaultEncryptionData();
463 Init( aEncryptionData );
466 XclExpBiff8Encrypter::~XclExpBiff8Encrypter()
470 void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 pnSaltDigest[16] ) const
472 if ( sizeof( mpnSaltDigest ) == 16 )
473 memcpy( pnSaltDigest, mpnSaltDigest, 16 );
476 void XclExpBiff8Encrypter::GetSalt( sal_uInt8 pnSalt[16] ) const
478 if ( sizeof( mpnSalt ) == 16 )
479 memcpy( pnSalt, mpnSalt, 16 );
482 void XclExpBiff8Encrypter::GetDocId( sal_uInt8 pnDocId[16] ) const
484 if ( sizeof( mpnDocId ) == 16 )
485 memcpy( pnDocId, mpnDocId, 16 );
488 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt8 nData )
490 vector<sal_uInt8> aByte(1);
491 aByte[0] = nData;
492 EncryptBytes(rStrm, aByte);
495 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt16 nData )
497 ::std::vector<sal_uInt8> pnBytes(2);
498 pnBytes[0] = nData & 0xFF;
499 pnBytes[1] = (nData >> 8) & 0xFF;
500 EncryptBytes(rStrm, pnBytes);
503 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt32 nData )
505 ::std::vector<sal_uInt8> pnBytes(4);
506 pnBytes[0] = nData & 0xFF;
507 pnBytes[1] = (nData >> 8) & 0xFF;
508 pnBytes[2] = (nData >> 16) & 0xFF;
509 pnBytes[3] = (nData >> 24) & 0xFF;
510 EncryptBytes(rStrm, pnBytes);
513 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, float fValue )
515 ::std::vector<sal_uInt8> pnBytes(4);
516 memcpy(pnBytes.data(), &fValue, 4);
517 EncryptBytes(rStrm, pnBytes);
520 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, double fValue )
522 ::std::vector<sal_uInt8> pnBytes(8);
523 memcpy(pnBytes.data(), &fValue, 8);
524 EncryptBytes(rStrm, pnBytes);
527 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int8 nData )
529 Encrypt(rStrm, static_cast<sal_uInt8>(nData));
532 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int16 nData )
534 Encrypt(rStrm, static_cast<sal_uInt16>(nData));
537 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int32 nData )
539 Encrypt(rStrm, static_cast<sal_uInt32>(nData));
542 void XclExpBiff8Encrypter::Init( const Sequence< NamedValue >& rEncryptionData )
544 mbValid = false;
546 if( maCodec.InitCodec( rEncryptionData ) )
548 maCodec.GetDocId( mpnDocId );
550 // generate the salt here
551 rtlRandomPool aRandomPool = rtl_random_createPool ();
552 rtl_random_getBytes( aRandomPool, mpnSalt, 16 );
553 rtl_random_destroyPool( aRandomPool );
555 memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) );
557 // generate salt hash.
558 ::msfilter::MSCodec_Std97 aCodec;
559 aCodec.InitCodec( rEncryptionData );
560 aCodec.CreateSaltDigest( mpnSalt, mpnSaltDigest );
562 // verify to make sure it's in good shape.
563 mbValid = maCodec.VerifyKey( mpnSalt, mpnSaltDigest );
567 sal_uInt32 XclExpBiff8Encrypter::GetBlockPos( std::size_t nStrmPos )
569 return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
572 sal_uInt16 XclExpBiff8Encrypter::GetOffsetInBlock( std::size_t nStrmPos )
574 return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
577 void XclExpBiff8Encrypter::EncryptBytes( SvStream& rStrm, vector<sal_uInt8>& aBytes )
579 sal_uInt64 nStrmPos = rStrm.Tell();
580 sal_uInt16 nBlockOffset = GetOffsetInBlock(nStrmPos);
581 sal_uInt32 nBlockPos = GetBlockPos(nStrmPos);
583 #if DEBUG_XL_ENCRYPTION
584 fprintf(stdout, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld offset in block = %d block pos = %ld\n",
585 nStrmPos, nBlockOffset, nBlockPos);
586 #endif
588 sal_uInt16 nSize = static_cast< sal_uInt16 >( aBytes.size() );
589 if (nSize == 0)
590 return;
592 #if DEBUG_XL_ENCRYPTION
593 fprintf(stdout, "RAW: ");
594 for (sal_uInt16 i = 0; i < nSize; ++i)
595 fprintf(stdout, "%2.2X ", aBytes[i]);
596 fprintf(stdout, "\n");
597 #endif
599 if (mnOldPos != nStrmPos)
601 sal_uInt16 nOldOffset = GetOffsetInBlock(mnOldPos);
602 sal_uInt32 nOldBlockPos = GetBlockPos(mnOldPos);
604 if ( (nBlockPos != nOldBlockPos) || (nBlockOffset < nOldOffset) )
606 maCodec.InitCipher(nBlockPos);
607 nOldOffset = 0;
610 if (nBlockOffset > nOldOffset)
611 maCodec.Skip(nBlockOffset - nOldOffset);
614 sal_uInt16 nBytesLeft = nSize;
615 sal_uInt16 nPos = 0;
616 while (nBytesLeft > 0)
618 sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - nBlockOffset;
619 sal_uInt16 nEncBytes = ::std::min(nBlockLeft, nBytesLeft);
621 bool bRet = maCodec.Encode(&aBytes[nPos], nEncBytes, &aBytes[nPos], nEncBytes);
622 OSL_ENSURE(bRet, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!");
624 std::size_t nRet = rStrm.WriteBytes(&aBytes[nPos], nEncBytes);
625 OSL_ENSURE(nRet == nEncBytes, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!");
627 nStrmPos = rStrm.Tell();
628 nBlockOffset = GetOffsetInBlock(nStrmPos);
629 nBlockPos = GetBlockPos(nStrmPos);
630 if (nBlockOffset == 0)
631 maCodec.InitCipher(nBlockPos);
633 nBytesLeft -= nEncBytes;
634 nPos += nEncBytes;
636 mnOldPos = nStrmPos;
639 static const char* lcl_GetErrorString( FormulaError nScErrCode )
641 sal_uInt8 nXclErrCode = XclTools::GetXclErrorCode( nScErrCode );
642 switch( nXclErrCode )
644 case EXC_ERR_NULL: return "#NULL!";
645 case EXC_ERR_DIV0: return "#DIV/0!";
646 case EXC_ERR_VALUE: return "#VALUE!";
647 case EXC_ERR_REF: return "#REF!";
648 case EXC_ERR_NAME: return "#NAME?";
649 case EXC_ERR_NUM: return "#NUM!";
650 case EXC_ERR_NA:
651 default: return "#N/A";
655 void XclXmlUtils::GetFormulaTypeAndValue( ScFormulaCell& rCell, const char*& rsType, OUString& rsValue )
657 sc::FormulaResultValue aResValue = rCell.GetResult();
659 switch (aResValue.meType)
661 case sc::FormulaResultValue::Error:
662 rsType = "e";
663 rsValue = ToOUString(lcl_GetErrorString(aResValue.mnError));
664 break;
665 case sc::FormulaResultValue::Value:
666 rsType = "n";
667 rsValue = OUString::number(aResValue.mfValue);
668 break;
669 case sc::FormulaResultValue::String:
670 rsType = "str";
671 rsValue = rCell.GetString().getString();
672 break;
673 case sc::FormulaResultValue::Invalid:
674 default:
675 // TODO : double-check this to see if this is correct.
676 rsType = "inlineStr";
677 rsValue = rCell.GetString().getString();
681 OUString XclXmlUtils::GetStreamName( const char* sStreamDir, const char* sStream, sal_Int32 nId )
683 OUStringBuffer sBuf;
684 if( sStreamDir )
685 sBuf.appendAscii( sStreamDir );
686 sBuf.appendAscii( sStream );
687 if( nId )
688 sBuf.append( nId );
689 if( strstr(sStream, "vml") )
690 sBuf.append( ".vml" );
691 else
692 sBuf.append( ".xml" );
693 return sBuf.makeStringAndClear();
696 OString XclXmlUtils::ToOString( const Color& rColor )
698 char buf[9];
699 sprintf( buf, "%.2X%.2X%.2X%.2X", 0xFF-rColor.GetTransparency(), rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
700 buf[8] = '\0';
701 return buf;
704 OStringBuffer& XclXmlUtils::ToOString( OStringBuffer& s, const ScAddress& rAddress )
706 rAddress.Format(s, ScRefFlags::VALID, nullptr, ScAddress::Details( FormulaGrammar::CONV_XL_A1));
707 return s;
710 OString XclXmlUtils::ToOString( const ScfUInt16Vec& rBuffer )
712 if(rBuffer.empty())
713 return OString();
715 const sal_uInt16* pBuffer = rBuffer.data();
716 return OString(
717 reinterpret_cast<sal_Unicode const *>(pBuffer), rBuffer.size(),
718 RTL_TEXTENCODING_UTF8);
721 OString XclXmlUtils::ToOString( const ScDocument* pDoc, const ScRange& rRange, bool bFullAddressNotation )
723 OUString sRange(rRange.Format( ScRefFlags::VALID, pDoc,
724 ScAddress::Details( FormulaGrammar::CONV_XL_A1 ),
725 bFullAddressNotation ) );
726 return sRange.toUtf8();
729 OString XclXmlUtils::ToOString( const ScDocument* pDoc, const ScRangeList& rRangeList )
731 OUString s;
732 rRangeList.Format(s, ScRefFlags::VALID, pDoc, FormulaGrammar::CONV_XL_OOX, ' ');
733 return s.toUtf8();
736 static ScAddress lcl_ToAddress( const XclAddress& rAddress )
738 ScAddress aAddress;
740 // For some reason, ScRange::Format() returns omits row numbers if
741 // the row is >= MAXROW or the column is >= MAXCOL, and Excel doesn't
742 // like "A:IV" (i.e. no row numbers). Prevent this.
743 // KOHEI: Find out if the above comment is still true.
744 aAddress.SetRow( std::min<sal_Int32>( rAddress.mnRow, MAXROW ) );
745 aAddress.SetCol( static_cast<sal_Int16>(std::min<sal_Int32>( rAddress.mnCol, MAXCOL )) );
747 return aAddress;
750 OStringBuffer& XclXmlUtils::ToOString( OStringBuffer& s, const XclAddress& rAddress )
752 return ToOString( s, lcl_ToAddress( rAddress ));
755 OString XclXmlUtils::ToOString( const XclExpString& s )
757 OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
758 return ToOString( s.GetUnicodeBuffer() );
761 static ScRange lcl_ToRange( const XclRange& rRange )
763 ScRange aRange;
765 aRange.aStart = lcl_ToAddress( rRange.maFirst );
766 aRange.aEnd = lcl_ToAddress( rRange.maLast );
768 return aRange;
771 OString XclXmlUtils::ToOString( const ScDocument* pDoc, const XclRangeList& rRanges )
773 ScRangeList aRanges;
774 for( const auto& rRange : rRanges )
776 aRanges.push_back( lcl_ToRange( rRange ) );
778 return ToOString( pDoc, aRanges );
781 OUString XclXmlUtils::ToOUString( const char* s )
783 return OUString( s, static_cast<sal_Int32>(strlen( s )), RTL_TEXTENCODING_ASCII_US );
786 OUString XclXmlUtils::ToOUString( const ScfUInt16Vec& rBuf, sal_Int32 nStart, sal_Int32 nLength )
788 if( nLength == -1 || ( nLength > (static_cast<sal_Int32>(rBuf.size()) - nStart) ) )
789 nLength = (rBuf.size() - nStart);
791 return nLength > 0
792 ? OUString(
793 reinterpret_cast<sal_Unicode const *>(&rBuf[nStart]), nLength)
794 : OUString();
797 OUString XclXmlUtils::ToOUString(
798 sc::CompileFormulaContext& rCtx, const ScAddress& rAddress, const ScTokenArray* pTokenArray )
800 ScCompiler aCompiler( rCtx, rAddress, const_cast<ScTokenArray&>(*pTokenArray));
802 /* TODO: isn't this the same as passed in rCtx and thus superfluous? */
803 aCompiler.SetGrammar(FormulaGrammar::GRAM_OOXML);
805 OUStringBuffer aBuffer( pTokenArray->GetLen() * 5 );
806 aCompiler.CreateStringFromTokenArray( aBuffer );
807 return aBuffer.makeStringAndClear();
810 OUString XclXmlUtils::ToOUString( const XclExpString& s )
812 OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
813 return ToOUString( s.GetUnicodeBuffer() );
816 static void lcl_WriteValue( const sax_fastparser::FSHelperPtr& rStream, sal_Int32 nElement, const char* pValue )
818 if( !pValue )
819 return;
820 rStream->singleElement(nElement, XML_val, pValue);
823 static const char* lcl_GetUnderlineStyle( FontLineStyle eUnderline, bool& bHaveUnderline )
825 bHaveUnderline = true;
826 switch( eUnderline )
828 // OOXTODO: doubleAccounting, singleAccounting
829 // OOXTODO: what should be done with the other FontLineStyle values?
830 case LINESTYLE_SINGLE: return "single";
831 case LINESTYLE_DOUBLE: return "double";
832 case LINESTYLE_NONE:
833 default: bHaveUnderline = false; return "none";
837 static const char* lcl_ToVerticalAlignmentRun( SvxEscapement eEscapement, bool& bHaveAlignment )
839 bHaveAlignment = true;
840 switch( eEscapement )
842 case SvxEscapement::Superscript: return "superscript";
843 case SvxEscapement::Subscript: return "subscript";
844 case SvxEscapement::Off:
845 default: bHaveAlignment = false; return "baseline";
849 sax_fastparser::FSHelperPtr XclXmlUtils::WriteFontData( sax_fastparser::FSHelperPtr pStream, const XclFontData& rFontData, sal_Int32 nFontId )
851 bool bHaveUnderline, bHaveVertAlign;
852 const char* pUnderline = lcl_GetUnderlineStyle( rFontData.GetScUnderline(), bHaveUnderline );
853 const char* pVertAlign = lcl_ToVerticalAlignmentRun( rFontData.GetScEscapement(), bHaveVertAlign );
855 lcl_WriteValue( pStream, XML_b, rFontData.mnWeight > 400 ? ToPsz( true ) : nullptr );
856 lcl_WriteValue( pStream, XML_i, rFontData.mbItalic ? ToPsz( true ) : nullptr );
857 lcl_WriteValue( pStream, XML_strike, rFontData.mbStrikeout ? ToPsz( true ) : nullptr );
858 // OOXTODO: lcl_WriteValue( rStream, XML_condense, ); // mac compatibility setting
859 // OOXTODO: lcl_WriteValue( rStream, XML_extend, ); // compatibility setting
860 lcl_WriteValue( pStream, XML_outline, rFontData.mbOutline ? ToPsz( true ) : nullptr );
861 lcl_WriteValue( pStream, XML_shadow, rFontData.mbShadow ? ToPsz( true ) : nullptr );
862 lcl_WriteValue( pStream, XML_u, bHaveUnderline ? pUnderline : nullptr );
863 lcl_WriteValue( pStream, XML_vertAlign, bHaveVertAlign ? pVertAlign : nullptr );
864 lcl_WriteValue( pStream, XML_sz, OString::number( rFontData.mnHeight / 20.0 ).getStr() ); // Twips->Pt
865 if( rFontData.maColor != Color( 0xFF, 0xFF, 0xFF, 0xFF ) )
866 pStream->singleElement( XML_color,
867 // OOXTODO: XML_auto, bool
868 // OOXTODO: XML_indexed, uint
869 XML_rgb, XclXmlUtils::ToOString(rFontData.maColor)
870 // OOXTODO: XML_theme, index into <clrScheme/>
871 // OOXTODO: XML_tint, double
873 lcl_WriteValue( pStream, nFontId, rFontData.maName.toUtf8().getStr() );
874 lcl_WriteValue( pStream, XML_family, OString::number( rFontData.mnFamily ).getStr() );
875 lcl_WriteValue( pStream, XML_charset, rFontData.mnCharSet != 0 ? OString::number( rFontData.mnCharSet ).getStr() : nullptr );
877 return pStream;
880 XclExpXmlStream::XclExpXmlStream( const uno::Reference< XComponentContext >& rCC, bool bExportVBA, bool bExportTemplate )
881 : XmlFilterBase( rCC ),
882 mpRoot( nullptr ),
883 mbExportVBA(bExportVBA),
884 mbExportTemplate(bExportTemplate)
888 XclExpXmlStream::~XclExpXmlStream()
890 assert(maStreams.empty() && "Forgotten PopStream()?");
893 sax_fastparser::FSHelperPtr& XclExpXmlStream::GetCurrentStream()
895 OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::GetCurrentStream - no current stream" );
896 return maStreams.top();
899 void XclExpXmlStream::PushStream( sax_fastparser::FSHelperPtr const & aStream )
901 maStreams.push( aStream );
904 void XclExpXmlStream::PopStream()
906 OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::PopStream - stack is empty!" );
907 maStreams.pop();
910 sax_fastparser::FSHelperPtr XclExpXmlStream::GetStreamForPath( const OUString& sPath )
912 if( maOpenedStreamMap.find( sPath ) == maOpenedStreamMap.end() )
913 return sax_fastparser::FSHelperPtr();
914 return maOpenedStreamMap[ sPath ].second;
917 void XclExpXmlStream::WriteAttribute(sal_Int32 nAttr, const OUString& sVal)
919 GetCurrentStream()->write(" ")->writeId(nAttr)->write("=\"")->writeEscaped(sVal)->write("\"");
922 sax_fastparser::FSHelperPtr XclExpXmlStream::CreateOutputStream (
923 const OUString& sFullStream,
924 const OUString& sRelativeStream,
925 const uno::Reference< XOutputStream >& xParentRelation,
926 const char* sContentType,
927 const char* sRelationshipType,
928 OUString* pRelationshipId )
930 OUString sRelationshipId;
931 if (xParentRelation.is())
932 sRelationshipId = addRelation( xParentRelation, OUString::createFromAscii( sRelationshipType), sRelativeStream );
933 else
934 sRelationshipId = addRelation( OUString::createFromAscii( sRelationshipType ), sRelativeStream );
936 if( pRelationshipId )
937 *pRelationshipId = sRelationshipId;
939 sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) );
941 maOpenedStreamMap[ sFullStream ] = std::make_pair( sRelationshipId, p );
943 return p;
946 bool XclExpXmlStream::importDocument() throw()
948 return false;
951 oox::vml::Drawing* XclExpXmlStream::getVmlDrawing()
953 return nullptr;
956 const oox::drawingml::Theme* XclExpXmlStream::getCurrentTheme() const
958 return nullptr;
961 oox::drawingml::table::TableStyleListPtr XclExpXmlStream::getTableStyles()
963 return oox::drawingml::table::TableStyleListPtr();
966 oox::drawingml::chart::ChartConverter* XclExpXmlStream::getChartConverter()
968 // DO NOT CALL
969 return nullptr;
972 ScDocShell* XclExpXmlStream::getDocShell()
974 uno::Reference< XInterface > xModel( getModel(), UNO_QUERY );
976 ScModelObj *pObj = dynamic_cast < ScModelObj* >( xModel.get() );
978 if ( pObj )
979 return static_cast < ScDocShell* >( pObj->GetEmbeddedObject() );
981 return nullptr;
984 bool XclExpXmlStream::exportDocument()
986 ScDocShell* pShell = getDocShell();
987 ScDocument& rDoc = pShell->GetDocument();
988 ScRefreshTimerProtector aProt(rDoc.GetRefreshTimerControlAddress());
990 uno::Reference<task::XStatusIndicator> xStatusIndicator = getStatusIndicator();
992 if (xStatusIndicator.is())
993 xStatusIndicator->start(ScResId(STR_SAVE_DOC), 100);
995 // NOTE: Don't use SotStorage or SvStream any more, and never call
996 // SfxMedium::GetOutStream() anywhere in the xlsx export filter code!
997 // Instead, write via XOutputStream instance.
998 tools::SvRef<SotStorage> rStorage = static_cast<SotStorage*>(nullptr);
999 XclExpObjList::ResetCounters();
1001 XclExpRootData aData(
1002 EXC_BIFF8, *pShell->GetMedium (), rStorage, rDoc,
1003 msfilter::util::getBestTextEncodingFromLocale(
1004 Application::GetSettings().GetLanguageTag().getLocale()));
1005 aData.meOutput = EXC_OUTPUT_XML_2007;
1006 aData.maXclMaxPos.Set( EXC_MAXCOL_XML_2007, EXC_MAXROW_XML_2007, EXC_MAXTAB_XML_2007 );
1007 aData.maMaxPos.SetCol( ::std::min( aData.maScMaxPos.Col(), aData.maXclMaxPos.Col() ) );
1008 aData.maMaxPos.SetRow( ::std::min( aData.maScMaxPos.Row(), aData.maXclMaxPos.Row() ) );
1009 aData.maMaxPos.SetTab( ::std::min( aData.maScMaxPos.Tab(), aData.maXclMaxPos.Tab() ) );
1010 aData.mpCompileFormulaCxt.reset( new sc::CompileFormulaContext(&rDoc) );
1011 // set target path to get correct relative links to target document, not source
1012 INetURLObject aPath(getFileUrl());
1013 aData.maBasePath = aPath.GetPath() + "\\";
1014 aData.maBasePath = "file:///" + aData.maBasePath.replace('\\', '/');
1016 XclExpRoot aRoot( aData );
1018 mpRoot = &aRoot;
1019 aRoot.GetOldRoot().pER = &aRoot;
1020 aRoot.GetOldRoot().eDateiTyp = Biff8;
1021 // Get the viewsettings before processing
1022 if( ScDocShell::GetViewData() )
1023 ScDocShell::GetViewData()->WriteExtOptions( mpRoot->GetExtDocOptions() );
1025 OUString const workbook = "xl/workbook.xml";
1026 const char* pWorkbookContentType = nullptr;
1027 if (mbExportVBA)
1029 if (mbExportTemplate)
1031 pWorkbookContentType = "application/vnd.ms-excel.template.macroEnabled.main+xml";
1033 else
1035 pWorkbookContentType = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
1038 else
1040 if (mbExportTemplate)
1042 pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml";
1044 else
1046 pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
1050 PushStream( CreateOutputStream( workbook, workbook,
1051 uno::Reference <XOutputStream>(),
1052 pWorkbookContentType,
1053 OUStringToOString(oox::getRelationship(Relationship::OFFICEDOCUMENT), RTL_TEXTENCODING_UTF8).getStr() ) );
1055 if (mbExportVBA)
1057 VbaExport aExport(getModel());
1058 if (aExport.containsVBAProject())
1060 SvMemoryStream aVbaStream(4096, 4096);
1061 tools::SvRef<SotStorage> pVBAStorage(new SotStorage(aVbaStream));
1062 aExport.exportVBA( pVBAStorage.get() );
1063 aVbaStream.Seek(0);
1064 css::uno::Reference<css::io::XInputStream> xVBAStream(
1065 new utl::OInputStreamWrapper(aVbaStream));
1066 css::uno::Reference<css::io::XOutputStream> xVBAOutput =
1067 openFragmentStream("xl/vbaProject.bin", "application/vnd.ms-office.vbaProject");
1068 comphelper::OStorageHelper::CopyInputToOutput(xVBAStream, xVBAOutput);
1070 addRelation(GetCurrentStream()->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), "vbaProject.bin");
1074 // destruct at the end of the block
1076 ExcDocument aDocRoot( aRoot );
1077 if (xStatusIndicator.is())
1078 xStatusIndicator->setValue(10);
1079 aDocRoot.ReadDoc();
1080 if (xStatusIndicator.is())
1081 xStatusIndicator->setValue(40);
1082 aDocRoot.WriteXml( *this );
1085 PopStream();
1086 // Free all FSHelperPtr, to flush data before committing storage
1087 maOpenedStreamMap.clear();
1089 commitStorage();
1091 if (xStatusIndicator.is())
1092 xStatusIndicator->end();
1093 mpRoot = nullptr;
1094 return true;
1097 ::oox::ole::VbaProject* XclExpXmlStream::implCreateVbaProject() const
1099 return new ::oox::xls::ExcelVbaProject( getComponentContext(), uno::Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
1102 OUString XclExpXmlStream::getImplementationName()
1104 return "TODO";
1107 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */