blob: 04afd8299912eb573ab7ce07181524d7174258bb [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <utility>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/random.h>
#include <sax/fshelper.hxx>
#include <unotools/streamwrap.hxx>
#include "precompiled_sc.hxx"
#include "docuno.hxx"
#include "xestream.hxx"
#include "xladdress.hxx"
#include "xlstring.hxx"
#include "xeroot.hxx"
#include "xestyle.hxx"
#include "rangelst.hxx"
#include "compiler.hxx"
#include <oox/xls/excelvbaproject.hxx>
#include <formula/grammar.hxx>
#define DEBUG_XL_ENCRYPTION 0
using ::rtl::OString;
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
using ::utl::OStreamWrapper;
using ::std::vector;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sheet;
using namespace ::com::sun::star::uno;
using namespace ::formula;
using namespace ::oox;
// ============================================================================
XclExpStream::XclExpStream( SvStream& rOutStrm, const XclExpRoot& rRoot, sal_uInt16 nMaxRecSize ) :
mrStrm( rOutStrm ),
mrRoot( rRoot ),
mnMaxRecSize( nMaxRecSize ),
mnCurrMaxSize( 0 ),
mnMaxSliceSize( 0 ),
mnHeaderSize( 0 ),
mnCurrSize( 0 ),
mnSliceSize( 0 ),
mnPredictSize( 0 ),
mnLastSizePos( 0 ),
mbInRec( false )
{
if( mnMaxRecSize == 0 )
mnMaxRecSize = (mrRoot.GetBiff() <= EXC_BIFF5) ? EXC_MAXRECSIZE_BIFF5 : EXC_MAXRECSIZE_BIFF8;
mnMaxContSize = mnMaxRecSize;
}
XclExpStream::~XclExpStream()
{
mrStrm.Flush();
}
void XclExpStream::StartRecord( sal_uInt16 nRecId, sal_Size nRecSize )
{
DBG_ASSERT( !mbInRec, "XclExpStream::StartRecord - another record still open" );
DisableEncryption();
mnMaxContSize = mnCurrMaxSize = mnMaxRecSize;
mnPredictSize = nRecSize;
mbInRec = true;
InitRecord( nRecId );
SetSliceSize( 0 );
EnableEncryption();
}
void XclExpStream::EndRecord()
{
DBG_ASSERT( mbInRec, "XclExpStream::EndRecord - no record open" );
DisableEncryption();
UpdateRecSize();
mrStrm.Seek( STREAM_SEEK_TO_END );
mbInRec = false;
}
void XclExpStream::SetSliceSize( sal_uInt16 nSize )
{
mnMaxSliceSize = nSize;
mnSliceSize = 0;
}
XclExpStream& XclExpStream::operator<<( sal_Int8 nValue )
{
PrepareWrite( 1 );
if (mbUseEncrypter && HasValidEncrypter())
mxEncrypter->Encrypt(mrStrm, nValue);
else
mrStrm << nValue;
return *this;
}
XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue )
{
PrepareWrite( 1 );
if (mbUseEncrypter && HasValidEncrypter())
mxEncrypter->Encrypt(mrStrm, nValue);
else
mrStrm << nValue;
return *this;
}
XclExpStream& XclExpStream::operator<<( sal_Int16 nValue )
{
PrepareWrite( 2 );
if (mbUseEncrypter && HasValidEncrypter())
mxEncrypter->Encrypt(mrStrm, nValue);
else
mrStrm << nValue;
return *this;
}
XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue )
{
PrepareWrite( 2 );
if (mbUseEncrypter && HasValidEncrypter())
mxEncrypter->Encrypt(mrStrm, nValue);
else
mrStrm << nValue;
return *this;
}
XclExpStream& XclExpStream::operator<<( sal_Int32 nValue )
{
PrepareWrite( 4 );
if (mbUseEncrypter && HasValidEncrypter())
mxEncrypter->Encrypt(mrStrm, nValue);
else
mrStrm << nValue;
return *this;
}
XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue )
{
PrepareWrite( 4 );
if (mbUseEncrypter && HasValidEncrypter())
mxEncrypter->Encrypt(mrStrm, nValue);
else
mrStrm << nValue;
return *this;
}
XclExpStream& XclExpStream::operator<<( float fValue )
{
PrepareWrite( 4 );
if (mbUseEncrypter && HasValidEncrypter())
mxEncrypter->Encrypt(mrStrm, fValue);
else
mrStrm << fValue;
return *this;
}
XclExpStream& XclExpStream::operator<<( double fValue )
{
PrepareWrite( 8 );
if (mbUseEncrypter && HasValidEncrypter())
mxEncrypter->Encrypt(mrStrm, fValue);
else
mrStrm << fValue;
return *this;
}
sal_Size XclExpStream::Write( const void* pData, sal_Size nBytes )
{
sal_Size nRet = 0;
if( pData && (nBytes > 0) )
{
if( mbInRec )
{
const sal_uInt8* pBuffer = reinterpret_cast< const sal_uInt8* >( pData );
sal_Size nBytesLeft = nBytes;
bool bValid = true;
while( bValid && (nBytesLeft > 0) )
{
sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
sal_Size nWriteRet = nWriteLen;
if (mbUseEncrypter && HasValidEncrypter())
{
DBG_ASSERT(nWriteLen > 0, "XclExpStream::Write: write length is 0!");
vector<sal_uInt8> aBytes(nWriteLen);
memcpy(&aBytes[0], pBuffer, nWriteLen);
mxEncrypter->EncryptBytes(mrStrm, aBytes);
// TODO: How do I check if all the bytes have been successfully written ?
}
else
{
nWriteRet = mrStrm.Write( pBuffer, nWriteLen );
bValid = (nWriteLen == nWriteRet);
DBG_ASSERT( bValid, "XclExpStream::Write - stream write error" );
}
pBuffer += nWriteRet;
nRet += nWriteRet;
nBytesLeft -= nWriteRet;
UpdateSizeVars( nWriteRet );
}
}
else
nRet = mrStrm.Write( pData, nBytes );
}
return nRet;
}
void XclExpStream::WriteZeroBytes( sal_Size nBytes )
{
if( mbInRec )
{
sal_Size nBytesLeft = nBytes;
while( nBytesLeft > 0 )
{
sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
WriteRawZeroBytes( nWriteLen );
nBytesLeft -= nWriteLen;
UpdateSizeVars( nWriteLen );
}
}
else
WriteRawZeroBytes( nBytes );
}
void XclExpStream::WriteZeroBytesToRecord( sal_Size nBytes )
{
if (!mbInRec)
// not in record.
return;
sal_uInt8 nZero = 0;
for (sal_Size i = 0; i < nBytes; ++i)
*this << nZero;
}
sal_Size XclExpStream::CopyFromStream( SvStream& rInStrm, sal_Size nBytes )
{
sal_Size nStrmPos = rInStrm.Tell();
rInStrm.Seek( STREAM_SEEK_TO_END );
sal_Size nStrmSize = rInStrm.Tell();
rInStrm.Seek( nStrmPos );
sal_Size nBytesLeft = ::std::min( nBytes, nStrmSize - nStrmPos );
sal_Size nRet = 0;
if( nBytesLeft > 0 )
{
const sal_Size nMaxBuffer = 4096;
sal_uInt8* pBuffer = new sal_uInt8[ ::std::min( nBytesLeft, nMaxBuffer ) ];
bool bValid = true;
while( bValid && (nBytesLeft > 0) )
{
sal_Size nWriteLen = ::std::min( nBytesLeft, nMaxBuffer );
rInStrm.Read( pBuffer, nWriteLen );
sal_Size nWriteRet = Write( pBuffer, nWriteLen );
bValid = (nWriteLen == nWriteRet);
nRet += nWriteRet;
nBytesLeft -= nWriteRet;
}
delete[] pBuffer;
}
return nRet;
}
//UNUSED2008-05 void XclExpStream::WriteUnicodeBuffer( const sal_uInt16* pBuffer, sal_Size nChars, sal_uInt8 nFlags )
//UNUSED2008-05 {
//UNUSED2008-05 SetSliceSize( 0 );
//UNUSED2008-05 if( pBuffer && (nChars > 0) )
//UNUSED2008-05 {
//UNUSED2008-05 sal_uInt16 nCharLen = (nFlags & EXC_STRF_16BIT) ? 2 : 1;
//UNUSED2008-05 for( sal_Size nIndex = 0; nIndex < nChars; ++nIndex )
//UNUSED2008-05 {
//UNUSED2008-05 if( mbInRec && (mnCurrSize + nCharLen > mnCurrMaxSize) )
//UNUSED2008-05 {
//UNUSED2008-05 StartContinue();
//UNUSED2008-05 // repeat only 16bit flag
//UNUSED2008-05 operator<<( static_cast< sal_uInt8 >( nFlags & EXC_STRF_16BIT ) );
//UNUSED2008-05 }
//UNUSED2008-05 if( nCharLen == 2 )
//UNUSED2008-05 operator<<( pBuffer[ nIndex ] );
//UNUSED2008-05 else
//UNUSED2008-05 operator<<( static_cast< sal_uInt8 >( pBuffer[ nIndex ] ) );
//UNUSED2008-05 }
//UNUSED2008-05 }
//UNUSED2008-05 }
void XclExpStream::WriteUnicodeBuffer( const ScfUInt16Vec& rBuffer, sal_uInt8 nFlags )
{
SetSliceSize( 0 );
nFlags &= EXC_STRF_16BIT; // repeat only 16bit flag
sal_uInt16 nCharLen = nFlags ? 2 : 1;
ScfUInt16Vec::const_iterator aEnd = rBuffer.end();
for( ScfUInt16Vec::const_iterator aIter = rBuffer.begin(); aIter != aEnd; ++aIter )
{
if( mbInRec && (mnCurrSize + nCharLen > mnCurrMaxSize) )
{
StartContinue();
operator<<( nFlags );
}
if( nCharLen == 2 )
operator<<( *aIter );
else
operator<<( static_cast< sal_uInt8 >( *aIter ) );
}
}
//UNUSED2008-05 void XclExpStream::WriteByteStringBuffer( const ByteString& rString, sal_uInt16 nMaxLen )
//UNUSED2008-05 {
//UNUSED2008-05 SetSliceSize( 0 );
//UNUSED2008-05 Write( rString.GetBuffer(), ::std::min< sal_Size >( rString.Len(), nMaxLen ) );
//UNUSED2008-05 }
// ER: #71367# Xcl has an obscure sense of whether starting a new record or not,
// and crashes if it encounters the string header at the very end of a record.
// Thus we add 1 to give some room, seems like they do it that way but with another count (10?)
void XclExpStream::WriteByteString( const ByteString& rString, sal_uInt16 nMaxLen, bool b16BitCount )
{
SetSliceSize( 0 );
sal_Size nLen = ::std::min< sal_Size >( rString.Len(), nMaxLen );
if( !b16BitCount )
nLen = ::std::min< sal_Size >( nLen, 0xFF );
sal_uInt16 nLeft = PrepareWrite();
sal_uInt16 nLenFieldSize = b16BitCount ? 2 : 1;
if( mbInRec && (nLeft <= nLenFieldSize) )
StartContinue();
if( b16BitCount )
operator<<( static_cast< sal_uInt16 >( nLen ) );
else
operator<<( static_cast< sal_uInt8 >( nLen ) );
Write( rString.GetBuffer(), nLen );
}
void XclExpStream::WriteCharBuffer( const ScfUInt8Vec& rBuffer )
{
SetSliceSize( 0 );
Write( &rBuffer[ 0 ], rBuffer.size() );
}
void XclExpStream::SetEncrypter( XclExpEncrypterRef xEncrypter )
{
mxEncrypter = xEncrypter;
}
bool XclExpStream::HasValidEncrypter() const
{
return mxEncrypter.is() && mxEncrypter->IsValid();
}
void XclExpStream::EnableEncryption( bool bEnable )
{
mbUseEncrypter = bEnable && HasValidEncrypter();
}
void XclExpStream::DisableEncryption()
{
EnableEncryption(false);
}
sal_Size XclExpStream::SetSvStreamPos( sal_Size nPos )
{
DBG_ASSERT( !mbInRec, "XclExpStream::SetSvStreamPos - not allowed inside of a record" );
return mbInRec ? 0 : mrStrm.Seek( nPos );
}
// private --------------------------------------------------------------------
void XclExpStream::InitRecord( sal_uInt16 nRecId )
{
mrStrm.Seek( STREAM_SEEK_TO_END );
mrStrm << nRecId;
mnLastSizePos = mrStrm.Tell();
mnHeaderSize = static_cast< sal_uInt16 >( ::std::min< sal_Size >( mnPredictSize, mnCurrMaxSize ) );
mrStrm << mnHeaderSize;
mnCurrSize = mnSliceSize = 0;
}
void XclExpStream::UpdateRecSize()
{
if( mnCurrSize != mnHeaderSize )
{
mrStrm.Seek( mnLastSizePos );
mrStrm << mnCurrSize;
}
}
void XclExpStream::UpdateSizeVars( sal_Size nSize )
{
DBG_ASSERT( mnCurrSize + nSize <= mnCurrMaxSize, "XclExpStream::UpdateSizeVars - record overwritten" );
mnCurrSize = mnCurrSize + static_cast< sal_uInt16 >( nSize );
if( mnMaxSliceSize > 0 )
{
DBG_ASSERT( mnSliceSize + nSize <= mnMaxSliceSize, "XclExpStream::UpdateSizeVars - slice overwritten" );
mnSliceSize = mnSliceSize + static_cast< sal_uInt16 >( nSize );
if( mnSliceSize >= mnMaxSliceSize )
mnSliceSize = 0;
}
}
void XclExpStream::StartContinue()
{
UpdateRecSize();
mnCurrMaxSize = mnMaxContSize;
mnPredictSize -= mnCurrSize;
InitRecord( EXC_ID_CONT );
}
void XclExpStream::PrepareWrite( sal_uInt16 nSize )
{
if( mbInRec )
{
if( (mnCurrSize + nSize > mnCurrMaxSize) ||
((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
StartContinue();
UpdateSizeVars( nSize );
}
}
sal_uInt16 XclExpStream::PrepareWrite()
{
sal_uInt16 nRet = 0;
if( mbInRec )
{
if( (mnCurrSize >= mnCurrMaxSize) ||
((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
StartContinue();
UpdateSizeVars( 0 );
nRet = (mnMaxSliceSize > 0) ? (mnMaxSliceSize - mnSliceSize) : (mnCurrMaxSize - mnCurrSize);
}
return nRet;
}
void XclExpStream::WriteRawZeroBytes( sal_Size nBytes )
{
const sal_uInt32 nData = 0;
sal_Size nBytesLeft = nBytes;
while( nBytesLeft >= sizeof( nData ) )
{
mrStrm << nData;
nBytesLeft -= sizeof( nData );
}
if( nBytesLeft )
mrStrm.Write( &nData, nBytesLeft );
}
// ============================================================================
XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot& rRoot ) :
mrRoot(rRoot),
mnOldPos(STREAM_SEEK_TO_END),
mbValid(false)
{
Sequence< NamedValue > aEncryptionData = rRoot.GetEncryptionData();
if( !aEncryptionData.hasElements() )
// Empty password. Get the default biff8 password.
aEncryptionData = rRoot.GenerateDefaultEncryptionData();
Init( aEncryptionData );
}
XclExpBiff8Encrypter::~XclExpBiff8Encrypter()
{
}
bool XclExpBiff8Encrypter::IsValid() const
{
return mbValid;
}
void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 pnSaltDigest[16] ) const
{
if ( sizeof( mpnSaltDigest ) == 16 )
memcpy( pnSaltDigest, mpnSaltDigest, 16 );
}
void XclExpBiff8Encrypter::GetSalt( sal_uInt8 pnSalt[16] ) const
{
if ( sizeof( mpnSalt ) == 16 )
memcpy( pnSalt, mpnSalt, 16 );
}
void XclExpBiff8Encrypter::GetDocId( sal_uInt8 pnDocId[16] ) const
{
if ( sizeof( mpnDocId ) == 16 )
memcpy( pnDocId, mpnDocId, 16 );
}
void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt8 nData )
{
vector<sal_uInt8> aByte(1);
aByte[0] = nData;
EncryptBytes(rStrm, aByte);
}
void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt16 nData )
{
::std::vector<sal_uInt8> pnBytes(2);
pnBytes[0] = nData & 0xFF;
pnBytes[1] = (nData >> 8) & 0xFF;
EncryptBytes(rStrm, pnBytes);
}
void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt32 nData )
{
::std::vector<sal_uInt8> pnBytes(4);
pnBytes[0] = nData & 0xFF;
pnBytes[1] = (nData >> 8) & 0xFF;
pnBytes[2] = (nData >> 16) & 0xFF;
pnBytes[3] = (nData >> 24) & 0xFF;
EncryptBytes(rStrm, pnBytes);
}
void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, float fValue )
{
::std::vector<sal_uInt8> pnBytes(4);
memcpy(&pnBytes[0], &fValue, 4);
EncryptBytes(rStrm, pnBytes);
}
void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, double fValue )
{
::std::vector<sal_uInt8> pnBytes(8);
memcpy(&pnBytes[0], &fValue, 8);
EncryptBytes(rStrm, pnBytes);
}
void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int8 nData )
{
Encrypt(rStrm, static_cast<sal_uInt8>(nData));
}
void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int16 nData )
{
Encrypt(rStrm, static_cast<sal_uInt16>(nData));
}
void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int32 nData )
{
Encrypt(rStrm, static_cast<sal_uInt32>(nData));
}
void XclExpBiff8Encrypter::Init( const Sequence< NamedValue >& rEncryptionData )
{
mbValid = false;
if( maCodec.InitCodec( rEncryptionData ) )
{
maCodec.GetDocId( mpnDocId );
// generate the salt here
TimeValue aTime;
osl_getSystemTime( &aTime );
rtlRandomPool aRandomPool = rtl_random_createPool ();
rtl_random_addBytes( aRandomPool, &aTime, 8 );
rtl_random_getBytes( aRandomPool, mpnSalt, 16 );
rtl_random_destroyPool( aRandomPool );
memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) );
// generate salt hash.
::msfilter::MSCodec_Std97 aCodec;
aCodec.InitCodec( rEncryptionData );
aCodec.CreateSaltDigest( mpnSalt, mpnSaltDigest );
// verify to make sure it's in good shape.
mbValid = maCodec.VerifyKey( mpnSalt, mpnSaltDigest );
}
}
sal_uInt32 XclExpBiff8Encrypter::GetBlockPos( sal_Size nStrmPos ) const
{
return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
}
sal_uInt16 XclExpBiff8Encrypter::GetOffsetInBlock( sal_Size nStrmPos ) const
{
return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
}
void XclExpBiff8Encrypter::EncryptBytes( SvStream& rStrm, vector<sal_uInt8>& aBytes )
{
sal_Size nStrmPos = rStrm.Tell();
sal_uInt16 nBlockOffset = GetOffsetInBlock(nStrmPos);
sal_uInt32 nBlockPos = GetBlockPos(nStrmPos);
#if DEBUG_XL_ENCRYPTION
fprintf(stdout, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld offset in block = %d block pos = %ld\n",
nStrmPos, nBlockOffset, nBlockPos);
#endif
sal_uInt16 nSize = static_cast< sal_uInt16 >( aBytes.size() );
if (nSize == 0)
return;
#if DEBUG_XL_ENCRYPTION
fprintf(stdout, "RAW: ");
for (sal_uInt16 i = 0; i < nSize; ++i)
fprintf(stdout, "%2.2X ", aBytes[i]);
fprintf(stdout, "\n");
#endif
if (mnOldPos != nStrmPos)
{
sal_uInt16 nOldOffset = GetOffsetInBlock(mnOldPos);
sal_uInt32 nOldBlockPos = GetBlockPos(mnOldPos);
if ( (nBlockPos != nOldBlockPos) || (nBlockOffset < nOldOffset) )
{
maCodec.InitCipher(nBlockPos);
nOldOffset = 0;
}
if (nBlockOffset > nOldOffset)
maCodec.Skip(nBlockOffset - nOldOffset);
}
sal_uInt16 nBytesLeft = nSize;
sal_uInt16 nPos = 0;
while (nBytesLeft > 0)
{
sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - nBlockOffset;
sal_uInt16 nEncBytes = ::std::min(nBlockLeft, nBytesLeft);
bool bRet = maCodec.Encode(&aBytes[nPos], nEncBytes, &aBytes[nPos], nEncBytes);
DBG_ASSERT(bRet, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!");
bRet = bRet; // to remove a silly compiler warning.
sal_Size nRet = rStrm.Write(&aBytes[nPos], nEncBytes);
DBG_ASSERT(nRet == nEncBytes, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!");
nRet = nRet; // to remove a silly compiler warning.
nStrmPos = rStrm.Tell();
nBlockOffset = GetOffsetInBlock(nStrmPos);
nBlockPos = GetBlockPos(nStrmPos);
if (nBlockOffset == 0)
maCodec.InitCipher(nBlockPos);
nBytesLeft -= nEncBytes;
nPos += nEncBytes;
}
mnOldPos = nStrmPos;
}
OUString XclXmlUtils::GetStreamName( const char* sStreamDir, const char* sStream, sal_Int32 nId )
{
OUStringBuffer sBuf;
if( sStreamDir )
sBuf.appendAscii( sStreamDir );
sBuf.appendAscii( sStream );
if( nId )
sBuf.append( nId );
sBuf.appendAscii( ".xml" );
return sBuf.makeStringAndClear();
}
OString XclXmlUtils::ToOString( const Color& rColor )
{
char buf[9];
sprintf( buf, "%.2X%.2X%.2X%.2X", rColor.GetTransparency(), rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
buf[8] = '\0';
return OString( buf );
}
OString XclXmlUtils::ToOString( const OUString& s )
{
return OUStringToOString( s, RTL_TEXTENCODING_UTF8 );
}
OString XclXmlUtils::ToOString( const String& s )
{
return OString( s.GetBuffer(), s.Len(), RTL_TEXTENCODING_UTF8 );
}
OString XclXmlUtils::ToOString( const ScAddress& rAddress )
{
String sAddress;
rAddress.Format( sAddress, SCA_VALID, NULL, ScAddress::Details( FormulaGrammar::CONV_XL_A1 ) );
return ToOString( sAddress );
}
OString XclXmlUtils::ToOString( const ScfUInt16Vec& rBuffer )
{
const sal_uInt16* pBuffer = &rBuffer [0];
return OString( pBuffer, rBuffer.size(), RTL_TEXTENCODING_UTF8 );
}
OString XclXmlUtils::ToOString( const ScRange& rRange )
{
String sRange;
rRange.Format( sRange, SCA_VALID, NULL, ScAddress::Details( FormulaGrammar::CONV_XL_A1 ) );
return ToOString( sRange );
}
OString XclXmlUtils::ToOString( const ScRangeList& rRangeList )
{
String s;
rRangeList.Format( s, SCA_VALID, NULL, FormulaGrammar::CONV_XL_A1, ' ' );
return ToOString( s );
}
static ScAddress lcl_ToAddress( const XclAddress& rAddress )
{
ScAddress aAddress;
// For some reason, ScRange::Format() returns omits row numbers if
// the row is >= MAXROW or the column is >= MAXCOL, and Excel doesn't
// like "A:IV" (i.e. no row numbers). Prevent this.
aAddress.SetRow( std::min<sal_Int32>( rAddress.mnRow, MAXROW-1 ) );
aAddress.SetCol( static_cast<sal_Int16>(std::min<sal_Int32>( rAddress.mnCol, MAXCOL-1 )) );
return aAddress;
}
OString XclXmlUtils::ToOString( const XclAddress& rAddress )
{
return ToOString( lcl_ToAddress( rAddress ) );
}
OString XclXmlUtils::ToOString( const XclExpString& s )
{
DBG_ASSERT( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
return ToOString( s.GetUnicodeBuffer() );
}
static ScRange lcl_ToRange( const XclRange& rRange )
{
ScRange aRange;
aRange.aStart = lcl_ToAddress( rRange.maFirst );
aRange.aEnd = lcl_ToAddress( rRange.maLast );
return aRange;
}
OString XclXmlUtils::ToOString( const XclRangeList& rRanges )
{
ScRangeList aRanges;
for( XclRangeList::const_iterator i = rRanges.begin(), end = rRanges.end();
i != end; ++i )
{
aRanges.Append( lcl_ToRange( *i ) );
}
return ToOString( aRanges );
}
OUString XclXmlUtils::ToOUString( const char* s )
{
return OUString( s, (sal_Int32) strlen( s ), RTL_TEXTENCODING_ASCII_US );
}
OUString XclXmlUtils::ToOUString( const ScfUInt16Vec& rBuf, sal_Int32 nStart, sal_Int32 nLength )
{
if( nLength == -1 )
nLength = rBuf.size();
return OUString( &rBuf[nStart], nLength );
}
OUString XclXmlUtils::ToOUString( const String& s )
{
return OUString( s.GetBuffer(), s.Len() );
}
OUString XclXmlUtils::ToOUString( ScDocument& rDocument, const ScAddress& rAddress, ScTokenArray* pTokenArray )
{
ScCompiler aCompiler( &rDocument, rAddress, *pTokenArray);
aCompiler.SetGrammar(FormulaGrammar::GRAM_NATIVE_XL_A1);
String s;
aCompiler.CreateStringFromTokenArray( s );
return ToOUString( s );
}
OUString XclXmlUtils::ToOUString( const XclExpString& s )
{
DBG_ASSERT( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
return ToOUString( s.GetUnicodeBuffer() );
}
const char* XclXmlUtils::ToPsz( bool b )
{
return b ? "true" : "false";
}
// ============================================================================
XclExpXmlStream::XclExpXmlStream( const Reference< XComponentContext >& rxContext, SvStream& rStrm, const XclExpRoot& rRoot )
: XmlFilterBase( rxContext )
, mrRoot( rRoot )
{
Sequence< PropertyValue > aArgs( 1 );
const OUString sStream( RTL_CONSTASCII_USTRINGPARAM( "StreamForOutput" ) );
aArgs[0].Name = sStream;
aArgs[0].Value <<= Reference< XStream > ( new OStreamWrapper( rStrm ) );
XServiceInfo* pInfo = rRoot.GetDocModelObj();
Reference< XComponent > aComponent( pInfo, UNO_QUERY );
setSourceDocument( aComponent );
filter( aArgs );
PushStream( CreateOutputStream(
OUString::createFromAscii( "xl/workbook.xml" ),
OUString::createFromAscii( "xl/workbook.xml" ),
Reference< XOutputStream >(),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" ) );
}
XclExpXmlStream::~XclExpXmlStream()
{
}
sax_fastparser::FSHelperPtr& XclExpXmlStream::GetCurrentStream()
{
DBG_ASSERT( !maStreams.empty(), "XclExpXmlStream::GetCurrentStream - no current stream" );
return maStreams.top();
}
void XclExpXmlStream::PushStream( sax_fastparser::FSHelperPtr aStream )
{
maStreams.push( aStream );
}
void XclExpXmlStream::PopStream()
{
DBG_ASSERT( !maStreams.empty(), "XclExpXmlStream::PopStream - stack is empty!" );
maStreams.pop();
}
OUString XclExpXmlStream::GetIdForPath( const OUString& sPath )
{
if( maOpenedStreamMap.find( sPath ) == maOpenedStreamMap.end() )
return OUString();
return maOpenedStreamMap[ sPath ].first;
}
sax_fastparser::FSHelperPtr XclExpXmlStream::GetStreamForPath( const OUString& sPath )
{
if( maOpenedStreamMap.find( sPath ) == maOpenedStreamMap.end() )
return sax_fastparser::FSHelperPtr();
return maOpenedStreamMap[ sPath ].second;
}
sax_fastparser::FSHelperPtr& XclExpXmlStream::WriteAttributes( sal_Int32 nAttribute, ... )
{
sax_fastparser::FSHelperPtr& rStream = GetCurrentStream();
va_list args;
va_start( args, nAttribute );
do {
const char* pValue = va_arg( args, const char* );
if( pValue )
{
rStream->write( " " )
->writeId( nAttribute )
->write( "=\"" )
->writeEscaped( pValue )
->write( "\"" );
}
nAttribute = va_arg( args, sal_Int32 );
if( nAttribute == FSEND )
break;
} while( true );
va_end( args );
return rStream;
}
static void lcl_WriteValue( sax_fastparser::FSHelperPtr& rStream, sal_Int32 nElement, const char* pValue )
{
if( !pValue )
return;
rStream->singleElement( nElement,
XML_val, pValue,
FSEND );
}
static const char* lcl_GetUnderlineStyle( FontUnderline eUnderline, bool& bHaveUnderline )
{
bHaveUnderline = true;
switch( eUnderline )
{
// OOXTODO: doubleAccounting, singleAccounting
// OOXTODO: what should be done with the other FontUnderline values?
case UNDERLINE_SINGLE: return "single";
case UNDERLINE_DOUBLE: return "double";
case UNDERLINE_NONE:
default: bHaveUnderline = false; return "none";
}
}
static const char* lcl_ToVerticalAlignmentRun( SvxEscapement eEscapement, bool& bHaveAlignment )
{
bHaveAlignment = true;
switch( eEscapement )
{
case SVX_ESCAPEMENT_SUPERSCRIPT: return "superscript";
case SVX_ESCAPEMENT_SUBSCRIPT: return "subscript";
case SVX_ESCAPEMENT_OFF:
default: bHaveAlignment = false; return "baseline";
}
}
sax_fastparser::FSHelperPtr& XclExpXmlStream::WriteFontData( const XclFontData& rFontData, sal_Int32 nFontId )
{
bool bHaveUnderline, bHaveVertAlign;
const char* pUnderline = lcl_GetUnderlineStyle( rFontData.GetScUnderline(), bHaveUnderline );
const char* pVertAlign = lcl_ToVerticalAlignmentRun( rFontData.GetScEscapement(), bHaveVertAlign );
sax_fastparser::FSHelperPtr& rStream = GetCurrentStream();
lcl_WriteValue( rStream, nFontId, XclXmlUtils::ToOString( rFontData.maName ).getStr() );
lcl_WriteValue( rStream, XML_charset, rFontData.mnCharSet != 0 ? OString::valueOf( (sal_Int32) rFontData.mnCharSet ).getStr() : NULL );
lcl_WriteValue( rStream, XML_family, OString::valueOf( (sal_Int32) rFontData.mnFamily ).getStr() );
lcl_WriteValue( rStream, XML_b, rFontData.mnWeight > 400 ? XclXmlUtils::ToPsz( rFontData.mnWeight > 400 ) : NULL );
lcl_WriteValue( rStream, XML_i, rFontData.mbItalic ? XclXmlUtils::ToPsz( rFontData.mbItalic ) : NULL );
lcl_WriteValue( rStream, XML_strike, rFontData.mbStrikeout ? XclXmlUtils::ToPsz( rFontData.mbStrikeout ) : NULL );
lcl_WriteValue( rStream, XML_outline, rFontData.mbOutline ? XclXmlUtils::ToPsz( rFontData.mbOutline ) : NULL );
lcl_WriteValue( rStream, XML_shadow, rFontData.mbShadow ? XclXmlUtils::ToPsz( rFontData.mbShadow ) : NULL );
// OOXTODO: lcl_WriteValue( rStream, XML_condense, ); // mac compatibility setting
// OOXTODO: lcl_WriteValue( rStream, XML_extend, ); // compatibility setting
if( rFontData.maColor != Color( 0xFF, 0xFF, 0xFF, 0xFF ) )
rStream->singleElement( XML_color,
// OOXTODO: XML_auto, bool
// OOXTODO: XML_indexed, uint
XML_rgb, XclXmlUtils::ToOString( rFontData.maColor ).getStr(),
// OOXTODO: XML_theme, index into <clrScheme/>
// OOXTODO: XML_tint, double
FSEND );
lcl_WriteValue( rStream, XML_sz, OString::valueOf( (double) (rFontData.mnHeight / 20.0) ).getStr() ); // Twips->Points
lcl_WriteValue( rStream, XML_u, bHaveUnderline ? pUnderline : NULL );
lcl_WriteValue( rStream, XML_vertAlign, bHaveVertAlign ? pVertAlign : NULL );
return rStream;
}
sax_fastparser::FSHelperPtr XclExpXmlStream::CreateOutputStream (
const OUString& sFullStream,
const OUString& sRelativeStream,
const Reference< XOutputStream >& xParentRelation,
const char* sContentType,
const char* sRelationshipType,
OUString* pRelationshipId )
{
OUString sRelationshipId;
if (xParentRelation.is())
sRelationshipId = addRelation( xParentRelation, OUString::createFromAscii( sRelationshipType), sRelativeStream );
else
sRelationshipId = addRelation( OUString::createFromAscii( sRelationshipType ), sRelativeStream );
if( pRelationshipId )
*pRelationshipId = sRelationshipId;
sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) );
maOpenedStreamMap[ sFullStream ] = std::make_pair( sRelationshipId, p );
return p;
}
bool XclExpXmlStream::importDocument() throw()
{
return false;
}
oox::vml::Drawing* XclExpXmlStream::getVmlDrawing()
{
return 0;
}
const oox::drawingml::Theme* XclExpXmlStream::getCurrentTheme() const
{
return 0;
}
const oox::drawingml::table::TableStyleListPtr XclExpXmlStream::getTableStyles()
{
return oox::drawingml::table::TableStyleListPtr();
}
oox::drawingml::chart::ChartConverter& XclExpXmlStream::getChartConverter()
{
// DO NOT CALL
return * (oox::drawingml::chart::ChartConverter*) NULL;
}
bool XclExpXmlStream::exportDocument() throw()
{
return false;
}
::oox::ole::VbaProject* XclExpXmlStream::implCreateVbaProject() const
{
return new ::oox::xls::ExcelVbaProject( getComponentContext(), Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
}
OUString XclExpXmlStream::implGetImplementationName() const
{
return CREATE_OUSTRING( "TODO" );
}
void XclExpXmlStream::Trace( const char* format, ...)
{
va_list ap;
va_start( ap, format );
vfprintf( stderr, format, ap );
va_end( ap );
}