1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
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>
37 #include <xestream.hxx>
38 #include <xladdress.hxx>
39 #include <xlstring.hxx>
40 #include <xltools.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>
54 #include <viewdata.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>
66 #include <comphelper/storagehelper.hxx>
68 #define DEBUG_XL_ENCRYPTION 0
70 using ::com::sun::star::uno::XInterface
;
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
) :
85 mbUseEncrypter( false ),
86 mnMaxRecSize( nMaxRecSize
),
96 if( mnMaxRecSize
== 0 )
97 mnMaxRecSize
= (mrRoot
.GetBiff() <= EXC_BIFF5
) ? EXC_MAXRECSIZE_BIFF5
: EXC_MAXRECSIZE_BIFF8
;
98 mnMaxContSize
= mnMaxRecSize
;
101 XclExpStream::~XclExpStream()
106 void XclExpStream::StartRecord( sal_uInt16 nRecId
, std::size_t nRecSize
)
108 OSL_ENSURE( !mbInRec
, "XclExpStream::StartRecord - another record still open" );
110 mnMaxContSize
= mnCurrMaxSize
= mnMaxRecSize
;
111 mnPredictSize
= nRecSize
;
113 InitRecord( nRecId
);
118 void XclExpStream::EndRecord()
120 OSL_ENSURE( mbInRec
, "XclExpStream::EndRecord - no record open" );
123 mrStrm
.Seek( STREAM_SEEK_TO_END
);
127 void XclExpStream::SetSliceSize( sal_uInt16 nSize
)
129 mnMaxSliceSize
= nSize
;
133 XclExpStream
& XclExpStream::operator<<( sal_Int8 nValue
)
136 if (mbUseEncrypter
&& HasValidEncrypter())
137 mxEncrypter
->Encrypt(mrStrm
, nValue
);
139 mrStrm
.WriteSChar( nValue
);
143 XclExpStream
& XclExpStream::operator<<( sal_uInt8 nValue
)
146 if (mbUseEncrypter
&& HasValidEncrypter())
147 mxEncrypter
->Encrypt(mrStrm
, nValue
);
149 mrStrm
.WriteUChar( nValue
);
153 XclExpStream
& XclExpStream::operator<<( sal_Int16 nValue
)
156 if (mbUseEncrypter
&& HasValidEncrypter())
157 mxEncrypter
->Encrypt(mrStrm
, nValue
);
159 mrStrm
.WriteInt16( nValue
);
163 XclExpStream
& XclExpStream::operator<<( sal_uInt16 nValue
)
166 if (mbUseEncrypter
&& HasValidEncrypter())
167 mxEncrypter
->Encrypt(mrStrm
, nValue
);
169 mrStrm
.WriteUInt16( nValue
);
173 XclExpStream
& XclExpStream::operator<<( sal_Int32 nValue
)
176 if (mbUseEncrypter
&& HasValidEncrypter())
177 mxEncrypter
->Encrypt(mrStrm
, nValue
);
179 mrStrm
.WriteInt32( nValue
);
183 XclExpStream
& XclExpStream::operator<<( sal_uInt32 nValue
)
186 if (mbUseEncrypter
&& HasValidEncrypter())
187 mxEncrypter
->Encrypt(mrStrm
, nValue
);
189 mrStrm
.WriteUInt32( nValue
);
193 XclExpStream
& XclExpStream::operator<<( float fValue
)
196 if (mbUseEncrypter
&& HasValidEncrypter())
197 mxEncrypter
->Encrypt(mrStrm
, fValue
);
199 mrStrm
.WriteFloat( fValue
);
203 XclExpStream
& XclExpStream::operator<<( double fValue
)
206 if (mbUseEncrypter
&& HasValidEncrypter())
207 mxEncrypter
->Encrypt(mrStrm
, fValue
);
209 mrStrm
.WriteDouble( fValue
);
213 std::size_t XclExpStream::Write( const void* pData
, std::size_t nBytes
)
215 std::size_t nRet
= 0;
216 if( pData
&& (nBytes
> 0) )
220 const sal_uInt8
* pBuffer
= static_cast< const sal_uInt8
* >( pData
);
221 std::size_t nBytesLeft
= nBytes
;
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 ?
238 nWriteRet
= mrStrm
.WriteBytes(pBuffer
, nWriteLen
);
239 bValid
= (nWriteLen
== nWriteRet
);
240 OSL_ENSURE( bValid
, "XclExpStream::Write - stream write error" );
242 pBuffer
+= nWriteRet
;
244 nBytesLeft
-= nWriteRet
;
245 UpdateSizeVars( nWriteRet
);
249 nRet
= mrStrm
.WriteBytes(pData
, nBytes
);
254 void XclExpStream::WriteZeroBytes( std::size_t nBytes
)
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
);
268 WriteRawZeroBytes( nBytes
);
271 void XclExpStream::WriteZeroBytesToRecord( std::size_t nBytes
)
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
);
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
) ]);
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
)
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
) )
314 operator<<( nFlags
);
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
)
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) )
336 operator<<( static_cast< sal_uInt8
>( nLen
) );
337 Write( rString
.getStr(), nLen
);
340 void XclExpStream::WriteCharBuffer( const ScfUInt8Vec
& rBuffer
)
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
)
408 void XclExpStream::StartContinue()
411 mnCurrMaxSize
= mnMaxContSize
;
412 mnPredictSize
-= mnCurrSize
;
413 InitRecord( EXC_ID_CONT
);
416 void XclExpStream::PrepareWrite( sal_uInt16 nSize
)
420 if( (mnCurrSize
+ nSize
> mnCurrMaxSize
) ||
421 ((mnMaxSliceSize
> 0) && (mnSliceSize
== 0) && (mnCurrSize
+ mnMaxSliceSize
> mnCurrMaxSize
)) )
423 UpdateSizeVars( nSize
);
427 sal_uInt16
XclExpStream::PrepareWrite()
432 if( (mnCurrSize
>= mnCurrMaxSize
) ||
433 ((mnMaxSliceSize
> 0) && (mnSliceSize
== 0) && (mnCurrSize
+ mnMaxSliceSize
> mnCurrMaxSize
)) )
437 nRet
= (mnMaxSliceSize
> 0) ? (mnMaxSliceSize
- mnSliceSize
) : (mnCurrMaxSize
- mnCurrSize
);
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
);
452 mrStrm
.WriteBytes(&nData
, nBytesLeft
);
455 XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot
& rRoot
) :
456 mnOldPos(STREAM_SEEK_TO_END
),
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);
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
)
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
);
588 sal_uInt16 nSize
= static_cast< sal_uInt16
>( aBytes
.size() );
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");
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
);
610 if (nBlockOffset
> nOldOffset
)
611 maCodec
.Skip(nBlockOffset
- nOldOffset
);
614 sal_uInt16 nBytesLeft
= nSize
;
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
;
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!";
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
:
663 rsValue
= ToOUString(lcl_GetErrorString(aResValue
.mnError
));
665 case sc::FormulaResultValue::Value
:
667 rsValue
= OUString::number(aResValue
.mfValue
);
669 case sc::FormulaResultValue::String
:
671 rsValue
= rCell
.GetString().getString();
673 case sc::FormulaResultValue::Invalid
:
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
)
685 sBuf
.appendAscii( sStreamDir
);
686 sBuf
.appendAscii( sStream
);
689 if( strstr(sStream
, "vml") )
690 sBuf
.append( ".vml" );
692 sBuf
.append( ".xml" );
693 return sBuf
.makeStringAndClear();
696 OString
XclXmlUtils::ToOString( const Color
& rColor
)
699 sprintf( buf
, "%.2X%.2X%.2X%.2X", 0xFF-rColor
.GetTransparency(), rColor
.GetRed(), rColor
.GetGreen(), rColor
.GetBlue() );
704 OStringBuffer
& XclXmlUtils::ToOString( OStringBuffer
& s
, const ScAddress
& rAddress
)
706 rAddress
.Format(s
, ScRefFlags::VALID
, nullptr, ScAddress::Details( FormulaGrammar::CONV_XL_A1
));
710 OString
XclXmlUtils::ToOString( const ScfUInt16Vec
& rBuffer
)
715 const sal_uInt16
* pBuffer
= rBuffer
.data();
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
)
732 rRangeList
.Format(s
, ScRefFlags::VALID
, pDoc
, FormulaGrammar::CONV_XL_OOX
, ' ');
736 static ScAddress
lcl_ToAddress( const XclAddress
& rAddress
)
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
)) );
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
)
765 aRange
.aStart
= lcl_ToAddress( rRange
.maFirst
);
766 aRange
.aEnd
= lcl_ToAddress( rRange
.maLast
);
771 OString
XclXmlUtils::ToOString( const ScDocument
* pDoc
, const XclRangeList
& rRanges
)
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
);
793 reinterpret_cast<sal_Unicode
const *>(&rBuf
[nStart
]), nLength
)
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
)
820 rStream
->singleElement(nElement
, XML_val
, pValue
);
823 static const char* lcl_GetUnderlineStyle( FontLineStyle eUnderline
, bool& bHaveUnderline
)
825 bHaveUnderline
= true;
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";
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 );
880 XclExpXmlStream::XclExpXmlStream( const uno::Reference
< XComponentContext
>& rCC
, bool bExportVBA
, bool bExportTemplate
)
881 : XmlFilterBase( rCC
),
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!" );
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
);
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
);
946 bool XclExpXmlStream::importDocument() throw()
951 oox::vml::Drawing
* XclExpXmlStream::getVmlDrawing()
956 const oox::drawingml::Theme
* XclExpXmlStream::getCurrentTheme() const
961 oox::drawingml::table::TableStyleListPtr
XclExpXmlStream::getTableStyles()
963 return oox::drawingml::table::TableStyleListPtr();
966 oox::drawingml::chart::ChartConverter
* XclExpXmlStream::getChartConverter()
972 ScDocShell
* XclExpXmlStream::getDocShell()
974 uno::Reference
< XInterface
> xModel( getModel(), UNO_QUERY
);
976 ScModelObj
*pObj
= dynamic_cast < ScModelObj
* >( xModel
.get() );
979 return static_cast < ScDocShell
* >( pObj
->GetEmbeddedObject() );
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
);
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;
1029 if (mbExportTemplate
)
1031 pWorkbookContentType
= "application/vnd.ms-excel.template.macroEnabled.main+xml";
1035 pWorkbookContentType
= "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
1040 if (mbExportTemplate
)
1042 pWorkbookContentType
= "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml";
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() ) );
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() );
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);
1080 if (xStatusIndicator
.is())
1081 xStatusIndicator
->setValue(40);
1082 aDocRoot
.WriteXml( *this );
1086 // Free all FSHelperPtr, to flush data before committing storage
1087 maOpenedStreamMap
.clear();
1091 if (xStatusIndicator
.is())
1092 xStatusIndicator
->end();
1097 ::oox::ole::VbaProject
* XclExpXmlStream::implCreateVbaProject() const
1099 return new ::oox::xls::ExcelVbaProject( getComponentContext(), uno::Reference
< XSpreadsheetDocument
>( getModel(), UNO_QUERY
) );
1102 OUString
XclExpXmlStream::getImplementationName()
1107 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */