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 <rtl/ustring.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <rtl/random.h>
28 #include <sax/fshelper.hxx>
29 #include <unotools/streamwrap.hxx>
32 #include "xestream.hxx"
33 #include "xladdress.hxx"
34 #include "xlstring.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>
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>
62 #include <comphelper/storagehelper.hxx>
64 #define DEBUG_XL_ENCRYPTION 0
66 using ::com::sun::star::uno::XInterface
;
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
) :
81 mbUseEncrypter( false ),
82 mnMaxRecSize( nMaxRecSize
),
92 if( mnMaxRecSize
== 0 )
93 mnMaxRecSize
= (mrRoot
.GetBiff() <= EXC_BIFF5
) ? EXC_MAXRECSIZE_BIFF5
: EXC_MAXRECSIZE_BIFF8
;
94 mnMaxContSize
= mnMaxRecSize
;
97 XclExpStream::~XclExpStream()
102 void XclExpStream::StartRecord( sal_uInt16 nRecId
, sal_Size nRecSize
)
104 OSL_ENSURE( !mbInRec
, "XclExpStream::StartRecord - another record still open" );
106 mnMaxContSize
= mnCurrMaxSize
= mnMaxRecSize
;
107 mnPredictSize
= nRecSize
;
109 InitRecord( nRecId
);
114 void XclExpStream::EndRecord()
116 OSL_ENSURE( mbInRec
, "XclExpStream::EndRecord - no record open" );
119 mrStrm
.Seek( STREAM_SEEK_TO_END
);
123 void XclExpStream::SetSliceSize( sal_uInt16 nSize
)
125 mnMaxSliceSize
= nSize
;
129 XclExpStream
& XclExpStream::operator<<( sal_Int8 nValue
)
132 if (mbUseEncrypter
&& HasValidEncrypter())
133 mxEncrypter
->Encrypt(mrStrm
, nValue
);
135 mrStrm
.WriteSChar( nValue
);
139 XclExpStream
& XclExpStream::operator<<( sal_uInt8 nValue
)
142 if (mbUseEncrypter
&& HasValidEncrypter())
143 mxEncrypter
->Encrypt(mrStrm
, nValue
);
145 mrStrm
.WriteUChar( nValue
);
149 XclExpStream
& XclExpStream::operator<<( sal_Int16 nValue
)
152 if (mbUseEncrypter
&& HasValidEncrypter())
153 mxEncrypter
->Encrypt(mrStrm
, nValue
);
155 mrStrm
.WriteInt16( nValue
);
159 XclExpStream
& XclExpStream::operator<<( sal_uInt16 nValue
)
162 if (mbUseEncrypter
&& HasValidEncrypter())
163 mxEncrypter
->Encrypt(mrStrm
, nValue
);
165 mrStrm
.WriteUInt16( nValue
);
169 XclExpStream
& XclExpStream::operator<<( sal_Int32 nValue
)
172 if (mbUseEncrypter
&& HasValidEncrypter())
173 mxEncrypter
->Encrypt(mrStrm
, nValue
);
175 mrStrm
.WriteInt32( nValue
);
179 XclExpStream
& XclExpStream::operator<<( sal_uInt32 nValue
)
182 if (mbUseEncrypter
&& HasValidEncrypter())
183 mxEncrypter
->Encrypt(mrStrm
, nValue
);
185 mrStrm
.WriteUInt32( nValue
);
189 XclExpStream
& XclExpStream::operator<<( float fValue
)
192 if (mbUseEncrypter
&& HasValidEncrypter())
193 mxEncrypter
->Encrypt(mrStrm
, fValue
);
195 mrStrm
.WriteFloat( fValue
);
199 XclExpStream
& XclExpStream::operator<<( double fValue
)
202 if (mbUseEncrypter
&& HasValidEncrypter())
203 mxEncrypter
->Encrypt(mrStrm
, fValue
);
205 mrStrm
.WriteDouble( fValue
);
209 sal_Size
XclExpStream::Write( const void* pData
, sal_Size nBytes
)
212 if( pData
&& (nBytes
> 0) )
216 const sal_uInt8
* pBuffer
= static_cast< const sal_uInt8
* >( pData
);
217 sal_Size nBytesLeft
= nBytes
;
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 ?
234 nWriteRet
= mrStrm
.Write( pBuffer
, nWriteLen
);
235 bValid
= (nWriteLen
== nWriteRet
);
236 OSL_ENSURE( bValid
, "XclExpStream::Write - stream write error" );
238 pBuffer
+= nWriteRet
;
240 nBytesLeft
-= nWriteRet
;
241 UpdateSizeVars( nWriteRet
);
245 nRet
= mrStrm
.Write( pData
, nBytes
);
250 void XclExpStream::WriteZeroBytes( sal_Size nBytes
)
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
);
264 WriteRawZeroBytes( nBytes
);
267 void XclExpStream::WriteZeroBytesToRecord( sal_Size nBytes
)
274 for (sal_Size i
= 0; i
< nBytes
; ++i
)
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
);
284 const sal_Size nMaxBuffer
= 4096;
285 std::unique_ptr
<sal_uInt8
[]> pBuffer(
286 new sal_uInt8
[ ::std::min
<sal_Size
>(nBytesLeft
, nMaxBuffer
) ]);
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
)
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
) )
312 operator<<( nFlags
);
315 operator<<( *aIter
);
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
)
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) )
334 operator<<( static_cast< sal_uInt8
>( nLen
) );
335 Write( rString
.getStr(), nLen
);
338 void XclExpStream::WriteCharBuffer( const ScfUInt8Vec
& rBuffer
)
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
)
406 void XclExpStream::StartContinue()
409 mnCurrMaxSize
= mnMaxContSize
;
410 mnPredictSize
-= mnCurrSize
;
411 InitRecord( EXC_ID_CONT
);
414 void XclExpStream::PrepareWrite( sal_uInt16 nSize
)
418 if( (mnCurrSize
+ nSize
> mnCurrMaxSize
) ||
419 ((mnMaxSliceSize
> 0) && (mnSliceSize
== 0) && (mnCurrSize
+ mnMaxSliceSize
> mnCurrMaxSize
)) )
421 UpdateSizeVars( nSize
);
425 sal_uInt16
XclExpStream::PrepareWrite()
430 if( (mnCurrSize
>= mnCurrMaxSize
) ||
431 ((mnMaxSliceSize
> 0) && (mnSliceSize
== 0) && (mnCurrSize
+ mnMaxSliceSize
> mnCurrMaxSize
)) )
435 nRet
= (mnMaxSliceSize
> 0) ? (mnMaxSliceSize
- mnSliceSize
) : (mnCurrMaxSize
- mnCurrSize
);
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
);
450 mrStrm
.Write( &nData
, nBytesLeft
);
453 XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot
& rRoot
) :
454 mnOldPos(STREAM_SEEK_TO_END
),
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);
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
)
544 if( maCodec
.InitCodec( rEncryptionData
) )
546 maCodec
.GetDocId( mpnDocId
);
548 // generate the salt here
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
);
589 sal_uInt16 nSize
= static_cast< sal_uInt16
>( aBytes
.size() );
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");
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
);
611 if (nBlockOffset
> nOldOffset
)
612 maCodec
.Skip(nBlockOffset
- nOldOffset
);
615 sal_uInt16 nBytesLeft
= nSize
;
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
;
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!";
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
:
666 rsValue
= ToOUString(lcl_GetErrorString(aResValue
.mnError
));
668 case sc::FormulaResultValue::Value
:
670 rsValue
= OUString::number(aResValue
.mfValue
);
672 case sc::FormulaResultValue::String
:
674 rsValue
= rCell
.GetString().getString();
676 case sc::FormulaResultValue::Invalid
:
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
)
688 sBuf
.appendAscii( sStreamDir
);
689 sBuf
.appendAscii( sStream
);
692 if( strstr(sStream
, "vml") )
693 sBuf
.append( ".vml" );
695 sBuf
.append( ".xml" );
696 return sBuf
.makeStringAndClear();
699 OString
XclXmlUtils::ToOString( const Color
& rColor
)
702 sprintf( buf
, "%.2X%.2X%.2X%.2X", 0xFF-rColor
.GetTransparency(), rColor
.GetRed(), rColor
.GetGreen(), rColor
.GetBlue() );
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
));
718 OString
XclXmlUtils::ToOString( const ScfUInt16Vec
& rBuffer
)
723 const sal_uInt16
* pBuffer
= &rBuffer
[0];
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
)
740 rRangeList
.Format(s
, ScRefFlags::VALID
, nullptr, FormulaGrammar::CONV_XL_OOX
, ' ');
741 return ToOString( s
);
744 static ScAddress
lcl_ToAddress( const XclAddress
& rAddress
)
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
)) );
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
)
773 aRange
.aStart
= lcl_ToAddress( rRange
.maFirst
);
774 aRange
.aEnd
= lcl_ToAddress( rRange
.maLast
);
779 OString
XclXmlUtils::ToOString( const XclRangeList
& rRanges
)
782 for( XclRangeVector::const_iterator i
= rRanges
.begin(), end
= rRanges
.end();
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
);
802 reinterpret_cast<sal_Unicode
const *>(&rBuf
[nStart
]), nLength
)
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
);
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
);
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
);
863 static void lcl_WriteValue( sax_fastparser::FSHelperPtr
& rStream
, sal_Int32 nElement
, const char* pValue
)
867 rStream
->singleElement( nElement
,
872 static const char* lcl_GetUnderlineStyle( FontLineStyle eUnderline
, bool& bHaveUnderline
)
874 bHaveUnderline
= true;
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";
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
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 );
929 XclExpXmlStream::XclExpXmlStream( const Reference
< XComponentContext
>& rCC
, bool bExportVBA
)
930 : XmlFilterBase( rCC
),
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!" );
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();
970 va_start( args
, nAttribute
);
972 const char* pValue
= va_arg( args
, const char* );
975 rStream
->write( " " )
976 ->writeId( nAttribute
)
978 ->writeEscaped( OUString(pValue
, strlen(pValue
), RTL_TEXTENCODING_UTF8
) )
982 nAttribute
= va_arg( args
, sal_Int32
);
983 if( nAttribute
== FSEND_internal
)
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
);
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
);
1014 bool XclExpXmlStream::importDocument() throw()
1019 oox::vml::Drawing
* XclExpXmlStream::getVmlDrawing()
1024 const oox::drawingml::Theme
* XclExpXmlStream::getCurrentTheme() const
1029 const oox::drawingml::table::TableStyleListPtr
XclExpXmlStream::getTableStyles()
1031 return oox::drawingml::table::TableStyleListPtr();
1034 oox::drawingml::chart::ChartConverter
* XclExpXmlStream::getChartConverter()
1040 ScDocShell
* XclExpXmlStream::getDocShell()
1042 Reference
< XInterface
> xModel( getModel(), UNO_QUERY
);
1044 ScModelObj
*pObj
= dynamic_cast < ScModelObj
* >( xModel
.get() );
1047 return static_cast < ScDocShell
* >( pObj
->GetEmbeddedObject() );
1052 bool XclExpXmlStream::exportDocument()
1053 throw (css::uno::RuntimeException
,
1054 css::ucb::ContentCreationException
,
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
);
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";
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" ) );
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
);
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);
1126 if (xStatusIndicator
.is())
1127 xStatusIndicator
->setValue(40);
1128 aDocRoot
.WriteXml( *this );
1132 // Free all FSHelperPtr, to flush data before committing storage
1133 maOpenedStreamMap
.clear();
1137 if (xStatusIndicator
.is())
1138 xStatusIndicator
->end();
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: */