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 <excelvbaproject.hxx>
55 #include <sfx2/docfile.hxx>
56 #include <sfx2/objsh.hxx>
57 #include <sfx2/app.hxx>
59 #include <com/sun/star/task/XStatusIndicator.hpp>
60 #include <boost/scoped_array.hpp>
62 #define DEBUG_XL_ENCRYPTION 0
64 using ::com::sun::star::embed::XStorage
;
65 using ::com::sun::star::lang::XSingleServiceFactory
;
66 using ::com::sun::star::registry::InvalidRegistryException
;
67 using ::com::sun::star::registry::XRegistryKey
;
68 using ::com::sun::star::uno::Exception
;
69 using ::com::sun::star::uno::XInterface
;
70 using ::utl::OStreamWrapper
;
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
, sal_Size 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 sal_Size
XclExpStream::Write( const void* pData
, sal_Size nBytes
)
216 if( pData
&& (nBytes
> 0) )
220 const sal_uInt8
* pBuffer
= static_cast< const sal_uInt8
* >( pData
);
221 sal_Size nBytesLeft
= nBytes
;
224 while( bValid
&& (nBytesLeft
> 0) )
226 sal_Size nWriteLen
= ::std::min
< sal_Size
>( PrepareWrite(), nBytesLeft
);
227 sal_Size 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
[0], pBuffer
, nWriteLen
);
233 mxEncrypter
->EncryptBytes(mrStrm
, aBytes
);
234 // TODO: How do I check if all the bytes have been successfully written ?
238 nWriteRet
= mrStrm
.Write( 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
.Write( pData
, nBytes
);
254 void XclExpStream::WriteZeroBytes( sal_Size nBytes
)
258 sal_Size nBytesLeft
= nBytes
;
259 while( nBytesLeft
> 0 )
261 sal_Size nWriteLen
= ::std::min
< sal_Size
>( PrepareWrite(), nBytesLeft
);
262 WriteRawZeroBytes( nWriteLen
);
263 nBytesLeft
-= nWriteLen
;
264 UpdateSizeVars( nWriteLen
);
268 WriteRawZeroBytes( nBytes
);
271 void XclExpStream::WriteZeroBytesToRecord( sal_Size nBytes
)
278 for (sal_Size i
= 0; i
< nBytes
; ++i
)
282 void XclExpStream::CopyFromStream(SvStream
& rInStrm
, sal_uInt64
const nBytes
)
284 sal_uInt64
const nRemaining(rInStrm
.remainingSize());
285 sal_uInt64 nBytesLeft
= ::std::min(nBytes
, nRemaining
);
288 const sal_Size nMaxBuffer
= 4096;
289 boost::scoped_array
<sal_uInt8
> pBuffer(
290 new sal_uInt8
[ ::std::min
<sal_Size
>(nBytesLeft
, nMaxBuffer
) ]);
293 while( bValid
&& (nBytesLeft
> 0) )
295 sal_Size nWriteLen
= ::std::min
<sal_Size
>(nBytesLeft
, nMaxBuffer
);
296 rInStrm
.Read( pBuffer
.get(), nWriteLen
);
297 sal_Size nWriteRet
= Write( pBuffer
.get(), nWriteLen
);
298 bValid
= (nWriteLen
== nWriteRet
);
299 nBytesLeft
-= nWriteRet
;
304 void XclExpStream::WriteUnicodeBuffer( const ScfUInt16Vec
& rBuffer
, sal_uInt8 nFlags
)
307 nFlags
&= EXC_STRF_16BIT
; // repeat only 16bit flag
308 sal_uInt16 nCharLen
= nFlags
? 2 : 1;
310 ScfUInt16Vec::const_iterator aEnd
= rBuffer
.end();
311 for( ScfUInt16Vec::const_iterator aIter
= rBuffer
.begin(); aIter
!= aEnd
; ++aIter
)
313 if( mbInRec
&& (mnCurrSize
+ nCharLen
> mnCurrMaxSize
) )
316 operator<<( nFlags
);
319 operator<<( *aIter
);
321 operator<<( static_cast< sal_uInt8
>( *aIter
) );
325 // Xcl has an obscure sense of whether starting a new record or not,
326 // and crashes if it encounters the string header at the very end of a record.
327 // Thus we add 1 to give some room, seems like they do it that way but with another count (10?)
328 void XclExpStream::WriteByteString( const OString
& rString
, sal_uInt16 nMaxLen
, bool b16BitCount
)
331 sal_Size nLen
= ::std::min
< sal_Size
>( rString
.getLength(), nMaxLen
);
333 nLen
= ::std::min
< sal_Size
>( nLen
, 0xFF );
335 sal_uInt16 nLeft
= PrepareWrite();
336 sal_uInt16 nLenFieldSize
= b16BitCount
? 2 : 1;
337 if( mbInRec
&& (nLeft
<= nLenFieldSize
) )
341 operator<<( static_cast< sal_uInt16
>( nLen
) );
343 operator<<( static_cast< sal_uInt8
>( nLen
) );
344 Write( rString
.getStr(), nLen
);
347 void XclExpStream::WriteCharBuffer( const ScfUInt8Vec
& rBuffer
)
350 Write( &rBuffer
[ 0 ], rBuffer
.size() );
353 void XclExpStream::SetEncrypter( XclExpEncrypterRef xEncrypter
)
355 mxEncrypter
= xEncrypter
;
358 bool XclExpStream::HasValidEncrypter() const
360 return mxEncrypter
&& mxEncrypter
->IsValid();
363 void XclExpStream::EnableEncryption( bool bEnable
)
365 mbUseEncrypter
= bEnable
&& HasValidEncrypter();
368 void XclExpStream::DisableEncryption()
370 EnableEncryption(false);
373 sal_uInt64
XclExpStream::SetSvStreamPos(sal_uInt64
const nPos
)
375 OSL_ENSURE( !mbInRec
, "XclExpStream::SetSvStreamPos - not allowed inside of a record" );
376 return mbInRec
? 0 : mrStrm
.Seek( nPos
);
379 // private --------------------------------------------------------------------
381 void XclExpStream::InitRecord( sal_uInt16 nRecId
)
383 mrStrm
.Seek( STREAM_SEEK_TO_END
);
384 mrStrm
.WriteUInt16( nRecId
);
386 mnLastSizePos
= mrStrm
.Tell();
387 mnHeaderSize
= static_cast< sal_uInt16
>( ::std::min
< sal_Size
>( mnPredictSize
, mnCurrMaxSize
) );
388 mrStrm
.WriteUInt16( mnHeaderSize
);
389 mnCurrSize
= mnSliceSize
= 0;
392 void XclExpStream::UpdateRecSize()
394 if( mnCurrSize
!= mnHeaderSize
)
396 mrStrm
.Seek( mnLastSizePos
);
397 mrStrm
.WriteUInt16( mnCurrSize
);
401 void XclExpStream::UpdateSizeVars( sal_Size nSize
)
403 OSL_ENSURE( mnCurrSize
+ nSize
<= mnCurrMaxSize
, "XclExpStream::UpdateSizeVars - record overwritten" );
404 mnCurrSize
= mnCurrSize
+ static_cast< sal_uInt16
>( nSize
);
406 if( mnMaxSliceSize
> 0 )
408 OSL_ENSURE( mnSliceSize
+ nSize
<= mnMaxSliceSize
, "XclExpStream::UpdateSizeVars - slice overwritten" );
409 mnSliceSize
= mnSliceSize
+ static_cast< sal_uInt16
>( nSize
);
410 if( mnSliceSize
>= mnMaxSliceSize
)
415 void XclExpStream::StartContinue()
418 mnCurrMaxSize
= mnMaxContSize
;
419 mnPredictSize
-= mnCurrSize
;
420 InitRecord( EXC_ID_CONT
);
423 void XclExpStream::PrepareWrite( sal_uInt16 nSize
)
427 if( (mnCurrSize
+ nSize
> mnCurrMaxSize
) ||
428 ((mnMaxSliceSize
> 0) && (mnSliceSize
== 0) && (mnCurrSize
+ mnMaxSliceSize
> mnCurrMaxSize
)) )
430 UpdateSizeVars( nSize
);
434 sal_uInt16
XclExpStream::PrepareWrite()
439 if( (mnCurrSize
>= mnCurrMaxSize
) ||
440 ((mnMaxSliceSize
> 0) && (mnSliceSize
== 0) && (mnCurrSize
+ mnMaxSliceSize
> mnCurrMaxSize
)) )
444 nRet
= (mnMaxSliceSize
> 0) ? (mnMaxSliceSize
- mnSliceSize
) : (mnCurrMaxSize
- mnCurrSize
);
449 void XclExpStream::WriteRawZeroBytes( sal_Size nBytes
)
451 const sal_uInt32 nData
= 0;
452 sal_Size nBytesLeft
= nBytes
;
453 while( nBytesLeft
>= sizeof( nData
) )
455 mrStrm
.WriteUInt32( nData
);
456 nBytesLeft
-= sizeof( nData
);
459 mrStrm
.Write( &nData
, nBytesLeft
);
462 XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot
& rRoot
) :
463 mnOldPos(STREAM_SEEK_TO_END
),
466 Sequence
< NamedValue
> aEncryptionData
= rRoot
.GetEncryptionData();
467 if( !aEncryptionData
.hasElements() )
468 // Empty password. Get the default biff8 password.
469 aEncryptionData
= rRoot
.GenerateDefaultEncryptionData();
470 Init( aEncryptionData
);
473 XclExpBiff8Encrypter::~XclExpBiff8Encrypter()
477 void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 pnSaltDigest
[16] ) const
479 if ( sizeof( mpnSaltDigest
) == 16 )
480 memcpy( pnSaltDigest
, mpnSaltDigest
, 16 );
483 void XclExpBiff8Encrypter::GetSalt( sal_uInt8 pnSalt
[16] ) const
485 if ( sizeof( mpnSalt
) == 16 )
486 memcpy( pnSalt
, mpnSalt
, 16 );
489 void XclExpBiff8Encrypter::GetDocId( sal_uInt8 pnDocId
[16] ) const
491 if ( sizeof( mpnDocId
) == 16 )
492 memcpy( pnDocId
, mpnDocId
, 16 );
495 void XclExpBiff8Encrypter::Encrypt( SvStream
& rStrm
, sal_uInt8 nData
)
497 vector
<sal_uInt8
> aByte(1);
499 EncryptBytes(rStrm
, aByte
);
502 void XclExpBiff8Encrypter::Encrypt( SvStream
& rStrm
, sal_uInt16 nData
)
504 ::std::vector
<sal_uInt8
> pnBytes(2);
505 pnBytes
[0] = nData
& 0xFF;
506 pnBytes
[1] = (nData
>> 8) & 0xFF;
507 EncryptBytes(rStrm
, pnBytes
);
510 void XclExpBiff8Encrypter::Encrypt( SvStream
& rStrm
, sal_uInt32 nData
)
512 ::std::vector
<sal_uInt8
> pnBytes(4);
513 pnBytes
[0] = nData
& 0xFF;
514 pnBytes
[1] = (nData
>> 8) & 0xFF;
515 pnBytes
[2] = (nData
>> 16) & 0xFF;
516 pnBytes
[3] = (nData
>> 24) & 0xFF;
517 EncryptBytes(rStrm
, pnBytes
);
520 void XclExpBiff8Encrypter::Encrypt( SvStream
& rStrm
, float fValue
)
522 ::std::vector
<sal_uInt8
> pnBytes(4);
523 memcpy(&pnBytes
[0], &fValue
, 4);
524 EncryptBytes(rStrm
, pnBytes
);
527 void XclExpBiff8Encrypter::Encrypt( SvStream
& rStrm
, double fValue
)
529 ::std::vector
<sal_uInt8
> pnBytes(8);
530 memcpy(&pnBytes
[0], &fValue
, 8);
531 EncryptBytes(rStrm
, pnBytes
);
534 void XclExpBiff8Encrypter::Encrypt( SvStream
& rStrm
, sal_Int8 nData
)
536 Encrypt(rStrm
, static_cast<sal_uInt8
>(nData
));
539 void XclExpBiff8Encrypter::Encrypt( SvStream
& rStrm
, sal_Int16 nData
)
541 Encrypt(rStrm
, static_cast<sal_uInt16
>(nData
));
544 void XclExpBiff8Encrypter::Encrypt( SvStream
& rStrm
, sal_Int32 nData
)
546 Encrypt(rStrm
, static_cast<sal_uInt32
>(nData
));
549 void XclExpBiff8Encrypter::Init( const Sequence
< NamedValue
>& rEncryptionData
)
553 if( maCodec
.InitCodec( rEncryptionData
) )
555 maCodec
.GetDocId( mpnDocId
);
557 // generate the salt here
559 osl_getSystemTime( &aTime
);
560 rtlRandomPool aRandomPool
= rtl_random_createPool ();
561 rtl_random_addBytes( aRandomPool
, &aTime
, 8 );
562 rtl_random_getBytes( aRandomPool
, mpnSalt
, 16 );
563 rtl_random_destroyPool( aRandomPool
);
565 memset( mpnSaltDigest
, 0, sizeof( mpnSaltDigest
) );
567 // generate salt hash.
568 ::msfilter::MSCodec_Std97 aCodec
;
569 aCodec
.InitCodec( rEncryptionData
);
570 aCodec
.CreateSaltDigest( mpnSalt
, mpnSaltDigest
);
572 // verify to make sure it's in good shape.
573 mbValid
= maCodec
.VerifyKey( mpnSalt
, mpnSaltDigest
);
577 sal_uInt32
XclExpBiff8Encrypter::GetBlockPos( sal_Size nStrmPos
)
579 return static_cast< sal_uInt32
>( nStrmPos
/ EXC_ENCR_BLOCKSIZE
);
582 sal_uInt16
XclExpBiff8Encrypter::GetOffsetInBlock( sal_Size nStrmPos
)
584 return static_cast< sal_uInt16
>( nStrmPos
% EXC_ENCR_BLOCKSIZE
);
587 void XclExpBiff8Encrypter::EncryptBytes( SvStream
& rStrm
, vector
<sal_uInt8
>& aBytes
)
589 sal_uInt64 nStrmPos
= rStrm
.Tell();
590 sal_uInt16 nBlockOffset
= GetOffsetInBlock(nStrmPos
);
591 sal_uInt32 nBlockPos
= GetBlockPos(nStrmPos
);
593 #if DEBUG_XL_ENCRYPTION
594 fprintf(stdout
, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld offset in block = %d block pos = %ld\n",
595 nStrmPos
, nBlockOffset
, nBlockPos
);
598 sal_uInt16 nSize
= static_cast< sal_uInt16
>( aBytes
.size() );
602 #if DEBUG_XL_ENCRYPTION
603 fprintf(stdout
, "RAW: ");
604 for (sal_uInt16 i
= 0; i
< nSize
; ++i
)
605 fprintf(stdout
, "%2.2X ", aBytes
[i
]);
606 fprintf(stdout
, "\n");
609 if (mnOldPos
!= nStrmPos
)
611 sal_uInt16 nOldOffset
= GetOffsetInBlock(mnOldPos
);
612 sal_uInt32 nOldBlockPos
= GetBlockPos(mnOldPos
);
614 if ( (nBlockPos
!= nOldBlockPos
) || (nBlockOffset
< nOldOffset
) )
616 maCodec
.InitCipher(nBlockPos
);
620 if (nBlockOffset
> nOldOffset
)
621 maCodec
.Skip(nBlockOffset
- nOldOffset
);
624 sal_uInt16 nBytesLeft
= nSize
;
626 while (nBytesLeft
> 0)
628 sal_uInt16 nBlockLeft
= EXC_ENCR_BLOCKSIZE
- nBlockOffset
;
629 sal_uInt16 nEncBytes
= ::std::min(nBlockLeft
, nBytesLeft
);
631 bool bRet
= maCodec
.Encode(&aBytes
[nPos
], nEncBytes
, &aBytes
[nPos
], nEncBytes
);
632 OSL_ENSURE(bRet
, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!");
633 (void) bRet
; // to remove a silly compiler warning.
635 sal_Size nRet
= rStrm
.Write(&aBytes
[nPos
], nEncBytes
);
636 OSL_ENSURE(nRet
== nEncBytes
, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!");
637 (void) nRet
; // to remove a silly compiler warning.
639 nStrmPos
= rStrm
.Tell();
640 nBlockOffset
= GetOffsetInBlock(nStrmPos
);
641 nBlockPos
= GetBlockPos(nStrmPos
);
642 if (nBlockOffset
== 0)
643 maCodec
.InitCipher(nBlockPos
);
645 nBytesLeft
-= nEncBytes
;
651 static const char* lcl_GetErrorString( sal_uInt16 nScErrCode
)
653 sal_uInt8 nXclErrCode
= XclTools::GetXclErrorCode( nScErrCode
);
654 switch( nXclErrCode
)
656 case EXC_ERR_NULL
: return "#NULL!";
657 case EXC_ERR_DIV0
: return "#DIV/0!";
658 case EXC_ERR_VALUE
: return "#VALUE!";
659 case EXC_ERR_REF
: return "#REF!";
660 case EXC_ERR_NAME
: return "#NAME?";
661 case EXC_ERR_NUM
: return "#NUM!";
663 default: return "#N/A";
667 void XclXmlUtils::GetFormulaTypeAndValue( ScFormulaCell
& rCell
, const char*& rsType
, OUString
& rsValue
)
669 sc::FormulaResultValue aResValue
= rCell
.GetResult();
671 switch (aResValue
.meType
)
673 case sc::FormulaResultValue::Error
:
675 rsValue
= ToOUString(lcl_GetErrorString(aResValue
.mnError
));
677 case sc::FormulaResultValue::Value
:
679 rsValue
= OUString::number(aResValue
.mfValue
);
681 case sc::FormulaResultValue::String
:
683 rsValue
= rCell
.GetString().getString();
685 case sc::FormulaResultValue::Invalid
:
687 // TODO : double-check this to see if this is correct.
688 rsType
= "inlineStr";
689 rsValue
= rCell
.GetString().getString();
693 OUString
XclXmlUtils::GetStreamName( const char* sStreamDir
, const char* sStream
, sal_Int32 nId
)
697 sBuf
.appendAscii( sStreamDir
);
698 sBuf
.appendAscii( sStream
);
701 if( strstr(sStream
, "vml") )
702 sBuf
.appendAscii( ".vml" );
704 sBuf
.appendAscii( ".xml" );
705 return sBuf
.makeStringAndClear();
708 OString
XclXmlUtils::ToOString( const Color
& rColor
)
711 sprintf( buf
, "%.2X%.2X%.2X%.2X", 0xFF-rColor
.GetTransparency(), rColor
.GetRed(), rColor
.GetGreen(), rColor
.GetBlue() );
713 return OString( buf
);
716 OString
XclXmlUtils::ToOString( const OUString
& s
)
718 return OUStringToOString( s
, RTL_TEXTENCODING_UTF8
);
721 OStringBuffer
& XclXmlUtils::ToOString( OStringBuffer
& s
, const ScAddress
& rAddress
)
723 rAddress
.Format(s
, SCA_VALID
, NULL
, ScAddress::Details( FormulaGrammar::CONV_XL_A1
));
727 OString
XclXmlUtils::ToOString( const ScfUInt16Vec
& rBuffer
)
732 const sal_uInt16
* pBuffer
= &rBuffer
[0];
733 return OString( pBuffer
, rBuffer
.size(), RTL_TEXTENCODING_UTF8
);
736 OString
XclXmlUtils::ToOString( const ScRange
& rRange
)
738 OUString
sRange(rRange
.Format(SCA_VALID
, NULL
, ScAddress::Details( FormulaGrammar::CONV_XL_A1
)));
739 return ToOString( sRange
);
742 OString
XclXmlUtils::ToOString( const ScRangeList
& rRangeList
)
745 rRangeList
.Format(s
, SCA_VALID
, NULL
, FormulaGrammar::CONV_XL_A1
, ' ');
746 return ToOString( s
);
749 static ScAddress
lcl_ToAddress( const XclAddress
& rAddress
)
753 // For some reason, ScRange::Format() returns omits row numbers if
754 // the row is >= MAXROW or the column is >= MAXCOL, and Excel doesn't
755 // like "A:IV" (i.e. no row numbers). Prevent this.
756 // KOHEI: Find out if the above comment is still true.
757 aAddress
.SetRow( std::min
<sal_Int32
>( rAddress
.mnRow
, MAXROW
) );
758 aAddress
.SetCol( static_cast<sal_Int16
>(std::min
<sal_Int32
>( rAddress
.mnCol
, MAXCOL
)) );
763 OStringBuffer
& XclXmlUtils::ToOString( OStringBuffer
& s
, const XclAddress
& rAddress
)
765 return ToOString( s
, lcl_ToAddress( rAddress
));
768 OString
XclXmlUtils::ToOString( const XclExpString
& s
)
770 OSL_ENSURE( !s
.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
771 return ToOString( s
.GetUnicodeBuffer() );
774 static ScRange
lcl_ToRange( const XclRange
& rRange
)
778 aRange
.aStart
= lcl_ToAddress( rRange
.maFirst
);
779 aRange
.aEnd
= lcl_ToAddress( rRange
.maLast
);
784 OString
XclXmlUtils::ToOString( const XclRange
& rRange
)
786 return ToOString( lcl_ToRange( rRange
) );
789 OString
XclXmlUtils::ToOString( const XclRangeList
& rRanges
)
792 for( XclRangeVector::const_iterator i
= rRanges
.begin(), end
= rRanges
.end();
795 aRanges
.Append( lcl_ToRange( *i
) );
797 return ToOString( aRanges
);
800 OUString
XclXmlUtils::ToOUString( const char* s
)
802 return OUString( s
, (sal_Int32
) strlen( s
), RTL_TEXTENCODING_ASCII_US
);
805 OUString
XclXmlUtils::ToOUString( const ScfUInt16Vec
& rBuf
, sal_Int32 nStart
, sal_Int32 nLength
)
807 if( nLength
== -1 || ( nLength
> ((sal_Int32
)rBuf
.size() - nStart
) ) )
808 nLength
= (rBuf
.size() - nStart
);
810 return (nLength
> 0) ? OUString( &rBuf
[nStart
], nLength
) : OUString();
813 OUString
XclXmlUtils::ToOUString(
814 sc::CompileFormulaContext
& rCtx
, const ScAddress
& rAddress
, const ScTokenArray
* pTokenArray
)
816 ScCompiler
aCompiler( rCtx
, rAddress
, const_cast<ScTokenArray
&>(*pTokenArray
));
818 aCompiler
.SetGrammar(FormulaGrammar::GRAM_OOXML
);
820 OUStringBuffer
aBuffer( pTokenArray
->GetLen() * 5 );
821 aCompiler
.CreateStringFromTokenArray( aBuffer
);
822 return aBuffer
.makeStringAndClear();
825 OUString
XclXmlUtils::ToOUString( const XclExpString
& s
)
827 OSL_ENSURE( !s
.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
828 return ToOUString( s
.GetUnicodeBuffer() );
831 const char* XclXmlUtils::ToPsz( bool b
)
833 return b
? "true" : "false";
836 const char* XclXmlUtils::ToPsz10( bool b
)
838 // xlsx seems to use "1" or "0" for boolean values. I wonder it ever uses
839 // the "true" "false" variant.
840 return b
? "1" : "0";
843 sax_fastparser::FSHelperPtr
XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream
, sal_Int32 nElement
, sal_Int32 nValue
)
845 pStream
->startElement( nElement
, FSEND
);
846 pStream
->write( nValue
);
847 pStream
->endElement( nElement
);
852 sax_fastparser::FSHelperPtr
XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream
, sal_Int32 nElement
, sal_Int64 nValue
)
854 pStream
->startElement( nElement
, FSEND
);
855 pStream
->write( nValue
);
856 pStream
->endElement( nElement
);
861 sax_fastparser::FSHelperPtr
XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream
, sal_Int32 nElement
, const char* sValue
)
863 pStream
->startElement( nElement
, FSEND
);
864 pStream
->write( sValue
);
865 pStream
->endElement( nElement
);
870 static void lcl_WriteValue( sax_fastparser::FSHelperPtr
& rStream
, sal_Int32 nElement
, const char* pValue
)
874 rStream
->singleElement( nElement
,
879 static const char* lcl_GetUnderlineStyle( FontUnderline eUnderline
, bool& bHaveUnderline
)
881 bHaveUnderline
= true;
884 // OOXTODO: doubleAccounting, singleAccounting
885 // OOXTODO: what should be done with the other FontUnderline values?
886 case UNDERLINE_SINGLE
: return "single";
887 case UNDERLINE_DOUBLE
: return "double";
889 default: bHaveUnderline
= false; return "none";
893 static const char* lcl_ToVerticalAlignmentRun( SvxEscapement eEscapement
, bool& bHaveAlignment
)
895 bHaveAlignment
= true;
896 switch( eEscapement
)
898 case SVX_ESCAPEMENT_SUPERSCRIPT
: return "superscript";
899 case SVX_ESCAPEMENT_SUBSCRIPT
: return "subscript";
900 case SVX_ESCAPEMENT_OFF
:
901 default: bHaveAlignment
= false; return "baseline";
905 sax_fastparser::FSHelperPtr
XclXmlUtils::WriteFontData( sax_fastparser::FSHelperPtr pStream
, const XclFontData
& rFontData
, sal_Int32 nFontId
)
907 bool bHaveUnderline
, bHaveVertAlign
;
908 const char* pUnderline
= lcl_GetUnderlineStyle( rFontData
.GetScUnderline(), bHaveUnderline
);
909 const char* pVertAlign
= lcl_ToVerticalAlignmentRun( rFontData
.GetScEscapement(), bHaveVertAlign
);
911 lcl_WriteValue( pStream
, XML_b
, rFontData
.mnWeight
> 400 ? XclXmlUtils::ToPsz( rFontData
.mnWeight
> 400 ) : NULL
);
912 lcl_WriteValue( pStream
, XML_i
, rFontData
.mbItalic
? XclXmlUtils::ToPsz( rFontData
.mbItalic
) : NULL
);
913 lcl_WriteValue( pStream
, XML_strike
, rFontData
.mbStrikeout
? XclXmlUtils::ToPsz( rFontData
.mbStrikeout
) : NULL
);
914 // OOXTODO: lcl_WriteValue( rStream, XML_condense, ); // mac compatibility setting
915 // OOXTODO: lcl_WriteValue( rStream, XML_extend, ); // compatibility setting
916 lcl_WriteValue( pStream
, XML_outline
, rFontData
.mbOutline
? XclXmlUtils::ToPsz( rFontData
.mbOutline
) : NULL
);
917 lcl_WriteValue( pStream
, XML_shadow
, rFontData
.mbShadow
? XclXmlUtils::ToPsz( rFontData
.mbShadow
) : NULL
);
918 lcl_WriteValue( pStream
, XML_u
, bHaveUnderline
? pUnderline
: NULL
);
919 lcl_WriteValue( pStream
, XML_vertAlign
, bHaveVertAlign
? pVertAlign
: NULL
);
920 lcl_WriteValue( pStream
, XML_sz
, OString::number( (double) (rFontData
.mnHeight
/ 20.0) ).getStr() ); // Twips->Pt
921 if( rFontData
.maColor
!= Color( 0xFF, 0xFF, 0xFF, 0xFF ) )
922 pStream
->singleElement( XML_color
,
923 // OOXTODO: XML_auto, bool
924 // OOXTODO: XML_indexed, uint
925 XML_rgb
, XclXmlUtils::ToOString( rFontData
.maColor
).getStr(),
926 // OOXTODO: XML_theme, index into <clrScheme/>
927 // OOXTODO: XML_tint, double
929 lcl_WriteValue( pStream
, nFontId
, XclXmlUtils::ToOString( rFontData
.maName
).getStr() );
930 lcl_WriteValue( pStream
, XML_family
, OString::number( rFontData
.mnFamily
).getStr() );
931 lcl_WriteValue( pStream
, XML_charset
, rFontData
.mnCharSet
!= 0 ? OString::number( rFontData
.mnCharSet
).getStr() : NULL
);
936 XclExpXmlStream::XclExpXmlStream( const Reference
< XComponentContext
>& rCC
)
937 : XmlFilterBase( rCC
),
942 XclExpXmlStream::~XclExpXmlStream()
944 assert(maStreams
.empty() && "Forgotten PopStream()?");
947 sax_fastparser::FSHelperPtr
& XclExpXmlStream::GetCurrentStream()
949 OSL_ENSURE( !maStreams
.empty(), "XclExpXmlStream::GetCurrentStream - no current stream" );
950 return maStreams
.top();
953 void XclExpXmlStream::PushStream( sax_fastparser::FSHelperPtr aStream
)
955 maStreams
.push( aStream
);
958 void XclExpXmlStream::PopStream()
960 OSL_ENSURE( !maStreams
.empty(), "XclExpXmlStream::PopStream - stack is empty!" );
964 sax_fastparser::FSHelperPtr
XclExpXmlStream::GetStreamForPath( const OUString
& sPath
)
966 if( maOpenedStreamMap
.find( sPath
) == maOpenedStreamMap
.end() )
967 return sax_fastparser::FSHelperPtr();
968 return maOpenedStreamMap
[ sPath
].second
;
971 sax_fastparser::FSHelperPtr
& XclExpXmlStream::WriteAttributesInternal( sal_Int32 nAttribute
, ... )
973 sax_fastparser::FSHelperPtr
& rStream
= GetCurrentStream();
976 va_start( args
, nAttribute
);
978 const char* pValue
= va_arg( args
, const char* );
981 rStream
->write( " " )
982 ->writeId( nAttribute
)
984 ->writeEscaped( OUString(pValue
, strlen(pValue
), RTL_TEXTENCODING_UTF8
) )
988 nAttribute
= va_arg( args
, sal_Int32
);
989 if( nAttribute
== FSEND_internal
)
996 sax_fastparser::FSHelperPtr
XclExpXmlStream::CreateOutputStream (
997 const OUString
& sFullStream
,
998 const OUString
& sRelativeStream
,
999 const Reference
< XOutputStream
>& xParentRelation
,
1000 const char* sContentType
,
1001 const char* sRelationshipType
,
1002 OUString
* pRelationshipId
)
1004 OUString sRelationshipId
;
1005 if (xParentRelation
.is())
1006 sRelationshipId
= addRelation( xParentRelation
, OUString::createFromAscii( sRelationshipType
), sRelativeStream
);
1008 sRelationshipId
= addRelation( OUString::createFromAscii( sRelationshipType
), sRelativeStream
);
1010 if( pRelationshipId
)
1011 *pRelationshipId
= sRelationshipId
;
1013 sax_fastparser::FSHelperPtr p
= openFragmentStreamWithSerializer( sFullStream
, OUString::createFromAscii( sContentType
) );
1015 maOpenedStreamMap
[ sFullStream
] = std::make_pair( sRelationshipId
, p
);
1020 bool XclExpXmlStream::importDocument() throw()
1025 oox::vml::Drawing
* XclExpXmlStream::getVmlDrawing()
1030 const oox::drawingml::Theme
* XclExpXmlStream::getCurrentTheme() const
1035 const oox::drawingml::table::TableStyleListPtr
XclExpXmlStream::getTableStyles()
1037 return oox::drawingml::table::TableStyleListPtr();
1040 oox::drawingml::chart::ChartConverter
* XclExpXmlStream::getChartConverter()
1046 ScDocShell
* XclExpXmlStream::getDocShell()
1048 Reference
< XInterface
> xModel( getModel(), UNO_QUERY
);
1050 ScModelObj
*pObj
= dynamic_cast < ScModelObj
* >( xModel
.get() );
1053 return static_cast < ScDocShell
* >( pObj
->GetEmbeddedObject() );
1058 bool XclExpXmlStream::exportDocument()
1059 throw (css::uno::RuntimeException
, std::exception
)
1061 ScDocShell
* pShell
= getDocShell();
1062 ScDocument
& rDoc
= pShell
->GetDocument();
1063 ScRefreshTimerProtector
aProt(rDoc
.GetRefreshTimerControlAddress());
1065 uno::Reference
<task::XStatusIndicator
> xStatusIndicator
= getStatusIndicator();
1067 if (xStatusIndicator
.is())
1068 xStatusIndicator
->start(ScGlobal::GetRscString(STR_SAVE_DOC
), 100);
1070 // NOTE: Don't use SotStorage or SvStream any more, and never call
1071 // SfxMedium::GetOutStream() anywhere in the xlsx export filter code!
1072 // Instead, write via XOutputStream instance.
1073 tools::SvRef
<SotStorage
> rStorage
= static_cast<SotStorage
*>(NULL
);
1074 XclExpObjList::ResetCounters();
1076 XclExpRootData
aData( EXC_BIFF8
, *pShell
->GetMedium (), rStorage
, rDoc
, RTL_TEXTENCODING_DONTKNOW
);
1077 aData
.meOutput
= EXC_OUTPUT_XML_2007
;
1078 aData
.maXclMaxPos
.Set( EXC_MAXCOL_XML_2007
, EXC_MAXROW_XML_2007
, EXC_MAXTAB_XML_2007
);
1079 aData
.maMaxPos
.SetCol( ::std::min( aData
.maScMaxPos
.Col(), aData
.maXclMaxPos
.Col() ) );
1080 aData
.maMaxPos
.SetRow( ::std::min( aData
.maScMaxPos
.Row(), aData
.maXclMaxPos
.Row() ) );
1081 aData
.maMaxPos
.SetTab( ::std::min( aData
.maScMaxPos
.Tab(), aData
.maXclMaxPos
.Tab() ) );
1082 aData
.mpCompileFormulaCxt
.reset( new sc::CompileFormulaContext(&rDoc
) );
1084 XclExpRoot
aRoot( aData
);
1087 aRoot
.GetOldRoot().pER
= &aRoot
;
1088 aRoot
.GetOldRoot().eDateiTyp
= Biff8
;
1089 // Get the viewsettings before processing
1090 if( ScDocShell::GetViewData() )
1091 ScDocShell::GetViewData()->WriteExtOptions( mpRoot
->GetExtDocOptions() );
1093 OUString
const workbook
= "xl/workbook.xml";
1094 PushStream( CreateOutputStream( workbook
, workbook
,
1095 Reference
<XOutputStream
>(),
1096 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
1097 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" ) );
1099 // destruct at the end of the block
1101 ExcDocument
aDocRoot( aRoot
);
1102 if (xStatusIndicator
.is())
1103 xStatusIndicator
->setValue(10);
1105 if (xStatusIndicator
.is())
1106 xStatusIndicator
->setValue(40);
1107 aDocRoot
.WriteXml( *this );
1111 // Free all FSHelperPtr, to flush data before committing storage
1112 maOpenedStreamMap
.clear();
1116 if (xStatusIndicator
.is())
1117 xStatusIndicator
->end();
1122 ::oox::ole::VbaProject
* XclExpXmlStream::implCreateVbaProject() const
1124 return new ::oox::xls::ExcelVbaProject( getComponentContext(), Reference
< XSpreadsheetDocument
>( getModel(), UNO_QUERY
) );
1127 OUString
XclExpXmlStream::getImplementationName() throw (css::uno::RuntimeException
, std::exception
)
1129 return OUString( "TODO" );
1132 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */