Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / excel / xestream.cxx
blob406b138b513e75d64465723088fb2945b7a67799
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 <rtl/ustring.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <rtl/random.h>
28 #include <sax/fshelper.hxx>
29 #include <unotools/streamwrap.hxx>
31 #include "docuno.hxx"
32 #include "xestream.hxx"
33 #include "xladdress.hxx"
34 #include "xlstring.hxx"
35 #include "xeroot.hxx"
36 #include "xestyle.hxx"
37 #include "xcl97rec.hxx"
38 #include "rangelst.hxx"
39 #include "compiler.hxx"
40 #include "formulacell.hxx"
41 #include "tokenarray.hxx"
42 #include "tokenstringcontext.hxx"
43 #include "refreshtimerprotector.hxx"
44 #include "globstr.hrc"
46 #include <../../ui/inc/docsh.hxx>
47 #include <../../ui/inc/viewdata.hxx>
48 #include <excdoc.hxx>
50 #include <oox/token/tokens.hxx>
51 #include <formula/grammar.hxx>
52 #include <oox/export/drawingml.hxx>
53 #include <oox/ole/vbaexport.hxx>
54 #include <excelvbaproject.hxx>
56 #include <sfx2/docfile.hxx>
57 #include <sfx2/objsh.hxx>
58 #include <sfx2/app.hxx>
60 #include <com/sun/star/task/XStatusIndicator.hpp>
61 #include <memory>
62 #include <comphelper/storagehelper.hxx>
64 #define DEBUG_XL_ENCRYPTION 0
66 using ::com::sun::star::uno::XInterface;
67 using ::std::vector;
69 using namespace com::sun::star;
70 using namespace ::com::sun::star::beans;
71 using namespace ::com::sun::star::io;
72 using namespace ::com::sun::star::lang;
73 using namespace ::com::sun::star::sheet;
74 using namespace ::com::sun::star::uno;
75 using namespace ::formula;
76 using namespace ::oox;
78 XclExpStream::XclExpStream( SvStream& rOutStrm, const XclExpRoot& rRoot, sal_uInt16 nMaxRecSize ) :
79 mrStrm( rOutStrm ),
80 mrRoot( rRoot ),
81 mbUseEncrypter( false ),
82 mnMaxRecSize( nMaxRecSize ),
83 mnCurrMaxSize( 0 ),
84 mnMaxSliceSize( 0 ),
85 mnHeaderSize( 0 ),
86 mnCurrSize( 0 ),
87 mnSliceSize( 0 ),
88 mnPredictSize( 0 ),
89 mnLastSizePos( 0 ),
90 mbInRec( false )
92 if( mnMaxRecSize == 0 )
93 mnMaxRecSize = (mrRoot.GetBiff() <= EXC_BIFF5) ? EXC_MAXRECSIZE_BIFF5 : EXC_MAXRECSIZE_BIFF8;
94 mnMaxContSize = mnMaxRecSize;
97 XclExpStream::~XclExpStream()
99 mrStrm.Flush();
102 void XclExpStream::StartRecord( sal_uInt16 nRecId, sal_Size nRecSize )
104 OSL_ENSURE( !mbInRec, "XclExpStream::StartRecord - another record still open" );
105 DisableEncryption();
106 mnMaxContSize = mnCurrMaxSize = mnMaxRecSize;
107 mnPredictSize = nRecSize;
108 mbInRec = true;
109 InitRecord( nRecId );
110 SetSliceSize( 0 );
111 EnableEncryption();
114 void XclExpStream::EndRecord()
116 OSL_ENSURE( mbInRec, "XclExpStream::EndRecord - no record open" );
117 DisableEncryption();
118 UpdateRecSize();
119 mrStrm.Seek( STREAM_SEEK_TO_END );
120 mbInRec = false;
123 void XclExpStream::SetSliceSize( sal_uInt16 nSize )
125 mnMaxSliceSize = nSize;
126 mnSliceSize = 0;
129 XclExpStream& XclExpStream::operator<<( sal_Int8 nValue )
131 PrepareWrite( 1 );
132 if (mbUseEncrypter && HasValidEncrypter())
133 mxEncrypter->Encrypt(mrStrm, nValue);
134 else
135 mrStrm.WriteSChar( nValue );
136 return *this;
139 XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue )
141 PrepareWrite( 1 );
142 if (mbUseEncrypter && HasValidEncrypter())
143 mxEncrypter->Encrypt(mrStrm, nValue);
144 else
145 mrStrm.WriteUChar( nValue );
146 return *this;
149 XclExpStream& XclExpStream::operator<<( sal_Int16 nValue )
151 PrepareWrite( 2 );
152 if (mbUseEncrypter && HasValidEncrypter())
153 mxEncrypter->Encrypt(mrStrm, nValue);
154 else
155 mrStrm.WriteInt16( nValue );
156 return *this;
159 XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue )
161 PrepareWrite( 2 );
162 if (mbUseEncrypter && HasValidEncrypter())
163 mxEncrypter->Encrypt(mrStrm, nValue);
164 else
165 mrStrm.WriteUInt16( nValue );
166 return *this;
169 XclExpStream& XclExpStream::operator<<( sal_Int32 nValue )
171 PrepareWrite( 4 );
172 if (mbUseEncrypter && HasValidEncrypter())
173 mxEncrypter->Encrypt(mrStrm, nValue);
174 else
175 mrStrm.WriteInt32( nValue );
176 return *this;
179 XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue )
181 PrepareWrite( 4 );
182 if (mbUseEncrypter && HasValidEncrypter())
183 mxEncrypter->Encrypt(mrStrm, nValue);
184 else
185 mrStrm.WriteUInt32( nValue );
186 return *this;
189 XclExpStream& XclExpStream::operator<<( float fValue )
191 PrepareWrite( 4 );
192 if (mbUseEncrypter && HasValidEncrypter())
193 mxEncrypter->Encrypt(mrStrm, fValue);
194 else
195 mrStrm.WriteFloat( fValue );
196 return *this;
199 XclExpStream& XclExpStream::operator<<( double fValue )
201 PrepareWrite( 8 );
202 if (mbUseEncrypter && HasValidEncrypter())
203 mxEncrypter->Encrypt(mrStrm, fValue);
204 else
205 mrStrm.WriteDouble( fValue );
206 return *this;
209 sal_Size XclExpStream::Write( const void* pData, sal_Size nBytes )
211 sal_Size nRet = 0;
212 if( pData && (nBytes > 0) )
214 if( mbInRec )
216 const sal_uInt8* pBuffer = static_cast< const sal_uInt8* >( pData );
217 sal_Size nBytesLeft = nBytes;
218 bool bValid = true;
220 while( bValid && (nBytesLeft > 0) )
222 sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
223 sal_Size nWriteRet = nWriteLen;
224 if (mbUseEncrypter && HasValidEncrypter())
226 OSL_ENSURE(nWriteLen > 0, "XclExpStream::Write: write length is 0!");
227 vector<sal_uInt8> aBytes(nWriteLen);
228 memcpy(&aBytes[0], pBuffer, nWriteLen);
229 mxEncrypter->EncryptBytes(mrStrm, aBytes);
230 // TODO: How do I check if all the bytes have been successfully written ?
232 else
234 nWriteRet = mrStrm.Write( pBuffer, nWriteLen );
235 bValid = (nWriteLen == nWriteRet);
236 OSL_ENSURE( bValid, "XclExpStream::Write - stream write error" );
238 pBuffer += nWriteRet;
239 nRet += nWriteRet;
240 nBytesLeft -= nWriteRet;
241 UpdateSizeVars( nWriteRet );
244 else
245 nRet = mrStrm.Write( pData, nBytes );
247 return nRet;
250 void XclExpStream::WriteZeroBytes( sal_Size nBytes )
252 if( mbInRec )
254 sal_Size nBytesLeft = nBytes;
255 while( nBytesLeft > 0 )
257 sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
258 WriteRawZeroBytes( nWriteLen );
259 nBytesLeft -= nWriteLen;
260 UpdateSizeVars( nWriteLen );
263 else
264 WriteRawZeroBytes( nBytes );
267 void XclExpStream::WriteZeroBytesToRecord( sal_Size nBytes )
269 if (!mbInRec)
270 // not in record.
271 return;
273 sal_uInt8 nZero = 0;
274 for (sal_Size i = 0; i < nBytes; ++i)
275 *this << nZero;
278 void XclExpStream::CopyFromStream(SvStream& rInStrm, sal_uInt64 const nBytes)
280 sal_uInt64 const nRemaining(rInStrm.remainingSize());
281 sal_uInt64 nBytesLeft = ::std::min(nBytes, nRemaining);
282 if( nBytesLeft > 0 )
284 const sal_Size nMaxBuffer = 4096;
285 std::unique_ptr<sal_uInt8[]> pBuffer(
286 new sal_uInt8[ ::std::min<sal_Size>(nBytesLeft, nMaxBuffer) ]);
287 bool bValid = true;
289 while( bValid && (nBytesLeft > 0) )
291 sal_Size nWriteLen = ::std::min<sal_Size>(nBytesLeft, nMaxBuffer);
292 rInStrm.Read( pBuffer.get(), nWriteLen );
293 sal_Size nWriteRet = Write( pBuffer.get(), nWriteLen );
294 bValid = (nWriteLen == nWriteRet);
295 nBytesLeft -= nWriteRet;
300 void XclExpStream::WriteUnicodeBuffer( const ScfUInt16Vec& rBuffer, sal_uInt8 nFlags )
302 SetSliceSize( 0 );
303 nFlags &= EXC_STRF_16BIT; // repeat only 16bit flag
304 sal_uInt16 nCharLen = nFlags ? 2 : 1;
306 ScfUInt16Vec::const_iterator aEnd = rBuffer.end();
307 for( ScfUInt16Vec::const_iterator aIter = rBuffer.begin(); aIter != aEnd; ++aIter )
309 if( mbInRec && (mnCurrSize + nCharLen > mnCurrMaxSize) )
311 StartContinue();
312 operator<<( nFlags );
314 if( nCharLen == 2 )
315 operator<<( *aIter );
316 else
317 operator<<( static_cast< sal_uInt8 >( *aIter ) );
321 // Xcl has an obscure sense of whether starting a new record or not,
322 // and crashes if it encounters the string header at the very end of a record.
323 // Thus we add 1 to give some room, seems like they do it that way but with another count (10?)
324 void XclExpStream::WriteByteString( const OString& rString )
326 SetSliceSize( 0 );
327 sal_Size nLen = ::std::min< sal_Size >( rString.getLength(), 0x00FF );
328 nLen = ::std::min< sal_Size >( nLen, 0xFF );
330 sal_uInt16 nLeft = PrepareWrite();
331 if( mbInRec && (nLeft <= 1) )
332 StartContinue();
334 operator<<( static_cast< sal_uInt8 >( nLen ) );
335 Write( rString.getStr(), nLen );
338 void XclExpStream::WriteCharBuffer( const ScfUInt8Vec& rBuffer )
340 SetSliceSize( 0 );
341 Write( &rBuffer[ 0 ], rBuffer.size() );
344 void XclExpStream::SetEncrypter( XclExpEncrypterRef xEncrypter )
346 mxEncrypter = xEncrypter;
349 bool XclExpStream::HasValidEncrypter() const
351 return mxEncrypter && mxEncrypter->IsValid();
354 void XclExpStream::EnableEncryption( bool bEnable )
356 mbUseEncrypter = bEnable && HasValidEncrypter();
359 void XclExpStream::DisableEncryption()
361 EnableEncryption(false);
364 void XclExpStream::SetSvStreamPos(sal_uInt64 const nPos)
366 OSL_ENSURE( !mbInRec, "XclExpStream::SetSvStreamPos - not allowed inside of a record" );
367 mbInRec ? 0 : mrStrm.Seek( nPos );
370 // private --------------------------------------------------------------------
372 void XclExpStream::InitRecord( sal_uInt16 nRecId )
374 mrStrm.Seek( STREAM_SEEK_TO_END );
375 mrStrm.WriteUInt16( nRecId );
377 mnLastSizePos = mrStrm.Tell();
378 mnHeaderSize = static_cast< sal_uInt16 >( ::std::min< sal_Size >( mnPredictSize, mnCurrMaxSize ) );
379 mrStrm.WriteUInt16( mnHeaderSize );
380 mnCurrSize = mnSliceSize = 0;
383 void XclExpStream::UpdateRecSize()
385 if( mnCurrSize != mnHeaderSize )
387 mrStrm.Seek( mnLastSizePos );
388 mrStrm.WriteUInt16( mnCurrSize );
392 void XclExpStream::UpdateSizeVars( sal_Size nSize )
394 OSL_ENSURE( mnCurrSize + nSize <= mnCurrMaxSize, "XclExpStream::UpdateSizeVars - record overwritten" );
395 mnCurrSize = mnCurrSize + static_cast< sal_uInt16 >( nSize );
397 if( mnMaxSliceSize > 0 )
399 OSL_ENSURE( mnSliceSize + nSize <= mnMaxSliceSize, "XclExpStream::UpdateSizeVars - slice overwritten" );
400 mnSliceSize = mnSliceSize + static_cast< sal_uInt16 >( nSize );
401 if( mnSliceSize >= mnMaxSliceSize )
402 mnSliceSize = 0;
406 void XclExpStream::StartContinue()
408 UpdateRecSize();
409 mnCurrMaxSize = mnMaxContSize;
410 mnPredictSize -= mnCurrSize;
411 InitRecord( EXC_ID_CONT );
414 void XclExpStream::PrepareWrite( sal_uInt16 nSize )
416 if( mbInRec )
418 if( (mnCurrSize + nSize > mnCurrMaxSize) ||
419 ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
420 StartContinue();
421 UpdateSizeVars( nSize );
425 sal_uInt16 XclExpStream::PrepareWrite()
427 sal_uInt16 nRet = 0;
428 if( mbInRec )
430 if( (mnCurrSize >= mnCurrMaxSize) ||
431 ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
432 StartContinue();
433 UpdateSizeVars( 0 );
435 nRet = (mnMaxSliceSize > 0) ? (mnMaxSliceSize - mnSliceSize) : (mnCurrMaxSize - mnCurrSize);
437 return nRet;
440 void XclExpStream::WriteRawZeroBytes( sal_Size nBytes )
442 const sal_uInt32 nData = 0;
443 sal_Size nBytesLeft = nBytes;
444 while( nBytesLeft >= sizeof( nData ) )
446 mrStrm.WriteUInt32( nData );
447 nBytesLeft -= sizeof( nData );
449 if( nBytesLeft )
450 mrStrm.Write( &nData, nBytesLeft );
453 XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot& rRoot ) :
454 mnOldPos(STREAM_SEEK_TO_END),
455 mbValid(false)
457 Sequence< NamedValue > aEncryptionData = rRoot.GetEncryptionData();
458 if( !aEncryptionData.hasElements() )
459 // Empty password. Get the default biff8 password.
460 aEncryptionData = rRoot.GenerateDefaultEncryptionData();
461 Init( aEncryptionData );
464 XclExpBiff8Encrypter::~XclExpBiff8Encrypter()
468 void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 pnSaltDigest[16] ) const
470 if ( sizeof( mpnSaltDigest ) == 16 )
471 memcpy( pnSaltDigest, mpnSaltDigest, 16 );
474 void XclExpBiff8Encrypter::GetSalt( sal_uInt8 pnSalt[16] ) const
476 if ( sizeof( mpnSalt ) == 16 )
477 memcpy( pnSalt, mpnSalt, 16 );
480 void XclExpBiff8Encrypter::GetDocId( sal_uInt8 pnDocId[16] ) const
482 if ( sizeof( mpnDocId ) == 16 )
483 memcpy( pnDocId, mpnDocId, 16 );
486 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt8 nData )
488 vector<sal_uInt8> aByte(1);
489 aByte[0] = nData;
490 EncryptBytes(rStrm, aByte);
493 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt16 nData )
495 ::std::vector<sal_uInt8> pnBytes(2);
496 pnBytes[0] = nData & 0xFF;
497 pnBytes[1] = (nData >> 8) & 0xFF;
498 EncryptBytes(rStrm, pnBytes);
501 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt32 nData )
503 ::std::vector<sal_uInt8> pnBytes(4);
504 pnBytes[0] = nData & 0xFF;
505 pnBytes[1] = (nData >> 8) & 0xFF;
506 pnBytes[2] = (nData >> 16) & 0xFF;
507 pnBytes[3] = (nData >> 24) & 0xFF;
508 EncryptBytes(rStrm, pnBytes);
511 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, float fValue )
513 ::std::vector<sal_uInt8> pnBytes(4);
514 memcpy(&pnBytes[0], &fValue, 4);
515 EncryptBytes(rStrm, pnBytes);
518 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, double fValue )
520 ::std::vector<sal_uInt8> pnBytes(8);
521 memcpy(&pnBytes[0], &fValue, 8);
522 EncryptBytes(rStrm, pnBytes);
525 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int8 nData )
527 Encrypt(rStrm, static_cast<sal_uInt8>(nData));
530 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int16 nData )
532 Encrypt(rStrm, static_cast<sal_uInt16>(nData));
535 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int32 nData )
537 Encrypt(rStrm, static_cast<sal_uInt32>(nData));
540 void XclExpBiff8Encrypter::Init( const Sequence< NamedValue >& rEncryptionData )
542 mbValid = false;
544 if( maCodec.InitCodec( rEncryptionData ) )
546 maCodec.GetDocId( mpnDocId );
548 // generate the salt here
549 TimeValue aTime;
550 osl_getSystemTime( &aTime );
551 rtlRandomPool aRandomPool = rtl_random_createPool ();
552 rtl_random_addBytes( aRandomPool, &aTime, 8 );
553 rtl_random_getBytes( aRandomPool, mpnSalt, 16 );
554 rtl_random_destroyPool( aRandomPool );
556 memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) );
558 // generate salt hash.
559 ::msfilter::MSCodec_Std97 aCodec;
560 aCodec.InitCodec( rEncryptionData );
561 aCodec.CreateSaltDigest( mpnSalt, mpnSaltDigest );
563 // verify to make sure it's in good shape.
564 mbValid = maCodec.VerifyKey( mpnSalt, mpnSaltDigest );
568 sal_uInt32 XclExpBiff8Encrypter::GetBlockPos( sal_Size nStrmPos )
570 return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
573 sal_uInt16 XclExpBiff8Encrypter::GetOffsetInBlock( sal_Size nStrmPos )
575 return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
578 void XclExpBiff8Encrypter::EncryptBytes( SvStream& rStrm, vector<sal_uInt8>& aBytes )
580 sal_uInt64 nStrmPos = rStrm.Tell();
581 sal_uInt16 nBlockOffset = GetOffsetInBlock(nStrmPos);
582 sal_uInt32 nBlockPos = GetBlockPos(nStrmPos);
584 #if DEBUG_XL_ENCRYPTION
585 fprintf(stdout, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld offset in block = %d block pos = %ld\n",
586 nStrmPos, nBlockOffset, nBlockPos);
587 #endif
589 sal_uInt16 nSize = static_cast< sal_uInt16 >( aBytes.size() );
590 if (nSize == 0)
591 return;
593 #if DEBUG_XL_ENCRYPTION
594 fprintf(stdout, "RAW: ");
595 for (sal_uInt16 i = 0; i < nSize; ++i)
596 fprintf(stdout, "%2.2X ", aBytes[i]);
597 fprintf(stdout, "\n");
598 #endif
600 if (mnOldPos != nStrmPos)
602 sal_uInt16 nOldOffset = GetOffsetInBlock(mnOldPos);
603 sal_uInt32 nOldBlockPos = GetBlockPos(mnOldPos);
605 if ( (nBlockPos != nOldBlockPos) || (nBlockOffset < nOldOffset) )
607 maCodec.InitCipher(nBlockPos);
608 nOldOffset = 0;
611 if (nBlockOffset > nOldOffset)
612 maCodec.Skip(nBlockOffset - nOldOffset);
615 sal_uInt16 nBytesLeft = nSize;
616 sal_uInt16 nPos = 0;
617 while (nBytesLeft > 0)
619 sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - nBlockOffset;
620 sal_uInt16 nEncBytes = ::std::min(nBlockLeft, nBytesLeft);
622 bool bRet = maCodec.Encode(&aBytes[nPos], nEncBytes, &aBytes[nPos], nEncBytes);
623 OSL_ENSURE(bRet, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!");
624 (void) bRet; // to remove a silly compiler warning.
626 sal_Size nRet = rStrm.Write(&aBytes[nPos], nEncBytes);
627 OSL_ENSURE(nRet == nEncBytes, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!");
628 (void) nRet; // to remove a silly compiler warning.
630 nStrmPos = rStrm.Tell();
631 nBlockOffset = GetOffsetInBlock(nStrmPos);
632 nBlockPos = GetBlockPos(nStrmPos);
633 if (nBlockOffset == 0)
634 maCodec.InitCipher(nBlockPos);
636 nBytesLeft -= nEncBytes;
637 nPos += nEncBytes;
639 mnOldPos = nStrmPos;
642 static const char* lcl_GetErrorString( sal_uInt16 nScErrCode )
644 sal_uInt8 nXclErrCode = XclTools::GetXclErrorCode( nScErrCode );
645 switch( nXclErrCode )
647 case EXC_ERR_NULL: return "#NULL!";
648 case EXC_ERR_DIV0: return "#DIV/0!";
649 case EXC_ERR_VALUE: return "#VALUE!";
650 case EXC_ERR_REF: return "#REF!";
651 case EXC_ERR_NAME: return "#NAME?";
652 case EXC_ERR_NUM: return "#NUM!";
653 case EXC_ERR_NA:
654 default: return "#N/A";
658 void XclXmlUtils::GetFormulaTypeAndValue( ScFormulaCell& rCell, const char*& rsType, OUString& rsValue )
660 sc::FormulaResultValue aResValue = rCell.GetResult();
662 switch (aResValue.meType)
664 case sc::FormulaResultValue::Error:
665 rsType = "e";
666 rsValue = ToOUString(lcl_GetErrorString(aResValue.mnError));
667 break;
668 case sc::FormulaResultValue::Value:
669 rsType = "n";
670 rsValue = OUString::number(aResValue.mfValue);
671 break;
672 case sc::FormulaResultValue::String:
673 rsType = "str";
674 rsValue = rCell.GetString().getString();
675 break;
676 case sc::FormulaResultValue::Invalid:
677 default:
678 // TODO : double-check this to see if this is correct.
679 rsType = "inlineStr";
680 rsValue = rCell.GetString().getString();
684 OUString XclXmlUtils::GetStreamName( const char* sStreamDir, const char* sStream, sal_Int32 nId )
686 OUStringBuffer sBuf;
687 if( sStreamDir )
688 sBuf.appendAscii( sStreamDir );
689 sBuf.appendAscii( sStream );
690 if( nId )
691 sBuf.append( nId );
692 if( strstr(sStream, "vml") )
693 sBuf.append( ".vml" );
694 else
695 sBuf.append( ".xml" );
696 return sBuf.makeStringAndClear();
699 OString XclXmlUtils::ToOString( const Color& rColor )
701 char buf[9];
702 sprintf( buf, "%.2X%.2X%.2X%.2X", 0xFF-rColor.GetTransparency(), rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
703 buf[8] = '\0';
704 return OString( buf );
707 OString XclXmlUtils::ToOString( const OUString& s )
709 return OUStringToOString( s, RTL_TEXTENCODING_UTF8 );
712 OStringBuffer& XclXmlUtils::ToOString( OStringBuffer& s, const ScAddress& rAddress )
714 rAddress.Format(s, ScRefFlags::VALID, nullptr, ScAddress::Details( FormulaGrammar::CONV_XL_A1));
715 return s;
718 OString XclXmlUtils::ToOString( const ScfUInt16Vec& rBuffer )
720 if(rBuffer.empty())
721 return OString();
723 const sal_uInt16* pBuffer = &rBuffer [0];
724 return OString(
725 reinterpret_cast<sal_Unicode const *>(pBuffer), rBuffer.size(),
726 RTL_TEXTENCODING_UTF8);
729 OString XclXmlUtils::ToOString( const ScRange& rRange, bool bFullAddressNotation )
731 OUString sRange(rRange.Format( ScRefFlags::VALID, nullptr,
732 ScAddress::Details( FormulaGrammar::CONV_XL_A1 ),
733 bFullAddressNotation ) );
734 return ToOString( sRange );
737 OString XclXmlUtils::ToOString( const ScRangeList& rRangeList )
739 OUString s;
740 rRangeList.Format(s, ScRefFlags::VALID, nullptr, FormulaGrammar::CONV_XL_OOX, ' ');
741 return ToOString( s );
744 static ScAddress lcl_ToAddress( const XclAddress& rAddress )
746 ScAddress aAddress;
748 // For some reason, ScRange::Format() returns omits row numbers if
749 // the row is >= MAXROW or the column is >= MAXCOL, and Excel doesn't
750 // like "A:IV" (i.e. no row numbers). Prevent this.
751 // KOHEI: Find out if the above comment is still true.
752 aAddress.SetRow( std::min<sal_Int32>( rAddress.mnRow, MAXROW ) );
753 aAddress.SetCol( static_cast<sal_Int16>(std::min<sal_Int32>( rAddress.mnCol, MAXCOL )) );
755 return aAddress;
758 OStringBuffer& XclXmlUtils::ToOString( OStringBuffer& s, const XclAddress& rAddress )
760 return ToOString( s, lcl_ToAddress( rAddress ));
763 OString XclXmlUtils::ToOString( const XclExpString& s )
765 OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
766 return ToOString( s.GetUnicodeBuffer() );
769 static ScRange lcl_ToRange( const XclRange& rRange )
771 ScRange aRange;
773 aRange.aStart = lcl_ToAddress( rRange.maFirst );
774 aRange.aEnd = lcl_ToAddress( rRange.maLast );
776 return aRange;
779 OString XclXmlUtils::ToOString( const XclRangeList& rRanges )
781 ScRangeList aRanges;
782 for( XclRangeVector::const_iterator i = rRanges.begin(), end = rRanges.end();
783 i != end; ++i )
785 aRanges.Append( lcl_ToRange( *i ) );
787 return ToOString( aRanges );
790 OUString XclXmlUtils::ToOUString( const char* s )
792 return OUString( s, (sal_Int32) strlen( s ), RTL_TEXTENCODING_ASCII_US );
795 OUString XclXmlUtils::ToOUString( const ScfUInt16Vec& rBuf, sal_Int32 nStart, sal_Int32 nLength )
797 if( nLength == -1 || ( nLength > ((sal_Int32)rBuf.size() - nStart) ) )
798 nLength = (rBuf.size() - nStart);
800 return nLength > 0
801 ? OUString(
802 reinterpret_cast<sal_Unicode const *>(&rBuf[nStart]), nLength)
803 : OUString();
806 OUString XclXmlUtils::ToOUString(
807 sc::CompileFormulaContext& rCtx, const ScAddress& rAddress, const ScTokenArray* pTokenArray )
809 ScCompiler aCompiler( rCtx, rAddress, const_cast<ScTokenArray&>(*pTokenArray));
811 aCompiler.SetGrammar(FormulaGrammar::GRAM_OOXML);
813 OUStringBuffer aBuffer( pTokenArray->GetLen() * 5 );
814 aCompiler.CreateStringFromTokenArray( aBuffer );
815 return aBuffer.makeStringAndClear();
818 OUString XclXmlUtils::ToOUString( const XclExpString& s )
820 OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
821 return ToOUString( s.GetUnicodeBuffer() );
824 const char* XclXmlUtils::ToPsz( bool b )
826 return b ? "true" : "false";
829 const char* XclXmlUtils::ToPsz10( bool b )
831 // xlsx seems to use "1" or "0" for boolean values. I wonder it ever uses
832 // the "true" "false" variant.
833 return b ? "1" : "0";
836 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int32 nValue )
838 pStream->startElement( nElement, FSEND );
839 pStream->write( nValue );
840 pStream->endElement( nElement );
842 return pStream;
845 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int64 nValue )
847 pStream->startElement( nElement, FSEND );
848 pStream->write( nValue );
849 pStream->endElement( nElement );
851 return pStream;
854 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, const char* sValue )
856 pStream->startElement( nElement, FSEND );
857 pStream->write( sValue );
858 pStream->endElement( nElement );
860 return pStream;
863 static void lcl_WriteValue( sax_fastparser::FSHelperPtr& rStream, sal_Int32 nElement, const char* pValue )
865 if( !pValue )
866 return;
867 rStream->singleElement( nElement,
868 XML_val, pValue,
869 FSEND );
872 static const char* lcl_GetUnderlineStyle( FontLineStyle eUnderline, bool& bHaveUnderline )
874 bHaveUnderline = true;
875 switch( eUnderline )
877 // OOXTODO: doubleAccounting, singleAccounting
878 // OOXTODO: what should be done with the other FontLineStyle values?
879 case LINESTYLE_SINGLE: return "single";
880 case LINESTYLE_DOUBLE: return "double";
881 case LINESTYLE_NONE:
882 default: bHaveUnderline = false; return "none";
886 static const char* lcl_ToVerticalAlignmentRun( SvxEscapement eEscapement, bool& bHaveAlignment )
888 bHaveAlignment = true;
889 switch( eEscapement )
891 case SVX_ESCAPEMENT_SUPERSCRIPT: return "superscript";
892 case SVX_ESCAPEMENT_SUBSCRIPT: return "subscript";
893 case SVX_ESCAPEMENT_OFF:
894 default: bHaveAlignment = false; return "baseline";
898 sax_fastparser::FSHelperPtr XclXmlUtils::WriteFontData( sax_fastparser::FSHelperPtr pStream, const XclFontData& rFontData, sal_Int32 nFontId )
900 bool bHaveUnderline, bHaveVertAlign;
901 const char* pUnderline = lcl_GetUnderlineStyle( rFontData.GetScUnderline(), bHaveUnderline );
902 const char* pVertAlign = lcl_ToVerticalAlignmentRun( rFontData.GetScEscapement(), bHaveVertAlign );
904 lcl_WriteValue( pStream, XML_b, rFontData.mnWeight > 400 ? XclXmlUtils::ToPsz( rFontData.mnWeight > 400 ) : nullptr );
905 lcl_WriteValue( pStream, XML_i, rFontData.mbItalic ? XclXmlUtils::ToPsz( rFontData.mbItalic ) : nullptr );
906 lcl_WriteValue( pStream, XML_strike, rFontData.mbStrikeout ? XclXmlUtils::ToPsz( rFontData.mbStrikeout ) : nullptr );
907 // OOXTODO: lcl_WriteValue( rStream, XML_condense, ); // mac compatibility setting
908 // OOXTODO: lcl_WriteValue( rStream, XML_extend, ); // compatibility setting
909 lcl_WriteValue( pStream, XML_outline, rFontData.mbOutline ? XclXmlUtils::ToPsz( rFontData.mbOutline ) : nullptr );
910 lcl_WriteValue( pStream, XML_shadow, rFontData.mbShadow ? XclXmlUtils::ToPsz( rFontData.mbShadow ) : nullptr );
911 lcl_WriteValue( pStream, XML_u, bHaveUnderline ? pUnderline : nullptr );
912 lcl_WriteValue( pStream, XML_vertAlign, bHaveVertAlign ? pVertAlign : nullptr );
913 lcl_WriteValue( pStream, XML_sz, OString::number( (double) (rFontData.mnHeight / 20.0) ).getStr() ); // Twips->Pt
914 if( rFontData.maColor != Color( 0xFF, 0xFF, 0xFF, 0xFF ) )
915 pStream->singleElement( XML_color,
916 // OOXTODO: XML_auto, bool
917 // OOXTODO: XML_indexed, uint
918 XML_rgb, XclXmlUtils::ToOString( rFontData.maColor ).getStr(),
919 // OOXTODO: XML_theme, index into <clrScheme/>
920 // OOXTODO: XML_tint, double
921 FSEND );
922 lcl_WriteValue( pStream, nFontId, XclXmlUtils::ToOString( rFontData.maName ).getStr() );
923 lcl_WriteValue( pStream, XML_family, OString::number( rFontData.mnFamily ).getStr() );
924 lcl_WriteValue( pStream, XML_charset, rFontData.mnCharSet != 0 ? OString::number( rFontData.mnCharSet ).getStr() : nullptr );
926 return pStream;
929 XclExpXmlStream::XclExpXmlStream( const Reference< XComponentContext >& rCC, bool bExportVBA )
930 : XmlFilterBase( rCC ),
931 mpRoot( nullptr ),
932 mbExportVBA(bExportVBA)
936 XclExpXmlStream::~XclExpXmlStream()
938 assert(maStreams.empty() && "Forgotten PopStream()?");
941 sax_fastparser::FSHelperPtr& XclExpXmlStream::GetCurrentStream()
943 OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::GetCurrentStream - no current stream" );
944 return maStreams.top();
947 void XclExpXmlStream::PushStream( sax_fastparser::FSHelperPtr aStream )
949 maStreams.push( aStream );
952 void XclExpXmlStream::PopStream()
954 OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::PopStream - stack is empty!" );
955 maStreams.pop();
958 sax_fastparser::FSHelperPtr XclExpXmlStream::GetStreamForPath( const OUString& sPath )
960 if( maOpenedStreamMap.find( sPath ) == maOpenedStreamMap.end() )
961 return sax_fastparser::FSHelperPtr();
962 return maOpenedStreamMap[ sPath ].second;
965 sax_fastparser::FSHelperPtr& XclExpXmlStream::WriteAttributesInternal( sal_Int32 nAttribute, ... )
967 sax_fastparser::FSHelperPtr& rStream = GetCurrentStream();
969 va_list args;
970 va_start( args, nAttribute );
971 do {
972 const char* pValue = va_arg( args, const char* );
973 if( pValue )
975 rStream->write( " " )
976 ->writeId( nAttribute )
977 ->write( "=\"" )
978 ->writeEscaped( OUString(pValue, strlen(pValue), RTL_TEXTENCODING_UTF8) )
979 ->write( "\"" );
982 nAttribute = va_arg( args, sal_Int32 );
983 if( nAttribute == FSEND_internal )
984 break;
985 } while( true );
986 va_end( args );
988 return rStream;
990 sax_fastparser::FSHelperPtr XclExpXmlStream::CreateOutputStream (
991 const OUString& sFullStream,
992 const OUString& sRelativeStream,
993 const Reference< XOutputStream >& xParentRelation,
994 const char* sContentType,
995 const char* sRelationshipType,
996 OUString* pRelationshipId )
998 OUString sRelationshipId;
999 if (xParentRelation.is())
1000 sRelationshipId = addRelation( xParentRelation, OUString::createFromAscii( sRelationshipType), sRelativeStream );
1001 else
1002 sRelationshipId = addRelation( OUString::createFromAscii( sRelationshipType ), sRelativeStream );
1004 if( pRelationshipId )
1005 *pRelationshipId = sRelationshipId;
1007 sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) );
1009 maOpenedStreamMap[ sFullStream ] = std::make_pair( sRelationshipId, p );
1011 return p;
1014 bool XclExpXmlStream::importDocument() throw()
1016 return false;
1019 oox::vml::Drawing* XclExpXmlStream::getVmlDrawing()
1021 return nullptr;
1024 const oox::drawingml::Theme* XclExpXmlStream::getCurrentTheme() const
1026 return nullptr;
1029 const oox::drawingml::table::TableStyleListPtr XclExpXmlStream::getTableStyles()
1031 return oox::drawingml::table::TableStyleListPtr();
1034 oox::drawingml::chart::ChartConverter* XclExpXmlStream::getChartConverter()
1036 // DO NOT CALL
1037 return nullptr;
1040 ScDocShell* XclExpXmlStream::getDocShell()
1042 Reference< XInterface > xModel( getModel(), UNO_QUERY );
1044 ScModelObj *pObj = dynamic_cast < ScModelObj* >( xModel.get() );
1046 if ( pObj )
1047 return static_cast < ScDocShell* >( pObj->GetEmbeddedObject() );
1049 return nullptr;
1052 bool XclExpXmlStream::exportDocument()
1053 throw (css::uno::RuntimeException,
1054 css::ucb::ContentCreationException,
1055 std::exception)
1057 ScDocShell* pShell = getDocShell();
1058 ScDocument& rDoc = pShell->GetDocument();
1059 ScRefreshTimerProtector aProt(rDoc.GetRefreshTimerControlAddress());
1061 uno::Reference<task::XStatusIndicator> xStatusIndicator = getStatusIndicator();
1063 if (xStatusIndicator.is())
1064 xStatusIndicator->start(ScGlobal::GetRscString(STR_SAVE_DOC), 100);
1066 // NOTE: Don't use SotStorage or SvStream any more, and never call
1067 // SfxMedium::GetOutStream() anywhere in the xlsx export filter code!
1068 // Instead, write via XOutputStream instance.
1069 tools::SvRef<SotStorage> rStorage = static_cast<SotStorage*>(nullptr);
1070 XclExpObjList::ResetCounters();
1072 XclExpRootData aData( EXC_BIFF8, *pShell->GetMedium (), rStorage, rDoc, RTL_TEXTENCODING_DONTKNOW );
1073 aData.meOutput = EXC_OUTPUT_XML_2007;
1074 aData.maXclMaxPos.Set( EXC_MAXCOL_XML_2007, EXC_MAXROW_XML_2007, EXC_MAXTAB_XML_2007 );
1075 aData.maMaxPos.SetCol( ::std::min( aData.maScMaxPos.Col(), aData.maXclMaxPos.Col() ) );
1076 aData.maMaxPos.SetRow( ::std::min( aData.maScMaxPos.Row(), aData.maXclMaxPos.Row() ) );
1077 aData.maMaxPos.SetTab( ::std::min( aData.maScMaxPos.Tab(), aData.maXclMaxPos.Tab() ) );
1078 aData.mpCompileFormulaCxt.reset( new sc::CompileFormulaContext(&rDoc) );
1080 XclExpRoot aRoot( aData );
1082 mpRoot = &aRoot;
1083 aRoot.GetOldRoot().pER = &aRoot;
1084 aRoot.GetOldRoot().eDateiTyp = Biff8;
1085 // Get the viewsettings before processing
1086 if( ScDocShell::GetViewData() )
1087 ScDocShell::GetViewData()->WriteExtOptions( mpRoot->GetExtDocOptions() );
1089 OUString const workbook = "xl/workbook.xml";
1090 const char* pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
1093 if (mbExportVBA)
1094 pWorkbookContentType = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
1096 PushStream( CreateOutputStream( workbook, workbook,
1097 Reference <XOutputStream>(),
1098 pWorkbookContentType,
1099 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" ) );
1101 if (mbExportVBA)
1103 VbaExport aExport(getModel());
1104 if (aExport.containsVBAProject())
1106 SvMemoryStream aVbaStream(4096, 4096);
1107 tools::SvRef<SotStorage> pVBAStorage(new SotStorage(aVbaStream));
1108 aExport.exportVBA(pVBAStorage);
1109 aVbaStream.Seek(0);
1110 css::uno::Reference<css::io::XInputStream> xVBAStream(
1111 new utl::OInputStreamWrapper(aVbaStream));
1112 css::uno::Reference<css::io::XOutputStream> xVBAOutput =
1113 openFragmentStream("xl/vbaProject.bin", "application/vnd.ms-office.vbaProject");
1114 comphelper::OStorageHelper::CopyInputToOutput(xVBAStream, xVBAOutput);
1116 addRelation(GetCurrentStream()->getOutputStream(), "http://schemas.microsoft.com/office/2006/relationships/vbaProject", "vbaProject.bin");
1120 // destruct at the end of the block
1122 ExcDocument aDocRoot( aRoot );
1123 if (xStatusIndicator.is())
1124 xStatusIndicator->setValue(10);
1125 aDocRoot.ReadDoc();
1126 if (xStatusIndicator.is())
1127 xStatusIndicator->setValue(40);
1128 aDocRoot.WriteXml( *this );
1131 PopStream();
1132 // Free all FSHelperPtr, to flush data before committing storage
1133 maOpenedStreamMap.clear();
1135 commitStorage();
1137 if (xStatusIndicator.is())
1138 xStatusIndicator->end();
1139 mpRoot = nullptr;
1140 return true;
1143 ::oox::ole::VbaProject* XclExpXmlStream::implCreateVbaProject() const
1145 return new ::oox::xls::ExcelVbaProject( getComponentContext(), Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
1148 OUString XclExpXmlStream::getImplementationName() throw (css::uno::RuntimeException, std::exception)
1150 return OUString( "TODO" );
1153 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */