bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / filter / excel / xestream.cxx
blob84210066652781c3c08c004da03d0e238859f64d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <utility>
25 #include <rtl/ustring.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <rtl/random.h>
28 #include <sax/fshelper.hxx>
29 #include <unotools/streamwrap.hxx>
31 #include "docuno.hxx"
32 #include "xestream.hxx"
33 #include "xladdress.hxx"
34 #include "xlstring.hxx"
35 #include "xeroot.hxx"
36 #include "xestyle.hxx"
37 #include "xcl97rec.hxx"
38 #include "rangelst.hxx"
39 #include "compiler.hxx"
40 #include "formulacell.hxx"
41 #include "tokenarray.hxx"
43 #include <../../ui/inc/docsh.hxx>
44 #include <../../ui/inc/viewdata.hxx>
45 #include <excdoc.hxx>
47 #include <oox/token/tokens.hxx>
48 #include <formula/grammar.hxx>
49 #include <oox/export/drawingml.hxx>
50 #include <excelvbaproject.hxx>
52 #include <sfx2/docfile.hxx>
53 #include <sfx2/objsh.hxx>
54 #include <sfx2/app.hxx>
55 #include <cppuhelper/implementationentry.hxx>
57 #define DEBUG_XL_ENCRYPTION 0
59 using ::com::sun::star::embed::XStorage;
60 using ::com::sun::star::lang::XSingleServiceFactory;
61 using ::com::sun::star::registry::InvalidRegistryException;
62 using ::com::sun::star::registry::XRegistryKey;
63 using ::com::sun::star::uno::Exception;
64 using ::com::sun::star::uno::XInterface;
65 using ::utl::OStreamWrapper;
66 using ::std::vector;
68 using namespace ::com::sun::star::beans;
69 using namespace ::com::sun::star::io;
70 using namespace ::com::sun::star::lang;
71 using namespace ::com::sun::star::sheet;
72 using namespace ::com::sun::star::uno;
73 using namespace ::formula;
74 using namespace ::oox;
76 // ============================================================================
78 XclExpStream::XclExpStream( SvStream& rOutStrm, const XclExpRoot& rRoot, sal_uInt16 nMaxRecSize ) :
79 mrStrm( rOutStrm ),
80 mrRoot( rRoot ),
81 mnMaxRecSize( nMaxRecSize ),
82 mnCurrMaxSize( 0 ),
83 mnMaxSliceSize( 0 ),
84 mnHeaderSize( 0 ),
85 mnCurrSize( 0 ),
86 mnSliceSize( 0 ),
87 mnPredictSize( 0 ),
88 mnLastSizePos( 0 ),
89 mbInRec( false )
91 if( mnMaxRecSize == 0 )
92 mnMaxRecSize = (mrRoot.GetBiff() <= EXC_BIFF5) ? EXC_MAXRECSIZE_BIFF5 : EXC_MAXRECSIZE_BIFF8;
93 mnMaxContSize = mnMaxRecSize;
96 XclExpStream::~XclExpStream()
98 mrStrm.Flush();
101 void XclExpStream::StartRecord( sal_uInt16 nRecId, sal_Size nRecSize )
103 OSL_ENSURE( !mbInRec, "XclExpStream::StartRecord - another record still open" );
104 DisableEncryption();
105 mnMaxContSize = mnCurrMaxSize = mnMaxRecSize;
106 mnPredictSize = nRecSize;
107 mbInRec = true;
108 InitRecord( nRecId );
109 SetSliceSize( 0 );
110 EnableEncryption();
113 void XclExpStream::EndRecord()
115 OSL_ENSURE( mbInRec, "XclExpStream::EndRecord - no record open" );
116 DisableEncryption();
117 UpdateRecSize();
118 mrStrm.Seek( STREAM_SEEK_TO_END );
119 mbInRec = false;
122 void XclExpStream::SetSliceSize( sal_uInt16 nSize )
124 mnMaxSliceSize = nSize;
125 mnSliceSize = 0;
128 XclExpStream& XclExpStream::operator<<( sal_Int8 nValue )
130 PrepareWrite( 1 );
131 if (mbUseEncrypter && HasValidEncrypter())
132 mxEncrypter->Encrypt(mrStrm, nValue);
133 else
134 mrStrm << nValue;
135 return *this;
138 XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue )
140 PrepareWrite( 1 );
141 if (mbUseEncrypter && HasValidEncrypter())
142 mxEncrypter->Encrypt(mrStrm, nValue);
143 else
144 mrStrm << nValue;
145 return *this;
148 XclExpStream& XclExpStream::operator<<( sal_Int16 nValue )
150 PrepareWrite( 2 );
151 if (mbUseEncrypter && HasValidEncrypter())
152 mxEncrypter->Encrypt(mrStrm, nValue);
153 else
154 mrStrm << nValue;
155 return *this;
158 XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue )
160 PrepareWrite( 2 );
161 if (mbUseEncrypter && HasValidEncrypter())
162 mxEncrypter->Encrypt(mrStrm, nValue);
163 else
164 mrStrm << nValue;
165 return *this;
168 XclExpStream& XclExpStream::operator<<( sal_Int32 nValue )
170 PrepareWrite( 4 );
171 if (mbUseEncrypter && HasValidEncrypter())
172 mxEncrypter->Encrypt(mrStrm, nValue);
173 else
174 mrStrm << nValue;
175 return *this;
178 XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue )
180 PrepareWrite( 4 );
181 if (mbUseEncrypter && HasValidEncrypter())
182 mxEncrypter->Encrypt(mrStrm, nValue);
183 else
184 mrStrm << nValue;
185 return *this;
188 XclExpStream& XclExpStream::operator<<( float fValue )
190 PrepareWrite( 4 );
191 if (mbUseEncrypter && HasValidEncrypter())
192 mxEncrypter->Encrypt(mrStrm, fValue);
193 else
194 mrStrm << fValue;
195 return *this;
198 XclExpStream& XclExpStream::operator<<( double fValue )
200 PrepareWrite( 8 );
201 if (mbUseEncrypter && HasValidEncrypter())
202 mxEncrypter->Encrypt(mrStrm, fValue);
203 else
204 mrStrm << fValue;
205 return *this;
208 sal_Size XclExpStream::Write( const void* pData, sal_Size nBytes )
210 sal_Size nRet = 0;
211 if( pData && (nBytes > 0) )
213 if( mbInRec )
215 const sal_uInt8* pBuffer = reinterpret_cast< const sal_uInt8* >( pData );
216 sal_Size nBytesLeft = nBytes;
217 bool bValid = true;
219 while( bValid && (nBytesLeft > 0) )
221 sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
222 sal_Size nWriteRet = nWriteLen;
223 if (mbUseEncrypter && HasValidEncrypter())
225 OSL_ENSURE(nWriteLen > 0, "XclExpStream::Write: write length is 0!");
226 vector<sal_uInt8> aBytes(nWriteLen);
227 memcpy(&aBytes[0], pBuffer, nWriteLen);
228 mxEncrypter->EncryptBytes(mrStrm, aBytes);
229 // TODO: How do I check if all the bytes have been successfully written ?
231 else
233 nWriteRet = mrStrm.Write( pBuffer, nWriteLen );
234 bValid = (nWriteLen == nWriteRet);
235 OSL_ENSURE( bValid, "XclExpStream::Write - stream write error" );
237 pBuffer += nWriteRet;
238 nRet += nWriteRet;
239 nBytesLeft -= nWriteRet;
240 UpdateSizeVars( nWriteRet );
243 else
244 nRet = mrStrm.Write( pData, nBytes );
246 return nRet;
249 void XclExpStream::WriteZeroBytes( sal_Size nBytes )
251 if( mbInRec )
253 sal_Size nBytesLeft = nBytes;
254 while( nBytesLeft > 0 )
256 sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
257 WriteRawZeroBytes( nWriteLen );
258 nBytesLeft -= nWriteLen;
259 UpdateSizeVars( nWriteLen );
262 else
263 WriteRawZeroBytes( nBytes );
266 void XclExpStream::WriteZeroBytesToRecord( sal_Size nBytes )
268 if (!mbInRec)
269 // not in record.
270 return;
272 sal_uInt8 nZero = 0;
273 for (sal_Size i = 0; i < nBytes; ++i)
274 *this << nZero;
277 sal_Size XclExpStream::CopyFromStream( SvStream& rInStrm, sal_Size nBytes )
279 sal_Size nStrmPos = rInStrm.Tell();
280 rInStrm.Seek( STREAM_SEEK_TO_END );
281 sal_Size nStrmSize = rInStrm.Tell();
282 rInStrm.Seek( nStrmPos );
284 sal_Size nBytesLeft = ::std::min( nBytes, nStrmSize - nStrmPos );
285 sal_Size nRet = 0;
286 if( nBytesLeft > 0 )
288 const sal_Size nMaxBuffer = 4096;
289 sal_uInt8* pBuffer = new sal_uInt8[ ::std::min( nBytesLeft, nMaxBuffer ) ];
290 bool bValid = true;
292 while( bValid && (nBytesLeft > 0) )
294 sal_Size nWriteLen = ::std::min( nBytesLeft, nMaxBuffer );
295 rInStrm.Read( pBuffer, nWriteLen );
296 sal_Size nWriteRet = Write( pBuffer, nWriteLen );
297 bValid = (nWriteLen == nWriteRet);
298 nRet += nWriteRet;
299 nBytesLeft -= nWriteRet;
301 delete[] pBuffer;
303 return nRet;
306 void XclExpStream::WriteUnicodeBuffer( const ScfUInt16Vec& rBuffer, sal_uInt8 nFlags )
308 SetSliceSize( 0 );
309 nFlags &= EXC_STRF_16BIT; // repeat only 16bit flag
310 sal_uInt16 nCharLen = nFlags ? 2 : 1;
312 ScfUInt16Vec::const_iterator aEnd = rBuffer.end();
313 for( ScfUInt16Vec::const_iterator aIter = rBuffer.begin(); aIter != aEnd; ++aIter )
315 if( mbInRec && (mnCurrSize + nCharLen > mnCurrMaxSize) )
317 StartContinue();
318 operator<<( nFlags );
320 if( nCharLen == 2 )
321 operator<<( *aIter );
322 else
323 operator<<( static_cast< sal_uInt8 >( *aIter ) );
327 // Xcl has an obscure sense of whether starting a new record or not,
328 // and crashes if it encounters the string header at the very end of a record.
329 // Thus we add 1 to give some room, seems like they do it that way but with another count (10?)
330 void XclExpStream::WriteByteString( const OString& rString, sal_uInt16 nMaxLen, bool b16BitCount )
332 SetSliceSize( 0 );
333 sal_Size nLen = ::std::min< sal_Size >( rString.getLength(), nMaxLen );
334 if( !b16BitCount )
335 nLen = ::std::min< sal_Size >( nLen, 0xFF );
337 sal_uInt16 nLeft = PrepareWrite();
338 sal_uInt16 nLenFieldSize = b16BitCount ? 2 : 1;
339 if( mbInRec && (nLeft <= nLenFieldSize) )
340 StartContinue();
342 if( b16BitCount )
343 operator<<( static_cast< sal_uInt16 >( nLen ) );
344 else
345 operator<<( static_cast< sal_uInt8 >( nLen ) );
346 Write( rString.getStr(), nLen );
349 void XclExpStream::WriteCharBuffer( const ScfUInt8Vec& rBuffer )
351 SetSliceSize( 0 );
352 Write( &rBuffer[ 0 ], rBuffer.size() );
355 void XclExpStream::SetEncrypter( XclExpEncrypterRef xEncrypter )
357 mxEncrypter = xEncrypter;
360 bool XclExpStream::HasValidEncrypter() const
362 return mxEncrypter && mxEncrypter->IsValid();
365 void XclExpStream::EnableEncryption( bool bEnable )
367 mbUseEncrypter = bEnable && HasValidEncrypter();
370 void XclExpStream::DisableEncryption()
372 EnableEncryption(false);
375 sal_Size XclExpStream::SetSvStreamPos( sal_Size nPos )
377 OSL_ENSURE( !mbInRec, "XclExpStream::SetSvStreamPos - not allowed inside of a record" );
378 return mbInRec ? 0 : mrStrm.Seek( nPos );
381 // private --------------------------------------------------------------------
383 void XclExpStream::InitRecord( sal_uInt16 nRecId )
385 mrStrm.Seek( STREAM_SEEK_TO_END );
386 mrStrm << nRecId;
388 mnLastSizePos = mrStrm.Tell();
389 mnHeaderSize = static_cast< sal_uInt16 >( ::std::min< sal_Size >( mnPredictSize, mnCurrMaxSize ) );
390 mrStrm << mnHeaderSize;
391 mnCurrSize = mnSliceSize = 0;
394 void XclExpStream::UpdateRecSize()
396 if( mnCurrSize != mnHeaderSize )
398 mrStrm.Seek( mnLastSizePos );
399 mrStrm << mnCurrSize;
403 void XclExpStream::UpdateSizeVars( sal_Size nSize )
405 OSL_ENSURE( mnCurrSize + nSize <= mnCurrMaxSize, "XclExpStream::UpdateSizeVars - record overwritten" );
406 mnCurrSize = mnCurrSize + static_cast< sal_uInt16 >( nSize );
408 if( mnMaxSliceSize > 0 )
410 OSL_ENSURE( mnSliceSize + nSize <= mnMaxSliceSize, "XclExpStream::UpdateSizeVars - slice overwritten" );
411 mnSliceSize = mnSliceSize + static_cast< sal_uInt16 >( nSize );
412 if( mnSliceSize >= mnMaxSliceSize )
413 mnSliceSize = 0;
417 void XclExpStream::StartContinue()
419 UpdateRecSize();
420 mnCurrMaxSize = mnMaxContSize;
421 mnPredictSize -= mnCurrSize;
422 InitRecord( EXC_ID_CONT );
425 void XclExpStream::PrepareWrite( sal_uInt16 nSize )
427 if( mbInRec )
429 if( (mnCurrSize + nSize > mnCurrMaxSize) ||
430 ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
431 StartContinue();
432 UpdateSizeVars( nSize );
436 sal_uInt16 XclExpStream::PrepareWrite()
438 sal_uInt16 nRet = 0;
439 if( mbInRec )
441 if( (mnCurrSize >= mnCurrMaxSize) ||
442 ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
443 StartContinue();
444 UpdateSizeVars( 0 );
446 nRet = (mnMaxSliceSize > 0) ? (mnMaxSliceSize - mnSliceSize) : (mnCurrMaxSize - mnCurrSize);
448 return nRet;
451 void XclExpStream::WriteRawZeroBytes( sal_Size nBytes )
453 const sal_uInt32 nData = 0;
454 sal_Size nBytesLeft = nBytes;
455 while( nBytesLeft >= sizeof( nData ) )
457 mrStrm << nData;
458 nBytesLeft -= sizeof( nData );
460 if( nBytesLeft )
461 mrStrm.Write( &nData, nBytesLeft );
464 // ============================================================================
466 XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot& rRoot ) :
467 mnOldPos(STREAM_SEEK_TO_END),
468 mbValid(false)
470 Sequence< NamedValue > aEncryptionData = rRoot.GetEncryptionData();
471 if( !aEncryptionData.hasElements() )
472 // Empty password. Get the default biff8 password.
473 aEncryptionData = rRoot.GenerateDefaultEncryptionData();
474 Init( aEncryptionData );
477 XclExpBiff8Encrypter::~XclExpBiff8Encrypter()
481 bool XclExpBiff8Encrypter::IsValid() const
483 return mbValid;
486 void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 pnSaltDigest[16] ) const
488 if ( sizeof( mpnSaltDigest ) == 16 )
489 memcpy( pnSaltDigest, mpnSaltDigest, 16 );
492 void XclExpBiff8Encrypter::GetSalt( sal_uInt8 pnSalt[16] ) const
494 if ( sizeof( mpnSalt ) == 16 )
495 memcpy( pnSalt, mpnSalt, 16 );
498 void XclExpBiff8Encrypter::GetDocId( sal_uInt8 pnDocId[16] ) const
500 if ( sizeof( mpnDocId ) == 16 )
501 memcpy( pnDocId, mpnDocId, 16 );
504 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt8 nData )
506 vector<sal_uInt8> aByte(1);
507 aByte[0] = nData;
508 EncryptBytes(rStrm, aByte);
511 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt16 nData )
513 ::std::vector<sal_uInt8> pnBytes(2);
514 pnBytes[0] = nData & 0xFF;
515 pnBytes[1] = (nData >> 8) & 0xFF;
516 EncryptBytes(rStrm, pnBytes);
519 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt32 nData )
521 ::std::vector<sal_uInt8> pnBytes(4);
522 pnBytes[0] = nData & 0xFF;
523 pnBytes[1] = (nData >> 8) & 0xFF;
524 pnBytes[2] = (nData >> 16) & 0xFF;
525 pnBytes[3] = (nData >> 24) & 0xFF;
526 EncryptBytes(rStrm, pnBytes);
529 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, float fValue )
531 ::std::vector<sal_uInt8> pnBytes(4);
532 memcpy(&pnBytes[0], &fValue, 4);
533 EncryptBytes(rStrm, pnBytes);
536 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, double fValue )
538 ::std::vector<sal_uInt8> pnBytes(8);
539 memcpy(&pnBytes[0], &fValue, 8);
540 EncryptBytes(rStrm, pnBytes);
543 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int8 nData )
545 Encrypt(rStrm, static_cast<sal_uInt8>(nData));
548 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int16 nData )
550 Encrypt(rStrm, static_cast<sal_uInt16>(nData));
553 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int32 nData )
555 Encrypt(rStrm, static_cast<sal_uInt32>(nData));
558 void XclExpBiff8Encrypter::Init( const Sequence< NamedValue >& rEncryptionData )
560 mbValid = false;
562 if( maCodec.InitCodec( rEncryptionData ) )
564 maCodec.GetDocId( mpnDocId );
566 // generate the salt here
567 TimeValue aTime;
568 osl_getSystemTime( &aTime );
569 rtlRandomPool aRandomPool = rtl_random_createPool ();
570 rtl_random_addBytes( aRandomPool, &aTime, 8 );
571 rtl_random_getBytes( aRandomPool, mpnSalt, 16 );
572 rtl_random_destroyPool( aRandomPool );
574 memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) );
576 // generate salt hash.
577 ::msfilter::MSCodec_Std97 aCodec;
578 aCodec.InitCodec( rEncryptionData );
579 aCodec.CreateSaltDigest( mpnSalt, mpnSaltDigest );
581 // verify to make sure it's in good shape.
582 mbValid = maCodec.VerifyKey( mpnSalt, mpnSaltDigest );
586 sal_uInt32 XclExpBiff8Encrypter::GetBlockPos( sal_Size nStrmPos ) const
588 return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
591 sal_uInt16 XclExpBiff8Encrypter::GetOffsetInBlock( sal_Size nStrmPos ) const
593 return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
596 void XclExpBiff8Encrypter::EncryptBytes( SvStream& rStrm, vector<sal_uInt8>& aBytes )
598 sal_Size nStrmPos = rStrm.Tell();
599 sal_uInt16 nBlockOffset = GetOffsetInBlock(nStrmPos);
600 sal_uInt32 nBlockPos = GetBlockPos(nStrmPos);
602 #if DEBUG_XL_ENCRYPTION
603 fprintf(stdout, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld offset in block = %d block pos = %ld\n",
604 nStrmPos, nBlockOffset, nBlockPos);
605 #endif
607 sal_uInt16 nSize = static_cast< sal_uInt16 >( aBytes.size() );
608 if (nSize == 0)
609 return;
611 #if DEBUG_XL_ENCRYPTION
612 fprintf(stdout, "RAW: ");
613 for (sal_uInt16 i = 0; i < nSize; ++i)
614 fprintf(stdout, "%2.2X ", aBytes[i]);
615 fprintf(stdout, "\n");
616 #endif
618 if (mnOldPos != nStrmPos)
620 sal_uInt16 nOldOffset = GetOffsetInBlock(mnOldPos);
621 sal_uInt32 nOldBlockPos = GetBlockPos(mnOldPos);
623 if ( (nBlockPos != nOldBlockPos) || (nBlockOffset < nOldOffset) )
625 maCodec.InitCipher(nBlockPos);
626 nOldOffset = 0;
629 if (nBlockOffset > nOldOffset)
630 maCodec.Skip(nBlockOffset - nOldOffset);
633 sal_uInt16 nBytesLeft = nSize;
634 sal_uInt16 nPos = 0;
635 while (nBytesLeft > 0)
637 sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - nBlockOffset;
638 sal_uInt16 nEncBytes = ::std::min(nBlockLeft, nBytesLeft);
640 bool bRet = maCodec.Encode(&aBytes[nPos], nEncBytes, &aBytes[nPos], nEncBytes);
641 OSL_ENSURE(bRet, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!");
642 (void) bRet; // to remove a silly compiler warning.
644 sal_Size nRet = rStrm.Write(&aBytes[nPos], nEncBytes);
645 OSL_ENSURE(nRet == nEncBytes, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!");
646 (void) nRet; // to remove a silly compiler warning.
648 nStrmPos = rStrm.Tell();
649 nBlockOffset = GetOffsetInBlock(nStrmPos);
650 nBlockPos = GetBlockPos(nStrmPos);
651 if (nBlockOffset == 0)
652 maCodec.InitCipher(nBlockPos);
654 nBytesLeft -= nEncBytes;
655 nPos += nEncBytes;
657 mnOldPos = nStrmPos;
660 static const char* lcl_GetErrorString( sal_uInt16 nScErrCode )
662 sal_uInt8 nXclErrCode = XclTools::GetXclErrorCode( nScErrCode );
663 switch( nXclErrCode )
665 case EXC_ERR_NULL: return "#NULL!";
666 case EXC_ERR_DIV0: return "#DIV/0!";
667 case EXC_ERR_VALUE: return "#VALUE!";
668 case EXC_ERR_REF: return "#REF!";
669 case EXC_ERR_NAME: return "#NAME?";
670 case EXC_ERR_NUM: return "#NUM!";
671 case EXC_ERR_NA:
672 default: return "#N/A";
676 void XclXmlUtils::GetFormulaTypeAndValue( ScFormulaCell& rCell, const char*& rsType, OUString& rsValue )
678 sal_uInt16 nScErrCode = rCell.GetErrCode();
679 if( nScErrCode )
681 rsType = "e";
682 rsValue = ToOUString( lcl_GetErrorString( nScErrCode ) );
684 return;
687 switch( rCell.GetFormatType() )
689 case NUMBERFORMAT_NUMBER:
691 // either value or error code
692 rsType = "n";
693 rsValue = OUString::valueOf( rCell.GetValue() );
695 break;
697 case NUMBERFORMAT_TEXT:
699 rsType = "str";
700 rsValue = rCell.GetString();
702 break;
704 case NUMBERFORMAT_LOGICAL:
706 rsType = "b";
707 rsValue = ToOUString( rCell.GetValue() == 0.0 ? "0" : "1" );
709 break;
711 default:
713 rsType = "inlineStr";
714 rsValue = rCell.GetString();
716 break;
720 OUString XclXmlUtils::GetStreamName( const char* sStreamDir, const char* sStream, sal_Int32 nId )
722 OUStringBuffer sBuf;
723 if( sStreamDir )
724 sBuf.appendAscii( sStreamDir );
725 sBuf.appendAscii( sStream );
726 if( nId )
727 sBuf.append( nId );
728 if( strstr(sStream, "vml") )
729 sBuf.appendAscii( ".vml" );
730 else
731 sBuf.appendAscii( ".xml" );
732 return sBuf.makeStringAndClear();
735 OString XclXmlUtils::ToOString( const Color& rColor )
737 char buf[9];
738 sprintf( buf, "%.2X%.2X%.2X%.2X", 0xFF-rColor.GetTransparency(), rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
739 buf[8] = '\0';
740 return OString( buf );
743 OString XclXmlUtils::ToOString( const OUString& s )
745 return OUStringToOString( s, RTL_TEXTENCODING_UTF8 );
748 OString XclXmlUtils::ToOString( const String& s )
750 return OString( s.GetBuffer(), s.Len(), RTL_TEXTENCODING_UTF8 );
753 OString XclXmlUtils::ToOString( const ScAddress& rAddress )
755 String sAddress;
756 rAddress.Format( sAddress, SCA_VALID, NULL, ScAddress::Details( FormulaGrammar::CONV_XL_A1 ) );
757 return ToOString( sAddress );
760 OString XclXmlUtils::ToOString( const ScfUInt16Vec& rBuffer )
762 const sal_uInt16* pBuffer = &rBuffer [0];
763 return OString( pBuffer, rBuffer.size(), RTL_TEXTENCODING_UTF8 );
766 OString XclXmlUtils::ToOString( const ScRange& rRange )
768 String sRange;
769 rRange.Format( sRange, SCA_VALID, NULL, ScAddress::Details( FormulaGrammar::CONV_XL_A1 ) );
770 return ToOString( sRange );
773 OString XclXmlUtils::ToOString( const ScRangeList& rRangeList )
775 String s;
776 rRangeList.Format( s, SCA_VALID, NULL, FormulaGrammar::CONV_XL_A1, ' ' );
777 return ToOString( s );
780 static ScAddress lcl_ToAddress( const XclAddress& rAddress )
782 ScAddress aAddress;
784 // For some reason, ScRange::Format() returns omits row numbers if
785 // the row is >= MAXROW or the column is >= MAXCOL, and Excel doesn't
786 // like "A:IV" (i.e. no row numbers). Prevent this.
787 // KOHEI: Find out if the above comment is still true.
788 aAddress.SetRow( std::min<sal_Int32>( rAddress.mnRow, MAXROW ) );
789 aAddress.SetCol( static_cast<sal_Int16>(std::min<sal_Int32>( rAddress.mnCol, MAXCOL )) );
791 return aAddress;
794 OString XclXmlUtils::ToOString( const XclAddress& rAddress )
796 return ToOString( lcl_ToAddress( rAddress ) );
799 OString XclXmlUtils::ToOString( const XclExpString& s )
801 OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
802 return ToOString( s.GetUnicodeBuffer() );
805 static ScRange lcl_ToRange( const XclRange& rRange )
807 ScRange aRange;
809 aRange.aStart = lcl_ToAddress( rRange.maFirst );
810 aRange.aEnd = lcl_ToAddress( rRange.maLast );
812 return aRange;
815 OString XclXmlUtils::ToOString( const XclRange& rRange )
817 return ToOString( lcl_ToRange( rRange ) );
820 OString XclXmlUtils::ToOString( const XclRangeList& rRanges )
822 ScRangeList aRanges;
823 for( XclRangeList::const_iterator i = rRanges.begin(), end = rRanges.end();
824 i != end; ++i )
826 aRanges.Append( lcl_ToRange( *i ) );
828 return ToOString( aRanges );
831 OUString XclXmlUtils::ToOUString( const char* s )
833 return OUString( s, (sal_Int32) strlen( s ), RTL_TEXTENCODING_ASCII_US );
836 OUString XclXmlUtils::ToOUString( const ScfUInt16Vec& rBuf, sal_Int32 nStart, sal_Int32 nLength )
838 if( nLength == -1 || ( nLength > ((sal_Int32)rBuf.size() - nStart) ) )
839 nLength = (rBuf.size() - nStart);
841 return (nLength > 0) ? OUString( &rBuf[nStart], nLength ) : OUString();
844 OUString XclXmlUtils::ToOUString( const String& s )
846 return OUString( s.GetBuffer(), s.Len() );
849 OUString XclXmlUtils::ToOUString( ScDocument& rDocument, const ScAddress& rAddress,
850 ScTokenArray* pTokenArray, const FormulaCompiler::OpCodeMapPtr & xOpCodeMap )
852 ScCompiler aCompiler( &rDocument, rAddress, *pTokenArray);
853 if (xOpCodeMap)
855 aCompiler.SetFormulaLanguage( xOpCodeMap );
856 /* TODO: The correct ref convention would be CONV_XL_OOX but that would
857 * need aCompiler.SetExternalLinks() and so far we don't have the links
858 * mapping. */
859 aCompiler.SetRefConvention( formula::FormulaGrammar::CONV_XL_A1 );
861 else
863 SAL_WARN( "sc", "XclXmlUtils::ToOUString - no opcodemap, dumb fallback to PODF");
864 aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH_XL_A1);
867 OUStringBuffer aBuffer( pTokenArray->GetLen() * 5 );
868 aCompiler.CreateStringFromTokenArray( aBuffer );
869 return aBuffer.makeStringAndClear();
872 OUString XclXmlUtils::ToOUString( const XclExpString& s )
874 OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
875 return ToOUString( s.GetUnicodeBuffer() );
878 const char* XclXmlUtils::ToPsz( bool b )
880 return b ? "true" : "false";
883 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int32 nValue )
885 pStream->startElement( nElement, FSEND );
886 pStream->write( nValue );
887 pStream->endElement( nElement );
889 return pStream;
892 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int64 nValue )
894 pStream->startElement( nElement, FSEND );
895 pStream->write( nValue );
896 pStream->endElement( nElement );
898 return pStream;
901 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, const char* sValue )
903 pStream->startElement( nElement, FSEND );
904 pStream->write( sValue );
905 pStream->endElement( nElement );
907 return pStream;
910 static void lcl_WriteValue( sax_fastparser::FSHelperPtr& rStream, sal_Int32 nElement, const char* pValue )
912 if( !pValue )
913 return;
914 rStream->singleElement( nElement,
915 XML_val, pValue,
916 FSEND );
919 static const char* lcl_GetUnderlineStyle( FontUnderline eUnderline, bool& bHaveUnderline )
921 bHaveUnderline = true;
922 switch( eUnderline )
924 // OOXTODO: doubleAccounting, singleAccounting
925 // OOXTODO: what should be done with the other FontUnderline values?
926 case UNDERLINE_SINGLE: return "single";
927 case UNDERLINE_DOUBLE: return "double";
928 case UNDERLINE_NONE:
929 default: bHaveUnderline = false; return "none";
933 static const char* lcl_ToVerticalAlignmentRun( SvxEscapement eEscapement, bool& bHaveAlignment )
935 bHaveAlignment = true;
936 switch( eEscapement )
938 case SVX_ESCAPEMENT_SUPERSCRIPT: return "superscript";
939 case SVX_ESCAPEMENT_SUBSCRIPT: return "subscript";
940 case SVX_ESCAPEMENT_OFF:
941 default: bHaveAlignment = false; return "baseline";
945 sax_fastparser::FSHelperPtr XclXmlUtils::WriteFontData( sax_fastparser::FSHelperPtr pStream, const XclFontData& rFontData, sal_Int32 nFontId )
947 bool bHaveUnderline, bHaveVertAlign;
948 const char* pUnderline = lcl_GetUnderlineStyle( rFontData.GetScUnderline(), bHaveUnderline );
949 const char* pVertAlign = lcl_ToVerticalAlignmentRun( rFontData.GetScEscapement(), bHaveVertAlign );
951 lcl_WriteValue( pStream, XML_b, rFontData.mnWeight > 400 ? XclXmlUtils::ToPsz( rFontData.mnWeight > 400 ) : NULL );
952 lcl_WriteValue( pStream, XML_i, rFontData.mbItalic ? XclXmlUtils::ToPsz( rFontData.mbItalic ) : NULL );
953 lcl_WriteValue( pStream, XML_strike, rFontData.mbStrikeout ? XclXmlUtils::ToPsz( rFontData.mbStrikeout ) : NULL );
954 // OOXTODO: lcl_WriteValue( rStream, XML_condense, ); // mac compatibility setting
955 // OOXTODO: lcl_WriteValue( rStream, XML_extend, ); // compatibility setting
956 lcl_WriteValue( pStream, XML_outline, rFontData.mbOutline ? XclXmlUtils::ToPsz( rFontData.mbOutline ) : NULL );
957 lcl_WriteValue( pStream, XML_shadow, rFontData.mbShadow ? XclXmlUtils::ToPsz( rFontData.mbShadow ) : NULL );
958 lcl_WriteValue( pStream, XML_u, bHaveUnderline ? pUnderline : NULL );
959 lcl_WriteValue( pStream, XML_vertAlign, bHaveVertAlign ? pVertAlign : NULL );
960 lcl_WriteValue( pStream, XML_sz, OString::valueOf( (double) (rFontData.mnHeight / 20.0) ).getStr() ); // Twips->Pt
961 if( rFontData.maColor != Color( 0xFF, 0xFF, 0xFF, 0xFF ) )
962 pStream->singleElement( XML_color,
963 // OOXTODO: XML_auto, bool
964 // OOXTODO: XML_indexed, uint
965 XML_rgb, XclXmlUtils::ToOString( rFontData.maColor ).getStr(),
966 // OOXTODO: XML_theme, index into <clrScheme/>
967 // OOXTODO: XML_tint, double
968 FSEND );
969 lcl_WriteValue( pStream, nFontId, XclXmlUtils::ToOString( rFontData.maName ).getStr() );
970 lcl_WriteValue( pStream, XML_family, OString::valueOf( (sal_Int32) rFontData.mnFamily ).getStr() );
971 lcl_WriteValue( pStream, XML_charset, rFontData.mnCharSet != 0 ? OString::valueOf( (sal_Int32) rFontData.mnCharSet ).getStr() : NULL );
973 return pStream;
977 // ============================================================================
979 XclExpXmlStream::XclExpXmlStream( const Reference< XComponentContext >& rCC )
980 : XmlFilterBase( rCC ),
981 mpRoot( NULL )
985 XclExpXmlStream::~XclExpXmlStream()
989 sax_fastparser::FSHelperPtr& XclExpXmlStream::GetCurrentStream()
991 OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::GetCurrentStream - no current stream" );
992 return maStreams.top();
995 void XclExpXmlStream::PushStream( sax_fastparser::FSHelperPtr aStream )
997 maStreams.push( aStream );
1000 void XclExpXmlStream::PopStream()
1002 OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::PopStream - stack is empty!" );
1003 maStreams.pop();
1006 sax_fastparser::FSHelperPtr XclExpXmlStream::GetStreamForPath( const OUString& sPath )
1008 if( maOpenedStreamMap.find( sPath ) == maOpenedStreamMap.end() )
1009 return sax_fastparser::FSHelperPtr();
1010 return maOpenedStreamMap[ sPath ].second;
1013 sax_fastparser::FSHelperPtr& XclExpXmlStream::WriteAttributesInternal( sal_Int32 nAttribute, ... )
1015 sax_fastparser::FSHelperPtr& rStream = GetCurrentStream();
1017 va_list args;
1018 va_start( args, nAttribute );
1019 do {
1020 const char* pValue = va_arg( args, const char* );
1021 if( pValue )
1023 rStream->write( " " )
1024 ->writeId( nAttribute )
1025 ->write( "=\"" )
1026 ->writeEscaped( pValue )
1027 ->write( "\"" );
1030 nAttribute = va_arg( args, sal_Int32 );
1031 if( nAttribute == FSEND_internal )
1032 break;
1033 } while( true );
1034 va_end( args );
1036 return rStream;
1038 sax_fastparser::FSHelperPtr XclExpXmlStream::CreateOutputStream (
1039 const OUString& sFullStream,
1040 const OUString& sRelativeStream,
1041 const Reference< XOutputStream >& xParentRelation,
1042 const char* sContentType,
1043 const char* sRelationshipType,
1044 OUString* pRelationshipId )
1046 OUString sRelationshipId;
1047 if (xParentRelation.is())
1048 sRelationshipId = addRelation( xParentRelation, OUString::createFromAscii( sRelationshipType), sRelativeStream );
1049 else
1050 sRelationshipId = addRelation( OUString::createFromAscii( sRelationshipType ), sRelativeStream );
1052 if( pRelationshipId )
1053 *pRelationshipId = sRelationshipId;
1055 sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) );
1057 maOpenedStreamMap[ sFullStream ] = std::make_pair( sRelationshipId, p );
1059 return p;
1062 bool XclExpXmlStream::importDocument() throw()
1064 return false;
1067 oox::vml::Drawing* XclExpXmlStream::getVmlDrawing()
1069 return 0;
1072 const oox::drawingml::Theme* XclExpXmlStream::getCurrentTheme() const
1074 return 0;
1077 const oox::drawingml::table::TableStyleListPtr XclExpXmlStream::getTableStyles()
1079 return oox::drawingml::table::TableStyleListPtr();
1082 oox::drawingml::chart::ChartConverter* XclExpXmlStream::getChartConverter()
1084 // DO NOT CALL
1085 return NULL;
1088 ScDocShell* XclExpXmlStream::getDocShell()
1090 Reference< XInterface > xModel( getModel(), UNO_QUERY );
1092 ScModelObj *pObj = dynamic_cast < ScModelObj* >( xModel.get() );
1094 if ( pObj )
1095 return static_cast < ScDocShell* >( pObj->GetEmbeddedObject() );
1097 return 0;
1100 bool XclExpXmlStream::exportDocument() throw()
1102 ScDocShell* pShell = getDocShell();
1103 ScDocument* pDoc = pShell->GetDocument();
1104 // NOTE: Don't use SotStorage or SvStream any more, and never call
1105 // SfxMedium::GetOutStream() anywhere in the xlsx export filter code!
1106 // Instead, write via XOutputStream instance.
1107 SotStorageRef rStorage = static_cast<SotStorage*>(NULL);
1108 XclExpObjList::ResetCounters();
1110 XclExpRootData aData( EXC_BIFF8, *pShell->GetMedium (), rStorage, *pDoc, RTL_TEXTENCODING_DONTKNOW );
1111 aData.meOutput = EXC_OUTPUT_XML_2007;
1112 aData.maXclMaxPos.Set( EXC_MAXCOL_XML_2007, EXC_MAXROW_XML_2007, EXC_MAXTAB_XML_2007 );
1113 aData.maMaxPos.SetCol( ::std::min( aData.maScMaxPos.Col(), aData.maXclMaxPos.Col() ) );
1114 aData.maMaxPos.SetRow( ::std::min( aData.maScMaxPos.Row(), aData.maXclMaxPos.Row() ) );
1115 aData.maMaxPos.SetTab( ::std::min( aData.maScMaxPos.Tab(), aData.maXclMaxPos.Tab() ) );
1117 XclExpRoot aRoot( aData );
1119 mpRoot = &aRoot;
1120 aRoot.GetOldRoot().pER = &aRoot;
1121 aRoot.GetOldRoot().eDateiTyp = Biff8;
1122 // Get the viewsettings before processing
1123 if( pShell->GetViewData() )
1124 pShell->GetViewData()->WriteExtOptions( mpRoot->GetExtDocOptions() );
1126 OUString const workbook = "xl/workbook.xml";
1127 PushStream( CreateOutputStream( workbook, workbook,
1128 Reference <XOutputStream>(),
1129 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
1130 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" ) );
1132 // destruct at the end of the block
1134 ExcDocument aDocRoot( aRoot );
1135 aDocRoot.ReadDoc();
1136 aDocRoot.WriteXml( *this );
1139 mpRoot = NULL;
1140 return true;
1143 //////////////////////////////////////////////////////////////////////////
1144 // UNO stuff so that the filter is registered
1145 //////////////////////////////////////////////////////////////////////////
1147 #define IMPL_NAME "com.sun.star.comp.oox.ExcelFilterExport"
1149 OUString XlsxExport_getImplementationName()
1151 return OUString( IMPL_NAME );
1154 ::oox::ole::VbaProject* XclExpXmlStream::implCreateVbaProject() const
1156 return new ::oox::xls::ExcelVbaProject( getComponentContext(), Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
1159 OUString XclExpXmlStream::implGetImplementationName() const
1161 return OUString( "TODO" );
1165 Sequence< OUString > SAL_CALL XlsxExport_getSupportedServiceNames() throw()
1167 const OUString aServiceName( "com.sun.star.document.ExportFilter" );
1168 const Sequence< OUString > aSeq( &aServiceName, 1 );
1169 return aSeq;
1172 Reference< XInterface > SAL_CALL XlsxExport_createInstance(const Reference< XComponentContext > & rCC ) throw( Exception )
1174 return (cppu::OWeakObject*) new XclExpXmlStream( rCC );
1177 namespace oox { namespace xls {
1178 OUString SAL_CALL ExcelFilter_getImplementationName() throw();
1179 Sequence< OUString > SAL_CALL ExcelFilter_getSupportedServiceNames() throw();
1180 Reference< XInterface > SAL_CALL ExcelFilter_createInstance(
1181 const Reference< XComponentContext >& rxContext ) throw( Exception );
1183 OUString SAL_CALL OOXMLFormulaParser_getImplementationName() throw();
1184 Sequence< OUString > SAL_CALL OOXMLFormulaParser_getSupportedServiceNames() throw();
1185 Reference< XInterface > SAL_CALL OOXMLFormulaParser_create(
1186 const Reference< XComponentContext >& rxContext ) throw();
1189 #ifdef __cplusplus
1190 extern "C"
1192 #endif
1194 // ------------------------
1195 // - component_getFactory -
1196 // ------------------------
1197 ::cppu::ImplementationEntry entries [] =
1200 XlsxExport_createInstance, XlsxExport_getImplementationName,
1201 XlsxExport_getSupportedServiceNames, ::cppu::createSingleComponentFactory,
1202 0, 0
1205 oox::xls::ExcelFilter_createInstance, oox::xls::ExcelFilter_getImplementationName,
1206 oox::xls::ExcelFilter_getSupportedServiceNames, ::cppu::createSingleComponentFactory,
1207 0, 0
1210 oox::xls::OOXMLFormulaParser_create, oox::xls::OOXMLFormulaParser_getImplementationName,
1211 oox::xls::OOXMLFormulaParser_getSupportedServiceNames, ::cppu::createSingleComponentFactory,
1212 0, 0
1214 { 0, 0, 0, 0, 0, 0 }
1217 SAL_DLLPUBLIC_EXPORT void* SAL_CALL scfilt_component_getFactory( const sal_Char* pImplName, XMultiServiceFactory* pServiceManager, XRegistryKey* pRegistryKey )
1219 return ::cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey, entries );
1223 #ifdef __cplusplus
1225 #endif
1226 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */