summaryrefslogtreecommitdiff
path: root/oox/source/xls
diff options
context:
space:
mode:
authorRüdiger Timm <rt@openoffice.org>2008-01-17 07:06:10 +0000
committerRüdiger Timm <rt@openoffice.org>2008-01-17 07:06:10 +0000
commit3381981e76873304b171f7df900561dac681d2af (patch)
treef496d5a2006e8719b5783d5a8966a05858ed3014 /oox/source/xls
parent90e7bde2a1f3dd8c81e947578f14f40059961740 (diff)
#i10000# Bring module to HEAD.
Diffstat (limited to 'oox/source/xls')
-rw-r--r--oox/source/xls/addressconverter.cxx772
-rw-r--r--oox/source/xls/autofiltercontext.cxx770
-rw-r--r--oox/source/xls/biffcodec.cxx211
-rw-r--r--oox/source/xls/biffdetector.cxx241
-rw-r--r--oox/source/xls/bifffragmenthandler.cxx169
-rw-r--r--oox/source/xls/biffhelper.cxx296
-rw-r--r--oox/source/xls/biffinputstream.cxx646
-rw-r--r--oox/source/xls/biffoutputstream.cxx191
-rw-r--r--oox/source/xls/condformatbuffer.cxx782
-rw-r--r--oox/source/xls/condformatcontext.cxx114
-rw-r--r--oox/source/xls/connectionsfragment.cxx127
-rw-r--r--oox/source/xls/defnamesbuffer.cxx674
-rw-r--r--oox/source/xls/excelfilter.cxx284
-rw-r--r--oox/source/xls/externallinkbuffer.cxx857
-rw-r--r--oox/source/xls/externallinkfragment.cxx392
-rw-r--r--oox/source/xls/formulabase.cxx1459
-rw-r--r--oox/source/xls/formulaparser.cxx2595
-rw-r--r--oox/source/xls/headerfooterparser.cxx643
-rw-r--r--oox/source/xls/makefile.mk106
-rw-r--r--oox/source/xls/numberformatsbuffer.cxx2124
-rw-r--r--oox/source/xls/pagesettings.cxx641
-rw-r--r--oox/source/xls/pivotcachefragment.cxx160
-rw-r--r--oox/source/xls/pivottablebuffer.cxx275
-rw-r--r--oox/source/xls/pivottablefragment.cxx194
-rw-r--r--oox/source/xls/querytablefragment.cxx82
-rw-r--r--oox/source/xls/richstring.cxx605
-rw-r--r--oox/source/xls/richstringcontext.cxx118
-rw-r--r--oox/source/xls/sharedformulabuffer.cxx220
-rw-r--r--oox/source/xls/sharedstringsbuffer.cxx91
-rw-r--r--oox/source/xls/sharedstringsfragment.cxx110
-rw-r--r--oox/source/xls/sheetcellrangemap.cxx172
-rw-r--r--oox/source/xls/sheetdatacontext.cxx1160
-rw-r--r--oox/source/xls/stylesbuffer.cxx3214
-rw-r--r--oox/source/xls/stylesfragment.cxx316
-rw-r--r--oox/source/xls/stylespropertyhelper.cxx386
-rw-r--r--oox/source/xls/tablebuffer.cxx172
-rw-r--r--oox/source/xls/tablefragment.cxx92
-rw-r--r--oox/source/xls/themebuffer.cxx170
-rw-r--r--oox/source/xls/unitconverter.cxx209
-rw-r--r--oox/source/xls/validationpropertyhelper.cxx174
-rw-r--r--oox/source/xls/viewsettings.cxx789
-rw-r--r--oox/source/xls/webquerybuffer.cxx207
-rw-r--r--oox/source/xls/workbookfragment.cxx756
-rw-r--r--oox/source/xls/workbookhelper.cxx876
-rw-r--r--oox/source/xls/workbooksettings.cxx297
-rw-r--r--oox/source/xls/worksheetbuffer.cxx333
-rw-r--r--oox/source/xls/worksheetfragment.cxx1068
-rw-r--r--oox/source/xls/worksheethelper.cxx1652
-rw-r--r--oox/source/xls/worksheetsettings.cxx270
49 files changed, 28262 insertions, 0 deletions
diff --git a/oox/source/xls/addressconverter.cxx b/oox/source/xls/addressconverter.cxx
new file mode 100644
index 000000000000..9d2a781cfdc2
--- /dev/null
+++ b/oox/source/xls/addressconverter.cxx
@@ -0,0 +1,772 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: addressconverter.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:07 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/addressconverter.hxx"
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/strbuf.hxx>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/biffoutputstream.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OStringBuffer;
+using ::rtl::OUStringToOString;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::XCellRangeAddressable;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+//! TODO: this limit may be changed
+const sal_Int16 API_MAXTAB = 255;
+
+const sal_Int32 OOX_MAXCOL = static_cast< sal_Int32 >( (1 << 14) - 1 );
+const sal_Int32 OOX_MAXROW = static_cast< sal_Int32 >( (1 << 20) - 1 );
+const sal_Int16 OOX_MAXTAB = static_cast< sal_Int16 >( (1 << 15) - 1 );
+
+const sal_Int32 BIFF2_MAXCOL = 255;
+const sal_Int32 BIFF2_MAXROW = 16383;
+const sal_Int16 BIFF2_MAXTAB = 0;
+
+const sal_Int32 BIFF3_MAXCOL = BIFF2_MAXCOL;
+const sal_Int32 BIFF3_MAXROW = BIFF2_MAXROW;
+const sal_Int16 BIFF3_MAXTAB = BIFF2_MAXTAB;
+
+const sal_Int32 BIFF4_MAXCOL = BIFF3_MAXCOL;
+const sal_Int32 BIFF4_MAXROW = BIFF3_MAXROW;
+const sal_Int16 BIFF4_MAXTAB = 32767;
+
+const sal_Int32 BIFF5_MAXCOL = BIFF4_MAXCOL;
+const sal_Int32 BIFF5_MAXROW = BIFF4_MAXROW;
+const sal_Int16 BIFF5_MAXTAB = BIFF4_MAXTAB;
+
+const sal_Int32 BIFF8_MAXCOL = BIFF5_MAXCOL;
+const sal_Int32 BIFF8_MAXROW = 65535;
+const sal_Int16 BIFF8_MAXTAB = BIFF5_MAXTAB;
+
+const sal_Unicode BIFF_URL_DRIVE = '\x01'; /// DOS drive letter or UNC path.
+const sal_Unicode BIFF_URL_ROOT = '\x02'; /// Root directory of current drive.
+const sal_Unicode BIFF_URL_SUBDIR = '\x03'; /// Subdirectory delimiter.
+const sal_Unicode BIFF_URL_PARENT = '\x04'; /// Parent directory.
+const sal_Unicode BIFF_URL_RAW = '\x05'; /// Unencoded URL.
+const sal_Unicode BIFF_URL_INSTALL = '\x06'; /// Application installation directory.
+const sal_Unicode BIFF_URL_INSTALL2 = '\x07'; /// Alternative application installation directory.
+const sal_Unicode BIFF_URL_ADDIN = '\x08'; /// Add-in installation directory.
+const sal_Unicode BIFF4_URL_SHEET = '\x09'; /// BIFF4 internal sheet.
+const sal_Unicode BIFF_URL_UNC = '@'; /// UNC path root.
+
+
+inline sal_uInt16 lclGetBiffAddressSize( bool bCol16Bit, bool bRow32Bit )
+{
+ return (bCol16Bit ? 2 : 1) + (bRow32Bit ? 4 : 2);
+}
+
+inline sal_uInt16 lclGetBiffRangeSize( bool bCol16Bit, bool bRow32Bit )
+{
+ return 2 * lclGetBiffAddressSize( bCol16Bit, bRow32Bit );
+}
+
+} // namespace
+
+// ============================================================================
+// ============================================================================
+
+CellAddress ApiCellRangeList::getBaseAddress() const
+{
+ if( empty() )
+ return CellAddress();
+ return CellAddress( front().Sheet, front().StartColumn, front().StartRow );
+}
+
+// ============================================================================
+
+void BinAddress::read( RecordInputStream& rStrm )
+{
+ rStrm >> mnRow >> mnCol;
+}
+
+void BinAddress::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
+{
+ mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
+ mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
+}
+
+void BinAddress::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
+{
+ if( bRow32Bit )
+ rStrm << mnRow;
+ else
+ rStrm << static_cast< sal_uInt16 >( mnRow );
+ if( bCol16Bit )
+ rStrm << static_cast< sal_uInt16 >( mnCol );
+ else
+ rStrm << static_cast< sal_uInt8 >( mnCol );
+}
+
+// ============================================================================
+
+bool BinRange::contains( const BinAddress& rAddr ) const
+{
+ return (maFirst.mnCol <= rAddr.mnCol) && (rAddr.mnCol <= maLast.mnCol) &&
+ (maFirst.mnRow <= rAddr.mnRow) && (rAddr.mnRow <= maLast.mnRow);
+}
+
+void BinRange::read( RecordInputStream& rStrm )
+{
+ rStrm >> maFirst.mnRow >> maLast.mnRow >> maFirst.mnCol >> maLast.mnCol;
+}
+
+void BinRange::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
+{
+ maFirst.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
+ maLast.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
+ maFirst.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
+ maLast.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
+}
+
+void BinRange::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
+{
+ if( bRow32Bit )
+ rStrm << maFirst.mnRow << maLast.mnRow;
+ else
+ rStrm << static_cast< sal_uInt16 >( maFirst.mnRow ) << static_cast< sal_uInt16 >( maLast.mnRow );
+ if( bCol16Bit )
+ rStrm << static_cast< sal_uInt16 >( maFirst.mnCol ) << static_cast< sal_uInt16 >( maLast.mnCol );
+ else
+ rStrm << static_cast< sal_uInt8 >( maFirst.mnCol ) << static_cast< sal_uInt8 >( maLast.mnCol );
+}
+
+// ============================================================================
+
+BinRange BinRangeList::getEnclosingRange() const
+{
+ BinRange aRange;
+ if( !empty() )
+ {
+ const_iterator aIt = begin(), aEnd = end();
+ aRange = *aIt;
+ for( ++aIt; aIt != aEnd; ++aIt )
+ {
+ aRange.maFirst.mnCol = ::std::min( aRange.maFirst.mnCol, aIt->maFirst.mnCol );
+ aRange.maFirst.mnRow = ::std::min( aRange.maFirst.mnRow, aIt->maFirst.mnRow );
+ aRange.maLast.mnCol = ::std::max( aRange.maLast.mnCol, aIt->maLast.mnCol );
+ aRange.maLast.mnRow = ::std::max( aRange.maLast.mnRow, aIt->maLast.mnRow );
+ }
+ }
+ return aRange;
+}
+
+void BinRangeList::read( RecordInputStream& rStrm )
+{
+ sal_Int32 nCount = rStrm.readInt32();
+ resize( getLimitedValue< size_t, sal_Int32 >( nCount, 0, rStrm.getRecLeft() / 16 ) );
+ for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
+ aIt->read( rStrm );
+}
+
+void BinRangeList::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
+{
+ sal_uInt16 nCount = rStrm.readuInt16();
+ resize( getLimitedValue< size_t, sal_uInt32 >( nCount, 0, rStrm.getRecLeft() / lclGetBiffRangeSize( bCol16Bit, bRow32Bit ) ) );
+ for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
+ aIt->read( rStrm, bCol16Bit, bRow32Bit );
+}
+
+void BinRangeList::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
+{
+ writeSubList( rStrm, 0, size(), bCol16Bit, bRow32Bit );
+}
+
+void BinRangeList::writeSubList( BiffOutputStream& rStrm, size_t nBegin, size_t nCount, bool bCol16Bit, bool bRow32Bit ) const
+{
+ OSL_ENSURE( nBegin <= size(), "BiffRangeList::writeSubList - invalid start position" );
+ size_t nEnd = ::std::min< size_t >( nBegin + nCount, size() );
+ sal_uInt16 nBiffCount = getLimitedValue< sal_uInt16, size_t >( nEnd - nBegin, 0, SAL_MAX_UINT16 );
+ rStrm << nBiffCount;
+ rStrm.setPortionSize( lclGetBiffRangeSize( bCol16Bit, bRow32Bit ) );
+ for( const_iterator aIt = begin() + nBegin, aEnd = begin() + nEnd; aIt != aEnd; ++aIt )
+ aIt->write( rStrm, bCol16Bit, bRow32Bit );
+}
+
+// ============================================================================
+// ============================================================================
+
+AddressConverter::AddressConverter( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mcUrlThisWorkbook( 0 ),
+ mcUrlExternal( 0 ),
+ mcUrlThisSheet( 0 ),
+ mcUrlInternal( 0 ),
+ mbColOverflow( false ),
+ mbRowOverflow( false ),
+ mbTabOverflow( false )
+{
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
+ break;
+ case FILTER_BIFF: switch( getBiff() )
+ {
+ case BIFF2:
+ initializeMaxPos( BIFF2_MAXTAB, BIFF2_MAXCOL, BIFF2_MAXROW );
+ initializeEncodedUrl( '\x00', '\x01', '\x02', '\x00' );
+ break;
+ case BIFF3:
+ initializeMaxPos( BIFF3_MAXTAB, BIFF3_MAXCOL, BIFF3_MAXROW );
+ initializeEncodedUrl( '\x00', '\x01', '\x02', '\x00' );
+ break;
+ case BIFF4:
+ initializeMaxPos( BIFF4_MAXTAB, BIFF4_MAXCOL, BIFF4_MAXROW );
+ initializeEncodedUrl( '\x00', '\x01', '\x02', '\x00' );
+ break;
+ case BIFF5:
+ initializeMaxPos( BIFF5_MAXTAB, BIFF5_MAXCOL, BIFF5_MAXROW );
+ initializeEncodedUrl( '\x04', '\x01', '\x02', '\x03' );
+ break;
+ case BIFF8:
+ initializeMaxPos( BIFF8_MAXTAB, BIFF8_MAXCOL, BIFF8_MAXROW );
+ initializeEncodedUrl( '\x04', '\x01', '\x00', '\x02' );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+ break;
+ case FILTER_UNKNOWN: break;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+bool AddressConverter::parseOoxAddress2d(
+ sal_Int32& ornColumn, sal_Int32& ornRow,
+ const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
+{
+ ornColumn = ornRow = 0;
+ if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
+ return false;
+
+ const sal_Unicode* pcChar = rString.getStr() + nStart;
+ const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, rString.getLength() - nStart );
+
+ enum { STATE_COL, STATE_ROW } eState = STATE_COL;
+ while( pcChar < pcEndChar )
+ {
+ sal_Unicode cChar = *pcChar;
+ switch( eState )
+ {
+ case STATE_COL:
+ {
+ if( ('a' <= cChar) && (cChar <= 'z') )
+ (cChar -= 'a') += 'A';
+ if( ('A' <= cChar) && (cChar <= 'Z') )
+ {
+ /* Return, if 1-based column index is already 6 characters
+ long (12356631 is column index for column AAAAAA). */
+ if( ornColumn >= 12356631 )
+ return false;
+ (ornColumn *= 26) += (cChar - 'A' + 1);
+ }
+ else if( ornColumn > 0 )
+ {
+ --pcChar;
+ eState = STATE_ROW;
+ }
+ else
+ return false;
+ }
+ break;
+
+ case STATE_ROW:
+ {
+ if( ('0' <= cChar) && (cChar <= '9') )
+ {
+ // return, if 1-based row is already 9 digits long
+ if( ornRow >= 100000000 )
+ return false;
+ (ornRow *= 10) += (cChar - '0');
+ }
+ else
+ return false;
+ }
+ break;
+ }
+ ++pcChar;
+ }
+
+ --ornColumn;
+ --ornRow;
+ return (ornColumn >= 0) && (ornRow >= 0);
+}
+
+bool AddressConverter::parseOoxRange2d(
+ sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
+ sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
+ const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
+{
+ ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
+ if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
+ return false;
+
+ sal_Int32 nEnd = nStart + ::std::min( nLength, rString.getLength() - nStart );
+ sal_Int32 nColonPos = rString.indexOf( ':', nStart );
+ if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) )
+ {
+ return
+ parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) &&
+ parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, nLength - nColonPos - 1 );
+ }
+
+ if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nLength ) )
+ {
+ ornEndColumn = ornStartColumn;
+ ornEndRow = ornStartRow;
+ return true;
+ }
+
+ return false;
+}
+
+namespace {
+
+bool lclAppendUrlChar( OUStringBuffer& orUrl, sal_Unicode cChar, bool bEncodeSpecial )
+{
+ // #126855# encode special characters
+ if( bEncodeSpecial ) switch( cChar )
+ {
+ case '#': orUrl.appendAscii( "%23" ); return true;
+ case '%': orUrl.appendAscii( "%25" ); return true;
+ }
+ orUrl.append( cChar );
+ return cChar >= ' ';
+}
+
+} // namespace
+
+bool AddressConverter::parseBiffTargetUrl(
+ OUString& orClassName, OUString& orTargetUrl, OUString& orSheetName,
+ const OUString& rBiffTargetUrl )
+{
+ OUStringBuffer aTargetUrl;
+ OUStringBuffer aSheetName;
+
+ enum
+ {
+ STATE_START,
+ STATE_ENCODED_PATH_START, /// Start of encoded file path.
+ STATE_ENCODED_PATH, /// Inside encoded file path.
+ STATE_ENCODED_DRIVE, /// DOS drive letter or start of UNC path.
+ STATE_ENCODED_URL, /// Encoded URL, e.g. http links.
+ STATE_UNENCODED, /// Unencoded URL, could be DDE or OLE.
+ STATE_DDE_OLE, /// Second part of DDE or OLE link.
+ STATE_FILENAME, /// File name enclosed in brackets.
+ STATE_SHEETNAME, /// Sheet name following enclosed file name.
+ STATE_UNSUPPORTED, /// Unsupported special paths.
+ STATE_ERROR
+ }
+ eState = STATE_START;
+
+ const sal_Unicode* pcChar = rBiffTargetUrl.getStr();
+ const sal_Unicode* pcEnd = pcChar + rBiffTargetUrl.getLength();
+ for( ; (eState != STATE_ERROR) && (pcChar < pcEnd) && (*pcChar != 0); ++pcChar )
+ {
+ sal_Unicode cChar = *pcChar;
+ switch( eState )
+ {
+ case STATE_START:
+ if( (cChar == mcUrlThisWorkbook) || (cChar == mcUrlThisSheet) )
+ {
+ if( pcChar + 1 < pcEnd ) eState = STATE_ERROR;
+ }
+ else if( cChar == mcUrlExternal )
+ eState = (pcChar + 1 < pcEnd) ? STATE_ENCODED_PATH_START : STATE_ERROR;
+ else if( cChar == mcUrlInternal )
+ eState = (pcChar + 1 < pcEnd) ? STATE_SHEETNAME : STATE_ERROR;
+ else
+ eState = lclAppendUrlChar( aTargetUrl, cChar, true ) ? STATE_UNENCODED : STATE_ERROR;
+ break;
+
+ case STATE_ENCODED_PATH_START:
+ if( cChar == BIFF_URL_DRIVE )
+ eState = STATE_ENCODED_DRIVE;
+ else if( cChar == BIFF_URL_ROOT )
+ {
+ aTargetUrl.append( sal_Unicode( '/' ) );
+ eState = STATE_ENCODED_PATH;
+ }
+ else if( cChar == BIFF_URL_PARENT )
+ aTargetUrl.appendAscii( "../" );
+ else if( cChar == BIFF_URL_RAW )
+ eState = STATE_ENCODED_URL;
+ else if( cChar == BIFF_URL_INSTALL )
+ eState = STATE_UNSUPPORTED;
+ else if( cChar == BIFF_URL_INSTALL2 )
+ eState = STATE_UNSUPPORTED;
+ else if( cChar == BIFF_URL_ADDIN )
+ eState = STATE_UNSUPPORTED;
+ else if( (getBiff() == BIFF4) && (cChar == BIFF4_URL_SHEET) )
+ eState = STATE_SHEETNAME;
+ else if( cChar == '[' )
+ eState = STATE_FILENAME;
+ else if( lclAppendUrlChar( aTargetUrl, cChar, true ) )
+ eState = STATE_ENCODED_PATH;
+ else
+ eState = STATE_ERROR;
+ break;
+
+ case STATE_ENCODED_PATH:
+ if( cChar == BIFF_URL_SUBDIR )
+ aTargetUrl.append( sal_Unicode( '/' ) );
+ else if( cChar == '[' )
+ eState = STATE_FILENAME;
+ else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
+ eState = STATE_ERROR;
+ break;
+
+ case STATE_ENCODED_DRIVE:
+ if( cChar == BIFF_URL_UNC )
+ {
+ aTargetUrl.appendAscii( "file://" );
+ eState = STATE_ENCODED_PATH;
+ }
+ else
+ {
+ aTargetUrl.appendAscii( "file:///" );
+ eState = lclAppendUrlChar( aTargetUrl, cChar, false ) ? STATE_ENCODED_PATH : STATE_ERROR;
+ aTargetUrl.appendAscii( ":/" );
+ }
+ break;
+
+ case STATE_ENCODED_URL:
+ {
+ sal_Int32 nLength = cChar;
+ if( nLength + 1 == pcEnd - pcChar )
+ aTargetUrl.append( pcChar + 1, nLength );
+ else
+ eState = STATE_ERROR;
+ }
+ break;
+
+ case STATE_UNENCODED:
+ if( cChar == BIFF_URL_SUBDIR )
+ {
+ orClassName = aTargetUrl.makeStringAndClear();
+ eState = STATE_DDE_OLE;
+ }
+ else if( cChar == '[' )
+ eState = STATE_FILENAME;
+ else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
+ eState = STATE_ERROR;
+ break;
+
+ case STATE_DDE_OLE:
+ if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
+ eState = STATE_ERROR;
+ break;
+
+ case STATE_FILENAME:
+ if( cChar == ']' )
+ eState = STATE_SHEETNAME;
+ else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
+ eState = STATE_ERROR;
+ break;
+
+ case STATE_SHEETNAME:
+ if( !lclAppendUrlChar( aSheetName, cChar, false ) )
+ eState = STATE_ERROR;
+ break;
+
+ case STATE_UNSUPPORTED:
+ pcChar = pcEnd - 1;
+ break;
+
+ case STATE_ERROR:
+ break;
+ }
+ }
+
+ orTargetUrl = aTargetUrl.makeStringAndClear();
+ orSheetName = aSheetName.makeStringAndClear();
+
+ OSL_ENSURE( (eState != STATE_ERROR) && (pcChar == pcEnd),
+ OStringBuffer( "AddressConverter::parseBiffTargetUrl - parser error in target \"" ).
+ append( OUStringToOString( rBiffTargetUrl, RTL_TEXTENCODING_UTF8 ) ).append( '"' ).getStr() );
+ return (eState != STATE_ERROR) && (eState != STATE_UNSUPPORTED) && (pcChar == pcEnd);
+}
+
+// ----------------------------------------------------------------------------
+
+bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
+{
+ bool bValid = (0 <= nCol) && (nCol <= maMaxPos.Column);
+ if( !bValid && bTrackOverflow )
+ mbColOverflow = true;
+ return bValid;
+}
+
+bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
+{
+ bool bValid = (0 <= nRow) && (nRow <= maMaxPos.Row);
+ if( !bValid && bTrackOverflow )
+ mbRowOverflow = true;
+ return bValid;
+}
+
+bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
+{
+ bool bValid = (0 <= nSheet) && (nSheet <= maMaxPos.Sheet);
+ if( !bValid && bTrackOverflow )
+ mbTabOverflow |= (nSheet > maMaxPos.Sheet); // do not warn for deleted refs (-1)
+ return bValid;
+}
+
+// ----------------------------------------------------------------------------
+
+bool AddressConverter::checkCellAddress( const CellAddress& rAddress, bool bTrackOverflow )
+{
+ return
+ checkTab( rAddress.Sheet, bTrackOverflow ) &&
+ checkCol( rAddress.Column, bTrackOverflow ) &&
+ checkRow( rAddress.Row, bTrackOverflow );
+}
+
+bool AddressConverter::convertToCellAddressUnckecked( CellAddress& orAddress,
+ const OUString& rString, sal_Int16 nSheet )
+{
+ orAddress.Sheet = nSheet;
+ return parseOoxAddress2d( orAddress.Column, orAddress.Row, rString );
+}
+
+bool AddressConverter::convertToCellAddress( CellAddress& orAddress,
+ const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
+{
+ return
+ convertToCellAddressUnckecked( orAddress, rString, nSheet ) &&
+ checkCellAddress( orAddress, bTrackOverflow );
+}
+
+CellAddress AddressConverter::createValidCellAddress(
+ const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
+{
+ CellAddress aAddress;
+ if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
+ {
+ aAddress.Sheet = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet );
+ aAddress.Column = ::std::min( aAddress.Column, maMaxPos.Column );
+ aAddress.Row = ::std::min( aAddress.Row, maMaxPos.Row );
+ }
+ return aAddress;
+}
+
+void AddressConverter::convertToCellAddressUnckecked( CellAddress& orAddress,
+ const BinAddress& rBinAddress, sal_Int16 nSheet )
+{
+ orAddress.Sheet = nSheet;
+ orAddress.Column = rBinAddress.mnCol;
+ orAddress.Row = rBinAddress.mnRow;
+}
+
+bool AddressConverter::convertToCellAddress( CellAddress& orAddress,
+ const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
+{
+ convertToCellAddressUnckecked( orAddress, rBinAddress, nSheet );
+ return checkCellAddress( orAddress, bTrackOverflow );
+}
+
+CellAddress AddressConverter::createValidCellAddress(
+ const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
+{
+ CellAddress aAddress;
+ if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
+ {
+ aAddress.Sheet = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet );
+ aAddress.Column = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnCol, 0, maMaxPos.Column );
+ aAddress.Row = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnRow, 0, maMaxPos.Row );
+ }
+ return aAddress;
+}
+
+// ----------------------------------------------------------------------------
+
+bool AddressConverter::checkCellRange( const CellRangeAddress& rRange, bool bTrackOverflow )
+{
+ checkCol( rRange.EndColumn, bTrackOverflow );
+ checkRow( rRange.EndRow, bTrackOverflow );
+ return
+ checkTab( rRange.Sheet, bTrackOverflow ) &&
+ checkCol( rRange.StartColumn, bTrackOverflow ) &&
+ checkRow( rRange.StartRow, bTrackOverflow );
+}
+
+bool AddressConverter::validateCellRange( CellRangeAddress& orRange, bool bTrackOverflow )
+{
+ if( orRange.StartColumn > orRange.EndColumn )
+ ::std::swap( orRange.StartColumn, orRange.EndColumn );
+ if( orRange.StartRow > orRange.EndRow )
+ ::std::swap( orRange.StartRow, orRange.EndRow );
+ if( !checkCellRange( orRange, bTrackOverflow ) )
+ return false;
+ if( orRange.EndColumn > maMaxPos.Column )
+ orRange.EndColumn = maMaxPos.Column;
+ if( orRange.EndRow > maMaxPos.Row )
+ orRange.EndRow = maMaxPos.Row;
+ return true;
+}
+
+bool AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange,
+ const OUString& rString, sal_Int16 nSheet )
+{
+ orRange.Sheet = nSheet;
+ return parseOoxRange2d( orRange.StartColumn, orRange.StartRow, orRange.EndColumn, orRange.EndRow, rString );
+}
+
+bool AddressConverter::convertToCellRange( CellRangeAddress& orRange,
+ const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
+{
+ return
+ convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
+ validateCellRange( orRange, bTrackOverflow );
+}
+
+void AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange,
+ const BinRange& rBinRange, sal_Int16 nSheet )
+{
+ orRange.Sheet = nSheet;
+ orRange.StartColumn = rBinRange.maFirst.mnCol;
+ orRange.StartRow = rBinRange.maFirst.mnRow;
+ orRange.EndColumn = rBinRange.maLast.mnCol;
+ orRange.EndRow = rBinRange.maLast.mnRow;
+}
+
+bool AddressConverter::convertToCellRange( CellRangeAddress& orRange,
+ const BinRange& rBinRange, sal_Int16 nSheet, bool bTrackOverflow )
+{
+ convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
+ return validateCellRange( orRange, bTrackOverflow );
+}
+
+// ----------------------------------------------------------------------------
+
+bool AddressConverter::checkCellRangeList( const ApiCellRangeList& rRanges, bool bTrackOverflow )
+{
+ for( ApiCellRangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt )
+ if( !checkCellRange( *aIt, bTrackOverflow ) )
+ return false;
+ return true;
+}
+
+void AddressConverter::validateCellRangeList( ApiCellRangeList& orRanges, bool bTrackOverflow )
+{
+ for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
+ if( !validateCellRange( orRanges[ nIndex - 1 ], bTrackOverflow ) )
+ orRanges.erase( orRanges.begin() + nIndex - 1 );
+}
+
+void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges,
+ const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
+{
+ sal_Int32 nPos = 0;
+ sal_Int32 nLen = rString.getLength();
+ CellRangeAddress aRange;
+ while( (0 <= nPos) && (nPos < nLen) )
+ {
+ OUString aToken = rString.getToken( 0, ' ', nPos );
+ if( (aToken.getLength() > 0) && convertToCellRange( aRange, aToken, nSheet, bTrackOverflow ) )
+ orRanges.push_back( aRange );
+ }
+}
+
+void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges,
+ const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
+{
+ CellRangeAddress aRange;
+ for( BinRangeList::const_iterator aIt = rBinRanges.begin(), aEnd = rBinRanges.end(); aIt != aEnd; ++aIt )
+ if( convertToCellRange( aRange, *aIt, nSheet, bTrackOverflow ) )
+ orRanges.push_back( aRange );
+}
+
+// private --------------------------------------------------------------------
+
+void AddressConverter::initializeMaxPos(
+ sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
+{
+ maMaxXlsPos.Sheet = nMaxXlsTab;
+ maMaxXlsPos.Column = nMaxXlsCol;
+ maMaxXlsPos.Row = nMaxXlsRow;
+
+ // maximum cell position in Calc
+ try
+ {
+ Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
+ Reference< XCellRangeAddressable > xAddressable( xSheetsIA->getByIndex( 0 ), UNO_QUERY_THROW );
+ CellRangeAddress aRange = xAddressable->getRangeAddress();
+ maMaxApiPos = CellAddress( API_MAXTAB, aRange.EndColumn, aRange.EndRow );
+ maMaxPos = getBaseFilter().isImportFilter() ? maMaxApiPos : maMaxXlsPos;
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "AddressConverter::AddressConverter - cannot get sheet limits" );
+ }
+}
+
+void AddressConverter::initializeEncodedUrl(
+ sal_Unicode cUrlThisWorkbook, sal_Unicode cUrlExternal,
+ sal_Unicode cUrlThisSheet, sal_Unicode cUrlInternal )
+{
+ mcUrlThisWorkbook = cUrlThisWorkbook;
+ mcUrlExternal = cUrlExternal;
+ mcUrlThisSheet = cUrlThisSheet;
+ mcUrlInternal = cUrlInternal;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/autofiltercontext.cxx b/oox/source/xls/autofiltercontext.cxx
new file mode 100644
index 000000000000..99f56575dc01
--- /dev/null
+++ b/oox/source/xls/autofiltercontext.cxx
@@ -0,0 +1,770 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: autofiltercontext.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:07 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/autofiltercontext.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/sheet/XDatabaseRange.hpp>
+#include <com/sun/star/sheet/XDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XSheetFilterDescriptor.hpp>
+#include <com/sun/star/sheet/FilterOperator.hpp>
+#include <com/sun/star/sheet/FilterConnection.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/i18n/XLocaleData.hpp>
+
+#define DEBUG_OOX_AUTOFILTER 0
+
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+#include <com/sun/star/sheet/XExtendedSheetFilterDescriptor.hpp>
+#include <com/sun/star/sheet/TableFilterFieldNormal.hpp>
+#include <com/sun/star/sheet/TableFilterFieldMultiString.hpp>
+using ::com::sun::star::sheet::TableFilterFieldNormal;
+using ::com::sun::star::sheet::TableFilterFieldMultiString;
+using ::com::sun::star::sheet::XExtendedSheetFilterDescriptor;
+#else
+#include <com/sun/star/sheet/TableFilterField.hpp>
+using ::com::sun::star::sheet::TableFilterField;
+#endif
+
+#if DEBUG_OOX_AUTOFILTER
+#include <stdio.h>
+#endif
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::std::list;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::table::XCellRange;
+using ::com::sun::star::sheet::XDatabaseRange;
+using ::com::sun::star::sheet::XDatabaseRanges;
+using ::com::sun::star::sheet::XSheetFilterDescriptor;
+using ::com::sun::star::i18n::LocaleDataItem;
+using ::com::sun::star::i18n::XLocaleData;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::lang::Locale;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+FilterFieldItem::FilterFieldItem() :
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ mpField(new TableFilterFieldNormal),
+#else
+ mpField(new TableFilterField),
+#endif
+ meType(NORMAL)
+{
+}
+
+FilterFieldItem::FilterFieldItem(Type eType) :
+ meType(eType)
+{
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ switch ( eType )
+ {
+ case MULTI_STRING:
+ mpField.reset(new TableFilterFieldMultiString);
+ break;
+ case NORMAL:
+ mpField.reset(new TableFilterFieldNormal);
+ break;
+ default:
+ mpField.reset(new TableFilterFieldNormal);
+ }
+#else
+ mpField.reset(new TableFilterField);
+ meType = NORMAL;
+#endif
+}
+
+// ============================================================================
+
+OoxAutoFilterContext::OoxAutoFilterContext( const OoxWorksheetFragmentBase& rFragment ) :
+ OoxWorksheetContextBase( rFragment ),
+ mbValidAddress( false ),
+ mbUseRegex( false ),
+ mbShowBlank( false ),
+ mbConnectionAnd( false )
+{
+}
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxAutoFilterContext::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( autoFilter ):
+ return (nElement == XLS_TOKEN( filterColumn ));
+ case XLS_TOKEN( filterColumn ):
+ return (nElement == XLS_TOKEN( filters )) ||
+ (nElement == XLS_TOKEN( customFilters )) ||
+ (nElement == XLS_TOKEN( top10 )) ||
+ (nElement == XLS_TOKEN( dynamicFilter ));
+ case XLS_TOKEN( filters ):
+ return (nElement == XLS_TOKEN( filter ));
+ case XLS_TOKEN( customFilters ):
+ return (nElement == XLS_TOKEN( customFilter ));
+ }
+ return false;
+}
+
+void OoxAutoFilterContext::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( autoFilter ):
+ importAutoFilter( rAttribs );
+ break;
+ case XLS_TOKEN( filterColumn ):
+ if ( mbValidAddress )
+ importFilterColumn( rAttribs );
+ break;
+ case XLS_TOKEN( filters ):
+ if ( mbValidAddress )
+ importFilters( rAttribs );
+ break;
+ case XLS_TOKEN( filter ):
+ if ( mbValidAddress )
+ importFilter( rAttribs );
+ break;
+ case XLS_TOKEN( customFilters ):
+ if ( mbValidAddress )
+ importCustomFilters( rAttribs );
+ break;
+ case XLS_TOKEN( customFilter ):
+ if ( mbValidAddress )
+ importCustomFilter( rAttribs );
+ break;
+ case XLS_TOKEN( top10 ):
+ if ( mbValidAddress )
+ importTop10( rAttribs );
+ break;
+ case XLS_TOKEN( dynamicFilter ):
+ if ( mbValidAddress )
+ importDynamicFilter( rAttribs );
+ break;
+ }
+}
+
+void OoxAutoFilterContext::onEndElement( const OUString& /*rChars*/ )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( autoFilter ):
+ maybeShowBlank();
+ setAutoFilter();
+ break;
+ case XLS_TOKEN( filters ):
+ setFilterNames();
+ break;
+ }
+}
+
+#if DEBUG_OOX_AUTOFILTER
+static void lclPrintNormalField(
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ TableFilterFieldNormal* pField
+#else
+ TableFilterField* pField
+#endif
+)
+{
+ using namespace ::com::sun::star::sheet;
+
+ printf(" Operator: ");
+ switch ( pField->Operator )
+ {
+ case FilterOperator_EQUAL:
+ printf("EQUAL");
+ break;
+ case FilterOperator_NOT_EQUAL:
+ printf("NOT_EQUAL");
+ break;
+ case com::sun::star::sheet::FilterOperator_GREATER:
+ printf("GREATER");
+ break;
+ case com::sun::star::sheet::FilterOperator_GREATER_EQUAL:
+ printf("GREATER_EQUAL");
+ break;
+ case FilterOperator_LESS:
+ printf("LESS");
+ break;
+ case FilterOperator_LESS_EQUAL:
+ printf("LESS_EQUAL");
+ break;
+ case FilterOperator_NOT_EMPTY:
+ printf("NOT_EMPTY");
+ break;
+ case FilterOperator_EMPTY:
+ printf("EMPTY");
+ break;
+ case FilterOperator_BOTTOM_PERCENT:
+ printf("BOTTOM_PERCENT");
+ break;
+ case FilterOperator_BOTTOM_VALUES:
+ printf("BOTTOM_VALUES");
+ break;
+ case FilterOperator_TOP_PERCENT:
+ printf("TOP_PERCENT");
+ break;
+ case FilterOperator_TOP_VALUES:
+ printf("TOP_VALUES");
+ break;
+ default:
+ printf("other");
+ }
+ printf("\n");
+
+ printf(" StringValue: %s\n",
+ OUStringToOString(pField->StringValue, RTL_TEXTENCODING_UTF8).getStr());
+
+ printf(" NumericValue: %g\n", pField->NumericValue);
+
+ printf(" IsNumeric: ");
+ if (pField->IsNumeric)
+ printf("yes\n");
+ else
+ printf("no\n");
+}
+
+static void lclPrintFieldConnection( ::com::sun::star::sheet::FilterConnection eConn )
+{
+ using namespace ::com::sun::star::sheet;
+
+ printf(" Connection: ");
+ switch ( eConn )
+ {
+ case FilterConnection_AND:
+ printf("AND");
+ break;
+ case FilterConnection_OR:
+ printf("OR");
+ break;
+ case FilterConnection_MAKE_FIXED_SIZE:
+ printf("MAKE_FIXED_SIZE");
+ break;
+ default:
+ printf("other");
+ }
+ printf("\n");
+}
+
+static void lclPrintFilterField( const FilterFieldItem& aItem )
+{
+ using namespace ::com::sun::star::sheet;
+
+ printf("----------------------------------------\n");
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ {
+ // Print common fields first.
+
+ TableFilterFieldBase* pField = aItem.mpField.get();
+ printf(" Field: %ld\n", pField->Field);
+ lclPrintFieldConnection(pField->Connection);
+ }
+ switch ( aItem.meType )
+ {
+ case FilterFieldItem::NORMAL:
+ {
+ TableFilterFieldNormal* pField = static_cast<TableFilterFieldNormal*>(aItem.mpField.get());
+ lclPrintNormalField(pField);
+ }
+ break;
+ case FilterFieldItem::MULTI_STRING:
+ {
+ TableFilterFieldMultiString* pMultiStrField = static_cast<TableFilterFieldMultiString*>(aItem.mpField.get());
+ sal_Int32 nSize = pMultiStrField->StringSet.getLength();
+ printf(" StringSet:\n");
+ for ( sal_Int32 i = 0; i < nSize; ++i )
+ {
+ printf(" * %s\n",
+ OUStringToOString(pMultiStrField->StringSet[i], RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ break;
+ }
+#else
+ TableFilterField* pField = aItem.mpField.get();
+ printf(" Field: %ld\n", pField->Field);
+ lclPrintFieldConnection(pField->Connection);
+ lclPrintNormalField(pField);
+
+#endif
+ fflush(stdout);
+}
+#endif
+
+void OoxAutoFilterContext::initialize()
+{
+ maFields.clear();
+ maFilterNames.clear();
+ mbValidAddress = mbShowBlank = mbUseRegex = mbConnectionAnd = false;
+}
+
+void OoxAutoFilterContext::setAutoFilter()
+{
+ using namespace ::com::sun::star::sheet;
+
+ // Name this built-in database.
+ OUStringBuffer sDataAreaNameBuf( CREATE_OUSTRING("Excel_BuiltIn__FilterDatabase_ ") );
+ sDataAreaNameBuf.append( static_cast<sal_Int32>(getSheetIndex()+1) );
+
+ OUString sDataAreaName = sDataAreaNameBuf.makeStringAndClear();
+ Reference< XCellRange > xCellRange = getCellRange( maAutoFilterRange );
+
+ // Create a new database range, add filters to it and refresh the database
+ // for that to take effect.
+
+ Reference< XDatabaseRanges > xDBRanges;
+ {
+ PropertySet aDocProp( getDocument() );
+ aDocProp.getProperty( xDBRanges, CREATE_OUSTRING("DatabaseRanges") );
+ if ( !xDBRanges.is() )
+ {
+ OSL_ENSURE(false, "OoxAutoFilterContext::setAutoFilter: DBRange empty");
+ return;
+ }
+ }
+
+ Reference< XNameAccess > xNA( xDBRanges, UNO_QUERY_THROW );
+ if ( !xNA->hasByName( sDataAreaName ) )
+ xDBRanges->addNewByName( sDataAreaName, maAutoFilterRange );
+
+ Reference< XDatabaseRange > xDB( xNA->getByName( sDataAreaName ), UNO_QUERY );
+ if ( xDB.is() )
+ {
+ PropertySet aProp( xDB );
+ aProp.setProperty( CREATE_OUSTRING("AutoFilter"), true );
+ }
+
+ sal_Int32 nSize = maFields.size();
+ sal_Int32 nMaxFieldCount = nSize;
+ Reference< XSheetFilterDescriptor > xDescriptor = xDB->getFilterDescriptor();
+ if ( xDescriptor.is() )
+ {
+ PropertySet aProp( xDescriptor );
+ aProp.setProperty( CREATE_OUSTRING("ContainsHeader"), true );
+ aProp.setProperty( CREATE_OUSTRING("UseRegularExpressions"), mbUseRegex );
+ aProp.getProperty( nMaxFieldCount, CREATE_OUSTRING("MaxFieldCount") );
+ }
+ else
+ {
+ OSL_ENSURE(false, "OoxAutoFilterContext::setAutoFilter: descriptor is empty");
+ return;
+ }
+
+ // Unpack all column field items into a sequence.
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ Reference< XExtendedSheetFilterDescriptor > xExtDescriptor( xDescriptor, UNO_QUERY );
+ if ( !xExtDescriptor.is() )
+ {
+ OSL_ENSURE(false, "OoxAutoFilterContext::setAutoFilter: extended descriptor is empty");
+ return;
+ }
+
+ xExtDescriptor->begin();
+
+ list< FilterFieldItem >::const_iterator itr = maFields.begin(), itrEnd = maFields.end();
+ for (sal_Int32 i = 0; itr != itrEnd && i < nMaxFieldCount; ++itr, ++i)
+ {
+#if DEBUG_OOX_AUTOFILTER
+ lclPrintFilterField(*itr);
+#endif
+ switch ( itr->meType )
+ {
+ case oox::xls::FilterFieldItem::MULTI_STRING:
+ {
+ // multi-string filter type
+ TableFilterFieldMultiString* pField = static_cast<TableFilterFieldMultiString*>( itr->mpField.get() );
+ xExtDescriptor->addFilterFieldMultiString( *pField );
+ }
+ break;
+ case oox::xls::FilterFieldItem::NORMAL:
+ default:
+ // normal filter type
+ TableFilterFieldNormal* pField = static_cast<TableFilterFieldNormal*>( itr->mpField.get() );
+ xExtDescriptor->addFilterFieldNormal( *pField );
+ }
+ }
+ xExtDescriptor->commit();
+
+#else
+ Sequence< TableFilterField > aFields(nSize);
+ list< FilterFieldItem >::const_iterator itr = maFields.begin(), itrEnd = maFields.end();
+ for (sal_Int32 i = 0; itr != itrEnd && i < nMaxFieldCount; ++itr, ++i)
+ {
+#if DEBUG_OOX_AUTOFILTER
+ lclPrintFilterField( *itr );
+#endif
+ aFields[i] = *itr->mpField;
+ }
+ xDescriptor->setFilterFields( aFields );
+#endif
+ xDB->refresh();
+}
+
+void OoxAutoFilterContext::maybeShowBlank()
+{
+ using namespace ::com::sun::star::sheet;
+
+ if ( !mbShowBlank )
+ return;
+
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ FilterFieldItem aItem(FilterFieldItem::NORMAL);
+ TableFilterFieldNormal* pField = static_cast<TableFilterFieldNormal*>(aItem.mpField.get());
+ pField->Field = mnCurColID;
+ pField->Operator = FilterOperator_EMPTY;
+ pField->Connection = FilterConnection_AND;
+ pField->IsNumeric = false;
+#else
+ FilterFieldItem aItem;
+ aItem.mpField->Field = mnCurColID;
+ aItem.mpField->Operator = FilterOperator_EMPTY;
+ aItem.mpField->Connection = FilterConnection_AND;
+ aItem.mpField->IsNumeric = false;
+#endif
+ maFields.push_back(aItem);
+}
+
+void OoxAutoFilterContext::setFilterNames()
+{
+ using namespace ::com::sun::star::sheet;
+
+
+ sal_Int32 size = maFilterNames.size();
+ if ( !size )
+ return;
+
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ Sequence< OUString > aStrList(size);
+ list< OUString >::const_iterator itr = maFilterNames.begin(), itrEnd = maFilterNames.end();
+ for (sal_Int32 i = 0; itr != itrEnd; ++itr, ++i)
+ aStrList[i] = *itr;
+
+ FilterFieldItem aItem(FilterFieldItem::MULTI_STRING);
+ TableFilterFieldMultiString* pField = static_cast<TableFilterFieldMultiString*>( aItem.mpField.get() );
+ pField->Field = mnCurColID;
+ pField->Connection = FilterConnection_AND;
+ pField->StringSet = aStrList;
+
+ maFields.push_back(aItem);
+#else
+ static const OUString sSep = CREATE_OUSTRING("|");
+
+ OUStringBuffer buf;
+ if ( size > 1 )
+ {
+ buf.append( CREATE_OUSTRING("^(") );
+ mbUseRegex = true;
+ }
+
+ list< OUString >::const_iterator itr = maFilterNames.begin(), itrEnd = maFilterNames.end();
+ bool bFirst = true;
+ for (; itr != itrEnd; ++itr)
+ {
+ if (bFirst)
+ bFirst = false;
+ else
+ buf.append( sSep );
+ buf.append( *itr );
+ }
+ if ( size > 1 )
+ buf.append( CREATE_OUSTRING(")$") );
+
+ FilterFieldItem aItem;
+ aItem.mpField->Field = mnCurColID;
+ aItem.mpField->StringValue = buf.makeStringAndClear();
+ aItem.mpField->Operator = FilterOperator_EQUAL;
+ aItem.mpField->Connection = FilterConnection_AND;
+ aItem.mpField->IsNumeric = false;
+ maFields.push_back(aItem);
+#endif
+}
+
+void OoxAutoFilterContext::importAutoFilter( const AttributeList& rAttribs )
+{
+ initialize();
+
+ mbValidAddress = getAddressConverter().convertToCellRange(
+ maAutoFilterRange, rAttribs.getString( XML_ref ), getSheetIndex(), true );
+}
+
+void OoxAutoFilterContext::importFilterColumn( const AttributeList& rAttribs )
+{
+ // hiddenButton and showButton attributes are not used for now.
+ mnCurColID = rAttribs.getInteger( XML_colId, -1 );
+}
+
+void OoxAutoFilterContext::importTop10( const AttributeList& rAttribs )
+{
+ using namespace ::com::sun::star::sheet;
+
+ // filterVal attribute is not necessarily, since Calc also supports top 10
+ // and top 10% filter type.
+ FilterFieldItem aItem;
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ TableFilterFieldNormal* pField = static_cast<TableFilterFieldNormal*>(aItem.mpField.get());
+#else
+ TableFilterField* pField = aItem.mpField.get();
+#endif
+ pField->Field = mnCurColID;
+
+ bool bPercent = rAttribs.getBool( XML_percent, false );
+ bool bTop = rAttribs.getBool( XML_top, true );
+ pField->NumericValue = rAttribs.getDouble( XML_val, 0.0 );
+ pField->IsNumeric = true;
+
+ // When top10 filter item is present, that's the only filter item for that column.
+ if ( bTop )
+ if ( bPercent )
+ pField->Operator = FilterOperator_TOP_PERCENT;
+ else
+ pField->Operator = FilterOperator_TOP_VALUES;
+ else
+ if ( bPercent )
+ pField->Operator = FilterOperator_BOTTOM_PERCENT;
+ else
+ pField->Operator = FilterOperator_BOTTOM_VALUES;
+
+ maFields.push_back(aItem);
+}
+
+void OoxAutoFilterContext::importCustomFilters( const AttributeList& rAttribs )
+{
+ // OR is default when the 'and' attribute is absent.
+ mbConnectionAnd = rAttribs.getBool( XML_and, false );
+}
+
+/** Do a best-effort guess of whether or not the given string is numerical. */
+static bool lclIsNumeric( const OUString& _str, const LocaleDataItem& aLocaleItem )
+{
+ OUString str = _str.trim();
+ sal_Int32 size = str.getLength();
+
+ if ( !size )
+ // Empty string. This can't be a number.
+ return false;
+
+ // Get the decimal separator for the current locale.
+ const OUString& sep = aLocaleItem.decimalSeparator;
+
+ bool bDecimalSep = false;
+ for (sal_Int32 i = 0; i < size; ++i)
+ {
+ OUString c = str.copy(i, 1);
+ if ( !c.compareTo(sep) )
+ {
+ if ( bDecimalSep )
+ return false;
+ else
+ {
+ bDecimalSep = true;
+ continue;
+ }
+ }
+ if ( (0 > c.compareToAscii("0") || 0 < c.compareToAscii("9")) )
+ return false;
+ }
+
+ return true;
+}
+
+/** Convert wildcard characters to regex equivalent. Returns true if any
+ wildcard character is found. */
+static bool lclWildcard2Regex( OUString& str )
+{
+ bool bWCFound = false;
+ OUStringBuffer buf;
+ sal_Int32 size = str.getLength();
+ buf.ensureCapacity(size + 6); // pure heuristics.
+
+ sal_Unicode dot = '.', star = '*', hat = '^', dollar = '$';
+ buf.append(hat);
+ for (sal_Int32 i = 0; i < size; ++i)
+ {
+ OUString c = str.copy(i, 1);
+ if ( !c.compareToAscii("?") )
+ {
+ buf.append(dot);
+ bWCFound = true;
+ }
+ else if ( !c.compareToAscii("*") )
+ {
+ buf.append(dot);
+ buf.append(star);
+ bWCFound = true;
+ }
+ else
+ buf.append(c);
+ }
+ buf.append(dollar);
+
+ if (bWCFound)
+ str = buf.makeStringAndClear();
+
+ return bWCFound;
+}
+
+/** Translate Excel's filter operator to Calc's. */
+static ::com::sun::star::sheet::FilterOperator lclTranslateFilterOp( sal_Int32 nToken )
+{
+ using namespace ::com::sun::star::sheet;
+
+ switch ( nToken )
+ {
+ case XML_equal:
+ return FilterOperator_EQUAL;
+ case XML_notEqual:
+ return FilterOperator_NOT_EQUAL;
+ case XML_greaterThan:
+ return FilterOperator_GREATER;
+ case XML_greaterThanOrEqual:
+ return FilterOperator_GREATER_EQUAL;
+ case XML_lessThan:
+ return FilterOperator_LESS;
+ case XML_lessThanOrEqual:
+ return FilterOperator_LESS_EQUAL;
+ }
+ return FilterOperator_EQUAL;
+}
+
+void OoxAutoFilterContext::importCustomFilter( const AttributeList& rAttribs )
+{
+ using namespace ::com::sun::star::sheet;
+
+ sal_Int32 nToken = rAttribs.getToken( XML_operator, XML_equal );
+#if USE_SC_MULTI_STRING_FILTER_PATCH
+ FilterFieldItem aItem(FilterFieldItem::NORMAL);
+ TableFilterFieldNormal* pField = static_cast<TableFilterFieldNormal*>(aItem.mpField.get());
+#else
+ FilterFieldItem aItem;
+ TableFilterField* pField = aItem.mpField.get();
+#endif
+ pField->Field = mnCurColID;
+ pField->StringValue = rAttribs.getString( XML_val );
+ pField->NumericValue = pField->StringValue.toDouble();
+ pField->Operator = lclTranslateFilterOp( nToken );
+
+ if ( nToken == XML_notEqual && !pField->StringValue.compareToAscii(" ") )
+ {
+ // Special case for hiding blanks. Excel translates "hide blanks" to
+ // (filter if notEqual " "). So, we need to translate it back.
+ pField->Operator = FilterOperator_NOT_EMPTY;
+ pField->IsNumeric = false;
+ maFields.push_back(aItem);
+ return;
+ }
+
+ switch ( nToken )
+ {
+ case XML_equal:
+ case XML_notEqual:
+ {
+ Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
+ Reference< XLocaleData > xLocale( xFactory->createInstance(
+ CREATE_OUSTRING("com.sun.star.i18n.LocaleData") ), UNO_QUERY );
+
+ if ( !xLocale.is() )
+ return;
+
+ LocaleDataItem aLocaleItem = xLocale->getLocaleItem( ::com::sun::star::lang::Locale() );
+ pField->IsNumeric = lclIsNumeric(pField->StringValue, aLocaleItem);
+
+ if ( !pField->IsNumeric && lclWildcard2Regex(pField->StringValue) )
+ mbUseRegex = true;
+
+ maFields.push_back(aItem);
+ }
+ break;
+
+ case XML_greaterThan:
+ case XML_greaterThanOrEqual:
+ case XML_lessThan:
+ case XML_lessThanOrEqual:
+ {
+ pField->IsNumeric = true;
+ maFields.push_back(aItem);
+ }
+ break;
+ default:
+ OSL_ENSURE( false, "OoxAutoFilterContext::importCustomFilter: unhandled case" );
+ }
+}
+
+void OoxAutoFilterContext::importFilters( const AttributeList& rAttribs )
+{
+ // blank (boolean) and calendarType attributes can be present, but not used for now.
+
+ mbShowBlank = rAttribs.getBool( XML_blank, false );
+ maFilterNames.clear();
+}
+
+void OoxAutoFilterContext::importFilter( const AttributeList& rAttribs )
+{
+ if (mnCurColID == -1)
+ return;
+
+ OUString value = rAttribs.getString( XML_val );
+ if ( value.getLength() )
+ maFilterNames.push_back(value);
+}
+
+void OoxAutoFilterContext::importDynamicFilter( const AttributeList& /*rAttribs*/ )
+{
+ // not implemented yet - Calc doesn't support this.
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/biffcodec.cxx b/oox/source/xls/biffcodec.cxx
new file mode 100644
index 000000000000..0eb0db29aa91
--- /dev/null
+++ b/oox/source/xls/biffcodec.cxx
@@ -0,0 +1,211 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: biffcodec.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:07 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffcodec.hxx"
+#include <osl/thread.h>
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OStringToOUString;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+const OString& BiffCodecHelper::getBiff5WbProtPassword()
+{
+ static const OString saPass( "VelvetSweatshop" );
+ return saPass;
+}
+
+const OUString& BiffCodecHelper::getBiff8WbProtPassword()
+{
+ static const OUString saPass = OStringToOUString( getBiff5WbProtPassword(), RTL_TEXTENCODING_ASCII_US );
+ return saPass;
+}
+
+// ============================================================================
+
+BiffDecoderBase::BiffDecoderBase( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mnError( CODEC_ERROR_UNSUPP_CRYPT )
+{
+}
+
+BiffDecoderBase::~BiffDecoderBase()
+{
+}
+
+void BiffDecoderBase::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes )
+{
+ if( pnDestData && pnSrcData && (nBytes > 0) )
+ {
+ if( isValid() )
+ implDecode( pnDestData, pnSrcData, nStreamPos, nBytes );
+ else
+ memcpy( pnDestData, pnSrcData, nBytes );
+ }
+}
+
+void BiffDecoderBase::setHasValidPassword( bool bValid )
+{
+ mnError = bValid ? CODEC_OK : CODEC_ERROR_WRONG_PASS;
+}
+
+// ============================================================================
+
+BiffDecoder_XOR::BiffDecoder_XOR( const WorkbookHelper& rHelper, sal_uInt16 nKey, sal_uInt16 nHash ) :
+ BiffDecoderBase( rHelper ),
+ maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL )
+{
+ init( BiffCodecHelper::getBiff5WbProtPassword(), nKey, nHash );
+ if( !isValid() )
+ {
+ OString aPass = OUStringToOString( queryPassword(), osl_getThreadTextEncoding() );
+ init( aPass, nKey, nHash );
+ }
+}
+
+void BiffDecoder_XOR::init( const OString& rPass, sal_uInt16 nKey, sal_uInt16 nHash )
+{
+ sal_Int32 nLen = rPass.getLength();
+ bool bValid = (0 < nLen) && (nLen < 16);
+
+ if( bValid )
+ {
+ // copy byte string to sal_uInt8 array
+ sal_uInt8 pnPassw[ 16 ];
+ memset( pnPassw, 0, sizeof( pnPassw ) );
+ memcpy( pnPassw, rPass.getStr(), static_cast< size_t >( nLen ) );
+
+ // init codec
+ maCodec.initKey( pnPassw );
+ bValid = maCodec.verifyKey( nKey, nHash );
+ }
+
+ setHasValidPassword( bValid );
+}
+
+void BiffDecoder_XOR::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes )
+{
+ maCodec.startBlock();
+ maCodec.skip( static_cast< sal_Int32 >( (nStreamPos + nBytes) & 0x0F ) );
+ maCodec.decode( pnDestData, pnSrcData, nBytes );
+}
+
+// ============================================================================
+
+namespace {
+
+/** Returns the block index of the passed stream position for RCF decryption. */
+sal_Int32 lclGetRcfBlock( sal_Int64 nStreamPos )
+{
+ return static_cast< sal_Int32 >( nStreamPos / BIFF_RCF_BLOCKSIZE );
+}
+
+/** Returns the offset of the passed stream position in a block for RCF decryption. */
+sal_Int32 lclGetRcfOffset( sal_Int64 nStreamPos )
+{
+ return static_cast< sal_Int32 >( nStreamPos % BIFF_RCF_BLOCKSIZE );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+BiffDecoder_RCF::BiffDecoder_RCF( const WorkbookHelper& rHelper,
+ sal_uInt8 pnDocId[ 16 ], sal_uInt8 pnSaltData[ 16 ], sal_uInt8 pnSaltHash[ 16 ] ) :
+ BiffDecoderBase( rHelper )
+{
+ init( BiffCodecHelper::getBiff8WbProtPassword(), pnDocId, pnSaltData, pnSaltHash );
+ if( !isValid() )
+ init( queryPassword(), pnDocId, pnSaltData, pnSaltHash );
+}
+
+void BiffDecoder_RCF::init( const OUString& rPass, sal_uInt8 pnDocId[ 16 ], sal_uInt8 pnSaltData[ 16 ], sal_uInt8 pnSaltHash[ 16 ] )
+{
+ sal_Int32 nLen = rPass.getLength();
+ bool bValid = (0 < nLen) && (nLen < 16);
+
+ if( bValid )
+ {
+ // copy string to sal_uInt16 array
+ sal_uInt16 pnPassw[ 16 ];
+ memset( pnPassw, 0, sizeof( pnPassw ) );
+ const sal_Unicode* pcChar = rPass.getStr();
+ const sal_Unicode* pcCharEnd = pcChar + nLen;
+ sal_uInt16* pnCurrPass = pnPassw;
+ for( ; pcChar < pcCharEnd; ++pcChar, ++pnCurrPass )
+ *pnCurrPass = static_cast< sal_uInt16 >( *pcChar );
+
+ // init codec
+ maCodec.initKey( pnPassw, pnDocId );
+ bValid = maCodec.verifyKey( pnSaltData, pnSaltHash );
+ }
+
+ setHasValidPassword( bValid );
+}
+
+void BiffDecoder_RCF::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes )
+{
+ sal_uInt8* pnCurrDest = pnDestData;
+ const sal_uInt8* pnCurrSrc = pnSrcData;
+ sal_Int64 nCurrPos = nStreamPos;
+ sal_uInt16 nBytesLeft = nBytes;
+ while( nBytesLeft > 0 )
+ {
+ // initialize codec for current stream position
+ maCodec.startBlock( lclGetRcfBlock( nCurrPos ) );
+ maCodec.skip( lclGetRcfOffset( nCurrPos ) );
+
+ // decode the block
+ sal_uInt16 nBlockLeft = static_cast< sal_uInt16 >( BIFF_RCF_BLOCKSIZE - lclGetRcfOffset( nCurrPos ) );
+ sal_uInt16 nDecBytes = ::std::min( nBytesLeft, nBlockLeft );
+ maCodec.decode( pnCurrDest, pnCurrSrc, static_cast< sal_Int32 >( nDecBytes ) );
+
+ // prepare for next block
+ pnCurrDest += nDecBytes;
+ pnCurrSrc += nDecBytes;
+ nCurrPos += nDecBytes;
+ nBytesLeft = nBytesLeft - nDecBytes;
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/biffdetector.cxx b/oox/source/xls/biffdetector.cxx
new file mode 100644
index 000000000000..b30e820fcbf0
--- /dev/null
+++ b/oox/source/xls/biffdetector.cxx
@@ -0,0 +1,241 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: biffdetector.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffdetector.hxx"
+#include <algorithm>
+#include <rtl/strbuf.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <comphelper/mediadescriptor.hxx>
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/helper/olestorage.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OStringBuffer;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::beans::PropertyValue;
+using ::com::sun::star::io::XInputStream;
+using ::comphelper::MediaDescriptor;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+Sequence< OUString > BiffDetector_getSupportedServiceNames()
+{
+ Sequence< OUString > aServiceNames( 1 );
+ aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.frame.ExtendedTypeDetection" );
+ return aServiceNames;
+}
+
+OUString BiffDetector_getImplementationName()
+{
+ return CREATE_OUSTRING( "com.sun.star.comp.oox.BiffDetector" );
+}
+
+Reference< XInterface > SAL_CALL BiffDetector_createInstance( const Reference< XMultiServiceFactory >& rxFactory ) throw( Exception )
+{
+ return static_cast< ::cppu::OWeakObject* >( new BiffDetector( rxFactory ) );
+}
+
+// ============================================================================
+
+BiffDetector::BiffDetector( const Reference< XMultiServiceFactory >& rxFactory ) :
+ mxFactory( rxFactory )
+{
+}
+
+BiffDetector::~BiffDetector()
+{
+}
+
+BiffType BiffDetector::detectStreamBiffVersion( BinaryInputStream& rInStream )
+{
+ BiffType eBiff = BIFF_UNKNOWN;
+ if( rInStream.is() && rInStream.isSeekable() && (rInStream.getLength() > 4) )
+ {
+ sal_Int64 nOldPos = rInStream.tell();
+ rInStream.seek( 0 );
+ sal_uInt16 nBofId, nBofSize;
+ rInStream >> nBofId >> nBofSize;
+
+ if( (4 <= nBofSize) && (nBofSize <= 16) && (rInStream.tell() + nBofSize <= rInStream.getLength()) )
+ {
+ switch( nBofId )
+ {
+ case BIFF2_ID_BOF:
+ eBiff = BIFF2;
+ break;
+ case BIFF3_ID_BOF:
+ eBiff = BIFF3;
+ break;
+ case BIFF4_ID_BOF:
+ eBiff = BIFF4;
+ break;
+ case BIFF5_ID_BOF:
+ {
+ if( 6 <= nBofSize )
+ {
+ sal_uInt16 nVersion;
+ rInStream >> nVersion;
+ // #i23425# #i44031# #i62752# there are some *really* broken documents out there...
+ switch( nVersion & 0xFF00 )
+ {
+ case 0: eBiff = BIFF5; break; // #i44031# #i62752#
+ case BIFF_BOF_BIFF2: eBiff = BIFF2; break;
+ case BIFF_BOF_BIFF3: eBiff = BIFF3; break;
+ case BIFF_BOF_BIFF4: eBiff = BIFF4; break;
+ case BIFF_BOF_BIFF5: eBiff = BIFF5; break;
+ case BIFF_BOF_BIFF8: eBiff = BIFF8; break;
+ default: OSL_ENSURE( false,
+ OStringBuffer( "lclDetectStreamBiffVersion - unknown BIFF version: 0x" ).
+ append( static_cast< sal_Int32 >( nVersion ), 16 ).getStr() );
+ }
+ }
+ }
+ break;
+ // else do nothing, no BIFF stream
+ }
+ }
+ rInStream.seek( nOldPos );
+ }
+ return eBiff;
+}
+
+BiffType BiffDetector::detectStorageBiffVersion( OUString& orWorkbookStreamName, StorageRef xStorage )
+{
+ static const OUString saBookName = CREATE_OUSTRING( "Book" );
+ static const OUString saWorkbookName = CREATE_OUSTRING( "Workbook" );
+
+ BiffType eBiff = BIFF_UNKNOWN;
+ if( xStorage.get() )
+ {
+ if( xStorage->isStorage() )
+ {
+ // try to open the "Book" stream
+ BinaryInputStream aBookStrm5( xStorage->openInputStream( saBookName ), true );
+ BiffType eBookStrm5Biff = detectStreamBiffVersion( aBookStrm5 );
+
+ // try to open the "Workbook" stream
+ BinaryInputStream aBookStrm8( xStorage->openInputStream( saWorkbookName ), true );
+ BiffType eBookStrm8Biff = detectStreamBiffVersion( aBookStrm8 );
+
+ // decide which stream to use
+ if( (eBookStrm8Biff != BIFF_UNKNOWN) && ((eBookStrm5Biff == BIFF_UNKNOWN) || (eBookStrm8Biff > eBookStrm5Biff)) )
+ {
+ /* Only "Workbook" stream exists; or both streams exist,
+ and "Workbook" has higher BIFF version than "Book" stream. */
+ eBiff = eBookStrm8Biff;
+ orWorkbookStreamName = saWorkbookName;
+ }
+ else if( eBookStrm5Biff != BIFF_UNKNOWN )
+ {
+ /* Only "Book" stream exists; or both streams exist,
+ and "Book" has higher BIFF version than "Workbook" stream. */
+ eBiff = eBookStrm5Biff;
+ orWorkbookStreamName = saBookName;
+ }
+ }
+ else
+ {
+ // no storage, try plain input stream from medium (even for BIFF5+)
+ BinaryInputStream aStrm( xStorage->openInputStream( OUString() ), false );
+ eBiff = detectStreamBiffVersion( aStrm );
+ orWorkbookStreamName = OUString();
+ }
+ }
+
+ return eBiff;
+}
+
+// com.sun.star.lang.XServiceInfo interface -----------------------------------
+
+OUString SAL_CALL BiffDetector::getImplementationName() throw( RuntimeException )
+{
+ return BiffDetector_getImplementationName();
+}
+
+sal_Bool SAL_CALL BiffDetector::supportsService( const OUString& rService ) throw( RuntimeException )
+{
+ const Sequence< OUString > aServices( BiffDetector_getSupportedServiceNames() );
+ const OUString* pArray = aServices.getConstArray();
+ const OUString* pArrayEnd = pArray + aServices.getLength();
+ return ::std::find( pArray, pArrayEnd, rService ) != pArrayEnd;
+}
+
+Sequence< OUString > SAL_CALL BiffDetector::getSupportedServiceNames() throw( RuntimeException )
+{
+ return BiffDetector_getSupportedServiceNames();
+}
+
+// com.sun.star.document.XExtendedFilterDetect interface ----------------------
+
+OUString SAL_CALL BiffDetector::detect( Sequence< PropertyValue >& rDescriptor ) throw( RuntimeException )
+{
+ OUString aTypeName;
+
+ MediaDescriptor aDescriptor( rDescriptor );
+ aDescriptor.addInputStream();
+
+ Reference< XInputStream > xInStrm( aDescriptor[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY );
+ if( xInStrm.is() )
+ {
+ OUString aWorkbookName;
+ StorageRef xStorage( new OleStorage( mxFactory, xInStrm, true ) );
+ switch( detectStorageBiffVersion( aWorkbookName, xStorage ) )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_40" ); break;
+ case BIFF5: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_95" ); break;
+ case BIFF8: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_97" ); break;
+ default:;
+ }
+ }
+
+ return aTypeName;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/bifffragmenthandler.cxx b/oox/source/xls/bifffragmenthandler.cxx
new file mode 100644
index 000000000000..061e213b1092
--- /dev/null
+++ b/oox/source/xls/bifffragmenthandler.cxx
@@ -0,0 +1,169 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: bifffragmenthandler.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/bifffragmenthandler.hxx"
+#include "oox/xls/biffhelper.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF_BOF_GLOBALS = 0x0005; /// BIFF5-BIFF8 workbook globals.
+const sal_uInt16 BIFF_BOF_MODULE = 0x0006; /// BIFF5-BIFF8 Visual Basic module.
+const sal_uInt16 BIFF_BOF_SHEET = 0x0010; /// BIFF2-BIFF8 worksheet/dialog sheet.
+const sal_uInt16 BIFF_BOF_CHART = 0x0020; /// BIFF2-BIFF8 chart sheet.
+const sal_uInt16 BIFF_BOF_MACRO = 0x0040; /// BIFF4-BIFF8 macro sheet.
+const sal_uInt16 BIFF_BOF_WORKSPACE = 0x0100; /// BIFF3-BIFF8 workspace.
+
+} // namespace
+
+// ============================================================================
+
+BiffFragmentHandler::~BiffFragmentHandler()
+{
+}
+
+bool BiffFragmentHandler::importFragment( BiffInputStream& rStrm )
+{
+ // default implementation: skip the entire fragment
+ return skipFragment( rStrm );
+}
+
+bool BiffFragmentHandler::isBofRecord( sal_uInt16 nRecId )
+{
+ return (nRecId == BIFF2_ID_BOF) || (nRecId == BIFF3_ID_BOF) || (nRecId == BIFF4_ID_BOF) || (nRecId == BIFF5_ID_BOF);
+}
+
+BiffFragmentType BiffFragmentHandler::startFragment( BiffInputStream& rStrm, BiffType eBiff )
+{
+ BiffFragmentType eFragment = BIFF_FRAGMENT_UNKNOWN;
+ if( rStrm.startNextRecord() )
+ {
+ /* #i23425# Don't rely on BOF record ID to read BOF contents, but on
+ the detected BIFF version. */
+ if( isBofRecord( rStrm.getRecId() ) )
+ {
+ // BOF is always written unencrypted
+ rStrm.enableDecoder( false );
+ sal_uInt16 nType = rStrm.skip( 2 ).readuInt16();
+
+ // decide which fragment types are valid for current BIFF version
+ switch( eBiff )
+ {
+ case BIFF2: switch( nType )
+ {
+ case BIFF_BOF_CHART: eFragment = BIFF_FRAGMENT_EMPTYSHEET; break;
+ case BIFF_BOF_MACRO: eFragment = BIFF_FRAGMENT_MACRO; break;
+ // #i51490# Excel interprets invalid types as worksheet
+ default: eFragment = BIFF_FRAGMENT_WORKSHEET;
+ }
+ break;
+
+ case BIFF3: switch( nType )
+ {
+ case BIFF_BOF_CHART: eFragment = BIFF_FRAGMENT_EMPTYSHEET; break;
+ case BIFF_BOF_MACRO: eFragment = BIFF_FRAGMENT_MACRO; break;
+ case BIFF_BOF_WORKSPACE:eFragment = BIFF_FRAGMENT_UNKNOWN; break;
+ // #i51490# Excel interprets invalid types as worksheet
+ default: eFragment = BIFF_FRAGMENT_WORKSHEET;
+ };
+ break;
+
+ case BIFF4: switch( nType )
+ {
+ case BIFF_BOF_CHART: eFragment = BIFF_FRAGMENT_EMPTYSHEET; break;
+ case BIFF_BOF_MACRO: eFragment = BIFF_FRAGMENT_MACRO; break;
+ case BIFF_BOF_WORKSPACE:eFragment = BIFF_FRAGMENT_WORKSPACE; break;
+ // #i51490# Excel interprets invalid types as worksheet
+ default: eFragment = BIFF_FRAGMENT_WORKSHEET;
+ };
+ break;
+
+ case BIFF5:
+ case BIFF8: switch( nType )
+ {
+ case BIFF_BOF_GLOBALS: eFragment = BIFF_FRAGMENT_GLOBALS; break;
+ case BIFF_BOF_CHART: eFragment = BIFF_FRAGMENT_CHART; break;
+ case BIFF_BOF_MACRO: eFragment = BIFF_FRAGMENT_MACRO; break;
+ case BIFF_BOF_WORKSPACE:eFragment = BIFF_FRAGMENT_UNKNOWN; break;
+ // #i51490# Excel interprets invalid types as worksheet
+ default: eFragment = BIFF_FRAGMENT_WORKSHEET;
+ };
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+ }
+ }
+ return eFragment;
+}
+
+bool BiffFragmentHandler::skipFragment( BiffInputStream& rStrm )
+{
+ while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+ if( isBofRecord( rStrm.getRecId() ) )
+ skipFragment( rStrm );
+ return rStrm.isValid() && (rStrm.getRecId() == BIFF_ID_EOF);
+}
+
+// ============================================================================
+
+BiffWorkbookFragmentBase::BiffWorkbookFragmentBase( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+// ============================================================================
+
+BiffWorksheetFragmentBase::BiffWorksheetFragmentBase( const WorkbookHelper& rHelper,
+ ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) :
+ WorksheetHelperRoot( rHelper, xProgressBar, eSheetType, nSheet )
+{
+}
+
+BiffWorksheetFragmentBase::BiffWorksheetFragmentBase( const WorksheetHelper& rHelper ) :
+ WorksheetHelperRoot( rHelper )
+{
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/biffhelper.cxx b/oox/source/xls/biffhelper.cxx
new file mode 100644
index 000000000000..fb04a87e2502
--- /dev/null
+++ b/oox/source/xls/biffhelper.cxx
@@ -0,0 +1,296 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: biffhelper.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffhelper.hxx"
+#include <algorithm>
+#include <rtl/math.hxx>
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/biffoutputstream.hxx"
+#include "oox/xls/worksheethelper.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+namespace oox {
+namespace xls {
+
+// GUID =======================================================================
+
+BiffGuid::BiffGuid()
+{
+ ::std::fill_n( mpnData, sizeof( mpnData ), 0 );
+}
+
+BiffGuid::BiffGuid(
+ sal_uInt32 nData1, sal_uInt16 nData2, sal_uInt16 nData3,
+ sal_uInt8 nData41, sal_uInt8 nData42, sal_uInt8 nData43, sal_uInt8 nData44,
+ sal_uInt8 nData45, sal_uInt8 nData46, sal_uInt8 nData47, sal_uInt8 nData48 )
+{
+ // convert to little endian -> makes streaming easy
+ ByteOrderConverter::writeLittleEndian( mpnData, nData1 );
+ ByteOrderConverter::writeLittleEndian( mpnData + 4, nData2 );
+ ByteOrderConverter::writeLittleEndian( mpnData + 6, nData3 );
+ mpnData[ 8 ] = nData41;
+ mpnData[ 9 ] = nData42;
+ mpnData[ 10 ] = nData43;
+ mpnData[ 11 ] = nData44;
+ mpnData[ 12 ] = nData45;
+ mpnData[ 13 ] = nData46;
+ mpnData[ 14 ] = nData47;
+ mpnData[ 15 ] = nData48;
+}
+
+bool operator==( const BiffGuid& rGuid1, const BiffGuid& rGuid2 )
+{
+ return ::std::equal( rGuid1.mpnData, STATIC_ARRAY_END( rGuid1.mpnData ), rGuid2.mpnData );
+}
+
+bool operator<( const BiffGuid& rGuid1, const BiffGuid& rGuid2 )
+{
+ return ::std::lexicographical_compare(
+ rGuid1.mpnData, STATIC_ARRAY_END( rGuid1.mpnData ),
+ rGuid2.mpnData, STATIC_ARRAY_END( rGuid2.mpnData ) );
+}
+
+BiffInputStream& operator>>( BiffInputStream& rStrm, BiffGuid& rGuid )
+{
+ rStrm.read( rGuid.mpnData, 16 ); // mpnData always in little endian
+ return rStrm;
+}
+
+BiffOutputStream& operator<<( BiffOutputStream& rStrm, const BiffGuid& rGuid )
+{
+ rStrm.setPortionSize( 16 );
+ rStrm.write( rGuid.mpnData, 16 ); // mpnData already in little endian
+ rStrm.setPortionSize( 0 );
+ return rStrm;
+}
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 BIFF_RK_100FLAG = 0x00000001;
+const sal_Int32 BIFF_RK_INTFLAG = 0x00000002;
+const sal_Int32 BIFF_RK_VALUEMASK = 0xFFFFFFFC;
+
+// ----------------------------------------------------------------------------
+
+static const struct CodePageEntry
+{
+ sal_uInt16 mnCodePage;
+ rtl_TextEncoding meTextEnc;
+}
+spCodePages[] =
+{
+ { 437, RTL_TEXTENCODING_IBM_437 }, // OEM US
+// { 720, RTL_TEXTENCODING_IBM_720 }, // OEM Arabic
+ { 737, RTL_TEXTENCODING_IBM_737 }, // OEM Greek
+ { 775, RTL_TEXTENCODING_IBM_775 }, // OEM Baltic
+ { 850, RTL_TEXTENCODING_IBM_850 }, // OEM Latin I
+ { 852, RTL_TEXTENCODING_IBM_852 }, // OEM Latin II (Central European)
+ { 855, RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic
+ { 857, RTL_TEXTENCODING_IBM_857 }, // OEM Turkish
+// { 858, RTL_TEXTENCODING_IBM_858 }, // OEM Multilingual Latin I with Euro
+ { 860, RTL_TEXTENCODING_IBM_860 }, // OEM Portugese
+ { 861, RTL_TEXTENCODING_IBM_861 }, // OEM Icelandic
+ { 862, RTL_TEXTENCODING_IBM_862 }, // OEM Hebrew
+ { 863, RTL_TEXTENCODING_IBM_863 }, // OEM Canadian (French)
+ { 864, RTL_TEXTENCODING_IBM_864 }, // OEM Arabic
+ { 865, RTL_TEXTENCODING_IBM_865 }, // OEM Nordic
+ { 866, RTL_TEXTENCODING_IBM_866 }, // OEM Cyrillic (Russian)
+ { 869, RTL_TEXTENCODING_IBM_869 }, // OEM Greek (Modern)
+ { 874, RTL_TEXTENCODING_MS_874 }, // MS Windows Thai
+ { 932, RTL_TEXTENCODING_MS_932 }, // MS Windows Japanese Shift-JIS
+ { 936, RTL_TEXTENCODING_MS_936 }, // MS Windows Chinese Simplified GBK
+ { 949, RTL_TEXTENCODING_MS_949 }, // MS Windows Korean (Wansung)
+ { 950, RTL_TEXTENCODING_MS_950 }, // MS Windows Chinese Traditional BIG5
+ { 1200, RTL_TEXTENCODING_DONTKNOW }, // Unicode (BIFF8) - return *_DONTKNOW to preserve old code page
+ { 1250, RTL_TEXTENCODING_MS_1250 }, // MS Windows Latin II (Central European)
+ { 1251, RTL_TEXTENCODING_MS_1251 }, // MS Windows Cyrillic
+ { 1252, RTL_TEXTENCODING_MS_1252 }, // MS Windows Latin I (BIFF4-BIFF8)
+ { 1253, RTL_TEXTENCODING_MS_1253 }, // MS Windows Greek
+ { 1254, RTL_TEXTENCODING_MS_1254 }, // MS Windows Turkish
+ { 1255, RTL_TEXTENCODING_MS_1255 }, // MS Windows Hebrew
+ { 1256, RTL_TEXTENCODING_MS_1256 }, // MS Windows Arabic
+ { 1257, RTL_TEXTENCODING_MS_1257 }, // MS Windows Baltic
+ { 1258, RTL_TEXTENCODING_MS_1258 }, // MS Windows Vietnamese
+ { 1361, RTL_TEXTENCODING_MS_1361 }, // MS Windows Korean (Johab)
+ { 10000, RTL_TEXTENCODING_APPLE_ROMAN }, // Apple Roman
+ { 32768, RTL_TEXTENCODING_APPLE_ROMAN }, // Apple Roman
+ { 32769, RTL_TEXTENCODING_MS_1252 } // MS Windows Latin I (BIFF2-BIFF3)
+};
+
+/** Predicate to search by given code page. */
+struct CodePageEntry_CPPred
+{
+ inline explicit CodePageEntry_CPPred( sal_uInt16 nCodePage ) : mnCodePage( nCodePage ) {}
+ inline bool operator()( const CodePageEntry& rEntry ) const { return rEntry.mnCodePage == mnCodePage; }
+ sal_uInt16 mnCodePage;
+};
+
+/** Predicate to search by given text encoding. */
+struct CodePageEntry_TEPred
+{
+ inline explicit CodePageEntry_TEPred( rtl_TextEncoding eTextEnc ) : meTextEnc( eTextEnc ) {}
+ inline bool operator()( const CodePageEntry& rEntry ) const { return rEntry.meTextEnc == meTextEnc; }
+ rtl_TextEncoding meTextEnc;
+};
+
+} // namespace
+
+// ============================================================================
+
+const BiffGuid BiffHelper::maGuidStdHlink(
+ 0x79EAC9D0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B );
+
+const BiffGuid BiffHelper::maGuidUrlMoniker(
+ 0x79EAC9E0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B );
+
+const BiffGuid BiffHelper::maGuidFileMoniker(
+ 0x00000303, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 );
+
+// conversion -----------------------------------------------------------------
+
+double BiffHelper::calcDoubleFromRk( sal_Int32 nRkValue )
+{
+ double fValue = 0.0;
+ if( getFlag( nRkValue, BIFF_RK_INTFLAG ) )
+ {
+ sal_Int32 nTemp = nRkValue >> 2;
+ setFlag< sal_Int32 >( nTemp, 0xE0000000, nRkValue < 0 );
+ fValue = nTemp;
+ }
+ else
+ {
+ sal_math_Double* pDouble = reinterpret_cast< sal_math_Double* >( &fValue );
+ pDouble->w32_parts.msw = static_cast< sal_uInt32 >( nRkValue & BIFF_RK_VALUEMASK );
+ }
+
+ if( getFlag( nRkValue, BIFF_RK_100FLAG ) )
+ fValue /= 100.0;
+
+ return fValue;
+}
+
+namespace {
+
+bool lclCalcRkFromDouble( sal_Int32& ornRkValue, double fValue )
+{
+ // double
+ const sal_math_Double* pValue = reinterpret_cast< const sal_math_Double* >( &fValue );
+ if( (pValue->w32_parts.lsw == 0) && ((pValue->w32_parts.msw & 0x3) == 0) )
+ {
+ ornRkValue = static_cast< sal_Int32 >( pValue->w32_parts.msw );
+ return true;
+ }
+
+ // integer
+ double fInt = 0.0;
+ double fFrac = modf( fValue, &fInt );
+ if( (fFrac == 0.0) && (-536870912.0 <= fInt) && (fInt <= 536870911.0) ) // 2^29
+ {
+ ornRkValue = static_cast< sal_Int32 >( fInt );
+ ornRkValue <<= 2;
+ ornRkValue |= BIFF_RK_INTFLAG;
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+bool BiffHelper::calcRkFromDouble( sal_Int32& ornRkValue, double fValue )
+{
+ if( lclCalcRkFromDouble( ornRkValue, fValue ) )
+ return true;
+
+ if( lclCalcRkFromDouble( ornRkValue, fValue * 100 ) )
+ {
+ ornRkValue |= BIFF_RK_100FLAG;
+ return true;
+ }
+
+ return false;
+}
+
+double BiffHelper::calcDoubleFromError( sal_uInt8 nErrorCode )
+{
+ sal_uInt16 nApiError = 0x7FFF;
+ switch( nErrorCode )
+ {
+ case BIFF_ERR_NULL: nApiError = 521; break;
+ case BIFF_ERR_DIV0: nApiError = 532; break;
+ case BIFF_ERR_VALUE: nApiError = 519; break;
+ case BIFF_ERR_REF: nApiError = 524; break;
+ case BIFF_ERR_NAME: nApiError = 525; break;
+ case BIFF_ERR_NUM: nApiError = 503; break;
+ case BIFF_ERR_NA: nApiError = 0x7FFF; break;
+ default: OSL_ENSURE( false, "BiffHelper::calcDoubleFromError - unknown error code" );
+ }
+ double fValue;
+ ::rtl::math::setNan( &fValue );
+ reinterpret_cast< sal_math_Double* >( &fValue )->nan_parts.fraction_lo = nApiError;
+ return fValue;
+}
+
+rtl_TextEncoding BiffHelper::calcTextEncodingFromCodePage( sal_uInt16 nCodePage )
+{
+ const CodePageEntry* pEntry = ::std::find_if( spCodePages, STATIC_ARRAY_END( spCodePages ), CodePageEntry_CPPred( nCodePage ) );
+ if( pEntry == STATIC_ARRAY_END( spCodePages ) )
+ {
+ OSL_ENSURE( false, "UnitConverter::calcTextEncodingFromCodePage - unknown code page" );
+ return RTL_TEXTENCODING_DONTKNOW;
+ }
+ return pEntry->meTextEnc;
+}
+
+sal_uInt16 BiffHelper::calcCodePageFromTextEncoding( rtl_TextEncoding eTextEnc )
+{
+ const CodePageEntry* pEntry = ::std::find_if( spCodePages, STATIC_ARRAY_END( spCodePages ), CodePageEntry_TEPred( eTextEnc ) );
+ if( pEntry == STATIC_ARRAY_END( spCodePages ) )
+ {
+ OSL_ENSURE( false, "UnitConverter::calcCodePageFromTextEncoding - unsupported text encoding" );
+ return 1252;
+ }
+ return pEntry->mnCodePage;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/biffinputstream.cxx b/oox/source/xls/biffinputstream.cxx
new file mode 100644
index 000000000000..70428f9de3ad
--- /dev/null
+++ b/oox/source/xls/biffinputstream.cxx
@@ -0,0 +1,646 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: biffinputstream.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OString;
+using ::rtl::OStringToOUString;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace prv {
+
+BiffInputRecordBuffer::BiffInputRecordBuffer( BinaryInputStream& rInStrm ) :
+ mrInStrm( rInStrm ),
+ mpCurrentData( 0 ),
+ mnHeaderPos( -1 ),
+ mnBodyPos( 0 ),
+ mnBufferBodyPos( 0 ),
+ mnNextHeaderPos( 0 ),
+ mnRecId( BIFF_ID_UNKNOWN ),
+ mnRecSize( 0 ),
+ mnRecPos( 0 ),
+ mbValidHeader( false )
+{
+ OSL_ENSURE( mrInStrm.isSeekable(), "BiffInputRecordBuffer::BiffInputRecordBuffer - stream must be seekable" );
+ mrInStrm.seekToStart();
+ maOriginalData.reserve( SAL_MAX_UINT16 );
+ maDecodedData.reserve( SAL_MAX_UINT16 );
+ enableDecoder( false ); // updates mpCurrentData
+}
+
+void BiffInputRecordBuffer::restartAt( sal_Int64 nPos )
+{
+ mnHeaderPos = -1;
+ mnBodyPos = mnBufferBodyPos = 0;
+ mnNextHeaderPos = nPos;
+ mnRecId = BIFF_ID_UNKNOWN;
+ mnRecSize = mnRecPos = 0;
+ mbValidHeader = false;
+}
+
+void BiffInputRecordBuffer::setDecoder( BiffDecoderRef xDecoder )
+{
+ mxDecoder = xDecoder;
+ enableDecoder( true );
+ updateDecoded();
+}
+
+void BiffInputRecordBuffer::enableDecoder( bool bEnable )
+{
+ mpCurrentData = (bEnable && mxDecoder.get() && mxDecoder->isValid()) ? &maDecodedData : &maOriginalData;
+}
+
+bool BiffInputRecordBuffer::startRecord( sal_Int64 nHeaderPos )
+{
+ mbValidHeader = (0 <= nHeaderPos) && (nHeaderPos + 4 <= mrInStrm.getLength());
+ if( mbValidHeader )
+ {
+ mnHeaderPos = nHeaderPos;
+ mrInStrm.seek( nHeaderPos );
+ mrInStrm >> mnRecId >> mnRecSize;
+ mnBodyPos = mrInStrm.tell();
+ mnNextHeaderPos = mnBodyPos + mnRecSize;
+ mbValidHeader = mnNextHeaderPos <= mrInStrm.getLength();
+ }
+ if( !mbValidHeader )
+ {
+ mnHeaderPos = mnBodyPos = -1;
+ mnNextHeaderPos = 0;
+ mnRecId = BIFF_ID_UNKNOWN;
+ mnRecSize = 0;
+ }
+ mnRecPos = 0;
+ return mbValidHeader;
+}
+
+bool BiffInputRecordBuffer::startNextRecord()
+{
+ return startRecord( mnNextHeaderPos );
+}
+
+sal_uInt16 BiffInputRecordBuffer::getNextRecId()
+{
+ sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
+ if( mbValidHeader && (mnNextHeaderPos + 4 <= mrInStrm.getLength()) )
+ {
+ mrInStrm.seek( mnNextHeaderPos );
+ mrInStrm >> nRecId;
+ }
+ return nRecId;
+}
+
+void BiffInputRecordBuffer::read( void* opData, sal_uInt16 nBytes )
+{
+ updateBuffer();
+ OSL_ENSURE( nBytes > 0, "BiffInputRecordBuffer::read - nothing to read" );
+ OSL_ENSURE( nBytes <= getRecLeft(), "BiffInputRecordBuffer::read - buffer overflow" );
+ memcpy( opData, &(*mpCurrentData)[ mnRecPos ], nBytes );
+ mnRecPos = mnRecPos + nBytes;
+}
+
+inline void BiffInputRecordBuffer::skip( sal_uInt16 nBytes )
+{
+ OSL_ENSURE( nBytes > 0, "BiffInputRecordBuffer::skip - nothing to skip" );
+ OSL_ENSURE( nBytes <= getRecLeft(), "BiffInputRecordBuffer::skip - buffer overflow" );
+ mnRecPos = mnRecPos + nBytes;
+}
+
+void BiffInputRecordBuffer::updateBuffer()
+{
+ OSL_ENSURE( mbValidHeader, "BiffInputRecordBuffer::updateBuffer - invalid access" );
+ if( mnBodyPos != mnBufferBodyPos )
+ {
+ mrInStrm.seek( mnBodyPos );
+ maOriginalData.resize( mnRecSize );
+ if( mnRecSize > 0 )
+ mrInStrm.read( &maOriginalData.front(), static_cast< sal_Int32 >( mnRecSize ) );
+ mnBufferBodyPos = mnBodyPos;
+ updateDecoded();
+ }
+}
+
+void BiffInputRecordBuffer::updateDecoded()
+{
+ if( mxDecoder.get() && mxDecoder->isValid() )
+ {
+ maDecodedData.resize( mnRecSize );
+ if( mnRecSize > 0 )
+ mxDecoder->decode( &maDecodedData.front(), &maOriginalData.front(), mnBodyPos, mnRecSize );
+ }
+}
+
+} // namespace prv
+
+// ============================================================================
+
+BiffInputStream::BiffInputStream( BinaryInputStream& rInStream, bool bContLookup ) :
+ maRecBuffer( rInStream ),
+ mnRecHandle( -1 ),
+ mnRecId( BIFF_ID_UNKNOWN ),
+ mnAltContId( BIFF_ID_UNKNOWN ),
+ mnCurrRecSize( 0 ),
+ mnComplRecSize( 0 ),
+ mbHasComplRec( false ),
+ mcNulSubst( BIFF_DEF_NUL_SUBST_CHAR ),
+ mbCont( bContLookup ),
+ mbValid( false )
+{
+}
+
+BiffInputStream::~BiffInputStream()
+{
+}
+
+// record control -------------------------------------------------------------
+
+bool BiffInputStream::startNextRecord()
+{
+ bool bValidRec = false;
+ /* #i4266# ignore zero records (id==len==0) (e.g. the application
+ "Crystal Report" writes zero records between other records) */
+ bool bIsZeroRec = false;
+ do
+ {
+ // record header is never encrypted
+ maRecBuffer.enableDecoder( false );
+ // read header of next raw record, returns false at end of stream
+ bValidRec = maRecBuffer.startNextRecord();
+ // ignore record, if identifier and size are zero
+ bIsZeroRec = (maRecBuffer.getRecId() == 0) && (maRecBuffer.getRecSize() == 0);
+ }
+ while( bValidRec && ((mbCont && isContinueId( maRecBuffer.getRecId() )) || bIsZeroRec) );
+
+ // setup other class members
+ setupRecord();
+ return isInRecord();
+}
+
+bool BiffInputStream::startRecordByHandle( sal_Int64 nRecHandle )
+{
+ rewindToRecord( nRecHandle );
+ return startNextRecord();
+}
+
+void BiffInputStream::resetRecord( bool bContLookup, sal_uInt16 nAltContId )
+{
+ if( isInRecord() )
+ {
+ mbCont = bContLookup;
+ mnAltContId = nAltContId;
+ restartRecord( true );
+ maRecBuffer.enableDecoder( true );
+ }
+}
+
+void BiffInputStream::rewindRecord()
+{
+ rewindToRecord( mnRecHandle );
+}
+
+// decoder --------------------------------------------------------------------
+
+void BiffInputStream::setDecoder( BiffDecoderRef xDecoder )
+{
+ maRecBuffer.setDecoder( xDecoder );
+}
+
+BiffDecoderRef BiffInputStream::getDecoder() const
+{
+ return maRecBuffer.getDecoder();
+}
+
+void BiffInputStream::enableDecoder( bool bEnable )
+{
+ maRecBuffer.enableDecoder( bEnable );
+}
+
+// stream/record state and info -----------------------------------------------
+
+sal_uInt32 BiffInputStream::getRecPos() const
+{
+ return mbValid ? (mnCurrRecSize - maRecBuffer.getRecLeft()) : BIFF_REC_SEEK_TO_END;
+}
+
+sal_uInt32 BiffInputStream::getRecSize()
+{
+ if( !mbHasComplRec )
+ {
+ sal_uInt32 nCurrPos = getRecPos(); // save current position in record
+ while( jumpToNextContinue() ); // jumpToNextContinue() adds up mnCurrRecSize
+ mnComplRecSize = mnCurrRecSize;
+ mbHasComplRec = true;
+ seek( nCurrPos ); // restore position, seek() resets old mbValid state
+ }
+ return mnComplRecSize;
+}
+
+sal_uInt32 BiffInputStream::getRecLeft()
+{
+ return mbValid ? (getRecSize() - getRecPos()) : 0;
+}
+
+sal_uInt16 BiffInputStream::getNextRecId()
+{
+ sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
+ if( isInRecord() )
+ {
+ sal_uInt32 nCurrPos = getRecPos(); // save current position in record
+ while( jumpToNextContinue() ); // skip following CONTINUE records
+ if( maRecBuffer.startNextRecord() ) // read header of next record
+ nRecId = maRecBuffer.getRecId();
+ seek( nCurrPos ); // restore position, seek() resets old mbValid state
+ }
+ return nRecId;
+}
+
+sal_Int64 BiffInputStream::getCoreStreamPos() const
+{
+ return maRecBuffer.getCoreStream().tell();
+}
+
+sal_Int64 BiffInputStream::getCoreStreamSize() const
+{
+ return maRecBuffer.getCoreStream().getLength();
+}
+
+// stream read access ---------------------------------------------------------
+
+sal_uInt32 BiffInputStream::read( void* opData, sal_uInt32 nBytes )
+{
+ sal_uInt32 nRet = 0;
+ if( mbValid && opData && (nBytes > 0) )
+ {
+ sal_uInt8* pnBuffer = reinterpret_cast< sal_uInt8* >( opData );
+ sal_uInt32 nBytesLeft = nBytes;
+
+ while( mbValid && (nBytesLeft > 0) )
+ {
+ sal_uInt16 nReadSize = getMaxRawReadSize( nBytesLeft );
+ // check nReadSize, stream may already be located at end of a raw record
+ if( nReadSize > 0 )
+ {
+ maRecBuffer.read( pnBuffer, nReadSize );
+ nRet += nReadSize;
+ pnBuffer += nReadSize;
+ nBytesLeft -= nReadSize;
+ }
+ if( nBytesLeft > 0 )
+ jumpToNextContinue();
+ OSL_ENSURE( mbValid, "BiffInputStream::read - record overread" );
+ }
+ }
+ return nRet;
+}
+
+// seeking --------------------------------------------------------------------
+
+BiffInputStream& BiffInputStream::seek( sal_uInt32 nRecPos )
+{
+ if( isInRecord() )
+ {
+ if( !mbValid || (nRecPos < getRecPos()) )
+ restartRecord( false );
+ if( mbValid && (nRecPos > getRecPos()) )
+ skip( nRecPos - getRecPos() );
+ }
+ return *this;
+}
+
+BiffInputStream& BiffInputStream::skip( sal_uInt32 nBytes )
+{
+ sal_uInt32 nBytesLeft = nBytes;
+ while( mbValid && (nBytesLeft > 0) )
+ {
+ sal_uInt16 nSkipSize = getMaxRawReadSize( nBytesLeft );
+ // check nSkipSize, stream may already be located at end of a raw record
+ if( nSkipSize > 0 )
+ {
+ maRecBuffer.skip( nSkipSize );
+ nBytesLeft -= nSkipSize;
+ }
+ if( nBytesLeft > 0 )
+ jumpToNextContinue();
+ OSL_ENSURE( mbValid, "BiffInputStream::skip - record overread" );
+ }
+ return *this;
+}
+
+// character arrays -----------------------------------------------------------
+
+OString BiffInputStream::readCharArray( sal_uInt16 nChars )
+{
+ ::std::vector< sal_Char > aBuffer( static_cast< size_t >( nChars ) + 1 );
+ size_t nCharsRead = static_cast< size_t >( read( &aBuffer.front(), nChars ) );
+ aBuffer[ nCharsRead ] = 0;
+ return OString( &aBuffer.front() );
+}
+
+OUString BiffInputStream::readCharArray( sal_uInt16 nChars, rtl_TextEncoding eTextEnc )
+{
+ return OStringToOUString( readCharArray( nChars ), eTextEnc );
+}
+
+OUString BiffInputStream::readUnicodeArray( sal_uInt16 nChars )
+{
+ ::std::vector< sal_Unicode > aBuffer;
+ aBuffer.reserve( static_cast< size_t >( nChars ) + 1 );
+ sal_uInt16 nChar;
+ for( sal_uInt16 nCharIdx = 0; mbValid && (nCharIdx < nChars); ++nCharIdx )
+ {
+ readValue( nChar );
+ aBuffer.push_back( static_cast< sal_Unicode >( nChar ) );
+ }
+ aBuffer.push_back( 0 );
+ return OUString( &aBuffer.front() );
+}
+
+// byte strings ---------------------------------------------------------------
+
+OString BiffInputStream::readByteString( bool b16BitLen )
+{
+ sal_uInt16 nStrLen = b16BitLen ? readuInt16() : readuInt8();
+ return readCharArray( nStrLen );
+}
+
+OUString BiffInputStream::readByteString( bool b16BitLen, rtl_TextEncoding eTextEnc )
+{
+ return OStringToOUString( readByteString( b16BitLen ), eTextEnc );
+}
+
+void BiffInputStream::skipByteString( bool b16BitLen )
+{
+ skip( b16BitLen ? readuInt16() : readuInt8() );
+}
+
+// Unicode strings ------------------------------------------------------------
+
+sal_uInt32 BiffInputStream::readExtendedUniStringHeader(
+ bool& rb16Bit, bool& rbFonts, bool& rbPhonetic,
+ sal_uInt16& rnFontCount, sal_uInt32& rnPhoneticSize, sal_uInt8 nFlags )
+{
+ OSL_ENSURE( !getFlag( nFlags, BIFF_STRF_UNKNOWN ), "BiffInputStream::readExtendedUniStringHeader - unknown flags" );
+ rb16Bit = getFlag( nFlags, BIFF_STRF_16BIT );
+ rbFonts = getFlag( nFlags, BIFF_STRF_RICH );
+ rbPhonetic = getFlag( nFlags, BIFF_STRF_PHONETIC );
+ rnFontCount = 0;
+ if( rbFonts ) readValue( rnFontCount );
+ rnPhoneticSize = 0;
+ if( rbPhonetic ) readValue( rnPhoneticSize );
+ return rnPhoneticSize + 4 * rnFontCount;
+}
+
+sal_uInt32 BiffInputStream::readExtendedUniStringHeader( bool& rb16Bit, sal_uInt8 nFlags )
+{
+ bool bFonts, bPhonetic;
+ sal_uInt16 nFontCount;
+ sal_uInt32 nPhoneticSize;
+ return readExtendedUniStringHeader( rb16Bit, bFonts, bPhonetic, nFontCount, nPhoneticSize, nFlags );
+}
+
+OUString BiffInputStream::readRawUniString( sal_uInt16 nChars, bool b16Bit )
+{
+ ::std::vector< sal_Unicode > aCharVec;
+ aCharVec.reserve( nChars + 1 );
+
+ /* This function has to react on CONTINUE records to reads the repeated
+ flags field, so readUnicodeArray() cannot be used here. */
+ sal_uInt16 nCharsLeft = nChars;
+ while( isValid() && (nCharsLeft > 0) )
+ {
+ sal_uInt16 nPortionCount = 0;
+ if( b16Bit )
+ {
+ nPortionCount = ::std::min< sal_uInt16 >( nCharsLeft, maRecBuffer.getRecLeft() / 2 );
+ OSL_ENSURE( (nPortionCount <= nCharsLeft) || ((maRecBuffer.getRecLeft() & 1) == 0),
+ "BiffInputStream::readRawUniString - missing a byte" );
+ // read the character array
+ sal_uInt16 nReadChar;
+ for( sal_uInt16 nCharIdx = 0; isValid() && (nCharIdx < nPortionCount); ++nCharIdx )
+ {
+ readValue( nReadChar );
+ aCharVec.push_back( (nReadChar == 0) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar ) );
+ }
+ }
+ else
+ {
+ nPortionCount = getMaxRawReadSize( nCharsLeft );
+ // read the character array
+ sal_uInt8 nReadChar;
+ for( sal_uInt16 nCharIdx = 0; isValid() && (nCharIdx < nPortionCount); ++nCharIdx )
+ {
+ readValue( nReadChar );
+ aCharVec.push_back( (nReadChar == 0) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar ) );
+ }
+ }
+
+ // prepare for next CONTINUE record
+ nCharsLeft = nCharsLeft - nPortionCount;
+ if( nCharsLeft > 0 )
+ jumpToNextStringContinue( b16Bit );
+ }
+
+ // string may contain embedded NUL characters, do not create the OUString by length of vector
+ aCharVec.push_back( 0 );
+ return OUString( &aCharVec.front() );
+}
+
+OUString BiffInputStream::readUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
+{
+ bool b16Bit;
+ sal_uInt32 nExtSize = readExtendedUniStringHeader( b16Bit, nFlags );
+ OUString aStr = readRawUniString( nChars, b16Bit );
+ skip( nExtSize );
+ return aStr;
+}
+
+OUString BiffInputStream::readUniString( sal_uInt16 nChars )
+{
+ return readUniString( nChars, readuInt8() );
+}
+
+OUString BiffInputStream::readUniString()
+{
+ return readUniString( readuInt16() );
+}
+
+void BiffInputStream::skipRawUniString( sal_uInt16 nChars, bool b16Bit )
+{
+ sal_uInt16 nCharsLeft = nChars;
+ while( isValid() && (nCharsLeft > 0) )
+ {
+ sal_uInt16 nPortionCount;
+ if( b16Bit )
+ {
+ nPortionCount = ::std::min< sal_uInt16 >( nCharsLeft, maRecBuffer.getRecLeft() / 2 );
+ OSL_ENSURE( (nPortionCount <= nCharsLeft) || ((maRecBuffer.getRecLeft() & 1) == 0),
+ "BiffInputStream::skipRawUniString - missing a byte" );
+ skip( 2 * nPortionCount );
+ }
+ else
+ {
+ nPortionCount = getMaxRawReadSize( nCharsLeft );
+ skip( nPortionCount );
+ }
+
+ // prepare for next CONTINUE record
+ nCharsLeft = nCharsLeft - nPortionCount;
+ if( nCharsLeft > 0 )
+ jumpToNextStringContinue( b16Bit );
+ }
+}
+
+void BiffInputStream::skipUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
+{
+ bool b16Bit;
+ sal_uInt32 nExtSize = readExtendedUniStringHeader( b16Bit, nFlags );
+ skipRawUniString( nChars, b16Bit );
+ skip( nExtSize );
+}
+
+void BiffInputStream::skipUniString( sal_uInt16 nChars )
+{
+ skipUniString( nChars, readuInt8() );
+}
+
+void BiffInputStream::skipUniString()
+{
+ skipUniString( readuInt16() );
+}
+
+// private --------------------------------------------------------------------
+
+void BiffInputStream::setupRecord()
+{
+ // initialize class members
+ mnRecHandle = maRecBuffer.getRecHeaderPos();
+ mnRecId = maRecBuffer.getRecId();
+ mnAltContId = BIFF_ID_UNKNOWN;
+ mnCurrRecSize = mnComplRecSize = maRecBuffer.getRecSize();
+ mbHasComplRec = !mbCont;
+ mbValid = isInRecord();
+ setNulSubstChar( BIFF_DEF_NUL_SUBST_CHAR );
+ // enable decoder in new record
+ enableDecoder( true );
+}
+
+void BiffInputStream::restartRecord( bool bInvalidateRecSize )
+{
+ if( isInRecord() )
+ {
+ maRecBuffer.startRecord( getRecHandle() );
+ mnCurrRecSize = maRecBuffer.getRecSize();
+ if( bInvalidateRecSize )
+ {
+ mnComplRecSize = mnCurrRecSize;
+ mbHasComplRec = !mbCont;
+ }
+ mbValid = true;
+ }
+}
+
+void BiffInputStream::rewindToRecord( sal_Int64 nRecHandle )
+{
+ if( nRecHandle >= 0 )
+ {
+ maRecBuffer.restartAt( nRecHandle );
+ mnRecHandle = -1;
+ mbValid = false;
+ }
+}
+
+bool BiffInputStream::isContinueId( sal_uInt16 nRecId ) const
+{
+ return (nRecId == BIFF_ID_CONT) || (nRecId == mnAltContId);
+}
+
+bool BiffInputStream::jumpToNextContinue()
+{
+ mbValid = mbValid && mbCont && isContinueId( maRecBuffer.getNextRecId() ) && maRecBuffer.startNextRecord();
+ if( mbValid )
+ mnCurrRecSize += maRecBuffer.getRecSize();
+ return mbValid;
+}
+
+bool BiffInputStream::jumpToNextStringContinue( bool& rb16Bit )
+{
+ OSL_ENSURE( maRecBuffer.getRecLeft() == 0, "BiffInputStream::jumpToNextStringContinue - unexpected garbage" );
+
+ if( mbCont && (getRecLeft() > 0) )
+ {
+ jumpToNextContinue();
+ }
+ else if( mnRecId == BIFF_ID_CONT )
+ {
+ /* CONTINUE handling is off, but we have started reading in a CONTINUE
+ record -> start next CONTINUE for TXO import. We really start a new
+ record here - no chance to return to string origin. */
+ mbValid = mbValid && (maRecBuffer.getNextRecId() == BIFF_ID_CONT) && maRecBuffer.startNextRecord();
+ if( mbValid )
+ setupRecord();
+ }
+
+ // trying to read the flags invalidates stream, if no CONTINUE record has been found
+ sal_uInt8 nFlags;
+ readValue( nFlags );
+ rb16Bit = getFlag( nFlags, BIFF_STRF_16BIT );
+ return mbValid;
+}
+
+bool BiffInputStream::ensureRawReadSize( sal_uInt16 nBytes )
+{
+ if( mbValid && (nBytes > 0) )
+ {
+ while( mbValid && (maRecBuffer.getRecLeft() == 0) ) jumpToNextContinue();
+ mbValid = mbValid && (nBytes <= maRecBuffer.getRecLeft());
+ OSL_ENSURE( mbValid, "BiffInputStream::ensureRawReadSize - record overread" );
+ }
+ return mbValid;
+}
+
+sal_uInt16 BiffInputStream::getMaxRawReadSize( sal_uInt32 nBytes ) const
+{
+ return static_cast< sal_uInt16 >( ::std::min< sal_uInt32 >( nBytes, maRecBuffer.getRecLeft() ) );
+}
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/biffoutputstream.cxx b/oox/source/xls/biffoutputstream.cxx
new file mode 100644
index 000000000000..570b145931ce
--- /dev/null
+++ b/oox/source/xls/biffoutputstream.cxx
@@ -0,0 +1,191 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: biffoutputstream.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffoutputstream.hxx"
+#include "oox/helper/binaryoutputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace prv {
+
+BiffOutputRecordBuffer::BiffOutputRecordBuffer( BinaryOutputStream& rOutStrm, sal_uInt16 nMaxRecSize ) :
+ mrOutStrm( rOutStrm ),
+ mnMaxRecSize( nMaxRecSize ),
+ mnRecId( BIFF_ID_UNKNOWN ),
+ mbInRec( false )
+{
+ OSL_ENSURE( mrOutStrm.isSeekable(), "BiffOutputRecordBuffer::BiffOutputRecordBuffer - stream must be seekable" );
+ maData.reserve( SAL_MAX_UINT16 );
+}
+
+void BiffOutputRecordBuffer::startRecord( sal_uInt16 nRecId )
+{
+ OSL_ENSURE( !mbInRec, "BiffOutputRecordBuffer::startRecord - another record still open" );
+ mnRecId = nRecId;
+ maData.clear();
+ mbInRec = true;
+}
+
+void BiffOutputRecordBuffer::endRecord()
+{
+ OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::endRecord - no record open" );
+ sal_uInt16 nRecSize = getLimitedValue< sal_uInt16, size_t >( maData.size(), 0, SAL_MAX_UINT16 );
+ mrOutStrm.seekToEnd();
+ mrOutStrm << mnRecId << nRecSize;
+ if( nRecSize > 0 )
+ mrOutStrm.write( &maData.front(), nRecSize );
+ mbInRec = false;
+}
+
+void BiffOutputRecordBuffer::write( const void* pData, sal_uInt16 nBytes )
+{
+ OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::write - no record open" );
+ OSL_ENSURE( nBytes > 0, "BiffOutputRecordBuffer::write - nothing to write" );
+ OSL_ENSURE( nBytes <= getRecLeft(), "BiffOutputRecordBuffer::write - buffer overflow" );
+ maData.resize( maData.size() + nBytes );
+ memcpy( &*(maData.end() - nBytes), pData, nBytes );
+}
+
+void BiffOutputRecordBuffer::fill( sal_uInt8 nValue, sal_uInt16 nBytes )
+{
+ OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::write - no record open" );
+ OSL_ENSURE( nBytes > 0, "BiffOutputRecordBuffer::write - nothing to write" );
+ OSL_ENSURE( nBytes <= getRecLeft(), "BiffOutputRecordBuffer::write - buffer overflow" );
+ maData.resize( maData.size() + nBytes, nValue );
+}
+
+} // namespace prv
+
+// ============================================================================
+
+BiffOutputStream::BiffOutputStream( BinaryOutputStream& rOutStream, sal_uInt16 nMaxRecSize ) :
+ maRecBuffer( rOutStream, nMaxRecSize ),
+ mnPortionSize( 0 ),
+ mnPortionPos( 0 )
+{
+}
+
+BiffOutputStream::~BiffOutputStream()
+{
+}
+
+// record control -------------------------------------------------------------
+
+void BiffOutputStream::startRecord( sal_uInt16 nRecId )
+{
+ maRecBuffer.startRecord( nRecId );
+ setPortionSize( 0 );
+}
+
+void BiffOutputStream::endRecord()
+{
+ maRecBuffer.endRecord();
+}
+
+void BiffOutputStream::setPortionSize( sal_uInt16 nSize )
+{
+ mnPortionSize = nSize;
+ mnPortionPos = 0;
+}
+
+// stream/record state and info -----------------------------------------------
+
+// stream write access --------------------------------------------------------
+
+void BiffOutputStream::write( const void* pData, sal_uInt32 nBytes )
+{
+ if( pData && (nBytes > 0) )
+ {
+ const sal_uInt8* pnBuffer = reinterpret_cast< const sal_uInt8* >( pData );
+ sal_uInt32 nBytesLeft = nBytes;
+ while( nBytesLeft > 0 )
+ {
+ sal_uInt16 nBlockSize = prepareRawBlock( nBytesLeft );
+ maRecBuffer.write( pnBuffer, nBlockSize );
+ pnBuffer += nBlockSize;
+ nBytesLeft -= nBlockSize;
+ }
+ }
+}
+
+void BiffOutputStream::fill( sal_uInt8 nValue, sal_uInt32 nBytes )
+{
+ sal_uInt32 nBytesLeft = nBytes;
+ while( nBytesLeft > 0 )
+ {
+ sal_uInt16 nBlockSize = prepareRawBlock( nBytesLeft );
+ maRecBuffer.fill( nValue, nBlockSize );
+ nBytesLeft -= nBlockSize;
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void BiffOutputStream::ensureRawBlock( sal_uInt16 nSize )
+{
+ if( (maRecBuffer.getRecLeft() < nSize) ||
+ ((mnPortionSize > 0) && (mnPortionPos == 0) && (maRecBuffer.getRecLeft() < mnPortionSize)) )
+ {
+ maRecBuffer.endRecord();
+ maRecBuffer.startRecord( BIFF_ID_CONT );
+ }
+ if( mnPortionSize > 0 )
+ {
+ OSL_ENSURE( mnPortionPos + nSize <= mnPortionSize, "BiffOutputStreamI::ensureRawBlock - portion overflow" );
+ mnPortionPos = (mnPortionPos + nSize) % mnPortionSize; // prevent compiler warning, do not use operator+=, operator%=
+ }
+}
+
+sal_uInt16 BiffOutputStream::prepareRawBlock( sal_uInt32 nTotalSize )
+{
+ sal_uInt16 nRecLeft = maRecBuffer.getRecLeft();
+ if( mnPortionSize > 0 )
+ {
+ OSL_ENSURE( mnPortionPos == 0, "BiffOutputStream::prepareRawBlock - block operation inside portion" );
+ OSL_ENSURE( nTotalSize % mnPortionSize == 0, "BiffOutputStream::prepareRawBlock - portion size does not match block size" );
+ nRecLeft = (nRecLeft / mnPortionSize) * mnPortionSize;
+ }
+ sal_uInt16 nSize = getLimitedValue< sal_uInt16, sal_uInt32 >( nTotalSize, 0, nRecLeft );
+ ensureRawBlock( nSize );
+ return nSize;
+}
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/condformatbuffer.cxx b/oox/source/xls/condformatbuffer.cxx
new file mode 100644
index 000000000000..f22910846d6c
--- /dev/null
+++ b/oox/source/xls/condformatbuffer.cxx
@@ -0,0 +1,782 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: condformatbuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/condformatbuffer.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/sheet/ConditionOperator.hpp>
+#include <com/sun/star/sheet/XSheetConditionalEntries.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheets.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/validationpropertyhelper.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::beans::PropertyValue;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::style::XStyleFamiliesSupplier;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameContainer;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::ConditionOperator;
+using ::com::sun::star::table::XCellRange;
+using ::com::sun::star::sheet::XSheetCellRanges;
+using ::com::sun::star::sheet::XSheetConditionalEntries;
+using ::com::sun::star::sheet::XSpreadsheetDocument;
+using ::com::sun::star::sheet::XSpreadsheets;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::style::XStyle;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 OOBIN_CFRULE_TYPE_CELLIS = 1;
+const sal_Int32 OOBIN_CFRULE_TYPE_EXPRESSION = 2;
+const sal_Int32 OOBIN_CFRULE_TYPE_COLORSCALE = 3;
+const sal_Int32 OOBIN_CFRULE_TYPE_DATABAR = 4;
+const sal_Int32 OOBIN_CFRULE_TYPE_TOPTEN = 5;
+const sal_Int32 OOBIN_CFRULE_TYPE_ICONSET = 6;
+
+const sal_Int32 OOBIN_CFRULE_SUB_CELLIS = 0;
+const sal_Int32 OOBIN_CFRULE_SUB_EXPRESSION = 1;
+const sal_Int32 OOBIN_CFRULE_SUB_COLORSCALE = 2;
+const sal_Int32 OOBIN_CFRULE_SUB_DATABAR = 3;
+const sal_Int32 OOBIN_CFRULE_SUB_ICONSET = 4;
+const sal_Int32 OOBIN_CFRULE_SUB_TOPTEN = 5;
+const sal_Int32 OOBIN_CFRULE_SUB_UNIQUE = 7;
+const sal_Int32 OOBIN_CFRULE_SUB_TEXT = 8;
+const sal_Int32 OOBIN_CFRULE_SUB_BLANK = 9;
+const sal_Int32 OOBIN_CFRULE_SUB_NOTBLANK = 10;
+const sal_Int32 OOBIN_CFRULE_SUB_ERROR = 11;
+const sal_Int32 OOBIN_CFRULE_SUB_NOTERROR = 12;
+const sal_Int32 OOBIN_CFRULE_SUB_TODAY = 15;
+const sal_Int32 OOBIN_CFRULE_SUB_TOMORROW = 16;
+const sal_Int32 OOBIN_CFRULE_SUB_YESTERDAY = 17;
+const sal_Int32 OOBIN_CFRULE_SUB_LAST7DAYS = 18;
+const sal_Int32 OOBIN_CFRULE_SUB_LASTMONTH = 19;
+const sal_Int32 OOBIN_CFRULE_SUB_NEXTMONTH = 20;
+const sal_Int32 OOBIN_CFRULE_SUB_THISWEEK = 21;
+const sal_Int32 OOBIN_CFRULE_SUB_NEXTWEEK = 22;
+const sal_Int32 OOBIN_CFRULE_SUB_LASTWEEK = 23;
+const sal_Int32 OOBIN_CFRULE_SUB_THISMONTH = 24;
+const sal_Int32 OOBIN_CFRULE_SUB_ABOVEAVERAGE = 25;
+const sal_Int32 OOBIN_CFRULE_SUB_BELOWAVERAGE = 26;
+const sal_Int32 OOBIN_CFRULE_SUB_DUPLICATE = 27;
+const sal_Int32 OOBIN_CFRULE_SUB_EQABOVEAVERAGE = 29;
+const sal_Int32 OOBIN_CFRULE_SUB_EQBELOWAVERAGE = 30;
+
+const sal_Int32 OOBIN_CFRULE_TIMEOP_TODAY = 0;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_YESTERDAY = 1;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_LAST7DAYS = 2;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_THISWEEK = 3;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_LASTWEEK = 4;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_LASTMONTH = 5;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_TOMORROW = 6;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_NEXTWEEK = 7;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_NEXTMONTH = 8;
+const sal_Int32 OOBIN_CFRULE_TIMEOP_THISMONTH = 9;
+
+const sal_uInt16 OOBIN_CFRULE_STOPIFTRUE = 0x0002;
+const sal_uInt16 OOBIN_CFRULE_ABOVEAVERAGE = 0x0004;
+const sal_uInt16 OOBIN_CFRULE_BOTTOM = 0x0008;
+const sal_uInt16 OOBIN_CFRULE_PERCENT = 0x0010;
+
+// ----------------------------------------------------------------------------
+
+template< typename Type >
+void lclAppendProperty( ::std::vector< PropertyValue >& orProps, const OUString& rPropName, const Type& rValue )
+{
+ orProps.push_back( PropertyValue() );
+ orProps.back().Name = rPropName;
+ orProps.back().Value <<= rValue;
+}
+
+} // namespace
+
+// ============================================================================
+
+OoxCondFormatRuleData::OoxCondFormatRuleData() :
+ mnPriority( -1 ),
+ mnType( XML_TOKEN_INVALID ),
+ mnOperator( XML_TOKEN_INVALID ),
+ mnTimePeriod( XML_TOKEN_INVALID ),
+ mnRank( 0 ),
+ mnStdDev( 0 ),
+ mnDxfId( -1 ),
+ mbStopIfTrue( false ),
+ mbBottom( false ),
+ mbPercent( false ),
+ mbAboveAverage( true ),
+ mbEqualAverage( false )
+{
+}
+
+void OoxCondFormatRuleData::setBinOperator( sal_Int32 nOperator )
+{
+ static const sal_Int32 spnOperators[] = {
+ XML_TOKEN_INVALID, XML_between, XML_notBetween, XML_equal, XML_notEqual,
+ XML_greaterThan, XML_lessThan, XML_greaterThanOrEqual, XML_lessThanOrEqual };
+ mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
+}
+
+void OoxCondFormatRuleData::setOobTextType( sal_Int32 nOperator )
+{
+ // note: type XML_notContainsText vs. operator XML_notContains
+ static const sal_Int32 spnTypes[] = { XML_containsText, XML_notContainsText, XML_beginsWith, XML_endsWith };
+ mnType = STATIC_ARRAY_SELECT( spnTypes, nOperator, XML_TOKEN_INVALID );
+ static const sal_Int32 spnOperators[] = { XML_containsText, XML_notContains, XML_beginsWith, XML_endsWith };
+ mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
+}
+
+// ============================================================================
+
+CondFormatRule::CondFormatRule( const CondFormat& rCondFormat ) :
+ WorksheetHelper( rCondFormat ),
+ mrCondFormat( rCondFormat )
+{
+}
+
+void CondFormatRule::importCfRule( const AttributeList& rAttribs )
+{
+ maOoxData.maText = rAttribs.getString( XML_text );
+ maOoxData.mnPriority = rAttribs.getInteger( XML_priority, -1 );
+ maOoxData.mnType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
+ maOoxData.mnOperator = rAttribs.getToken( XML_operator, XML_TOKEN_INVALID );
+ maOoxData.mnTimePeriod = rAttribs.getToken( XML_timePeriod, XML_TOKEN_INVALID );
+ maOoxData.mnRank = rAttribs.getInteger( XML_rank, 0 );
+ maOoxData.mnStdDev = rAttribs.getInteger( XML_stdDev, 0 );
+ maOoxData.mnDxfId = rAttribs.getInteger( XML_dxfId, -1 );
+ maOoxData.mbStopIfTrue = rAttribs.getBool( XML_stopIfTrue, false );
+ maOoxData.mbBottom = rAttribs.getBool( XML_bottom, false );
+ maOoxData.mbPercent = rAttribs.getBool( XML_percent, false );
+ maOoxData.mbAboveAverage = rAttribs.getBool( XML_aboveAverage, true );
+ maOoxData.mbEqualAverage = rAttribs.getBool( XML_equalAverage, false );
+}
+
+void CondFormatRule::appendFormula( const OUString& rFormula )
+{
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( mrCondFormat.getRanges().getBaseAddress() );
+ getFormulaParser().importFormula( aContext, rFormula );
+ maOoxData.maFormulas.push_back( aContext );
+}
+
+void CondFormatRule::importCfRule( RecordInputStream& rStrm )
+{
+ sal_Int32 nType, nSubType, nOperator, nFmla1Size, nFmla2Size, nFmla3Size;
+ sal_uInt16 nFlags;
+ rStrm >> nType >> nSubType >> maOoxData.mnDxfId >> maOoxData.mnPriority >> nOperator;
+ rStrm.skip( 8 );
+ rStrm >> nFlags >> nFmla1Size >> nFmla2Size >> nFmla3Size >> maOoxData.maText;
+
+ /* Import the formulas. For no obvious reason, the sizes of the formulas
+ are already stored before. Nevertheless the following formulas contain
+ their own sizes. */
+
+ // first formula
+ OSL_ENSURE( (nFmla1Size >= 0) || ((nFmla2Size == 0) && (nFmla3Size == 0)), "CondFormatRule::importCfRule - missing first formula" );
+ OSL_ENSURE( (nFmla1Size > 0) == (rStrm.getRecLeft() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
+ if( rStrm.getRecLeft() >= 8 )
+ {
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( mrCondFormat.getRanges().getBaseAddress() );
+ getFormulaParser().importFormula( aContext, rStrm );
+ maOoxData.maFormulas.push_back( aContext );
+
+ // second formula
+ OSL_ENSURE( (nFmla2Size >= 0) || (nFmla3Size == 0), "CondFormatRule::importCfRule - missing second formula" );
+ OSL_ENSURE( (nFmla2Size > 0) == (rStrm.getRecLeft() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
+ if( rStrm.getRecLeft() >= 8 )
+ {
+ getFormulaParser().importFormula( aContext, rStrm );
+ maOoxData.maFormulas.push_back( aContext );
+
+ // third formula
+ OSL_ENSURE( (nFmla3Size > 0) == (rStrm.getRecLeft() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
+ if( rStrm.getRecLeft() >= 8 )
+ {
+ getFormulaParser().importFormula( aContext, rStrm );
+ maOoxData.maFormulas.push_back( aContext );
+ }
+ }
+ }
+
+ // flags
+ maOoxData.mbStopIfTrue = getFlag( nFlags, OOBIN_CFRULE_STOPIFTRUE );
+ maOoxData.mbBottom = getFlag( nFlags, OOBIN_CFRULE_BOTTOM );
+ maOoxData.mbPercent = getFlag( nFlags, OOBIN_CFRULE_PERCENT );
+ maOoxData.mbAboveAverage = getFlag( nFlags, OOBIN_CFRULE_ABOVEAVERAGE );
+ // no flag for equalAverage, must be determined from subtype below...
+
+ // Convert the type/operator settings. This is a real mess...
+ switch( nType )
+ {
+ case OOBIN_CFRULE_TYPE_CELLIS:
+ OSL_ENSURE( nSubType == OOBIN_CFRULE_SUB_CELLIS, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+ maOoxData.mnType = XML_cellIs;
+ maOoxData.setBinOperator( nOperator );
+ OSL_ENSURE( maOoxData.mnOperator != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unknown operator" );
+ break;
+ case OOBIN_CFRULE_TYPE_EXPRESSION:
+ // here we have to look at the subtype to find the real type...
+ switch( nSubType )
+ {
+ case OOBIN_CFRULE_SUB_EXPRESSION:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_expression;
+ break;
+ case OOBIN_CFRULE_SUB_UNIQUE:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_uniqueValues;
+ break;
+ case OOBIN_CFRULE_SUB_TEXT:
+ maOoxData.setOobTextType( nOperator );
+ OSL_ENSURE( maOoxData.mnType != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unexpected operator value" );
+ break;
+ case OOBIN_CFRULE_SUB_BLANK:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_containsBlanks;
+ break;
+ case OOBIN_CFRULE_SUB_NOTBLANK:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_notContainsBlanks;
+ break;
+ case OOBIN_CFRULE_SUB_ERROR:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_containsErrors;
+ break;
+ case OOBIN_CFRULE_SUB_NOTERROR:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_notContainsErrors;
+ break;
+ case OOBIN_CFRULE_SUB_TODAY:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_TODAY, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_today;
+ break;
+ case OOBIN_CFRULE_SUB_TOMORROW:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_TOMORROW, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_tomorrow;
+ break;
+ case OOBIN_CFRULE_SUB_YESTERDAY:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_YESTERDAY, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_yesterday;
+ break;
+ case OOBIN_CFRULE_SUB_LAST7DAYS:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_LAST7DAYS, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_last7Days;
+ break;
+ case OOBIN_CFRULE_SUB_LASTMONTH:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_LASTMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_lastMonth;
+ break;
+ case OOBIN_CFRULE_SUB_NEXTMONTH:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_NEXTMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_nextMonth;
+ break;
+ case OOBIN_CFRULE_SUB_THISWEEK:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_THISWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_thisWeek;
+ break;
+ case OOBIN_CFRULE_SUB_NEXTWEEK:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_NEXTWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_nextWeek;
+ break;
+ case OOBIN_CFRULE_SUB_LASTWEEK:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_LASTWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_lastWeek;
+ break;
+ case OOBIN_CFRULE_SUB_THISMONTH:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_THISMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maOoxData.mnType = XML_timePeriod;
+ maOoxData.mnTimePeriod = XML_thisMonth;
+ break;
+ case OOBIN_CFRULE_SUB_ABOVEAVERAGE:
+ OSL_ENSURE( maOoxData.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
+ maOoxData.mnType = XML_aboveAverage;
+ maOoxData.mnStdDev = nOperator; // operator field used for standard deviation
+ maOoxData.mbAboveAverage = true;
+ maOoxData.mbEqualAverage = false; // does not exist as real flag...
+ break;
+ case OOBIN_CFRULE_SUB_BELOWAVERAGE:
+ OSL_ENSURE( !maOoxData.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
+ maOoxData.mnType = XML_aboveAverage;
+ maOoxData.mnStdDev = nOperator; // operator field used for standard deviation
+ maOoxData.mbAboveAverage = false;
+ maOoxData.mbEqualAverage = false; // does not exist as real flag...
+ break;
+ case OOBIN_CFRULE_SUB_DUPLICATE:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_duplicateValues;
+ break;
+ case OOBIN_CFRULE_SUB_EQABOVEAVERAGE:
+ OSL_ENSURE( maOoxData.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
+ maOoxData.mnType = XML_aboveAverage;
+ maOoxData.mnStdDev = nOperator; // operator field used for standard deviation
+ maOoxData.mbAboveAverage = true;
+ maOoxData.mbEqualAverage = true; // does not exist as real flag...
+ break;
+ case OOBIN_CFRULE_SUB_EQBELOWAVERAGE:
+ OSL_ENSURE( !maOoxData.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
+ maOoxData.mnType = XML_aboveAverage;
+ maOoxData.mnStdDev = nOperator; // operator field used for standard deviation
+ maOoxData.mbAboveAverage = false;
+ maOoxData.mbEqualAverage = true; // does not exist as real flag...
+ break;
+ }
+ break;
+ case OOBIN_CFRULE_TYPE_COLORSCALE:
+ OSL_ENSURE( nSubType == OOBIN_CFRULE_SUB_COLORSCALE, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_colorScale;
+ break;
+ case OOBIN_CFRULE_TYPE_DATABAR:
+ OSL_ENSURE( nSubType == OOBIN_CFRULE_SUB_DATABAR, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_dataBar;
+ break;
+ case OOBIN_CFRULE_TYPE_TOPTEN:
+ OSL_ENSURE( nSubType == OOBIN_CFRULE_SUB_TOPTEN, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+ maOoxData.mnType = XML_top10;
+ maOoxData.mnRank = nOperator; // operator field used for rank value
+ break;
+ case OOBIN_CFRULE_TYPE_ICONSET:
+ OSL_ENSURE( nSubType == OOBIN_CFRULE_SUB_ICONSET, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maOoxData.mnType = XML_iconSet;
+ break;
+ default:
+ OSL_ENSURE( false, "CondFormatRule::importCfRule - unknown rule type" );
+ }
+}
+
+void CondFormatRule::importCfRule( BiffInputStream& rStrm, sal_Int32 nPriority )
+{
+ sal_uInt8 nType, nOperator;
+ sal_uInt16 nFmla1Size, nFmla2Size;
+ sal_uInt32 nFlags;
+ rStrm >> nType >> nOperator >> nFmla1Size >> nFmla2Size >> nFlags;
+ rStrm.skip( 2 );
+
+ static const sal_Int32 spnTypeIds[] = { XML_TOKEN_INVALID, XML_cellIs, XML_expression };
+ maOoxData.mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_TOKEN_INVALID );
+
+ maOoxData.setBinOperator( nOperator );
+ maOoxData.mnPriority = nPriority;
+ maOoxData.mbStopIfTrue = true;
+
+ DxfRef xDxf = getStyles().createDxf( &maOoxData.mnDxfId );
+ xDxf->importCfRule( rStrm, nFlags );
+ xDxf->finalizeImport();
+
+ // import the formulas
+ OSL_ENSURE( (nFmla1Size > 0) || (nFmla2Size == 0), "CondFormatRule::importCfRule - missing first formula" );
+ if( nFmla1Size > 0 )
+ {
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( mrCondFormat.getRanges().getBaseAddress() );
+ getFormulaParser().importFormula( aContext, rStrm, &nFmla1Size );
+ maOoxData.maFormulas.push_back( aContext );
+ if( nFmla2Size > 0 )
+ {
+ getFormulaParser().importFormula( aContext, rStrm, &nFmla2Size );
+ maOoxData.maFormulas.push_back( aContext );
+ }
+ }
+}
+
+void CondFormatRule::finalizeImport( const Reference< XSheetConditionalEntries >& rxEntries )
+{
+ ConditionOperator eOperator = ::com::sun::star::sheet::ConditionOperator_NONE;
+
+ /* Replacement formula for unsupported rule types (text comparison rules,
+ time period rules, cell type rules). The replacement formulas below may
+ contain several placeholders:
+ - '#B' will be replaced by the current base address (may occur
+ several times).
+ - '#R' will be replaced by the entire range list of the conditional
+ formatting (absolute addresses).
+ - '#T' will be replaced by the quoted comparison text.
+ - '#L' will be replaced by the length of the comparison text (from
+ the 'text' attribute) used in text comparison rules.
+ - '#K' will be replaced by the rank (from the 'rank' attribute) used in
+ top-10 rules.
+ - '#M' will be replaced by the top/bottom flag (from the 'bottom'
+ attribute) used in the RANK function in top-10 rules.
+ */
+ OUString aReplaceFormula;
+
+ switch( maOoxData.mnType )
+ {
+ case XML_cellIs:
+ eOperator = ValidationPropertyHelper::convertToApiOperator( maOoxData.mnOperator );
+ break;
+ case XML_expression:
+ eOperator = ::com::sun::star::sheet::ConditionOperator_FORMULA;
+ break;
+ case XML_containsText:
+ OSL_ENSURE( maOoxData.mnOperator == XML_containsText, "CondFormatRule::finalizeImport - unexpected operator" );
+ aReplaceFormula = CREATE_OUSTRING( "NOT(ISERROR(SEARCH(#T,#B)))" );
+ break;
+ case XML_notContainsText:
+ // note: type XML_notContainsText vs. operator XML_notContains
+ OSL_ENSURE( maOoxData.mnOperator == XML_notContains, "CondFormatRule::finalizeImport - unexpected operator" );
+ aReplaceFormula = CREATE_OUSTRING( "ISERROR(SEARCH(#T,#B))" );
+ break;
+ case XML_beginsWith:
+ OSL_ENSURE( maOoxData.mnOperator == XML_beginsWith, "CondFormatRule::finalizeImport - unexpected operator" );
+ aReplaceFormula = CREATE_OUSTRING( "LEFT(#B,#L)=#T" );
+ break;
+ case XML_endsWith:
+ OSL_ENSURE( maOoxData.mnOperator == XML_endsWith, "CondFormatRule::finalizeImport - unexpected operator" );
+ aReplaceFormula = CREATE_OUSTRING( "RIGHT(#B,#L)=#T" );
+ break;
+ case XML_timePeriod:
+ switch( maOoxData.mnTimePeriod )
+ {
+ case XML_yesterday:
+ aReplaceFormula = CREATE_OUSTRING( "FLOOR(#B,1)=TODAY()-1" );
+ break;
+ case XML_today:
+ aReplaceFormula = CREATE_OUSTRING( "FLOOR(#B,1)=TODAY()" );
+ break;
+ case XML_tomorrow:
+ aReplaceFormula = CREATE_OUSTRING( "FLOOR(#B,1)=TODAY()+1" );
+ break;
+ case XML_last7Days:
+ aReplaceFormula = CREATE_OUSTRING( "AND(TODAY()-7<FLOOR(#B,1),FLOOR(#B,1)<=TODAY())" );
+ break;
+ case XML_lastWeek:
+ aReplaceFormula = CREATE_OUSTRING( "AND(TODAY()-WEEKDAY(TODAY())-7<FLOOR(#B,1),FLOOR(#B,1)<=TODAY()-WEEKDAY(TODAY()))" );
+ break;
+ case XML_thisWeek:
+ aReplaceFormula = CREATE_OUSTRING( "AND(TODAY()-WEEKDAY(TODAY())<FLOOR(#B,1),FLOOR(#B,1)<=TODAY()-WEEKDAY(TODAY())+7)" );
+ break;
+ case XML_nextWeek:
+ aReplaceFormula = CREATE_OUSTRING( "AND(TODAY()-WEEKDAY(TODAY())+7<FLOOR(#B,1),FLOOR(#B,1)<=TODAY()-WEEKDAY(TODAY())+14)" );
+ break;
+ case XML_lastMonth:
+ aReplaceFormula = CREATE_OUSTRING( "OR(AND(MONTH(#B)=MONTH(TODAY())-1,YEAR(#B)=YEAR(TODAY())),AND(MONTH(#B)=12,MONTH(TODAY())=1,YEAR(#B)=YEAR(TODAY())-1))" );
+ break;
+ case XML_thisMonth:
+ aReplaceFormula = CREATE_OUSTRING( "AND(MONTH(#B)=MONTH(TODAY()),YEAR(#B)=YEAR(TODAY()))" );
+ break;
+ case XML_nextMonth:
+ aReplaceFormula = CREATE_OUSTRING( "OR(AND(MONTH(#B)=MONTH(TODAY())+1,YEAR(#B)=YEAR(TODAY())),AND(MONTH(#B)=1,MONTH(TODAY())=12,YEAR(#B)=YEAR(TODAY())+1))" );
+ break;
+ default:
+ OSL_ENSURE( false, "CondFormatRule::finalizeImport - unknown time period type" );
+ }
+ break;
+ case XML_containsBlanks:
+ aReplaceFormula = CREATE_OUSTRING( "LEN(TRIM(#B))=0" );
+ break;
+ case XML_notContainsBlanks:
+ aReplaceFormula = CREATE_OUSTRING( "LEN(TRIM(#B))>0" );
+ break;
+ case XML_containsErrors:
+ aReplaceFormula = CREATE_OUSTRING( "ISERROR(#B)" );
+ break;
+ case XML_notContainsErrors:
+ aReplaceFormula = CREATE_OUSTRING( "NOT(ISERROR(#B))" );
+ break;
+ case XML_top10:
+ if( maOoxData.mbPercent )
+ aReplaceFormula = CREATE_OUSTRING( "RANK(#B,#R,#M)/COUNT(#R)<=#K%" );
+ else
+ aReplaceFormula = CREATE_OUSTRING( "RANK(#B,#R,#M)<=#K" );
+ break;
+ case XML_aboveAverage:
+ if( maOoxData.mnStdDev == 0 )
+ {
+ if( maOoxData.mbAboveAverage )
+ aReplaceFormula = maOoxData.mbEqualAverage ? CREATE_OUSTRING( "#B>=AVERAGE(#R)" ) : CREATE_OUSTRING( "#B>AVERAGE(#R)" );
+ else
+ aReplaceFormula = maOoxData.mbEqualAverage ? CREATE_OUSTRING( "#B<=AVERAGE(#R)" ) : CREATE_OUSTRING( "#B<AVERAGE(#R)" );
+ }
+ break;
+ }
+
+ if( aReplaceFormula.getLength() > 0 )
+ {
+ OUString aAddress, aRanges, aText;
+ sal_Int32 nStrPos = aReplaceFormula.getLength();
+ while( (nStrPos = aReplaceFormula.lastIndexOf( '#', nStrPos )) >= 0 )
+ {
+ switch( aReplaceFormula[ nStrPos + 1 ] )
+ {
+ case 'B': // current base address
+ if( aAddress.getLength() == 0 )
+ aAddress = FormulaProcessorBase::generateAddress2dString( mrCondFormat.getRanges().getBaseAddress(), false );
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aAddress );
+ break;
+ case 'R': // range list of conditional formatting
+ if( aRanges.getLength() == 0 )
+ aRanges = FormulaProcessorBase::generateRangeList2dString( mrCondFormat.getRanges(), true, ',', true );
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aRanges );
+ break;
+ case 'T': // comparison text
+ if( aText.getLength() == 0 )
+ {
+ // handle quote characters in comparison text
+ aText = maOoxData.maText;
+ sal_Int32 nQuotePos = aText.getLength();
+ while( (nQuotePos = aText.lastIndexOf( '"', nQuotePos )) >= 0 )
+ aText = aText.replaceAt( nQuotePos, 1, CREATE_OUSTRING( "\"\"" ) );
+ aText = OUStringBuffer().append( sal_Unicode( '"' ) ).append( aText ).append( sal_Unicode( '"' ) ).makeStringAndClear();
+ }
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aText );
+ break;
+ case 'L': // length of comparison text
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2,
+ OUString::valueOf( maOoxData.maText.getLength() ) );
+ break;
+ case 'K': // top-10 rank
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2,
+ OUString::valueOf( maOoxData.mnRank ) );
+ break;
+ case 'M': // top-10 top/bottom flag
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2,
+ OUString::valueOf( static_cast< sal_Int32 >( maOoxData.mbBottom ? 1 : 0 ) ) );
+ break;
+ default:
+ OSL_ENSURE( false, "CondFormatRule::finalizeImport - unknown placeholder" );
+ }
+ }
+
+ // set the replacement formula
+ maOoxData.maFormulas.clear();
+ appendFormula( aReplaceFormula );
+ eOperator = ::com::sun::star::sheet::ConditionOperator_FORMULA;
+ }
+
+ if( rxEntries.is() && (eOperator != ::com::sun::star::sheet::ConditionOperator_NONE) && !maOoxData.maFormulas.empty() )
+ {
+ ::std::vector< PropertyValue > aProps;
+ // create condition properties
+ lclAppendProperty( aProps, CREATE_OUSTRING( "Operator" ), eOperator );
+ lclAppendProperty( aProps, CREATE_OUSTRING( "Formula1" ), maOoxData.maFormulas[ 0 ].getTokens() );
+ if( maOoxData.maFormulas.size() >= 2 )
+ lclAppendProperty( aProps, CREATE_OUSTRING( "Formula2" ), maOoxData.maFormulas[ 1 ].getTokens() );
+
+ // style name for the formatting attributes
+ OUString aStyleName = getStyles().createDxfStyle( maOoxData.mnDxfId );
+ if( aStyleName.getLength() > 0 )
+ lclAppendProperty( aProps, CREATE_OUSTRING( "StyleName" ), aStyleName );
+
+ // append the new rule
+ try
+ {
+ rxEntries->addNew( ContainerHelper::vectorToSequence( aProps ) );
+ }
+ catch( Exception& )
+ {
+ }
+ }
+}
+
+// ============================================================================
+
+OoxCondFormatData::OoxCondFormatData() :
+ mbPivot( false )
+{
+}
+
+// ============================================================================
+
+CondFormat::CondFormat( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+void CondFormat::importConditionalFormatting( const AttributeList& rAttribs )
+{
+ getAddressConverter().convertToCellRangeList( maOoxData.maRanges, rAttribs.getString( XML_sqref ), getSheetIndex(), true );
+ maOoxData.mbPivot = rAttribs.getBool( XML_pivot, false );
+}
+
+CondFormatRuleRef CondFormat::importCfRule( const AttributeList& rAttribs )
+{
+ CondFormatRuleRef xRule = createRule();
+ xRule->importCfRule( rAttribs );
+ insertRule( xRule );
+ return xRule;
+}
+
+void CondFormat::importCondFormatting( RecordInputStream& rStrm )
+{
+ BinRangeList aRanges;
+ rStrm.skip( 8 );
+ rStrm >> aRanges;
+ getAddressConverter().convertToCellRangeList( maOoxData.maRanges, aRanges, getSheetIndex(), true );
+}
+
+void CondFormat::importCfRule( RecordInputStream& rStrm )
+{
+ CondFormatRuleRef xRule = createRule();
+ xRule->importCfRule( rStrm );
+ insertRule( xRule );
+}
+
+void CondFormat::importCfHeader( BiffInputStream& rStrm )
+{
+ // import the CFHEADER record
+ sal_uInt16 nRuleCount;
+ BinRangeList aRanges;
+ rStrm >> nRuleCount;
+ rStrm.skip( 10 );
+ rStrm >> aRanges;
+ getAddressConverter().convertToCellRangeList( maOoxData.maRanges, aRanges, getSheetIndex(), true );
+
+ // import following list of CFRULE records
+ for( sal_uInt16 nRule = 0; (nRule < nRuleCount) && (rStrm.getNextRecId() == BIFF_ID_CFRULE) && rStrm.startNextRecord(); ++nRule )
+ {
+ CondFormatRuleRef xRule = createRule();
+ xRule->importCfRule( rStrm, nRule + 1 );
+ insertRule( xRule );
+ }
+}
+
+void CondFormat::finalizeImport()
+{
+ Reference< XSheetCellRanges > xRanges = getCellRangeList( maOoxData.maRanges );
+ if( xRanges.is() )
+ {
+ PropertySet aPropSet( xRanges );
+ Reference< XSheetConditionalEntries > xEntries;
+ aPropSet.getProperty( xEntries, CREATE_OUSTRING( "ConditionalFormat" ) );
+ if( xEntries.is() )
+ {
+ // maRules is sorted by rule priority
+ maRules.forEachMem( &CondFormatRule::finalizeImport, xEntries );
+ aPropSet.setProperty( CREATE_OUSTRING( "ConditionalFormat" ), xEntries );
+ }
+ }
+}
+
+CondFormatRuleRef CondFormat::createRule()
+{
+ return CondFormatRuleRef( new CondFormatRule( *this ) );
+}
+
+void CondFormat::insertRule( CondFormatRuleRef xRule )
+{
+ if( xRule.get() && (xRule->getPriority() > 0) )
+ {
+ OSL_ENSURE( maRules.find( xRule->getPriority() ) == maRules.end(), "CondFormat::insertRule - multiple rules with equal priority" );
+ maRules[ xRule->getPriority() ] = xRule;
+ }
+}
+
+// ============================================================================
+
+CondFormatBuffer::CondFormatBuffer( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+CondFormatRef CondFormatBuffer::importConditionalFormatting( const AttributeList& rAttribs )
+{
+ CondFormatRef xCondFmt = createCondFormat();
+ xCondFmt->importConditionalFormatting( rAttribs );
+ return xCondFmt;
+}
+
+CondFormatRef CondFormatBuffer::importCondFormatting( RecordInputStream& rStrm )
+{
+ CondFormatRef xCondFmt = createCondFormat();
+ xCondFmt->importCondFormatting( rStrm );
+ return xCondFmt;
+}
+
+void CondFormatBuffer::importCfHeader( BiffInputStream& rStrm )
+{
+ createCondFormat()->importCfHeader( rStrm );
+}
+
+void CondFormatBuffer::finalizeImport()
+{
+ maCondFormats.forEachMem( &CondFormat::finalizeImport );
+}
+
+// private --------------------------------------------------------------------
+
+CondFormatRef CondFormatBuffer::createCondFormat()
+{
+ CondFormatRef xCondFmt( new CondFormat( *this ) );
+ maCondFormats.push_back( xCondFmt );
+ return xCondFmt;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/condformatcontext.cxx b/oox/source/xls/condformatcontext.cxx
new file mode 100644
index 000000000000..d387bc959cca
--- /dev/null
+++ b/oox/source/xls/condformatcontext.cxx
@@ -0,0 +1,114 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: condformatcontext.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/condformatcontext.hxx"
+
+using ::rtl::OUString;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxCondFormatContext::OoxCondFormatContext( const OoxWorksheetFragmentBase& rFragment ) :
+ OoxWorksheetContextBase( rFragment )
+{
+}
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxCondFormatContext::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( conditionalFormatting ):
+ return (nElement == XLS_TOKEN( cfRule ));
+ case XLS_TOKEN( cfRule ):
+ return (nElement == XLS_TOKEN( formula ));
+ }
+ return false;
+}
+
+void OoxCondFormatContext::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( conditionalFormatting ):
+ mxCondFmt = getCondFormats().importConditionalFormatting( rAttribs );
+ break;
+ case XLS_TOKEN( cfRule ):
+ if( mxCondFmt.get() ) mxRule = mxCondFmt->importCfRule( rAttribs );
+ break;
+ }
+}
+
+void OoxCondFormatContext::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( formula ):
+ if( mxCondFmt.get() && mxRule.get() ) mxRule->appendFormula( rChars );
+ break;
+ }
+}
+
+bool OoxCondFormatContext::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_CONDFORMATTING:
+ return (nRecId == OOBIN_ID_CFRULE);
+ }
+ return false;
+}
+
+void OoxCondFormatContext::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_CONDFORMATTING:
+ mxCondFmt = getCondFormats().importCondFormatting( rStrm );
+ break;
+ case OOBIN_ID_CFRULE:
+ if( mxCondFmt.get() ) mxCondFmt->importCfRule( rStrm );
+ break;
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/connectionsfragment.cxx b/oox/source/xls/connectionsfragment.cxx
new file mode 100644
index 000000000000..125e79cccc45
--- /dev/null
+++ b/oox/source/xls/connectionsfragment.cxx
@@ -0,0 +1,127 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: connectionsfragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/connectionsfragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/xls/webquerybuffer.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::xml::sax::SAXException;
+
+namespace oox {
+namespace xls {
+
+OoxConnectionsFragment::OoxConnectionsFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+bool OoxConnectionsFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT: return (nElement == XLS_TOKEN( connections ));
+ case XLS_TOKEN( connections ): return (nElement == XLS_TOKEN( connection ));
+ case XLS_TOKEN( connection ): return (nElement == XLS_TOKEN( webPr )) ||
+ (nElement == XLS_TOKEN( textPr )) ||
+ (nElement == XLS_TOKEN( dbPr )) ||
+ (nElement == XLS_TOKEN( olapPr )) ||
+ (nElement == XLS_TOKEN( parameters ));
+ case XLS_TOKEN( webPr ): return (nElement == XLS_TOKEN( tables ));
+ case XLS_TOKEN( tables ): return (nElement == XLS_TOKEN( m )) ||
+ (nElement == XLS_TOKEN( s )) ||
+ (nElement == XLS_TOKEN( x ));
+ }
+ return false;
+}
+
+void OoxConnectionsFragment::onStartElement( const AttributeList& rAttribs )
+{
+ switch ( getCurrentContext() )
+ {
+ case XLS_TOKEN( connection ):
+ importConnection( rAttribs );
+ break;
+ case XLS_TOKEN( webPr ):
+ importWebPr( rAttribs );
+ break;
+ case XLS_TOKEN( tables ):
+ importTables( rAttribs );
+ break;
+ case XLS_TOKEN( s ):
+ importS( rAttribs );
+ break;
+ case XLS_TOKEN( x ):
+ importX( rAttribs );
+ break;
+ }
+}
+
+void OoxConnectionsFragment::importConnection( const AttributeList& rAttribs )
+{
+ if ( rAttribs.getInteger( XML_type, 0 ) == Connection::CONNECTION_WEBQUERY )
+ {
+ getWebQueries().importConnection( rAttribs );
+ }
+}
+
+void OoxConnectionsFragment::importWebPr( const AttributeList& rAttribs )
+{
+ getWebQueries().importWebPr( rAttribs );
+}
+
+void OoxConnectionsFragment::importTables( const AttributeList& /*rAttribs*/ )
+{
+// sal_Int32 nCount = rAttribs.getInteger( XML_count, 0 );
+}
+
+void OoxConnectionsFragment::importS( const AttributeList& /*rAttribs*/ )
+{
+// OUString aName = rAttribs.getString( XML_v );
+}
+
+void OoxConnectionsFragment::importX( const AttributeList& /*rAttribs*/ )
+{
+// sal_Int32 nSharedId = rAttribs.getInteger( XML_v, 0 );
+}
+
+} // namespace xls
+} // namespace oox
diff --git a/oox/source/xls/defnamesbuffer.cxx b/oox/source/xls/defnamesbuffer.cxx
new file mode 100644
index 000000000000..6fc1623dea0e
--- /dev/null
+++ b/oox/source/xls/defnamesbuffer.cxx
@@ -0,0 +1,674 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: defnamesbuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/defnamesbuffer.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/sheet/XNamedRange.hpp>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include <com/sun/star/sheet/XPrintAreas.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+#include <com/sun/star/sheet/SingleReference.hpp>
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/NamedRangeFlag.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/externallinkbuffer.hxx"
+#include "oox/xls/formulaparser.hxx"
+#include "oox/xls/ooxtokens.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::SingleReference;
+using ::com::sun::star::sheet::ComplexReference;
+using ::com::sun::star::sheet::XNamedRanges;
+using ::com::sun::star::sheet::XNamedRange;
+using ::com::sun::star::sheet::XFormulaTokens;
+using ::com::sun::star::sheet::XPrintAreas;
+using namespace ::com::sun::star::sheet::ReferenceFlags;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF_DEFNAME_HIDDEN = 0x0001;
+const sal_uInt16 BIFF_DEFNAME_FUNC = 0x0002;
+const sal_uInt16 BIFF_DEFNAME_VBNAME = 0x0004;
+const sal_uInt16 BIFF_DEFNAME_MACRO = 0x0008;
+const sal_uInt16 BIFF_DEFNAME_CALCEXP = 0x0010;
+const sal_uInt16 BIFF_DEFNAME_BUILTIN = 0x0020;
+const sal_uInt16 BIFF_DEFNAME_FGROUPMASK = 0x0FC0;
+const sal_uInt16 BIFF_DEFNAME_BIG = 0x1000;
+
+const sal_uInt8 BIFF2_DEFNAME_FUNC = 0x02; /// BIFF2 function/command flag.
+
+const sal_uInt16 BIFF_DEFNAME_GLOBAL = 0; /// 0 = Globally defined name.
+
+} // namespace
+
+// ============================================================================
+
+OoxDefinedNameData::OoxDefinedNameData() :
+ mnSheet( -1 ),
+ mbMacro( false ),
+ mbFunction( false ),
+ mbVBName( false ),
+ mbHidden( false )
+{
+}
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF_REFFLAG_COL1REL = 0x0001;
+const sal_uInt16 BIFF_REFFLAG_ROW1REL = 0x0002;
+const sal_uInt16 BIFF_REFFLAG_COL2REL = 0x0004;
+const sal_uInt16 BIFF_REFFLAG_ROW2REL = 0x0008;
+
+void lclConvertRefFlags( sal_Int32& ornFlags, sal_Int32& ornAbsPos, sal_Int32& ornRelPos, sal_Int32 nBasePos, sal_Int32 nApiRelFlag, bool bRel )
+{
+ if( getFlag( ornFlags, nApiRelFlag ) && !bRel )
+ {
+ // convert relative to absolute
+ setFlag( ornFlags, nApiRelFlag, false );
+ ornAbsPos = nBasePos + ornRelPos;
+ }
+ else if( !getFlag( ornFlags, nApiRelFlag ) && bRel )
+ {
+ // convert absolute to relative
+ setFlag( ornFlags, nApiRelFlag, true );
+ ornRelPos = ornAbsPos - nBasePos;
+ }
+}
+
+void lclConvertSingleRefFlags( SingleReference& orApiRef, const CellAddress& rBaseAddress, bool bColRel, bool bRowRel )
+{
+ lclConvertRefFlags(
+ orApiRef.Flags, orApiRef.Column, orApiRef.RelativeColumn,
+ rBaseAddress.Column, COLUMN_RELATIVE, bColRel );
+ lclConvertRefFlags(
+ orApiRef.Flags, orApiRef.Row, orApiRef.RelativeRow,
+ rBaseAddress.Row, ROW_RELATIVE, bRowRel );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+DefinedNameBase::DefinedNameBase( const WorkbookHelper& rHelper, sal_Int32 nLocalSheet ) :
+ WorkbookHelper( rHelper )
+{
+ maOoxData.mnSheet = nLocalSheet;
+}
+
+Any DefinedNameBase::getReference( const CellAddress& rBaseAddress ) const
+{
+ if( maRefAny.hasValue() && (maOoxData.maName.getLength() >= 2) && (maOoxData.maName[ 0 ] == '\x01') )
+ {
+ sal_Unicode cFlagsChar = maOoxData.maName.toAsciiUpperCase()[ 1 ];
+ if( ('A' <= cFlagsChar) && (cFlagsChar <= 'P') )
+ {
+ sal_uInt16 nFlags = static_cast< sal_uInt16 >( cFlagsChar - 'A' );
+ if( maRefAny.has< SingleReference >() && (cFlagsChar <= 'D') )
+ {
+ SingleReference aApiRef;
+ maRefAny >>= aApiRef;
+ lclConvertSingleRefFlags( aApiRef, rBaseAddress, getFlag( nFlags, BIFF_REFFLAG_COL1REL ), getFlag( nFlags, BIFF_REFFLAG_ROW1REL ) );
+ return Any( aApiRef );
+ }
+ if( maRefAny.has< ComplexReference >() )
+ {
+ ComplexReference aApiRef;
+ maRefAny >>= aApiRef;
+ lclConvertSingleRefFlags( aApiRef.Reference1, rBaseAddress, getFlag( nFlags, BIFF_REFFLAG_COL1REL ), getFlag( nFlags, BIFF_REFFLAG_ROW1REL ) );
+ lclConvertSingleRefFlags( aApiRef.Reference2, rBaseAddress, getFlag( nFlags, BIFF_REFFLAG_COL2REL ), getFlag( nFlags, BIFF_REFFLAG_ROW2REL ) );
+ return Any( aApiRef );
+ }
+ }
+ }
+ return Any();
+}
+
+void DefinedNameBase::importOoxFormula( FormulaContext& rContext )
+{
+ if( maOoxData.maFormula.getLength() > 0 )
+ {
+ rContext.setBaseAddress( CellAddress( static_cast< sal_Int16 >( maOoxData.mnSheet ), 0, 0 ) );
+ getFormulaParser().importFormula( rContext, maOoxData.maFormula );
+ }
+ else
+ getFormulaParser().convertErrorToFormula( rContext, BIFF_ERR_NAME );
+}
+
+void DefinedNameBase::importOobFormula( FormulaContext& rContext, RecordInputStream& rStrm )
+{
+ rContext.setBaseAddress( CellAddress( static_cast< sal_Int16 >( maOoxData.mnSheet ), 0, 0 ) );
+ getFormulaParser().importFormula( rContext, rStrm );
+}
+
+void DefinedNameBase::importBiffFormula( FormulaContext& rContext, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
+{
+ rContext.setBaseAddress( CellAddress( static_cast< sal_Int16 >( maOoxData.mnSheet ), 0, 0 ) );
+ if( !pnFmlaSize || (*pnFmlaSize > 0) )
+ getFormulaParser().importFormula( rContext, rStrm, pnFmlaSize );
+ else
+ getFormulaParser().convertErrorToFormula( rContext, BIFF_ERR_NAME );
+}
+
+void DefinedNameBase::setReference( const ApiTokenSequence& rTokens )
+{
+ maRefAny = getFormulaParser().extractReference( rTokens );
+}
+
+// ============================================================================
+
+namespace {
+
+const sal_Char* const spcLegacyPrefix = "Excel_BuiltIn_";
+const sal_Char* const spcOoxPrefix = "_xlnm.";
+
+const sal_Char* const sppcBaseNames[] =
+{
+ "Consolidate_Area", /* OOX */
+ "Auto_Open",
+ "Auto_Close",
+ "Extract", /* OOX */
+ "Database", /* OOX */
+ "Criteria", /* OOX */
+ "Print_Area", /* OOX */
+ "Print_Titles", /* OOX */
+ "Recorder",
+ "Data_Form",
+ "Auto_Activate",
+ "Auto_Deactivate",
+ "Sheet_Title", /* OOX */
+ "_FilterDatabase" /* OOX */
+};
+
+/** Localized names for _xlnm._FilterDatabase as used in BIFF5. */
+const sal_Char* const sppcFilterDbNames[] =
+{
+ "_FilterDatabase", // English
+ "_FilterDatenbank" // German
+};
+
+OUString lclGetBaseName( sal_Unicode cBuiltinId )
+{
+ OSL_ENSURE( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ), "lclGetBaseName - unknown builtin name" );
+ OUStringBuffer aBuffer;
+ if( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ) )
+ aBuffer.appendAscii( sppcBaseNames[ cBuiltinId ] );
+ else
+ aBuffer.append( static_cast< sal_Int32 >( cBuiltinId ) );
+ return aBuffer.makeStringAndClear();
+}
+
+OUString lclGetFinalName( sal_Unicode cBuiltinId )
+{
+ return OUStringBuffer().appendAscii( spcOoxPrefix ).append( lclGetBaseName( cBuiltinId ) ).makeStringAndClear();
+}
+
+sal_Unicode lclGetBuiltinIdFromOox( const OUString& rOoxName )
+{
+ OUString aPrefix = OUString::createFromAscii( spcOoxPrefix );
+ sal_Int32 nPrefixLen = aPrefix.getLength();
+ if( rOoxName.matchIgnoreAsciiCase( aPrefix ) )
+ {
+ for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId )
+ {
+ OUString aBaseName = lclGetBaseName( cBuiltinId );
+ sal_Int32 nBaseNameLen = aBaseName.getLength();
+ if( (rOoxName.getLength() == nPrefixLen + nBaseNameLen) && rOoxName.matchIgnoreAsciiCase( aBaseName, nPrefixLen ) )
+ return cBuiltinId;
+ }
+ }
+ return OOX_DEFNAME_UNKNOWN;
+}
+
+sal_Unicode lclGetBuiltinIdFromOob( const OUString& rOobName )
+{
+ for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId )
+ if( rOobName.equalsIgnoreAsciiCaseAscii( sppcBaseNames[ cBuiltinId ] ) )
+ return cBuiltinId;
+ return OOX_DEFNAME_UNKNOWN;
+}
+
+bool lclIsFilterDatabaseName( const OUString& rName )
+{
+ for( const sal_Char* const* ppcName = sppcFilterDbNames; ppcName < STATIC_ARRAY_END( sppcFilterDbNames ); ++ppcName )
+ if( rName.equalsIgnoreAsciiCaseAscii( *ppcName ) )
+ return true;
+ return false;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+DefinedName::DefinedName( const WorkbookHelper& rHelper, sal_Int32 nLocalSheet ) :
+ DefinedNameBase( rHelper, nLocalSheet ),
+ mnTokenIndex( -1 ),
+ mcBuiltinId( OOX_DEFNAME_UNKNOWN ),
+ mpStrm( 0 ),
+ mnRecHandle( -1 ),
+ mnRecPos( 0 ),
+ mnFmlaSize( 0 )
+{
+}
+
+void DefinedName::importDefinedName( const AttributeList& rAttribs )
+{
+ maOoxData.maName = rAttribs.getString( XML_name );
+ maOoxData.mnSheet = rAttribs.getInteger( XML_localSheetId, -1 );
+ maOoxData.mbMacro = rAttribs.getBool( XML_xlm, false );
+ maOoxData.mbFunction = rAttribs.getBool( XML_function, false );
+ maOoxData.mbVBName = rAttribs.getBool( XML_vbProcedure, false );
+ maOoxData.mbHidden = rAttribs.getBool( XML_hidden, false );
+ mcBuiltinId = lclGetBuiltinIdFromOox( maOoxData.maName );
+}
+
+void DefinedName::setFormula( const OUString& rFormula )
+{
+ maOoxData.maFormula = rFormula;
+}
+
+void DefinedName::importDefinedName( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ rStrm.skip( 3 ); // 2 bytes unknown, 1 byte keyboard shortcut
+ rStrm >> maOoxData.mnSheet >> maOoxData.maName;
+
+ // macro function/command, hidden flag, equal flags in BIFF and OOBIN
+ maOoxData.mbMacro = getFlag( nFlags, BIFF_DEFNAME_MACRO );
+ maOoxData.mbFunction = getFlag( nFlags, BIFF_DEFNAME_FUNC );
+ maOoxData.mbVBName = getFlag( nFlags, BIFF_DEFNAME_VBNAME );
+ maOoxData.mbHidden = getFlag( nFlags, BIFF_DEFNAME_HIDDEN );
+
+ // get builtin name index from name
+ if( getFlag( nFlags, BIFF_DEFNAME_BUILTIN ) )
+ mcBuiltinId = lclGetBuiltinIdFromOob( maOoxData.maName );
+ // unhide built-in names (_xlnm._FilterDatabase is always hidden)
+ if( isBuiltinName() )
+ maOoxData.mbHidden = false;
+
+ // store token array data
+ sal_Int32 nRecPos = rStrm.getRecPos();
+ sal_Int32 nFmlaSize = rStrm.readInt32();
+ rStrm.skip( nFmlaSize );
+ sal_Int32 nAddDataSize = rStrm.readInt32();
+ if( rStrm.isValid() && (nFmlaSize > 0) && (nAddDataSize >= 0) && (rStrm.getRecLeft() >= nAddDataSize) )
+ {
+ sal_Int32 nTotalSize = 8 + nFmlaSize + nAddDataSize;
+ mxFormula.reset( new RecordDataSequence( nTotalSize ) );
+ rStrm.seek( nRecPos );
+ rStrm.read( mxFormula->getArray(), nTotalSize );
+ }
+}
+
+void DefinedName::importDefinedName( BiffInputStream& rStrm )
+{
+ BiffType eBiff = getBiff();
+ sal_uInt16 nFlags = 0;
+ sal_Int16 nRefId = BIFF_DEFNAME_GLOBAL;
+ sal_Int16 nTabId = BIFF_DEFNAME_GLOBAL;
+ sal_uInt8 nNameLen = 0, nShortCut = 0;
+
+ switch( eBiff )
+ {
+ case BIFF2:
+ {
+ sal_uInt8 nFlagsBiff2;
+ rStrm >> nFlagsBiff2;
+ rStrm.skip( 1 );
+ rStrm >> nShortCut >> nNameLen;
+ mnFmlaSize = rStrm.readuInt8();
+ setFlag( nFlags, BIFF_DEFNAME_FUNC, getFlag( nFlagsBiff2, BIFF2_DEFNAME_FUNC ) );
+ maOoxData.maName = rStrm.readCharArray( nNameLen, getTextEncoding() );
+ }
+ break;
+ case BIFF3:
+ case BIFF4:
+ rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize;
+ maOoxData.maName = rStrm.readCharArray( nNameLen, getTextEncoding() );
+ break;
+ case BIFF5:
+ rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId;
+ maOoxData.maName = rStrm.skip( 4 ).readCharArray( nNameLen, getTextEncoding() );
+ break;
+ case BIFF8:
+ rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId;
+ maOoxData.maName = rStrm.skip( 4 ).readUniString( nNameLen );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+
+ // macro function/command, hidden flag
+ maOoxData.mbMacro = getFlag( nFlags, BIFF_DEFNAME_MACRO );
+ maOoxData.mbFunction = getFlag( nFlags, BIFF_DEFNAME_FUNC );
+ maOoxData.mbVBName = getFlag( nFlags, BIFF_DEFNAME_VBNAME );
+ maOoxData.mbHidden = getFlag( nFlags, BIFF_DEFNAME_HIDDEN );
+
+ // get builtin name index from name
+ if( getFlag( nFlags, BIFF_DEFNAME_BUILTIN ) )
+ {
+ OSL_ENSURE( maOoxData.maName.getLength() == 1, "DefinedName::importDefinedName - wrong builtin name" );
+ if( maOoxData.maName.getLength() > 0 )
+ {
+ mcBuiltinId = maOoxData.maName[ 0 ];
+ if( mcBuiltinId == '?' ) // the NUL character is imported as '?'
+ mcBuiltinId = OOX_DEFNAME_CONSOLIDATEAREA;
+ }
+ }
+ /* In BIFF5, _xlnm._FilterDatabase appears as hidden user name without
+ built-in flag, and even worse, localized. */
+ else if( (eBiff == BIFF5) && lclIsFilterDatabaseName( maOoxData.maName ) )
+ {
+ mcBuiltinId = OOX_DEFNAME_FILTERDATABASE;
+ }
+
+ // unhide built-in names (_xlnm._FilterDatabase is always hidden)
+ if( isBuiltinName() )
+ maOoxData.mbHidden = false;
+
+ // get sheet index for sheet-local names in BIFF5-BIFF8
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ break;
+ case BIFF5:
+ // #i44019# nTabId may be invalid, resolve nRefId to sheet index
+ if( nRefId != BIFF_DEFNAME_GLOBAL )
+ if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
+ if( pExtLink->getLinkType() == LINKTYPE_INTERNAL )
+ maOoxData.mnSheet = pExtLink->getSheetIndex();
+ break;
+ case BIFF8:
+ // one-based sheet index
+ if( nTabId != BIFF_DEFNAME_GLOBAL )
+ maOoxData.mnSheet = nTabId - 1;
+ break;
+ case BIFF_UNKNOWN:
+ break;
+ }
+
+ // store record position to be able to import token array later
+ mpStrm = &rStrm;
+ mnRecHandle = rStrm.getRecHandle();
+ mnRecPos = rStrm.getRecPos();
+}
+
+void DefinedName::createNameObject()
+{
+ // do not create hidden names and names for (macro) functions
+ if( maOoxData.mbHidden || maOoxData.mbFunction )
+ return;
+
+ // convert original name to final Calc name
+ if( maOoxData.mbVBName )
+ maFinalName = maOoxData.maName;
+ else if( isBuiltinName() )
+ maFinalName = lclGetFinalName( mcBuiltinId );
+ else
+ maFinalName = maOoxData.maName; //! TODO convert to valid name
+
+ // append sheet index for local names in multi-sheet documents
+ if( isWorkbookFile() && !isGlobalName() )
+ maFinalName = OUStringBuffer( maFinalName ).append( sal_Unicode( '_' ) ).append( maOoxData.mnSheet + 1 ).makeStringAndClear();
+
+ // special flags for this name
+ sal_Int32 nNameFlags = 0;
+ using namespace ::com::sun::star::sheet::NamedRangeFlag;
+ if( !isGlobalName() ) switch( mcBuiltinId )
+ {
+ case OOX_DEFNAME_CRITERIA: nNameFlags = FILTER_CRITERIA; break;
+ case OOX_DEFNAME_PRINTAREA: nNameFlags = PRINT_AREA; break;
+ case OOX_DEFNAME_PRINTTITLES: nNameFlags = COLUMN_HEADER | ROW_HEADER; break;
+ }
+
+ // create the name and insert it into the document, maFinalName will be changed to the resulting name
+ mxNamedRange = getDefinedNames().createDefinedName( maFinalName, nNameFlags );
+ // index of this defined name used in formula token arrays
+ mnTokenIndex = getDefinedNames().getTokenIndex( mxNamedRange );
+}
+
+void DefinedName::convertFormula()
+{
+ Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY );
+ if( xTokens.is() )
+ {
+ // convert and set formula of the defined name
+ SimpleFormulaContext aContext( xTokens, true, true );
+ switch( getFilterType() )
+ {
+ case FILTER_OOX: implImportOoxFormula( aContext ); break;
+ case FILTER_BIFF: implImportBiffFormula( aContext ); break;
+ case FILTER_UNKNOWN: break;
+ }
+
+ // set builtin names (print ranges, repeated titles, filter ranges)
+ if( !isGlobalName() ) switch( mcBuiltinId )
+ {
+ case OOX_DEFNAME_PRINTAREA:
+ {
+ Reference< XPrintAreas > xPrintAreas( getSheet( maOoxData.mnSheet ), UNO_QUERY );
+ ApiCellRangeList aPrintRanges;
+ getFormulaParser().extractCellRangeList( aPrintRanges, xTokens->getTokens(), maOoxData.mnSheet );
+ if( xPrintAreas.is() && !aPrintRanges.empty() )
+ xPrintAreas->setPrintAreas( ContainerHelper::vectorToSequence( aPrintRanges ) );
+ }
+ break;
+ case OOX_DEFNAME_PRINTTITLES:
+ {
+ Reference< XPrintAreas > xPrintAreas( getSheet( maOoxData.mnSheet ), UNO_QUERY );
+ ApiCellRangeList aTitleRanges;
+ getFormulaParser().extractCellRangeList( aTitleRanges, xTokens->getTokens(), maOoxData.mnSheet );
+ if( xPrintAreas.is() && !aTitleRanges.empty() )
+ {
+ bool bHasRowTitles = false;
+ bool bHasColTitles = false;
+ const CellAddress& rMaxPos = getAddressConverter().getMaxAddress();
+ for( ApiCellRangeList::const_iterator aIt = aTitleRanges.begin(), aEnd = aTitleRanges.end(); (aIt != aEnd) && (!bHasRowTitles || !bHasColTitles); ++aIt )
+ {
+ bool bFullRow = (aIt->StartColumn == 0) && (aIt->EndColumn >= rMaxPos.Column);
+ bool bFullCol = (aIt->StartRow == 0) && (aIt->EndRow >= rMaxPos.Row);
+ if( !bHasRowTitles && bFullRow && !bFullCol )
+ {
+ xPrintAreas->setTitleRows( *aIt );
+ xPrintAreas->setPrintTitleRows( sal_True );
+ bHasRowTitles = true;
+ }
+ else if( !bHasColTitles && bFullCol && !bFullRow )
+ {
+ xPrintAreas->setTitleColumns( *aIt );
+ xPrintAreas->setPrintTitleColumns( sal_True );
+ bHasColTitles = true;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ else if( maOoxData.mbHidden && (maOoxData.maName.getLength() > 0) && (maOoxData.maName[ 0 ] == '\x01') )
+ {
+ // import BIFF2-BIFF4 external references
+ TokensFormulaContext aContext( true, true );
+ implImportBiffFormula( aContext );
+ setReference( aContext.getTokens() );
+ }
+}
+
+void DefinedName::implImportOoxFormula( FormulaContext& rContext )
+{
+ if( mxFormula.get() )
+ {
+ RecordInputStream aStrm( *mxFormula );
+ importOobFormula( rContext, aStrm );
+ }
+ else
+ importOoxFormula( rContext );
+}
+
+void DefinedName::implImportBiffFormula( FormulaContext& rContext )
+{
+ OSL_ENSURE( mpStrm, "DefinedName::importBiffFormula - missing BIFF stream" );
+ sal_Int64 nCurrRecHandle = mpStrm->getRecHandle();
+ if( mpStrm->startRecordByHandle( mnRecHandle ) )
+ mpStrm->seek( mnRecPos );
+ importBiffFormula( rContext, *mpStrm, &mnFmlaSize );
+ mpStrm->startRecordByHandle( nCurrRecHandle );
+}
+
+// ============================================================================
+
+DefinedNamesBuffer::DefinedNamesBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maTokenIndexProp( CREATE_OUSTRING( "TokenIndex" ) ),
+ mnLocalSheet( -1 )
+{
+}
+
+Reference< XNamedRange > DefinedNamesBuffer::createDefinedName( OUString& orName, sal_Int32 nNameFlags ) const
+{
+ // find an unused name
+ Reference< XNamedRanges > xNamedRanges = getNamedRanges();
+ Reference< XNameAccess > xNameAccess( xNamedRanges, UNO_QUERY );
+ if( xNameAccess.is() )
+ orName = ContainerHelper::getUnusedName( xNameAccess, orName, '_' );
+
+ // create the name and insert it into the Calc document
+ Reference< XNamedRange > xNamedRange;
+ if( xNamedRanges.is() && (orName.getLength() > 0) ) try
+ {
+ xNamedRanges->addNewByName( orName, OUString(), CellAddress( 0, 0, 0 ), nNameFlags );
+ xNamedRange.set( xNamedRanges->getByName( orName ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "DefinedNamesBuffer::createDefinedName - cannot create defined name" );
+ }
+ return xNamedRange;
+}
+
+sal_Int32 DefinedNamesBuffer::getTokenIndex( const Reference< XNamedRange >& rxNamedRange ) const
+{
+ PropertySet aPropSet( rxNamedRange );
+ sal_Int32 nIndex = -1;
+ return aPropSet.getProperty( nIndex, maTokenIndexProp ) ? nIndex : -1;
+}
+
+void DefinedNamesBuffer::setLocalSheetIndex( sal_Int32 nLocalSheet )
+{
+ mnLocalSheet = nLocalSheet;
+}
+
+DefinedNameRef DefinedNamesBuffer::importDefinedName( const AttributeList& rAttribs )
+{
+ DefinedNameRef xDefName = createDefinedName();
+ xDefName->importDefinedName( rAttribs );
+ return xDefName;
+}
+
+void DefinedNamesBuffer::importDefinedName( RecordInputStream& rStrm )
+{
+ createDefinedName()->importDefinedName( rStrm );
+}
+
+void DefinedNamesBuffer::importDefinedName( BiffInputStream& rStrm )
+{
+ createDefinedName()->importDefinedName( rStrm );
+}
+
+void DefinedNamesBuffer::finalizeImport()
+{
+ /* First insert all names without formula definition into the document. */
+ maDefNames.forEachMem( &DefinedName::createNameObject );
+ /* Now convert all name formulas, so that the formula parser can find all
+ names in case of circular dependencies. */
+ maDefNames.forEachMem( &DefinedName::convertFormula );
+}
+
+DefinedNameRef DefinedNamesBuffer::getByIndex( sal_Int32 nIndex ) const
+{
+ return maDefNames.get( nIndex );
+}
+
+DefinedNameRef DefinedNamesBuffer::getByOoxName( const OUString& rOoxName, sal_Int32 nSheet ) const
+{
+ DefinedNameRef xGlobalName; // a found global name
+ DefinedNameRef xLocalName; // a found local name
+ for( DefNameVec::const_iterator aIt = maDefNames.begin(), aEnd = maDefNames.end(); (aIt != aEnd) && !xLocalName; ++aIt )
+ {
+ DefinedNameRef xCurrName = *aIt;
+ if( xCurrName->getOoxName() == rOoxName )
+ {
+ if( xCurrName->getSheetIndex() == nSheet )
+ xLocalName = xCurrName;
+ else if( xCurrName->isGlobalName() )
+ xGlobalName = xCurrName;
+ }
+ }
+ return xLocalName.get() ? xLocalName : xGlobalName;
+}
+
+DefinedNameRef DefinedNamesBuffer::createDefinedName()
+{
+ DefinedNameRef xDefName( new DefinedName( *this, mnLocalSheet ) );
+ maDefNames.push_back( xDefName );
+ return xDefName;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/excelfilter.cxx b/oox/source/xls/excelfilter.cxx
new file mode 100644
index 000000000000..feaf77188ee6
--- /dev/null
+++ b/oox/source/xls/excelfilter.cxx
@@ -0,0 +1,284 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: excelfilter.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/excelfilter.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/xls/biffdetector.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/workbookfragment.hxx"
+#include "oox/dump/biffdumper.hxx"
+#include "oox/dump/xlsbdumper.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::xml::sax::XFastDocumentHandler;
+using ::oox::core::BinaryFilterBase;
+using ::oox::core::FragmentHandlerRef;
+using ::oox::core::RecordInfo;
+using ::oox::core::RecordInfoProvider;
+using ::oox::core::RecordInfoProviderRef;
+using ::oox::core::Relation;
+using ::oox::core::Relations;
+using ::oox::core::XmlFilterBase;
+using ::oox::vml::DrawingPtr;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+/** List of OOBIN record identifiers that start a new context level. */
+static const struct RecordInfo spRecInfos[] =
+{
+ { OOBIN_ID_BOOKVIEWS, OOBIN_ID_BOOKVIEWS + 1 },
+ { OOBIN_ID_BORDERS, OOBIN_ID_BORDERS + 1 },
+ { OOBIN_ID_CELLSTYLES, OOBIN_ID_CELLSTYLES + 1 },
+ { OOBIN_ID_CELLSTYLEXFS, OOBIN_ID_CELLSTYLEXFS + 1 },
+ { OOBIN_ID_CELLXFS, OOBIN_ID_CELLXFS + 1 },
+ { OOBIN_ID_CFRULE, OOBIN_ID_CFRULE + 1 },
+ { OOBIN_ID_COLBREAKS, OOBIN_ID_COLBREAKS + 1 },
+ { OOBIN_ID_COLORS, OOBIN_ID_COLORS + 1 },
+ { OOBIN_ID_COLORSCALE, OOBIN_ID_COLORSCALE + 1 },
+ { OOBIN_ID_COLS, OOBIN_ID_COLS + 1 },
+ { OOBIN_ID_CONDFORMATTING, OOBIN_ID_CONDFORMATTING + 1 },
+ { OOBIN_ID_DATABAR, OOBIN_ID_DATABAR + 1 },
+ { OOBIN_ID_DATAVALIDATIONS, OOBIN_ID_DATAVALIDATIONS + 1 },
+ { OOBIN_ID_DDEITEMVALUES, OOBIN_ID_DDEITEMVALUES + 1 },
+ { OOBIN_ID_DXFS, OOBIN_ID_DXFS + 1 },
+ { OOBIN_ID_EXTERNALBOOK, -1 },
+ { OOBIN_ID_EXTERNALREFS, OOBIN_ID_EXTERNALREFS + 1 },
+ { OOBIN_ID_EXTROW, -1 },
+ { OOBIN_ID_EXTSHEETDATA, OOBIN_ID_EXTSHEETDATA + 1 },
+ { OOBIN_ID_FILLS, OOBIN_ID_FILLS + 1 },
+ { OOBIN_ID_FONTS, OOBIN_ID_FONTS + 1 },
+ { OOBIN_ID_HEADERFOOTER, OOBIN_ID_HEADERFOOTER + 1 },
+ { OOBIN_ID_ICONSET, OOBIN_ID_ICONSET + 1 },
+ { OOBIN_ID_INDEXEDCOLORS, OOBIN_ID_INDEXEDCOLORS + 1 },
+ { OOBIN_ID_MERGECELLS, OOBIN_ID_MERGECELLS + 1 },
+ { OOBIN_ID_MRUCOLORS, OOBIN_ID_MRUCOLORS + 1 },
+ { OOBIN_ID_NUMFMTS, OOBIN_ID_NUMFMTS + 1 },
+ { OOBIN_ID_ROW, -1 },
+ { OOBIN_ID_ROWBREAKS, OOBIN_ID_ROWBREAKS + 1 },
+ { OOBIN_ID_SHEETDATA, OOBIN_ID_SHEETDATA + 1 },
+ { OOBIN_ID_SHEETDATASET, OOBIN_ID_SHEETDATASET + 1 },
+ { OOBIN_ID_SHEETS, OOBIN_ID_SHEETS + 1 },
+ { OOBIN_ID_SHEETVIEW, OOBIN_ID_SHEETVIEW + 1 },
+ { OOBIN_ID_SHEETVIEWS, OOBIN_ID_SHEETVIEWS + 1 },
+ { OOBIN_ID_SST, OOBIN_ID_SST + 1 },
+ { OOBIN_ID_STYLESHEET, OOBIN_ID_STYLESHEET + 1 },
+ { OOBIN_ID_TABLE, OOBIN_ID_TABLE + 1 },
+ { OOBIN_ID_TABLEPARTS, OOBIN_ID_TABLEPARTS + 2 }, // end element increased by 2!
+ { OOBIN_ID_TABLESTYLES, OOBIN_ID_TABLESTYLES + 1 },
+ { OOBIN_ID_VOLTYPE, OOBIN_ID_VOLTYPE + 1 },
+ { OOBIN_ID_VOLTYPEMAIN, OOBIN_ID_VOLTYPEMAIN + 1 },
+ { OOBIN_ID_VOLTYPES, OOBIN_ID_VOLTYPES + 1 },
+ { OOBIN_ID_WORKBOOK, OOBIN_ID_WORKBOOK + 1 },
+ { OOBIN_ID_WORKSHEET, OOBIN_ID_WORKSHEET + 1 },
+ { -1, -1 }
+};
+
+} // namespace
+
+// ============================================================================
+
+OUString SAL_CALL ExcelFilter_getImplementationName() throw()
+{
+ return CREATE_OUSTRING( "com.sun.star.comp.oox.ExcelFilter" );
+}
+
+Sequence< OUString > SAL_CALL ExcelFilter_getSupportedServiceNames() throw()
+{
+ OUString aServiceName = CREATE_OUSTRING( "com.sun.star.comp.oox.ExcelFilter" );
+ Sequence< OUString > aSeq( &aServiceName, 1 );
+ return aSeq;
+}
+
+Reference< XInterface > SAL_CALL ExcelFilter_createInstance(
+ const Reference< XMultiServiceFactory >& rxFactory ) throw( Exception )
+{
+ return static_cast< ::cppu::OWeakObject* >( new ExcelFilter( rxFactory ) );
+}
+
+// ----------------------------------------------------------------------------
+
+ExcelFilter::ExcelFilter( const Reference< XMultiServiceFactory >& rxFactory ) :
+ XmlFilterBase( rxFactory ),
+ mpHelper( 0 )
+{
+}
+
+ExcelFilter::~ExcelFilter()
+{
+}
+
+bool ExcelFilter::importDocument() throw()
+{
+#if OOX_INCLUDE_DUMPER
+ {
+ ::oox::dump::xlsb::Dumper aDumper( *this );
+ aDumper.dump();
+ if( !aDumper.isImportEnabled() )
+ return aDumper.isValid();
+ }
+#endif
+
+ bool bRet = false;
+ OUString aWorkbookPath = getFragmentPathFromType( CREATE_RELATIONS_TYPE( "officeDocument" ) );
+ if( aWorkbookPath.getLength() > 0 )
+ {
+ WorkbookHelperRoot aHelper( *this );
+ if( aHelper.isValid() )
+ {
+ mpHelper = &aHelper; // needed for callbacks
+ bRet = importFragment( new OoxWorkbookFragment( aHelper, aWorkbookPath ) );
+ mpHelper = 0;
+ }
+ }
+ return bRet;
+}
+
+bool ExcelFilter::exportDocument() throw()
+{
+ return false;
+}
+
+sal_Int32 ExcelFilter::getSchemeClr( sal_Int32 nColorSchemeToken ) const
+{
+ OSL_ENSURE( mpHelper, "ExcelFilter::getSchemeClr - no workbook helper" );
+ return mpHelper ? mpHelper->getTheme().getColorByToken( nColorSchemeToken ) : -1;
+}
+
+const DrawingPtr ExcelFilter::getDrawings()
+{
+ return DrawingPtr();
+}
+
+RecordInfoProviderRef ExcelFilter::getRecordInfoProvider()
+{
+ if( !mxRecInfoProv )
+ mxRecInfoProv.reset( new RecordInfoProvider( spRecInfos ) );
+ return mxRecInfoProv;
+}
+
+OUString ExcelFilter::implGetImplementationName() const
+{
+ return ExcelFilter_getImplementationName();
+}
+
+// ============================================================================
+
+OUString SAL_CALL ExcelBiffFilter_getImplementationName() throw()
+{
+ return CREATE_OUSTRING( "com.sun.star.comp.oox.ExcelBiffFilter" );
+}
+
+Sequence< OUString > SAL_CALL ExcelBiffFilter_getSupportedServiceNames() throw()
+{
+ OUString aServiceName = CREATE_OUSTRING( "com.sun.star.comp.oox.ExcelBiffFilter" );
+ Sequence< OUString > aSeq( &aServiceName, 1 );
+ return aSeq;
+}
+
+Reference< XInterface > SAL_CALL ExcelBiffFilter_createInstance(
+ const Reference< XMultiServiceFactory >& rxFactory ) throw( Exception )
+{
+ return static_cast< ::cppu::OWeakObject* >( new ExcelBiffFilter( rxFactory ) );
+}
+
+// ----------------------------------------------------------------------------
+
+ExcelBiffFilter::ExcelBiffFilter( const Reference< XMultiServiceFactory >& rxFactory ) :
+ BinaryFilterBase( rxFactory )
+{
+}
+
+ExcelBiffFilter::~ExcelBiffFilter()
+{
+}
+
+bool ExcelBiffFilter::importDocument() throw()
+{
+#if OOX_INCLUDE_DUMPER
+ {
+ ::oox::dump::biff::Dumper aDumper( *this );
+ aDumper.dump();
+ if( !aDumper.isImportEnabled() )
+ return aDumper.isValid();
+ }
+#endif
+
+ bool bRet = false;
+
+ // detect BIFF version and workbook stream name
+ OUString aWorkbookName;
+ BiffType eBiff = BiffDetector::detectStorageBiffVersion( aWorkbookName, getStorage() );
+ BinaryInputStream aInStrm( getStorage()->openInputStream( aWorkbookName ), aWorkbookName.getLength() > 0 );
+ OSL_ENSURE( (eBiff != BIFF_UNKNOWN) && aInStrm.is(), "ExcelBiffFilter::ExcelBiffFilter - invalid file format" );
+
+ if( (eBiff != BIFF_UNKNOWN) && aInStrm.is() )
+ {
+ WorkbookHelperRoot aHelper( *this, eBiff );
+ if( aHelper.isValid() )
+ {
+ BiffWorkbookFragment aFragment( aHelper );
+ BiffInputStream aBiffStream( aInStrm );
+ bRet = aFragment.importFragment( aBiffStream );
+ }
+ }
+ return bRet;
+}
+
+bool ExcelBiffFilter::exportDocument() throw()
+{
+ return false;
+}
+
+OUString ExcelBiffFilter::implGetImplementationName() const
+{
+ return ExcelBiffFilter_getImplementationName();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/externallinkbuffer.cxx b/oox/source/xls/externallinkbuffer.cxx
new file mode 100644
index 000000000000..72dab2171955
--- /dev/null
+++ b/oox/source/xls/externallinkbuffer.cxx
@@ -0,0 +1,857 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: externallinkbuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/externallinkbuffer.hxx"
+#include <rtl/strbuf.hxx>
+#include <com/sun/star/sheet/XDDELinks.hpp>
+#include <com/sun/star/sheet/XDDELink.hpp>
+#include <com/sun/star/sheet/XDDELinkResults.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/formulaparser.hxx"
+#include "oox/xls/ooxfragmenthandler.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OStringToOUString;
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::sheet::XDDELinks;
+using ::com::sun::star::sheet::XDDELinkResults;
+using ::oox::core::Relations;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 OOBIN_EXTERNALBOOK_BOOK = 0;
+const sal_uInt16 OOBIN_EXTERNALBOOK_DDE = 1;
+const sal_uInt16 OOBIN_EXTERNALBOOK_OLE = 2;
+
+const sal_uInt16 OOBIN_EXTNAME_AUTOMATIC = 0x0002;
+const sal_uInt16 OOBIN_EXTNAME_PREFERPIC = 0x0004;
+const sal_uInt16 OOBIN_EXTNAME_STDDOCNAME = 0x0008;
+const sal_uInt16 OOBIN_EXTNAME_OLEOBJECT = 0x0010;
+const sal_uInt16 OOBIN_EXTNAME_ICONIFIED = 0x0020;
+
+const sal_uInt16 BIFF_EXTNAME_BUILTIN = 0x0001;
+const sal_uInt16 BIFF_EXTNAME_AUTOMATIC = 0x0002;
+const sal_uInt16 BIFF_EXTNAME_PREFERPIC = 0x0004;
+const sal_uInt16 BIFF_EXTNAME_STDDOCNAME = 0x0008;
+const sal_uInt16 BIFF_EXTNAME_OLEOBJECT = 0x0010;
+const sal_uInt16 BIFF_EXTNAME_ICONIFIED = 0x8000;
+
+} // namespace
+
+// ============================================================================
+
+OoxExternalNameData::OoxExternalNameData() :
+ mbBuiltIn( false ),
+ mbNotify( false ),
+ mbPreferPic( false ),
+ mbStdDocName( false ),
+ mbOleObj( false ),
+ mbIconified( false )
+{
+}
+
+// ============================================================================
+
+ExternalName::ExternalName( const ExternalLink& rParentLink, sal_Int32 nLocalSheet ) :
+ DefinedNameBase( rParentLink, nLocalSheet ),
+ mrParentLink( rParentLink ),
+ mnStorageId( 0 ),
+ mbDdeLinkCreated( false )
+{
+}
+
+void ExternalName::importDefinedName( const AttributeList& rAttribs )
+{
+ maOoxData.maName = rAttribs.getString( XML_name );
+ OSL_ENSURE( maOoxData.maName.getLength() > 0, "ExternalName::importDefinedName - empty name" );
+ // zero-based index into sheet list of externalBook
+ maOoxData.mnSheet = mrParentLink.getSheetIndex( rAttribs.getInteger( XML_sheetId, -1 ) );
+}
+
+void ExternalName::importDdeItem( const AttributeList& rAttribs )
+{
+ maOoxData.maName = rAttribs.getString( XML_name );
+ OSL_ENSURE( maOoxData.maName.getLength() > 0, "ExternalName::importDdeItem - empty name" );
+ maOoxExtNameData.mbOleObj = false;
+ maOoxExtNameData.mbStdDocName = rAttribs.getBool( XML_ole, false );
+ maOoxExtNameData.mbNotify = rAttribs.getBool( XML_advise, false );
+ maOoxExtNameData.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
+}
+
+void ExternalName::importValues( const AttributeList& rAttribs )
+{
+ setResultSize( rAttribs.getInteger( XML_cols, 1 ), rAttribs.getInteger( XML_rows, 1 ) );
+}
+
+void ExternalName::importOleItem( const AttributeList& rAttribs )
+{
+ maOoxData.maName = rAttribs.getString( XML_name );
+ OSL_ENSURE( maOoxData.maName.getLength() > 0, "ExternalName::importOleItem - empty name" );
+ maOoxExtNameData.mbOleObj = true;
+ maOoxExtNameData.mbNotify = rAttribs.getBool( XML_advise, false );
+ maOoxExtNameData.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
+ maOoxExtNameData.mbIconified = rAttribs.getBool( XML_icon, false );
+}
+
+void ExternalName::importExternalName( RecordInputStream& rStrm )
+{
+ rStrm >> maOoxData.maName;
+ OSL_ENSURE( maOoxData.maName.getLength() > 0, "ExternalName::importExternalName - empty name" );
+}
+
+void ExternalName::importExternalNameFlags( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ sal_Int32 nSheetId;
+ rStrm >> nFlags >> nSheetId;
+ // one-based index into sheet list of EXTSHEETNAMES
+ maOoxData.mnSheet = mrParentLink.getSheetIndex( nSheetId - 1 );
+ // no flag for built-in names, as in OOX...
+ maOoxExtNameData.mbNotify = getFlag( nFlags, OOBIN_EXTNAME_AUTOMATIC );
+ maOoxExtNameData.mbPreferPic = getFlag( nFlags, OOBIN_EXTNAME_PREFERPIC );
+ maOoxExtNameData.mbStdDocName = getFlag( nFlags, OOBIN_EXTNAME_STDDOCNAME );
+ maOoxExtNameData.mbOleObj = getFlag( nFlags, OOBIN_EXTNAME_OLEOBJECT );
+ maOoxExtNameData.mbIconified = getFlag( nFlags, OOBIN_EXTNAME_ICONIFIED );
+ OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_OLE) == maOoxExtNameData.mbOleObj,
+ "ExternalName::importExternalNameFlags - wrong flags in external name" );
+}
+
+void ExternalName::importDdeItemValues( RecordInputStream& rStrm )
+{
+ sal_Int32 nRows, nCols;
+ rStrm >> nRows >> nCols;
+ setResultSize( nCols, nRows );
+}
+
+void ExternalName::importDdeItemBool( RecordInputStream& rStrm )
+{
+ appendResultValue< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
+}
+
+void ExternalName::importDdeItemDouble( RecordInputStream& rStrm )
+{
+ appendResultValue( rStrm.readDouble() );
+}
+
+void ExternalName::importDdeItemError( RecordInputStream& rStrm )
+{
+ appendResultValue( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) );
+}
+
+void ExternalName::importDdeItemString( RecordInputStream& rStrm )
+{
+ appendResultValue( rStrm.readString() );
+}
+
+void ExternalName::importExternalName( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFlags = 0;
+ if( getBiff() >= BIFF3 )
+ {
+ rStrm >> nFlags;
+ maOoxExtNameData.mbBuiltIn = getFlag( nFlags, BIFF_EXTNAME_BUILTIN );
+ maOoxExtNameData.mbNotify = getFlag( nFlags, BIFF_EXTNAME_AUTOMATIC );
+ maOoxExtNameData.mbPreferPic = getFlag( nFlags, BIFF_EXTNAME_PREFERPIC );
+
+ // BIFF5-BIFF8: sheet index for sheet-local names, OLE settings
+ if( getBiff() >= BIFF5 )
+ {
+ maOoxExtNameData.mbStdDocName = getFlag( nFlags, BIFF_EXTNAME_STDDOCNAME );
+ maOoxExtNameData.mbOleObj = getFlag( nFlags, BIFF_EXTNAME_OLEOBJECT );
+ maOoxExtNameData.mbIconified = getFlag( nFlags, BIFF_EXTNAME_ICONIFIED );
+
+ if( maOoxExtNameData.mbOleObj )
+ {
+ rStrm >> mnStorageId;
+ }
+ else
+ {
+ // get sheet index for sheet-local names
+ sal_Int16 nRefId = rStrm.skip( 2 ).readuInt16();
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ break;
+ case BIFF5:
+ // resolve nRefId to sheet index, zero is global name
+ if( nRefId > 0 )
+ if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
+ if( pExtLink->getLinkType() == LINKTYPE_EXTERNAL )
+ maOoxData.mnSheet = pExtLink->getSheetIndex();
+ break;
+ case BIFF8:
+ // one-based index into sheet list of EXTERNALBOOK record, zero is global name
+ if( nRefId > 0 )
+ maOoxData.mnSheet = mrParentLink.getSheetIndex( nRefId - 1 );
+ break;
+ case BIFF_UNKNOWN:
+ break;
+ }
+ }
+ }
+ }
+
+ maOoxData.maName = (getBiff() == BIFF8) ?
+ rStrm.readUniString( rStrm.readuInt8() ) :
+ rStrm.readByteString( false, getTextEncoding() );
+ OSL_ENSURE( maOoxData.maName.getLength() > 0, "ExternalName::importExternalName - empty name" );
+
+ switch( mrParentLink.getLinkType() )
+ {
+ case LINKTYPE_EXTERNAL:
+ // external cell references that are stored in hidden external names (seen in BIFF3-BIFF4)
+ if( (maOoxData.maName.getLength() > 0) && (maOoxData.maName[ 0 ] == '\x01') && (rStrm.getRecLeft() > 2) )
+ {
+ TokensFormulaContext aContext( true, true );
+ importBiffFormula( aContext, rStrm );
+ setReference( aContext.getTokens() );
+ }
+ break;
+
+ case LINKTYPE_DDE:
+ case LINKTYPE_OLE:
+ case LINKTYPE_MAYBE_DDE_OLE:
+ // DDE/OLE link results
+ if( rStrm.getRecLeft() > 3 )
+ {
+ bool bBiff8 = getBiff() == BIFF8;
+ sal_Int32 nCols = rStrm.readuInt8();
+ sal_Int32 nRows = rStrm.readuInt16();
+ if( bBiff8 ) { ++nCols; ++nRows; } else if( nCols == 0 ) nCols = 256;
+ setResultSize( nCols, nRows );
+
+ bool bLoop = true;
+ while( bLoop && rStrm.isValid() && (maCurrIt != maResults.end()) )
+ {
+ switch( rStrm.readuInt8() )
+ {
+ case BIFF_DATATYPE_EMPTY:
+ appendResultValue( OUString() );
+ rStrm.skip( 8 );
+ break;
+ case BIFF_DATATYPE_DOUBLE:
+ appendResultValue( rStrm.readDouble() );
+ break;
+ case BIFF_DATATYPE_STRING:
+ appendResultValue( bBiff8 ? rStrm.readUniString() : rStrm.readByteString( false, getTextEncoding() ) );
+ break;
+ case BIFF_DATATYPE_BOOL:
+ appendResultValue< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
+ rStrm.skip( 7 );
+ break;
+ case BIFF_DATATYPE_ERROR:
+ appendResultValue( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) );
+ rStrm.skip( 7 );
+ break;
+ default:
+ bLoop = false;
+ }
+ }
+ OSL_ENSURE( bLoop && rStrm.isValid() && (maCurrIt == maResults.end()),
+ "ExternalName::importExternalName - stream error in result set" );
+ }
+ break;
+
+ default:;
+ }
+}
+
+bool ExternalName::getDdeLinkData( OUString& orDdeServer, OUString& orDdeTopic, OUString& orDdeItem )
+{
+ if( (mrParentLink.getLinkType() == LINKTYPE_DDE) && (maOoxData.maName.getLength() > 0) )
+ {
+ // try to create a DDE link and to set the imported link results
+ if( !mbDdeLinkCreated ) try
+ {
+ Reference< XDDELinks > xDdeLinks( getDdeLinks(), UNO_QUERY_THROW );
+ mxDdeLink = xDdeLinks->addDDELink( mrParentLink.getClassName(), mrParentLink.getTargetUrl(), maOoxData.maName, ::com::sun::star::sheet::DDELinkMode_DEFAULT );
+ if( !maResults.empty() )
+ {
+ Reference< XDDELinkResults > xResults( mxDdeLink, UNO_QUERY_THROW );
+ xResults->setResults( ContainerHelper::matrixToSequenceSequence( maResults ) );
+ }
+ mbDdeLinkCreated = true;
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "ExternalName::getDdeLinkData - cannot create DDE link" );
+ }
+ // get link data from created DDE link
+ if( mxDdeLink.is() )
+ {
+ orDdeServer = mxDdeLink->getApplication();
+ orDdeTopic = mxDdeLink->getTopic();
+ orDdeItem = mxDdeLink->getItem();
+ return true;
+ }
+ }
+ return false;
+}
+
+void ExternalName::setResultSize( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_DDE) || (mrParentLink.getLinkType() == LINKTYPE_OLE) ||
+ (mrParentLink.getLinkType() == LINKTYPE_MAYBE_DDE_OLE), "ExternalName::setResultSize - wrong link type" );
+ OSL_ENSURE( (nRows > 0) && (nColumns > 0), "ExternalName::setResultSize - invalid matrix size" );
+ const CellAddress& rMaxPos = getAddressConverter().getMaxApiAddress();
+ if( (0 < nRows) && (nRows <= rMaxPos.Row + 1) && (0 < nColumns) && (nColumns <= rMaxPos.Column + 1) )
+ maResults.resize( static_cast< size_t >( nColumns ), static_cast< size_t >( nRows ), Any( BiffHelper::calcDoubleFromError( BIFF_ERR_NA ) ) );
+ else
+ maResults.clear();
+ maCurrIt = maResults.begin();
+}
+
+// ============================================================================
+
+ExternalLink::ExternalLink( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ meLinkType( LINKTYPE_UNKNOWN )
+{
+}
+
+void ExternalLink::importExternalReference( const AttributeList& rAttribs )
+{
+ maRelId = rAttribs.getString( R_TOKEN( id ) );
+}
+
+void ExternalLink::importExternalBook( const Relations& rRelations, const AttributeList& rAttribs )
+{
+ OUString aTargetUrl = rRelations.getTargetFromRelId( rAttribs.getString( R_TOKEN( id ) ) );
+ setExternalTargetUrl( aTargetUrl );
+}
+
+void ExternalLink::importSheetName( const AttributeList& rAttribs )
+{
+ OUString aSheetName = rAttribs.getString( XML_val );
+ OSL_ENSURE( aSheetName.getLength() > 0, "ExternalLink::importSheetName - empty sheet name" );
+ if( meLinkType == LINKTYPE_EXTERNAL )
+ maSheetIndexes.push_back( getWorksheets().insertExternalSheet( maTargetUrl, aSheetName ) );
+}
+
+void ExternalLink::importDefinedName( const AttributeList& rAttribs )
+{
+ createExternalName()->importDefinedName( rAttribs );
+}
+
+void ExternalLink::importDdeLink( const AttributeList& rAttribs )
+{
+ OUString aDdeService = rAttribs.getString( XML_ddeService );
+ OUString aDdeTopic = rAttribs.getString( XML_ddeTopic );
+ setDdeOleTargetUrl( aDdeService, aDdeTopic, LINKTYPE_DDE );
+}
+
+ExternalNameRef ExternalLink::importDdeItem( const AttributeList& rAttribs )
+{
+ ExternalNameRef xExtName = createExternalName();
+ xExtName->importDdeItem( rAttribs );
+ return xExtName;
+}
+
+void ExternalLink::importOleLink( const Relations& rRelations, const AttributeList& rAttribs )
+{
+ OUString aProgId = rAttribs.getString( XML_progId );
+ OUString aTargetUrl = rRelations.getTargetFromRelId( rAttribs.getString( R_TOKEN( id ) ) );
+ setDdeOleTargetUrl( aProgId, aTargetUrl, LINKTYPE_OLE );
+}
+
+ExternalNameRef ExternalLink::importOleItem( const AttributeList& rAttribs )
+{
+ ExternalNameRef xExtName = createExternalName();
+ xExtName->importOleItem( rAttribs );
+ return xExtName;
+}
+
+void ExternalLink::importExternalRef( RecordInputStream& rStrm )
+{
+ rStrm >> maRelId;
+}
+
+void ExternalLink::importExternalSelf( RecordInputStream& )
+{
+ meLinkType = LINKTYPE_SELF;
+}
+
+void ExternalLink::importExternalBook( const Relations& rRelations, RecordInputStream& rStrm )
+{
+ switch( rStrm.readuInt16() )
+ {
+ case OOBIN_EXTERNALBOOK_BOOK:
+ {
+ OUString aTargetUrl = rRelations.getTargetFromRelId( rStrm.readString() );
+ setExternalTargetUrl( aTargetUrl );
+ }
+ break;
+ case OOBIN_EXTERNALBOOK_DDE:
+ {
+ OUString aDdeService, aDdeTopic;
+ rStrm >> aDdeService >> aDdeTopic;
+ setDdeOleTargetUrl( aDdeService, aDdeTopic, LINKTYPE_DDE );
+ }
+ break;
+ case OOBIN_EXTERNALBOOK_OLE:
+ {
+ OUString aTargetUrl = rRelations.getTargetFromRelId( rStrm.readString() );
+ OUString aProgId = rStrm.readString();
+ setDdeOleTargetUrl( aProgId, aTargetUrl, LINKTYPE_OLE );
+ }
+ break;
+ default:
+ OSL_ENSURE( false, "ExternalLink::importExternalBook - unknown link type" );
+ }
+}
+
+void ExternalLink::importExtSheetNames( RecordInputStream& rStrm )
+{
+ // load external sheet names and create the linked sheets in the Calc document
+ OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::importExtSheetNames - invalid link type" );
+ if( meLinkType == LINKTYPE_EXTERNAL )
+ {
+ WorksheetBuffer& rWorksheets = getWorksheets();
+ for( sal_Int32 nSheet = 0, nCount = rStrm.readInt32(); rStrm.isValid() && (nSheet < nCount); ++nSheet )
+ {
+ OUString aSheetName = rStrm.readString();
+ OSL_ENSURE( aSheetName.getLength() > 0, "ExternalLink::importExtSheetNames - empty sheet name" );
+ maSheetIndexes.push_back( rWorksheets.insertExternalSheet( maTargetUrl, aSheetName ) );
+ }
+ }
+}
+
+ExternalNameRef ExternalLink::importExternalName( RecordInputStream& rStrm )
+{
+ ExternalNameRef xExtName = createExternalName();
+ xExtName->importExternalName( rStrm );
+ return xExtName;
+}
+
+void ExternalLink::importExternSheet( BiffInputStream& rStrm )
+{
+ OStringBuffer aTargetBuffer( rStrm.readByteString( false ) );
+ // references to own sheets have wrong string length field (off by 1)
+ if( (aTargetBuffer.getLength() > 0) && (aTargetBuffer[ 0 ] == 3) )
+ aTargetBuffer.append( static_cast< sal_Char >( rStrm.readuInt8() ) );
+ // parse the encoded URL
+ OUString aBiffTarget = OStringToOUString( aTargetBuffer.makeStringAndClear(), getTextEncoding() );
+ OUString aSheetName = parseBiffTargetUrl( aBiffTarget );
+ switch( meLinkType )
+ {
+ case LINKTYPE_INTERNAL:
+ maSheetIndexes.push_back( getWorksheets().getFinalSheetIndex( aSheetName ) );
+ break;
+ case LINKTYPE_EXTERNAL:
+ maSheetIndexes.push_back( getWorksheets().insertExternalSheet( maTargetUrl, aSheetName ) );
+ break;
+ default:;
+ }
+}
+
+void ExternalLink::importExternalBook( BiffInputStream& rStrm )
+{
+ OUString aTarget;
+ sal_uInt16 nSheetCount;
+ rStrm >> nSheetCount;
+ if( rStrm.getRecLeft() == 2 )
+ {
+ if( rStrm.readuInt8() == 1 )
+ {
+ sal_Char cChar = static_cast< sal_Char >( rStrm.readuInt8() );
+ if( cChar != 0 )
+ aTarget = OStringToOUString( OString( cChar ), getTextEncoding() );
+ }
+ }
+ else if( rStrm.getRecLeft() >= 3 )
+ {
+ aTarget = rStrm.readUniString();
+ }
+
+ // parse the encoded URL
+ OUString aDummySheetName = parseBiffTargetUrl( aTarget );
+ OSL_ENSURE( aDummySheetName.getLength() == 0, "ExternalLink::importExternalBook - sheet name in encoded URL" );
+ (void)aDummySheetName; // prevent compiler warning
+
+ // load external sheet names and create the linked sheets in the Calc document
+ if( meLinkType == LINKTYPE_EXTERNAL )
+ {
+ WorksheetBuffer& rWorksheets = getWorksheets();
+ for( sal_uInt16 nSheet = 0; rStrm.isValid() && (nSheet < nSheetCount); ++nSheet )
+ {
+ OUString aSheetName = rStrm.readUniString();
+ OSL_ENSURE( aSheetName.getLength() > 0, "ExternalLink::importExternalBook - empty sheet name" );
+ maSheetIndexes.push_back( rWorksheets.insertExternalSheet( maTargetUrl, aSheetName ) );
+ }
+ }
+}
+
+void ExternalLink::importExternalName( BiffInputStream& rStrm )
+{
+ ExternalNameRef xExtName = createExternalName();
+ xExtName->importExternalName( rStrm );
+ switch( meLinkType )
+ {
+ case LINKTYPE_DDE:
+ OSL_ENSURE( !xExtName->isOleObject(), "ExternalLink::importExternalName - OLE object in DDE link" );
+ break;
+ case LINKTYPE_OLE:
+ OSL_ENSURE( xExtName->isOleObject(), "ExternalLink::importExternalName - anything but OLE object in OLE link" );
+ break;
+ case LINKTYPE_MAYBE_DDE_OLE:
+ meLinkType = xExtName->isOleObject() ? LINKTYPE_OLE : LINKTYPE_DDE;
+ break;
+ default:
+ OSL_ENSURE( !xExtName->isOleObject(), "ExternalLink::importExternalName - OLE object in external name" );
+ }
+}
+
+sal_Int32 ExternalLink::getSheetIndex( sal_Int32 nTabId ) const
+{
+ OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOX) || (getBiff() == BIFF8),
+ "ExternalLink::getSheetIndex - invalid sheet index" );
+ return ((0 <= nTabId) && (static_cast< size_t >( nTabId ) < maSheetIndexes.size())) ?
+ maSheetIndexes[ static_cast< size_t >( nTabId ) ] : -1;
+}
+
+void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId1, sal_Int32 nTabId2 ) const
+{
+ orSheetRange.setDeleted();
+ switch( meLinkType )
+ {
+ case LINKTYPE_SELF:
+ case LINKTYPE_INTERNAL:
+ orSheetRange.set( nTabId1, nTabId2 );
+ break;
+ case LINKTYPE_EXTERNAL: switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ // OOBIN: passed indexes point into sheet list of EXTSHEETLIST
+ orSheetRange.set( getSheetIndex( nTabId1 ), getSheetIndex( nTabId2 ) );
+ break;
+ case FILTER_BIFF:
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ orSheetRange.set( getSheetIndex( nTabId1 ), getSheetIndex( nTabId2 ) );
+ break;
+ case BIFF5:
+ // BIFF5: first sheet from this external link, last sheet is passed in nTabId2
+ if( const ExternalLink* pExtLink2 = getExternalLinks().getExternalLink( nTabId2 ).get() )
+ if( (pExtLink2->getLinkType() == LINKTYPE_EXTERNAL) && (maTargetUrl == pExtLink2->getTargetUrl()) )
+ orSheetRange.set( getSheetIndex(), pExtLink2->getSheetIndex() );
+ break;
+ case BIFF8:
+ // BIFF8: passed indexes point into sheet list of EXTERNALBOOK
+ orSheetRange.set( getSheetIndex( nTabId1 ), getSheetIndex( nTabId2 ) );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+ break;
+ case FILTER_UNKNOWN:
+ break;
+ }
+ break;
+
+ default:;
+ }
+}
+
+ExternalNameRef ExternalLink::getNameByIndex( sal_Int32 nIndex ) const
+{
+ return maExtNames.get( nIndex );
+}
+
+// private --------------------------------------------------------------------
+
+void ExternalLink::setExternalTargetUrl( const OUString& rTargetUrl )
+{
+ maTargetUrl = getBaseFilter().getAbsoluteUrl( rTargetUrl );
+ meLinkType = (maTargetUrl.getLength() > 0) ? LINKTYPE_EXTERNAL : LINKTYPE_UNKNOWN;
+ OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::setExternalTargetUrl - empty target URL" );
+}
+
+void ExternalLink::setDdeOleTargetUrl( const OUString& rClassName, const OUString& rTargetUrl, ExternalLinkType eLinkType )
+{
+ maClassName = rClassName;
+ maTargetUrl = rTargetUrl;
+ meLinkType = ((maClassName.getLength() > 0) && (maTargetUrl.getLength() > 0)) ? eLinkType : LINKTYPE_UNKNOWN;
+ OSL_ENSURE( meLinkType == eLinkType, "ExternalLink::setDdeOleTargetUrl - missing classname or target" );
+}
+
+OUString ExternalLink::parseBiffTargetUrl( const OUString& rBiffTargetUrl )
+{
+ OUString aClassName, aTargetUrl, aSheetName;
+ meLinkType = LINKTYPE_UNKNOWN;
+ if( getAddressConverter().parseBiffTargetUrl( aClassName, aTargetUrl, aSheetName, rBiffTargetUrl ) )
+ {
+ if( aClassName.getLength() > 0 )
+ {
+ setDdeOleTargetUrl( aClassName, aTargetUrl, LINKTYPE_MAYBE_DDE_OLE );
+ }
+ else if( aTargetUrl.getLength() == 0 )
+ {
+ meLinkType = (aSheetName.getLength() > 0) ? LINKTYPE_INTERNAL : LINKTYPE_SELF;
+ }
+ else if( (aTargetUrl.getLength() == 1) && (aTargetUrl[ 0 ] == ':') )
+ {
+ if( getBiff() >= BIFF4 )
+ meLinkType = LINKTYPE_ANALYSIS;
+ }
+ else if( (aTargetUrl.getLength() == 1) && (aTargetUrl[ 0 ] == ' ') )
+ {
+ meLinkType = LINKTYPE_UNKNOWN;
+ }
+ else
+ {
+ setExternalTargetUrl( aTargetUrl );
+ }
+ }
+ return aSheetName;
+}
+
+ExternalNameRef ExternalLink::createExternalName()
+{
+ ExternalNameRef xExtName( new ExternalName( *this, getSheetIndex() ) );
+ maExtNames.push_back( xExtName );
+ return xExtName;
+}
+
+// ============================================================================
+
+OoxRefSheets::OoxRefSheets() :
+ mnExtRefId( -1 ),
+ mnTabId1( -1 ),
+ mnTabId2( -1 )
+{
+}
+
+void OoxRefSheets::readOobData( RecordInputStream& rStrm )
+{
+ rStrm >> mnExtRefId >> mnTabId1 >> mnTabId2;
+}
+
+void OoxRefSheets::readBiff8Data( BiffInputStream& rStrm )
+{
+ mnExtRefId = rStrm.readuInt16();
+ mnTabId1 = rStrm.readInt16();
+ mnTabId2 = rStrm.readInt16();
+}
+
+// ----------------------------------------------------------------------------
+
+ExternalLinkBuffer::ExternalLinkBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mbUseRefSheets( false )
+{
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternalReference( const AttributeList& rAttribs )
+{
+ ExternalLinkRef xExtLink = createExternalLink();
+ xExtLink->importExternalReference( rAttribs );
+ return xExtLink;
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternalRef( RecordInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ ExternalLinkRef xExtLink = createExternalLink();
+ xExtLink->importExternalRef( rStrm );
+ return xExtLink;
+}
+
+void ExternalLinkBuffer::importExternalSelf( RecordInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ createExternalLink()->importExternalSelf( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalSheets( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbUseRefSheets, "ExternalLinkBuffer::importExternalSheets - missing EXTERNALREFS records" );
+ mbUseRefSheets = true;
+ OSL_ENSURE( maRefSheets.empty(), "ExternalLinkBuffer::importExternalSheets - multiple EXTERNALSHEETS records" );
+ maRefSheets.clear();
+ sal_Int32 nRefCount;
+ rStrm >> nRefCount;
+ size_t nMaxCount = getLimitedValue< size_t, sal_Int32 >( nRefCount, 0, rStrm.getRecLeft() / 12 );
+ maRefSheets.reserve( nMaxCount );
+ for( size_t nRefId = 0; rStrm.isValid() && (nRefId < nMaxCount); ++nRefId )
+ {
+ OoxRefSheets aRefSheets;
+ aRefSheets.readOobData( rStrm );
+ maRefSheets.push_back( aRefSheets );
+ }
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternSheet( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( getBiff() <= BIFF5, "ExternalLinkBuffer::importExternSheet - wrong BIFF version" );
+ ExternalLinkRef xExtLink = createExternalLink();
+ xExtLink->importExternSheet( rStrm );
+ return xExtLink;
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternalBook( BiffInputStream& rStrm )
+{
+ ExternalLinkRef xExtLink = createExternalLink();
+ xExtLink->importExternalBook( rStrm );
+ return xExtLink;
+}
+
+void ExternalLinkBuffer::importExternalName( BiffInputStream& rStrm )
+{
+ if( !maExtLinks.empty() )
+ maExtLinks.back()->importExternalName( rStrm );
+}
+
+void ExternalLinkBuffer::importExternSheet8( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( getBiff() == BIFF8, "ExternalLinkBuffer::importExternSheet - wrong BIFF version" );
+ OSL_ENSURE( maRefSheets.empty(), "ExternalLinkBuffer::importExternSheet - multiple EXTERNSHEET records" );
+ maRefSheets.clear();
+ sal_uInt16 nRefCount;
+ rStrm >> nRefCount;
+ maRefSheets.reserve( nRefCount );
+ for( sal_uInt16 nRefId = 0; rStrm.isValid() && (nRefId < nRefCount); ++nRefId )
+ {
+ OoxRefSheets aRefSheets;
+ aRefSheets.readBiff8Data( rStrm );
+ maRefSheets.push_back( aRefSheets );
+ }
+}
+
+ExternalLinkRef ExternalLinkBuffer::getExternalLink( sal_Int32 nRefId ) const
+{
+ ExternalLinkRef xExtLink;
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ // OOXML: one-based index
+ if( !mbUseRefSheets )
+ xExtLink = maExtLinks.get( nRefId - 1 );
+ // OOBIN: zero-based index into ref-sheets list
+ else if( const OoxRefSheets* pRefSheets = getRefSheets( nRefId ) )
+ xExtLink = maExtLinks.get( pRefSheets->mnExtRefId );
+ break;
+ case FILTER_BIFF:
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ // one-based index to EXTERNSHEET records
+ xExtLink = maExtLinks.get( nRefId - 1 );
+ break;
+ case BIFF5:
+ if( nRefId < 0 )
+ {
+ // internal links in formula tokens have negative index
+ xExtLink = maExtLinks.get( -nRefId - 1 );
+ if( xExtLink.get() && !xExtLink->isInternalLink() )
+ xExtLink.reset();
+ }
+ else
+ {
+ // one-based index to EXTERNSHEET records
+ xExtLink = maExtLinks.get( nRefId - 1 );
+ }
+ break;
+ case BIFF8:
+ // zero-based index into REF list in EXTERNSHEET record
+ if( const OoxRefSheets* pRefSheets = getRefSheets( nRefId ) )
+ xExtLink = maExtLinks.get( pRefSheets->mnExtRefId );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+ break;
+ case FILTER_UNKNOWN: break;
+ }
+ return xExtLink;
+}
+
+LinkSheetRange ExternalLinkBuffer::getSheetRange( sal_Int32 nRefId, sal_Int16 nTabId1, sal_Int16 nTabId2 ) const
+{
+ OSL_ENSURE( getBiff() <= BIFF5, "ExternalLinkBuffer::getSheetRange - wrong BIFF version" );
+ LinkSheetRange aSheetRange;
+ if( const ExternalLink* pExtLink = getExternalLink( nRefId ).get() )
+ pExtLink->getSheetRange( aSheetRange, nTabId1, nTabId2 );
+ return aSheetRange;
+}
+
+LinkSheetRange ExternalLinkBuffer::getSheetRange( sal_Int32 nRefId ) const
+{
+ OSL_ENSURE( ((getFilterType() == FILTER_OOX) && mbUseRefSheets) || (getBiff() == BIFF8), "ExternalLinkBuffer::getSheetRange - wrong BIFF version" );
+ LinkSheetRange aSheetRange;
+ if( const ExternalLink* pExtLink = getExternalLink( nRefId ).get() )
+ if( const OoxRefSheets* pRefSheets = getRefSheets( nRefId ) )
+ pExtLink->getSheetRange( aSheetRange, pRefSheets->mnTabId1, pRefSheets->mnTabId2 );
+ return aSheetRange;
+}
+
+// private --------------------------------------------------------------------
+
+ExternalLinkRef ExternalLinkBuffer::createExternalLink()
+{
+ ExternalLinkRef xExtLink( new ExternalLink( *this ) );
+ maExtLinks.push_back( xExtLink );
+ return xExtLink;
+}
+
+const OoxRefSheets* ExternalLinkBuffer::getRefSheets( sal_Int32 nRefId ) const
+{
+ return ((0 <= nRefId) && (static_cast< size_t >( nRefId ) < maRefSheets.size())) ?
+ &maRefSheets[ static_cast< size_t >( nRefId ) ] : 0;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/externallinkfragment.cxx b/oox/source/xls/externallinkfragment.cxx
new file mode 100644
index 000000000000..b291a6ad7147
--- /dev/null
+++ b/oox/source/xls/externallinkfragment.cxx
@@ -0,0 +1,392 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: externallinkfragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/externallinkfragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/core/recordparser.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/defnamesbuffer.hxx"
+#include "oox/xls/sheetdatacontext.hxx"
+#include "oox/xls/unitconverter.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::xml::sax::XFastContextHandler;
+using ::oox::core::RecordContextRef;
+using ::oox::core::Relation;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxExternalLinkFragment::OoxExternalLinkFragment( const WorkbookHelper& rHelper,
+ const OUString& rFragmentPath, ExternalLink& rExtLink ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath ),
+ mrExtLink( rExtLink ),
+ mnResultType( XML_TOKEN_INVALID )
+{
+}
+
+bool OoxExternalLinkFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nElement == XLS_TOKEN( externalLink ));
+ case XLS_TOKEN( externalLink ):
+ return (nElement == XLS_TOKEN( externalBook )) ||
+ (nElement == XLS_TOKEN( ddeLink )) ||
+ (nElement == XLS_TOKEN( oleLink ));
+ case XLS_TOKEN( externalBook ):
+ return (nElement == XLS_TOKEN( sheetNames )) ||
+ (nElement == XLS_TOKEN( definedNames )) ||
+ (nElement == XLS_TOKEN( sheetDataSet ));
+ case XLS_TOKEN( sheetNames ):
+ return (nElement == XLS_TOKEN( sheetName ));
+ case XLS_TOKEN( definedNames ):
+ return (nElement == XLS_TOKEN( definedName ));
+ case XLS_TOKEN( sheetDataSet ):
+ return (nElement == XLS_TOKEN( sheetData ));
+ case XLS_TOKEN( ddeLink ):
+ return (nElement == XLS_TOKEN( ddeItems ));
+ case XLS_TOKEN( ddeItems ):
+ return (nElement == XLS_TOKEN( ddeItem ));
+ case XLS_TOKEN( ddeItem ):
+ return (nElement == XLS_TOKEN( values ));
+ case XLS_TOKEN( values ):
+ return (nElement == XLS_TOKEN( value ));
+ case XLS_TOKEN( value ):
+ return (nElement == XLS_TOKEN( val ));
+ case XLS_TOKEN( oleLink ):
+ return (nElement == XLS_TOKEN( oleItems ));
+ case XLS_TOKEN( oleItems ):
+ return (nElement == XLS_TOKEN( oleItem ));
+ }
+ return false;
+}
+
+Reference< XFastContextHandler > OoxExternalLinkFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( nElement )
+ {
+ case XLS_TOKEN( sheetData ):
+ if( mrExtLink.getLinkType() == LINKTYPE_EXTERNAL )
+ {
+ sal_Int32 nSheet = mrExtLink.getSheetIndex( rAttribs.getInteger( XML_sheetId, -1 ) );
+ Reference< XFastContextHandler > xHandler;
+ ::rtl::Reference< OoxExternalSheetDataContext > xContext( new OoxExternalSheetDataContext( *this, SHEETTYPE_WORKSHEET, nSheet ) );
+ if( xContext->isValidSheet() )
+ xHandler.set( xContext.get() );
+ return xHandler;
+ }
+ break;
+ }
+ return this;
+}
+
+void OoxExternalLinkFragment::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( externalBook ): mrExtLink.importExternalBook( getRelations(), rAttribs ); break;
+ case XLS_TOKEN( sheetName ): mrExtLink.importSheetName( rAttribs ); break;
+ case XLS_TOKEN( definedName ): mrExtLink.importDefinedName( rAttribs ); break;
+ case XLS_TOKEN( ddeLink ): mrExtLink.importDdeLink( rAttribs ); break;
+ case XLS_TOKEN( ddeItem ): mxExtName = mrExtLink.importDdeItem( rAttribs ); break;
+ case XLS_TOKEN( values ): if( mxExtName.get() ) mxExtName->importValues( rAttribs ); break;
+ case XLS_TOKEN( value ): mnResultType = rAttribs.getToken( XML_t, XML_n ); break;
+ case XLS_TOKEN( oleLink ): mrExtLink.importOleLink( getRelations(), rAttribs ); break;
+ case XLS_TOKEN( oleItem ): mxExtName = mrExtLink.importOleItem( rAttribs ); break;
+ }
+}
+
+void OoxExternalLinkFragment::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( val ):
+ maResultValue = rChars;
+ break;
+ case XLS_TOKEN( value ):
+ if( mxExtName.get() ) switch( mnResultType )
+ {
+ case XML_b:
+ mxExtName->appendResultValue( maResultValue.toDouble() );
+ break;
+ case XML_e:
+ mxExtName->appendResultValue( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( maResultValue ) ) );
+ break;
+ case XML_n:
+ mxExtName->appendResultValue( maResultValue.toDouble() );
+ break;
+ case XML_str:
+ mxExtName->appendResultValue( maResultValue );
+ break;
+ default:
+ mxExtName->appendResultValue( BiffHelper::calcDoubleFromError( BIFF_ERR_NA ) );
+ }
+ break;
+ }
+}
+
+bool OoxExternalLinkFragment::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ /* Weird things are going on in this fragment...
+
+ Without external names, several EXTSHEETDATA/EXTSHEETDATA_END contexts
+ contain the external cells. They are not preceded by a SHEETDATASET
+ context record, but a SHEETDATASET_END record occurs at the end of the
+ stream. In this case we have to start a SHEETDATASET context on-the-fly
+ to keep the context stack valid.
+ */
+ if( (getCurrentContext() == OOBIN_ID_EXTERNALBOOK) && (nRecId == OOBIN_ID_EXTSHEETDATA) )
+ getRecordParser().pushContext( OOBIN_ID_SHEETDATASET, this );
+
+ /* With external names, SHEETDATASET contexts are opened after each
+ external name, but not closed before a new external name starts. Here
+ we have to close the SHEETDATASET context before.
+ */
+ else if( (getCurrentContext() == OOBIN_ID_SHEETDATASET) && (nRecId != OOBIN_ID_EXTSHEETDATA) )
+ getRecordParser().popContext();
+
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nRecId == OOBIN_ID_EXTERNALBOOK);
+ case OOBIN_ID_EXTERNALBOOK:
+ return (nRecId == OOBIN_ID_EXTSHEETNAMES) ||
+ (nRecId == OOBIN_ID_EXTERNALNAME) ||
+ (nRecId == OOBIN_ID_EXTERNALNAMEFLAGS) ||
+ (nRecId == OOBIN_ID_SHEETDATASET) ||
+ (nRecId == OOBIN_ID_DDEITEMVALUES);
+ case OOBIN_ID_SHEETDATASET:
+ return (nRecId == OOBIN_ID_EXTSHEETDATA);
+ case OOBIN_ID_DDEITEMVALUES:
+ return (nRecId == OOBIN_ID_DDEITEM_BOOL) ||
+ (nRecId == OOBIN_ID_DDEITEM_DOUBLE) ||
+ (nRecId == OOBIN_ID_DDEITEM_ERROR) ||
+ (nRecId == OOBIN_ID_DDEITEM_STRING);
+ }
+ return false;
+}
+
+RecordContextRef OoxExternalLinkFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( nRecId )
+ {
+ case OOBIN_ID_EXTSHEETDATA:
+ if( mrExtLink.getLinkType() == LINKTYPE_EXTERNAL )
+ {
+ sal_Int32 nSheet = mrExtLink.getSheetIndex( rStrm.readInt32() );
+ RecordContextRef xRecContext;
+ ::rtl::Reference< OoxExternalSheetDataContext > xContext( new OoxExternalSheetDataContext( *this, SHEETTYPE_WORKSHEET, nSheet ) );
+ if( xContext->isValidSheet() )
+ xRecContext.set( xContext.get() );
+ return xRecContext;
+ }
+ break;
+ }
+ return this;
+}
+
+void OoxExternalLinkFragment::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_EXTERNALBOOK: mrExtLink.importExternalBook( getRelations(), rStrm ); break;
+ case OOBIN_ID_EXTSHEETNAMES: mrExtLink.importExtSheetNames( rStrm ); break;
+ case OOBIN_ID_EXTERNALNAME: mxExtName = mrExtLink.importExternalName( rStrm ); break;
+ case OOBIN_ID_EXTERNALNAMEFLAGS: if( mxExtName.get() ) mxExtName->importExternalNameFlags( rStrm ); break;
+ case OOBIN_ID_DDEITEMVALUES: if( mxExtName.get() ) mxExtName->importDdeItemValues( rStrm ); break;
+ case OOBIN_ID_DDEITEM_BOOL: if( mxExtName.get() ) mxExtName->importDdeItemBool( rStrm ); break;
+ case OOBIN_ID_DDEITEM_DOUBLE: if( mxExtName.get() ) mxExtName->importDdeItemDouble( rStrm ); break;
+ case OOBIN_ID_DDEITEM_ERROR: if( mxExtName.get() ) mxExtName->importDdeItemError( rStrm ); break;
+ case OOBIN_ID_DDEITEM_STRING: if( mxExtName.get() ) mxExtName->importDdeItemString( rStrm ); break;
+ }
+}
+
+// ============================================================================
+
+BiffExternalLinkFragment::BiffExternalLinkFragment( const WorkbookHelper& rHelper, bool bImportDefNames ) :
+ BiffWorkbookFragmentBase( rHelper ),
+ mbImportDefNames( bImportDefNames )
+{
+}
+
+BiffExternalLinkFragment::~BiffExternalLinkFragment()
+{
+}
+
+bool BiffExternalLinkFragment::importFragment( BiffInputStream& rStrm )
+{
+ // process all record in this sheet fragment
+ while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+ {
+ if( isBofRecord( rStrm.getRecId() ) )
+ skipFragment( rStrm ); // skip unknown embedded fragments
+ else
+ importRecord( rStrm );
+ }
+ return rStrm.isValid() && (rStrm.getRecId() == BIFF_ID_EOF);
+}
+
+void BiffExternalLinkFragment::importRecord( BiffInputStream& rStrm )
+{
+ sal_uInt16 nRecId = rStrm.getRecId();
+ switch( getBiff() )
+ {
+ case BIFF2: switch( nRecId )
+ {
+ case BIFF2_ID_EXTERNALNAME: importExternalName( rStrm ); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
+ case BIFF2_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
+ }
+ break;
+ case BIFF3: switch( nRecId )
+ {
+ case BIFF_ID_CRN: importCrn( rStrm ); break;
+ case BIFF3_ID_EXTERNALNAME: importExternalName( rStrm ); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
+ case BIFF3_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
+ case BIFF_ID_XCT: importXct( rStrm ); break;
+ }
+ break;
+ case BIFF4: switch( nRecId )
+ {
+ case BIFF_ID_CRN: importCrn( rStrm ); break;
+ case BIFF3_ID_EXTERNALNAME: importExternalName( rStrm ); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
+ case BIFF3_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
+ case BIFF_ID_XCT: importXct( rStrm ); break;
+ }
+ break;
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF_ID_CRN: importCrn( rStrm ); break;
+ case BIFF5_ID_EXTERNALNAME: importExternalName( rStrm ); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
+ case BIFF5_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
+ case BIFF_ID_XCT: importXct( rStrm ); break;
+ }
+ break;
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF_ID_CRN: importCrn( rStrm ); break;
+ case BIFF_ID_EXTERNALBOOK: importExternalBook( rStrm ); break;
+ case BIFF5_ID_EXTERNALNAME: importExternalName( rStrm ); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
+ case BIFF5_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
+ case BIFF_ID_XCT: importXct( rStrm ); break;
+ }
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+}
+
+void BiffExternalLinkFragment::finalizeImport()
+{
+ getDefinedNames().finalizeImport();
+}
+
+// private --------------------------------------------------------------------
+
+void BiffExternalLinkFragment::importExternSheet( BiffInputStream& rStrm )
+{
+ mxContext.reset();
+ if( getBiff() == BIFF8 )
+ getExternalLinks().importExternSheet8( rStrm );
+ else
+ mxExtLink = getExternalLinks().importExternSheet( rStrm );
+}
+
+void BiffExternalLinkFragment::importExternalBook( BiffInputStream& rStrm )
+{
+ mxContext.reset();
+ mxExtLink = getExternalLinks().importExternalBook( rStrm );
+}
+
+void BiffExternalLinkFragment::importExternalName( BiffInputStream& rStrm )
+{
+ if( mxExtLink.get() )
+ mxExtLink->importExternalName( rStrm );
+}
+
+void BiffExternalLinkFragment::importXct( BiffInputStream& rStrm )
+{
+ mxContext.reset();
+ if( mxExtLink.get() && (mxExtLink->getLinkType() == LINKTYPE_EXTERNAL) )
+ {
+ sal_Int32 nSheet = -1;
+ switch( getBiff() )
+ {
+ case BIFF2:
+ break;
+ case BIFF3:
+ case BIFF4:
+ case BIFF5:
+ nSheet = mxExtLink->getSheetIndex();
+ break;
+ case BIFF8:
+ rStrm.skip( 2 );
+ nSheet = mxExtLink->getSheetIndex( rStrm.readInt16() );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+
+ // create a sheet data context to import the CRN records and set the cached cell values
+ mxContext.reset( new BiffExternalSheetDataContext( *this, SHEETTYPE_WORKSHEET, nSheet ) );
+ if( !mxContext->isValidSheet() )
+ mxContext.reset();
+ }
+}
+
+void BiffExternalLinkFragment::importCrn( BiffInputStream& rStrm )
+{
+ if( mxContext.get() )
+ mxContext->importCrn( rStrm );
+}
+
+void BiffExternalLinkFragment::importDefinedName( BiffInputStream& rStrm )
+{
+ if( mbImportDefNames )
+ getDefinedNames().importDefinedName( rStrm );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/formulabase.cxx b/oox/source/xls/formulabase.cxx
new file mode 100644
index 000000000000..4c5cb1bdfabc
--- /dev/null
+++ b/oox/source/xls/formulabase.cxx
@@ -0,0 +1,1459 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: formulabase.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/formulabase.hxx"
+#include <map>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+#include <com/sun/star/sheet/SingleReference.hpp>
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/FormulaLanguage.hpp>
+#include <com/sun/star/sheet/FormulaMapGroup.hpp>
+#include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
+#include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OStringToOUString;
+using ::rtl::OUStringToOString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::SingleReference;
+using ::com::sun::star::sheet::ComplexReference;
+using ::com::sun::star::sheet::FormulaToken;
+using ::com::sun::star::sheet::FormulaOpCodeMapEntry;
+using ::com::sun::star::sheet::XSpreadsheetDocument;
+using ::com::sun::star::sheet::XFormulaOpCodeMapper;
+using ::com::sun::star::sheet::XFormulaTokens;
+using namespace ::com::sun::star::sheet::ReferenceFlags;
+
+namespace oox {
+namespace xls {
+
+// reference helpers ==========================================================
+
+BinSingleRef2d::BinSingleRef2d() :
+ mnCol( 0 ),
+ mnRow( 0 ),
+ mbColRel( false ),
+ mbRowRel( false )
+{
+}
+
+void BinSingleRef2d::setOobData( sal_uInt16 nCol, sal_Int32 nRow, bool bRelativeAsOffset )
+{
+ mnCol = nCol & OOBIN_TOK_REF_COLMASK;
+ mnRow = nRow & OOBIN_TOK_REF_ROWMASK;
+ mbColRel = getFlag( nCol, OOBIN_TOK_REF_COLREL );
+ mbRowRel = getFlag( nCol, OOBIN_TOK_REF_ROWREL );
+ if( bRelativeAsOffset && mbColRel && (mnCol > (OOBIN_TOK_REF_COLMASK >> 1)) )
+ mnCol -= (OOBIN_TOK_REF_COLMASK + 1);
+ if( bRelativeAsOffset && mbRowRel && (mnRow > (OOBIN_TOK_REF_ROWMASK >> 1)) )
+ mnRow -= (OOBIN_TOK_REF_ROWMASK + 1);
+}
+
+void BinSingleRef2d::setBiff2Data( sal_uInt8 nCol, sal_uInt16 nRow, bool bRelativeAsOffset )
+{
+ mnCol = nCol;
+ mnRow = nRow & BIFF_TOK_REF_ROWMASK;
+ mbColRel = getFlag( nRow, BIFF_TOK_REF_COLREL );
+ mbRowRel = getFlag( nRow, BIFF_TOK_REF_ROWREL );
+ if( bRelativeAsOffset && mbColRel && (mnCol >= 0x80) )
+ mnCol -= 0x100;
+ if( bRelativeAsOffset && mbRowRel && (mnRow > (BIFF_TOK_REF_ROWMASK >> 1)) )
+ mnRow -= (BIFF_TOK_REF_ROWMASK + 1);
+}
+
+void BinSingleRef2d::setBiff8Data( sal_uInt16 nCol, sal_uInt16 nRow, bool bRelativeAsOffset )
+{
+ mnCol = nCol & BIFF_TOK_REF_COLMASK;
+ mnRow = nRow;
+ mbColRel = getFlag( nCol, BIFF_TOK_REF_COLREL );
+ mbRowRel = getFlag( nCol, BIFF_TOK_REF_ROWREL );
+ if( bRelativeAsOffset && mbColRel && (mnCol > (BIFF_TOK_REF_COLMASK >> 1)) )
+ mnCol -= (BIFF_TOK_REF_COLMASK + 1);
+ if( bRelativeAsOffset && mbRowRel && (mnRow >= 0x8000) )
+ mnRow -= 0x10000;
+}
+
+void BinSingleRef2d::readOobData( RecordInputStream& rStrm, bool bRelativeAsOffset )
+{
+ sal_Int32 nRow;
+ sal_uInt16 nCol;
+ rStrm >> nRow >> nCol;
+ setOobData( nCol, nRow, bRelativeAsOffset );
+}
+
+void BinSingleRef2d::readBiff2Data( BiffInputStream& rStrm, bool bRelativeAsOffset )
+{
+ sal_uInt16 nRow;
+ sal_uInt8 nCol;
+ rStrm >> nRow >> nCol;
+ setBiff2Data( nCol, nRow, bRelativeAsOffset );
+}
+
+void BinSingleRef2d::readBiff8Data( BiffInputStream& rStrm, bool bRelativeAsOffset )
+{
+ sal_uInt16 nRow, nCol;
+ rStrm >> nRow >> nCol;
+ setBiff8Data( nCol, nRow, bRelativeAsOffset );
+}
+
+// ----------------------------------------------------------------------------
+
+void BinComplexRef2d::readOobData( RecordInputStream& rStrm, bool bRelativeAsOffset )
+{
+ sal_Int32 nRow1, nRow2;
+ sal_uInt16 nCol1, nCol2;
+ rStrm >> nRow1 >> nRow2 >> nCol1 >> nCol2;
+ maRef1.setOobData( nCol1, nRow1, bRelativeAsOffset );
+ maRef2.setOobData( nCol2, nRow2, bRelativeAsOffset );
+}
+
+void BinComplexRef2d::readBiff2Data( BiffInputStream& rStrm, bool bRelativeAsOffset )
+{
+ sal_uInt16 nRow1, nRow2;
+ sal_uInt8 nCol1, nCol2;
+ rStrm >> nRow1 >> nRow2 >> nCol1 >> nCol2;
+ maRef1.setBiff2Data( nCol1, nRow1, bRelativeAsOffset );
+ maRef2.setBiff2Data( nCol2, nRow2, bRelativeAsOffset );
+}
+
+void BinComplexRef2d::readBiff8Data( BiffInputStream& rStrm, bool bRelativeAsOffset )
+{
+ sal_uInt16 nRow1, nRow2, nCol1, nCol2;
+ rStrm >> nRow1 >> nRow2 >> nCol1 >> nCol2;
+ maRef1.setBiff8Data( nCol1, nRow1, bRelativeAsOffset );
+ maRef2.setBiff8Data( nCol2, nRow2, bRelativeAsOffset );
+}
+
+// function data ==============================================================
+
+namespace {
+
+const size_t FUNCINFO_CLASSCOUNT = 5; /// Number of token class entries.
+
+const sal_uInt8 FUNCFLAG_VOLATILE = 0x01; /// Result is volatile (e.g. NOW() function).
+const sal_uInt8 FUNCFLAG_IMPORTONLY = 0x02; /// Only used in import filter.
+const sal_uInt8 FUNCFLAG_EXPORTONLY = 0x04; /// Only used in export filter.
+const sal_uInt8 FUNCFLAG_MACROCALL = 0x08; /// Function is simulated by macro call in Excel.
+const sal_uInt8 FUNCFLAG_EXTERNAL = 0x10; /// Function is external in Calc.
+
+typedef ::boost::shared_ptr< FunctionInfo > FunctionInfoRef;
+
+struct FunctionData
+{
+ const sal_Char* mpcOdfFuncName; /// ODF function name.
+ const sal_Char* mpcOoxFuncName; /// OOXML function name.
+ sal_uInt16 mnOobFuncId; /// OOBIN function identifier.
+ sal_uInt16 mnBiffFuncId; /// BIFF function identifier.
+ sal_uInt8 mnMinParamCount; /// Minimum number of parameters.
+ sal_uInt8 mnMaxParamCount; /// Maximum number of parameters.
+ sal_uInt8 mnRetClass; /// BIFF token class of the return value.
+ sal_uInt8 mpnParamClass[ FUNCINFO_CLASSCOUNT ]; /// Expected BIFF token classes of parameters.
+ sal_uInt8 mnFlags; /// Additional flags.
+
+ inline bool isSupported( bool bImportFilter ) const;
+};
+
+inline bool FunctionData::isSupported( bool bImportFilter ) const
+{
+ /* For import filters: the FUNCFLAG_EXPORTONLY flag must not be set,
+ for export filters: the FUNCFLAG_IMPORTONLY flag must not be set. */
+ return !getFlag( mnFlags, bImportFilter ? FUNCFLAG_EXPORTONLY : FUNCFLAG_IMPORTONLY );
+}
+
+const sal_uInt8 R = BIFF_TOKCLASS_REF;
+const sal_uInt8 V = BIFF_TOKCLASS_VAL;
+const sal_uInt8 A = BIFF_TOKCLASS_ARR;
+const sal_uInt8 ER = FUNCINFO_PARAM_EXCELONLY | BIFF_TOKCLASS_REF;
+const sal_uInt8 EV = FUNCINFO_PARAM_EXCELONLY | BIFF_TOKCLASS_VAL;
+const sal_uInt8 EA = FUNCINFO_PARAM_EXCELONLY | BIFF_TOKCLASS_ARR;
+const sal_uInt8 C = FUNCINFO_PARAM_CALCONLY;
+const sal_uInt8 I = FUNCINFO_PARAM_INVALID;
+const sal_uInt16 NOID = SAL_MAX_UINT16;
+const sal_uInt8 MX = SAL_MAX_UINT8;
+
+/** Functions new in BIFF2. */
+static const FunctionData saFuncTableBiff2[] =
+{
+ { "COUNT", "COUNT", 0, 0, 0, MX, V, { R }, 0 },
+ { "IF", "IF", 1, 1, 2, 3, R, { V, R }, 0 },
+ { "ISNA", "ISNA", 2, 2, 1, 1, V, { V }, 0 },
+ { "ISERROR", "ISERROR", 3, 3, 1, 1, V, { V }, 0 },
+ { "SUM", "SUM", 4, 4, 0, MX, V, { R }, 0 },
+ { "AVERAGE", "AVERAGE", 5, 5, 1, MX, V, { R }, 0 },
+ { "MIN", "MIN", 6, 6, 1, MX, V, { R }, 0 },
+ { "MAX", "MAX", 7, 7, 1, MX, V, { R }, 0 },
+ { "ROW", "ROW", 8, 8, 0, 1, V, { R }, 0 },
+ { "COLUMN", "COLUMN", 9, 9, 0, 1, V, { R }, 0 },
+ { "NA", "NA", 10, 10, 0, 0, V, {}, 0 },
+ { "NPV", "NPV", 11, 11, 2, MX, V, { V, R }, 0 },
+ { "STDEV", "STDEV", 12, 12, 1, MX, V, { R }, 0 },
+ { "DOLLAR", "DOLLAR", 13, 13, 1, 2, V, { V }, 0 },
+ { "FIXED", "FIXED", 14, 14, 1, 2, V, { V, V, C, I }, 0 },
+ { "SIN", "SIN", 15, 15, 1, 1, V, { V }, 0 },
+ { "COS", "COS", 16, 16, 1, 1, V, { V }, 0 },
+ { "TAN", "TAN", 17, 17, 1, 1, V, { V }, 0 },
+ { "COT", "TAN", 17, 17, 1, 1, V, { V }, FUNCFLAG_EXPORTONLY },
+ { "ATAN", "ATAN", 18, 18, 1, 1, V, { V }, 0 },
+ { "ACOT", "ATAN", 18, 18, 1, 1, V, { V }, FUNCFLAG_EXPORTONLY },
+ { "PI", "PI", 19, 19, 0, 0, V, {}, 0 },
+ { "SQRT", "SQRT", 20, 20, 1, 1, V, { V }, 0 },
+ { "EXP", "EXP", 21, 21, 1, 1, V, { V }, 0 },
+ { "LN", "LN", 22, 22, 1, 1, V, { V }, 0 },
+ { "LOG10", "LOG10", 23, 23, 1, 1, V, { V }, 0 },
+ { "ABS", "ABS", 24, 24, 1, 1, V, { V }, 0 },
+ { "INT", "INT", 25, 25, 1, 1, V, { V }, 0 },
+ { "SIGN", "SIGN", 26, 26, 1, 1, V, { V }, 0 },
+ { "ROUND", "ROUND", 27, 27, 2, 2, V, { V }, 0 },
+ { "LOOKUP", "LOOKUP", 28, 28, 2, 3, V, { V, R }, 0 },
+ { "INDEX", "INDEX", 29, 29, 2, 4, R, { R, V }, 0 },
+ { "REPT", "REPT", 30, 30, 2, 2, V, { V }, 0 },
+ { "MID", "MID", 31, 31, 3, 3, V, { V }, 0 },
+ { "LEN", "LEN", 32, 32, 1, 1, V, { V }, 0 },
+ { "VALUE", "VALUE", 33, 33, 1, 1, V, { V }, 0 },
+ { "TRUE", "TRUE", 34, 34, 0, 0, V, {}, 0 },
+ { "FALSE", "FALSE", 35, 35, 0, 0, V, {}, 0 },
+ { "AND", "AND", 36, 36, 1, MX, V, { R }, 0 },
+ { "OR", "OR", 37, 37, 1, MX, V, { R }, 0 },
+ { "NOT", "NOT", 38, 38, 1, 1, V, { V }, 0 },
+ { "MOD", "MOD", 39, 39, 2, 2, V, { V }, 0 },
+ { "DCOUNT", "DCOUNT", 40, 40, 3, 3, V, { R }, 0 },
+ { "DSUM", "DSUM", 41, 41, 3, 3, V, { R }, 0 },
+ { "DAVERAGE", "DAVERAGE", 42, 42, 3, 3, V, { R }, 0 },
+ { "DMIN", "DMIN", 43, 43, 3, 3, V, { R }, 0 },
+ { "DMAX", "DMAX", 44, 44, 3, 3, V, { R }, 0 },
+ { "DSTDEV", "DSTDEV", 45, 45, 3, 3, V, { R }, 0 },
+ { "VAR", "VAR", 46, 46, 1, MX, V, { R }, 0 },
+ { "DVAR", "DVAR", 47, 47, 3, 3, V, { R }, 0 },
+ { "TEXT", "TEXT", 48, 48, 2, 2, V, { V }, 0 },
+ { "LINEST", "LINEST", 49, 49, 1, 2, A, { R, R, C, C, I }, 0 },
+ { "TREND", "TREND", 50, 50, 1, 3, A, { R, R, R, C, I }, 0 },
+ { "LOGEST", "LOGEST", 51, 51, 1, 2, A, { R, R, C, C, I }, 0 },
+ { "GROWTH", "GROWTH", 52, 52, 1, 3, A, { R, R, R, C, I }, 0 },
+ { "PV", "PV", 56, 56, 3, 5, V, { V }, 0 },
+ { "FV", "FV", 57, 57, 3, 5, V, { V }, 0 },
+ { "NPER", "NPER", 58, 58, 3, 5, V, { V }, 0 },
+ { "PMT", "PMT", 59, 59, 3, 5, V, { V }, 0 },
+ { "RATE", "RATE", 60, 60, 3, 6, V, { V }, 0 },
+ { "MIRR", "MIRR", 61, 61, 3, 3, V, { R, V }, 0 },
+ { "IRR", "IRR", 62, 62, 1, 2, V, { R, V }, 0 },
+ { "RAND", "RAND", 63, 63, 0, 0, V, {}, FUNCFLAG_VOLATILE },
+ { "MATCH", "MATCH", 64, 64, 2, 3, V, { V, R }, 0 },
+ { "DATE", "DATE", 65, 65, 3, 3, V, { V }, 0 },
+ { "TIME", "TIME", 66, 66, 3, 3, V, { V }, 0 },
+ { "DAY", "DAY", 67, 67, 1, 1, V, { V }, 0 },
+ { "MONTH", "MONTH", 68, 68, 1, 1, V, { V }, 0 },
+ { "YEAR", "YEAR", 69, 69, 1, 1, V, { V }, 0 },
+ { "WEEKDAY", "WEEKDAY", 70, 70, 1, 1, V, { V, C, I }, 0 },
+ { "HOUR", "HOUR", 71, 71, 1, 1, V, { V }, 0 },
+ { "MINUTE", "MINUTE", 72, 72, 1, 1, V, { V }, 0 },
+ { "SECOND", "SECOND", 73, 73, 1, 1, V, { V }, 0 },
+ { "NOW", "NOW", 74, 74, 0, 0, V, {}, FUNCFLAG_VOLATILE },
+ { "AREAS", "AREAS", 75, 75, 1, 1, V, { R }, 0 },
+ { "ROWS", "ROWS", 76, 76, 1, 1, V, { R }, 0 },
+ { "COLUMNS", "COLUMNS", 77, 77, 1, 1, V, { R }, 0 },
+ { "OFFSET", "OFFSET", 78, 78, 3, 5, R, { R, V }, FUNCFLAG_VOLATILE },
+ { "SEARCH", "SEARCH", 82, 82, 2, 3, V, { V }, 0 },
+ { "TRANSPOSE", "TRANSPOSE", 83, 83, 1, 1, A, { A }, 0 },
+ { "TYPE", "TYPE", 86, 86, 1, 1, V, { V }, 0 },
+ { "ATAN2", "ATAN2", 97, 97, 2, 2, V, { V }, 0 },
+ { "ASIN", "ASIN", 98, 98, 1, 1, V, { V }, 0 },
+ { "ACOS", "ACOS", 99, 99, 1, 1, V, { V }, 0 },
+ { "CHOOSE", "CHOOSE", 100, 100, 2, MX, R, { V, R }, 0 },
+ { "HLOOKUP", "HLOOKUP", 101, 101, 3, 3, V, { V, R, R, C, I }, 0 },
+ { "VLOOKUP", "VLOOKUP", 102, 102, 3, 3, V, { V, R, R, C, I }, 0 },
+ { "ISREF", "ISREF", 105, 105, 1, 1, V, { R }, 0 },
+ { "LOG", "LOG", 109, 109, 1, 2, V, { V }, 0 },
+ { "CHAR", "CHAR", 111, 111, 1, 1, V, { V }, 0 },
+ { "LOWER", "LOWER", 112, 112, 1, 1, V, { V }, 0 },
+ { "UPPER", "UPPER", 113, 113, 1, 1, V, { V }, 0 },
+ { "PROPER", "PROPER", 114, 114, 1, 1, V, { V }, 0 },
+ { "LEFT", "LEFT", 115, 115, 1, 2, V, { V }, 0 },
+ { "RIGHT", "RIGHT", 116, 116, 1, 2, V, { V }, 0 },
+ { "EXACT", "EXACT", 117, 117, 2, 2, V, { V }, 0 },
+ { "TRIM", "TRIM", 118, 118, 1, 1, V, { V }, 0 },
+ { "REPLACE", "REPLACE", 119, 119, 4, 4, V, { V }, 0 },
+ { "SUBSTITUTE", "SUBSTITUTE", 120, 120, 3, 4, V, { V }, 0 },
+ { "CODE", "CODE", 121, 121, 1, 1, V, { V }, 0 },
+ { "FIND", "FIND", 124, 124, 2, 3, V, { V }, 0 },
+ { "CELL", "CELL", 125, 125, 1, 2, V, { V, R }, FUNCFLAG_VOLATILE },
+ { "ISERR", "ISERR", 126, 126, 1, 1, V, { V }, 0 },
+ { "ISTEXT", "ISTEXT", 127, 127, 1, 1, V, { V }, 0 },
+ { "ISNUMBER", "ISNUMBER", 128, 128, 1, 1, V, { V }, 0 },
+ { "ISBLANK", "ISBLANK", 129, 129, 1, 1, V, { V }, 0 },
+ { "T", "T", 130, 130, 1, 1, V, { R }, 0 },
+ { "N", "N", 131, 131, 1, 1, V, { R }, 0 },
+ { "DATEVALUE", "DATEVALUE", 140, 140, 1, 1, V, { V }, 0 },
+ { "TIMEVALUE", "TIMEVALUE", 141, 141, 1, 1, V, { V }, 0 },
+ { "SLN", "SLN", 142, 142, 3, 3, V, { V }, 0 },
+ { "SYD", "SYD", 143, 143, 4, 4, V, { V }, 0 },
+ { "DDB", "DDB", 144, 144, 4, 5, V, { V }, 0 },
+ { "INDIRECT", "INDIRECT", 148, 148, 1, 2, R, { V, EV, I }, FUNCFLAG_VOLATILE },
+ { "CLEAN", "CLEAN", 162, 162, 1, 1, V, { V }, 0 },
+ { "MDETERM", "MDETERM", 163, 163, 1, 1, V, { A }, 0 },
+ { "MINVERSE", "MINVERSE", 164, 164, 1, 1, A, { A }, 0 },
+ { "MMULT", "MMULT", 165, 165, 2, 2, A, { A }, 0 },
+ { "IPMT", "IPMT", 167, 167, 4, 6, V, { V }, 0 },
+ { "PPMT", "PPMT", 168, 168, 4, 6, V, { V }, 0 },
+ { "COUNTA", "COUNTA", 169, 169, 0, MX, V, { R }, 0 },
+ { "PRODUCT", "PRODUCT", 183, 183, 0, MX, V, { R }, 0 },
+ { "FACT", "FACT", 184, 184, 1, 1, V, { V }, 0 },
+ { "DPRODUCT", "DPRODUCT", 189, 189, 3, 3, V, { R }, 0 },
+ { "ISNONTEXT", "ISNONTEXT", 190, 190, 1, 1, V, { V }, 0 },
+ { "STDEVP", "STDEVP", 193, 193, 1, MX, V, { R }, 0 },
+ { "VARP", "VARP", 194, 194, 1, MX, V, { R }, 0 },
+ { "DSTDEVP", "DSTDEVP", 195, 195, 3, 3, V, { R }, 0 },
+ { "DVARP", "DVARP", 196, 196, 3, 3, V, { R }, 0 },
+ { "TRUNC", "TRUNC", 197, 197, 1, 1, V, { V, C, I }, 0 },
+ { "ISLOGICAL", "ISLOGICAL", 198, 198, 1, 1, V, { V }, 0 },
+ { "DCOUNTA", "DCOUNTA", 199, 199, 3, 3, V, { R }, 0 },
+ { 0, 0, 255, 255, 1, MX, R, { ER, R }, FUNCFLAG_IMPORTONLY } // EXTERNAL
+};
+
+/** Functions new in BIFF3. */
+static const FunctionData saFuncTableBiff3[] =
+{
+ { "LINEST", "LINEST", 49, 49, 1, 4, A, { R, R, V, V }, 0 }, // BIFF2: 1-2, BIFF3: 1-4,
+ { "TREND", "TREND", 50, 50, 1, 4, A, { R, R, R, V }, 0 }, // BIFF2: 1-3, BIFF3: 1-4
+ { "LOGEST", "LOGEST", 51, 51, 1, 4, A, { R, R, V, V }, 0 }, // BIFF2: 1-2, BIFF3: 1-4,
+ { "GROWTH", "GROWTH", 52, 52, 1, 4, A, { R, R, R, V }, 0 }, // BIFF2: 1-3, BIFF3: 1-4
+ { "TRUNC", "TRUNC", 197, 197, 1, 2, V, { V }, 0 }, // BIFF2: 1, BIFF3: 1-2
+ { "DOLLAR", "USDOLLAR", 204, 204, 1, 2, V, { V }, FUNCFLAG_IMPORTONLY },
+ { 0/*"FIND"*/, "FINDB", 205, 205, 2, 3, V, { V }, 0 },
+ { 0/*"SEARCH"*/, "SEARCHB", 206, 206, 2, 3, V, { V }, 0 },
+ { 0/*"REPLACE"*/, "REPLACEB", 207, 207, 4, 4, V, { V }, 0 },
+ { 0/*"LEFT"*/, "LEFTB", 208, 208, 1, 2, V, { V }, 0 },
+ { 0/*"RIGHT"*/, "RIGHTB", 209, 209, 1, 2, V, { V }, 0 },
+ { 0/*"MID"*/, "MIDB", 210, 210, 3, 3, V, { V }, 0 },
+ { 0/*"LEN"*/, "LENB", 211, 211, 1, 1, V, { V }, 0 },
+ { "ROUNDUP", "ROUNDUP", 212, 212, 2, 2, V, { V }, 0 },
+ { "ROUNDDOWN", "ROUNDDOWN", 213, 213, 2, 2, V, { V }, 0 },
+ { "ASC", "ASC", 214, 214, 1, 1, V, { V }, 0 },
+ { "JIS", "DBCS", 215, 215, 1, 1, V, { V }, 0 },
+ { "ADDRESS", "ADDRESS", 219, 219, 2, 5, V, { V, V, V, EV, V }, 0 },
+ { "DAYS360", "DAYS360", 220, 220, 2, 2, V, { V, V, C, I }, 0 },
+ { "TODAY", "TODAY", 221, 221, 0, 0, V, {}, FUNCFLAG_VOLATILE },
+ { "VDB", "VDB", 222, 222, 5, 7, V, { V }, 0 },
+ { "MEDIAN", "MEDIAN", 227, 227, 1, MX, V, { R }, 0 },
+ { "SUMPRODUCT", "SUMPRODUCT", 228, 228, 1, MX, V, { A }, 0 },
+ { "SINH", "SINH", 229, 229, 1, 1, V, { V }, 0 },
+ { "COSH", "COSH", 230, 230, 1, 1, V, { V }, 0 },
+ { "TANH", "TANH", 231, 231, 1, 1, V, { V }, 0 },
+ { "COTH", "TANH", 231, 231, 1, 1, V, { V }, FUNCFLAG_EXPORTONLY },
+ { "ASINH", "ASINH", 232, 232, 1, 1, V, { V }, 0 },
+ { "ACOSH", "ACOSH", 233, 233, 1, 1, V, { V }, 0 },
+ { "ATANH", "ATANH", 234, 234, 1, 1, V, { V }, 0 },
+ { "ACOTH", "ATANH", 234, 234, 1, 1, V, { V }, FUNCFLAG_EXPORTONLY },
+ { "DGET", "DGET", 235, 235, 3, 3, V, { R }, 0 },
+ { "INFO", "INFO", 244, 244, 1, 1, V, { V }, FUNCFLAG_VOLATILE }
+};
+
+/** Functions new in BIFF4. */
+static const FunctionData saFuncTableBiff4[] =
+{
+ { "FIXED", "FIXED", 14, 14, 1, 3, V, { V }, 0 }, // BIFF2-3: 1-2, BIFF4: 1-3
+ { "RANK", "RANK", 216, 216, 2, 3, V, { V, R, V }, 0 },
+ { "DB", "DB", 247, 247, 4, 5, V, { V }, 0 },
+ { "FREQUENCY", "FREQUENCY", 252, 252, 2, 2, A, { R }, 0 },
+ { "ERROR.TYPE", "ERROR.TYPE", 261, 261, 1, 1, V, { V }, 0 },
+ { "AVEDEV", "AVEDEV", 269, 269, 1, MX, V, { R }, 0 },
+ { "BETADIST", "BETADIST", 270, 270, 3, 5, V, { V }, 0 },
+ { "GAMMALN", "GAMMALN", 271, 271, 1, 1, V, { V }, 0 },
+ { "BETAINV", "BETAINV", 272, 272, 3, 5, V, { V }, 0 },
+ { "BINOMDIST", "BINOMDIST", 273, 273, 4, 4, V, { V }, 0 },
+ { "LEGACY.CHIDIST", "CHIDIST", 274, 274, 2, 2, V, { V }, 0 },
+ { "LEGACY.CHIINV", "CHIINV", 275, 275, 2, 2, V, { V }, 0 },
+ { "COMBIN", "COMBIN", 276, 276, 2, 2, V, { V }, 0 },
+ { "CONFIDENCE", "CONFIDENCE", 277, 277, 3, 3, V, { V }, 0 },
+ { "CRITBINOM", "CRITBINOM", 278, 278, 3, 3, V, { V }, 0 },
+ { "EVEN", "EVEN", 279, 279, 1, 1, V, { V }, 0 },
+ { "EXPONDIST", "EXPONDIST", 280, 280, 3, 3, V, { V }, 0 },
+ { "LEGACY.FDIST", "FDIST", 281, 281, 3, 3, V, { V }, 0 },
+ { "LEGACY.FINV", "FINV", 282, 282, 3, 3, V, { V }, 0 },
+ { "FISHER", "FISHER", 283, 283, 1, 1, V, { V }, 0 },
+ { "FISHERINV", "FISHERINV", 284, 284, 1, 1, V, { V }, 0 },
+ { "FLOOR", "FLOOR", 285, 285, 2, 2, V, { V, V, C, I }, 0 },
+ { "GAMMADIST", "GAMMADIST", 286, 286, 4, 4, V, { V }, 0 },
+ { "GAMMAINV", "GAMMAINV", 287, 287, 3, 3, V, { V }, 0 },
+ { "CEILING", "CEILING", 288, 288, 2, 2, V, { V, V, C, I }, 0 },
+ { "HYPGEOMDIST", "HYPGEOMDIST", 289, 289, 4, 4, V, { V }, 0 },
+ { "LOGNORMDIST", "LOGNORMDIST", 290, 290, 3, 3, V, { V }, 0 },
+ { "LOGINV", "LOGINV", 291, 291, 3, 3, V, { V }, 0 },
+ { "NEGBINOMDIST", "NEGBINOMDIST", 292, 292, 3, 3, V, { V }, 0 },
+ { "NORMDIST", "NORMDIST", 293, 293, 4, 4, V, { V }, 0 },
+ { "LEGACY.NORMSDIST", "NORMSDIST", 294, 294, 1, 1, V, { V }, 0 },
+ { "NORMINV", "NORMINV", 295, 295, 3, 3, V, { V }, 0 },
+ { "LEGACY.NORMSINV", "NORMSINV", 296, 296, 1, 1, V, { V }, 0 },
+ { "STANDARDIZE", "STANDARDIZE", 297, 297, 3, 3, V, { V }, 0 },
+ { "ODD", "ODD", 298, 298, 1, 1, V, { V }, 0 },
+ { "PERMUT", "PERMUT", 299, 299, 2, 2, V, { V }, 0 },
+ { "POISSON", "POISSON", 300, 300, 3, 3, V, { V }, 0 },
+ { "TDIST", "TDIST", 301, 301, 3, 3, V, { V }, 0 },
+ { "WEIBULL", "WEIBULL", 302, 302, 4, 4, V, { V }, 0 },
+ { "SUMXMY2", "SUMXMY2", 303, 303, 2, 2, V, { A }, 0 },
+ { "SUMX2MY2", "SUMX2MY2", 304, 304, 2, 2, V, { A }, 0 },
+ { "SUMX2PY2", "SUMX2PY2", 305, 305, 2, 2, V, { A }, 0 },
+ { "LEGACY.CHITEST", "CHITEST", 306, 306, 2, 2, V, { A }, 0 },
+ { "CORREL", "CORREL", 307, 307, 2, 2, V, { A }, 0 },
+ { "COVAR", "COVAR", 308, 308, 2, 2, V, { A }, 0 },
+ { "FORECAST", "FORECAST", 309, 309, 3, 3, V, { V, A }, 0 },
+ { "FTEST", "FTEST", 310, 310, 2, 2, V, { A }, 0 },
+ { "INTERCEPT", "INTERCEPT", 311, 311, 2, 2, V, { A }, 0 },
+ { "PEARSON", "PEARSON", 312, 312, 2, 2, V, { A }, 0 },
+ { "RSQ", "RSQ", 313, 313, 2, 2, V, { A }, 0 },
+ { "STEYX", "STEYX", 314, 314, 2, 2, V, { A }, 0 },
+ { "SLOPE", "SLOPE", 315, 315, 2, 2, V, { A }, 0 },
+ { "TTEST", "TTEST", 316, 316, 4, 4, V, { A, A, V }, 0 },
+ { "PROB", "PROB", 317, 317, 3, 4, V, { A, A, V }, 0 },
+ { "DEVSQ", "DEVSQ", 318, 318, 1, MX, V, { R }, 0 },
+ { "GEOMEAN", "GEOMEAN", 319, 319, 1, MX, V, { R }, 0 },
+ { "HARMEAN", "HARMEAN", 320, 320, 1, MX, V, { R }, 0 },
+ { "SUMSQ", "SUMSQ", 321, 321, 0, MX, V, { R }, 0 },
+ { "KURT", "KURT", 322, 322, 1, MX, V, { R }, 0 },
+ { "SKEW", "SKEW", 323, 323, 1, MX, V, { R }, 0 },
+ { "ZTEST", "ZTEST", 324, 324, 2, 3, V, { R, V }, 0 },
+ { "LARGE", "LARGE", 325, 325, 2, 2, V, { R, V }, 0 },
+ { "SMALL", "SMALL", 326, 326, 2, 2, V, { R, V }, 0 },
+ { "QUARTILE", "QUARTILE", 327, 327, 2, 2, V, { R, V }, 0 },
+ { "PERCENTILE", "PERCENTILE", 328, 328, 2, 2, V, { R, V }, 0 },
+ { "PERCENTRANK", "PERCENTRANK", 329, 329, 2, 3, V, { R, V, EV, I }, 0 },
+ { "MODE", "MODE", 330, 330, 1, MX, V, { A }, 0 },
+ { "TRIMMEAN", "TRIMMEAN", 331, 331, 2, 2, V, { R, V }, 0 },
+ { "TINV", "TINV", 332, 332, 2, 2, V, { V }, 0 },
+
+ // *** Analysis add-in ***
+
+ { "HEX2BIN", "HEX2BIN", 384, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "HEX2DEC", "HEX2DEC", 385, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "HEX2OCT", "HEX2OCT", 386, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "DEC2BIN", "DEC2BIN", 387, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "DEC2HEX", "DEC2HEX", 388, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "DEC2OCT", "DEC2OCT", 389, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "OCT2BIN", "OCT2BIN", 390, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "OCT2HEX", "OCT2HEX", 391, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "OCT2DEC", "OCT2DEC", 392, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "BIN2DEC", "BIN2DEC", 393, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "BIN2OCT", "BIN2OCT", 394, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "BIN2HEX", "BIN2HEX", 395, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMSUB", "IMSUB", 396, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMDIV", "IMDIV", 397, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMPOWER", "IMPOWER", 398, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMABS", "IMABS", 399, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMSQRT", "IMSQRT", 400, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMLN", "IMLN", 401, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMLOG2", "IMLOG2", 402, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMLOG10", "IMLOG10", 403, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMSIN", "IMSIN", 404, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMCOS", "IMCOS", 405, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMEXP", "IMEXP", 406, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMARGUMENT", "IMARGUMENT", 407, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMCONJUGATE", "IMCONJUGATE", 408, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMAGINARY", "IMAGINARY", 409, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMREAL", "IMREAL", 410, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "COMPLEX", "COMPLEX", 411, NOID, 2, 3, V, { V }, FUNCFLAG_EXTERNAL },
+ { "IMSUM", "IMSUM", 412, NOID, 1, MX, V, { R }, FUNCFLAG_EXTERNAL },
+ { "IMPRODUCT", "IMPRODUCT", 413, NOID, 1, MX, V, { R }, FUNCFLAG_EXTERNAL },
+ { "SERIESSUM", "SERIESSUM", 414, NOID, 4, 4, V, { V, V, V, R }, FUNCFLAG_EXTERNAL },
+ { "FACTDOUBLE", "FACTDOUBLE", 415, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "SQRTPI", "SQRTPI", 416, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "QUOTIENT", "QUOTIENT", 417, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "DELTA", "DELTA", 418, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "GESTEP", "GESTEP", 419, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "ISEVEN", "ISEVEN", 420, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "ISODD", "ISODD", 421, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "MROUND", "MROUND", 422, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "ERF", "ERF", 423, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "ERFC", "ERFC", 424, NOID, 1, 1, V, { V }, FUNCFLAG_EXTERNAL },
+ { "BESSELJ", "BESSELJ", 425, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "BESSELK", "BESSELK", 426, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "BESSELY", "BESSELY", 427, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "BESSELI", "BESSELI", 428, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "XIRR", "XIRR", 429, NOID, 2, 3, V, { A, R, V }, FUNCFLAG_EXTERNAL },
+ { "XNPV", "XNPV", 430, NOID, 3, 3, V, { V, A, R }, FUNCFLAG_EXTERNAL },
+ { "PRICEMAT", "PRICEMAT", 431, NOID, 5, 6, V, { V }, FUNCFLAG_EXTERNAL },
+ { "YIELDMAT", "YIELDMAT", 432, NOID, 5, 6, V, { V }, FUNCFLAG_EXTERNAL },
+ { "INTRATE", "INTRATE", 433, NOID, 4, 5, V, { V }, FUNCFLAG_EXTERNAL },
+ { "RECEIVED", "RECEIVED", 434, NOID, 4, 5, V, { V }, FUNCFLAG_EXTERNAL },
+ { "DISC", "DISC", 435, NOID, 4, 5, V, { V }, FUNCFLAG_EXTERNAL },
+ { "PRICEDISC", "PRICEDISC", 436, NOID, 4, 5, V, { V }, FUNCFLAG_EXTERNAL },
+ { "YIELDDISC", "YIELDDISC", 437, NOID, 4, 5, V, { V }, FUNCFLAG_EXTERNAL },
+ { "TBILLEQ", "TBILLEQ", 438, NOID, 3, 3, V, { V }, FUNCFLAG_EXTERNAL },
+ { "TBILLPRICE", "TBILLPRICE", 439, NOID, 3, 3, V, { V }, FUNCFLAG_EXTERNAL },
+ { "TBILLYIELD", "TBILLYIELD", 440, NOID, 3, 3, V, { V }, FUNCFLAG_EXTERNAL },
+ { "PRICE", "PRICE", 441, NOID, 6, 7, V, { V }, FUNCFLAG_EXTERNAL },
+ { "YIELD", "YIELD", 442, NOID, 6, 7, V, { V }, FUNCFLAG_EXTERNAL },
+ { "DOLLARDE", "DOLLARDE", 443, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "DOLLARFR", "DOLLARFR", 444, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "NOMINAL", "NOMINAL", 445, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "EFFECT", "EFFECT", 446, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "CUMPRINC", "CUMPRINC", 447, NOID, 6, 6, V, { V }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "CUMIPMT", "CUMIPMT", 448, NOID, 6, 6, V, { V }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "EDATE", "EDATE", 449, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "EOMONTH", "EOMONTH", 450, NOID, 2, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "YEARFRAC", "YEARFRAC", 451, NOID, 2, 3, V, { V }, FUNCFLAG_EXTERNAL },
+ { "COUPDAYBS", "COUPDAYBS", 452, NOID, 3, 4, V, { V }, FUNCFLAG_EXTERNAL },
+ { "COUPDAYS", "COUPDAYS", 453, NOID, 3, 4, V, { V }, FUNCFLAG_EXTERNAL },
+ { "COUPDAYSNC", "COUPDAYSNC", 454, NOID, 3, 4, V, { V }, FUNCFLAG_EXTERNAL },
+ { "COUPNCD", "COUPNCD", 455, NOID, 3, 4, V, { V }, FUNCFLAG_EXTERNAL },
+ { "COUPNUM", "COUPNUM", 456, NOID, 3, 4, V, { V }, FUNCFLAG_EXTERNAL },
+ { "COUPPCD", "COUPPCD", 457, NOID, 3, 4, V, { V }, FUNCFLAG_EXTERNAL },
+ { "DURATION", "DURATION", 458, NOID, 5, 6, V, { V }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "MDURATION", "MDURATION", 459, NOID, 5, 6, V, { V }, FUNCFLAG_EXTERNAL },
+ { "ODDLPRICE", "ODDLPRICE", 460, NOID, 7, 8, V, { V }, FUNCFLAG_EXTERNAL },
+ { "ODDLYIELD", "ODDLYIELD", 461, NOID, 8, 9, V, { V }, FUNCFLAG_EXTERNAL },
+ { "ODDFPRICE", "ODDFPRICE", 462, NOID, 8, 9, V, { V }, FUNCFLAG_EXTERNAL },
+ { "ODDFYIELD", "ODDFYIELD", 463, NOID, 8, 9, V, { V }, FUNCFLAG_EXTERNAL },
+ { "RANDBETWEEN", "RANDBETWEEN", 464, NOID, 2, 2, V, {}, FUNCFLAG_VOLATILE | FUNCFLAG_EXTERNAL },
+ { "WEEKNUM", "WEEKNUM", 465, NOID, 1, 2, V, { V }, FUNCFLAG_EXTERNAL },
+ { "AMORDEGRC", "AMORDEGRC", 466, NOID, 6, 7, V, { V }, FUNCFLAG_EXTERNAL },
+ { "AMORLINC", "AMORLINC", 467, NOID, 6, 7, V, { V }, FUNCFLAG_EXTERNAL },
+ { "CONVERT", "CONVERT", 468, NOID, 3, 3, V, { V }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "ACCRINT", "ACCRINT", 469, NOID, 6, 7, V, { V }, FUNCFLAG_EXTERNAL },
+ { "ACCRINTM", "ACCRINTM", 470, NOID, 4, 5, V, { V }, FUNCFLAG_EXTERNAL },
+ { "WORKDAY", "WORKDAY", 471, NOID, 2, 3, V, { V, V, A, C, I }, FUNCFLAG_EXTERNAL },
+ { "NETWORKDAYS", "NETWORKDAYS", 472, NOID, 2, 3, V, { V, V, A, C, I }, FUNCFLAG_EXTERNAL },
+ { "GCD", "GCD", 473, NOID, 1, MX, V, { R }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "MULTINOMIAL", "MULTINOMIAL", 474, NOID, 1, MX, V, { R }, FUNCFLAG_EXTERNAL },
+ { "LCM", "LCM", 475, NOID, 1, MX, V, { R }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "FVSCHEDULE", "FVSCHEDULE", 476, NOID, 2, 2, V, { V, A }, FUNCFLAG_EXTERNAL }
+// { "EUROCONVERT", "EUROCONVERT", NOID, NOID, 3, 5, V, { V }, FUNCFLAG_EXTERNAL }, // Euro conversion add-in
+};
+
+/** Functions new in BIFF5/BIFF7. */
+static const FunctionData saFuncTableBiff5[] =
+{
+ { "WEEKDAY", "WEEKDAY", 70, 70, 1, 2, V, { V }, 0 }, // BIFF2-4: 1, BIFF5: 1-2
+ { "HLOOKUP", "HLOOKUP", 101, 101, 3, 4, V, { V, R, R, V }, 0 }, // BIFF2-4: 3, BIFF5: 3-4
+ { "VLOOKUP", "VLOOKUP", 102, 102, 3, 4, V, { V, R, R, V }, 0 }, // BIFF2-4: 3, BIFF5: 3-4
+ { "DAYS360", "DAYS360", 220, 220, 2, 3, V, { V }, 0 }, // BIFF3-4: 2, BIFF5: 2-3
+ { 0, 0, 255, 255, 1, MX, R, { ER, R }, FUNCFLAG_EXPORTONLY }, // MACRO or EXTERNAL
+ { "CONCATENATE", "CONCATENATE", 336, 336, 0, MX, V, { V }, 0 },
+ { "POWER", "POWER", 337, 337, 2, 2, V, { V }, 0 },
+ { "RADIANS", "RADIANS", 342, 342, 1, 1, V, { V }, 0 },
+ { "DEGREES", "DEGREES", 343, 343, 1, 1, V, { V }, 0 },
+ { "SUBTOTAL", "SUBTOTAL", 344, 344, 2, MX, V, { V, R }, 0 },
+ { "SUMIF", "SUMIF", 345, 345, 2, 3, V, { R, V, R }, 0 },
+ { "COUNTIF", "COUNTIF", 346, 346, 2, 2, V, { R, V }, 0 },
+ { "COUNTBLANK", "COUNTBLANK", 347, 347, 1, 1, V, { R }, 0 },
+ { "ISPMT", "ISPMT", 350, 350, 4, 4, V, { V }, 0 },
+ { 0, "DATEDIF", 351, 351, 3, 3, V, { V }, FUNCFLAG_IMPORTONLY }, // not supported in Calc
+ { 0, "DATESTRING", 352, 352, 1, 1, V, { V }, FUNCFLAG_IMPORTONLY }, // not supported in Calc, missing in OOX spec
+ { 0, "NUMBERSTRING", 353, 353, 2, 2, V, { V }, FUNCFLAG_IMPORTONLY }, // not supported in Calc, missing in OOX spec
+ { "ROMAN", "ROMAN", 354, 354, 1, 2, V, { V }, 0 }
+};
+
+/** Functions new in BIFF8. */
+static const FunctionData saFuncTableBiff8[] =
+{
+ { "GETPIVOTDATA", "GETPIVOTDATA", 358, 358, 2, MX, V, { V, R, V }, FUNCFLAG_IMPORTONLY },
+ { "HYPERLINK", "HYPERLINK", 359, 359, 1, 2, V, { V }, 0 },
+ { 0, "PHONETIC", 360, 360, 1, 1, V, { R }, FUNCFLAG_IMPORTONLY },
+ { "AVERAGEA", "AVERAGEA", 361, 361, 1, MX, V, { R }, 0 },
+ { "MAXA", "MAXA", 362, 362, 1, MX, V, { R }, 0 },
+ { "MINA", "MINA", 363, 363, 1, MX, V, { R }, 0 },
+ { "STDEVPA", "STDEVPA", 364, 364, 1, MX, V, { R }, 0 },
+ { "VARPA", "VARPA", 365, 365, 1, MX, V, { R }, 0 },
+ { "STDEVA", "STDEVA", 366, 366, 1, MX, V, { R }, 0 },
+ { "VARA", "VARA", 367, 367, 1, MX, V, { R }, 0 },
+ { "COM.MICROSOFT.BAHTTEXT", "BAHTTEXT", 368, 368, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "THAIDAYOFWEEK", 369, 369, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "THAIDIGIT", 370, 370, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "THAIMONTHOFYEAR", 371, 371, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "THAINUMSOUND", 372, 372, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "THAINUMSTRING", 373, 373, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "THAISTRINGLENGTH", 374, 374, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "ISTHAIDIGIT", 375, 375, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "ROUNDBAHTDOWN", 376, 376, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "ROUNDBAHTUP", 377, 377, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "THAIYEAR", 378, 378, 1, 1, V, { V }, FUNCFLAG_MACROCALL },
+ { 0, "RTD", 379, 379, 3, 3, A, { V, V, R }, 0 }
+};
+
+/** Functions new in OOX. */
+static const FunctionData saFuncTableOox[] =
+{
+ { 0, "IFERROR", 480, NOID, 2, 2, V, { V, R }, 0 },
+ { 0, "COUNTIFS", 481, NOID, 3, MX, V, { R, V }, 0 },
+ { 0, "SUMIFS", 482, NOID, 3, MX, V, { R, V }, 0 },
+ { 0, "AVERAGEIF", 483, NOID, 2, 3, V, { R, V, R }, 0 },
+ { 0, "AVERAGEIFS", 484, NOID, 3, MX, V, { R, V }, 0 },
+ { 0, "CUBEKPIMEMBER", NOID, NOID, 3, 4, V, { V }, 0 },
+ { 0, "CUBEMEMBER", NOID, NOID, 2, 3, V, { V, A, V }, 0 },
+ { 0, "CUBEMEMBERPROPERTY",NOID, NOID, 3, 3, V, { V }, 0 },
+ { 0, "CUBERANKEDMEMBER", NOID, NOID, 3, 4, V, { V }, 0 },
+ { 0, "CUBESET", NOID, NOID, 2, 5, V, { V, R, V }, 0 },
+ { 0, "CUBESETCOUNT", NOID, NOID, 1, 1, V, { V }, 0 },
+ { 0, "CUBEVALUE", NOID, NOID, 2, 2, V, { V, R }, 0 }
+};
+
+/** Functions defined by OpenFormula, but not supported by Calc or by Excel. */
+static const FunctionData saFuncTableOdf[] =
+{
+ { "ARABIC", 0, NOID, NOID, 1, 1, V, { V }, 0 },
+ { "B", 0, NOID, NOID, 3, 4, V, { V }, 0 },
+ { "BASE", 0, NOID, NOID, 2, 3, V, { V }, 0 },
+ { "BITAND", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "BITLSHIFT", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "BITOR", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "BITRSHIFT", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "BITXOR", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "CHISQDIST", 0, NOID, NOID, 2, 3, V, { V }, 0 },
+ { "CHISQINV", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "COMBINA", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "DAYS", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "DDE", 0, NOID, NOID, 3, 4, V, { V }, 0 },
+ { "DECIMAL", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "FDIST", 0, NOID, NOID, 3, 4, V, { V }, 0 },
+ { "FINV", 0, NOID, NOID, 3, 3, V, { V }, 0 },
+ { "FORMULA", 0, NOID, NOID, 1, 1, V, { R }, 0 },
+ { "GAMMA", 0, NOID, NOID, 1, 1, V, { V }, 0 },
+ { "GAUSS", 0, NOID, NOID, 1, 1, V, { V }, 0 },
+ { "IFNA", 0, NOID, NOID, 2, 2, V, { V, R }, 0 },
+ { "ISFORMULA", 0, NOID, NOID, 1, 1, V, { R }, 0 },
+ { "ISOWEEKNUM", 0, NOID, NOID, 1, 2, V, { V }, 0 },
+ { "MULTIPLE.OPERATIONS", 0, NOID, NOID, 3, 5, V, { R }, 0 },
+ { "MUNIT", 0, NOID, NOID, 1, 1, A, { V }, 0 },
+ { "NUMBERVALUE", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "PDURATION", 0, NOID, NOID, 3, 3, V, { V }, 0 },
+ { "PERMUTATIONA", 0, NOID, NOID, 2, 2, V, { V }, 0 },
+ { "PHI", 0, NOID, NOID, 1, 1, V, { V }, 0 },
+ { "RRI", 0, NOID, NOID, 3, 3, V, { V }, 0 },
+ { "SHEET", 0, NOID, NOID, 1, 1, V, { R }, 0 },
+ { "SHEETS", 0, NOID, NOID, 0, 1, V, { R }, 0 },
+ { "SKEWP", 0, NOID, NOID, 1, MX, V, { R }, 0 },
+ { "UNICHAR", 0, NOID, NOID, 1, 1, V, { V }, 0 },
+ { "UNICODE", 0, NOID, NOID, 1, 1, V, { V }, 0 },
+ { "XOR", 0, NOID, NOID, 1, MX, V, { R }, 0 }
+};
+
+} // namespace
+
+// function info parameter class iterator =====================================
+
+FuncInfoParamClassIterator::FuncInfoParamClassIterator( const FunctionInfo& rFuncInfo ) :
+ mpnParamClass( rFuncInfo.mpnParamClass ),
+ mpnParamClassEnd( rFuncInfo.mpnParamClass + FUNCINFO_CLASSCOUNT )
+{
+}
+
+FuncInfoParamClassIterator& FuncInfoParamClassIterator::operator++()
+{
+ if( (mpnParamClass + 1 < mpnParamClassEnd) && (mpnParamClass[ 1 ] != 0) )
+ ++mpnParamClass;
+ return *this;
+}
+
+// function provider implementation ===========================================
+
+class FunctionProviderImpl
+{
+public:
+ explicit FunctionProviderImpl(
+ ApiOpCodes& rOpCodes,
+ const Reference< XSpreadsheetDocument >& rxDocument,
+ bool bImportFilter );
+
+ explicit FunctionProviderImpl(
+ ApiOpCodes& rOpCodes,
+ const Reference< XSpreadsheetDocument >& rxDocument,
+ BiffType eBiff,
+ bool bImportFilter );
+
+ const FunctionInfo* getFuncInfoFromApiToken( const ApiToken& rToken ) const;
+ const FunctionInfo* getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const;
+ const FunctionInfo* getFuncInfoFromOobFuncId( sal_uInt16 nFuncId ) const;
+ const FunctionInfo* getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const;
+ const FunctionInfo* getFuncInfoFromExternCallName( const OUString& rExtCallName ) const;
+
+ Sequence< FormulaOpCodeMapEntry > getOoxParserMap() const;
+
+private:
+ typedef ::std::map< OUString, FormulaToken > FormulaTokenMap;
+ typedef Sequence< FormulaOpCodeMapEntry > OpCodeEntrySequence;
+ typedef ::std::vector< FormulaOpCodeMapEntry > OpCodeEntryVector;
+
+ static bool fillEntrySeq( OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
+ static bool fillTokenMap( FormulaTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
+
+ static bool initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId );
+ static bool initOpCode( OpCodeEntryVector& orParserMap, sal_Int32& ornOpCode, const FormulaTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName );
+
+ void construct( const Reference< XSpreadsheetDocument >& rxDocument, bool bImportFilter );
+ void construct( const Reference< XSpreadsheetDocument >& rxDocument, BiffType eBiff, bool bImportFilter );
+
+ bool initFuncNames( const OpCodeEntrySequence& rEntrySeq );
+ void initOpCodes( const Reference< XSpreadsheetDocument >& rxDocument );
+
+ void initFuncOpCode( FunctionInfo& orFuncInfo, const FormulaTokenMap& rFuncTokens );
+ void initFuncMaps( const FunctionData* pBeg, const FunctionData* pEnd );
+
+private:
+ typedef RefMap< sal_Int32, FunctionInfo > OpCodeFuncMap;
+ typedef RefMap< OUString, FunctionInfo > FuncNameMap;
+ typedef RefMap< sal_uInt16, FunctionInfo > FuncIdMap;
+
+ ApiOpCodes& mrOpCodes; /// All needed API op-codes.
+ FormulaTokenMap maIntFuncTokens; /// Internal functions keyed by ODFF name.
+ FormulaTokenMap maExtFuncTokens; /// External functions keyed by ODFF name.
+ OpCodeFuncMap maOpCodeFuncs; /// Maps API op-codes to function data.
+ FuncNameMap maOoxFuncs; /// Maps OOXML function names to function data.
+ FuncNameMap maExtProgFuncs; /// Maps programmatical API function names to function data.
+ FuncIdMap maOobFuncs; /// Maps OOBIN function indexes to function data.
+ FuncIdMap maBiffFuncs; /// Maps BIFF function indexes to function data.
+ FuncNameMap maMacroFuncs; /// Maps BIFF macro function names to function data.
+ OpCodeEntryVector maParserMap; /// OOXML token mapping for formula parser service.
+ sal_uInt8 mnMaxParam; /// Maximum parameter count for current file type.
+ bool mbImportFilter; /// True = import filter, false = export filter.
+};
+
+// ----------------------------------------------------------------------------
+
+FunctionProviderImpl::FunctionProviderImpl( ApiOpCodes& rOpCodes,
+ const Reference< XSpreadsheetDocument >& rxDocument, bool bImportFilter ) :
+ mrOpCodes( rOpCodes ),
+ mnMaxParam( OOX_MAX_PARAMCOUNT )
+{
+ construct( rxDocument, bImportFilter );
+}
+
+FunctionProviderImpl::FunctionProviderImpl( ApiOpCodes& rOpCodes,
+ const Reference< XSpreadsheetDocument >& rxDocument, BiffType eBiff, bool bImportFilter ) :
+ mrOpCodes( rOpCodes ),
+ mnMaxParam( BIFF_MAX_PARAMCOUNT )
+{
+ construct( rxDocument, eBiff, bImportFilter );
+}
+
+const FunctionInfo* FunctionProviderImpl::getFuncInfoFromApiToken( const ApiToken& rToken ) const
+{
+ const FunctionInfo* pFuncInfo = 0;
+ if( (rToken.OpCode == mrOpCodes.OPCODE_EXTERNAL) && rToken.Data.hasValue() )
+ {
+ OUString aProgFuncName;
+ if( rToken.Data >>= aProgFuncName )
+ pFuncInfo = maExtProgFuncs.get( aProgFuncName ).get();
+ }
+ else
+ {
+ pFuncInfo = maOpCodeFuncs.get( rToken.OpCode ).get();
+ }
+ return pFuncInfo;
+}
+
+const FunctionInfo* FunctionProviderImpl::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
+{
+ return maOoxFuncs.get( rFuncName ).get();
+}
+
+const FunctionInfo* FunctionProviderImpl::getFuncInfoFromOobFuncId( sal_uInt16 nFuncId ) const
+{
+ return maOobFuncs.get( nFuncId ).get();
+}
+
+const FunctionInfo* FunctionProviderImpl::getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const
+{
+ return maBiffFuncs.get( nFuncId ).get();
+}
+
+const FunctionInfo* FunctionProviderImpl::getFuncInfoFromExternCallName( const OUString& rExtCallName ) const
+{
+ return maMacroFuncs.get( rExtCallName ).get();
+}
+
+Sequence< FormulaOpCodeMapEntry > FunctionProviderImpl::getOoxParserMap() const
+{
+ return ContainerHelper::vectorToSequence( maParserMap );
+}
+
+// private --------------------------------------------------------------------
+
+bool FunctionProviderImpl::fillEntrySeq( OpCodeEntrySequence& orEntrySeq,
+ const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
+{
+ try
+ {
+ orEntrySeq = rxMapper->getAvailableMappings( ::com::sun::star::sheet::FormulaLanguage::ODFF, nMapGroup );
+ return orEntrySeq.hasElements();
+ }
+ catch( Exception& )
+ {
+ }
+ return false;
+}
+
+bool FunctionProviderImpl::fillTokenMap( FormulaTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq,
+ const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
+{
+ orTokenMap.clear();
+ if( fillEntrySeq( orEntrySeq, rxMapper, nMapGroup ) )
+ {
+ const FormulaOpCodeMapEntry* pEntry = orEntrySeq.getConstArray();
+ const FormulaOpCodeMapEntry* pEntryEnd = pEntry + orEntrySeq.getLength();
+ for( ; pEntry != pEntryEnd; ++pEntry )
+ orTokenMap[ pEntry->Name ] = pEntry->Token;
+ }
+ return !orTokenMap.empty();
+}
+
+bool FunctionProviderImpl::initOpCode( sal_Int32& ornOpCode,
+ const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId )
+{
+ if( (0 <= nSpecialId) && (nSpecialId < rEntrySeq.getLength()) )
+ {
+ ornOpCode = rEntrySeq[ nSpecialId ].Token.OpCode;
+ return true;
+ }
+ OSL_ENSURE( false,
+ OStringBuffer( "FunctionProviderImpl::initOpCode - opcode for special offset " ).
+ append( nSpecialId ).append( " not found" ).getStr() );
+ return false;
+}
+
+bool FunctionProviderImpl::initOpCode( OpCodeEntryVector& orParserMap, sal_Int32& ornOpCode,
+ const FormulaTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName )
+{
+ OUString aOdfName = OUString::createFromAscii( pcOdfName );
+ FormulaTokenMap::const_iterator aIt = rTokenMap.find( aOdfName );
+ if( aIt != rTokenMap.end() )
+ {
+ ornOpCode = aIt->second.OpCode;
+ if( pcOoxName )
+ {
+ FormulaOpCodeMapEntry aEntry;
+ aEntry.Name = OUString::createFromAscii( pcOoxName );
+ aEntry.Token.OpCode = ornOpCode;
+ orParserMap.push_back( aEntry );
+ }
+ return true;
+ }
+ OSL_ENSURE( false,
+ OStringBuffer( "FunctionProviderImpl::initOpCode - opcode for \"" ).
+ append( OUStringToOString( aOdfName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( "\" not found" ).getStr() );
+ return false;
+}
+
+void FunctionProviderImpl::construct(
+ const Reference< XSpreadsheetDocument >& rxDocument, bool bImportFilter )
+{
+ construct( rxDocument, BIFF8, bImportFilter );
+ // additional functions for OOX
+ initFuncMaps( saFuncTableOox, STATIC_ARRAY_END( saFuncTableOox ) );
+}
+
+void FunctionProviderImpl::construct(
+ const Reference< XSpreadsheetDocument >& rxDocument, BiffType eBiff, bool bImportFilter )
+{
+ mbImportFilter = bImportFilter;
+ OSL_ENSURE( mbImportFilter, "FunctionProviderImpl::construct - need special handling for macro call functions" );
+
+ // operator op-codes, special op-codes, function op-codes
+ initOpCodes( rxDocument );
+
+ /* Add functions supported in the current BIFF version only.
+ Function tables from later BIFF versions may overwrite single
+ functions from earlier tables. */
+ if( eBiff >= BIFF2 )
+ initFuncMaps( saFuncTableBiff2, STATIC_ARRAY_END( saFuncTableBiff2 ) );
+ if( eBiff >= BIFF3 )
+ initFuncMaps( saFuncTableBiff3, STATIC_ARRAY_END( saFuncTableBiff3 ) );
+ if( eBiff >= BIFF4 )
+ initFuncMaps( saFuncTableBiff4, STATIC_ARRAY_END( saFuncTableBiff4 ) );
+ if( eBiff >= BIFF5 )
+ initFuncMaps( saFuncTableBiff5, STATIC_ARRAY_END( saFuncTableBiff5 ) );
+ if( eBiff >= BIFF8 )
+ initFuncMaps( saFuncTableBiff8, STATIC_ARRAY_END( saFuncTableBiff8 ) );
+}
+
+bool FunctionProviderImpl::initFuncNames( const OpCodeEntrySequence& rEntrySeq )
+{
+ const FormulaOpCodeMapEntry* pEntry = rEntrySeq.getConstArray();
+ const FormulaOpCodeMapEntry* pEntryEnd = pEntry + rEntrySeq.getLength();
+ for( ; pEntry != pEntryEnd; ++pEntry )
+ {
+ if( pEntry->Token.OpCode == mrOpCodes.OPCODE_EXTERNAL )
+ maExtFuncTokens[ pEntry->Name ] = pEntry->Token;
+ else
+ maIntFuncTokens[ pEntry->Name ] = pEntry->Token;
+ }
+ return true;
+}
+
+void FunctionProviderImpl::initOpCodes( const Reference< XSpreadsheetDocument >& rxDocument )
+{
+ bool bIsValid = false;
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( rxDocument, UNO_QUERY_THROW );
+ Reference< XFormulaOpCodeMapper > xMapper( xFactory->createInstance(
+ CREATE_OUSTRING( "com.sun.star.sheet.FormulaOpCodeMapper" ) ), UNO_QUERY_THROW );
+
+ // op-codes provided as attributes
+ mrOpCodes.OPCODE_EXTERNAL = xMapper->getOpCodeExternal();
+ mrOpCodes.OPCODE_UNKNOWN = xMapper->getOpCodeUnknown();
+
+ using namespace ::com::sun::star::sheet::FormulaMapGroup;
+ using namespace ::com::sun::star::sheet::FormulaMapGroupSpecialOffset;
+
+ OpCodeEntrySequence aEntrySeq;
+ FormulaTokenMap aTokenMap;
+ bIsValid =
+ // special
+ fillEntrySeq( aEntrySeq, xMapper, SPECIAL ) &&
+ initOpCode( mrOpCodes.OPCODE_PUSH, aEntrySeq, PUSH ) &&
+ initOpCode( mrOpCodes.OPCODE_MISSING, aEntrySeq, MISSING ) &&
+ initOpCode( mrOpCodes.OPCODE_SPACES, aEntrySeq, SPACES ) &&
+ initOpCode( mrOpCodes.OPCODE_NAME, aEntrySeq, NAME ) &&
+ initOpCode( mrOpCodes.OPCODE_DBAREA, aEntrySeq, DB_AREA ) &&
+ initOpCode( mrOpCodes.OPCODE_NLR, aEntrySeq, COL_ROW_NAME ) &&
+ initOpCode( mrOpCodes.OPCODE_MACRO, aEntrySeq, MACRO ) &&
+ initOpCode( mrOpCodes.OPCODE_BAD, aEntrySeq, BAD ) &&
+ initOpCode( mrOpCodes.OPCODE_NONAME, aEntrySeq, NO_NAME ) &&
+ // separators
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, SEPARATORS ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_OPEN, aTokenMap, "(", "(" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_CLOSE, aTokenMap, ")", ")" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_SEP, aTokenMap, ";", "," ) &&
+ // array separators
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, ARRAY_SEPARATORS ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_ARRAY_OPEN, aTokenMap, "{", "{" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_ARRAY_CLOSE, aTokenMap, "}", "}" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_ARRAY_ROWSEP, aTokenMap, "|", ";" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_ARRAY_COLSEP, aTokenMap, ";", "," ) &&
+ // unary operators
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, UNARY_OPERATORS ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_PLUS_SIGN, aTokenMap, "+", 0 ) && // same op-code as OPCODE_ADD
+ initOpCode( maParserMap, mrOpCodes.OPCODE_MINUS_SIGN, aTokenMap, "-", "-" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_PERCENT, aTokenMap, "%", "%" ) &&
+ // binary operators
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, BINARY_OPERATORS ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_ADD, aTokenMap, "+", "+" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_SUB, aTokenMap, "-", "-" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_MULT, aTokenMap, "*", "*" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_DIV, aTokenMap, "/", "/" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_POWER, aTokenMap, "^", "^" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_CONCAT, aTokenMap, "&", "&" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_EQUAL, aTokenMap, "=", "=" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_NOT_EQUAL, aTokenMap, "<>", "<>" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_LESS, aTokenMap, "<", "<" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_LESS_EQUAL, aTokenMap, "<=", "<=" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_GREATER, aTokenMap, ">", ">" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_GREATER_EQUAL, aTokenMap, ">=", ">=" ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_INTERSECT, aTokenMap, "!", " " ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_LIST, aTokenMap, "~", "," ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_RANGE, aTokenMap, ":", ":" ) &&
+ // functions
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, FUNCTIONS ) &&
+ initFuncNames( aEntrySeq ) &&
+ initOpCode( maParserMap, mrOpCodes.OPCODE_DDE, aTokenMap, "DDE", 0 );
+
+ // OPCODE_PLUS_SIGN and OPCODE_ADD should be equal, otherwise "+" has to be passed above
+ OSL_ENSURE( mrOpCodes.OPCODE_PLUS_SIGN == mrOpCodes.OPCODE_ADD,
+ "FunctionProviderImpl::initOpCodes - need opcode mapping for OPCODE_PLUS_SIGN" );
+ // OPCODE_LIST not supported in Calc core
+ mrOpCodes.OPCODE_LIST = mrOpCodes.OPCODE_SEP;
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( bIsValid, "FunctionProviderImpl::initOpCodes - opcodes not initialized" );
+}
+
+void FunctionProviderImpl::initFuncOpCode( FunctionInfo& orFuncInfo, const FormulaTokenMap& rFuncTokens )
+{
+ bool bRet = false;
+ if( orFuncInfo.mnOobFuncId == OOBIN_FUNC_EXTERNCALL )
+ {
+ orFuncInfo.mnApiOpCode = mrOpCodes.OPCODE_EXTERNAL;
+ bRet = true;
+ }
+ else if( orFuncInfo.maOdfFuncName.getLength() > 0 )
+ {
+ FormulaTokenMap::const_iterator aIt = rFuncTokens.find( orFuncInfo.maOdfFuncName );
+ if( aIt != rFuncTokens.end() )
+ {
+ orFuncInfo.mnApiOpCode = aIt->second.OpCode;
+ OSL_ENSURE( orFuncInfo.mnApiOpCode != mrOpCodes.OPCODE_NONAME,
+ OStringBuffer( "FunctionProviderImpl::initFuncOpCode - no valid op-code for \"" ).
+ append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( '"' ).getStr() );
+ OSL_ENSURE( orFuncInfo.maOoxFuncName.getLength() > 0,
+ OStringBuffer( "FunctionProviderImpl::initFuncOpCode - no valid OOX function name for \"" ).
+ append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( '"' ).getStr() );
+ bRet = (orFuncInfo.mnApiOpCode != mrOpCodes.OPCODE_EXTERNAL) ||
+ ((aIt->second.Data >>= orFuncInfo.maExtProgName) && (orFuncInfo.maExtProgName.getLength() > 0));
+ if( bRet )
+ {
+ // create the parser map entry
+ FormulaOpCodeMapEntry aEntry;
+ aEntry.Name = orFuncInfo.maOoxFuncName;
+ aEntry.Token = aIt->second;
+ maParserMap.push_back( aEntry );
+ }
+ }
+ OSL_ENSURE( bRet,
+ OStringBuffer( "FunctionProviderImpl::initFuncOpCode - opcode or external name for \"" ).
+ append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( "\" not found" ).getStr() );
+ }
+ if( !bRet || (orFuncInfo.mnApiOpCode == mrOpCodes.OPCODE_UNKNOWN) )
+ orFuncInfo.mnApiOpCode = mrOpCodes.OPCODE_NONAME;
+}
+
+void FunctionProviderImpl::initFuncMaps( const FunctionData* pBeg, const FunctionData* pEnd )
+{
+ for( const FunctionData* pIt = pBeg; pIt != pEnd; ++pIt )
+ {
+ if( pIt->isSupported( mbImportFilter ) )
+ {
+ // create a function info object
+ FunctionInfoRef xFuncInfo( new FunctionInfo );
+ if( pIt->mpcOdfFuncName )
+ xFuncInfo->maOdfFuncName = OUString::createFromAscii( pIt->mpcOdfFuncName );
+ if( pIt->mpcOoxFuncName )
+ xFuncInfo->maOoxFuncName = OUString::createFromAscii( pIt->mpcOoxFuncName );
+ if( getFlag( pIt->mnFlags, FUNCFLAG_MACROCALL ) )
+ xFuncInfo->maExternCallName = CREATE_OUSTRING( "_xlfn." ) + xFuncInfo->maOoxFuncName;
+ else if( getFlag( pIt->mnFlags, FUNCFLAG_EXTERNAL ) )
+ xFuncInfo->maExternCallName = xFuncInfo->maOoxFuncName;
+ xFuncInfo->mnOobFuncId = pIt->mnOobFuncId;
+ xFuncInfo->mnBiffFuncId = pIt->mnBiffFuncId;
+ xFuncInfo->mnMinParamCount = pIt->mnMinParamCount;
+ xFuncInfo->mnMaxParamCount = (pIt->mnMaxParamCount == MX) ? mnMaxParam : pIt->mnMaxParamCount;
+ xFuncInfo->mnRetClass = pIt->mnRetClass;
+ xFuncInfo->mpnParamClass = pIt->mpnParamClass;
+ xFuncInfo->mbVolatile = getFlag( pIt->mnFlags, FUNCFLAG_VOLATILE );
+
+ // get API opcode from BIFF function index or function name
+ initFuncOpCode( *xFuncInfo, getFlag( pIt->mnFlags, FUNCFLAG_EXTERNAL ) ? maExtFuncTokens : maIntFuncTokens );
+
+ // insert the function info into the maps
+ if( xFuncInfo->mnApiOpCode != mrOpCodes.OPCODE_NONAME )
+ {
+ if( (xFuncInfo->mnApiOpCode == mrOpCodes.OPCODE_EXTERNAL) && (xFuncInfo->maExtProgName.getLength() > 0) )
+ maExtProgFuncs[ xFuncInfo->maExtProgName ] = xFuncInfo;
+ else
+ maOpCodeFuncs[ xFuncInfo->mnApiOpCode ] = xFuncInfo;
+ }
+ if( xFuncInfo->maOoxFuncName.getLength() > 0 )
+ maOoxFuncs[ xFuncInfo->maOoxFuncName ] = xFuncInfo;
+ if( xFuncInfo->mnOobFuncId != NOID )
+ maOobFuncs[ xFuncInfo->mnOobFuncId ] = xFuncInfo;
+ if( xFuncInfo->mnBiffFuncId != NOID )
+ maBiffFuncs[ xFuncInfo->mnBiffFuncId ] = xFuncInfo;
+ if( xFuncInfo->maExternCallName.getLength() > 0 )
+ maMacroFuncs[ xFuncInfo->maExternCallName ] = xFuncInfo;
+ }
+ }
+}
+
+// function provider ==========================================================
+
+FunctionProvider::FunctionProvider( const WorkbookHelper& rHelper )
+{
+ bool bImportFilter = rHelper.getBaseFilter().isImportFilter();
+ switch( rHelper.getFilterType() )
+ {
+ case FILTER_OOX:
+ mxImpl.reset( new FunctionProviderImpl( *this, rHelper.getDocument(), bImportFilter ) );
+ break;
+ case FILTER_BIFF:
+ mxImpl.reset( new FunctionProviderImpl( *this, rHelper.getDocument(), rHelper.getBiff(), bImportFilter ) );
+ break;
+ case FILTER_UNKNOWN: break;
+ }
+}
+
+FunctionProvider::FunctionProvider( const Reference< XSpreadsheetDocument >& rxDocument, bool bImportFilter )
+{
+ mxImpl.reset( new FunctionProviderImpl( *this, rxDocument, bImportFilter ) );
+}
+
+FunctionProvider::FunctionProvider( const Reference< XSpreadsheetDocument >& rxDocument, BiffType eBiff, bool bImportFilter )
+{
+ mxImpl.reset( new FunctionProviderImpl( *this, rxDocument, eBiff, bImportFilter ) );
+}
+
+FunctionProvider::~FunctionProvider()
+{
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromApiToken( const ApiToken& rToken ) const
+{
+ return mxImpl->getFuncInfoFromApiToken( rToken );
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
+{
+ return mxImpl->getFuncInfoFromOoxFuncName( rFuncName );
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromOobFuncId( sal_uInt16 nFuncId ) const
+{
+ return mxImpl->getFuncInfoFromOobFuncId( nFuncId );
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const
+{
+ return mxImpl->getFuncInfoFromBiffFuncId( nFuncId );
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromExternCallName( const OUString& rExtCallName ) const
+{
+ return mxImpl->getFuncInfoFromExternCallName( rExtCallName );
+}
+
+Sequence< FormulaOpCodeMapEntry > FunctionProvider::getOoxParserMap() const
+{
+ return mxImpl->getOoxParserMap();
+}
+
+// token sequence iterator ====================================================
+
+ApiTokenIterator::ApiTokenIterator( const ApiTokenSequence& rTokens, sal_Int32 nSpacesOpCode, bool bSkipSpaces ) :
+ mpToken( rTokens.getConstArray() ),
+ mpTokenEnd( rTokens.getConstArray() + rTokens.getLength() ),
+ mnSpacesOpCode( nSpacesOpCode ),
+ mbSkipSpaces( bSkipSpaces )
+{
+ skipSpaces();
+}
+
+ApiTokenIterator::ApiTokenIterator( const ApiTokenIterator& rIter, bool bSkipSpaces ) :
+ mpToken( rIter.mpToken ),
+ mpTokenEnd( rIter.mpTokenEnd ),
+ mnSpacesOpCode( rIter.mnSpacesOpCode ),
+ mbSkipSpaces( bSkipSpaces )
+{
+ skipSpaces();
+}
+
+ApiTokenIterator& ApiTokenIterator::operator++()
+{
+ if( is() )
+ {
+ ++mpToken;
+ skipSpaces();
+ }
+ return *this;
+}
+
+void ApiTokenIterator::skipSpaces()
+{
+ if( mbSkipSpaces )
+ while( is() && (mpToken->OpCode == mnSpacesOpCode) )
+ ++mpToken;
+}
+
+// formual contexts ===========================================================
+
+FormulaContext::FormulaContext( bool bRelativeAsOffset, bool bAlways3dRefs ) :
+ maBaseAddress( 0, 0, 0 ),
+ mbRelativeAsOffset( bRelativeAsOffset ),
+ mbAlways3dRefs( bAlways3dRefs )
+{
+}
+
+FormulaContext::~FormulaContext()
+{
+}
+
+void FormulaContext::setSharedFormula( const CellAddress& )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+TokensFormulaContext::TokensFormulaContext( bool bRelativeAsOffset, bool bAlways3dRefs ) :
+ FormulaContext( bRelativeAsOffset, bAlways3dRefs )
+{
+}
+
+void TokensFormulaContext::setTokens( const ApiTokenSequence& rTokens )
+{
+ maTokens = rTokens;
+}
+
+// ----------------------------------------------------------------------------
+
+SimpleFormulaContext::SimpleFormulaContext( const Reference< XFormulaTokens >& rxTokens,
+ bool bRelativeAsOffset, bool bAlways3dRefs ) :
+ FormulaContext( bRelativeAsOffset, bAlways3dRefs ),
+ mxTokens( rxTokens )
+{
+ OSL_ENSURE( mxTokens.is(), "SimpleFormulaContext::SimpleFormulaContext - missing XFormulaTokens interface" );
+}
+
+void SimpleFormulaContext::setTokens( const ApiTokenSequence& rTokens )
+{
+ mxTokens->setTokens( rTokens );
+}
+
+// formula parser/formula compiler base class =================================
+
+namespace {
+
+bool lclConvertToCellAddress( CellAddress& orAddress, const SingleReference& rSingleRef, sal_Int32 nExpectedSheet )
+{
+ orAddress = CellAddress( static_cast< sal_Int16 >( rSingleRef.Sheet ),
+ rSingleRef.Column, rSingleRef.Row );
+ return
+ ((nExpectedSheet < 0) || (nExpectedSheet == rSingleRef.Sheet)) &&
+ !getFlag( rSingleRef.Flags, COLUMN_DELETED | ROW_DELETED | SHEET_DELETED );
+}
+
+bool lclConvertToCellRange( CellRangeAddress& orRange, const ComplexReference& rComplexRef, sal_Int32 nExpectedSheet )
+{
+ orRange = CellRangeAddress( static_cast< sal_Int16 >( rComplexRef.Reference1.Sheet ),
+ rComplexRef.Reference1.Column, rComplexRef.Reference1.Row,
+ rComplexRef.Reference2.Column, rComplexRef.Reference2.Row );
+ return
+ (rComplexRef.Reference1.Sheet == rComplexRef.Reference2.Sheet) &&
+ ((nExpectedSheet < 0) || (nExpectedSheet == rComplexRef.Reference1.Sheet)) &&
+ !getFlag( rComplexRef.Reference1.Flags, COLUMN_DELETED | ROW_DELETED | SHEET_DELETED ) &&
+ !getFlag( rComplexRef.Reference2.Flags, COLUMN_DELETED | ROW_DELETED | SHEET_DELETED );
+}
+
+enum TokenToRangeListState { STATE_REF, STATE_SEP, STATE_OPEN, STATE_CLOSE, STATE_ERROR };
+
+TokenToRangeListState lclProcessRef( ApiCellRangeList& orRanges, const Any& rData, sal_Int32 nExpectedSheet )
+{
+ SingleReference aSingleRef;
+ if( rData >>= aSingleRef )
+ {
+ CellAddress aAddress;
+ // ignore invalid addresses (with #REF! errors), but to not stop parsing
+ if( lclConvertToCellAddress( aAddress, aSingleRef, nExpectedSheet ) )
+ orRanges.push_back( CellRangeAddress( aAddress.Sheet, aAddress.Column, aAddress.Row, aAddress.Column, aAddress.Row ) );
+ return STATE_REF;
+ }
+ ComplexReference aComplexRef;
+ if( rData >>= aComplexRef )
+ {
+ CellRangeAddress aRange;
+ // ignore invalid ranges (with #REF! errors), but to not stop parsing
+ if( lclConvertToCellRange( aRange, aComplexRef, nExpectedSheet ) )
+ orRanges.push_back( aRange );
+ return STATE_REF;
+ }
+ return STATE_ERROR;
+}
+
+TokenToRangeListState lclProcessOpen( sal_Int32& ornParenLevel )
+{
+ ++ornParenLevel;
+ return STATE_OPEN;
+}
+
+TokenToRangeListState lclProcessClose( sal_Int32& ornParenLevel )
+{
+ --ornParenLevel;
+ return (ornParenLevel >= 0) ? STATE_CLOSE : STATE_ERROR;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+FormulaProcessorBase::FormulaProcessorBase( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maFuncProv( rHelper )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+OUString FormulaProcessorBase::generateAddress2dString( const CellAddress& rAddress, bool bAbsolute )
+{
+ return generateAddress2dString( BinAddress( rAddress ), bAbsolute );
+}
+
+OUString FormulaProcessorBase::generateAddress2dString( const BinAddress& rAddress, bool bAbsolute )
+{
+ OUStringBuffer aBuffer;
+ // column
+ for( sal_Int32 nTemp = rAddress.mnCol; nTemp >= 0; (nTemp /= 26) -= 1 )
+ aBuffer.insert( 0, sal_Unicode( 'A' + (nTemp % 26) ) );
+ if( bAbsolute )
+ aBuffer.insert( 0, sal_Unicode( '$' ) );
+ // row
+ if( bAbsolute )
+ aBuffer.append( sal_Unicode( '$' ) );
+ aBuffer.append( static_cast< sal_Int32 >( rAddress.mnRow + 1 ) );
+ return aBuffer.makeStringAndClear();
+}
+
+OUString FormulaProcessorBase::generateRange2dString( const CellRangeAddress& rRange, bool bAbsolute )
+{
+ return generateRange2dString( BinRange( rRange ), bAbsolute );
+}
+
+OUString FormulaProcessorBase::generateRange2dString( const BinRange& rRange, bool bAbsolute )
+{
+ OUStringBuffer aBuffer( generateAddress2dString( rRange.maFirst, bAbsolute ) );
+ if( (rRange.getColCount() > 1) || (rRange.getRowCount() > 1) )
+ aBuffer.append( sal_Unicode( ':' ) ).append( generateAddress2dString( rRange.maLast, bAbsolute ) );
+ return aBuffer.makeStringAndClear();
+}
+
+OUString FormulaProcessorBase::generateRangeList2dString( const ApiCellRangeList& rRanges,
+ bool bAbsolute, sal_Unicode cSeparator, bool bEncloseMultiple )
+{
+ OUStringBuffer aBuffer;
+ for( ApiCellRangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt )
+ {
+ if( aBuffer.getLength() > 0 )
+ aBuffer.append( cSeparator );
+ aBuffer.append( generateRange2dString( *aIt, bAbsolute ) );
+ }
+ if( bEncloseMultiple && (rRanges.size() > 1) )
+ aBuffer.insert( 0, sal_Unicode( '(' ) ).append( sal_Unicode( ')' ) );
+ return aBuffer.makeStringAndClear();
+}
+
+// ----------------------------------------------------------------------------
+
+Any FormulaProcessorBase::extractReference( const ApiTokenSequence& rTokens ) const
+{
+ ApiTokenIterator aTokenIt( rTokens, maFuncProv.OPCODE_SPACES, true );
+ if( aTokenIt.is() && (aTokenIt->OpCode == maFuncProv.OPCODE_PUSH) )
+ {
+ Any aRefAny = aTokenIt->Data;
+ if( !(++aTokenIt).is() && (aRefAny.has< SingleReference >() || aRefAny.has< ComplexReference >()) )
+ return aRefAny;
+ }
+ return Any();
+}
+
+void FormulaProcessorBase::extractCellRangeList( ApiCellRangeList& orRanges,
+ const ApiTokenSequence& rTokens, sal_Int32 nExpectedSheet ) const
+{
+ orRanges.clear();
+ TokenToRangeListState eState = STATE_OPEN;
+ sal_Int32 nParenLevel = 0;
+ for( ApiTokenIterator aIt( rTokens, maFuncProv.OPCODE_SPACES, true ); aIt.is() && (eState != STATE_ERROR); ++aIt )
+ {
+ sal_Int32 nOpCode = aIt->OpCode;
+ switch( eState )
+ {
+ case STATE_REF:
+ if( nOpCode == maFuncProv.OPCODE_LIST ) eState = STATE_SEP;
+ else if( nOpCode == maFuncProv.OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
+ else eState = STATE_ERROR;
+ break;
+ case STATE_SEP:
+ if( nOpCode == maFuncProv.OPCODE_PUSH ) eState = lclProcessRef( orRanges, aIt->Data, nExpectedSheet );
+ else if( nOpCode == maFuncProv.OPCODE_LIST ) eState = STATE_SEP;
+ else if( nOpCode == maFuncProv.OPCODE_OPEN ) eState = lclProcessOpen( nParenLevel );
+ else if( nOpCode == maFuncProv.OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
+ else eState = STATE_ERROR;
+ break;
+ case STATE_OPEN:
+ if( nOpCode == maFuncProv.OPCODE_PUSH ) eState = lclProcessRef( orRanges, aIt->Data, nExpectedSheet );
+ else if( nOpCode == maFuncProv.OPCODE_LIST ) eState = STATE_SEP;
+ else if( nOpCode == maFuncProv.OPCODE_OPEN ) eState = lclProcessOpen( nParenLevel );
+ else if( nOpCode == maFuncProv.OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
+ else eState = STATE_ERROR;
+ break;
+ case STATE_CLOSE:
+ if( nOpCode == maFuncProv.OPCODE_LIST ) eState = STATE_SEP;
+ else if( nOpCode == maFuncProv.OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
+ else eState = STATE_ERROR;
+ break;
+ default:;
+ }
+ }
+
+ if( eState == STATE_ERROR )
+ orRanges.clear();
+ else
+ getAddressConverter().validateCellRangeList( orRanges, false );
+}
+
+bool FormulaProcessorBase::extractString( OUString& orString, const ApiTokenSequence& rTokens ) const
+{
+ ApiTokenIterator aTokenIt( rTokens, maFuncProv.OPCODE_SPACES, true );
+ return aTokenIt.is() && (aTokenIt->OpCode == maFuncProv.OPCODE_PUSH) && (aTokenIt->Data >>= orString) && !(++aTokenIt).is();
+}
+
+void FormulaProcessorBase::convertStringToStringList(
+ ApiTokenSequence& orTokens, sal_Unicode cStringSep, bool bTrimLeadingSpaces ) const
+{
+ OUString aString;
+ if( extractString( aString, orTokens ) && (aString.getLength() > 0) )
+ {
+ ::std::vector< ApiToken > aNewTokens;
+ sal_Int32 nPos = 0;
+ sal_Int32 nLen = aString.getLength();
+ while( (0 <= nPos) && (nPos < nLen) )
+ {
+ OUString aEntry = aString.getToken( 0, cStringSep, nPos );
+ if( bTrimLeadingSpaces )
+ {
+ sal_Int32 nStart = 0;
+ while( (nStart < aEntry.getLength()) && (aEntry[ nStart ] == ' ') ) ++nStart;
+ aEntry = aEntry.copy( nStart );
+ }
+ if( !aNewTokens.empty() )
+ aNewTokens.push_back( ApiToken( maFuncProv.OPCODE_SEP, Any() ) );
+ aNewTokens.push_back( ApiToken( maFuncProv.OPCODE_PUSH, Any( aEntry ) ) );
+ }
+ orTokens = ContainerHelper::vectorToSequence( aNewTokens );
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/formulaparser.cxx b/oox/source/xls/formulaparser.cxx
new file mode 100644
index 000000000000..165d8f2b2873
--- /dev/null
+++ b/oox/source/xls/formulaparser.cxx
@@ -0,0 +1,2595 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: formulaparser.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/formulaparser.hxx"
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/FormulaToken.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+#include <com/sun/star/sheet/SingleReference.hpp>
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/XFormulaParser.hpp>
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/defnamesbuffer.hxx"
+#include "oox/xls/externallinkbuffer.hxx"
+#include "oox/xls/tablebuffer.hxx"
+#include "oox/xls/worksheethelper.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::SingleReference;
+using ::com::sun::star::sheet::ComplexReference;
+using ::com::sun::star::sheet::XFormulaParser;
+using namespace ::com::sun::star::sheet::ReferenceFlags;
+
+namespace oox {
+namespace xls {
+
+// parser implementation base =================================================
+
+class FormulaParserImpl : public WorkbookHelper
+{
+public:
+ explicit FormulaParserImpl(
+ const WorkbookHelper& rHelper,
+ const FunctionProvider& rFuncProv );
+
+ /** Converts an XML formula string. */
+ virtual void importOoxFormula(
+ FormulaContext& rContext,
+ const OUString& rFormulaString );
+
+ /** Imports and converts a OOBIN token array from the passed stream. */
+ virtual void importOobFormula(
+ FormulaContext& rContext,
+ RecordInputStream& rStrm );
+
+ /** Imports and converts a BIFF token array from the passed stream. */
+ virtual void importBiffFormula(
+ FormulaContext& rContext,
+ BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize );
+
+ /** Finalizes the passed token array after import (e.g. adjusts function
+ parameters) and sets the formula using the passed context. */
+ void setFormula(
+ FormulaContext& rContext,
+ const ApiTokenSequence& rTokens );
+
+protected:
+ /** Sets the current formula context used for import. */
+ inline FormulaContext& getFormulaContext() const { return *mpContext; }
+
+ /** Sets the current formula context used for import. */
+ void initializeImport( FormulaContext& rContext );
+ /** Finalizes the passed token array after import. */
+ void finalizeImport( const ApiTokenSequence& rTokens );
+ /** Finalizes the internal token storage after import. */
+ void finalizeImport();
+
+ /** Inserts a shared formula using the current formula context and passed base address. */
+ void setSharedFormula( const BinAddress& rBaseAddr );
+
+ // token array ------------------------------------------------------------
+
+ bool resetSpaces();
+ inline void incLeadingSpaces( sal_Int32 nSpaces ) { mnLeadingSpaces += nSpaces; }
+ inline void incOpeningSpaces( sal_Int32 nSpaces ) { mnOpeningSpaces += nSpaces; }
+ inline void incClosingSpaces( sal_Int32 nSpaces ) { mnClosingSpaces += nSpaces; }
+
+ size_t getFormulaSize() const;
+ Any& appendRawToken( sal_Int32 nOpCode );
+ Any& insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd );
+ size_t appendSpacesToken( sal_Int32 nSpaces );
+ size_t insertSpacesToken( sal_Int32 nSpaces, size_t nIndexFromEnd );
+
+ size_t getOperandSize( size_t nOpCountFromEnd, size_t nOpIndex ) const;
+ void pushOperandSize( size_t nSize );
+ size_t popOperandSize();
+
+ ApiToken& getOperandToken( size_t nOpCountFromEnd, size_t nOpIndex, size_t nTokenIndex );
+ void removeOperand( size_t nOpCountFromEnd, size_t nOpIndex );
+ void removeLastOperands( size_t nOpCountFromEnd );
+
+ bool pushOperandToken( sal_Int32 nOpCode, sal_Int32 nSpaces );
+ bool pushAnyOperandToken( const Any& rAny, sal_Int32 nOpCode, sal_Int32 nSpaces );
+ template< typename Type >
+ bool pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, sal_Int32 nSpaces );
+ template< typename Type >
+ inline bool pushValueOperandToken( const Type& rValue, sal_Int32 nSpaces )
+ { return pushValueOperandToken( rValue, mrFuncProv.OPCODE_PUSH, nSpaces ); }
+ bool pushParenthesesOperandToken( sal_Int32 nOpeningSpaces, sal_Int32 nClosingSpaces );
+ bool pushUnaryPreOperatorToken( sal_Int32 nOpCode, sal_Int32 nSpaces );
+ bool pushUnaryPostOperatorToken( sal_Int32 nOpCode, sal_Int32 nSpaces );
+ bool pushBinaryOperatorToken( sal_Int32 nOpCode, sal_Int32 nSpaces );
+ bool pushParenthesesOperatorToken( sal_Int32 nOpeningSpaces, sal_Int32 nClosingSpaces );
+ bool pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, sal_Int32 nLeadingSpaces, sal_Int32 nClosingSpaces );
+ bool pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, sal_Int32 nLeadingSpaces, sal_Int32 nClosingSpaces );
+
+ bool pushOperand( sal_Int32 nOpCode );
+ bool pushAnyOperand( const Any& rAny, sal_Int32 nOpCode );
+ template< typename Type >
+ bool pushValueOperand( const Type& rValue, sal_Int32 nOpCode );
+ template< typename Type >
+ inline bool pushValueOperand( const Type& rValue )
+ { return pushValueOperand( rValue, mrFuncProv.OPCODE_PUSH ); }
+ bool pushBoolOperand( bool bValue );
+ bool pushErrorOperand( double fEncodedError );
+ bool pushBiffErrorOperand( sal_uInt8 nErrorCode );
+ bool pushParenthesesOperand();
+ bool pushReferenceOperand( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
+ bool pushReferenceOperand( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
+ bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
+ bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
+ bool pushNlrOperand( const BinSingleRef2d& rRef );
+ bool pushEmbeddedRefOperand( const DefinedNameBase& rName );
+ bool pushDefinedNameOperand( const DefinedNameRef& rxDefName );
+ bool pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem );
+ bool pushExternalNameOperand( const ExternalNameRef& rxExtName, ExternalLinkType eLinkType );
+
+ bool pushUnaryPreOperator( sal_Int32 nOpCode );
+ bool pushUnaryPostOperator( sal_Int32 nOpCode );
+ bool pushBinaryOperator( sal_Int32 nOpCode );
+ bool pushParenthesesOperator();
+ bool pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount );
+ bool pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount );
+
+private:
+ // reference conversion ---------------------------------------------------
+
+ void initReference2d( SingleReference& orApiRef ) const;
+ void initReference3d( SingleReference& orApiRef, sal_Int32 nSheet ) const;
+ void convertColRow( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bRelativeAsOffset ) const;
+ void convertReference( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
+ void convertReference( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
+ void convertReference2d( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
+ void convertReference2d( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
+ void convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
+ void convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
+
+ // finalize token sequence ------------------------------------------------
+
+ typedef ::std::vector< const ApiToken* > ParameterPosVector;
+
+ void processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd );
+ const ApiToken* processParameters( const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd );
+
+ bool isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+ OUString getExternCallParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+ const ApiToken* skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+ const ApiToken* findParameters( ParameterPosVector& rParams, const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+ void appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam );
+ void appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount );
+
+ void appendFinalToken( const ApiToken& rToken );
+ Any& appendFinalToken( sal_Int32 nOpCode );
+
+protected:
+ const FunctionProvider& mrFuncProv; /// Function info provider.
+ const sal_Int32 mnMaxApiCol; /// Maximum column index in own document.
+ const sal_Int32 mnMaxApiRow; /// Maximum row index in own document.
+ const sal_Int32 mnMaxXlsCol; /// Maximum column index in imported document.
+ const sal_Int32 mnMaxXlsRow; /// Maximum row index in imported document.
+
+private:
+ typedef ::std::vector< ApiToken > ApiTokenVector;
+ typedef ::std::vector< size_t > SizeTypeVector;
+
+ ApiTokenVector maTokenStorage; /// Raw unordered token storage.
+ SizeTypeVector maTokenIndexes; /// Indexes into maTokenStorage.
+ SizeTypeVector maOperandSizeStack; /// Stack with token sizes per operand.
+ FormulaContext* mpContext; /// Current formula context.
+ sal_Int32 mnLeadingSpaces; /// Current number of spaces before next token.
+ sal_Int32 mnOpeningSpaces; /// Current number of spaces before opening parenthesis.
+ sal_Int32 mnClosingSpaces; /// Current number of spaces before closing parenthesis.
+};
+
+// ----------------------------------------------------------------------------
+
+FormulaParserImpl::FormulaParserImpl( const WorkbookHelper& rHelper, const FunctionProvider& rFuncProv ) :
+ WorkbookHelper( rHelper ),
+ mrFuncProv( rFuncProv ),
+ mnMaxApiCol( rHelper.getAddressConverter().getMaxApiAddress().Column ),
+ mnMaxApiRow( rHelper.getAddressConverter().getMaxApiAddress().Row ),
+ mnMaxXlsCol( rHelper.getAddressConverter().getMaxXlsAddress().Column ),
+ mnMaxXlsRow( rHelper.getAddressConverter().getMaxXlsAddress().Row ),
+ mpContext( 0 )
+{
+ maTokenStorage.reserve( 0x2000 );
+ maTokenIndexes.reserve( 0x2000 );
+ maOperandSizeStack.reserve( 256 );
+ resetSpaces();
+}
+
+void FormulaParserImpl::importOoxFormula( FormulaContext&, const OUString& )
+{
+ OSL_ENSURE( false, "FormulaParserImpl::importOoxFormula - not implemented" );
+}
+
+void FormulaParserImpl::importOobFormula( FormulaContext&, RecordInputStream& )
+{
+ OSL_ENSURE( false, "FormulaParserImpl::importOobFormula - not implemented" );
+}
+
+void FormulaParserImpl::importBiffFormula( FormulaContext&, BiffInputStream&, const sal_uInt16* )
+{
+ OSL_ENSURE( false, "FormulaParserImpl::importBiffFormula - not implemented" );
+}
+
+void FormulaParserImpl::setFormula( FormulaContext& rContext, const ApiTokenSequence& rTokens )
+{
+ initializeImport( rContext );
+ finalizeImport( rTokens );
+}
+
+void FormulaParserImpl::initializeImport( FormulaContext& rContext )
+{
+ maTokenStorage.clear();
+ maTokenIndexes.clear();
+ maOperandSizeStack.clear();
+ mpContext = &rContext;
+}
+
+void FormulaParserImpl::finalizeImport( const ApiTokenSequence& rTokens )
+{
+ maTokenStorage.clear();
+ const ApiToken* pToken = rTokens.getConstArray();
+ processTokens( pToken, pToken + rTokens.getLength() );
+ if( !maTokenStorage.empty() )
+ mpContext->setTokens( ContainerHelper::vectorToSequence( maTokenStorage ) );
+}
+
+void FormulaParserImpl::finalizeImport()
+{
+ ApiTokenSequence aTokens( static_cast< sal_Int32 >( maTokenIndexes.size() ) );
+ if( aTokens.hasElements() )
+ {
+ ApiToken* pToken = aTokens.getArray();
+ for( SizeTypeVector::const_iterator aIt = maTokenIndexes.begin(), aEnd = maTokenIndexes.end(); aIt != aEnd; ++aIt, ++pToken )
+ *pToken = maTokenStorage[ *aIt ];
+ }
+ finalizeImport( aTokens );
+}
+
+void FormulaParserImpl::setSharedFormula( const BinAddress& rBaseAddr )
+{
+ CellAddress aApiBaseAddr;
+ if( getAddressConverter().convertToCellAddress( aApiBaseAddr, rBaseAddr, mpContext->getBaseAddress().Sheet, false ) )
+ mpContext->setSharedFormula( aApiBaseAddr );
+}
+
+// token array ----------------------------------------------------------------
+
+bool FormulaParserImpl::resetSpaces()
+{
+ mnLeadingSpaces = mnOpeningSpaces = mnClosingSpaces = 0;
+ return true;
+}
+
+size_t FormulaParserImpl::getFormulaSize() const
+{
+ return maTokenIndexes.size();
+}
+
+Any& FormulaParserImpl::appendRawToken( sal_Int32 nOpCode )
+{
+ size_t nTokenIndex = maTokenStorage.size();
+ maTokenStorage.resize( nTokenIndex + 1 );
+ maTokenStorage.back().OpCode = nOpCode;
+ maTokenIndexes.push_back( nTokenIndex );
+ return maTokenStorage.back().Data;
+}
+
+Any& FormulaParserImpl::insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd )
+{
+ size_t nTokenIndex = maTokenStorage.size();
+ maTokenStorage.resize( nTokenIndex + 1 );
+ maTokenStorage.back().OpCode = nOpCode;
+ maTokenIndexes.insert( maTokenIndexes.end() - nIndexFromEnd, nTokenIndex );
+ return maTokenStorage.back().Data;
+}
+
+size_t FormulaParserImpl::appendSpacesToken( sal_Int32 nSpaces )
+{
+ if( nSpaces > 0 )
+ {
+ appendRawToken( mrFuncProv.OPCODE_SPACES ) <<= nSpaces;
+ return 1;
+ }
+ return 0;
+}
+
+size_t FormulaParserImpl::insertSpacesToken( sal_Int32 nSpaces, size_t nIndexFromEnd )
+{
+ if( nSpaces > 0 )
+ {
+ insertRawToken( mrFuncProv.OPCODE_SPACES, nIndexFromEnd ) <<= nSpaces;
+ return 1;
+ }
+ return 0;
+}
+
+size_t FormulaParserImpl::getOperandSize( size_t nOpCountFromEnd, size_t nOpIndex ) const
+{
+ OSL_ENSURE( (nOpIndex < nOpCountFromEnd) && (nOpCountFromEnd <= maOperandSizeStack.size()),
+ "FormulaParserImpl::getOperandSize - invalid parameters" );
+ return maOperandSizeStack[ maOperandSizeStack.size() - nOpCountFromEnd + nOpIndex ];
+}
+
+void FormulaParserImpl::pushOperandSize( size_t nSize )
+{
+ maOperandSizeStack.push_back( nSize );
+}
+
+size_t FormulaParserImpl::popOperandSize()
+{
+ OSL_ENSURE( !maOperandSizeStack.empty(), "FormulaParserImpl::popOperandSize - invalid call" );
+ size_t nOpSize = maOperandSizeStack.back();
+ maOperandSizeStack.pop_back();
+ return nOpSize;
+}
+
+ApiToken& FormulaParserImpl::getOperandToken( size_t nOpCountFromEnd, size_t nOpIndex, size_t nTokenIndex )
+{
+ OSL_ENSURE( getOperandSize( nOpCountFromEnd, nOpIndex ) > nTokenIndex,
+ "FormulaParserImpl::getOperandToken - invalid parameters" );
+ SizeTypeVector::const_iterator aIndexIt = maTokenIndexes.end();
+ for( SizeTypeVector::const_iterator aEnd = maOperandSizeStack.end(), aIt = aEnd - nOpCountFromEnd + nOpIndex; aIt != aEnd; ++aIt )
+ aIndexIt -= *aIt;
+ return maTokenStorage[ *(aIndexIt + nTokenIndex) ];
+}
+
+void FormulaParserImpl::removeOperand( size_t nOpCountFromEnd, size_t nOpIndex )
+{
+ OSL_ENSURE( (nOpIndex < nOpCountFromEnd) && (nOpCountFromEnd <= maOperandSizeStack.size()),
+ "FormulaParserImpl::removeOperand - invalid parameters" );
+ // remove indexes into token storage, but do not touch storage itself
+ SizeTypeVector::iterator aSizeEnd = maOperandSizeStack.end();
+ SizeTypeVector::iterator aSizeIt = aSizeEnd - nOpCountFromEnd + nOpIndex;
+ size_t nRemainingSize = 0;
+ for( SizeTypeVector::iterator aIt = aSizeIt + 1; aIt != aSizeEnd; ++aIt )
+ nRemainingSize += *aIt;
+ maTokenIndexes.erase( maTokenIndexes.end() - nRemainingSize - *aSizeIt, maTokenIndexes.end() - nRemainingSize );
+ maOperandSizeStack.erase( aSizeIt );
+}
+
+void FormulaParserImpl::removeLastOperands( size_t nOpCountFromEnd )
+{
+ for( size_t nOpIndex = 0; nOpIndex < nOpCountFromEnd; ++nOpIndex )
+ removeOperand( 1, 0 );
+}
+
+bool FormulaParserImpl::pushOperandToken( sal_Int32 nOpCode, sal_Int32 nSpaces )
+{
+ size_t nSpacesSize = appendSpacesToken( nSpaces );
+ appendRawToken( nOpCode );
+ pushOperandSize( nSpacesSize + 1 );
+ return true;
+}
+
+bool FormulaParserImpl::pushAnyOperandToken( const Any& rAny, sal_Int32 nOpCode, sal_Int32 nSpaces )
+{
+ size_t nSpacesSize = appendSpacesToken( nSpaces );
+ appendRawToken( nOpCode ) = rAny;
+ pushOperandSize( nSpacesSize + 1 );
+ return true;
+}
+
+template< typename Type >
+bool FormulaParserImpl::pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, sal_Int32 nSpaces )
+{
+ size_t nSpacesSize = appendSpacesToken( nSpaces );
+ appendRawToken( nOpCode ) <<= rValue;
+ pushOperandSize( nSpacesSize + 1 );
+ return true;
+}
+
+bool FormulaParserImpl::pushParenthesesOperandToken( sal_Int32 nOpeningSpaces, sal_Int32 nClosingSpaces )
+{
+ size_t nSpacesSize = appendSpacesToken( nOpeningSpaces );
+ appendRawToken( mrFuncProv.OPCODE_OPEN );
+ nSpacesSize += appendSpacesToken( nClosingSpaces );
+ appendRawToken( mrFuncProv.OPCODE_CLOSE );
+ pushOperandSize( nSpacesSize + 2 );
+ return true;
+}
+
+bool FormulaParserImpl::pushUnaryPreOperatorToken( sal_Int32 nOpCode, sal_Int32 nSpaces )
+{
+ bool bOk = maOperandSizeStack.size() >= 1;
+ if( bOk )
+ {
+ size_t nOpSize = popOperandSize();
+ size_t nSpacesSize = insertSpacesToken( nSpaces, nOpSize );
+ insertRawToken( nOpCode, nOpSize );
+ pushOperandSize( nOpSize + nSpacesSize + 1 );
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushUnaryPostOperatorToken( sal_Int32 nOpCode, sal_Int32 nSpaces )
+{
+ bool bOk = maOperandSizeStack.size() >= 1;
+ if( bOk )
+ {
+ size_t nOpSize = popOperandSize();
+ size_t nSpacesSize = appendSpacesToken( nSpaces );
+ appendRawToken( nOpCode );
+ pushOperandSize( nOpSize + nSpacesSize + 1 );
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushBinaryOperatorToken( sal_Int32 nOpCode, sal_Int32 nSpaces )
+{
+ bool bOk = maOperandSizeStack.size() >= 2;
+ if( bOk )
+ {
+ size_t nOp2Size = popOperandSize();
+ size_t nOp1Size = popOperandSize();
+ size_t nSpacesSize = insertSpacesToken( nSpaces, nOp2Size );
+ insertRawToken( nOpCode, nOp2Size );
+ pushOperandSize( nOp1Size + nSpacesSize + 1 + nOp2Size );
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushParenthesesOperatorToken( sal_Int32 nOpeningSpaces, sal_Int32 nClosingSpaces )
+{
+ bool bOk = maOperandSizeStack.size() >= 1;
+ if( bOk )
+ {
+ size_t nOpSize = popOperandSize();
+ size_t nSpacesSize = insertSpacesToken( nOpeningSpaces, nOpSize );
+ insertRawToken( mrFuncProv.OPCODE_OPEN, nOpSize );
+ nSpacesSize += appendSpacesToken( nClosingSpaces );
+ appendRawToken( mrFuncProv.OPCODE_CLOSE );
+ pushOperandSize( nOpSize + nSpacesSize + 2 );
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, sal_Int32 nLeadingSpaces, sal_Int32 nClosingSpaces )
+{
+ /* #i70925# if there are not enough tokens available on token stack, do
+ not exit with error, but reduce parameter count. */
+ nParamCount = ::std::min( maOperandSizeStack.size(), nParamCount );
+
+ // convert all parameters on stack to a single operand separated with OPCODE_SEP
+ bool bOk = true;
+ for( size_t nParam = 1; bOk && (nParam < nParamCount); ++nParam )
+ bOk = pushBinaryOperatorToken( mrFuncProv.OPCODE_SEP, 0 );
+
+ // add function parentheses and function name
+ return bOk &&
+ ((nParamCount > 0) ? pushParenthesesOperatorToken( 0, nClosingSpaces ) : pushParenthesesOperandToken( 0, nClosingSpaces )) &&
+ pushUnaryPreOperatorToken( nOpCode, nLeadingSpaces );
+}
+
+bool FormulaParserImpl::pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, sal_Int32 nLeadingSpaces, sal_Int32 nClosingSpaces )
+{
+ bool bOk = pushFunctionOperatorToken( rFuncInfo.mnApiOpCode, nParamCount, nLeadingSpaces, nClosingSpaces );
+ // try to create an external add-in call for the passed built-in function
+ if( bOk && (rFuncInfo.maExtProgName.getLength() > 0) )
+ getOperandToken( 1, 0, 0 ).Data <<= rFuncInfo.maExtProgName;
+ return bOk;
+}
+
+bool FormulaParserImpl::pushOperand( sal_Int32 nOpCode )
+{
+ return pushOperandToken( nOpCode, mnLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushAnyOperand( const Any& rAny, sal_Int32 nOpCode )
+{
+ return pushAnyOperandToken( rAny, nOpCode, mnLeadingSpaces ) && resetSpaces();
+}
+
+template< typename Type >
+bool FormulaParserImpl::pushValueOperand( const Type& rValue, sal_Int32 nOpCode )
+{
+ return pushValueOperandToken( rValue, nOpCode, mnLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushBoolOperand( bool bValue )
+{
+ if( const FunctionInfo* pFuncInfo = mrFuncProv.getFuncInfoFromOobFuncId( bValue ? OOBIN_FUNC_TRUE : OOBIN_FUNC_FALSE ) )
+ return pushFunctionOperator( pFuncInfo->mnApiOpCode, 0 );
+ return pushValueOperand< double >( bValue ? 1.0 : 0.0 );
+}
+
+bool FormulaParserImpl::pushErrorOperand( double fEncodedError )
+{
+ // HACK: enclose all error codes into an 1x1 matrix
+ // start token array with opening brace and leading spaces
+ pushOperand( mrFuncProv.OPCODE_ARRAY_OPEN );
+ size_t nOpSize = popOperandSize();
+ size_t nOldArraySize = maTokenIndexes.size();
+ // push a double containing the Calc error code
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= fEncodedError;
+ // close token array and set resulting operand size
+ appendRawToken( mrFuncProv.OPCODE_ARRAY_CLOSE );
+ pushOperandSize( nOpSize + maTokenIndexes.size() - nOldArraySize );
+ return true;
+}
+
+bool FormulaParserImpl::pushBiffErrorOperand( sal_uInt8 nErrorCode )
+{
+ return pushErrorOperand( BiffHelper::calcDoubleFromError( nErrorCode ) );
+}
+
+bool FormulaParserImpl::pushParenthesesOperand()
+{
+ return pushParenthesesOperandToken( mnOpeningSpaces, mnClosingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushReferenceOperand( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
+{
+ SingleReference aApiRef;
+ convertReference2d( aApiRef, rRef, bDeleted, bRelativeAsOffset );
+ return pushValueOperand( aApiRef );
+}
+
+bool FormulaParserImpl::pushReferenceOperand( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
+{
+ ComplexReference aApiRef;
+ convertReference2d( aApiRef, rRef.maRef1, rRef.maRef2, bDeleted, bRelativeAsOffset );
+ return pushValueOperand( aApiRef );
+}
+
+bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
+{
+ if( rSheetRange.is3dRange() )
+ {
+ // single-cell-range over several sheets, needs to create a ComplexReference
+ ComplexReference aApiRef;
+ convertReference3d( aApiRef, rSheetRange, rRef, rRef, bDeleted, bRelativeAsOffset );
+ return pushValueOperand( aApiRef );
+ }
+ SingleReference aApiRef;
+ convertReference3d( aApiRef, rSheetRange.isDeleted() ? -1 : rSheetRange.mnFirst, rRef, bDeleted, bRelativeAsOffset );
+ return pushValueOperand( aApiRef );
+}
+
+bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
+{
+ ComplexReference aApiRef;
+ convertReference3d( aApiRef, rSheetRange, rRef.maRef1, rRef.maRef2, bDeleted, bRelativeAsOffset );
+ return pushValueOperand( aApiRef );
+}
+
+bool FormulaParserImpl::pushNlrOperand( const BinSingleRef2d& rRef )
+{
+ SingleReference aApiRef;
+ convertReference2d( aApiRef, rRef, false, false );
+ return pushValueOperand( aApiRef, mrFuncProv.OPCODE_NLR );
+}
+
+bool FormulaParserImpl::pushEmbeddedRefOperand( const DefinedNameBase& rName )
+{
+ Any aRefAny = rName.getReference( mpContext->getBaseAddress() );
+ return aRefAny.hasValue() ? pushAnyOperand( aRefAny, mrFuncProv.OPCODE_PUSH ) : pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool FormulaParserImpl::pushDefinedNameOperand( const DefinedNameRef& rxDefName )
+{
+ if( !rxDefName )
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+ if( rxDefName->isMacroFunc( false ) )
+ return pushValueOperand( rxDefName->getOoxName(), mrFuncProv.OPCODE_MACRO );
+ if( rxDefName->getTokenIndex() >= 0 )
+ return pushValueOperand( rxDefName->getTokenIndex(), mrFuncProv.OPCODE_NAME );
+ return pushEmbeddedRefOperand( *rxDefName );
+}
+
+bool FormulaParserImpl::pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem )
+{
+ // create the function call DDE("server";"topic";"item")
+ return
+ pushValueOperandToken( rDdeServer, 0 ) &&
+ pushValueOperandToken( rDdeTopic, 0 ) &&
+ pushValueOperandToken( rDdeItem, 0 ) &&
+ pushFunctionOperator( mrFuncProv.OPCODE_DDE, 3 );
+}
+
+bool FormulaParserImpl::pushExternalNameOperand( const ExternalNameRef& rxExtName, ExternalLinkType eLinkType )
+{
+ if( rxExtName.get() ) switch( eLinkType )
+ {
+ case LINKTYPE_INTERNAL:
+ case LINKTYPE_EXTERNAL:
+ return pushEmbeddedRefOperand( *rxExtName );
+
+ case LINKTYPE_ANALYSIS:
+ if( const FunctionInfo* pFuncInfo = mrFuncProv.getFuncInfoFromOoxFuncName( rxExtName->getOoxName() ) )
+ if( pFuncInfo->maExternCallName.getLength() > 0 )
+ return pushValueOperand( pFuncInfo->maExternCallName, mrFuncProv.OPCODE_MACRO );
+ break;
+
+ case LINKTYPE_DDE:
+ {
+ OUString aDdeServer, aDdeTopic, aDdeItem;
+ if( rxExtName->getDdeLinkData( aDdeServer, aDdeTopic, aDdeItem ) )
+ return pushDdeLinkOperand( aDdeServer, aDdeTopic, aDdeItem );
+ }
+ break;
+
+ default:
+ OSL_ENSURE( eLinkType != LINKTYPE_SELF, "FormulaParserImpl::pushExternalNameOperand - invalid call" );
+ }
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool FormulaParserImpl::pushUnaryPreOperator( sal_Int32 nOpCode )
+{
+ return pushUnaryPreOperatorToken( nOpCode, mnLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushUnaryPostOperator( sal_Int32 nOpCode )
+{
+ return pushUnaryPostOperatorToken( nOpCode, mnLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushBinaryOperator( sal_Int32 nOpCode )
+{
+ return pushBinaryOperatorToken( nOpCode, mnLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushParenthesesOperator()
+{
+ return pushParenthesesOperatorToken( mnOpeningSpaces, mnClosingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount )
+{
+ return pushFunctionOperatorToken( nOpCode, nParamCount, mnLeadingSpaces, mnClosingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount )
+{
+ return pushFunctionOperatorToken( rFuncInfo, nParamCount, mnLeadingSpaces, mnClosingSpaces ) && resetSpaces();
+}
+
+// reference conversion -------------------------------------------------------
+
+void FormulaParserImpl::initReference2d( SingleReference& orApiRef ) const
+{
+ if( mpContext->isAlways3dRefs() )
+ {
+ initReference3d( orApiRef, mpContext->getBaseAddress().Sheet );
+ }
+ else
+ {
+ orApiRef.Flags = SHEET_RELATIVE;
+ // #i10184# absolute sheet index needed for relative references in shared formulas
+ orApiRef.Sheet = mpContext->getBaseAddress().Sheet;
+ orApiRef.RelativeSheet = 0;
+ }
+}
+
+void FormulaParserImpl::initReference3d( SingleReference& orApiRef, sal_Int32 nSheet ) const
+{
+ orApiRef.Flags = SHEET_3D;
+ if( nSheet < 0 )
+ {
+ orApiRef.Sheet = 0;
+ orApiRef.Flags |= SHEET_DELETED;
+ }
+ else
+ {
+ orApiRef.Sheet = nSheet;
+ }
+}
+
+void FormulaParserImpl::convertReference( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
+{
+ if( bDeleted )
+ {
+ orApiRef.Column = 0;
+ orApiRef.Row = 0;
+ // no explicit information about whether row or column is deleted
+ orApiRef.Flags |= COLUMN_DELETED | ROW_DELETED;
+ }
+ else
+ {
+ // column/row indexes and flags
+ setFlag( orApiRef.Flags, COLUMN_RELATIVE, rRef.mbColRel );
+ setFlag( orApiRef.Flags, ROW_RELATIVE, rRef.mbRowRel );
+ (rRef.mbColRel ? orApiRef.RelativeColumn : orApiRef.Column) = rRef.mnCol;
+ (rRef.mbRowRel ? orApiRef.RelativeRow : orApiRef.Row) = rRef.mnRow;
+ // convert absolute indexes to relative offsets used in API
+ if( !bRelativeAsOffset )
+ {
+ if( rRef.mbColRel )
+ orApiRef.RelativeColumn -= mpContext->getBaseAddress().Column;
+ if( rRef.mbRowRel )
+ orApiRef.RelativeRow -= mpContext->getBaseAddress().Row;
+ }
+ }
+}
+
+void FormulaParserImpl::convertReference( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
+{
+ convertReference( orApiRef.Reference1, rRef1, bDeleted, bRelativeAsOffset );
+ convertReference( orApiRef.Reference2, rRef2, bDeleted, bRelativeAsOffset );
+ /* Handle references to complete rows or columns (e.g. $1:$2 or C:D),
+ need to expand or shrink to limits of own document. */
+ if( !bDeleted && !rRef1.mbColRel && !rRef2.mbColRel && (orApiRef.Reference1.Column == 0) && (orApiRef.Reference2.Column == mnMaxXlsCol) )
+ orApiRef.Reference2.Column = mnMaxApiCol;
+ if( !bDeleted && !rRef1.mbRowRel && !rRef2.mbRowRel && (orApiRef.Reference1.Row == 0) && (orApiRef.Reference2.Row == mnMaxXlsRow) )
+ orApiRef.Reference2.Row = mnMaxApiRow;
+}
+
+void FormulaParserImpl::convertReference2d( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
+{
+ initReference2d( orApiRef );
+ convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
+}
+
+void FormulaParserImpl::convertReference2d( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
+{
+ initReference2d( orApiRef.Reference1 );
+ initReference2d( orApiRef.Reference2 );
+ convertReference( orApiRef, rRef1, rRef2, bDeleted, bRelativeAsOffset );
+ // remove sheet name from second part of reference
+ setFlag( orApiRef.Reference2.Flags, SHEET_3D, false );
+}
+
+void FormulaParserImpl::convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
+{
+ initReference3d( orApiRef, nSheet );
+ convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
+}
+
+void FormulaParserImpl::convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
+{
+ initReference3d( orApiRef.Reference1, rSheetRange.isDeleted() ? -1 : rSheetRange.mnFirst );
+ initReference3d( orApiRef.Reference2, rSheetRange.isDeleted() ? -1 : rSheetRange.mnLast );
+ convertReference( orApiRef, rRef1, rRef2, bDeleted, bRelativeAsOffset );
+ // remove sheet name from second part of reference
+ setFlag( orApiRef.Reference2.Flags, SHEET_3D, rSheetRange.is3dRange() );
+}
+
+// finalize token sequence ----------------------------------------------------
+
+void FormulaParserImpl::processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd )
+{
+ while( pToken < pTokenEnd )
+ {
+ // push the current token into the vector
+ appendFinalToken( *pToken );
+ // try to process a function, otherwise go to next token
+ if( const FunctionInfo* pFuncInfo = mrFuncProv.getFuncInfoFromApiToken( *pToken ) )
+ pToken = processParameters( *pFuncInfo, pToken + 1, pTokenEnd );
+ else
+ ++pToken;
+ }
+}
+
+const ApiToken* FormulaParserImpl::processParameters(
+ const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd )
+{
+ // remember position of the token containing the function op-code
+ size_t nFuncNameIdx = maTokenStorage.size() - 1;
+
+ // process a function, if an OPCODE_OPEN token is following
+ OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_OPEN), "FormulaParserImpl::processParameters - OPCODE_OPEN expected" );
+ if( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_OPEN) )
+ {
+ // append the OPCODE_OPEN token to the vector
+ appendFinalToken( mrFuncProv.OPCODE_OPEN );
+
+ // store positions of OPCODE_OPEN, parameter separators, and OPCODE_CLOSE
+ ParameterPosVector aParams;
+ pToken = findParameters( aParams, pToken, pTokenEnd );
+ OSL_ENSURE( aParams.size() >= 2, "FormulaParserImpl::processParameters - missing tokens" );
+ size_t nParamCount = aParams.size() - 1;
+
+ if( (nParamCount == 1) && isEmptyParameter( aParams[ 0 ] + 1, aParams[ 1 ] ) )
+ {
+ /* Empty pair of parentheses -> function call without parameters,
+ process parameter, there might be spaces between parentheses. */
+ processTokens( aParams[ 0 ] + 1, aParams[ 1 ] );
+ }
+ else
+ {
+ const FunctionInfo* pRealFuncInfo = &rFuncInfo;
+ ParameterPosVector::const_iterator aPosIt = aParams.begin();
+
+ // preprocess add-ins, first parameter is reference to function name
+ if( rFuncInfo.mnOobFuncId == OOBIN_FUNC_EXTERNCALL )
+ {
+ OUString aName = getExternCallParameter( *aPosIt + 1, *(aPosIt + 1) );
+ if( const FunctionInfo* pExtFuncInfo = mrFuncProv.getFuncInfoFromExternCallName( aName ) )
+ {
+ maTokenStorage[ nFuncNameIdx ].OpCode = pExtFuncInfo->mnApiOpCode;
+ // insert programmatic add-in function name
+ if( pExtFuncInfo->mnApiOpCode == mrFuncProv.OPCODE_EXTERNAL )
+ maTokenStorage[ nFuncNameIdx ].Data <<= pExtFuncInfo->maExtProgName;
+ // prepare for following parameters
+ pRealFuncInfo = pExtFuncInfo;
+ --nParamCount;
+ ++aPosIt;
+ }
+ }
+
+ // process all parameters
+ FuncInfoParamClassIterator aClassIt( *pRealFuncInfo );
+ size_t nLastValidSize = maTokenStorage.size();
+ size_t nLastValidCount = 0;
+ for( size_t nParam = 0; nParam < nParamCount; ++nParam, ++aPosIt, ++aClassIt )
+ {
+ // add embedded Calc-only parameters
+ if( aClassIt.isCalcOnlyParam() )
+ {
+ appendCalcOnlyParameter( *pRealFuncInfo, nParam );
+ while( aClassIt.isCalcOnlyParam() ) ++aClassIt;
+ }
+
+ const ApiToken* pParamBegin = *aPosIt + 1;
+ const ApiToken* pParamEnd = *(aPosIt + 1);
+ bool bIsEmpty = isEmptyParameter( pParamBegin, pParamEnd );
+
+ if( !aClassIt.isExcelOnlyParam() )
+ {
+ // replace empty second and third parameter in IF function with zeros
+ if( (pRealFuncInfo->mnOobFuncId == OOBIN_FUNC_IF) && ((nParam == 1) || (nParam == 2)) && bIsEmpty )
+ {
+ appendFinalToken( mrFuncProv.OPCODE_PUSH ) <<= static_cast< double >( 0.0 );
+ bIsEmpty = false;
+ }
+ else
+ {
+ // process all tokens of the parameter
+ processTokens( pParamBegin, pParamEnd );
+ }
+ // append parameter separator token
+ appendFinalToken( mrFuncProv.OPCODE_SEP );
+ }
+
+ /* #84453# Update size of new token sequence with valid parameters
+ to be able to remove trailing optional empty parameters. */
+ if( !bIsEmpty || (nParam < pRealFuncInfo->mnMinParamCount) )
+ {
+ nLastValidSize = maTokenStorage.size();
+ nLastValidCount = nParam + 1;
+ }
+ }
+
+ // #84453# remove trailing optional empty parameters
+ maTokenStorage.resize( nLastValidSize );
+
+ // add trailing Calc-only parameters
+ if( aClassIt.isCalcOnlyParam() )
+ appendCalcOnlyParameter( *pRealFuncInfo, nLastValidCount );
+
+ // add optional parameters that are required in Calc
+ appendRequiredParameters( *pRealFuncInfo, nLastValidCount );
+
+ // remove last parameter separator token
+ if( maTokenStorage.back().OpCode == mrFuncProv.OPCODE_SEP )
+ maTokenStorage.pop_back();
+ }
+
+ /* Append the OPCODE_CLOSE token to the vector, but only if there is
+ no OPCODE_BAD token at the end, this token already contains the
+ trailing closing parentheses. */
+ if( (pTokenEnd - 1)->OpCode != mrFuncProv.OPCODE_BAD )
+ appendFinalToken( mrFuncProv.OPCODE_CLOSE );
+ }
+
+ /* Replace OPCODE_EXTERNAL with OPCODE_NONAME to get #NAME! error in cell,
+ if no matching add-in function was found. */
+ ApiToken& rFuncNameToken = maTokenStorage[ nFuncNameIdx ];
+ if( (rFuncNameToken.OpCode == mrFuncProv.OPCODE_EXTERNAL) && !rFuncNameToken.Data.hasValue() )
+ rFuncNameToken.OpCode = mrFuncProv.OPCODE_NONAME;
+
+ return pToken;
+}
+
+bool FormulaParserImpl::isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+ while( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_SPACES) ) ++pToken;
+ if( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_MISSING) ) ++pToken;
+ while( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_SPACES) ) ++pToken;
+ return pToken == pTokenEnd;
+}
+
+OUString FormulaParserImpl::getExternCallParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+ OUString aExtCallName;
+ while( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_SPACES) ) ++pToken;
+ if( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_MACRO) ) (pToken++)->Data >>= aExtCallName;
+ while( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_SPACES) ) ++pToken;
+ return (pToken == pTokenEnd) ? aExtCallName : OUString();
+}
+
+const ApiToken* FormulaParserImpl::skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+ // skip tokens between OPCODE_OPEN and OPCODE_CLOSE
+ OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_OPEN), "skipParentheses - OPCODE_OPEN expected" );
+ ++pToken;
+ while( (pToken < pTokenEnd) && (pToken->OpCode != mrFuncProv.OPCODE_CLOSE) )
+ {
+ if( pToken->OpCode == mrFuncProv.OPCODE_OPEN )
+ pToken = skipParentheses( pToken, pTokenEnd );
+ else
+ ++pToken;
+ }
+ // skip the OPCODE_CLOSE token
+ OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == mrFuncProv.OPCODE_BAD), "skipParentheses - OPCODE_CLOSE expected" );
+ return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
+}
+
+const ApiToken* FormulaParserImpl::findParameters( ParameterPosVector& rParams,
+ const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+ // push position of OPCODE_OPEN
+ OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_OPEN), "FormulaParserImpl::findParameters - OPCODE_OPEN expected" );
+ rParams.push_back( pToken++ );
+
+ // find positions of parameter separators
+ while( (pToken < pTokenEnd) && (pToken->OpCode != mrFuncProv.OPCODE_CLOSE) )
+ {
+ if( pToken->OpCode == mrFuncProv.OPCODE_OPEN )
+ pToken = skipParentheses( pToken, pTokenEnd );
+ else if( pToken->OpCode == mrFuncProv.OPCODE_SEP )
+ rParams.push_back( pToken++ );
+ else
+ ++pToken;
+ }
+
+ // push position of OPCODE_CLOSE
+ OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == mrFuncProv.OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == mrFuncProv.OPCODE_BAD), "FormulaParserImpl::findParameters - OPCODE_CLOSE expected" );
+ rParams.push_back( pToken );
+ return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
+}
+
+void FormulaParserImpl::appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
+{
+ (void)nParam; // prevent 'unused' warning
+ switch( rFuncInfo.mnOobFuncId )
+ {
+ case OOBIN_FUNC_FLOOR:
+ case OOBIN_FUNC_CEILING:
+ OSL_ENSURE( nParam == 2, "FormulaParserImpl::appendCalcOnlyParameter - unexpected parameter index" );
+ appendFinalToken( mrFuncProv.OPCODE_PUSH ) <<= static_cast< double >( 1.0 );
+ appendFinalToken( mrFuncProv.OPCODE_SEP );
+ break;
+ }
+}
+
+void FormulaParserImpl::appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount )
+{
+ switch( rFuncInfo.mnOobFuncId )
+ {
+ case OOBIN_FUNC_WEEKNUM:
+ if( nParamCount == 1 )
+ {
+ appendFinalToken( mrFuncProv.OPCODE_PUSH ) <<= static_cast< double >( 1.0 );
+ appendFinalToken( mrFuncProv.OPCODE_SEP );
+ }
+ break;
+ }
+}
+
+void FormulaParserImpl::appendFinalToken( const ApiToken& rToken )
+{
+ if( (rToken.OpCode == mrFuncProv.OPCODE_MACRO) && !rToken.Data.hasValue() )
+ {
+ appendFinalToken( mrFuncProv.OPCODE_ARRAY_OPEN );
+ appendFinalToken( mrFuncProv.OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NAME );
+ appendFinalToken( mrFuncProv.OPCODE_ARRAY_CLOSE );
+ }
+ else
+ maTokenStorage.push_back( rToken );
+}
+
+Any& FormulaParserImpl::appendFinalToken( sal_Int32 nOpCode )
+{
+ maTokenStorage.resize( maTokenStorage.size() + 1 );
+ maTokenStorage.back().OpCode = nOpCode;
+ return maTokenStorage.back().Data;
+}
+
+// OOX parser implementation ==================================================
+
+class OoxFormulaParserImpl : public FormulaParserImpl
+{
+public:
+ explicit OoxFormulaParserImpl(
+ const WorkbookHelper& rHelper,
+ const FunctionProvider& rFuncProv );
+
+ virtual void importOoxFormula(
+ FormulaContext& rContext,
+ const OUString& rFormulaString );
+
+ virtual void importOobFormula(
+ FormulaContext& rContext,
+ RecordInputStream& rStrm );
+
+private:
+ // import token contents and create API formula token ---------------------
+
+ bool importAttrToken( RecordInputStream& rStrm );
+ bool importSpaceToken( RecordInputStream& rStrm );
+ bool importTableToken( RecordInputStream& rStrm );
+ bool importArrayToken( RecordInputStream& rStrm );
+ bool importRefToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importAreaToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importRef3dToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importArea3dToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importMemAreaToken( RecordInputStream& rStrm, bool bAddData );
+ bool importMemFuncToken( RecordInputStream& rStrm );
+ bool importNameToken( RecordInputStream& rStrm );
+ bool importNameXToken( RecordInputStream& rStrm );
+ bool importFuncToken( RecordInputStream& rStrm );
+ bool importFuncVarToken( RecordInputStream& rStrm );
+ bool importExpToken( RecordInputStream& rStrm );
+
+ LinkSheetRange readSheetRange( RecordInputStream& rStrm );
+
+ void swapStreamPosition( RecordInputStream& rStrm );
+ void skipMemAreaAddData( RecordInputStream& rStrm );
+
+ // convert BIN token and push API operand or operator ---------------------
+
+ bool pushOobName( sal_Int32 nNameId );
+ bool pushOobExtName( sal_Int32 nRefId, sal_Int32 nNameId );
+ bool pushOobFunction( sal_uInt16 nFuncId );
+ bool pushOobFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount );
+
+private:
+ Reference< XFormulaParser > mxParser;
+ PropertySet maParserProps;
+ const OUString maRefPosProp;
+ sal_Int32 mnAddDataPos; /// Current stream position for additional data (tExp, tArray, tMemArea).
+};
+
+// ----------------------------------------------------------------------------
+
+OoxFormulaParserImpl::OoxFormulaParserImpl( const WorkbookHelper& rHelper, const FunctionProvider& rFuncProv ) :
+ FormulaParserImpl( rHelper, rFuncProv ),
+ maRefPosProp( CREATE_OUSTRING( "ReferencePosition" ) ),
+ mnAddDataPos( 0 )
+{
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( getDocument(), UNO_QUERY_THROW );
+ mxParser.set( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.sheet.FormulaParser" ) ), UNO_QUERY_THROW );
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( mxParser.is(), "OoxFormulaParserImpl::OoxFormulaParserImpl - cannot create formula parser" );
+ maParserProps.set( mxParser );
+ maParserProps.setProperty( CREATE_OUSTRING( "CompileEnglish" ), true );
+ maParserProps.setProperty( CREATE_OUSTRING( "R1C1Notation" ), false );
+ maParserProps.setProperty( CREATE_OUSTRING( "Compatibility3DNotation" ), true );
+ maParserProps.setProperty( CREATE_OUSTRING( "IgnoreLeadingSpaces" ), false );
+ maParserProps.setProperty( CREATE_OUSTRING( "OpCodeMap" ), mrFuncProv.getOoxParserMap() );
+}
+
+void OoxFormulaParserImpl::importOoxFormula(
+ FormulaContext& rContext, const OUString& rFormulaString )
+{
+ if( mxParser.is() )
+ {
+ initializeImport( rContext );
+ maParserProps.setProperty( maRefPosProp, getFormulaContext().getBaseAddress() );
+ finalizeImport( mxParser->parseFormula( rFormulaString ) );
+ }
+}
+
+void OoxFormulaParserImpl::importOobFormula( FormulaContext& rContext, RecordInputStream& rStrm )
+{
+ initializeImport( rContext );
+
+ sal_Int32 nFmlaSize = rStrm.readInt32();
+ sal_Int32 nFmlaPos = rStrm.getRecPos();
+ sal_Int32 nFmlaEndPos = nFmlaPos + nFmlaSize;
+
+ rStrm.seek( nFmlaEndPos );
+ sal_Int32 nAddDataSize = rStrm.readInt32();
+ mnAddDataPos = rStrm.getRecPos();
+ sal_Int32 nAddDataEndPos = mnAddDataPos + nAddDataSize;
+ rStrm.seek( nFmlaPos );
+
+ bool bOk = (nFmlaSize >= 0) && (nAddDataSize >= 0);
+ bool bRelativeAsOffset = getFormulaContext().isRelativeAsOffset();
+
+ while( bOk && rStrm.isValid() && (rStrm.getRecPos() < nFmlaEndPos) )
+ {
+ sal_uInt8 nTokenId;
+ rStrm >> nTokenId;
+ sal_uInt8 nTokenClass = nTokenId & BIFF_TOKCLASS_MASK;
+ sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
+
+ if( nTokenClass == BIFF_TOKCLASS_NONE )
+ {
+ // base tokens
+ switch( nBaseId )
+ {
+ case BIFF_TOKID_EXP: bOk = importExpToken( rStrm ); break;
+ case BIFF_TOKID_ADD: bOk = pushBinaryOperator( mrFuncProv.OPCODE_ADD ); break;
+ case BIFF_TOKID_SUB: bOk = pushBinaryOperator( mrFuncProv.OPCODE_SUB ); break;
+ case BIFF_TOKID_MUL: bOk = pushBinaryOperator( mrFuncProv.OPCODE_MULT ); break;
+ case BIFF_TOKID_DIV: bOk = pushBinaryOperator( mrFuncProv.OPCODE_DIV ); break;
+ case BIFF_TOKID_POWER: bOk = pushBinaryOperator( mrFuncProv.OPCODE_POWER ); break;
+ case BIFF_TOKID_CONCAT: bOk = pushBinaryOperator( mrFuncProv.OPCODE_CONCAT ); break;
+ case BIFF_TOKID_LT: bOk = pushBinaryOperator( mrFuncProv.OPCODE_LESS ); break;
+ case BIFF_TOKID_LE: bOk = pushBinaryOperator( mrFuncProv.OPCODE_LESS_EQUAL ); break;
+ case BIFF_TOKID_EQ: bOk = pushBinaryOperator( mrFuncProv.OPCODE_EQUAL ); break;
+ case BIFF_TOKID_GE: bOk = pushBinaryOperator( mrFuncProv.OPCODE_GREATER_EQUAL ); break;
+ case BIFF_TOKID_GT: bOk = pushBinaryOperator( mrFuncProv.OPCODE_GREATER ); break;
+ case BIFF_TOKID_NE: bOk = pushBinaryOperator( mrFuncProv.OPCODE_NOT_EQUAL ); break;
+ case BIFF_TOKID_ISECT: bOk = pushBinaryOperator( mrFuncProv.OPCODE_INTERSECT ); break;
+ case BIFF_TOKID_LIST: bOk = pushBinaryOperator( mrFuncProv.OPCODE_LIST ); break;
+ case BIFF_TOKID_RANGE: bOk = pushBinaryOperator( mrFuncProv.OPCODE_RANGE ); break;
+ case BIFF_TOKID_UPLUS: bOk = pushUnaryPreOperator( mrFuncProv.OPCODE_PLUS_SIGN ); break;
+ case BIFF_TOKID_UMINUS: bOk = pushUnaryPreOperator( mrFuncProv.OPCODE_MINUS_SIGN ); break;
+ case BIFF_TOKID_PERCENT: bOk = pushUnaryPostOperator( mrFuncProv.OPCODE_PERCENT ); break;
+ case BIFF_TOKID_PAREN: bOk = pushParenthesesOperator(); break;
+ case BIFF_TOKID_MISSARG: bOk = pushOperand( mrFuncProv.OPCODE_MISSING ); break;
+ case BIFF_TOKID_STR: bOk = pushValueOperand( rStrm.readString( false ) ); break;
+ case BIFF_TOKID_NLR: bOk = importTableToken( rStrm ); break;
+ case BIFF_TOKID_ATTR: bOk = importAttrToken( rStrm ); break;
+ case BIFF_TOKID_ERR: bOk = pushBiffErrorOperand( rStrm.readuInt8() ); break;
+ case BIFF_TOKID_BOOL: bOk = pushBoolOperand( rStrm.readuInt8() != BIFF_TOK_BOOL_FALSE ); break;
+ case BIFF_TOKID_INT: bOk = pushValueOperand< double >( rStrm.readuInt16() ); break;
+ case BIFF_TOKID_NUM: bOk = pushValueOperand( rStrm.readDouble() ); break;
+ default: bOk = false;
+ }
+ }
+ else
+ {
+ // classified tokens
+ switch( nBaseId )
+ {
+ case BIFF_TOKID_ARRAY: bOk = importArrayToken( rStrm ); break;
+ case BIFF_TOKID_FUNC: bOk = importFuncToken( rStrm ); break;
+ case BIFF_TOKID_FUNCVAR: bOk = importFuncVarToken( rStrm ); break;
+ case BIFF_TOKID_NAME: bOk = importNameToken( rStrm ); break;
+ case BIFF_TOKID_REF: bOk = importRefToken( rStrm, false, false ); break;
+ case BIFF_TOKID_AREA: bOk = importAreaToken( rStrm, false, false ); break;
+ case BIFF_TOKID_MEMAREA: bOk = importMemAreaToken( rStrm, true ); break;
+ case BIFF_TOKID_MEMERR: bOk = importMemAreaToken( rStrm, false ); break;
+ case BIFF_TOKID_MEMNOMEM: bOk = importMemAreaToken( rStrm, false ); break;
+ case BIFF_TOKID_MEMFUNC: bOk = importMemFuncToken( rStrm ); break;
+ case BIFF_TOKID_REFERR: bOk = importRefToken( rStrm, true, false ); break;
+ case BIFF_TOKID_AREAERR: bOk = importAreaToken( rStrm, true, false ); break;
+ case BIFF_TOKID_REFN: bOk = importRefToken( rStrm, false, true ); break;
+ case BIFF_TOKID_AREAN: bOk = importAreaToken( rStrm, false, true ); break;
+ case BIFF_TOKID_MEMAREAN: bOk = importMemFuncToken( rStrm ); break;
+ case BIFF_TOKID_MEMNOMEMN: bOk = importMemFuncToken( rStrm ); break;
+ case BIFF_TOKID_NAMEX: bOk = importNameXToken( rStrm ); break;
+ case BIFF_TOKID_REF3D: bOk = importRef3dToken( rStrm, false, bRelativeAsOffset ); break;
+ case BIFF_TOKID_AREA3D: bOk = importArea3dToken( rStrm, false, bRelativeAsOffset ); break;
+ case BIFF_TOKID_REFERR3D: bOk = importRef3dToken( rStrm, true, bRelativeAsOffset ); break;
+ case BIFF_TOKID_AREAERR3D: bOk = importArea3dToken( rStrm, true, bRelativeAsOffset ); break;
+ default: bOk = false;
+ }
+ }
+ }
+
+ // build and finalize the token sequence
+ if( bOk && (rStrm.getRecPos() == nFmlaEndPos) && (mnAddDataPos == nAddDataEndPos) )
+ finalizeImport();
+
+ // seek behind token array
+ if( (nFmlaSize >= 0) && (nAddDataSize >= 0) )
+ rStrm.seek( nAddDataEndPos );
+}
+
+// import token contents and create API formula token -------------------------
+
+bool OoxFormulaParserImpl::importAttrToken( RecordInputStream& rStrm )
+{
+ bool bOk = true;
+ sal_uInt8 nType;
+ rStrm >> nType;
+ // equal flags in BIFF and OOBIN
+ switch( nType )
+ {
+ case OOBIN_TOK_ATTR_VOLATILE:
+ case OOBIN_TOK_ATTR_IF:
+ case OOBIN_TOK_ATTR_SKIP:
+ case OOBIN_TOK_ATTR_ASSIGN:
+ case OOBIN_TOK_ATTR_IFERROR:
+ rStrm.skip( 2 );
+ break;
+ case OOBIN_TOK_ATTR_CHOOSE:
+ rStrm.skip( 2 * rStrm.readuInt16() + 2 );
+ break;
+ case OOBIN_TOK_ATTR_SUM:
+ rStrm.skip( 2 );
+ bOk = pushOobFunction( OOBIN_FUNC_SUM, 1 );
+ break;
+ case OOBIN_TOK_ATTR_SPACE:
+ case OOBIN_TOK_ATTR_SPACE_VOLATILE:
+ bOk = importSpaceToken( rStrm );
+ break;
+ default:
+ bOk = false;
+ }
+ return bOk;
+}
+
+bool OoxFormulaParserImpl::importSpaceToken( RecordInputStream& rStrm )
+{
+ // equal constants in BIFF and OOX
+ sal_uInt8 nType, nCount;
+ rStrm >> nType >> nCount;
+ switch( nType )
+ {
+ case BIFF_TOK_ATTR_SPACE_SP:
+ case BIFF_TOK_ATTR_SPACE_BR:
+ incLeadingSpaces( nCount );
+ break;
+ case BIFF_TOK_ATTR_SPACE_SP_OPEN:
+ case BIFF_TOK_ATTR_SPACE_BR_OPEN:
+ incOpeningSpaces( nCount );
+ break;
+ case BIFF_TOK_ATTR_SPACE_SP_CLOSE:
+ case BIFF_TOK_ATTR_SPACE_BR_CLOSE:
+ incClosingSpaces( nCount );
+ break;
+ }
+ return true;
+}
+
+bool OoxFormulaParserImpl::importTableToken( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags, nTableId, nCol1, nCol2;
+ rStrm.skip( 3 );
+ rStrm >> nFlags >> nTableId;
+ rStrm.skip( 2 );
+ rStrm >> nCol1 >> nCol2;
+ TableRef xTable = getTables().getTable( nTableId );
+ sal_Int32 nTokenIndex = xTable.get() ? xTable->getTokenIndex() : -1;
+ if( nTokenIndex >= 0 )
+ {
+ sal_Int32 nWidth = xTable->getWidth();
+ sal_Int32 nHeight = xTable->getHeight();
+ sal_Int32 nStartCol = 0;
+ sal_Int32 nEndCol = nWidth - 1;
+ sal_Int32 nStartRow = 0;
+ sal_Int32 nEndRow = nHeight - 1;
+ bool bFixedStartRow = true;
+ bool bFixedHeight = false;
+
+ bool bSingleCol = getFlag( nFlags, OOBIN_TOK_TABLE_COLUMN );
+ bool bColRange = getFlag( nFlags, OOBIN_TOK_TABLE_COLRANGE );
+ bool bValidRef = !bSingleCol || !bColRange;
+ OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - illegal combination of single column and column range" );
+ if( bValidRef )
+ {
+ if( bSingleCol )
+ nStartCol = nEndCol = nCol1;
+ else if( bColRange )
+ { nStartCol = nCol1; nEndCol = nCol2; }
+ bValidRef = (nStartCol <= nEndCol) && (nEndCol < nWidth);
+ OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - invalid column range" );
+ }
+
+ if( bValidRef )
+ {
+ bool bAllRows = getFlag( nFlags, OOBIN_TOK_TABLE_ALL );
+ bool bHeaderRows = getFlag( nFlags, OOBIN_TOK_TABLE_HEADERS );
+ bool bDataRows = getFlag( nFlags, OOBIN_TOK_TABLE_DATA );
+ bool bTotalsRows = getFlag( nFlags, OOBIN_TOK_TABLE_TOTALS );
+ bool bThisRow = getFlag( nFlags, OOBIN_TOK_TABLE_THISROW );
+
+ sal_Int32 nStartDataRow = xTable->getHeaderRows();
+ sal_Int32 nEndDataRow = nEndRow - xTable->getTotalsRows();
+ bValidRef = (nStartRow <= nStartDataRow) && (nStartDataRow <= nEndDataRow) && (nEndDataRow <= nEndRow);
+ OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - invalid data row range" );
+ if( bValidRef )
+ {
+ if( bAllRows )
+ {
+ bValidRef = !bHeaderRows && !bDataRows && !bTotalsRows && !bThisRow;
+ OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#All] table token" );
+ }
+ else if( bHeaderRows )
+ {
+ bValidRef = !bTotalsRows && !bThisRow;
+ OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Headers] table token" );
+ nEndRow = bDataRows ? nEndDataRow : (nStartDataRow - 1);
+ bFixedHeight = !bDataRows;
+ }
+ else if( bDataRows )
+ {
+ bValidRef = !bThisRow;
+ OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Data] table token" );
+ nStartRow = nStartDataRow;
+ if( !bTotalsRows ) nEndRow = nEndDataRow;
+ }
+ else if( bTotalsRows )
+ {
+ bValidRef = !bThisRow;
+ OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Totals] table token" );
+ nStartRow = nEndDataRow + 1;
+ bFixedStartRow = false;
+ bFixedHeight = !bDataRows;
+ }
+ else if( bThisRow )
+ {
+ nStartRow = nEndRow = getFormulaContext().getBaseAddress().Row - xTable->getRange().StartRow;
+ bFixedHeight = true;
+ }
+ else
+ {
+ // nothing is the same as [#Data]
+ nStartRow = nStartDataRow;
+ nEndRow = nEndDataRow;
+ }
+ }
+ if( bValidRef )
+ bValidRef = (0 <= nStartRow) && (nStartRow <= nEndRow) && (nEndRow < nHeight);
+ }
+ if( bValidRef )
+ {
+ // push single database area token, if table token refers to entire table
+ if( (nStartCol == 0) && (nEndCol + 1 == nWidth) && (nStartRow == 0) && (nEndRow + 1 == nHeight) )
+ return pushValueOperand( nTokenIndex, mrFuncProv.OPCODE_DBAREA );
+ // create an OFFSET function call to refer to a subrange of the table
+ const FunctionInfo* pRowsInfo = mrFuncProv.getFuncInfoFromOobFuncId( OOBIN_FUNC_ROWS );
+ const FunctionInfo* pColumnsInfo = mrFuncProv.getFuncInfoFromOobFuncId( OOBIN_FUNC_COLUMNS );
+ return
+ pRowsInfo && pColumnsInfo &&
+ pushValueOperandToken( nTokenIndex, mrFuncProv.OPCODE_DBAREA, 0 ) &&
+ (bFixedStartRow ?
+ pushValueOperandToken< double >( nStartRow, 0 ) :
+ (pushValueOperandToken( nTokenIndex, mrFuncProv.OPCODE_DBAREA, 0 ) &&
+ pushFunctionOperatorToken( *pRowsInfo, 1, 0, 0 ) &&
+ pushValueOperandToken< double >( nHeight - nStartRow, 0 ) &&
+ pushBinaryOperatorToken( mrFuncProv.OPCODE_SUB, 0 ))) &&
+ pushValueOperandToken< double >( nStartCol, 0 ) &&
+ (bFixedHeight ?
+ pushValueOperandToken< double >( nEndRow - nStartRow + 1, 0 ) :
+ (pushValueOperandToken( nTokenIndex, mrFuncProv.OPCODE_DBAREA, 0 ) &&
+ pushFunctionOperatorToken( *pRowsInfo, 1, 0, 0 ) &&
+ (((nStartRow == 0) && (nEndRow + 1 == nHeight)) ||
+ (pushValueOperandToken< double >( nHeight - (nEndRow - nStartRow + 1), 0 ) &&
+ pushBinaryOperatorToken( mrFuncProv.OPCODE_SUB, 0 ))))) &&
+ (((nStartCol == 0) && (nEndCol + 1 == nWidth)) ?
+ (pushValueOperandToken( nTokenIndex, mrFuncProv.OPCODE_DBAREA, 0 ) &&
+ pushFunctionOperatorToken( *pColumnsInfo, 1, 0, 0 )) :
+ pushValueOperandToken< double >( nEndCol - nStartCol + 1, 0 )) &&
+ pushOobFunction( OOBIN_FUNC_OFFSET, 5 );
+ }
+ }
+ return pushBiffErrorOperand( BIFF_ERR_REF );
+}
+
+bool OoxFormulaParserImpl::importArrayToken( RecordInputStream& rStrm )
+{
+ rStrm.skip( 14 );
+
+ // start token array with opening brace and leading spaces
+ pushOperand( mrFuncProv.OPCODE_ARRAY_OPEN );
+ size_t nOpSize = popOperandSize();
+ size_t nOldArraySize = getFormulaSize();
+
+ // read array size
+ swapStreamPosition( rStrm );
+ sal_Int32 nRows = rStrm.readInt32();
+ sal_Int32 nCols = rStrm.readInt32();
+ OSL_ENSURE( (nCols > 0) && (nRows > 0), "OoxFormulaParserImpl::importArrayToken - empty array" );
+
+ // read array values and build token array
+ for( sal_Int32 nRow = 0; rStrm.isValid() && (nRow < nRows); ++nRow )
+ {
+ if( nRow > 0 )
+ appendRawToken( mrFuncProv.OPCODE_ARRAY_ROWSEP );
+ for( sal_Int32 nCol = 0; rStrm.isValid() && (nCol < nCols); ++nCol )
+ {
+ if( nCol > 0 )
+ appendRawToken( mrFuncProv.OPCODE_ARRAY_COLSEP );
+ switch( rStrm.readuInt8() )
+ {
+ case OOBIN_TOK_ARRAY_DOUBLE:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= rStrm.readDouble();
+ break;
+ case OOBIN_TOK_ARRAY_STRING:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= rStrm.readString( false );
+ break;
+ case OOBIN_TOK_ARRAY_BOOL:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
+ break;
+ case OOBIN_TOK_ARRAY_ERROR:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
+ rStrm.skip( 3 );
+ break;
+ default:
+ OSL_ENSURE( false, "OoxFormulaParserImpl::importArrayToken - unknown data type" );
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
+ }
+ }
+ }
+ swapStreamPosition( rStrm );
+
+ // close token array and set resulting operand size
+ appendRawToken( mrFuncProv.OPCODE_ARRAY_CLOSE );
+ pushOperandSize( nOpSize + getFormulaSize() - nOldArraySize );
+ return true;
+}
+
+bool OoxFormulaParserImpl::importRefToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ BinSingleRef2d aRef;
+ aRef.readOobData( rStrm, bRelativeAsOffset );
+ return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool OoxFormulaParserImpl::importAreaToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ BinComplexRef2d aRef;
+ aRef.readOobData( rStrm, bRelativeAsOffset );
+ return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool OoxFormulaParserImpl::importRef3dToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ LinkSheetRange aSheetRange = readSheetRange( rStrm );
+ BinSingleRef2d aRef;
+ aRef.readOobData( rStrm, bRelativeAsOffset );
+ return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool OoxFormulaParserImpl::importArea3dToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ LinkSheetRange aSheetRange = readSheetRange( rStrm );
+ BinComplexRef2d aRef;
+ aRef.readOobData( rStrm, bRelativeAsOffset );
+ return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool OoxFormulaParserImpl::importMemAreaToken( RecordInputStream& rStrm, bool bAddData )
+{
+ rStrm.skip( 6 );
+ if( bAddData )
+ skipMemAreaAddData( rStrm );
+ return true;
+}
+
+bool OoxFormulaParserImpl::importMemFuncToken( RecordInputStream& rStrm )
+{
+ rStrm.skip( 2 );
+ return true;
+}
+
+bool OoxFormulaParserImpl::importNameToken( RecordInputStream& rStrm )
+{
+ return pushOobName( rStrm.readInt32() );
+}
+
+bool OoxFormulaParserImpl::importNameXToken( RecordInputStream& rStrm )
+{
+ sal_Int32 nRefId = rStrm.readInt16();
+ sal_Int32 nNameId = rStrm.readInt32();
+ return pushOobExtName( nRefId, nNameId );
+}
+
+bool OoxFormulaParserImpl::importFuncToken( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFuncId;
+ rStrm >> nFuncId;
+ return pushOobFunction( nFuncId );
+}
+
+bool OoxFormulaParserImpl::importFuncVarToken( RecordInputStream& rStrm )
+{
+ sal_uInt8 nParamCount;
+ sal_uInt16 nFuncId;
+ rStrm >> nParamCount >> nFuncId;
+ return pushOobFunction( nFuncId, nParamCount );
+}
+
+bool OoxFormulaParserImpl::importExpToken( RecordInputStream& rStrm )
+{
+ BinAddress aBaseAddr;
+ rStrm >> aBaseAddr.mnRow;
+ swapStreamPosition( rStrm );
+ rStrm >> aBaseAddr.mnCol;
+ swapStreamPosition( rStrm );
+ setSharedFormula( aBaseAddr );
+ // formula has been set, exit parser by returning false
+ return false;
+}
+
+LinkSheetRange OoxFormulaParserImpl::readSheetRange( RecordInputStream& rStrm )
+{
+ return getExternalLinks().getSheetRange( rStrm.readInt16() );
+}
+
+void OoxFormulaParserImpl::swapStreamPosition( RecordInputStream& rStrm )
+{
+ sal_Int32 nRecPos = rStrm.getRecPos();
+ rStrm.seek( mnAddDataPos );
+ mnAddDataPos = nRecPos;
+}
+
+void OoxFormulaParserImpl::skipMemAreaAddData( RecordInputStream& rStrm )
+{
+ swapStreamPosition( rStrm );
+ rStrm.skip( 16 * rStrm.readInt32() );
+ swapStreamPosition( rStrm );
+}
+
+// convert BIN token and push API operand or operator -------------------------
+
+bool OoxFormulaParserImpl::pushOobName( sal_Int32 nNameId )
+{
+ // one-based in OOBIN formulas
+ return pushDefinedNameOperand( getDefinedNames().getByIndex( nNameId - 1 ) );
+}
+
+bool OoxFormulaParserImpl::pushOobExtName( sal_Int32 nRefId, sal_Int32 nNameId )
+{
+ if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
+ {
+ if( pExtLink->getLinkType() == LINKTYPE_SELF )
+ return pushOobName( nNameId );
+ // external name indexes are one-based in OOBIN
+ ExternalNameRef xExtName = pExtLink->getNameByIndex( nNameId - 1 );
+ return pushExternalNameOperand( xExtName, pExtLink->getLinkType() );
+ }
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool OoxFormulaParserImpl::pushOobFunction( sal_uInt16 nFuncId )
+{
+ if( const FunctionInfo* pFuncInfo = mrFuncProv.getFuncInfoFromOobFuncId( nFuncId ) )
+ if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
+ return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
+ return pushFunctionOperator( mrFuncProv.OPCODE_NONAME, 0 );
+}
+
+bool OoxFormulaParserImpl::pushOobFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount )
+{
+ if( getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD ) )
+ nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
+ if( const FunctionInfo* pFuncInfo = mrFuncProv.getFuncInfoFromOobFuncId( nFuncId ) )
+ return pushFunctionOperator( *pFuncInfo, nParamCount );
+ return pushFunctionOperator( mrFuncProv.OPCODE_NONAME, nParamCount );
+}
+
+// BIFF parser implementation =================================================
+
+namespace {
+
+/** A natural language reference struct with relative flag. */
+struct BiffNlr
+{
+ sal_Int32 mnCol; /// Column index.
+ sal_Int32 mnRow; /// Row index.
+ bool mbRel; /// True = relative column/row reference.
+
+ explicit BiffNlr();
+
+ void readBiff8Data( BiffInputStream& rStrm );
+};
+
+BiffNlr::BiffNlr() :
+ mnCol( 0 ),
+ mnRow( 0 ),
+ mbRel( false )
+{
+}
+
+void BiffNlr::readBiff8Data( BiffInputStream& rStrm )
+{
+ sal_uInt16 nRow, nCol;
+ rStrm >> nRow >> nCol;
+ mnCol = nCol & BIFF_TOK_NLR_MASK;
+ mnRow = nRow;
+ mbRel = getFlag( nCol, BIFF_TOK_NLR_REL );
+}
+
+bool lclIsValidNlrStack( const BinAddress& rAddr1, const BinAddress& rAddr2, bool bRow )
+{
+ return bRow ?
+ ((rAddr1.mnRow == rAddr2.mnRow) && (rAddr1.mnCol + 1 == rAddr2.mnCol)) :
+ ((rAddr1.mnCol == rAddr2.mnCol) && (rAddr1.mnRow + 1 == rAddr2.mnRow));
+}
+
+bool lclIsValidNlrRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow )
+{
+ return bRow ?
+ ((rNlr.mnRow == rRange.maFirst.mnRow) && (rNlr.mnCol + 1 == rRange.maFirst.mnCol) && (rRange.maFirst.mnRow == rRange.maLast.mnRow)) :
+ ((rNlr.mnCol == rRange.maFirst.mnCol) && (rNlr.mnRow + 1 == rRange.maFirst.mnRow) && (rRange.maFirst.mnCol == rRange.maLast.mnCol));
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+class BiffFormulaParserImpl : public FormulaParserImpl
+{
+public:
+ explicit BiffFormulaParserImpl(
+ const WorkbookHelper& rHelper,
+ const FunctionProvider& rFuncProv );
+
+ virtual void importBiffFormula(
+ FormulaContext& rContext,
+ BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize );
+
+private:
+ // import token contents and create API formula token ---------------------
+
+ bool importTokenNotAvailable( BiffInputStream& rStrm );
+ bool importRefTokenNotAvailable( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importStrToken2( BiffInputStream& rStrm );
+ bool importStrToken8( BiffInputStream& rStrm );
+ bool importAttrToken( BiffInputStream& rStrm );
+ bool importSpaceToken3( BiffInputStream& rStrm );
+ bool importSpaceToken4( BiffInputStream& rStrm );
+ bool importSheetToken2( BiffInputStream& rStrm );
+ bool importSheetToken3( BiffInputStream& rStrm );
+ bool importEndSheetToken2( BiffInputStream& rStrm );
+ bool importEndSheetToken3( BiffInputStream& rStrm );
+ bool importNlrToken( BiffInputStream& rStrm );
+ bool importArrayToken( BiffInputStream& rStrm );
+ bool importRefToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importRefToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importAreaToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importAreaToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importRef3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importRef3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importArea3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importArea3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+ bool importMemAreaToken( BiffInputStream& rStrm, bool bAddData );
+ bool importMemFuncToken( BiffInputStream& rStrm );
+ bool importNameToken( BiffInputStream& rStrm );
+ bool importNameXToken( BiffInputStream& rStrm );
+ bool importFuncToken2( BiffInputStream& rStrm );
+ bool importFuncToken4( BiffInputStream& rStrm );
+ bool importFuncVarToken2( BiffInputStream& rStrm );
+ bool importFuncVarToken4( BiffInputStream& rStrm );
+ bool importFuncCEToken( BiffInputStream& rStrm );
+ bool importExpToken5( BiffInputStream& rStrm );
+
+ bool importNlrAddrToken( BiffInputStream& rStrm, bool bRow );
+ bool importNlrRangeToken( BiffInputStream& rStrm );
+ bool importNlrSAddrToken( BiffInputStream& rStrm, bool bRow );
+ bool importNlrSRangeToken( BiffInputStream& rStrm );
+ bool importNlrErrToken( BiffInputStream& rStrm, sal_uInt16 nSkip );
+
+ sal_Int32 readRefId( BiffInputStream& rStrm );
+ sal_uInt16 readNameId( BiffInputStream& rStrm );
+ LinkSheetRange readSheetRange5( BiffInputStream& rStrm );
+ LinkSheetRange readSheetRange8( BiffInputStream& rStrm );
+
+ void swapStreamPosition( BiffInputStream& rStrm );
+ void skipMemAreaAddData( BiffInputStream& rStrm );
+ bool readNlrSAddrAddData( BiffNlr& orNlr, BiffInputStream& rStrm, bool bRow );
+ bool readNlrSRangeAddData( BiffNlr& orNlr, bool& orbIsRow, BiffInputStream& rStrm );
+
+ // convert BIFF token and push API operand or operator --------------------
+
+ bool pushBiffReference( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
+ bool pushBiffReference( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
+ bool pushBiffNlrAddr( const BiffNlr& rNlr, bool bRow );
+ bool pushBiffNlrRange( const BiffNlr& rNlr, const BinRange& rRange );
+ bool pushBiffNlrSAddr( const BiffNlr& rNlr, bool bRow );
+ bool pushBiffNlrSRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow );
+ bool pushBiffName( sal_uInt16 nNameId );
+ bool pushBiffExtName( sal_Int32 nRefId, sal_uInt16 nNameId );
+ bool pushBiffFunction( sal_uInt16 nFuncId );
+ bool pushBiffFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount );
+
+ // ------------------------------------------------------------------------
+private:
+ typedef bool (BiffFormulaParserImpl::*ImportTokenFunc)( BiffInputStream& );
+ typedef bool (BiffFormulaParserImpl::*ImportRefTokenFunc)( BiffInputStream&, bool, bool );
+
+ ImportTokenFunc mpImportStrToken; /// Pointer to tStr import function (string constant).
+ ImportTokenFunc mpImportSpaceToken; /// Pointer to tAttrSpace import function (spaces/line breaks).
+ ImportTokenFunc mpImportSheetToken; /// Pointer to tSheet import function (external reference).
+ ImportTokenFunc mpImportEndSheetToken; /// Pointer to tEndSheet import function (end of external reference).
+ ImportTokenFunc mpImportNlrToken; /// Pointer to tNlr import function (natural language reference).
+ ImportRefTokenFunc mpImportRefToken; /// Pointer to tRef import function (2d cell reference).
+ ImportRefTokenFunc mpImportAreaToken; /// Pointer to tArea import function (2d area reference).
+ ImportRefTokenFunc mpImportRef3dToken; /// Pointer to tRef3d import function (3d cell reference).
+ ImportRefTokenFunc mpImportArea3dToken; /// Pointer to tArea3d import function (3d area reference).
+ ImportTokenFunc mpImportNameXToken; /// Pointer to tNameX import function (external name).
+ ImportTokenFunc mpImportFuncToken; /// Pointer to tFunc import function (function with fixed parameter count).
+ ImportTokenFunc mpImportFuncVarToken; /// Pointer to tFuncVar import function (function with variable parameter count).
+ ImportTokenFunc mpImportFuncCEToken; /// Pointer to tFuncCE import function (command macro call).
+ ImportTokenFunc mpImportExpToken; /// Pointer to tExp import function (array/shared formula).
+ sal_uInt32 mnAddDataPos; /// Current stream position for additional data (tArray, tMemArea, tNlr).
+ sal_Int32 mnCurrRefId; /// Current ref-id from tSheet token (BIFF2-BIFF4 only).
+ sal_uInt16 mnAttrDataSize; /// Size of one tAttr data element.
+ sal_uInt16 mnArraySize; /// Size of tArray data.
+ sal_uInt16 mnNameSize; /// Size of tName data.
+ sal_uInt16 mnMemAreaSize; /// Size of tMemArea data.
+ sal_uInt16 mnMemFuncSize; /// Size of tMemFunc data.
+ sal_uInt16 mnRefIdSize; /// Size of unused data following a reference identifier.
+};
+
+// ----------------------------------------------------------------------------
+
+BiffFormulaParserImpl::BiffFormulaParserImpl( const WorkbookHelper& rHelper, const FunctionProvider& rFuncProv ) :
+ FormulaParserImpl( rHelper, rFuncProv ),
+ mnAddDataPos( 0 ),
+ mnCurrRefId( 0 )
+{
+ switch( getBiff() )
+ {
+ case BIFF2:
+ mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
+ mpImportSpaceToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken2;
+ mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken2;
+ mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
+ mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
+ mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
+ mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
+ mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken2;
+ mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken2;
+ mpImportFuncCEToken = &BiffFormulaParserImpl::importFuncCEToken;
+ mpImportExpToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mnAttrDataSize = 1;
+ mnArraySize = 6;
+ mnNameSize = 5;
+ mnMemAreaSize = 4;
+ mnMemFuncSize = 1;
+ mnRefIdSize = 1;
+ break;
+ case BIFF3:
+ mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
+ mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken3;
+ mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken3;
+ mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken3;
+ mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
+ mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
+ mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
+ mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
+ mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken2;
+ mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken2;
+ mpImportFuncCEToken = &BiffFormulaParserImpl::importFuncCEToken;
+ mpImportExpToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mnAttrDataSize = 2;
+ mnArraySize = 7;
+ mnNameSize = 8;
+ mnMemAreaSize = 6;
+ mnMemFuncSize = 2;
+ mnRefIdSize = 2;
+ break;
+ case BIFF4:
+ mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
+ mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
+ mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken3;
+ mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken3;
+ mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
+ mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
+ mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
+ mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
+ mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
+ mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
+ mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportExpToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mnAttrDataSize = 2;
+ mnArraySize = 7;
+ mnNameSize = 8;
+ mnMemAreaSize = 6;
+ mnMemFuncSize = 2;
+ mnRefIdSize = 2;
+ break;
+ case BIFF5:
+ mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
+ mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
+ mpImportSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportEndSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
+ mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
+ mpImportRef3dToken = &BiffFormulaParserImpl::importRef3dToken5;
+ mpImportArea3dToken = &BiffFormulaParserImpl::importArea3dToken5;
+ mpImportNameXToken = &BiffFormulaParserImpl::importNameXToken;
+ mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
+ mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
+ mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportExpToken = &BiffFormulaParserImpl::importExpToken5;
+ mnAttrDataSize = 2;
+ mnArraySize = 7;
+ mnNameSize = 12;
+ mnMemAreaSize = 6;
+ mnMemFuncSize = 2;
+ mnRefIdSize = 8;
+ break;
+ case BIFF8:
+ mpImportStrToken = &BiffFormulaParserImpl::importStrToken8;
+ mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
+ mpImportSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportEndSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportNlrToken = &BiffFormulaParserImpl::importNlrToken;
+ mpImportRefToken = &BiffFormulaParserImpl::importRefToken8;
+ mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken8;
+ mpImportRef3dToken = &BiffFormulaParserImpl::importRef3dToken8;
+ mpImportArea3dToken = &BiffFormulaParserImpl::importArea3dToken8;
+ mpImportNameXToken = &BiffFormulaParserImpl::importNameXToken;
+ mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
+ mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
+ mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
+ mpImportExpToken = &BiffFormulaParserImpl::importExpToken5;
+ mnAttrDataSize = 2;
+ mnArraySize = 7;
+ mnNameSize = 2;
+ mnMemAreaSize = 6;
+ mnMemFuncSize = 2;
+ mnRefIdSize = 0;
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+}
+
+void BiffFormulaParserImpl::importBiffFormula( FormulaContext& rContext,
+ BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
+{
+ initializeImport( rContext );
+ mnCurrRefId = 0;
+
+ sal_uInt16 nFmlaSize = pnFmlaSize ? *pnFmlaSize : ((getBiff() == BIFF2) ? rStrm.readuInt8() : rStrm.readuInt16());
+ sal_uInt32 nEndPos = mnAddDataPos = rStrm.getRecPos() + nFmlaSize;
+ bool bRelativeAsOffset = getFormulaContext().isRelativeAsOffset();
+
+ bool bOk = true;
+ while( bOk && rStrm.isValid() && (rStrm.getRecPos() < nEndPos) )
+ {
+ sal_uInt8 nTokenId;
+ rStrm >> nTokenId;
+ sal_uInt8 nTokenClass = nTokenId & BIFF_TOKCLASS_MASK;
+ sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
+
+ if( nTokenClass == BIFF_TOKCLASS_NONE )
+ {
+ // base tokens
+ switch( nBaseId )
+ {
+ case BIFF_TOKID_EXP: bOk = (this->*mpImportExpToken)( rStrm ); break;
+ case BIFF_TOKID_TBL: bOk = false; /* multiple op. will be set externally */ break;
+ case BIFF_TOKID_ADD: bOk = pushBinaryOperator( mrFuncProv.OPCODE_ADD ); break;
+ case BIFF_TOKID_SUB: bOk = pushBinaryOperator( mrFuncProv.OPCODE_SUB ); break;
+ case BIFF_TOKID_MUL: bOk = pushBinaryOperator( mrFuncProv.OPCODE_MULT ); break;
+ case BIFF_TOKID_DIV: bOk = pushBinaryOperator( mrFuncProv.OPCODE_DIV ); break;
+ case BIFF_TOKID_POWER: bOk = pushBinaryOperator( mrFuncProv.OPCODE_POWER ); break;
+ case BIFF_TOKID_CONCAT: bOk = pushBinaryOperator( mrFuncProv.OPCODE_CONCAT ); break;
+ case BIFF_TOKID_LT: bOk = pushBinaryOperator( mrFuncProv.OPCODE_LESS ); break;
+ case BIFF_TOKID_LE: bOk = pushBinaryOperator( mrFuncProv.OPCODE_LESS_EQUAL ); break;
+ case BIFF_TOKID_EQ: bOk = pushBinaryOperator( mrFuncProv.OPCODE_EQUAL ); break;
+ case BIFF_TOKID_GE: bOk = pushBinaryOperator( mrFuncProv.OPCODE_GREATER_EQUAL ); break;
+ case BIFF_TOKID_GT: bOk = pushBinaryOperator( mrFuncProv.OPCODE_GREATER ); break;
+ case BIFF_TOKID_NE: bOk = pushBinaryOperator( mrFuncProv.OPCODE_NOT_EQUAL ); break;
+ case BIFF_TOKID_ISECT: bOk = pushBinaryOperator( mrFuncProv.OPCODE_INTERSECT ); break;
+ case BIFF_TOKID_LIST: bOk = pushBinaryOperator( mrFuncProv.OPCODE_LIST ); break;
+ case BIFF_TOKID_RANGE: bOk = pushBinaryOperator( mrFuncProv.OPCODE_RANGE ); break;
+ case BIFF_TOKID_UPLUS: bOk = pushUnaryPreOperator( mrFuncProv.OPCODE_PLUS_SIGN ); break;
+ case BIFF_TOKID_UMINUS: bOk = pushUnaryPreOperator( mrFuncProv.OPCODE_MINUS_SIGN ); break;
+ case BIFF_TOKID_PERCENT: bOk = pushUnaryPostOperator( mrFuncProv.OPCODE_PERCENT ); break;
+ case BIFF_TOKID_PAREN: bOk = pushParenthesesOperator(); break;
+ case BIFF_TOKID_MISSARG: bOk = pushOperand( mrFuncProv.OPCODE_MISSING ); break;
+ case BIFF_TOKID_STR: bOk = (this->*mpImportStrToken)( rStrm ); break;
+ case BIFF_TOKID_NLR: bOk = (this->*mpImportNlrToken)( rStrm ); break;
+ case BIFF_TOKID_ATTR: bOk = importAttrToken( rStrm ); break;
+ case BIFF_TOKID_SHEET: bOk = (this->*mpImportSheetToken)( rStrm ); break;
+ case BIFF_TOKID_ENDSHEET: bOk = (this->*mpImportEndSheetToken)( rStrm ); break;
+ case BIFF_TOKID_ERR: bOk = pushBiffErrorOperand( rStrm.readuInt8() ); break;
+ case BIFF_TOKID_BOOL: bOk = pushBoolOperand( rStrm.readuInt8() != BIFF_TOK_BOOL_FALSE ); break;
+ case BIFF_TOKID_INT: bOk = pushValueOperand< double >( rStrm.readuInt16() ); break;
+ case BIFF_TOKID_NUM: bOk = pushValueOperand( rStrm.readDouble() ); break;
+ default: bOk = false;
+ }
+ }
+ else
+ {
+ // classified tokens
+ switch( nBaseId )
+ {
+ case BIFF_TOKID_ARRAY: bOk = importArrayToken( rStrm ); break;
+ case BIFF_TOKID_FUNC: bOk = (this->*mpImportFuncToken)( rStrm ); break;
+ case BIFF_TOKID_FUNCVAR: bOk = (this->*mpImportFuncVarToken)( rStrm ); break;
+ case BIFF_TOKID_NAME: bOk = importNameToken( rStrm ); break;
+ case BIFF_TOKID_REF: bOk = (this->*mpImportRefToken)( rStrm, false, false ); break;
+ case BIFF_TOKID_AREA: bOk = (this->*mpImportAreaToken)( rStrm, false, false ); break;
+ case BIFF_TOKID_MEMAREA: bOk = importMemAreaToken( rStrm, true ); break;
+ case BIFF_TOKID_MEMERR: bOk = importMemAreaToken( rStrm, false ); break;
+ case BIFF_TOKID_MEMNOMEM: bOk = importMemAreaToken( rStrm, false ); break;
+ case BIFF_TOKID_MEMFUNC: bOk = importMemFuncToken( rStrm ); break;
+ case BIFF_TOKID_REFERR: bOk = (this->*mpImportRefToken)( rStrm, true, false ); break;
+ case BIFF_TOKID_AREAERR: bOk = (this->*mpImportAreaToken)( rStrm, true, false ); break;
+ case BIFF_TOKID_REFN: bOk = (this->*mpImportRefToken)( rStrm, false, true ); break;
+ case BIFF_TOKID_AREAN: bOk = (this->*mpImportAreaToken)( rStrm, false, true ); break;
+ case BIFF_TOKID_MEMAREAN: bOk = importMemFuncToken( rStrm ); break;
+ case BIFF_TOKID_MEMNOMEMN: bOk = importMemFuncToken( rStrm ); break;
+ case BIFF_TOKID_FUNCCE: bOk = (this->*mpImportFuncCEToken)( rStrm ); break;
+ case BIFF_TOKID_NAMEX: bOk = (this->*mpImportNameXToken)( rStrm ); break;
+ case BIFF_TOKID_REF3D: bOk = (this->*mpImportRef3dToken)( rStrm, false, bRelativeAsOffset ); break;
+ case BIFF_TOKID_AREA3D: bOk = (this->*mpImportArea3dToken)( rStrm, false, bRelativeAsOffset ); break;
+ case BIFF_TOKID_REFERR3D: bOk = (this->*mpImportRef3dToken)( rStrm, true, bRelativeAsOffset ); break;
+ case BIFF_TOKID_AREAERR3D: bOk = (this->*mpImportArea3dToken)( rStrm, true, bRelativeAsOffset ); break;
+ default: bOk = false;
+ }
+ }
+ }
+
+ // build and finalize the token sequence
+ if( bOk && (rStrm.getRecPos() == nEndPos) )
+ finalizeImport();
+
+ // seek behind additional token data of tArray, tMemArea, tNlr tokens
+ rStrm.seek( mnAddDataPos );
+}
+
+// import token contents and create API formula token -------------------------
+
+bool BiffFormulaParserImpl::importTokenNotAvailable( BiffInputStream& )
+{
+ // dummy function for pointer-to-member-function
+ return false;
+}
+
+bool BiffFormulaParserImpl::importRefTokenNotAvailable( BiffInputStream&, bool, bool )
+{
+ // dummy function for pointer-to-member-function
+ return false;
+}
+
+bool BiffFormulaParserImpl::importStrToken2( BiffInputStream& rStrm )
+{
+ return pushValueOperand( rStrm.readByteString( false, getTextEncoding() ) );
+}
+
+bool BiffFormulaParserImpl::importStrToken8( BiffInputStream& rStrm )
+{
+ // read flags field for empty strings also
+ return pushValueOperand( rStrm.readUniString( rStrm.readuInt8() ) );
+}
+
+bool BiffFormulaParserImpl::importAttrToken( BiffInputStream& rStrm )
+{
+ bool bOk = true;
+ sal_uInt8 nType;
+ rStrm >> nType;
+ switch( nType )
+ {
+ case BIFF_TOK_ATTR_VOLATILE:
+ case BIFF_TOK_ATTR_IF:
+ case BIFF_TOK_ATTR_SKIP:
+ case BIFF_TOK_ATTR_ASSIGN:
+ rStrm.skip( mnAttrDataSize );
+ break;
+ case BIFF_TOK_ATTR_CHOOSE:
+ rStrm.skip( mnAttrDataSize * (1 + ((getBiff() == BIFF2) ? rStrm.readuInt8() : rStrm.readuInt16())) );
+ break;
+ case BIFF_TOK_ATTR_SUM:
+ rStrm.skip( mnAttrDataSize );
+ bOk = pushBiffFunction( BIFF_FUNC_SUM, 1 );
+ break;
+ case BIFF_TOK_ATTR_SPACE:
+ case BIFF_TOK_ATTR_SPACE_VOLATILE:
+ bOk = (this->*mpImportSpaceToken)( rStrm );
+ break;
+ default:
+ bOk = false;
+ }
+ return bOk;
+}
+
+bool BiffFormulaParserImpl::importSpaceToken3( BiffInputStream& rStrm )
+{
+ rStrm.skip( 2 );
+ return true;
+}
+
+bool BiffFormulaParserImpl::importSpaceToken4( BiffInputStream& rStrm )
+{
+ sal_uInt8 nType, nCount;
+ rStrm >> nType >> nCount;
+ switch( nType )
+ {
+ case BIFF_TOK_ATTR_SPACE_SP:
+ case BIFF_TOK_ATTR_SPACE_BR:
+ incLeadingSpaces( nCount );
+ break;
+ case BIFF_TOK_ATTR_SPACE_SP_OPEN:
+ case BIFF_TOK_ATTR_SPACE_BR_OPEN:
+ incOpeningSpaces( nCount );
+ break;
+ case BIFF_TOK_ATTR_SPACE_SP_CLOSE:
+ case BIFF_TOK_ATTR_SPACE_BR_CLOSE:
+ incClosingSpaces( nCount );
+ break;
+ }
+ return true;
+}
+
+bool BiffFormulaParserImpl::importSheetToken2( BiffInputStream& rStrm )
+{
+ rStrm.skip( 4 );
+ mnCurrRefId = readRefId( rStrm );
+ return true;
+}
+
+bool BiffFormulaParserImpl::importSheetToken3( BiffInputStream& rStrm )
+{
+ rStrm.skip( 6 );
+ mnCurrRefId = readRefId( rStrm );
+ return true;
+}
+
+bool BiffFormulaParserImpl::importEndSheetToken2( BiffInputStream& rStrm )
+{
+ rStrm.skip( 3 );
+ mnCurrRefId = 0;
+ return true;
+}
+
+bool BiffFormulaParserImpl::importEndSheetToken3( BiffInputStream& rStrm )
+{
+ rStrm.skip( 4 );
+ mnCurrRefId = 0;
+ return true;
+}
+
+bool BiffFormulaParserImpl::importNlrToken( BiffInputStream& rStrm )
+{
+ bool bOk = true;
+ sal_uInt8 nNlrType;
+ rStrm >> nNlrType;
+ switch( nNlrType )
+ {
+ case BIFF_TOK_NLR_ERR: bOk = importNlrErrToken( rStrm, 4 ); break;
+ case BIFF_TOK_NLR_ROWR: bOk = importNlrAddrToken( rStrm, true ); break;
+ case BIFF_TOK_NLR_COLR: bOk = importNlrAddrToken( rStrm, false ); break;
+ case BIFF_TOK_NLR_ROWV: bOk = importNlrAddrToken( rStrm, true ); break;
+ case BIFF_TOK_NLR_COLV: bOk = importNlrAddrToken( rStrm, false ); break;
+ case BIFF_TOK_NLR_RANGE: bOk = importNlrRangeToken( rStrm ); break;
+ case BIFF_TOK_NLR_SRANGE: bOk = importNlrSRangeToken( rStrm ); break;
+ case BIFF_TOK_NLR_SROWR: bOk = importNlrSAddrToken( rStrm, true ); break;
+ case BIFF_TOK_NLR_SCOLR: bOk = importNlrSAddrToken( rStrm, false ); break;
+ case BIFF_TOK_NLR_SROWV: bOk = importNlrSAddrToken( rStrm, true ); break;
+ case BIFF_TOK_NLR_SCOLV: bOk = importNlrSAddrToken( rStrm, false ); break;
+ case BIFF_TOK_NLR_RANGEERR: bOk = importNlrErrToken( rStrm, 13 ); break;
+ case BIFF_TOK_NLR_SXNAME: bOk = importNlrErrToken( rStrm, 4 ); break;
+ default: bOk = false;
+ }
+ return bOk;
+}
+
+bool BiffFormulaParserImpl::importArrayToken( BiffInputStream& rStrm )
+{
+ rStrm.skip( mnArraySize );
+
+ // start token array with opening brace and leading spaces
+ pushOperand( mrFuncProv.OPCODE_ARRAY_OPEN );
+ size_t nOpSize = popOperandSize();
+ size_t nOldArraySize = getFormulaSize();
+ bool bBiff8 = getBiff() == BIFF8;
+
+ // read array size
+ swapStreamPosition( rStrm );
+ sal_uInt16 nCols = rStrm.readuInt8();
+ sal_uInt16 nRows = rStrm.readuInt16();
+ if( bBiff8 ) { ++nCols; ++nRows; } else if( nCols == 0 ) nCols = 256;
+ OSL_ENSURE( (nCols > 0) && (nRows > 0), "BiffFormulaParserImpl::importArrayToken - empty array" );
+
+ // read array values and build token array
+ for( sal_uInt16 nRow = 0; rStrm.isValid() && (nRow < nRows); ++nRow )
+ {
+ if( nRow > 0 )
+ appendRawToken( mrFuncProv.OPCODE_ARRAY_ROWSEP );
+ for( sal_uInt16 nCol = 0; rStrm.isValid() && (nCol < nCols); ++nCol )
+ {
+ if( nCol > 0 )
+ appendRawToken( mrFuncProv.OPCODE_ARRAY_COLSEP );
+ switch( rStrm.readuInt8() )
+ {
+ case BIFF_DATATYPE_EMPTY:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= OUString();
+ rStrm.skip( 8 );
+ break;
+ case BIFF_DATATYPE_DOUBLE:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= rStrm.readDouble();
+ break;
+ case BIFF_DATATYPE_STRING:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= bBiff8 ?
+ rStrm.readUniString() :
+ rStrm.readByteString( false, getTextEncoding() );
+ break;
+ case BIFF_DATATYPE_BOOL:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
+ rStrm.skip( 7 );
+ break;
+ case BIFF_DATATYPE_ERROR:
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
+ rStrm.skip( 7 );
+ break;
+ default:
+ OSL_ENSURE( false, "BiffFormulaParserImpl::importArrayToken - unknown data type" );
+ appendRawToken( mrFuncProv.OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
+ }
+ }
+ }
+ swapStreamPosition( rStrm );
+
+ // close token array and set resulting operand size
+ appendRawToken( mrFuncProv.OPCODE_ARRAY_CLOSE );
+ pushOperandSize( nOpSize + getFormulaSize() - nOldArraySize );
+ return true;
+}
+
+bool BiffFormulaParserImpl::importRefToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ BinSingleRef2d aRef;
+ aRef.readBiff2Data( rStrm, bRelativeAsOffset );
+ return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::importRefToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ BinSingleRef2d aRef;
+ aRef.readBiff8Data( rStrm, bRelativeAsOffset );
+ return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::importAreaToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ BinComplexRef2d aRef;
+ aRef.readBiff2Data( rStrm, bRelativeAsOffset );
+ return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::importAreaToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ BinComplexRef2d aRef;
+ aRef.readBiff8Data( rStrm, bRelativeAsOffset );
+ return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::importRef3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ LinkSheetRange aSheetRange = readSheetRange5( rStrm );
+ BinSingleRef2d aRef;
+ aRef.readBiff2Data( rStrm, bRelativeAsOffset );
+ return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::importRef3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ LinkSheetRange aSheetRange = readSheetRange8( rStrm );
+ BinSingleRef2d aRef;
+ aRef.readBiff8Data( rStrm, bRelativeAsOffset );
+ return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::importArea3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ LinkSheetRange aSheetRange = readSheetRange5( rStrm );
+ BinComplexRef2d aRef;
+ aRef.readBiff2Data( rStrm, bRelativeAsOffset );
+ return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::importArea3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+ LinkSheetRange aSheetRange = readSheetRange8( rStrm );
+ BinComplexRef2d aRef;
+ aRef.readBiff8Data( rStrm, bRelativeAsOffset );
+ return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::importMemAreaToken( BiffInputStream& rStrm, bool bAddData )
+{
+ rStrm.skip( mnMemAreaSize );
+ if( bAddData )
+ skipMemAreaAddData( rStrm );
+ return true;
+}
+
+bool BiffFormulaParserImpl::importMemFuncToken( BiffInputStream& rStrm )
+{
+ rStrm.skip( mnMemFuncSize );
+ return true;
+}
+
+bool BiffFormulaParserImpl::importNameToken( BiffInputStream& rStrm )
+{
+ sal_uInt16 nNameId = readNameId( rStrm );
+ return (mnCurrRefId > 0) ? pushBiffExtName( mnCurrRefId, nNameId ) : pushBiffName( nNameId );
+}
+
+bool BiffFormulaParserImpl::importNameXToken( BiffInputStream& rStrm )
+{
+ sal_Int32 nRefId = readRefId( rStrm );
+ sal_uInt16 nNameId = readNameId( rStrm );
+ return pushBiffExtName( nRefId, nNameId );
+}
+
+bool BiffFormulaParserImpl::importFuncToken2( BiffInputStream& rStrm )
+{
+ sal_uInt8 nFuncId;
+ rStrm >> nFuncId;
+ return pushBiffFunction( nFuncId );
+}
+
+bool BiffFormulaParserImpl::importFuncToken4( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFuncId;
+ rStrm >> nFuncId;
+ return pushBiffFunction( nFuncId );
+}
+
+bool BiffFormulaParserImpl::importFuncVarToken2( BiffInputStream& rStrm )
+{
+ sal_uInt8 nParamCount, nFuncId;
+ rStrm >> nParamCount >> nFuncId;
+ return pushBiffFunction( nFuncId, nParamCount );
+}
+
+bool BiffFormulaParserImpl::importFuncVarToken4( BiffInputStream& rStrm )
+{
+ sal_uInt8 nParamCount;
+ sal_uInt16 nFuncId;
+ rStrm >> nParamCount >> nFuncId;
+ return pushBiffFunction( nFuncId, nParamCount & BIFF_TOK_FUNCVAR_COUNTMASK );
+}
+
+bool BiffFormulaParserImpl::importFuncCEToken( BiffInputStream& rStrm )
+{
+ sal_uInt8 nParamCount, nFuncId;
+ rStrm >> nParamCount >> nFuncId;
+ sal_uInt16 nCmdId = nFuncId;
+ setFlag( nCmdId, BIFF_TOK_FUNCVAR_CMD );
+ return pushBiffFunction( nCmdId, nParamCount );
+}
+
+bool BiffFormulaParserImpl::importExpToken5( BiffInputStream& rStrm )
+{
+ BinAddress aBaseAddr;
+ aBaseAddr.read( rStrm );
+ setSharedFormula( aBaseAddr );
+ // formula has been set, exit parser by returning false
+ return false;
+}
+
+bool BiffFormulaParserImpl::importNlrAddrToken( BiffInputStream& rStrm, bool bRow )
+{
+ BiffNlr aNlr;
+ aNlr.readBiff8Data( rStrm );
+ return pushBiffNlrAddr( aNlr, bRow );
+}
+
+bool BiffFormulaParserImpl::importNlrRangeToken( BiffInputStream& rStrm )
+{
+ BiffNlr aNlr;
+ aNlr.readBiff8Data( rStrm );
+ rStrm.skip( 1 );
+ BinRange aRange;
+ rStrm >> aRange;
+ return pushBiffNlrRange( aNlr, aRange );
+}
+
+bool BiffFormulaParserImpl::importNlrSAddrToken( BiffInputStream& rStrm, bool bRow )
+{
+ rStrm.skip( 4 );
+ BiffNlr aNlr;
+ return readNlrSAddrAddData( aNlr, rStrm, bRow ) ? pushBiffNlrSAddr( aNlr, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
+}
+
+bool BiffFormulaParserImpl::importNlrSRangeToken( BiffInputStream& rStrm )
+{
+ rStrm.skip( 5 );
+ BinRange aRange;
+ rStrm >> aRange;
+ BiffNlr aNlr;
+ bool bRow;
+ return readNlrSRangeAddData( aNlr, bRow, rStrm ) ? pushBiffNlrSRange( aNlr, aRange, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
+}
+
+bool BiffFormulaParserImpl::importNlrErrToken( BiffInputStream& rStrm, sal_uInt16 nIgnore )
+{
+ rStrm.skip( nIgnore );
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+sal_Int32 BiffFormulaParserImpl::readRefId( BiffInputStream& rStrm )
+{
+ sal_Int16 nRefId;
+ rStrm >> nRefId;
+ rStrm.skip( mnRefIdSize );
+ return nRefId;
+}
+
+sal_uInt16 BiffFormulaParserImpl::readNameId( BiffInputStream& rStrm )
+{
+ sal_uInt16 nNameId;
+ rStrm >> nNameId;
+ rStrm.skip( mnNameSize );
+ return nNameId;
+}
+
+LinkSheetRange BiffFormulaParserImpl::readSheetRange5( BiffInputStream& rStrm )
+{
+ sal_Int32 nRefId = readRefId( rStrm );
+ sal_Int16 nTab1, nTab2;
+ rStrm >> nTab1 >> nTab2;
+ return getExternalLinks().getSheetRange( nRefId, nTab1, nTab2 );
+}
+
+LinkSheetRange BiffFormulaParserImpl::readSheetRange8( BiffInputStream& rStrm )
+{
+ return getExternalLinks().getSheetRange( readRefId( rStrm ) );
+}
+
+void BiffFormulaParserImpl::swapStreamPosition( BiffInputStream& rStrm )
+{
+ sal_uInt32 nRecPos = rStrm.getRecPos();
+ rStrm.seek( mnAddDataPos );
+ mnAddDataPos = nRecPos;
+}
+
+void BiffFormulaParserImpl::skipMemAreaAddData( BiffInputStream& rStrm )
+{
+ swapStreamPosition( rStrm );
+ sal_uInt32 nCount = rStrm.readuInt16();
+ rStrm.skip( ((getBiff() == BIFF8) ? 8 : 6) * nCount );
+ swapStreamPosition( rStrm );
+}
+
+bool BiffFormulaParserImpl::readNlrSAddrAddData( BiffNlr& orNlr, BiffInputStream& rStrm, bool bRow )
+{
+ bool bIsRow;
+ return readNlrSRangeAddData( orNlr, bIsRow, rStrm ) && (bIsRow == bRow);
+}
+
+bool BiffFormulaParserImpl::readNlrSRangeAddData( BiffNlr& orNlr, bool& orbIsRow, BiffInputStream& rStrm )
+{
+ swapStreamPosition( rStrm );
+ // read number of cell addresses and relative flag
+ sal_uInt32 nCount;
+ rStrm >> nCount;
+ bool bRel = getFlag( nCount, BIFF_TOK_NLR_ADDREL );
+ nCount &= BIFF_TOK_NLR_ADDMASK;
+ sal_uInt32 nEndPos = rStrm.getRecPos() + 4 * nCount;
+ // read list of cell addresses
+ bool bValid = false;
+ if( nCount >= 2 )
+ {
+ // detect column/row orientation
+ BinAddress aAddr1, aAddr2;
+ rStrm >> aAddr1 >> aAddr2;
+ orbIsRow = aAddr1.mnRow == aAddr2.mnRow;
+ bValid = lclIsValidNlrStack( aAddr1, aAddr2, orbIsRow );
+ // read and verify additional cell positions
+ for( sal_uInt32 nIndex = 2; bValid && (nIndex < nCount); ++nIndex )
+ {
+ aAddr1 = aAddr2;
+ rStrm >> aAddr2;
+ bValid = rStrm.isValid() && lclIsValidNlrStack( aAddr1, aAddr2, orbIsRow );
+ }
+ // check that last imported position (aAddr2) is not at the end of the sheet
+ bValid = bValid && (orbIsRow ? (aAddr2.mnCol < mnMaxApiCol) : (aAddr2.mnRow < mnMaxApiRow));
+ // fill the NLR struct with the last imported position
+ if( bValid )
+ {
+ orNlr.mnCol = aAddr2.mnCol;
+ orNlr.mnRow = aAddr2.mnRow;
+ orNlr.mbRel = bRel;
+ }
+ }
+ // seek to end of additional data for this token
+ rStrm.seek( nEndPos );
+ swapStreamPosition( rStrm );
+
+ return bValid;
+}
+
+// convert BIFF token and push API operand or operator ------------------------
+
+bool BiffFormulaParserImpl::pushBiffReference( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
+{
+ return (mnCurrRefId > 0) ?
+ pushReferenceOperand( getExternalLinks().getSheetRange( mnCurrRefId, 0, 0 ), rRef, bDeleted, bRelativeAsOffset ) :
+ pushReferenceOperand( rRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::pushBiffReference( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
+{
+ return (mnCurrRefId > 0) ?
+ pushReferenceOperand( getExternalLinks().getSheetRange( mnCurrRefId, 0, 0 ), rRef, bDeleted, bRelativeAsOffset ) :
+ pushReferenceOperand( rRef, bDeleted, bRelativeAsOffset );
+}
+
+bool BiffFormulaParserImpl::pushBiffNlrAddr( const BiffNlr& rNlr, bool bRow )
+{
+ BinSingleRef2d aRef;
+ aRef.mnCol = rNlr.mnCol;
+ aRef.mnRow = rNlr.mnRow;
+ aRef.mbColRel = !bRow;
+ aRef.mbRowRel = bRow;
+ return pushNlrOperand( aRef );
+}
+
+bool BiffFormulaParserImpl::pushBiffNlrRange( const BiffNlr& rNlr, const BinRange& rRange )
+{
+ bool bRow = rNlr.mnRow == rRange.maFirst.mnRow;
+ return lclIsValidNlrRange( rNlr, rRange, bRow ) ?
+ pushBiffNlrAddr( rNlr, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
+}
+
+bool BiffFormulaParserImpl::pushBiffNlrSAddr( const BiffNlr& rNlr, bool bRow )
+{
+ BinRange aRange;
+ aRange.maFirst.mnCol = rNlr.mnCol + (bRow ? 1 : 0);
+ aRange.maFirst.mnRow = rNlr.mnRow + (bRow ? 0 : 1);
+ aRange.maLast.mnCol = bRow ? mnMaxApiCol : rNlr.mnCol;
+ aRange.maLast.mnRow = bRow ? rNlr.mnRow : mnMaxApiRow;
+ return pushBiffNlrSRange( rNlr, aRange, bRow );
+}
+
+bool BiffFormulaParserImpl::pushBiffNlrSRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow )
+{
+ if( lclIsValidNlrRange( rNlr, rRange, bRow ) )
+ {
+ BinComplexRef2d aRef;
+ aRef.maRef1.mnCol = rRange.maFirst.mnCol;
+ aRef.maRef1.mnRow = rRange.maFirst.mnRow;
+ aRef.maRef2.mnCol = rRange.maLast.mnCol;
+ aRef.maRef2.mnRow = rRange.maLast.mnRow;
+ aRef.maRef1.mbColRel = aRef.maRef2.mbColRel = !bRow && rNlr.mbRel;
+ aRef.maRef1.mbRowRel = aRef.maRef2.mbRowRel = bRow && rNlr.mbRel;
+ return pushReferenceOperand( aRef, false, false );
+ }
+ return pushBiffErrorOperand( BIFF_ERR_REF );
+}
+
+bool BiffFormulaParserImpl::pushBiffName( sal_uInt16 nNameId )
+{
+ // one-based in BIFF formulas
+ return pushDefinedNameOperand( getDefinedNames().getByIndex( static_cast< sal_Int32 >( nNameId ) - 1 ) );
+}
+
+bool BiffFormulaParserImpl::pushBiffExtName( sal_Int32 nRefId, sal_uInt16 nNameId )
+{
+ if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
+ {
+ if( pExtLink->getLinkType() == LINKTYPE_SELF )
+ return pushBiffName( nNameId );
+ // external name indexes are one-based in BIFF
+ ExternalNameRef xExtName = pExtLink->getNameByIndex( static_cast< sal_Int32 >( nNameId ) - 1 );
+ return pushExternalNameOperand( xExtName, pExtLink->getLinkType() );
+ }
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool BiffFormulaParserImpl::pushBiffFunction( sal_uInt16 nFuncId )
+{
+ if( const FunctionInfo* pFuncInfo = mrFuncProv.getFuncInfoFromBiffFuncId( nFuncId ) )
+ if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
+ return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
+ return pushFunctionOperator( mrFuncProv.OPCODE_NONAME, 0 );
+}
+
+bool BiffFormulaParserImpl::pushBiffFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount )
+{
+ if( getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD ) )
+ nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
+ if( const FunctionInfo* pFuncInfo = mrFuncProv.getFuncInfoFromBiffFuncId( nFuncId ) )
+ return pushFunctionOperator( *pFuncInfo, nParamCount );
+ return pushFunctionOperator( mrFuncProv.OPCODE_NONAME, nParamCount );
+}
+
+// ============================================================================
+
+FormulaParser::FormulaParser( const WorkbookHelper& rHelper ) :
+ FormulaProcessorBase( rHelper )
+{
+ switch( getFilterType() )
+ {
+ case FILTER_OOX: mxImpl.reset( new OoxFormulaParserImpl( rHelper, maFuncProv ) ); break;
+ case FILTER_BIFF: mxImpl.reset( new BiffFormulaParserImpl( rHelper, maFuncProv ) ); break;
+ case FILTER_UNKNOWN: break;
+ }
+}
+
+FormulaParser::~FormulaParser()
+{
+}
+
+void FormulaParser::importFormula( FormulaContext& rContext, const OUString& rFormulaString ) const
+{
+ mxImpl->importOoxFormula( rContext, rFormulaString );
+}
+
+void FormulaParser::importFormula( FormulaContext& rContext, RecordInputStream& rStrm ) const
+{
+ mxImpl->importOobFormula( rContext, rStrm );
+}
+
+void FormulaParser::importFormula( FormulaContext& rContext, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) const
+{
+ mxImpl->importBiffFormula( rContext, rStrm, pnFmlaSize );
+}
+
+void FormulaParser::convertErrorToFormula( FormulaContext& rContext, sal_uInt8 nErrorCode ) const
+{
+ ApiTokenSequence aTokens( 3 );
+ // HACK: enclose all error codes into an 1x1 matrix
+ aTokens[ 0 ].OpCode = maFuncProv.OPCODE_ARRAY_OPEN;
+ aTokens[ 1 ].OpCode = maFuncProv.OPCODE_PUSH;
+ aTokens[ 1 ].Data <<= BiffHelper::calcDoubleFromError( nErrorCode );
+ aTokens[ 2 ].OpCode = maFuncProv.OPCODE_ARRAY_CLOSE;
+ mxImpl->setFormula( rContext, aTokens );
+}
+
+void FormulaParser::convertNameToFormula( FormulaContext& rContext, sal_Int32 nTokenIndex ) const
+{
+ if( nTokenIndex >= 0 )
+ {
+ ApiTokenSequence aTokens( 1 );
+ aTokens[ 0 ].OpCode = maFuncProv.OPCODE_NAME;
+ aTokens[ 0 ].Data <<= nTokenIndex;
+ mxImpl->setFormula( rContext, aTokens );
+ }
+ else
+ convertErrorToFormula( rContext, BIFF_ERR_REF );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/headerfooterparser.cxx b/oox/source/xls/headerfooterparser.cxx
new file mode 100644
index 000000000000..663a17c5c89f
--- /dev/null
+++ b/oox/source/xls/headerfooterparser.cxx
@@ -0,0 +1,643 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: headerfooterparser.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/headerfooterparser.hxx"
+#include <vector>
+#include <set>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/strbuf.hxx>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/XHeaderFooterContent.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/text/FilenameDisplayFormat.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/themebuffer.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OUStringToOString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::sheet::XHeaderFooterContent;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::text::XTextCursor;
+using ::com::sun::star::text::XTextContent;
+using ::com::sun::star::text::XTextRange;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+enum HFPortionId
+{
+ HF_LEFT,
+ HF_CENTER,
+ HF_RIGHT,
+ HF_COUNT
+};
+
+// ----------------------------------------------------------------------------
+
+struct HFPortionInfo
+{
+ Reference< XText > mxText; /// XText interface of this portion.
+ Reference< XTextCursor > mxStart; /// Start position of current text range for formatting.
+ Reference< XTextCursor > mxEnd; /// End position of current text range for formatting.
+ double mfTotalHeight; /// Sum of heights of previous lines in points.
+ double mfCurrHeight; /// Height of the current text line in points.
+
+ bool initialize( const Reference< XText >& rxText );
+};
+
+bool HFPortionInfo::initialize( const Reference< XText >& rxText )
+{
+ mfTotalHeight = mfCurrHeight = 0.0;
+ mxText = rxText;
+ if( mxText.is() )
+ {
+ mxStart = mxText->createTextCursor();
+ mxEnd = mxText->createTextCursor();
+ }
+ bool bRet = mxText.is() && mxStart.is() && mxEnd.is();
+ OSL_ENSURE( bRet, "HFPortionInfo::initialize - missing interfaces" );
+ return bRet;
+}
+
+// ----------------------------------------------------------------------------
+
+class HeaderFooterParserImpl : public WorkbookHelper
+{
+public:
+ explicit HeaderFooterParserImpl( const WorkbookHelper& rHelper );
+
+ /** Parses the passed string and creates the header/footer contents. */
+ void parse(
+ const Reference< XHeaderFooterContent >& rxContext,
+ const OUString& rData );
+
+ /** Returns the total height of the converted header or footer in points. */
+ double getTotalHeight() const;
+
+private:
+ /** Returns the current edit engine text object. */
+ inline HFPortionInfo& getPortion() { return maPortions[ meCurrPortion ]; }
+ /** Returns the start cursor of the current text range. */
+ inline const Reference< XTextCursor >& getStartPos() { return getPortion().mxStart; }
+ /** Returns the end cursor of the current text range. */
+ inline const Reference< XTextCursor >& getEndPos() { return getPortion().mxEnd; }
+
+ /** Returns the current line height of the specified portion. */
+ double getCurrHeight( HFPortionId ePortion ) const;
+ /** Returns the current line height. */
+ double getCurrHeight() const;
+
+ /** Updates the current line height of the specified portion, using the current font size. */
+ void updateCurrHeight( HFPortionId ePortion );
+ /** Updates the current line height, using the current font size. */
+ void updateCurrHeight();
+
+ /** Sets the font attributes at the current selection. */
+ void setAttributes();
+ /** Appends and clears internal string buffer. */
+ void appendText();
+ /** Appends a line break and adjusts internal text height data. */
+ void appendLineBreak();
+
+ /** Creates a text field from the passed service name. */
+ Reference< XTextContent > createField( const OUString& rServiceName ) const;
+ /** Appends the passed text field. */
+ void appendField( const Reference< XTextContent >& rxContent );
+
+ /** Sets the passed font name if it is valid. */
+ void convertFontName( const OUString& rStyle );
+ /** Converts a font style given as string. */
+ void convertFontStyle( const OUString& rStyle );
+ /** Converts a font color given as string. */
+ void convertFontColor( const OUString& rColor );
+
+ /** Finalizes current portion: sets font attributes and updates text height data. */
+ void finalizePortion();
+ /** Changes current header/footer portion. */
+ void setNewPortion( HFPortionId ePortion );
+
+private:
+ typedef ::std::vector< HFPortionInfo > HFPortionInfoVec;
+ typedef ::std::set< OString > OStringSet;
+
+ OUString maPageNumberService;
+ OUString maPageCountService;
+ OUString maSheetNameService;
+ OUString maFileNameService;
+ OUString maDateTimeService;
+ OUString maIsDateProp;
+ OUString maFileFormatProp;
+ OStringSet maBoldNames; /// All names for bold font style in lowercase UTF-8.
+ OStringSet maItalicNames; /// All names for italic font style in lowercase UTF-8.
+ HFPortionInfoVec maPortions;
+ HFPortionId meCurrPortion; /// Identifier of current H/F portion.
+ OUStringBuffer maBuffer; /// Text data to append to current text range.
+ OoxFontData maFontData; /// Font attributes of current text range.
+};
+
+
+HeaderFooterParserImpl::HeaderFooterParserImpl( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maPageNumberService( CREATE_OUSTRING( "com.sun.star.text.TextField.PageNumber" ) ),
+ maPageCountService( CREATE_OUSTRING( "com.sun.star.text.TextField.PageCount" ) ),
+ maSheetNameService( CREATE_OUSTRING( "com.sun.star.text.TextField.SheetName" ) ),
+ maFileNameService( CREATE_OUSTRING( "com.sun.star.text.TextField.FileName" ) ),
+ maDateTimeService( CREATE_OUSTRING( "com.sun.star.text.TextField.DateTime" ) ),
+ maIsDateProp( CREATE_OUSTRING( "IsDate" ) ),
+ maFileFormatProp( CREATE_OUSTRING( "FileFormat" ) ),
+ maPortions( static_cast< size_t >( HF_COUNT ) ),
+ meCurrPortion( HF_CENTER )
+{
+ // different names for bold font style (lowercase)
+ maBoldNames.insert( CREATE_OSTRING( "bold" ) );
+ maBoldNames.insert( CREATE_OSTRING( "fett" ) );
+ maBoldNames.insert( CREATE_OSTRING( "demibold" ) );
+ maBoldNames.insert( CREATE_OSTRING( "halbfett" ) );
+ maBoldNames.insert( CREATE_OSTRING( "black" ) );
+ maBoldNames.insert( CREATE_OSTRING( "heavy" ) );
+
+ // different names for italic font style (lowercase)
+ maItalicNames.insert( CREATE_OSTRING( "italic" ) );
+ maItalicNames.insert( CREATE_OSTRING( "kursiv" ) );
+ maItalicNames.insert( CREATE_OSTRING( "oblique" ) );
+ maItalicNames.insert( CREATE_OSTRING( "schr\303\204g" ) ); // with uppercase A umlaut
+ maItalicNames.insert( CREATE_OSTRING( "schr\303\244g" ) ); // with lowercase A umlaut
+}
+
+void HeaderFooterParserImpl::parse( const Reference< XHeaderFooterContent >& rxContext, const OUString& rData )
+{
+ if( !rxContext.is() || (rData.getLength() == 0) ||
+ !maPortions[ HF_LEFT ].initialize( rxContext->getLeftText() ) ||
+ !maPortions[ HF_CENTER ].initialize( rxContext->getCenterText() ) ||
+ !maPortions[ HF_RIGHT ].initialize( rxContext->getRightText() ) )
+ return;
+
+ meCurrPortion = HF_CENTER;
+ maBuffer.setLength( 0 );
+ maFontData = getStyles().getDefaultFontData();
+ OUStringBuffer aFontName; // current font name
+ OUStringBuffer aFontStyle; // current font style
+ sal_Int32 nFontHeight = 0; // current font height
+
+ /** State of the parser. */
+ enum
+ {
+ STATE_TEXT, /// Literal text data.
+ STATE_TOKEN, /// Control token following a '&' character.
+ STATE_FONTNAME, /// Font name ('&' is followed by '"', reads until next '"' or ',').
+ STATE_FONTSTYLE, /// Font style name (font part after ',', reads until next '"').
+ STATE_FONTHEIGHT /// Font height ('&' is followed by num. digits, reads until non-digit).
+ }
+ eState = STATE_TEXT;
+
+ const sal_Unicode* pcChar = rData.getStr();
+ const sal_Unicode* pcEnd = pcChar + rData.getLength();
+ for( ; (pcChar != pcEnd) && (*pcChar != 0); ++pcChar )
+ {
+ sal_Unicode cChar = *pcChar;
+ switch( eState )
+ {
+ case STATE_TEXT:
+ {
+ switch( cChar )
+ {
+ case '&': // new token
+ appendText();
+ eState = STATE_TOKEN;
+ break;
+ case '\n': // line break
+ appendText();
+ appendLineBreak();
+ break;
+ default:
+ maBuffer.append( cChar );
+ }
+ }
+ break;
+
+ case STATE_TOKEN:
+ {
+ // default: back to text mode, may be changed in specific cases
+ eState = STATE_TEXT;
+ // ignore case of token codes
+ if( ('a' <= cChar) && (cChar <= 'z') )
+ (cChar -= 'a') += 'A';
+ switch( cChar )
+ {
+ case '&': maBuffer.append( cChar ); break; // the '&' character
+
+ case 'L': setNewPortion( HF_LEFT ); break; // left portion
+ case 'C': setNewPortion( HF_CENTER ); break; // center portion
+ case 'R': setNewPortion( HF_RIGHT ); break; // right portion
+
+ case 'P': // page number
+ appendField( createField( maPageNumberService ) );
+ break;
+ case 'N': // total page count
+ appendField( createField( maPageCountService ) );
+ break;
+ case 'A': // current sheet name
+ appendField( createField( maSheetNameService ) );
+ break;
+
+ case 'F': // file name
+ {
+ Reference< XTextContent > xContent = createField( maFileNameService );
+ PropertySet aPropSet( xContent );
+ aPropSet.setProperty( maFileFormatProp, ::com::sun::star::text::FilenameDisplayFormat::NAME_AND_EXT );
+ appendField( xContent );
+ }
+ break;
+ case 'Z': // file path (without file name), BIFF8 and OOX only
+ if( (getFilterType() == FILTER_OOX) || ((getFilterType() == FILTER_BIFF) && (getBiff() == BIFF8)) )
+ {
+ Reference< XTextContent > xContent = createField( maFileNameService );
+ PropertySet aPropSet( xContent );
+ // FilenameDisplayFormat::PATH not supported by Calc
+ aPropSet.setProperty( maFileFormatProp, ::com::sun::star::text::FilenameDisplayFormat::FULL );
+ appendField( xContent );
+ /* path only is not supported -- if we find a '&Z&F'
+ combination for path/name, skip the '&F' part */
+ if( (pcChar + 2 < pcEnd) && (pcChar[ 1 ] == '&') && ((pcChar[ 2 ] == 'f') || (pcChar[ 2 ] == 'F')) )
+ pcChar += 2;
+ }
+ break;
+ case 'D': // date
+ {
+ Reference< XTextContent > xContent = createField( maDateTimeService );
+ PropertySet aPropSet( xContent );
+ aPropSet.setProperty( maIsDateProp, true );
+ appendField( xContent );
+ }
+ break;
+ case 'T': // time
+ {
+ Reference< XTextContent > xContent = createField( maDateTimeService );
+ PropertySet aPropSet( xContent );
+ aPropSet.setProperty( maIsDateProp, false );
+ appendField( xContent );
+ }
+ break;
+
+ case 'B': // bold
+ setAttributes();
+ maFontData.mbBold = !maFontData.mbBold;
+ break;
+ case 'I': // italic
+ setAttributes();
+ maFontData.mbItalic = !maFontData.mbItalic;
+ break;
+ case 'U': // underline
+ setAttributes();
+ maFontData.mnUnderline = (maFontData.mnUnderline == XML_single) ? XML_none : XML_single;
+ break;
+ case 'E': // double underline
+ setAttributes();
+ maFontData.mnUnderline = (maFontData.mnUnderline == XML_double) ? XML_none : XML_double;
+ break;
+ case 'S': // strikeout
+ setAttributes();
+ maFontData.mbStrikeout = !maFontData.mbStrikeout;
+ break;
+ case 'X': // superscript
+ setAttributes();
+ maFontData.mnEscapement = (maFontData.mnEscapement == XML_superscript) ? XML_baseline : XML_superscript;
+ break;
+ case 'Y': // subsrcipt
+ setAttributes();
+ maFontData.mnEscapement = (maFontData.mnEscapement == XML_subscript) ? XML_baseline : XML_subscript;
+ break;
+ case 'O': // outlined
+ setAttributes();
+ maFontData.mbOutline = !maFontData.mbOutline;
+ break;
+ case 'H': // shadow
+ setAttributes();
+ maFontData.mbShadow = !maFontData.mbShadow;
+ break;
+
+ case 'K': // text color (not in BIFF)
+ if( (getFilterType() == FILTER_OOX) && (pcChar + 6 < pcEnd) )
+ {
+ setAttributes();
+ // eat the following 6 characters
+ convertFontColor( OUString( pcChar + 1, 6 ) );
+ pcChar += 6;
+ }
+ break;
+
+ case '\"': // font name
+ aFontName.setLength( 0 );
+ aFontStyle.setLength( 0 );
+ eState = STATE_FONTNAME;
+ break;
+ default:
+ if( ('0' <= cChar) && (cChar <= '9') ) // font size
+ {
+ nFontHeight = cChar - '0';
+ eState = STATE_FONTHEIGHT;
+ }
+ }
+ }
+ break;
+
+ case STATE_FONTNAME:
+ {
+ switch( cChar )
+ {
+ case '\"':
+ setAttributes();
+ convertFontName( aFontName.makeStringAndClear() );
+ eState = STATE_TEXT;
+ break;
+ case ',':
+ eState = STATE_FONTSTYLE;
+ break;
+ default:
+ aFontName.append( cChar );
+ }
+ }
+ break;
+
+ case STATE_FONTSTYLE:
+ {
+ switch( cChar )
+ {
+ case '\"':
+ setAttributes();
+ convertFontName( aFontName.makeStringAndClear() );
+ convertFontStyle( aFontStyle.makeStringAndClear() );
+ eState = STATE_TEXT;
+ break;
+ default:
+ aFontStyle.append( cChar );
+ }
+ }
+ break;
+
+ case STATE_FONTHEIGHT:
+ {
+ if( ('0' <= cChar) && (cChar <= '9') )
+ {
+ if( nFontHeight >= 0 )
+ {
+ nFontHeight *= 10;
+ nFontHeight += (cChar - '0');
+ if( nFontHeight > 1000 )
+ nFontHeight = -1;
+ }
+ }
+ else
+ {
+ if( nFontHeight > 0 )
+ {
+ setAttributes();
+ maFontData.mfHeight = nFontHeight;
+ }
+ --pcChar;
+ eState = STATE_TEXT;
+ }
+ }
+ break;
+ }
+ }
+
+ // finalize
+ finalizePortion();
+ maPortions[ HF_LEFT ].mfTotalHeight += getCurrHeight( HF_LEFT );
+ maPortions[ HF_CENTER ].mfTotalHeight += getCurrHeight( HF_CENTER );
+ maPortions[ HF_RIGHT ].mfTotalHeight += getCurrHeight( HF_RIGHT );
+}
+
+double HeaderFooterParserImpl::getTotalHeight() const
+{
+ return ::std::max( maPortions[ HF_LEFT ].mfTotalHeight,
+ ::std::max( maPortions[ HF_CENTER ].mfTotalHeight, maPortions[ HF_RIGHT ].mfTotalHeight ) );
+}
+
+// private --------------------------------------------------------------------
+
+double HeaderFooterParserImpl::getCurrHeight( HFPortionId ePortion ) const
+{
+ double fMaxHt = maPortions[ ePortion ].mfCurrHeight;
+ return (fMaxHt == 0.0) ? maFontData.mfHeight : fMaxHt;
+}
+
+double HeaderFooterParserImpl::getCurrHeight() const
+{
+ return getCurrHeight( meCurrPortion );
+}
+
+void HeaderFooterParserImpl::updateCurrHeight( HFPortionId ePortion )
+{
+ double& rfMaxHt = maPortions[ ePortion ].mfCurrHeight;
+ rfMaxHt = ::std::max( rfMaxHt, maFontData.mfHeight );
+}
+
+void HeaderFooterParserImpl::updateCurrHeight()
+{
+ updateCurrHeight( meCurrPortion );
+}
+
+void HeaderFooterParserImpl::setAttributes()
+{
+ Reference< XTextRange > xRange( getStartPos(), UNO_QUERY );
+ getEndPos()->gotoRange( xRange, sal_False );
+ getEndPos()->gotoEnd( sal_True );
+ if( !getEndPos()->isCollapsed() )
+ {
+ Font aFont( *this, maFontData );
+ aFont.finalizeImport();
+ PropertySet aPropSet( getEndPos() );
+ aFont.writeToPropertySet( aPropSet, FONT_PROPTYPE_RICHTEXT );
+ getStartPos()->gotoEnd( sal_False );
+ getEndPos()->gotoEnd( sal_False );
+ }
+}
+
+void HeaderFooterParserImpl::appendText()
+{
+ if( maBuffer.getLength() > 0 )
+ {
+ getEndPos()->gotoEnd( sal_False );
+ getEndPos()->setString( maBuffer.makeStringAndClear() );
+ updateCurrHeight();
+ }
+}
+
+void HeaderFooterParserImpl::appendLineBreak()
+{
+ getEndPos()->gotoEnd( sal_False );
+ getEndPos()->setString( OUString( sal_Unicode( '\n' ) ) );
+ getPortion().mfTotalHeight += getCurrHeight();
+ getPortion().mfCurrHeight = 0;
+}
+
+Reference< XTextContent > HeaderFooterParserImpl::createField( const OUString& rServiceName ) const
+{
+ Reference< XTextContent > xContent;
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( getDocument(), UNO_QUERY_THROW );
+ xContent.set( xFactory->createInstance( rServiceName ), UNO_QUERY_THROW );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false,
+ OStringBuffer( "HeaderFooterParserImpl::createField - error while creating text field \"" ).
+ append( OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( '"' ).getStr() );
+ }
+ return xContent;
+}
+
+void HeaderFooterParserImpl::appendField( const Reference< XTextContent >& rxContent )
+{
+ getEndPos()->gotoEnd( sal_False );
+ try
+ {
+ Reference< XTextRange > xRange( getEndPos(), UNO_QUERY_THROW );
+ getPortion().mxText->insertTextContent( xRange, rxContent, sal_False );
+ updateCurrHeight();
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void HeaderFooterParserImpl::convertFontName( const OUString& rName )
+{
+ if( rName.getLength() > 0 )
+ {
+ // single dash is document default font
+ if( (rName.getLength() == 1) && (rName[ 0 ] == '-') )
+ maFontData.maName = getStyles().getDefaultFontData().maName;
+ else
+ maFontData.maName = rName;
+ }
+}
+
+void HeaderFooterParserImpl::convertFontStyle( const OUString& rStyle )
+{
+ maFontData.mbBold = maFontData.mbItalic = false;
+ sal_Int32 nPos = 0;
+ sal_Int32 nLen = rStyle.getLength();
+ while( (0 <= nPos) && (nPos < nLen) )
+ {
+ OString aToken = OUStringToOString( rStyle.getToken( 0, ' ', nPos ), RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
+ if( aToken.getLength() > 0 )
+ {
+ if( maBoldNames.count( aToken ) > 0 )
+ maFontData.mbBold = true;
+ else if( maItalicNames.count( aToken ) > 0 )
+ maFontData.mbItalic = true;
+ }
+ }
+}
+
+void HeaderFooterParserImpl::convertFontColor( const OUString& rColor )
+{
+ OSL_ENSURE( rColor.getLength() == 6, "HeaderFooterParserImpl::convertFontColor - invalid font color code" );
+ if( (rColor[ 2 ] == '+') || (rColor[ 2 ] == '-') )
+ // theme color: TTSNNN (TT = decimal theme index, S = +/-, NNN = decimal tint/shade in percent)
+ maFontData.maColor.set(
+ XML_theme, rColor.copy( 0, 2 ).toInt32(),
+ static_cast< double >( rColor.copy( 2 ).toInt32() ) / 100.0 );
+ else
+ // RGB color: RRGGBB
+ maFontData.maColor.set( XML_rgb, rColor.toInt32( 16 ) );
+}
+
+void HeaderFooterParserImpl::finalizePortion()
+{
+ appendText();
+ setAttributes();
+}
+
+void HeaderFooterParserImpl::setNewPortion( HFPortionId ePortion )
+{
+ if( ePortion != meCurrPortion )
+ {
+ finalizePortion();
+ meCurrPortion = ePortion;
+ maFontData = getStyles().getDefaultFontData();
+ }
+}
+
+// ============================================================================
+
+HeaderFooterParser::HeaderFooterParser( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mxImpl( new HeaderFooterParserImpl( rHelper ) )
+{
+}
+
+HeaderFooterParser::~HeaderFooterParser()
+{
+}
+
+void HeaderFooterParser::parse( const Reference< XHeaderFooterContent >& rxContext, const OUString& rData )
+{
+ mxImpl->parse( rxContext, rData );
+}
+
+double HeaderFooterParser::getTotalHeight() const
+{
+ return mxImpl->getTotalHeight();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/makefile.mk b/oox/source/xls/makefile.mk
new file mode 100644
index 000000000000..f46737cb307b
--- /dev/null
+++ b/oox/source/xls/makefile.mk
@@ -0,0 +1,106 @@
+#*************************************************************************
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.2 $
+#
+# last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+#
+# The Contents of this file are made available subject to
+# the terms of GNU Lesser General Public License Version 2.1.
+#
+#
+# GNU Lesser General Public License Version 2.1
+# =============================================
+# Copyright 2005 by Sun Microsystems, Inc.
+# 901 San Antonio Road, Palo Alto, CA 94303, USA
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1, as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=oox
+TARGET=xls
+AUTOSEG=true
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE: $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES = \
+ $(SLO)$/addressconverter.obj \
+ $(SLO)$/autofiltercontext.obj \
+ $(SLO)$/biffcodec.obj \
+ $(SLO)$/biffdetector.obj \
+ $(SLO)$/bifffragmenthandler.obj \
+ $(SLO)$/biffhelper.obj \
+ $(SLO)$/biffinputstream.obj \
+ $(SLO)$/biffoutputstream.obj \
+ $(SLO)$/condformatbuffer.obj \
+ $(SLO)$/condformatcontext.obj \
+ $(SLO)$/connectionsfragment.obj \
+ $(SLO)$/defnamesbuffer.obj \
+ $(SLO)$/excelfilter.obj \
+ $(SLO)$/externallinkbuffer.obj \
+ $(SLO)$/externallinkfragment.obj \
+ $(SLO)$/formulabase.obj \
+ $(SLO)$/formulaparser.obj \
+ $(SLO)$/headerfooterparser.obj \
+ $(SLO)$/numberformatsbuffer.obj \
+ $(SLO)$/ooxcontexthandler.obj \
+ $(SLO)$/ooxcontexthelper.obj \
+ $(SLO)$/ooxfragmenthandler.obj \
+ $(SLO)$/pagesettings.obj \
+ $(SLO)$/pivotcachefragment.obj \
+ $(SLO)$/pivottablebuffer.obj \
+ $(SLO)$/pivottablefragment.obj \
+ $(SLO)$/querytablefragment.obj \
+ $(SLO)$/richstring.obj \
+ $(SLO)$/richstringcontext.obj \
+ $(SLO)$/sharedformulabuffer.obj \
+ $(SLO)$/sharedstringsbuffer.obj \
+ $(SLO)$/sharedstringsfragment.obj \
+ $(SLO)$/sheetcellrangemap.obj \
+ $(SLO)$/sheetdatacontext.obj \
+ $(SLO)$/stylesbuffer.obj \
+ $(SLO)$/stylesfragment.obj \
+ $(SLO)$/stylespropertyhelper.obj \
+ $(SLO)$/tablebuffer.obj \
+ $(SLO)$/tablefragment.obj \
+ $(SLO)$/themebuffer.obj \
+ $(SLO)$/unitconverter.obj \
+ $(SLO)$/validationpropertyhelper.obj \
+ $(SLO)$/viewsettings.obj \
+ $(SLO)$/webquerybuffer.obj \
+ $(SLO)$/workbookfragment.obj \
+ $(SLO)$/workbookhelper.obj \
+ $(SLO)$/workbooksettings.obj \
+ $(SLO)$/worksheetbuffer.obj \
+ $(SLO)$/worksheetfragment.obj \
+ $(SLO)$/worksheethelper.obj \
+ $(SLO)$/worksheetsettings.obj
+
+# --- Targets -------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/oox/source/xls/numberformatsbuffer.cxx b/oox/source/xls/numberformatsbuffer.cxx
new file mode 100644
index 000000000000..3433a7885704
--- /dev/null
+++ b/oox/source/xls/numberformatsbuffer.cxx
@@ -0,0 +1,2124 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: numberformatsbuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ * * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/numberformatsbuffer.hxx"
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/i18n/NumberFormatIndex.hpp>
+#include <osl/thread.h>
+#include <rtl/string.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/processfactory.hxx>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OStringToOUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::lang::Locale;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::util::XNumberFormatsSupplier;
+using ::com::sun::star::util::XNumberFormats;
+using ::com::sun::star::util::XNumberFormatTypes;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+/** Stores the number format used in Calc for an Excel built-in number format. */
+struct BuiltinFormat
+{
+ sal_Int32 mnNumFmtId; /// Built-in number format index.
+ const sal_Char* mpcFmtCode; /// Format string, UTF-8, may be 0 (mnPredefId is used then).
+ sal_Int16 mnPredefId; /// Predefined format index, if mpcFmtCode is 0.
+ sal_Int32 mnReuseId; /// Use this format, if mpcFmtCode is 0 and mnPredefId is -1.
+};
+
+/** Defines a literal built-in number format. */
+#define NUMFMT_STRING( INDEX, FORMATCODE ) \
+ { INDEX, FORMATCODE, -1, -1 }
+
+/** Defines a built-in number format that maps to an own predefined format. */
+#define NUMFMT_PREDEF( INDEX, PREDEFINED ) \
+ { INDEX, 0, ::com::sun::star::i18n::NumberFormatIndex::PREDEFINED, -1 }
+
+/** Defines a built-in number format that is the same as the specified in nReuseId. */
+#define NUMFMT_REUSE( INDEX, REUSED_INDEX ) \
+ { INDEX, 0, -1, REUSED_INDEX }
+
+/** Terminates a built-in number format table. */
+#define NUMFMT_ENDTABLE() \
+ { -1, 0, -1, -1 }
+
+/** Defines builtin date and time formats 14...22.
+ @param SYSTEMDATE Complete short system date (for formats 14 and 22).
+ @param DAY Day format (for formats 15 and 16).
+ @param DAYSEP Separator between day and month (for formats 15 and 16).
+ @param MONTH Month format (for formats 15...17).
+ @param MONTHSEP Separator between month and year (for formats 15 and 17).
+ @param YEAR Year format (for formats 15 and 17).
+ @param HOUR12 Hour format for 12-hour AM/PM formats (formats 18 and 19).
+ @param HOUR24 Hour format for 24-hour formats (formats 20...22). */
+#define NUMFMT_ALLDATETIMES( SYSTEMDATE, DAY, DAYSEP, MONTH, MONTHSEP, YEAR, HOUR12, HOUR24 ) \
+ NUMFMT_STRING( 14, SYSTEMDATE ), \
+ NUMFMT_STRING( 15, DAY DAYSEP MONTH MONTHSEP YEAR ), \
+ NUMFMT_STRING( 16, DAY DAYSEP MONTH ), \
+ NUMFMT_STRING( 17, MONTH MONTHSEP YEAR ), \
+ NUMFMT_STRING( 18, HOUR12 ":mm AM/PM" ), \
+ NUMFMT_STRING( 19, HOUR12 ":mm:ss AM/PM" ), \
+ NUMFMT_STRING( 20, HOUR24 ":mm" ), \
+ NUMFMT_STRING( 21, HOUR24 ":mm:ss" ), \
+ NUMFMT_STRING( 22, SYSTEMDATE " " HOUR24 ":mm" )
+
+/** Defines builtin time formats INDEX and INDEX+1 for CJK locales.
+ @param INDEX First number format index.
+ @param HOURFORMAT Hour format.
+ @param HOUR Hour symbol.
+ @param MINUTE Minute symbol.
+ @param SECOND Second symbol. */
+#define NUMFMT_TIME_CJK( INDEX, HOURFORMAT, HOUR, MINUTE, SECOND ) \
+ NUMFMT_STRING( INDEX + 0, HOURFORMAT "\"" HOUR "\"mm\"" MINUTE "\"" ), \
+ NUMFMT_STRING( INDEX + 1, HOURFORMAT "\"" HOUR "\"mm\"" MINUTE "\"ss\"" SECOND "\"" )
+
+/** Defines builtin time formats 32...35 for CJK locales.
+ @param HOUR12 Hour format for 12-hour AM/PM formats (formats 34 and 35).
+ @param HOUR24 Hour format for 24-hour formats (formats 32 and 33).
+ @param HOUR Hour symbol.
+ @param MINUTE Minute symbol.
+ @param SECOND Second symbol. */
+#define NUMFMT_ALLTIMES_CJK( HOUR12, HOUR24, HOUR, MINUTE, SECOND ) \
+ NUMFMT_TIME_CJK( 32, HOUR24, HOUR, MINUTE, SECOND ), \
+ NUMFMT_TIME_CJK( 34, "AM/PM" HOUR12, HOUR, MINUTE, SECOND )
+
+/** Defines builtin currency formats INDEX...INDEX+3 in the following format:
+ "symbol, [minus], number".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number.
+ @param MODIF Leading modifier for each portion (e.g. "t" for Thai formats). */
+#define NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( INDEX, SYMBOL, SPACE, MODIF ) \
+ NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0;" MODIF SYMBOL SPACE "-#,##0" ), \
+ NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0;" "[RED]" MODIF SYMBOL SPACE "-#,##0" ), \
+ NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00;" MODIF SYMBOL SPACE "-#,##0.00" ), \
+ NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00;" "[RED]" MODIF SYMBOL SPACE "-#,##0.00" )
+
+/** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
+ "symbol, [minus], number".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number. */
+#define NUMFMT_ACCOUNTING_SYMBOL_MINUS_NUMBER( INDEX, SYMBOL, SPACE ) \
+ NUMFMT_STRING( INDEX + 0, "_ " "* #,##0_ ;" "_ " "* -#,##0_ ;" "_ " "* \"-\"_ ;" "_ @_ " ), \
+ NUMFMT_STRING( INDEX + 1, "_ " SYMBOL SPACE "* #,##0_ ;" "_ " SYMBOL SPACE "* -#,##0_ ;" "_ " SYMBOL SPACE "* \"-\"_ ;" "_ @_ " ), \
+ NUMFMT_STRING( INDEX + 2, "_ " "* #,##0.00_ ;" "_ " "* -#,##0.00_ ;" "_ " "* \"-\"?\?_ ;" "_ @_ " ), \
+ NUMFMT_STRING( INDEX + 3, "_ " SYMBOL SPACE "* #,##0.00_ ;" "_ " SYMBOL SPACE "* -#,##0.00_ ;" "_ " SYMBOL SPACE "* \"-\"?\?_ ;" "_ @_ " )
+
+/** Defines builtin currency formats 5...8 (with currency symbol), 37...40
+ (blind currency symbol), and 41...44 (accounting), in the following format:
+ "symbol, [minus], number".
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number. */
+#define NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( SYMBOL, SPACE ) \
+ NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( 5, SYMBOL, SPACE, "" ), \
+ NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( 37, "", "", "" ), \
+ NUMFMT_ACCOUNTING_SYMBOL_MINUS_NUMBER( 41, SYMBOL, SPACE )
+
+/** Defines builtin currency formats INDEX...INDEX+3 in the following format:
+ "symbol, number, [minus]".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number.
+ @param MODIF Leading modifier for each portion (e.g. "t" for Thai formats). */
+#define NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( INDEX, SYMBOL, SPACE, MODIF ) \
+ NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0_-;" MODIF SYMBOL SPACE "#,##0-" ), \
+ NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0_-;" "[RED]" MODIF SYMBOL SPACE "#,##0-" ), \
+ NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00_-;" MODIF SYMBOL SPACE "#,##0.00-" ), \
+ NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00_-;" "[RED]" MODIF SYMBOL SPACE "#,##0.00-" )
+
+/** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
+ "symbol, number, [minus]".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number. */
+#define NUMFMT_ACCOUNTING_SYMBOL_NUMBER_MINUS( INDEX, SYMBOL, SPACE ) \
+ NUMFMT_STRING( INDEX + 0, "_-" "* #,##0_-;" "_-" "* #,##0-;" "_-" "* \"-\"_-;" "_-@_-" ), \
+ NUMFMT_STRING( INDEX + 1, "_-" SYMBOL SPACE "* #,##0_-;" "_-" SYMBOL SPACE "* #,##0-;" "_-" SYMBOL SPACE "* \"-\"_-;" "_-@_-" ), \
+ NUMFMT_STRING( INDEX + 2, "_-" "* #,##0.00_-;" "_-" "* #,##0.00-;" "_-" "* \"-\"?\?_-;" "_-@_-" ), \
+ NUMFMT_STRING( INDEX + 3, "_-" SYMBOL SPACE "* #,##0.00_-;" "_-" SYMBOL SPACE "* #,##0.00-;" "_-" SYMBOL SPACE "* \"-\"?\?_-;" "_-@_-" )
+
+/** Defines builtin currency formats 5...8 (with currency symbol), 37...40
+ (blind currency symbol), and 41...44 (accounting), in the following format:
+ "symbol, number, [minus]".
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number. */
+#define NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( SYMBOL, SPACE ) \
+ NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( 5, SYMBOL, SPACE, "" ), \
+ NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( 37, "", "", "" ), \
+ NUMFMT_ACCOUNTING_SYMBOL_NUMBER_MINUS( 41, SYMBOL, SPACE )
+
+/** Defines builtin currency formats INDEX...INDEX+3 in the following format:
+ "number, symbol, [minus]".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between number and currency symbol.
+ @param MODIF Leading modifier for each portion (e.g. "t" for Thai formats). */
+#define NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( INDEX, SYMBOL, SPACE, MODIF ) \
+ NUMFMT_STRING( INDEX + 0, MODIF "#,##0" SPACE SYMBOL "_-;" MODIF "#,##0" SPACE SYMBOL "-" ), \
+ NUMFMT_STRING( INDEX + 1, MODIF "#,##0" SPACE SYMBOL "_-;" "[RED]" MODIF "#,##0" SPACE SYMBOL "-" ), \
+ NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL "_-;" MODIF "#,##0.00" SPACE SYMBOL "-" ), \
+ NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL "_-;" "[RED]" MODIF "#,##0.00" SPACE SYMBOL "-" )
+
+/** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
+ "number, symbol, [minus]".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param BLINDS Blind currency symbol.
+ @param SPACE Space character(s) between number and currency symbol. */
+#define NUMFMT_ACCOUNTING_NUMBER_SYMBOL_MINUS( INDEX, SYMBOL, BLINDS, SPACE ) \
+ NUMFMT_STRING( INDEX + 0, "_-* #,##0" SPACE BLINDS "_-;_-* #,##0" SPACE BLINDS "-;_-* \"-\"" SPACE BLINDS "_-;_-@_-" ), \
+ NUMFMT_STRING( INDEX + 1, "_-* #,##0" SPACE SYMBOL "_-;_-* #,##0" SPACE SYMBOL "-;_-* \"-\"" SPACE SYMBOL "_-;_-@_-" ), \
+ NUMFMT_STRING( INDEX + 2, "_-* #,##0.00" SPACE BLINDS "_-;_-* #,##0.00" SPACE BLINDS "-;_-* \"-\"?\?" SPACE BLINDS "_-;_-@_-" ), \
+ NUMFMT_STRING( INDEX + 3, "_-* #,##0.00" SPACE SYMBOL "_-;_-* #,##0.00" SPACE SYMBOL "-;_-* \"-\"?\?" SPACE SYMBOL "_-;_-@_-" )
+
+/** Defines builtin currency formats 5...8 (with currency symbol), 37...40
+ (blind currency symbol), and 41...44 (accounting), in the following format:
+ "number, symbol, [minus]".
+ @param SYMBOL Currency symbol.
+ @param BLINDS Blind currency symbol.
+ @param SPACE Space character(s) between number and currency symbol. */
+#define NUMFMT_ALLCURRENCIES_NUMBER_SYMBOL_MINUS( SYMBOL, BLINDS, SPACE ) \
+ NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( 5, SYMBOL, SPACE, "" ), \
+ NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( 37, BLINDS, SPACE, "" ), \
+ NUMFMT_ACCOUNTING_NUMBER_SYMBOL_MINUS( 41, SYMBOL, BLINDS, SPACE )
+
+/** Defines builtin currency formats INDEX...INDEX+3 in the following format:
+ "[minus], symbol, number".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number.
+ @param MODIF Leading modifier for each portion (e.g. "t" for Thai formats). */
+#define NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( INDEX, SYMBOL, SPACE, MODIF ) \
+ NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0;" MODIF "-" SYMBOL SPACE "#,##0" ), \
+ NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0;" "[RED]" MODIF "-" SYMBOL SPACE "#,##0" ), \
+ NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00;" MODIF "-" SYMBOL SPACE "#,##0.00" ), \
+ NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00;" "[RED]" MODIF "-" SYMBOL SPACE "#,##0.00" )
+
+/** Defines builtin accounting formats INDEX...INDEX+3 in the following order:
+ "[minus], symbol, number".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number. */
+#define NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( INDEX, SYMBOL, SPACE ) \
+ NUMFMT_STRING( INDEX + 0, "_-" "* #,##0_-;" "-" "* #,##0_-;" "_-" "* \"-\"_-;" "_-@_-" ), \
+ NUMFMT_STRING( INDEX + 1, "_-" SYMBOL SPACE "* #,##0_-;" "-" SYMBOL SPACE "* #,##0_-;" "_-" SYMBOL SPACE "* \"-\"_-;" "_-@_-" ), \
+ NUMFMT_STRING( INDEX + 2, "_-" "* #,##0.00_-;" "-" "* #,##0.00_-;" "_-" "* \"-\"?\?_-;" "_-@_-" ), \
+ NUMFMT_STRING( INDEX + 3, "_-" SYMBOL SPACE "* #,##0.00_-;" "-" SYMBOL SPACE "* #,##0.00_-;" "_-" SYMBOL SPACE "* \"-\"?\?_-;" "_-@_-" )
+
+/** Defines builtin currency formats 5...8 (with currency symbol), 37...40
+ (blind currency symbol), and 41...44 (accounting), in the following order:
+ "[minus], symbol, number".
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number. */
+#define NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( SYMBOL, SPACE ) \
+ NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 5, SYMBOL, SPACE, "" ), \
+ NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 37, "", "", "" ), \
+ NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( 41, SYMBOL, SPACE )
+
+/** Defines builtin currency formats INDEX...INDEX+3 in the following format:
+ "[minus], number, symbol".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between number and currency symbol.
+ @param MODIF Leading modifier for each portion (e.g. "t" for Thai formats). */
+#define NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( INDEX, SYMBOL, SPACE, MODIF ) \
+ NUMFMT_STRING( INDEX + 0, MODIF "#,##0" SPACE SYMBOL ";" MODIF "-#,##0" SPACE SYMBOL ), \
+ NUMFMT_STRING( INDEX + 1, MODIF "#,##0" SPACE SYMBOL ";" "[RED]" MODIF "-#,##0" SPACE SYMBOL ), \
+ NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL ";" MODIF "-#,##0.00" SPACE SYMBOL ), \
+ NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL ";" "[RED]" MODIF "-#,##0.00" SPACE SYMBOL )
+
+/** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
+ "[minus], number, symbol".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param BLINDS Blind currency symbol.
+ @param SPACE Space character(s) between number and currency symbol. */
+#define NUMFMT_ACCOUNTING_MINUS_NUMBER_SYMBOL( INDEX, SYMBOL, BLINDS, SPACE ) \
+ NUMFMT_STRING( INDEX + 0, "_-* #,##0" SPACE BLINDS "_-;-* #,##0" SPACE BLINDS "_-;_-* \"-\"" SPACE BLINDS "_-;_-@_-" ), \
+ NUMFMT_STRING( INDEX + 1, "_-* #,##0" SPACE SYMBOL "_-;-* #,##0" SPACE SYMBOL "_-;_-* \"-\"" SPACE SYMBOL "_-;_-@_-" ), \
+ NUMFMT_STRING( INDEX + 2, "_-* #,##0.00" SPACE BLINDS "_-;-* #,##0.00" SPACE BLINDS "_-;_-* \"-\"?\?" SPACE BLINDS "_-;_-@_-" ), \
+ NUMFMT_STRING( INDEX + 3, "_-* #,##0.00" SPACE SYMBOL "_-;-* #,##0.00" SPACE SYMBOL "_-;_-* \"-\"?\?" SPACE SYMBOL "_-;_-@_-" )
+
+/** Defines builtin currency formats 5...8 (with currency symbol), 37...40
+ (blind currency symbol), and 41...44 (accounting), in the following format:
+ "[minus], number, symbol".
+ @param SYMBOL Currency symbol.
+ @param BLINDS Blind currency symbol.
+ @param SPACE Space character(s) between number and currency symbol. */
+#define NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( SYMBOL, BLINDS, SPACE ) \
+ NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( 5, SYMBOL, SPACE, "" ), \
+ NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( 37, BLINDS, SPACE, "" ), \
+ NUMFMT_ACCOUNTING_MINUS_NUMBER_SYMBOL( 41, SYMBOL, BLINDS, SPACE )
+
+/** Defines builtin currency formats INDEX...INDEX+3 in the following format:
+ "[opening parenthesis], symbol, number, [closing parenthesis].".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number.
+ @param MODIF Leading modifier for each portion (e.g. "t" for Thai formats). */
+#define NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( INDEX, SYMBOL, SPACE, MODIF ) \
+ NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0_);" MODIF "(" SYMBOL SPACE "#,##0)" ), \
+ NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0_);" "[RED]" MODIF "(" SYMBOL SPACE "#,##0)" ), \
+ NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00_);" MODIF "(" SYMBOL SPACE "#,##0.00)" ), \
+ NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00_);" "[RED]" MODIF "(" SYMBOL SPACE "#,##0.00)" )
+
+/** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
+ "[opening parenthesis], symbol, number, [closing parenthesis].".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number. */
+#define NUMFMT_ACCOUNTING_OPEN_SYMBOL_NUMBER_CLOSE( INDEX, SYMBOL, SPACE ) \
+ NUMFMT_STRING( INDEX + 0, "_(" "* #,##0_);" "_(" "* (#,##0);" "_(" "* \"-\"_);" "_(@_)" ), \
+ NUMFMT_STRING( INDEX + 1, "_(" SYMBOL SPACE "* #,##0_);" "_(" SYMBOL SPACE "* (#,##0);" "_(" SYMBOL SPACE "* \"-\"_);" "_(@_)" ), \
+ NUMFMT_STRING( INDEX + 2, "_(" "* #,##0.00_);" "_(" "* (#,##0.00);" "_(" "* \"-\"?\?_);" "_(@_)" ), \
+ NUMFMT_STRING( INDEX + 3, "_(" SYMBOL SPACE "* #,##0.00_);" "_(" SYMBOL SPACE "* (#,##0.00);" "_(" SYMBOL SPACE "* \"-\"?\?_);" "_(@_)" )
+
+/** Defines builtin currency formats 5...8 (with currency symbol), 37...40
+ (blind currency symbol), and 41...44 (accounting), in the following format:
+ "[opening parenthesis], symbol, number, [closing parenthesis].".
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between currency symbol and number. */
+#define NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( SYMBOL, SPACE ) \
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 5, SYMBOL, SPACE, "" ), \
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 37, "", "", "" ), \
+ NUMFMT_ACCOUNTING_OPEN_SYMBOL_NUMBER_CLOSE( 41, SYMBOL, SPACE )
+
+/** Defines builtin currency formats INDEX...INDEX+3 in the following format:
+ "[opening parenthesis], number, symbol, [closing parenthesis].".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param SPACE Space character(s) between number and currency symbol.
+ @param MODIF Leading modifier for each portion (e.g. "t" for Thai formats). */
+#define NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( INDEX, SYMBOL, SPACE, MODIF ) \
+ NUMFMT_STRING( INDEX + 0, MODIF "#,##0" SPACE SYMBOL "_);" MODIF "(#,##0" SPACE SYMBOL ")" ), \
+ NUMFMT_STRING( INDEX + 1, MODIF "#,##0" SPACE SYMBOL "_);" "[RED]" MODIF "(#,##0" SPACE SYMBOL ")" ), \
+ NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL "_);" MODIF "(#,##0.00" SPACE SYMBOL ")" ), \
+ NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL "_);" "[RED]" MODIF "(#,##0.00" SPACE SYMBOL ")" )
+
+/** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
+ "[opening parenthesis], number, symbol, [closing parenthesis].".
+ @param INDEX First number format index.
+ @param SYMBOL Currency symbol.
+ @param BLINDS Blind currency symbol.
+ @param SPACE Space character(s) between number and currency symbol. */
+#define NUMFMT_ACCOUNTING_OPEN_NUMBER_SYMBOL_CLOSE( INDEX, SYMBOL, BLINDS, SPACE ) \
+ NUMFMT_STRING( INDEX + 0, "_ * #,##0_)" SPACE BLINDS "_ ;_ * (#,##0)" SPACE BLINDS "_ ;_ * \"-\"_)" SPACE BLINDS "_ ;_ @_ " ), \
+ NUMFMT_STRING( INDEX + 1, "_ * #,##0_)" SPACE SYMBOL "_ ;_ * (#,##0)" SPACE SYMBOL "_ ;_ * \"-\"_)" SPACE SYMBOL "_ ;_ @_ " ), \
+ NUMFMT_STRING( INDEX + 2, "_ * #,##0.00_)" SPACE BLINDS "_ ;_ * (#,##0.00)" SPACE BLINDS "_ ;_ * \"-\"?\?_)" SPACE BLINDS "_ ;_ @_ " ), \
+ NUMFMT_STRING( INDEX + 3, "_ * #,##0.00_)" SPACE SYMBOL "_ ;_ * (#,##0.00)" SPACE SYMBOL "_ ;_ * \"-\"?\?_)" SPACE SYMBOL "_ ;_ @_ " )
+
+/** Defines builtin currency formats 5...8 (with currency symbol), 37...40
+ (blind currency symbol), and 41...44 (accounting), in the following format:
+ "[opening parenthesis], number, symbol, [closing parenthesis].".
+ @param SYMBOL Currency symbol.
+ @param BLINDS Blind currency symbol.
+ @param SPACE Space character(s) between number and currency symbol. */
+#define NUMFMT_ALLCURRENCIES_OPEN_NUMBER_SYMBOL_CLOSE( SYMBOL, BLINDS, SPACE ) \
+ NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( 5, SYMBOL, SPACE, "" ), \
+ NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( 37, BLINDS, SPACE, "" ), \
+ NUMFMT_ACCOUNTING_OPEN_NUMBER_SYMBOL_CLOSE( 41, SYMBOL, BLINDS, SPACE )
+
+// currency unit characters
+#define UTF8_BAHT "\340\270\277"
+#define UTF8_COLON "\342\202\241"
+#define UTF8_CURR_AR_AE "\330\257.\330\245."
+#define UTF8_CURR_AR_BH "\330\257.\330\250."
+#define UTF8_CURR_AR_DZ "\330\257.\330\254."
+#define UTF8_CURR_AR_EG "\330\254.\331\205."
+#define UTF8_CURR_AR_IQ "\330\257.\330\271."
+#define UTF8_CURR_AR_JO "\330\257.\330\247."
+#define UTF8_CURR_AR_KW "\330\257.\331\203."
+#define UTF8_CURR_AR_LB "\331\204.\331\204."
+#define UTF8_CURR_AR_LY "\330\257.\331\204."
+#define UTF8_CURR_AR_MA "\330\257.\331\205."
+#define UTF8_CURR_AR_OM "\330\261.\330\271."
+#define UTF8_CURR_AR_QA "\330\261.\331\202."
+#define UTF8_CURR_AR_SA "\330\261.\330\263."
+#define UTF8_CURR_AR_SY "\331\204.\330\263."
+#define UTF8_CURR_AR_TN "\330\257.\330\252."
+#define UTF8_CURR_AR_YE "\330\261.\331\212."
+#define UTF8_CURR_BN_IN "\340\246\237\340\246\276"
+#define UTF8_CURR_FA_IR "\330\261\331\212\330\247\331\204"
+#define UTF8_CURR_GU_IN "\340\252\260\340\253\202"
+#define UTF8_CURR_HI_IN "\340\244\260\340\245\201"
+#define UTF8_CURR_KN_IN "\340\262\260\340\263\202"
+#define UTF8_CURR_ML_IN "\340\264\225"
+#define UTF8_CURR_PA_IN "\340\250\260\340\251\201"
+#define UTF8_CURR_TA_IN "\340\256\260\340\257\202"
+#define UTF8_CURR_TE_IN "\340\260\260\340\261\202"
+#define UTF8_DONG "\342\202\253"
+#define UTF8_EURO "\342\202\254"
+#define UTF8_POUND_GB "\302\243"
+#define UTF8_RUFIYAA "\336\203"
+#define UTF8_SHEQEL "\342\202\252"
+#define UTF8_TUGRUG "\342\202\256"
+#define UTF8_WON "\342\202\251"
+#define UTF8_YEN_CN "\357\277\245"
+#define UTF8_YEN_JP "\302\245"
+
+// Unicode characters for currency units
+#define UTF8_CCARON_LC "\304\215"
+#define UTF8_LSTROKE_LC "\305\202"
+// Armenian
+#define UTF8_HY_DA_LC "\325\244"
+#define UTF8_HY_REH_LC "\326\200"
+// Cyrillic
+#define UTF8_CYR_G_LC "\320\263"
+#define UTF8_CYR_L_LC "\320\273"
+#define UTF8_CYR_M_LC "\320\274"
+#define UTF8_CYR_N_LC "\320\275"
+#define UTF8_CYR_O_LC "\320\276"
+#define UTF8_CYR_R_LC "\321\200"
+#define UTF8_CYR_S_LC "\321\201"
+#define UTF8_CYR_W_LC "\320\262"
+
+// Japanese/Chinese date/time characters
+#define UTF8_CJ_YEAR "\345\271\264"
+#define UTF8_CJ_MON "\346\234\210"
+#define UTF8_CJ_DAY "\346\227\245"
+#define UTF8_CJ_HOUR "\346\231\202"
+#define UTF8_CJ_MIN "\345\210\206"
+#define UTF8_CJ_SEC "\347\247\222"
+
+// Chinese Simplified date/time characters
+#define UTF8_CS_YEAR "\345\271\264"
+#define UTF8_CS_MON "\346\234\210"
+#define UTF8_CS_DAY "\346\227\245"
+#define UTF8_CS_HOUR "\346\227\266"
+#define UTF8_CS_MIN "\345\210\206"
+#define UTF8_CS_SEC "\347\247\222"
+
+// Korean date/time characters
+#define UTF8_KO_YEAR "\353\205\204"
+#define UTF8_KO_MON "\354\233\224"
+#define UTF8_KO_DAY "\354\235\274"
+#define UTF8_KO_HOUR "\354\213\234"
+#define UTF8_KO_MIN "\353\266\204"
+#define UTF8_KO_SEC "\354\264\210"
+
+// ----------------------------------------------------------------------------
+
+/** Default number format table. Last parent of all other tables, used for unknown locales. */
+static const BuiltinFormat spBuiltinFormats_BASE[] =
+{
+ // 0..13 numeric and currency formats
+ NUMFMT_PREDEF( 0, NUMBER_STANDARD ), // General
+ NUMFMT_PREDEF( 1, NUMBER_INT ), // 0
+ NUMFMT_PREDEF( 2, NUMBER_DEC2 ), // 0.00
+ NUMFMT_PREDEF( 3, NUMBER_1000INT ), // #,##0
+ NUMFMT_PREDEF( 4, NUMBER_1000DEC2 ), // #,##0.00
+ NUMFMT_PREDEF( 5, CURRENCY_1000INT ), // #,##0[symbol]
+ NUMFMT_PREDEF( 6, CURRENCY_1000INT_RED ), // #,##0[symbol];[RED]-#,##0[symbol]
+ NUMFMT_PREDEF( 7, CURRENCY_1000DEC2 ), // #,##0.00[symbol]
+ NUMFMT_PREDEF( 8, CURRENCY_1000DEC2_RED ), // #,##0.00[symbol];[RED]-#,##0.00[symbol]
+ NUMFMT_PREDEF( 9, PERCENT_INT ), // 0%
+ NUMFMT_PREDEF( 10, PERCENT_DEC2 ), // 0.00%
+ NUMFMT_PREDEF( 11, SCIENTIFIC_000E00 ), // 0.00E+00
+ NUMFMT_PREDEF( 12, FRACTION_1 ), // # ?/?
+ NUMFMT_PREDEF( 13, FRACTION_2 ), // # ??/??
+
+ // 14...22 date and time formats
+ NUMFMT_PREDEF( 14, DATE_SYS_DDMMYYYY ),
+ NUMFMT_PREDEF( 15, DATE_SYS_DMMMYY ),
+ NUMFMT_PREDEF( 16, DATE_SYS_DDMMM ),
+ NUMFMT_PREDEF( 17, DATE_SYS_MMYY ),
+ NUMFMT_PREDEF( 18, TIME_HHMMAMPM ),
+ NUMFMT_PREDEF( 19, TIME_HHMMSSAMPM ),
+ NUMFMT_PREDEF( 20, TIME_HHMM ),
+ NUMFMT_PREDEF( 21, TIME_HHMMSS ),
+ NUMFMT_PREDEF( 22, DATETIME_SYSTEM_SHORT_HHMM ),
+
+ // 23...36 international formats
+ NUMFMT_REUSE( 23, 0 ),
+ NUMFMT_REUSE( 24, 0 ),
+ NUMFMT_REUSE( 25, 0 ),
+ NUMFMT_REUSE( 26, 0 ),
+ NUMFMT_REUSE( 27, 14 ),
+ NUMFMT_REUSE( 28, 14 ),
+ NUMFMT_REUSE( 29, 14 ),
+ NUMFMT_REUSE( 30, 14 ),
+ NUMFMT_REUSE( 31, 14 ),
+ NUMFMT_REUSE( 32, 21 ),
+ NUMFMT_REUSE( 33, 21 ),
+ NUMFMT_REUSE( 34, 21 ),
+ NUMFMT_REUSE( 35, 21 ),
+ NUMFMT_REUSE( 36, 14 ),
+
+ // 37...44 accounting formats, defaults without currency symbol here
+ NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 37, "", "", "" ),
+ NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( 41, "", "" ),
+
+ // 45...49 more special formats
+ NUMFMT_STRING( 45, "mm:ss" ),
+ NUMFMT_STRING( 46, "[h]:mm:ss" ),
+ NUMFMT_STRING( 47, "mm:ss.0" ),
+ NUMFMT_STRING( 48, "##0.0E+0" ),
+ NUMFMT_PREDEF( 49, TEXT ),
+
+ // 50...81 international formats
+ NUMFMT_REUSE( 50, 14 ),
+ NUMFMT_REUSE( 51, 14 ),
+ NUMFMT_REUSE( 52, 14 ),
+ NUMFMT_REUSE( 53, 14 ),
+ NUMFMT_REUSE( 54, 14 ),
+ NUMFMT_REUSE( 55, 14 ),
+ NUMFMT_REUSE( 56, 14 ),
+ NUMFMT_REUSE( 57, 14 ),
+ NUMFMT_REUSE( 58, 14 ),
+ NUMFMT_REUSE( 59, 1 ),
+ NUMFMT_REUSE( 60, 2 ),
+ NUMFMT_REUSE( 61, 3 ),
+ NUMFMT_REUSE( 62, 4 ),
+ NUMFMT_REUSE( 63, 5 ),
+ NUMFMT_REUSE( 64, 6 ),
+ NUMFMT_REUSE( 65, 7 ),
+ NUMFMT_REUSE( 66, 8 ),
+ NUMFMT_REUSE( 67, 9 ),
+ NUMFMT_REUSE( 68, 10 ),
+ NUMFMT_REUSE( 69, 12 ),
+ NUMFMT_REUSE( 70, 13 ),
+ NUMFMT_REUSE( 71, 14 ),
+ NUMFMT_REUSE( 72, 14 ),
+ NUMFMT_REUSE( 73, 15 ),
+ NUMFMT_REUSE( 74, 16 ),
+ NUMFMT_REUSE( 75, 17 ),
+ NUMFMT_REUSE( 76, 20 ),
+ NUMFMT_REUSE( 77, 21 ),
+ NUMFMT_REUSE( 78, 22 ),
+ NUMFMT_REUSE( 79, 45 ),
+ NUMFMT_REUSE( 80, 46 ),
+ NUMFMT_REUSE( 81, 47 ),
+
+ // 82...163 not used, must not occur in a file (Excel may crash)
+
+ NUMFMT_ENDTABLE()
+};
+
+// ----------------------------------------------------------------------------
+
+/** Arabic, U.A.E. */
+static const BuiltinFormat spBuiltinFormats_ar_AE[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_AE "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Bahrain. */
+static const BuiltinFormat spBuiltinFormats_ar_BH[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_BH "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Algeria. */
+static const BuiltinFormat spBuiltinFormats_ar_DZ[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_DZ "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Egypt. */
+static const BuiltinFormat spBuiltinFormats_ar_EG[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_EG "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Iraq. */
+static const BuiltinFormat spBuiltinFormats_ar_IQ[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_IQ "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Jordan. */
+static const BuiltinFormat spBuiltinFormats_ar_JO[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_JO "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Kuwait. */
+static const BuiltinFormat spBuiltinFormats_ar_KW[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_KW "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Lebanon. */
+static const BuiltinFormat spBuiltinFormats_ar_LB[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_LB "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Libya. */
+static const BuiltinFormat spBuiltinFormats_ar_LY[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_LY "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Morocco. */
+static const BuiltinFormat spBuiltinFormats_ar_MA[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_MA "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Oman. */
+static const BuiltinFormat spBuiltinFormats_ar_OM[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_OM "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Qatar. */
+static const BuiltinFormat spBuiltinFormats_ar_QA[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_QA "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Saudi Arabia. */
+static const BuiltinFormat spBuiltinFormats_ar_SA[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_SA "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Syria. */
+static const BuiltinFormat spBuiltinFormats_ar_SY[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_SY "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Tunisia. */
+static const BuiltinFormat spBuiltinFormats_ar_TN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_TN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Arabic, Yemen. */
+static const BuiltinFormat spBuiltinFormats_ar_YE[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_YE "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Belarusian, Belarus. */
+static const BuiltinFormat spBuiltinFormats_be_BY[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Bulgarian, Bulgaria. */
+static const BuiltinFormat spBuiltinFormats_bg_BG[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.M.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_L_LC UTF8_CYR_W_LC "\"", "_" UTF8_CYR_L_LC "_" UTF8_CYR_W_LC, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Bengali, India. */
+static const BuiltinFormat spBuiltinFormats_bn_IN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_BN_IN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Czech, Czech Republic. */
+static const BuiltinFormat spBuiltinFormats_cs_CZ[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"K" UTF8_CCARON_LC "\"", "_K_" UTF8_CCARON_LC, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Danish, Denmark. */
+static const BuiltinFormat spBuiltinFormats_da_DK[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** German, Austria. */
+static const BuiltinFormat spBuiltinFormats_de_AT[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** German, Switzerland. */
+static const BuiltinFormat spBuiltinFormats_de_CH[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** German, Germany. */
+static const BuiltinFormat spBuiltinFormats_de_DE[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** German, Liechtenstein. */
+static const BuiltinFormat spBuiltinFormats_de_LI[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"CHF\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** German, Luxembourg. */
+static const BuiltinFormat spBuiltinFormats_de_LU[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Divehi, Maldives. */
+static const BuiltinFormat spBuiltinFormats_div_MV[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_NUMBER_SYMBOL_MINUS( "\"" UTF8_RUFIYAA ".\"", "_" UTF8_RUFIYAA "_.", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Greek, Greece. */
+static const BuiltinFormat spBuiltinFormats_el_GR[] =
+{
+ NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Australia. */
+static const BuiltinFormat spBuiltinFormats_en_AU[] =
+{
+ NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Belize. */
+static const BuiltinFormat spBuiltinFormats_en_BZ[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"BZ$\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Canada. */
+static const BuiltinFormat spBuiltinFormats_en_CA[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Caribbean. */
+static const BuiltinFormat spBuiltinFormats_en_CB[] =
+{
+ NUMFMT_ALLDATETIMES( "MM/DD/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, United Kingdom. */
+static const BuiltinFormat spBuiltinFormats_en_GB[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_POUND_GB, "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Ireland. */
+static const BuiltinFormat spBuiltinFormats_en_IE[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Jamaica. */
+static const BuiltinFormat spBuiltinFormats_en_JM[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"J$\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, New Zealand. */
+static const BuiltinFormat spBuiltinFormats_en_NZ[] =
+{
+ NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Philippines. */
+static const BuiltinFormat spBuiltinFormats_en_PH[] =
+{
+ NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Php\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Trinidad and Tobago. */
+static const BuiltinFormat spBuiltinFormats_en_TT[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"TT$\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, USA. */
+static const BuiltinFormat spBuiltinFormats_en_US[] =
+{
+ NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, South Africa. */
+static const BuiltinFormat spBuiltinFormats_en_ZA[] =
+{
+ NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\\R", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** English, Zimbabwe. */
+static const BuiltinFormat spBuiltinFormats_en_ZW[] =
+{
+ NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Z$\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Argentina. */
+static const BuiltinFormat spBuiltinFormats_es_AR[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "$", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Bolivia. */
+static const BuiltinFormat spBuiltinFormats_es_BO[] =
+{
+ // slashes must be quoted to prevent conversion to minus
+ NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"$b\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Chile. */
+static const BuiltinFormat spBuiltinFormats_es_CL[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Colombia. */
+static const BuiltinFormat spBuiltinFormats_es_CO[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Costa Rica. */
+static const BuiltinFormat spBuiltinFormats_es_CR[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( UTF8_COLON, "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Dominican Republic. */
+static const BuiltinFormat spBuiltinFormats_es_DO[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"RD$\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Ecuador. */
+static const BuiltinFormat spBuiltinFormats_es_EC[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Spain. */
+static const BuiltinFormat spBuiltinFormats_es_ES[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Guatemala. */
+static const BuiltinFormat spBuiltinFormats_es_GT[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\Q", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Honduras. */
+static const BuiltinFormat spBuiltinFormats_es_HN[] =
+{
+ // slashes must be quoted to prevent conversion to minus
+ NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"L.\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Mexico. */
+static const BuiltinFormat spBuiltinFormats_es_MX[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Nicaragua. */
+static const BuiltinFormat spBuiltinFormats_es_NI[] =
+{
+ // slashes must be quoted to prevent conversion to minus
+ NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"C$\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Panama. */
+static const BuiltinFormat spBuiltinFormats_es_PA[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"B/.\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Peru. */
+static const BuiltinFormat spBuiltinFormats_es_PE[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"S/.\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Puerto Rico. */
+static const BuiltinFormat spBuiltinFormats_es_PR[] =
+{
+ // slashes must be quoted to prevent conversion to minus
+ NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Paraguay. */
+static const BuiltinFormat spBuiltinFormats_es_PY[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Gs\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, El Salvador. */
+static const BuiltinFormat spBuiltinFormats_es_SV[] =
+{
+ // slashes must be quoted to prevent conversion to minus
+ NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Uruguay. */
+static const BuiltinFormat spBuiltinFormats_es_UY[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"$U\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Spanish, Venezuela. */
+static const BuiltinFormat spBuiltinFormats_es_VE[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "Bs", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Estonian, Estonia. */
+static const BuiltinFormat spBuiltinFormats_et_EE[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "D.MM.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr\"", "_k_r", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Farsi, Iran. */
+static const BuiltinFormat spBuiltinFormats_fa_IR[] =
+{
+ NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_FA_IR "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Finnish, Finland. */
+static const BuiltinFormat spBuiltinFormats_fi_FI[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_STRING( 9, "0\\ %" ),
+ NUMFMT_STRING( 10, "0.00\\ %" ),
+ NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Faroese, Faroe Islands. */
+static const BuiltinFormat spBuiltinFormats_fo_FO[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** French, Belgium. */
+static const BuiltinFormat spBuiltinFormats_fr_BE[] =
+{
+ NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** French, Canada. */
+static const BuiltinFormat spBuiltinFormats_fr_CA[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_NUMBER_SYMBOL_CLOSE( "$", "_$", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** French, Switzerland. */
+static const BuiltinFormat spBuiltinFormats_fr_CH[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** French, France. */
+static const BuiltinFormat spBuiltinFormats_fr_FR[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** French, Luxembourg. */
+static const BuiltinFormat spBuiltinFormats_fr_LU[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** French, Monaco. */
+static const BuiltinFormat spBuiltinFormats_fr_MC[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Galizian, Spain. */
+static const BuiltinFormat spBuiltinFormats_gl_ES[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Gujarati, India. */
+static const BuiltinFormat spBuiltinFormats_gu_IN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_GU_IN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Hebrew, Israel. */
+static const BuiltinFormat spBuiltinFormats_he_IL[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( UTF8_SHEQEL, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Hindi, India. */
+static const BuiltinFormat spBuiltinFormats_hi_IN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_HI_IN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Croatian, Bosnia and Herzegowina. */
+static const BuiltinFormat spBuiltinFormats_hr_BA[] =
+{
+ NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"KM\"", "_K_M", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Croatian, Croatia. */
+static const BuiltinFormat spBuiltinFormats_hr_HR[] =
+{
+ NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kn\"", "_k_n", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Hungarian, Hungary. */
+static const BuiltinFormat spBuiltinFormats_hu_HU[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ // MMM is rendered differently in Calc and Excel (see #i41488#)
+ NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Ft\"", "_F_t", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Armenian, Armenia. */
+static const BuiltinFormat spBuiltinFormats_hy_AM[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_HY_DA_LC UTF8_HY_REH_LC ".\"", "_" UTF8_HY_DA_LC "_" UTF8_HY_REH_LC "_.", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Indonesian, Indonesia. */
+static const BuiltinFormat spBuiltinFormats_id_ID[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Rp\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Icelandic, Iceland. */
+static const BuiltinFormat spBuiltinFormats_is_IS[] =
+{
+ NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr.\"", "_k_r_.", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Italian, Switzerland. */
+static const BuiltinFormat spBuiltinFormats_it_CH[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Italian, Italy. */
+static const BuiltinFormat spBuiltinFormats_it_IT[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Georgian, Georgia. */
+static const BuiltinFormat spBuiltinFormats_ka_GE[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Lari\"", "_L_a_r_i", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Kazakh, Kazakhstan. */
+static const BuiltinFormat spBuiltinFormats_kk_KZ[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\\T", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Kannada, India. */
+static const BuiltinFormat spBuiltinFormats_kn_IN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_KN_IN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Kyrgyz, Kyrgyzstan. */
+static const BuiltinFormat spBuiltinFormats_ky_KG[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.MM.YY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_S_LC UTF8_CYR_O_LC UTF8_CYR_M_LC "\"", "_" UTF8_CYR_S_LC "_" UTF8_CYR_O_LC "_" UTF8_CYR_M_LC, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Lithuanian, Lithuania. */
+static const BuiltinFormat spBuiltinFormats_lt_LT[] =
+{
+ NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Lt\"", "_L_t", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Latvian, Latvia. */
+static const BuiltinFormat spBuiltinFormats_lv_LV[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"Ls\"", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Malayalam, India. */
+static const BuiltinFormat spBuiltinFormats_ml_IN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_ML_IN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Mongolian, Mongolia. */
+static const BuiltinFormat spBuiltinFormats_mn_MN[] =
+{
+ NUMFMT_ALLDATETIMES( "YY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_TUGRUG, "_" UTF8_TUGRUG, "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Malay, Brunei Darussalam. */
+static const BuiltinFormat spBuiltinFormats_ms_BN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Malay, Malaysia. */
+static const BuiltinFormat spBuiltinFormats_ms_MY[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\R", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Maltese, Malta. */
+static const BuiltinFormat spBuiltinFormats_mt_MT[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"Lm\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Dutch, Belgium. */
+static const BuiltinFormat spBuiltinFormats_nl_BE[] =
+{
+ // slashes must be quoted to prevent conversion to minus
+ NUMFMT_ALLDATETIMES( "D\\/MM\\/YYYY", "D", "\\/", "MMM", "\\/", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Dutch, Netherlands. */
+static const BuiltinFormat spBuiltinFormats_nl_NL[] =
+{
+ NUMFMT_ALLDATETIMES( "D-M-YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Norwegian (Bokmal and Nynorsk), Norway. */
+static const BuiltinFormat spBuiltinFormats_no_NO[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Punjabi, India. */
+static const BuiltinFormat spBuiltinFormats_pa_IN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_PA_IN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Polish, Poland. */
+static const BuiltinFormat spBuiltinFormats_pl_PL[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ // MMM is rendered differently in Calc and Excel (see #i72300#)
+ NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"z" UTF8_LSTROKE_LC "\"", "_z_" UTF8_LSTROKE_LC, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Portugese, Brazil. */
+static const BuiltinFormat spBuiltinFormats_pt_BR[] =
+{
+ NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "/", "MMM", "/", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"R$\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Portugese, Portugal. */
+static const BuiltinFormat spBuiltinFormats_pt_PT[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Romanian, Romania. */
+static const BuiltinFormat spBuiltinFormats_ro_RO[] =
+{
+ // space character is group separator, literal spaces must be quoted (but see #i75367#)
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"lei\"", "_l_e_i", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Russian, Russian Federation. */
+static const BuiltinFormat spBuiltinFormats_ru_RU[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Slovak, Slovakia. */
+static const BuiltinFormat spBuiltinFormats_sk_SK[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Sk\"", "_S_k", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Slovenian, Slovenia. */
+static const BuiltinFormat spBuiltinFormats_sl_SI[] =
+{
+ NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"SIT\"", "_S_I_T", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Swedish, Finland. */
+static const BuiltinFormat spBuiltinFormats_sv_FI[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_STRING( 9, "0\\ %" ),
+ NUMFMT_STRING( 10, "0.00\\ %" ),
+ NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Swedish, Sweden. */
+static const BuiltinFormat spBuiltinFormats_sv_SE[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr\"", "_k_r", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Swahili, Tanzania. */
+static const BuiltinFormat spBuiltinFormats_sw_TZ[] =
+{
+ NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\S", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Tamil, India. */
+static const BuiltinFormat spBuiltinFormats_ta_IN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_TA_IN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Telugu, India. */
+static const BuiltinFormat spBuiltinFormats_te_IN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_TE_IN "\"", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Thai, Thailand. */
+static const BuiltinFormat spBuiltinFormats_th_TH[] =
+{
+ NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_BAHT, "" ),
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 63, UTF8_BAHT, "", "t" ),
+ NUMFMT_STRING( 59, "t0" ),
+ NUMFMT_STRING( 60, "t0.00" ),
+ NUMFMT_STRING( 61, "t#,##0" ),
+ NUMFMT_STRING( 62, "t#,##0.00" ),
+ NUMFMT_STRING( 67, "t0%" ),
+ NUMFMT_STRING( 68, "t0.00%" ),
+ NUMFMT_STRING( 69, "t# ?/?" ),
+ NUMFMT_STRING( 70, "t# ?\?/?\?" ),
+ NUMFMT_STRING( 71, "tD/M/EE" ),
+ NUMFMT_STRING( 72, "tD-MMM-E" ),
+ NUMFMT_STRING( 73, "tD-MMM" ),
+ NUMFMT_STRING( 74, "tMMM-E" ),
+ NUMFMT_STRING( 75, "th:mm" ),
+ NUMFMT_STRING( 76, "th:mm:ss" ),
+ NUMFMT_STRING( 77, "tD/M/EE h:mm" ),
+ NUMFMT_STRING( 78, "tmm:ss" ),
+ NUMFMT_STRING( 79, "t[h]:mm:ss" ),
+ NUMFMT_STRING( 80, "tmm:ss.0" ),
+ NUMFMT_STRING( 81, "D/M/E" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Turkish, Turkey. */
+static const BuiltinFormat spBuiltinFormats_tr_TR[] =
+{
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"TL\"", "_T_L", " " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Tatar, Russian Federation. */
+static const BuiltinFormat spBuiltinFormats_tt_RU[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Ukrainian, Ukraine. */
+static const BuiltinFormat spBuiltinFormats_uk_UA[] =
+{
+ // space character is group separator, literal spaces must be quoted
+ NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_G_LC UTF8_CYR_R_LC UTF8_CYR_N_LC ".\"", "_" UTF8_CYR_G_LC "_" UTF8_CYR_R_LC "_" UTF8_CYR_N_LC "_.", "\\ " ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Urdu, Pakistan. */
+static const BuiltinFormat spBuiltinFormats_ur_PK[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"Rs\"", "" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Vietnamese, Viet Nam. */
+static const BuiltinFormat spBuiltinFormats_vi_VN[] =
+{
+ NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_DONG, "_" UTF8_DONG, " " ),
+ NUMFMT_ENDTABLE()
+};
+
+// CJK ------------------------------------------------------------------------
+
+/** Base table for CJK locales. */
+static const BuiltinFormat spBuiltinFormats_CJK[] =
+{
+ NUMFMT_REUSE( 29, 28 ),
+ NUMFMT_REUSE( 36, 27 ),
+ NUMFMT_REUSE( 50, 27 ),
+ NUMFMT_REUSE( 51, 28 ),
+ NUMFMT_REUSE( 52, 34 ),
+ NUMFMT_REUSE( 53, 35 ),
+ NUMFMT_REUSE( 54, 28 ),
+ NUMFMT_REUSE( 55, 34 ),
+ NUMFMT_REUSE( 56, 35 ),
+ NUMFMT_REUSE( 57, 27 ),
+ NUMFMT_REUSE( 58, 28 ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Japanese, Japan. */
+static const BuiltinFormat spBuiltinFormats_ja_JP[] =
+{
+ NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_YEN_JP, "" ),
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
+ NUMFMT_STRING( 27, "[$-411]GE.MM.DD" ),
+ NUMFMT_STRING( 28, "[$-411]GGGE\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
+ NUMFMT_STRING( 30, "MM/DD/YY" ),
+ NUMFMT_STRING( 31, "YYYY\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
+ NUMFMT_TIME_CJK( 32, "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
+ NUMFMT_STRING( 34, "YYYY\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"" ),
+ NUMFMT_STRING( 35, "MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Korean, South Korea. */
+static const BuiltinFormat spBuiltinFormats_ko_KR[] =
+{
+ NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_WON, "" ),
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
+ NUMFMT_STRING( 27, "YYYY" UTF8_CJ_YEAR " MM" UTF8_CJ_MON " DD" UTF8_CJ_DAY ),
+ NUMFMT_STRING( 28, "MM-DD" ),
+ NUMFMT_STRING( 30, "MM-DD-YY" ),
+ NUMFMT_STRING( 31, "YYYY" UTF8_KO_YEAR " MM" UTF8_KO_MON " DD" UTF8_KO_DAY ),
+ NUMFMT_TIME_CJK( 32, "h", UTF8_KO_HOUR, UTF8_KO_MIN, UTF8_KO_SEC ),
+ // slashes must be quoted to prevent conversion to minus
+ NUMFMT_STRING( 34, "YYYY\\/MM\\/DD" ),
+ NUMFMT_REUSE( 35, 14 ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Chinese, China. */
+static const BuiltinFormat spBuiltinFormats_zh_CN[] =
+{
+ NUMFMT_ALLDATETIMES( "YYYY-M-D", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( UTF8_YEN_CN, "" ),
+ NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CS_HOUR, UTF8_CS_MIN, UTF8_CS_SEC ),
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
+ NUMFMT_STRING( 27, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"" ),
+ NUMFMT_STRING( 28, "M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
+ NUMFMT_STRING( 30, "M-D-YY" ),
+ NUMFMT_STRING( 31, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
+ NUMFMT_REUSE( 52, 27 ),
+ NUMFMT_REUSE( 53, 28 ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Chinese, Hong Kong. */
+static const BuiltinFormat spBuiltinFormats_zh_HK[] =
+{
+ NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"HK$\"", "" ),
+ NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
+ NUMFMT_STRING( 27, "[$-404]D/M/E" ),
+ NUMFMT_STRING( 28, "[$-404]D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"E\"" UTF8_CJ_YEAR "\"" ),
+ NUMFMT_STRING( 30, "M/D/YY" ),
+ NUMFMT_STRING( 31, "D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"YYYY\"" UTF8_CJ_YEAR "\"" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Chinese, Macau. */
+static const BuiltinFormat spBuiltinFormats_zh_MO[] =
+{
+ NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\P", "" ),
+ NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
+ NUMFMT_STRING( 27, "[$-404]D/M/E" ),
+ NUMFMT_STRING( 28, "[$-404]D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"E\"" UTF8_CJ_YEAR "\"" ),
+ NUMFMT_STRING( 30, "M/D/YY" ),
+ NUMFMT_STRING( 31, "D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"YYYY\"" UTF8_CJ_YEAR "\"" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Chinese, Singapore. */
+static const BuiltinFormat spBuiltinFormats_zh_SG[] =
+{
+ NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
+ NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
+ NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CS_HOUR, UTF8_CS_MIN, UTF8_CS_SEC ),
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
+ NUMFMT_STRING( 27, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"" ),
+ NUMFMT_STRING( 28, "M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
+ NUMFMT_STRING( 30, "M/D/YY" ),
+ NUMFMT_STRING( 31, "D\"" UTF8_CS_DAY "\"M\"" UTF8_CS_MON "\"YYYY\"" UTF8_CS_YEAR "\"" ),
+ NUMFMT_ENDTABLE()
+};
+
+/** Chinese, Taiwan. */
+static const BuiltinFormat spBuiltinFormats_zh_TW[] =
+{
+ NUMFMT_ALLDATETIMES( "YYYY/M/D", "D", "-", "MMM", "-", "YY", "hh", "hh" ),
+ NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
+ NUMFMT_ALLTIMES_CJK( "hh", "hh", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
+ NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
+ NUMFMT_STRING( 27, "[$-404]E/M/D" ),
+ NUMFMT_STRING( 28, "[$-404]E\"" UTF8_CJ_YEAR "\"M\"" UTF8_CJ_MON "\"D\"" UTF8_CJ_DAY "\"" ),
+ NUMFMT_STRING( 30, "M/D/YY" ),
+ NUMFMT_STRING( 31, "YYYY\"" UTF8_CJ_YEAR "\"M\"" UTF8_CJ_MON "\"D\"" UTF8_CJ_DAY "\"" ),
+ NUMFMT_ENDTABLE()
+};
+
+// ----------------------------------------------------------------------------
+
+/** Specifies a built-in number format table for a specific locale. */
+struct BuiltinFormatTable
+{
+ const sal_Char* mpcLocale; /// The locale for this table.
+ const sal_Char* mpcParent; /// The locale of the parent table.
+ const BuiltinFormat* mpFormats; /// The number format table (may be 0, if equal to parent).
+};
+
+static const BuiltinFormatTable spBuiltinFormatTables[] =
+{ // locale parent format table
+ { "*", "", spBuiltinFormats_BASE }, // Base table
+ { "af-ZA", "*", spBuiltinFormats_en_ZA }, // Afrikaans, South Africa
+ { "ar-AE", "*", spBuiltinFormats_ar_AE }, // Arabic, U.A.E.
+ { "ar-BH", "*", spBuiltinFormats_ar_BH }, // Arabic, Bahrain
+ { "ar-DZ", "*", spBuiltinFormats_ar_DZ }, // Arabic, Algeria
+ { "ar-EG", "*", spBuiltinFormats_ar_EG }, // Arabic, Egypt
+ { "ar-IQ", "*", spBuiltinFormats_ar_IQ }, // Arabic, Iraq
+ { "ar-JO", "*", spBuiltinFormats_ar_JO }, // Arabic, Jordan
+ { "ar-KW", "*", spBuiltinFormats_ar_KW }, // Arabic, Kuwait
+ { "ar-LB", "*", spBuiltinFormats_ar_LB }, // Arabic, Lebanon
+ { "ar-LY", "*", spBuiltinFormats_ar_LY }, // Arabic, Libya
+ { "ar-MA", "*", spBuiltinFormats_ar_MA }, // Arabic, Morocco
+ { "ar-OM", "*", spBuiltinFormats_ar_OM }, // Arabic, Oman
+ { "ar-QA", "*", spBuiltinFormats_ar_QA }, // Arabic, Qatar
+ { "ar-SA", "*", spBuiltinFormats_ar_SA }, // Arabic, Saudi Arabia
+ { "ar-SY", "*", spBuiltinFormats_ar_SY }, // Arabic, Syria
+ { "ar-TN", "*", spBuiltinFormats_ar_TN }, // Arabic, Tunisia
+ { "ar-YE", "*", spBuiltinFormats_ar_YE }, // Arabic, Yemen
+ { "be-BY", "*", spBuiltinFormats_be_BY }, // Belarusian, Belarus
+ { "bg-BG", "*", spBuiltinFormats_bg_BG }, // Bulgarian, Bulgaria
+ { "bn-IN", "*", spBuiltinFormats_bn_IN }, // Bengali, India
+ { "ca-ES", "*", spBuiltinFormats_es_ES }, // Catalan, Spain
+ { "cs-CZ", "*", spBuiltinFormats_cs_CZ }, // Czech, Czech Republic
+ { "cy-GB", "*", spBuiltinFormats_en_GB }, // Welsh, United Kingdom
+ { "da-DK", "*", spBuiltinFormats_da_DK }, // Danish, Denmark
+ { "de-AT", "*", spBuiltinFormats_de_AT }, // German, Austria
+ { "de-CH", "*", spBuiltinFormats_de_CH }, // German, Switzerland
+ { "de-DE", "*", spBuiltinFormats_de_DE }, // German, Germany
+ { "de-LI", "*", spBuiltinFormats_de_LI }, // German, Liechtenstein
+ { "de-LU", "*", spBuiltinFormats_de_LU }, // German, Luxembourg
+ { "div-MV", "*", spBuiltinFormats_div_MV }, // Divehi, Maldives
+ { "el-GR", "*", spBuiltinFormats_el_GR }, // Greek, Greece
+ { "en-AU", "*", spBuiltinFormats_en_AU }, // English, Australia
+ { "en-BZ", "*", spBuiltinFormats_en_BZ }, // English, Belize
+ { "en-CA", "*", spBuiltinFormats_en_CA }, // English, Canada
+ { "en-CB", "*", spBuiltinFormats_en_CB }, // English, Caribbean
+ { "en-GB", "*", spBuiltinFormats_en_GB }, // English, United Kingdom
+ { "en-IE", "*", spBuiltinFormats_en_IE }, // English, Ireland
+ { "en-JM", "*", spBuiltinFormats_en_JM }, // English, Jamaica
+ { "en-NZ", "*", spBuiltinFormats_en_NZ }, // English, New Zealand
+ { "en-PH", "*", spBuiltinFormats_en_PH }, // English, Philippines
+ { "en-TT", "*", spBuiltinFormats_en_TT }, // English, Trinidad and Tobago
+ { "en-US", "*", spBuiltinFormats_en_US }, // English, USA
+ { "en-ZA", "*", spBuiltinFormats_en_ZA }, // English, South Africa
+ { "en-ZW", "*", spBuiltinFormats_en_ZW }, // English, Zimbabwe
+ { "es-AR", "*", spBuiltinFormats_es_AR }, // Spanish, Argentina
+ { "es-BO", "*", spBuiltinFormats_es_BO }, // Spanish, Bolivia
+ { "es-CL", "*", spBuiltinFormats_es_CL }, // Spanish, Chile
+ { "es-CO", "*", spBuiltinFormats_es_CO }, // Spanish, Colombia
+ { "es-CR", "*", spBuiltinFormats_es_CR }, // Spanish, Costa Rica
+ { "es-DO", "*", spBuiltinFormats_es_DO }, // Spanish, Dominican Republic
+ { "es-EC", "*", spBuiltinFormats_es_EC }, // Spanish, Ecuador
+ { "es-ES", "*", spBuiltinFormats_es_ES }, // Spanish, Spain
+ { "es-GT", "*", spBuiltinFormats_es_GT }, // Spanish, Guatemala
+ { "es-HN", "*", spBuiltinFormats_es_HN }, // Spanish, Honduras
+ { "es-MX", "*", spBuiltinFormats_es_MX }, // Spanish, Mexico
+ { "es-NI", "*", spBuiltinFormats_es_NI }, // Spanish, Nicaragua
+ { "es-PA", "*", spBuiltinFormats_es_PA }, // Spanish, Panama
+ { "es-PE", "*", spBuiltinFormats_es_PE }, // Spanish, Peru
+ { "es-PR", "*", spBuiltinFormats_es_PR }, // Spanish, Puerto Rico
+ { "es-PY", "*", spBuiltinFormats_es_PY }, // Spanish, Paraguay
+ { "es-SV", "*", spBuiltinFormats_es_SV }, // Spanish, El Salvador
+ { "es-UY", "*", spBuiltinFormats_es_UY }, // Spanish, Uruguay
+ { "es-VE", "*", spBuiltinFormats_es_VE }, // Spanish, Venezuela
+ { "et-EE", "*", spBuiltinFormats_et_EE }, // Estonian, Estonia
+ { "fa-IR", "*", spBuiltinFormats_fa_IR }, // Farsi, Iran
+ { "fi-FI", "*", spBuiltinFormats_fi_FI }, // Finnish, Finland
+ { "fo-FO", "*", spBuiltinFormats_fo_FO }, // Faroese, Faroe Islands
+ { "fr-BE", "*", spBuiltinFormats_fr_BE }, // French, Belgium
+ { "fr-CA", "*", spBuiltinFormats_fr_CA }, // French, Canada
+ { "fr-CH", "*", spBuiltinFormats_fr_CH }, // French, Switzerland
+ { "fr-FR", "*", spBuiltinFormats_fr_FR }, // French, France
+ { "fr-LU", "*", spBuiltinFormats_fr_LU }, // French, Luxembourg
+ { "fr-MC", "*", spBuiltinFormats_fr_MC }, // French, Monaco
+ { "gl-ES", "*", spBuiltinFormats_gl_ES }, // Galizian, Spain
+ { "gu-IN", "*", spBuiltinFormats_gu_IN }, // Gujarati, India
+ { "he-IL", "*", spBuiltinFormats_he_IL }, // Hebrew, Israel
+ { "hi-IN", "*", spBuiltinFormats_hi_IN }, // Hindi, India
+ { "hr-BA", "*", spBuiltinFormats_hr_BA }, // Croatian, Bosnia and Herzegowina
+ { "hr-HR", "*", spBuiltinFormats_hr_HR }, // Croatian, Croatia
+ { "hu-HU", "*", spBuiltinFormats_hu_HU }, // Hungarian, Hungary
+ { "hy-AM", "*", spBuiltinFormats_hy_AM }, // Armenian, Armenia
+ { "id-ID", "*", spBuiltinFormats_id_ID }, // Indonesian, Indonesia
+ { "is-IS", "*", spBuiltinFormats_is_IS }, // Icelandic, Iceland
+ { "it-CH", "*", spBuiltinFormats_it_CH }, // Italian, Switzerland
+ { "it-IT", "*", spBuiltinFormats_it_IT }, // Italian, Italy
+ { "ka-GE", "*", spBuiltinFormats_ka_GE }, // Georgian, Georgia
+ { "kk-KZ", "*", spBuiltinFormats_kk_KZ }, // Kazakh, Kazakhstan
+ { "kn-IN", "*", spBuiltinFormats_kn_IN }, // Kannada, India
+ { "kok-IN", "*", spBuiltinFormats_hi_IN }, // Konkani, India
+ { "ky-KG", "*", spBuiltinFormats_ky_KG }, // Kyrgyz, Kyrgyzstan
+ { "lt-LT", "*", spBuiltinFormats_lt_LT }, // Lithuanian, Lithuania
+ { "lv-LV", "*", spBuiltinFormats_lv_LV }, // Latvian, Latvia
+ { "mi-NZ", "*", spBuiltinFormats_en_NZ }, // Maori, New Zealand
+ { "ml-IN", "*", spBuiltinFormats_ml_IN }, // Malayalam, India
+ { "mn-MN", "*", spBuiltinFormats_mn_MN }, // Mongolian, Mongolia
+ { "mr-IN", "*", spBuiltinFormats_hi_IN }, // Marathi, India
+ { "ms-BN", "*", spBuiltinFormats_ms_BN }, // Malay, Brunei Darussalam
+ { "ms-MY", "*", spBuiltinFormats_ms_MY }, // Malay, Malaysia
+ { "mt-MT", "*", spBuiltinFormats_mt_MT }, // Maltese, Malta
+ { "nb-NO", "*", spBuiltinFormats_no_NO }, // Norwegian Bokmal, Norway
+ { "nl-BE", "*", spBuiltinFormats_nl_BE }, // Dutch, Belgium
+ { "nl-NL", "*", spBuiltinFormats_nl_NL }, // Dutch, Netherlands
+ { "nn-NO", "*", spBuiltinFormats_no_NO }, // Norwegian Nynorsk, Norway
+ { "nso-ZA", "*", spBuiltinFormats_en_ZA }, // Northern Sotho, South Africa
+ { "pa-IN", "*", spBuiltinFormats_pa_IN }, // Punjabi, India
+ { "pl-PL", "*", spBuiltinFormats_pl_PL }, // Polish, Poland
+ { "pt-BR", "*", spBuiltinFormats_pt_BR }, // Portugese, Brazil
+ { "pt-PT", "*", spBuiltinFormats_pt_PT }, // Portugese, Portugal
+ { "qu-BO", "*", spBuiltinFormats_es_BO }, // Quechua, Bolivia
+ { "qu-EC", "*", spBuiltinFormats_es_EC }, // Quechua, Ecuador
+ { "qu-PE", "*", spBuiltinFormats_es_PE }, // Quechua, Peru
+ { "ro-RO", "*", spBuiltinFormats_ro_RO }, // Romanian, Romania
+ { "ru-RU", "*", spBuiltinFormats_ru_RU }, // Russian, Russian Federation
+ { "sa-IN", "*", spBuiltinFormats_hi_IN }, // Sanskrit, India
+ { "se-FI", "*", spBuiltinFormats_fi_FI }, // Sami, Finland
+ { "se-NO", "*", spBuiltinFormats_no_NO }, // Sami, Norway
+ { "se-SE", "*", spBuiltinFormats_sv_SE }, // Sami, Sweden
+ { "sk-SK", "*", spBuiltinFormats_sk_SK }, // Slovak, Slovakia
+ { "sl-SI", "*", spBuiltinFormats_sl_SI }, // Slovenian, Slovenia
+ { "sv-FI", "*", spBuiltinFormats_sv_FI }, // Swedish, Finland
+ { "sv-SE", "*", spBuiltinFormats_sv_SE }, // Swedish, Sweden
+ { "sw-TZ", "*", spBuiltinFormats_sw_TZ }, // Swahili, Tanzania
+ { "syr-SY", "*", spBuiltinFormats_ar_SY }, // Syriac, Syria
+ { "syr-TR", "*", spBuiltinFormats_tr_TR }, // Syriac, Turkey
+ { "ta-IN", "*", spBuiltinFormats_ta_IN }, // Tamil, India
+ { "te-IN", "*", spBuiltinFormats_te_IN }, // Telugu, India
+ { "th-TH", "*", spBuiltinFormats_th_TH }, // Thai, Thailand
+ { "tn-ZA", "*", spBuiltinFormats_en_ZA }, // Tswana, South Africa
+ { "tr-TR", "*", spBuiltinFormats_tr_TR }, // Turkish, Turkey
+ { "tt-RU", "*", spBuiltinFormats_tt_RU }, // Tatar, Russian Federation
+ { "uk-UA", "*", spBuiltinFormats_uk_UA }, // Ukrainian, Ukraine
+ { "ur-PK", "*", spBuiltinFormats_ur_PK }, // Urdu, Pakistan
+ { "vi-VN", "*", spBuiltinFormats_vi_VN }, // Vietnamese, Viet Nam
+ { "xh-ZA", "*", spBuiltinFormats_en_ZA }, // Xhosa, South Africa
+ { "zu-ZA", "*", spBuiltinFormats_en_ZA }, // Zulu, South Africa
+
+ { "*CJK", "*", spBuiltinFormats_CJK }, // CJK base table
+ { "ja-JP", "*CJK", spBuiltinFormats_ja_JP }, // Japanese, Japan
+ { "ko-KR", "*CJK", spBuiltinFormats_ko_KR }, // Korean, South Korea
+ { "zh-CN", "*CJK", spBuiltinFormats_zh_CN }, // Chinese, China
+ { "zh-HK", "*CJK", spBuiltinFormats_zh_HK }, // Chinese, Hong Kong
+ { "zh-MO", "*CJK", spBuiltinFormats_zh_MO }, // Chinese, Macau
+ { "zh-SG", "*CJK", spBuiltinFormats_zh_SG }, // Chinese, Singapore
+ { "zh-TW", "*CJK", spBuiltinFormats_zh_TW } // Chinese, Taiwan
+};
+
+// ============================================================================
+
+/** Functor for converting an XML number format to an API number format index. */
+class NumberFormatFunctor
+{
+public:
+ explicit NumberFormatFunctor( const WorkbookHelper& rHelper );
+
+ inline bool is() const { return mxNumFmts.is(); }
+
+ inline void operator()( NumberFormat& rNumFmt ) const
+ { rNumFmt.finalizeImport( mxNumFmts, maEnUsLocale ); }
+
+private:
+ Reference< XNumberFormats > mxNumFmts;
+ Locale maEnUsLocale;
+};
+
+// ----------------------------------------------------------------------------
+
+NumberFormatFunctor::NumberFormatFunctor( const WorkbookHelper& rHelper ) :
+ maEnUsLocale( CREATE_OUSTRING( "en" ), CREATE_OUSTRING( "US" ), OUString() )
+{
+ try
+ {
+ Reference< XNumberFormatsSupplier > xNumFmtsSupp( rHelper.getDocument(), UNO_QUERY_THROW );
+ mxNumFmts = xNumFmtsSupp->getNumberFormats();
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( mxNumFmts.is(), "NumberFormatFunctor::NumberFormatFunctor - cannot get number formats" );
+}
+
+} // namespace
+
+// ============================================================================
+
+OoxNumFmtData::OoxNumFmtData() :
+ mnPredefId( -1 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+sal_Int32 lclCreatePredefinedFormat( const Reference< XNumberFormats >& rxNumFmts,
+ sal_Int16 nPredefId, const Locale& rToLocale )
+{
+ sal_Int32 nIndex = 0;
+ try
+ {
+ Reference< XNumberFormatTypes > xNumFmtTypes( rxNumFmts, UNO_QUERY_THROW );
+ nIndex = (nPredefId >= 0) ?
+ xNumFmtTypes->getFormatIndex( nPredefId, rToLocale ) :
+ xNumFmtTypes->getStandardIndex( rToLocale );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false,
+ OStringBuffer( "lclCreatePredefinedFormat - cannot create predefined number format " ).
+ append( OString::valueOf( static_cast< sal_Int32 >( nPredefId ) ) ).getStr() );
+ }
+ return nIndex;
+}
+
+sal_Int32 lclCreateFormat( const Reference< XNumberFormats >& rxNumFmts,
+ const OUString& rFmtCode, const Locale& rToLocale, const Locale& rFromLocale )
+{
+ sal_Int32 nIndex = 0;
+ try
+ {
+ nIndex = rxNumFmts->addNewConverted( rFmtCode, rFromLocale, rToLocale );
+ }
+ catch( Exception& )
+ {
+ // BIFF2-BIFF4 stores standard format explicitly in stream
+ static const OUString saGeneral = CREATE_OUSTRING( "general" );
+ if( rFmtCode.equalsIgnoreAsciiCase( saGeneral ) )
+ {
+ nIndex = lclCreatePredefinedFormat( rxNumFmts, 0, rToLocale );
+ }
+ else
+ {
+ OSL_ENSURE( false,
+ OStringBuffer( "lclCreateFormat - cannot create number format '" ).
+ append( OUStringToOString( rFmtCode, osl_getThreadTextEncoding() ) ).
+ append( '\'' ).getStr() );
+ }
+ }
+ return nIndex;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+NumberFormat::NumberFormat( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void NumberFormat::setFormatCode( const OUString& rFmtCode )
+{
+ maOoxData.maFmtCode = rFmtCode;
+}
+
+void NumberFormat::setFormatCode( const Locale& rLocale, const sal_Char* pcFmtCode )
+{
+ maOoxData.maLocale = rLocale;
+ maOoxData.maFmtCode = OStringToOUString( OString( pcFmtCode ), RTL_TEXTENCODING_UTF8 );
+ maOoxData.mnPredefId = -1;
+}
+
+void NumberFormat::setPredefinedId( const Locale& rLocale, sal_Int16 nPredefId )
+{
+ maOoxData.maLocale = rLocale;
+ maOoxData.maFmtCode = OUString();
+ maOoxData.mnPredefId = nPredefId;
+}
+
+void NumberFormat::finalizeImport( const Reference< XNumberFormats >& rxNumFmts, const Locale& rFromLocale )
+{
+ if( rxNumFmts.is() && (maOoxData.maFmtCode.getLength() > 0) )
+ maApiData.mnIndex = lclCreateFormat( rxNumFmts, maOoxData.maFmtCode, maOoxData.maLocale, rFromLocale );
+ else
+ maApiData.mnIndex = lclCreatePredefinedFormat( rxNumFmts, maOoxData.mnPredefId, maOoxData.maLocale );
+}
+
+void NumberFormat::writeToPropertySet( PropertySet& rPropSet ) const
+{
+ getStylesPropertyHelper().writeNumFmtProperties( rPropSet, maApiData );
+}
+
+// ============================================================================
+
+NumberFormatsBuffer::NumberFormatsBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mnNextBiffIndex( 0 )
+{
+ // get the current locale
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
+ Reference< XMultiServiceFactory > xConfigProv(
+ xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.configuration.ConfigurationProvider" ) ),
+ UNO_QUERY_THROW );
+
+ // try user-defined locale setting
+ Sequence< Any > aArgs( 1 );
+ aArgs[ 0 ] <<= CREATE_OUSTRING( "org.openoffice.Setup/L10N/" );
+ Reference< XNameAccess > xConfigNA( xConfigProv->createInstanceWithArguments(
+ CREATE_OUSTRING( "com.sun.star.configuration.ConfigurationAccess" ), aArgs ), UNO_QUERY_THROW );
+ xConfigNA->getByName( CREATE_OUSTRING( "ooSetupSystemLocale" ) ) >>= maLocaleStr;
+
+ // if set to "use system", get locale from system
+ if( maLocaleStr.getLength() == 0 )
+ {
+ aArgs[ 0 ] <<= CREATE_OUSTRING( "org.openoffice.System/L10N/" );
+ xConfigNA.set( xConfigProv->createInstanceWithArguments(
+ CREATE_OUSTRING( "com.sun.star.configuration.ConfigurationAccess" ), aArgs ), UNO_QUERY_THROW );
+ xConfigNA->getByName( CREATE_OUSTRING( "Locale" ) ) >>= maLocaleStr;
+ }
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "NumberFormatsBuffer::NumberFormatsBuffer - cannot get system locale" );
+ }
+
+ // create built-in formats for current locale
+ insertBuiltinFormats();
+}
+
+NumberFormatRef NumberFormatsBuffer::createNumFmt( sal_Int32 nNumFmtId, const OUString& rFmtCode )
+{
+ NumberFormatRef xNumFmt;
+ if( nNumFmtId >= 0 )
+ {
+ xNumFmt.reset( new NumberFormat( *this ) );
+ maNumFmts[ nNumFmtId ] = xNumFmt;
+ xNumFmt->setFormatCode( rFmtCode );
+ }
+ return xNumFmt;
+}
+
+NumberFormatRef NumberFormatsBuffer::importNumFmt( const AttributeList& rAttribs )
+{
+ sal_Int32 nNumFmtId = rAttribs.getInteger( XML_numFmtId, -1 );
+ OUString aFmtCode = rAttribs.getString( XML_formatCode );
+ return createNumFmt( nNumFmtId, aFmtCode );
+}
+
+void NumberFormatsBuffer::importNumFmt( RecordInputStream& rStrm )
+{
+ sal_Int32 nNumFmtId = rStrm.readuInt16();
+ OUString aFmtCode = rStrm.readString();
+ createNumFmt( nNumFmtId, aFmtCode );
+}
+
+void NumberFormatsBuffer::importFormat( BiffInputStream& rStrm )
+{
+ OUString aFmtCode;
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ aFmtCode = rStrm.readByteString( false, getTextEncoding() );
+ break;
+ case BIFF4:
+ // in BIFF4 the index field exists, but is undefined
+ aFmtCode = rStrm.skip( 2 ).readByteString( false, getTextEncoding() );
+ break;
+ case BIFF5:
+ mnNextBiffIndex = rStrm.readuInt16();
+ aFmtCode = rStrm.readByteString( false, getTextEncoding() );
+ break;
+ case BIFF8:
+ mnNextBiffIndex = rStrm.readuInt16();
+ aFmtCode = rStrm.readUniString();
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+
+ createNumFmt( mnNextBiffIndex, aFmtCode );
+ ++mnNextBiffIndex;
+}
+
+void NumberFormatsBuffer::finalizeImport()
+{
+ maNumFmts.forEach( NumberFormatFunctor( *this ) );
+}
+
+void NumberFormatsBuffer::writeToPropertySet( PropertySet& rPropSet, sal_Int32 nNumFmtId ) const
+{
+ if( const NumberFormat* pNumFmt = maNumFmts.get( nNumFmtId ).get() )
+ pNumFmt->writeToPropertySet( rPropSet );
+}
+
+void NumberFormatsBuffer::insertBuiltinFormats()
+{
+ // build a map containing pointers to all tables
+ typedef ::std::map< OUString, const BuiltinFormatTable* > BuiltinMap;
+ BuiltinMap aBuiltinMap;
+ for( const BuiltinFormatTable* pTable = spBuiltinFormatTables;
+ pTable != STATIC_ARRAY_END( spBuiltinFormatTables ); ++pTable )
+ aBuiltinMap[ OUString::createFromAscii( pTable->mpcLocale ) ] = pTable;
+
+ // convert locale string to locale struct
+ Locale aSysLocale;
+ sal_Int32 nDashPos = maLocaleStr.indexOf( '-' );
+ if( nDashPos < 0 ) nDashPos = maLocaleStr.getLength();
+ aSysLocale.Language = maLocaleStr.copy( 0, nDashPos );
+ if( nDashPos + 1 < maLocaleStr.getLength() )
+ aSysLocale.Country = maLocaleStr.copy( nDashPos + 1 );
+
+ // build a list of table pointers for the current locale, with all parent tables
+ typedef ::std::vector< const BuiltinFormatTable* > BuiltinVec;
+ BuiltinVec aBuiltinVec;
+ BuiltinMap::const_iterator aMIt = aBuiltinMap.find( maLocaleStr ), aMEnd = aBuiltinMap.end();
+ OSL_ENSURE( aMIt != aMEnd,
+ OStringBuffer( "NumberFormatsBuffer::insertBuiltinFormats - locale '" ).
+ append( OUStringToOString( maLocaleStr, RTL_TEXTENCODING_ASCII_US ) ).
+ append( "' not supported (#i29949#)" ).getStr() );
+ // start with default table, if no table has been found
+ if( aMIt == aMEnd )
+ aMIt = aBuiltinMap.find( CREATE_OUSTRING( "*" ) );
+ OSL_ENSURE( aMIt != aMEnd, "NumberFormatsBuffer::insertBuiltinFormats - default map not found" );
+ // insert all tables into the vector
+ for( ; aMIt != aMEnd; aMIt = aBuiltinMap.find( OUString::createFromAscii( aMIt->second->mpcParent ) ) )
+ aBuiltinVec.push_back( aMIt->second );
+
+ // insert the default formats in the format map (in reverse order from default table to system locale)
+ typedef ::std::map< sal_Int32, sal_Int32 > ReuseMap;
+ ReuseMap aReuseMap;
+ for( BuiltinVec::reverse_iterator aVIt = aBuiltinVec.rbegin(), aVEnd = aBuiltinVec.rend(); aVIt != aVEnd; ++aVIt )
+ {
+ // do not put the current system locale for default table
+ Locale aLocale;
+ if( (*aVIt)->mpcLocale[ 0 ] != '\0' )
+ aLocale = aSysLocale;
+ for( const BuiltinFormat* pBuiltin = (*aVIt)->mpFormats; pBuiltin && (pBuiltin->mnNumFmtId >= 0); ++pBuiltin )
+ {
+ NumberFormatRef& rxNumFmt = maNumFmts[ pBuiltin->mnNumFmtId ];
+ rxNumFmt.reset( new NumberFormat( *this ) );
+
+ bool bReuse = false;
+ if( pBuiltin->mpcFmtCode )
+ rxNumFmt->setFormatCode( aLocale, pBuiltin->mpcFmtCode );
+ else if( pBuiltin->mnPredefId >= 0 )
+ rxNumFmt->setPredefinedId( aLocale, pBuiltin->mnPredefId );
+ else
+ bReuse = pBuiltin->mnReuseId >= 0;
+
+ if( bReuse )
+ aReuseMap[ pBuiltin->mnNumFmtId ] = pBuiltin->mnReuseId;
+ else
+ aReuseMap.erase( pBuiltin->mnNumFmtId );
+ }
+ }
+
+ // copy reused number formats
+ for( ReuseMap::const_iterator aRIt = aReuseMap.begin(), aREnd = aReuseMap.end(); aRIt != aREnd; ++aRIt )
+ maNumFmts[ aRIt->first ] = maNumFmts[ aRIt->second ];
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/pagesettings.cxx b/oox/source/xls/pagesettings.cxx
new file mode 100644
index 000000000000..6cb32f961352
--- /dev/null
+++ b/oox/source/xls/pagesettings.cxx
@@ -0,0 +1,641 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: pagesettings.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:08 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/pagesettings.hxx"
+#include <algorithm>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/sheet/XHeaderFooterContent.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/ooxtokens.hxx"
+#include "oox/xls/unitconverter.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::sheet::XHeaderFooterContent;
+using ::com::sun::star::style::XStyle;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const double OOX_MARGIN_DEFAULT_LR = 0.748; /// Left/right default margin in inches.
+const double OOX_MARGIN_DEFAULT_TB = 0.984; /// Top/bottom default margin in inches.
+const double OOX_MARGIN_DEFAULT_HF = 0.512; /// Header/footer default margin in inches.
+
+const sal_uInt16 OOBIN_HEADERFOOTER_DIFFEVEN = 0x0001;
+const sal_uInt16 OOBIN_HEADERFOOTER_DIFFFIRST = 0x0002;
+const sal_uInt16 OOBIN_HEADERFOOTER_SCALEDOC = 0x0004;
+const sal_uInt16 OOBIN_HEADERFOOTER_ALIGNMARGIN = 0x0008;
+
+const sal_uInt16 OOBIN_PAGESETUP_INROWS = 0x0001;
+const sal_uInt16 OOBIN_PAGESETUP_LANDSCAPE = 0x0002;
+const sal_uInt16 OOBIN_PAGESETUP_INVALID = 0x0004;
+const sal_uInt16 OOBIN_PAGESETUP_BLACKWHITE = 0x0008;
+const sal_uInt16 OOBIN_PAGESETUP_DRAFTQUALITY = 0x0010;
+const sal_uInt16 OOBIN_PAGESETUP_PRINTNOTES = 0x0020;
+const sal_uInt16 OOBIN_PAGESETUP_DEFAULTORIENT = 0x0040;
+const sal_uInt16 OOBIN_PAGESETUP_USEFIRSTPAGE = 0x0080;
+const sal_uInt16 OOBIN_PAGESETUP_NOTES_END = 0x0100; // different to BIFF flag
+
+const sal_uInt16 OOBIN_PRINTOPT_HORCENTER = 0x0001;
+const sal_uInt16 OOBIN_PRINTOPT_VERCENTER = 0x0002;
+const sal_uInt16 OOBIN_PRINTOPT_PRINTHEADING = 0x0004;
+const sal_uInt16 OOBIN_PRINTOPT_PRINTGRID = 0x0008;
+
+const sal_uInt16 BIFF_PAGESETUP_INROWS = 0x0001;
+const sal_uInt16 BIFF_PAGESETUP_PORTRAIT = 0x0002;
+const sal_uInt16 BIFF_PAGESETUP_INVALID = 0x0004;
+const sal_uInt16 BIFF_PAGESETUP_BLACKWHITE = 0x0008;
+const sal_uInt16 BIFF_PAGESETUP_DRAFTQUALITY = 0x0010;
+const sal_uInt16 BIFF_PAGESETUP_PRINTNOTES = 0x0020;
+const sal_uInt16 BIFF_PAGESETUP_DEFAULTORIENT = 0x0040;
+const sal_uInt16 BIFF_PAGESETUP_USEFIRSTPAGE = 0x0080;
+const sal_uInt16 BIFF_PAGESETUP_NOTES_END = 0x0200;
+
+} // namespace
+
+// ============================================================================
+
+OoxPageData::OoxPageData() :
+ mfLeftMargin( OOX_MARGIN_DEFAULT_LR ),
+ mfRightMargin( OOX_MARGIN_DEFAULT_LR ),
+ mfTopMargin( OOX_MARGIN_DEFAULT_TB ),
+ mfBottomMargin( OOX_MARGIN_DEFAULT_TB ),
+ mfHeaderMargin( OOX_MARGIN_DEFAULT_HF ),
+ mfFooterMargin( OOX_MARGIN_DEFAULT_HF ),
+ mnPaperSize( 1 ),
+ mnCopies( 1 ),
+ mnScale( 100 ),
+ mnFirstPage( 1 ),
+ mnFitToWidth( 1 ),
+ mnFitToHeight( 1 ),
+ mnHorPrintRes( 600 ),
+ mnVerPrintRes( 600 ),
+ mnOrientation( XML_default ),
+ mnPageOrder( XML_downThenOver ),
+ mnCellComments( XML_none ),
+ mnPrintErrors( XML_displayed ),
+ mbUseEvenHF( false ),
+ mbUseFirstHF( false ),
+ mbValidSettings( true ),
+ mbUseFirstPage( false ),
+ mbBlackWhite( false ),
+ mbDraftQuality( false ),
+ mbFitToPages( false ),
+ mbHorCenter( false ),
+ mbVerCenter( false ),
+ mbPrintGrid( false ),
+ mbPrintHeadings( false )
+{
+}
+
+void OoxPageData::setBinPrintErrors( sal_uInt8 nPrintErrors )
+{
+ static const sal_Int32 spnErrorIds[] = { XML_displayed, XML_none, XML_dash, XML_NA };
+ mnPrintErrors = STATIC_ARRAY_SELECT( spnErrorIds, nPrintErrors, XML_none );
+}
+
+// ============================================================================
+
+PageSettings::PageSettings( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+void PageSettings::importPageMargins( const AttributeList& rAttribs )
+{
+ maOoxData.mfLeftMargin = rAttribs.getDouble( XML_left, OOX_MARGIN_DEFAULT_LR );
+ maOoxData.mfRightMargin = rAttribs.getDouble( XML_right, OOX_MARGIN_DEFAULT_LR );
+ maOoxData.mfTopMargin = rAttribs.getDouble( XML_top, OOX_MARGIN_DEFAULT_TB );
+ maOoxData.mfBottomMargin = rAttribs.getDouble( XML_bottom, OOX_MARGIN_DEFAULT_TB );
+ maOoxData.mfHeaderMargin = rAttribs.getDouble( XML_header, OOX_MARGIN_DEFAULT_HF );
+ maOoxData.mfFooterMargin = rAttribs.getDouble( XML_footer, OOX_MARGIN_DEFAULT_HF );
+}
+
+void PageSettings::importPageSetup( const AttributeList& rAttribs )
+{
+ maOoxData.maRelId = rAttribs.getString( R_TOKEN( id ) );
+ maOoxData.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 );
+ maOoxData.mnCopies = rAttribs.getInteger( XML_copies, 1 );
+ maOoxData.mnScale = rAttribs.getInteger( XML_scale, 100 );
+ maOoxData.mnFirstPage = rAttribs.getInteger( XML_firstPageNumber, 1 );
+ maOoxData.mnFitToWidth = rAttribs.getInteger( XML_fitToWidth, 1 );
+ maOoxData.mnFitToHeight = rAttribs.getInteger( XML_fitToHeight, 1 );
+ maOoxData.mnHorPrintRes = rAttribs.getInteger( XML_horizontalDpi, 600 );
+ maOoxData.mnVerPrintRes = rAttribs.getInteger( XML_verticalDpi, 600 );
+ maOoxData.mnOrientation = rAttribs.getToken( XML_orientation, XML_default );
+ maOoxData.mnPageOrder = rAttribs.getToken( XML_pageOrder, XML_downThenOver );
+ maOoxData.mnCellComments = rAttribs.getToken( XML_cellComments, XML_none );
+ maOoxData.mnPrintErrors = rAttribs.getToken( XML_errors, XML_displayed );
+ maOoxData.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, true );
+ maOoxData.mbUseFirstPage = rAttribs.getBool( XML_useFirstPageNumber, false );
+ maOoxData.mbBlackWhite = rAttribs.getBool( XML_blackAndWhite, false );
+ maOoxData.mbDraftQuality = rAttribs.getBool( XML_draft, false );
+}
+
+void PageSettings::importPrintOptions( const AttributeList& rAttribs )
+{
+ maOoxData.mbHorCenter = rAttribs.getBool( XML_horizontalCentered, false );
+ maOoxData.mbVerCenter = rAttribs.getBool( XML_verticalCentered, false );
+ maOoxData.mbPrintGrid = rAttribs.getBool( XML_gridLines, false );
+ maOoxData.mbPrintHeadings = rAttribs.getBool( XML_headings, false );
+}
+
+void PageSettings::importHeaderFooter( const AttributeList& rAttribs )
+{
+ maOoxData.mbUseEvenHF = rAttribs.getBool( XML_differentOddEven, false );
+ maOoxData.mbUseFirstHF = rAttribs.getBool( XML_differentFirst, false );
+}
+
+void PageSettings::importHeaderFooterCharacters( const OUString& rChars, sal_Int32 nElement )
+{
+ switch( nElement )
+ {
+ case XLS_TOKEN( oddHeader ): maOoxData.maOddHeader += rChars; break;
+ case XLS_TOKEN( oddFooter ): maOoxData.maOddFooter += rChars; break;
+ case XLS_TOKEN( evenHeader ): maOoxData.maEvenHeader += rChars; break;
+ case XLS_TOKEN( evenFooter ): maOoxData.maEvenFooter += rChars; break;
+ case XLS_TOKEN( firstHeader ): maOoxData.maFirstHeader += rChars; break;
+ case XLS_TOKEN( firstFooter ): maOoxData.maFirstFooter += rChars; break;
+ }
+}
+
+void PageSettings::importPageMargins( RecordInputStream& rStrm )
+{
+ rStrm >> maOoxData.mfLeftMargin >> maOoxData.mfRightMargin
+ >> maOoxData.mfTopMargin >> maOoxData.mfBottomMargin
+ >> maOoxData.mfHeaderMargin >> maOoxData.mfFooterMargin;
+}
+
+void PageSettings::importPageSetup( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> maOoxData.mnPaperSize >> maOoxData.mnScale
+ >> maOoxData.mnHorPrintRes >> maOoxData.mnVerPrintRes
+ >> maOoxData.mnCopies >> maOoxData.mnFirstPage
+ >> maOoxData.mnFitToWidth >> maOoxData.mnFitToHeight
+ >> nFlags >> maOoxData.maRelId;
+ maOoxData.setBinPrintErrors( extractValue< sal_uInt8 >( nFlags, 9, 2 ) );
+ maOoxData.mnOrientation = getFlagValue( nFlags, OOBIN_PAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, OOBIN_PAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
+ maOoxData.mnPageOrder = getFlagValue( nFlags, OOBIN_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
+ maOoxData.mnCellComments = getFlagValue( nFlags, OOBIN_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, OOBIN_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
+ maOoxData.mbValidSettings = !getFlag( nFlags, OOBIN_PAGESETUP_INVALID );
+ maOoxData.mbUseFirstPage = getFlag( nFlags, OOBIN_PAGESETUP_USEFIRSTPAGE );
+ maOoxData.mbBlackWhite = getFlag( nFlags, OOBIN_PAGESETUP_BLACKWHITE );
+ maOoxData.mbDraftQuality = getFlag( nFlags, OOBIN_PAGESETUP_DRAFTQUALITY );
+}
+
+void PageSettings::importPrintOptions( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ maOoxData.mbHorCenter = getFlag( nFlags, OOBIN_PRINTOPT_HORCENTER );
+ maOoxData.mbVerCenter = getFlag( nFlags, OOBIN_PRINTOPT_VERCENTER );
+ maOoxData.mbPrintGrid = getFlag( nFlags, OOBIN_PRINTOPT_PRINTGRID );
+ maOoxData.mbPrintHeadings = getFlag( nFlags, OOBIN_PRINTOPT_PRINTHEADING );
+}
+
+void PageSettings::importHeaderFooter( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags
+ >> maOoxData.maOddHeader >> maOoxData.maOddFooter
+ >> maOoxData.maEvenHeader >> maOoxData.maEvenFooter
+ >> maOoxData.maFirstHeader >> maOoxData.maFirstFooter;
+ maOoxData.mbUseEvenHF = getFlag( nFlags, OOBIN_HEADERFOOTER_DIFFEVEN );
+ maOoxData.mbUseFirstHF = getFlag( nFlags, OOBIN_HEADERFOOTER_DIFFFIRST );
+}
+
+void PageSettings::importLeftMargin( BiffInputStream& rStrm )
+{
+ rStrm >> maOoxData.mfLeftMargin;
+}
+
+void PageSettings::importRightMargin( BiffInputStream& rStrm )
+{
+ rStrm >> maOoxData.mfRightMargin;
+}
+
+void PageSettings::importTopMargin( BiffInputStream& rStrm )
+{
+ rStrm >> maOoxData.mfTopMargin;
+}
+
+void PageSettings::importBottomMargin( BiffInputStream& rStrm )
+{
+ rStrm >> maOoxData.mfBottomMargin;
+}
+
+void PageSettings::importPageSetup( BiffInputStream& rStrm )
+{
+ sal_uInt16 nPaperSize, nScale, nFirstPage, nFitToWidth, nFitToHeight, nFlags;
+ rStrm >> nPaperSize >> nScale >> nFirstPage >> nFitToWidth >> nFitToHeight >> nFlags;
+
+ maOoxData.mnPaperSize = nPaperSize; // equal in BIFF and OOX
+ maOoxData.mnScale = nScale;
+ maOoxData.mnFirstPage = nFirstPage;
+ maOoxData.mnFitToWidth = nFitToWidth;
+ maOoxData.mnFitToHeight = nFitToHeight;
+ maOoxData.mnOrientation = getFlagValue( nFlags, BIFF_PAGESETUP_PORTRAIT, XML_portrait, XML_landscape );
+ maOoxData.mnPageOrder = getFlagValue( nFlags, BIFF_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
+ maOoxData.mbValidSettings = !getFlag( nFlags, BIFF_PAGESETUP_INVALID );
+ maOoxData.mbUseFirstPage = true;
+ maOoxData.mbBlackWhite = getFlag( nFlags, BIFF_PAGESETUP_BLACKWHITE );
+
+ if( getBiff() >= BIFF5 )
+ {
+ sal_uInt16 nHorPrintRes, nVerPrintRes, nCopies;
+ rStrm >> nHorPrintRes >> nVerPrintRes >> maOoxData.mfHeaderMargin >> maOoxData.mfFooterMargin >> nCopies;
+
+ maOoxData.mnCopies = nCopies;
+ maOoxData.mnOrientation = getFlagValue( nFlags, BIFF_PAGESETUP_DEFAULTORIENT, XML_default, maOoxData.mnOrientation );
+ maOoxData.mnHorPrintRes = nHorPrintRes;
+ maOoxData.mnVerPrintRes = nVerPrintRes;
+ maOoxData.mnCellComments = getFlagValue( nFlags, BIFF_PAGESETUP_PRINTNOTES, XML_asDisplayed, XML_none );
+ maOoxData.mbUseFirstPage = getFlag( nFlags, BIFF_PAGESETUP_USEFIRSTPAGE );
+ maOoxData.mbDraftQuality = getFlag( nFlags, BIFF_PAGESETUP_DRAFTQUALITY );
+
+ if( getBiff() == BIFF8 )
+ {
+ maOoxData.setBinPrintErrors( extractValue< sal_uInt8 >( nFlags, 10, 2 ) );
+ maOoxData.mnCellComments = getFlagValue( nFlags, BIFF_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, BIFF_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
+ }
+ }
+}
+
+void PageSettings::importHorCenter( BiffInputStream& rStrm )
+{
+ maOoxData.mbHorCenter = rStrm.readuInt16() != 0;
+}
+
+void PageSettings::importVerCenter( BiffInputStream& rStrm )
+{
+ maOoxData.mbVerCenter = rStrm.readuInt16() != 0;
+}
+
+void PageSettings::importPrintHeaders( BiffInputStream& rStrm )
+{
+ maOoxData.mbPrintHeadings = rStrm.readuInt16() != 0;
+}
+
+void PageSettings::importPrintGridLines( BiffInputStream& rStrm )
+{
+ maOoxData.mbPrintGrid = rStrm.readuInt16() != 0;
+}
+
+void PageSettings::importHeader( BiffInputStream& rStrm )
+{
+ if( rStrm.getRecLeft() > 0 )
+ maOoxData.maOddHeader = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteString( false, getTextEncoding() );
+ else
+ maOoxData.maOddHeader = OUString();
+}
+
+void PageSettings::importFooter( BiffInputStream& rStrm )
+{
+ if( rStrm.getRecLeft() > 0 )
+ maOoxData.maOddFooter = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteString( false, getTextEncoding() );
+ else
+ maOoxData.maOddFooter = OUString();
+}
+
+void PageSettings::setFitToPagesMode( bool bFitToPages )
+{
+ maOoxData.mbFitToPages = bFitToPages;
+}
+
+void PageSettings::finalizeImport()
+{
+ OUStringBuffer aStyleNameBuffer( CREATE_OUSTRING( "PageStyle_" ) );
+ Reference< XNamed > xSheetName( getXSpreadsheet(), UNO_QUERY );
+ if( xSheetName.is() )
+ aStyleNameBuffer.append( xSheetName->getName() );
+ else
+ aStyleNameBuffer.append( static_cast< sal_Int32 >( getSheetIndex() + 1 ) );
+ OUString aStyleName = aStyleNameBuffer.makeStringAndClear();
+
+ Reference< XStyle > xStyle = createStyleObject( aStyleName, true );
+ PropertySet aStyleProps( xStyle );
+ getPageSettingsPropertyHelper().writePageSettingsProperties( aStyleProps, maOoxData, getSheetType() );
+
+ PropertySet aSheetProps( getXSpreadsheet() );
+ aSheetProps.setProperty( CREATE_OUSTRING( "PageStyle" ), aStyleName );
+}
+
+// ============================================================================
+
+namespace {
+
+/** Property names for page style settings. */
+const sal_Char* const sppcPageNames[] =
+{
+ "IsLandscape",
+ "FirstPageNumber",
+ "PrintDownFirst",
+ "PrintAnnotations",
+ "CenterHorizontally",
+ "CenterVertically",
+ "PrintGrid",
+ "PrintHeaders",
+ "LeftMargin",
+ "RightMargin",
+ "TopMargin",
+ "BottomMargin",
+ "HeaderIsOn",
+ "HeaderIsShared",
+ "HeaderIsDynamicHeight",
+ "HeaderHeight",
+ "HeaderBodyDistance",
+ "FooterIsOn",
+ "FooterIsShared",
+ "FooterIsDynamicHeight",
+ "FooterHeight",
+ "FooterBodyDistance",
+ 0
+};
+
+/** Paper size in 1/100 millimeters. */
+struct ApiPaperSize
+{
+ sal_Int32 mnWidth;
+ sal_Int32 mnHeight;
+};
+
+#define IN2MM100( v ) static_cast< sal_Int32 >( (v) * 2540.0 + 0.5 )
+#define MM2MM100( v ) static_cast< sal_Int32 >( (v) * 100.0 + 0.5 )
+
+static const ApiPaperSize spPaperSizeTable[] =
+{
+ { 0, 0 }, // 0 - (undefined)
+ { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 1 - Letter paper
+ { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 2 - Letter small paper
+ { IN2MM100( 11 ), IN2MM100( 17 ) }, // 3 - Tabloid paper
+ { IN2MM100( 17 ), IN2MM100( 11 ) }, // 4 - Ledger paper
+ { IN2MM100( 8.5 ), IN2MM100( 14 ) }, // 5 - Legal paper
+ { IN2MM100( 5.5 ), IN2MM100( 8.5 ) }, // 6 - Statement paper
+ { IN2MM100( 7.25 ), IN2MM100( 10.5 ) }, // 7 - Executive paper
+ { MM2MM100( 297 ), MM2MM100( 420 ) }, // 8 - A3 paper
+ { MM2MM100( 210 ), MM2MM100( 297 ) }, // 9 - A4 paper
+ { MM2MM100( 210 ), MM2MM100( 297 ) }, // 10 - A4 small paper
+ { MM2MM100( 148 ), MM2MM100( 210 ) }, // 11 - A5 paper
+ { MM2MM100( 250 ), MM2MM100( 353 ) }, // 12 - B4 paper
+ { MM2MM100( 176 ), MM2MM100( 250 ) }, // 13 - B5 paper
+ { IN2MM100( 8.5 ), IN2MM100( 13 ) }, // 14 - Folio paper
+ { MM2MM100( 215 ), MM2MM100( 275 ) }, // 15 - Quarto paper
+ { IN2MM100( 10 ), IN2MM100( 14 ) }, // 16 - Standard paper
+ { IN2MM100( 11 ), IN2MM100( 17 ) }, // 17 - Standard paper
+ { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 18 - Note paper
+ { IN2MM100( 3.875 ), IN2MM100( 8.875 ) }, // 19 - #9 envelope
+ { IN2MM100( 4.125 ), IN2MM100( 9.5 ) }, // 20 - #10 envelope
+ { IN2MM100( 4.5 ), IN2MM100( 10.375 ) }, // 21 - #11 envelope
+ { IN2MM100( 4.75 ), IN2MM100( 11 ) }, // 22 - #12 envelope
+ { IN2MM100( 5 ), IN2MM100( 11.5 ) }, // 23 - #14 envelope
+ { IN2MM100( 17 ), IN2MM100( 22 ) }, // 24 - C paper
+ { IN2MM100( 22 ), IN2MM100( 34 ) }, // 25 - D paper
+ { IN2MM100( 34 ), IN2MM100( 44 ) }, // 26 - E paper
+ { MM2MM100( 110 ), MM2MM100( 220 ) }, // 27 - DL envelope
+ { MM2MM100( 162 ), MM2MM100( 229 ) }, // 28 - C5 envelope
+ { MM2MM100( 324 ), MM2MM100( 458 ) }, // 29 - C3 envelope
+ { MM2MM100( 229 ), MM2MM100( 324 ) }, // 30 - C4 envelope
+ { MM2MM100( 114 ), MM2MM100( 162 ) }, // 31 - C6 envelope
+ { MM2MM100( 114 ), MM2MM100( 229 ) }, // 32 - C65 envelope
+ { MM2MM100( 250 ), MM2MM100( 353 ) }, // 33 - B4 envelope
+ { MM2MM100( 176 ), MM2MM100( 250 ) }, // 34 - B5 envelope
+ { MM2MM100( 176 ), MM2MM100( 125 ) }, // 35 - B6 envelope
+ { MM2MM100( 110 ), MM2MM100( 230 ) }, // 36 - Italy envelope
+ { IN2MM100( 3.875 ), IN2MM100( 7.5 ) }, // 37 - Monarch envelope
+ { IN2MM100( 3.625 ), IN2MM100( 6.5 ) }, // 38 - 6 3/4 envelope
+ { IN2MM100( 14.875 ), IN2MM100( 11 ) }, // 39 - US standard fanfold
+ { IN2MM100( 8.5 ), IN2MM100( 12 ) }, // 40 - German standard fanfold
+ { IN2MM100( 8.5 ), IN2MM100( 13 ) }, // 41 - German legal fanfold
+ { MM2MM100( 250 ), MM2MM100( 353 ) }, // 42 - ISO B4
+ { MM2MM100( 200 ), MM2MM100( 148 ) }, // 43 - Japanese double postcard
+ { IN2MM100( 9 ), IN2MM100( 11 ) }, // 44 - Standard paper
+ { IN2MM100( 10 ), IN2MM100( 11 ) }, // 45 - Standard paper
+ { IN2MM100( 15 ), IN2MM100( 11 ) }, // 46 - Standard paper
+ { MM2MM100( 220 ), MM2MM100( 220 ) }, // 47 - Invite envelope
+ { 0, 0 }, // 48 - (undefined)
+ { 0, 0 }, // 49 - (undefined)
+ { IN2MM100( 9.275 ), IN2MM100( 12 ) }, // 50 - Letter extra paper
+ { IN2MM100( 9.275 ), IN2MM100( 15 ) }, // 51 - Legal extra paper
+ { IN2MM100( 11.69 ), IN2MM100( 18 ) }, // 52 - Tabloid extra paper
+ { MM2MM100( 236 ), MM2MM100( 322 ) }, // 53 - A4 extra paper
+ { IN2MM100( 8.275 ), IN2MM100( 11 ) }, // 54 - Letter transverse paper
+ { MM2MM100( 210 ), MM2MM100( 297 ) }, // 55 - A4 transverse paper
+ { IN2MM100( 9.275 ), IN2MM100( 12 ) }, // 56 - Letter extra transverse paper
+ { MM2MM100( 227 ), MM2MM100( 356 ) }, // 57 - SuperA/SuperA/A4 paper
+ { MM2MM100( 305 ), MM2MM100( 487 ) }, // 58 - SuperB/SuperB/A3 paper
+ { IN2MM100( 8.5 ), IN2MM100( 12.69 ) }, // 59 - Letter plus paper
+ { MM2MM100( 210 ), MM2MM100( 330 ) }, // 60 - A4 plus paper
+ { MM2MM100( 148 ), MM2MM100( 210 ) }, // 61 - A5 transverse paper
+ { MM2MM100( 182 ), MM2MM100( 257 ) }, // 62 - JIS B5 transverse paper
+ { MM2MM100( 322 ), MM2MM100( 445 ) }, // 63 - A3 extra paper
+ { MM2MM100( 174 ), MM2MM100( 235 ) }, // 64 - A5 extra paper
+ { MM2MM100( 201 ), MM2MM100( 276 ) }, // 65 - ISO B5 extra paper
+ { MM2MM100( 420 ), MM2MM100( 594 ) }, // 66 - A2 paper
+ { MM2MM100( 297 ), MM2MM100( 420 ) }, // 67 - A3 transverse paper
+ { MM2MM100( 322 ), MM2MM100( 445 ) } // 68 - A3 extra transverse paper
+};
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+PageSettingsPropertyHelper::HFHelperData::HFHelperData( const OUString& rLeftProp, const OUString& rRightProp ) :
+ maLeftProp( rLeftProp ),
+ maRightProp( rRightProp ),
+ mnHeight( 0 ),
+ mnBodyDist( 0 ),
+ mbHasContent( false ),
+ mbShareOddEven( false ),
+ mbDynamicHeight( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PageSettingsPropertyHelper::PageSettingsPropertyHelper( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maHFParser( rHelper ),
+ maPageProps( sppcPageNames ),
+ maHeaderData( CREATE_OUSTRING( "LeftPageHeaderContent" ), CREATE_OUSTRING( "RightPageHeaderContent" ) ),
+ maFooterData( CREATE_OUSTRING( "LeftPageFooterContent" ), CREATE_OUSTRING( "RightPageFooterContent" ) )
+{
+}
+
+void PageSettingsPropertyHelper::writePageSettingsProperties(
+ PropertySet& rPropSet, const OoxPageData& rData, WorksheetType eSheetType )
+{
+ // printout scaling
+ if( rData.mbFitToPages )
+ {
+ // fit to number of pages
+ rPropSet.setProperty( CREATE_OUSTRING( "ScaleToPagesX" ), getLimitedValue< sal_Int16, sal_Int32 >( rData.mnFitToWidth, 0, 1000 ) );
+ rPropSet.setProperty( CREATE_OUSTRING( "ScaleToPagesY" ), getLimitedValue< sal_Int16, sal_Int32 >( rData.mnFitToHeight, 0, 1000 ) );
+ }
+ else
+ {
+ // scale may be 0 which indicates uninitialized
+ sal_Int16 nScale = (rData.mbValidSettings && (rData.mnScale > 0)) ? getLimitedValue< sal_Int16, sal_Int32 >( rData.mnScale, 10, 400 ) : 100;
+ rPropSet.setProperty( CREATE_OUSTRING( "PageScale" ), nScale );
+ }
+
+ // paper orientation
+ bool bLandscape = rData.mnOrientation == XML_landscape;
+ // default orientation for current sheet type (chart sheets default to landscape)
+ if( !rData.mbValidSettings || (rData.mnOrientation == XML_default) ) switch( eSheetType )
+ {
+ case SHEETTYPE_WORKSHEET: bLandscape = false; break;
+ case SHEETTYPE_CHART: bLandscape = true; break;
+ case SHEETTYPE_MACRO: bLandscape = false; break;
+ }
+
+ // paper size
+ if( rData.mbValidSettings && (0 < rData.mnPaperSize) && (rData.mnPaperSize < static_cast< sal_Int32 >( STATIC_ARRAY_SIZE( spPaperSizeTable ) )) )
+ {
+ const ApiPaperSize& rPaperSize = spPaperSizeTable[ rData.mnPaperSize ];
+ ::com::sun::star::awt::Size aSize( rPaperSize.mnWidth, rPaperSize.mnHeight );
+ if( bLandscape )
+ ::std::swap( aSize.Width, aSize.Height );
+ rPropSet.setProperty( CREATE_OUSTRING( "Size" ), aSize );
+ }
+
+ // header/footer
+ convertHeaderFooterData( rPropSet, maHeaderData, rData.maOddHeader, rData.maEvenHeader, rData.mbUseEvenHF, rData.mfTopMargin, rData.mfHeaderMargin );
+ convertHeaderFooterData( rPropSet, maFooterData, rData.maOddFooter, rData.maEvenFooter, rData.mbUseEvenHF, rData.mfBottomMargin, rData.mfFooterMargin );
+
+ // write all properties to property set
+ const UnitConverter& rUnitConv = getUnitConverter();
+ maPageProps
+ << bLandscape
+ << getLimitedValue< sal_Int16, sal_Int32 >( rData.mbUseFirstPage ? rData.mnFirstPage : 0, 0, 9999 )
+ << (rData.mnPageOrder == XML_downThenOver)
+ << (rData.mnCellComments == XML_asDisplayed)
+ << rData.mbHorCenter
+ << rData.mbVerCenter
+ << rData.mbPrintGrid
+ << rData.mbPrintHeadings
+ << rUnitConv.calcMm100FromInches( rData.mfLeftMargin )
+ << rUnitConv.calcMm100FromInches( rData.mfRightMargin )
+ // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled
+ << rUnitConv.calcMm100FromInches( maHeaderData.mbHasContent ? rData.mfHeaderMargin : rData.mfTopMargin )
+ // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled
+ << rUnitConv.calcMm100FromInches( maFooterData.mbHasContent ? rData.mfFooterMargin : rData.mfBottomMargin )
+ << maHeaderData.mbHasContent
+ << maHeaderData.mbShareOddEven
+ << maHeaderData.mbDynamicHeight
+ << maHeaderData.mnHeight
+ << maHeaderData.mnBodyDist
+ << maFooterData.mbHasContent
+ << maFooterData.mbShareOddEven
+ << maFooterData.mbDynamicHeight
+ << maFooterData.mnHeight
+ << maFooterData.mnBodyDist
+ >> rPropSet;
+}
+
+void PageSettingsPropertyHelper::convertHeaderFooterData(
+ PropertySet& rPropSet, HFHelperData& rHFData,
+ const OUString rOddContent, const OUString rEvenContent, bool bUseEvenContent,
+ double fPageMargin, double fContentMargin )
+{
+ bool bHasOddContent = rOddContent.getLength() > 0;
+ bool bHasEvenContent = bUseEvenContent && (rEvenContent.getLength() > 0);
+
+ sal_Int32 nOddHeight = bHasOddContent ? writeHeaderFooter( rPropSet, rHFData.maRightProp, rOddContent ) : 0;
+ sal_Int32 nEvenHeight = bHasEvenContent ? writeHeaderFooter( rPropSet, rHFData.maLeftProp, rEvenContent ) : 0;
+
+ rHFData.mnHeight = 750;
+ rHFData.mnBodyDist = 250;
+ rHFData.mbHasContent = bHasOddContent || bHasEvenContent;
+ rHFData.mbShareOddEven = !bUseEvenContent;
+ rHFData.mbDynamicHeight = true;
+
+ if( rHFData.mbHasContent )
+ {
+ // use maximum height of odd/even header/footer
+ rHFData.mnHeight = ::std::max( nOddHeight, nEvenHeight );
+ /* Calc contains distance between bottom of header and top of page
+ body in "HeaderBodyDistance" property, and distance between bottom
+ of page body and top of footer in "FooterBodyDistance" property */
+ rHFData.mnBodyDist = getUnitConverter().calcMm100FromInches( fPageMargin - fContentMargin ) - rHFData.mnHeight;
+ /* #i23296# Distance less than 0 means, header or footer overlays page
+ body. As this is not possible in Calc, set fixed header or footer
+ height (crop header/footer) to get correct top position of page body. */
+ rHFData.mbDynamicHeight = rHFData.mnBodyDist >= 0;
+ /* "HeaderHeight" property is in fact distance from top of header to
+ top of page body (including "HeaderBodyDistance").
+ "FooterHeight" property is in fact distance from bottom of page
+ body to bottom of footer (including "FooterBodyDistance"). */
+ rHFData.mnHeight += rHFData.mnBodyDist;
+ // negative body distance not allowed
+ rHFData.mnBodyDist = ::std::max< sal_Int32 >( rHFData.mnBodyDist, 0 );
+ }
+}
+
+sal_Int32 PageSettingsPropertyHelper::writeHeaderFooter(
+ PropertySet& rPropSet, const OUString& rPropName, const OUString& rContent )
+{
+ OSL_ENSURE( rContent.getLength() > 0, "PageSettingsPropertyHelper::writeHeaderFooter - empty h/f string found" );
+ sal_Int32 nHeight = 0;
+ if( rContent.getLength() > 0 )
+ {
+ Reference< XHeaderFooterContent > xHFContent;
+ if( rPropSet.getProperty( xHFContent, rPropName ) && xHFContent.is() )
+ {
+ maHFParser.parse( xHFContent, rContent );
+ rPropSet.setProperty( rPropName, xHFContent );
+ nHeight = getUnitConverter().calcMm100FromPoints( maHFParser.getTotalHeight() );
+ }
+ }
+ return nHeight;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/pivotcachefragment.cxx b/oox/source/xls/pivotcachefragment.cxx
new file mode 100644
index 000000000000..adc7fe2076cb
--- /dev/null
+++ b/oox/source/xls/pivotcachefragment.cxx
@@ -0,0 +1,160 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: pivotcachefragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/pivotcachefragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/xls/addressconverter.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::xml::sax::SAXException;
+
+namespace oox {
+namespace xls {
+
+OoxPivotCacheFragment::OoxPivotCacheFragment( const WorkbookHelper& rHelper,
+ const OUString& rFragmentPath,
+ sal_uInt32 nCacheId ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath ),
+ mnCacheId( nCacheId ),
+ mbValidSource( false )
+{
+}
+
+bool OoxPivotCacheFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT: return nElement == XLS_TOKEN( pivotCacheDefinition );
+ case XLS_TOKEN( pivotCacheDefinition ): return (nElement == XLS_TOKEN( cacheSource ) ||
+ nElement == XLS_TOKEN( cacheFields ));
+ case XLS_TOKEN( cacheSource ): return nElement == XLS_TOKEN( worksheetSource );
+ case XLS_TOKEN( cacheFields ): return nElement == XLS_TOKEN( cacheField );
+ case XLS_TOKEN( cacheField ): return nElement == XLS_TOKEN( sharedItems );
+ case XLS_TOKEN( sharedItems ): return nElement == XLS_TOKEN( s );
+ }
+ return false;
+}
+
+void OoxPivotCacheFragment::onStartElement( const AttributeList& rAttribs )
+{
+ switch ( getCurrentContext() )
+ {
+ case XLS_TOKEN( pivotCacheDefinition ):
+ importPivotCacheDefinition( rAttribs );
+ break;
+ case XLS_TOKEN( cacheSource ):
+ importCacheSource( rAttribs );
+ break;
+ case XLS_TOKEN( worksheetSource ):
+ if ( mbValidSource )
+ importWorksheetSource( rAttribs );
+ break;
+ case XLS_TOKEN( cacheFields ):
+ if ( mbValidSource )
+ maPCacheData.maFields.reserve( rAttribs.getUnsignedInteger(XML_count, 1) );
+ break;
+ case XLS_TOKEN( cacheField ):
+ if ( mbValidSource )
+ importCacheField( rAttribs );
+ break;
+ case XLS_TOKEN( sharedItems ):
+ if ( mbValidSource )
+ maPCacheData.maFields.back().maItems.reserve( rAttribs.getUnsignedInteger(XML_count, 1) );
+ break;
+ case XLS_TOKEN( s ):
+ if ( mbValidSource )
+ maPCacheData.maFields.back().maItems.push_back( rAttribs.getString( XML_v ) );
+ break;
+ }
+}
+
+void OoxPivotCacheFragment::finalizeImport()
+{
+ if( mbValidSource )
+ getPivotTables().setPivotCache( mnCacheId, maPCacheData );
+}
+
+void OoxPivotCacheFragment::importPivotCacheDefinition( const AttributeList& /*rAttribs*/ )
+{
+}
+
+void OoxPivotCacheFragment::importCacheSource( const AttributeList& rAttribs )
+{
+ switch ( rAttribs.getToken(XML_type) )
+ {
+ case XML_worksheet:
+ maPCacheData.meSourceType = PivotCacheData::WORKSHEET;
+ maPCacheData.mpSourceProp.reset( new PivotCacheData::WorksheetSource );
+ mbValidSource = true;
+ break;
+ case XML_external:
+ maPCacheData.meSourceType = PivotCacheData::EXTERNAL;
+ maPCacheData.mpSourceProp.reset( new PivotCacheData::ExternalSource );
+ mbValidSource = true;
+ break;
+ default:
+ // unsupported case source type.
+ break;
+ }
+}
+
+void OoxPivotCacheFragment::importWorksheetSource( const AttributeList& rAttribs )
+{
+ if ( maPCacheData.meSourceType != PivotCacheData::WORKSHEET )
+ return;
+
+ PivotCacheData::WorksheetSource* pSrc = static_cast<PivotCacheData::WorksheetSource*>(
+ maPCacheData.mpSourceProp.get() );
+
+ pSrc->maSrcRange = rAttribs.getString( XML_ref );
+ pSrc->maSheetName = rAttribs.getString( XML_sheet );
+}
+
+void OoxPivotCacheFragment::importCacheField( const AttributeList& rAttribs )
+{
+ PivotCacheField aField;
+ aField.maName = rAttribs.getString( XML_name );
+ maPCacheData.maFields.push_back(aField);
+}
+
+} // namespace xls
+} // namespace oox
diff --git a/oox/source/xls/pivottablebuffer.cxx b/oox/source/xls/pivottablebuffer.cxx
new file mode 100644
index 000000000000..08e61b8a16d5
--- /dev/null
+++ b/oox/source/xls/pivottablebuffer.cxx
@@ -0,0 +1,275 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: pivottablebuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2007 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/pivottablebuffer.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XElementAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/GeneralFunction.hpp>
+#include <com/sun/star/sheet/XCellRangeData.hpp>
+#include <com/sun/star/sheet/XDataPilotDescriptor.hpp>
+#include <com/sun/star/sheet/XDataPilotField.hpp>
+#include <com/sun/star/sheet/XDataPilotTables.hpp>
+#include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp>
+#include <com/sun/star/sheet/XSheetFilterDescriptor.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::sheet::XCellRangeData;
+using ::com::sun::star::sheet::XDataPilotDescriptor;
+using ::com::sun::star::sheet::XDataPilotField;
+using ::com::sun::star::sheet::XDataPilotTables;
+using ::com::sun::star::sheet::XDataPilotTablesSupplier;
+using ::com::sun::star::sheet::XSheetFilterDescriptor;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::table::XCellRange;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::rtl::OUString;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+PivotCacheData::PivotCacheData() :
+ meSourceType( WORKSHEET ),
+ mpSourceProp( static_cast<BaseSource*>(NULL) )
+{
+}
+
+PivotCacheData::WorksheetSource* PivotCacheData::getWorksheetSource() const
+{
+ if ( meSourceType != WORKSHEET )
+ return NULL;
+ return static_cast<WorksheetSource*>( mpSourceProp.get() );
+}
+
+PivotCacheData::ExternalSource* PivotCacheData::getExternalSource() const
+{
+ if ( meSourceType != EXTERNAL )
+ return NULL;
+ return static_cast<ExternalSource*>( mpSourceProp.get() );
+}
+
+// ============================================================================
+
+PivotTableField::PivotTableField() :
+ meAxis( ROW ),
+ mbDataField( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PivotTableData::PivotTableData()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PivotTableBuffer::PivotTableBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+const PivotCacheData* PivotTableBuffer::getPivotCache( sal_uInt32 nCacheId ) const
+{
+ PivotCacheMapType::const_iterator itr = maPivotCacheMap.find(nCacheId),
+ itrEnd = maPivotCacheMap.end();
+
+ if ( itr != itrEnd )
+ return &itr->second;
+
+ return NULL;
+}
+
+void PivotTableBuffer::setPivotCache( sal_uInt32 nCacheId, const PivotCacheData& aData )
+{
+ maPivotCacheMap.insert( PivotCacheMapType::value_type(nCacheId, aData) );
+}
+
+PivotTableData* PivotTableBuffer::getPivotTable( const OUString& aName )
+{
+ PivotTableMapType::iterator itr = maPivotTableMap.find(aName),
+ itrEnd = maPivotTableMap.end();
+
+ if ( itr != itrEnd )
+ return &itr->second;
+
+ return NULL;
+}
+
+void PivotTableBuffer::setPivotTable( const OUString& aName, const PivotTableData& aData )
+{
+ maPivotTableMap.insert( PivotTableMapType::value_type(aName, aData) );
+ maCellRangeMap.addCellRange( aData.maRange );
+}
+
+bool PivotTableBuffer::isOverlapping( const CellAddress& aCellAddress ) const
+{
+ return maCellRangeMap.isOverlapping(aCellAddress);
+}
+
+void PivotTableBuffer::finalizeImport() const
+{
+ PivotTableMapType::const_iterator itr = maPivotTableMap.begin(), itrEnd = maPivotTableMap.end();
+ for ( ; itr != itrEnd; ++itr )
+ writePivotTable( itr->first, itr->second );
+}
+
+void PivotTableBuffer::writePivotTable( const OUString& aName, const PivotTableData& aData ) const
+{
+ using namespace ::com::sun::star::sheet;
+
+ const PivotCacheData* pCache = getPivotCache( aData.mnCacheId );
+ if ( !pCache )
+ {
+ OSL_ENSURE( false, "OoxPivotTableFragment::commit: pivot cache data not found" );
+ return;
+ }
+
+ const CellRangeAddress& aRange = aData.maRange;
+ Reference< XSpreadsheet > xSheet = getSheet( aRange.Sheet );
+ if ( !xSheet.is() )
+ return;
+
+ try
+ {
+ Reference< XDataPilotTablesSupplier > xDPTSupplier( xSheet, UNO_QUERY_THROW );
+
+ Reference< XDataPilotTables > xDPTables( xDPTSupplier->getDataPilotTables(), UNO_QUERY_THROW );
+ Reference< XDataPilotDescriptor > xDPDesc( xDPTables->createDataPilotDescriptor(), UNO_QUERY_THROW );
+ if ( pCache->meSourceType != PivotCacheData::WORKSHEET )
+ return;
+
+ PivotCacheData::WorksheetSource* pSrc = pCache->getWorksheetSource();
+ if ( !pSrc )
+ return;
+
+ OUString sheetname = pSrc->maSheetName;
+ OUString srcrange = pSrc->maSrcRange;
+
+ CellRangeAddress aSrcRange;
+ if ( !getSourceRange( pSrc->maSheetName, pSrc->maSrcRange, aSrcRange ) )
+ return;
+
+ xDPDesc->setSourceRange(aSrcRange);
+ Reference< XIndexAccess > xIA = xDPDesc->getDataPilotFields();
+
+ bool bPageAxisExists = false;
+
+ // Go through all fields in pivot table, and register them.
+ sal_Int32 nCount = ::std::min( xIA->getCount(), static_cast<sal_Int32>(aData.maFields.size()) );
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ Reference< XDataPilotField > xField( xIA->getByIndex(i), UNO_QUERY_THROW );
+ PropertySet aProp( xField );
+ Reference< XNamed > xNamed( xField, UNO_QUERY_THROW );
+
+ PivotTableField::AxisType eAxis = aData.maFields[i].meAxis;
+ if ( aData.maFields[i].mbDataField )
+ eAxis = PivotTableField::VALUES;
+
+ switch ( eAxis )
+ {
+ case PivotTableField::COLUMN:
+ aProp.setProperty( CREATE_OUSTRING("Orientation"), DataPilotFieldOrientation_COLUMN );
+ break;
+ case PivotTableField::ROW:
+ aProp.setProperty( CREATE_OUSTRING("Orientation"), DataPilotFieldOrientation_ROW );
+ break;
+ case PivotTableField::PAGE:
+ bPageAxisExists = true;
+ aProp.setProperty( CREATE_OUSTRING("Orientation"), DataPilotFieldOrientation_PAGE );
+ break;
+ case PivotTableField::VALUES:
+ aProp.setProperty( CREATE_OUSTRING("Orientation"), DataPilotFieldOrientation_DATA );
+ break;
+ default:
+ OSL_ENSURE( false, "OoxPivotTableFragment::commit: unhandled case" );
+ }
+ }
+ CellAddress aCell;
+ aCell.Sheet = aData.maRange.Sheet;
+ aCell.Column = aData.maRange.StartColumn;
+ aCell.Row = aData.maRange.StartRow;
+ if ( bPageAxisExists )
+ aCell.Row -= 2;
+
+ xDPTables->insertNewByName( aName, aCell, xDPDesc );
+ }
+ catch ( const Exception& )
+ {
+ OSL_ENSURE( false, "OoxPivotTableFragment::commit: exception thrown");
+ return;
+ }
+}
+
+bool PivotTableBuffer::getSourceRange( const OUString& aSheetName, const OUString& aRefName,
+ CellRangeAddress& rRange ) const
+{
+ sal_Int32 nCount = getWorksheets().getInternalSheetCount();
+ for ( sal_Int32 nSheet = 0; nSheet < nCount; ++nSheet )
+ {
+ Reference< XNamed > xNamed( getSheet( nSheet ), UNO_QUERY );
+ if ( xNamed.is() && !aSheetName.compareTo( xNamed->getName() ) )
+ return getAddressConverter().convertToCellRange(
+ rRange, aRefName, static_cast< sal_Int16 >( nSheet ), true );
+ }
+ return false;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
diff --git a/oox/source/xls/pivottablefragment.cxx b/oox/source/xls/pivottablefragment.cxx
new file mode 100644
index 000000000000..48f99cb4d41c
--- /dev/null
+++ b/oox/source/xls/pivottablefragment.cxx
@@ -0,0 +1,194 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: pivottablefragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/pivottablefragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/xls/addressconverter.hxx"
+
+#define DEBUG_OOX_PIVOTTABLE 1
+
+#include <vector>
+#include <stdexcept>
+#if DEBUG_OOX_PIVOTTABLE
+#include <stdio.h>
+#endif
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::xml::sax::SAXException;
+
+namespace oox {
+namespace xls {
+
+OoxPivotTableFragment::OoxPivotTableFragment(
+ const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath ),
+ mbValidRange( false )
+{
+}
+
+bool OoxPivotTableFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT: return (nElement == XLS_TOKEN( pivotTableDefinition ));
+ case XLS_TOKEN( pivotTableDefinition ): return (nElement == XLS_TOKEN( location )) ||
+ (nElement == XLS_TOKEN( pivotFields )) ||
+ (nElement == XLS_TOKEN( rowFields )) ||
+ (nElement == XLS_TOKEN( rowItems )) ||
+ (nElement == XLS_TOKEN( colFields )) ||
+ (nElement == XLS_TOKEN( colItems )) ||
+ (nElement == XLS_TOKEN( pageFields )) ||
+ (nElement == XLS_TOKEN( dataFields )) ||
+ (nElement == XLS_TOKEN( pivotTableStyleInfo ));
+ case XLS_TOKEN( pivotFields ): return (nElement == XLS_TOKEN( pivotField ));
+ case XLS_TOKEN( pivotField ): return (nElement == XLS_TOKEN( items ));
+ case XLS_TOKEN( items ): return (nElement == XLS_TOKEN( item ));
+ case XLS_TOKEN( rowFields ): return (nElement == XLS_TOKEN( field ));
+ case XLS_TOKEN( colFields ): return (nElement == XLS_TOKEN( field ));
+ case XLS_TOKEN( pageFields ): return (nElement == XLS_TOKEN( pageField ));
+ case XLS_TOKEN( dataFields ): return (nElement == XLS_TOKEN( dataField ));
+ case XLS_TOKEN( colItems ): return (nElement == XLS_TOKEN( i ));
+ case XLS_TOKEN( rowItems ): return (nElement == XLS_TOKEN( i ));
+ }
+ return false;
+}
+
+void OoxPivotTableFragment::onStartElement( const AttributeList& rAttribs )
+{
+ switch ( getCurrentContext() )
+ {
+ case XLS_TOKEN( pivotTableDefinition ):
+ importPivotTableDefinition( rAttribs );
+ break;
+ case XLS_TOKEN( location ):
+ importLocation( rAttribs );
+ break;
+ case XLS_TOKEN( pivotFields ):
+ importPivotFields( rAttribs );
+ break;
+ case XLS_TOKEN( pivotField ):
+ importPivotField( rAttribs );
+ break;
+ }
+}
+
+void OoxPivotTableFragment::finalizeImport()
+{
+ if( mbValidRange )
+ getPivotTables().setPivotTable( maName, maData );
+}
+
+void OoxPivotTableFragment::importLocation( const AttributeList& rAttribs )
+{
+ CellRangeAddress aRange;
+ OUString aRangeName = rAttribs.getString( XML_ref );
+ mbValidRange = getAddressConverter().convertToCellRange(
+ aRange, aRangeName, getSheetIndex(), true );
+
+ if ( mbValidRange )
+ maData.maRange = aRange;
+}
+
+void OoxPivotTableFragment::importPivotTableDefinition( const AttributeList& rAttribs )
+{
+ if ( !rAttribs.hasAttribute( XML_cacheId ) )
+ return;
+
+ maName = rAttribs.getString( XML_name );
+ maData.mnCacheId = rAttribs.getInteger( XML_cacheId, 0 );
+
+ // name="PivotTable3"
+ // cacheId="0"
+ // applyNumberFormats="0"
+ // applyBorderFormats="0"
+ // applyFontFormats="0"
+ // applyPatternFormats="0"
+ // applyAlignmentFormats="0"
+ // applyWidthHeightFormats="1"
+ // dataCaption="Values"
+ // updatedVersion="3"
+ // minRefreshableVersion="3"
+ // showCalcMbrs="0"
+ // useAutoFormatting="1"
+ // itemPrintTitles="1"
+ // createdVersion="3"
+ // indent="0"
+ // outline="1"
+ // outlineData="1"
+ // multipleFieldFilters="0"
+}
+
+void OoxPivotTableFragment::importPivotFields( const AttributeList& rAttribs )
+{
+ maData.maFields.reserve( rAttribs.getUnsignedInteger( XML_count, 1 ) );
+}
+
+void OoxPivotTableFragment::importPivotField( const AttributeList& rAttribs )
+{
+ maData.maFields.push_back( PivotTableField() );
+ PivotTableField& rField = maData.maFields.back();
+ rField.mbDataField = rAttribs.getBool( XML_dataField, false );
+
+ // Possible values are: axisCol, axisRow, axisPage, axisValues
+ switch ( rAttribs.getToken( XML_axis ) )
+ {
+ case XML_axisCol:
+ rField.meAxis = PivotTableField::COLUMN;
+ break;
+ case XML_axisRow:
+ rField.meAxis = PivotTableField::ROW;
+ break;
+ case XML_axisPage:
+ rField.meAxis = PivotTableField::PAGE;
+ break;
+ case XML_axisValues:
+ rField.meAxis = PivotTableField::VALUES;
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace xls
+} // namespace oox
diff --git a/oox/source/xls/querytablefragment.cxx b/oox/source/xls/querytablefragment.cxx
new file mode 100644
index 000000000000..703ec9f9f156
--- /dev/null
+++ b/oox/source/xls/querytablefragment.cxx
@@ -0,0 +1,82 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: querytablefragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/querytablefragment.hxx"
+#include "oox/xls/webquerybuffer.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::xml::sax::SAXException;
+
+namespace oox {
+namespace xls {
+
+OoxQueryTableFragment::OoxQueryTableFragment(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+bool OoxQueryTableFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT: return (nElement == XLS_TOKEN( queryTable ));
+ }
+ return false;
+}
+
+void OoxQueryTableFragment::onStartElement( const AttributeList& rAttribs )
+{
+ switch ( getCurrentContext() )
+ {
+ case XLS_TOKEN( queryTable ):
+ importQueryTable( rAttribs );
+ break;
+ }
+}
+
+void OoxQueryTableFragment::importQueryTable( const AttributeList& rAttribs )
+{
+ getWebQueries().importQueryTable( rAttribs );
+}
+
+} // namespace xls
+} // namespace oox
diff --git a/oox/source/xls/richstring.cxx b/oox/source/xls/richstring.cxx
new file mode 100644
index 000000000000..97cc1cbe82c2
--- /dev/null
+++ b/oox/source/xls/richstring.cxx
@@ -0,0 +1,605 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: richstring.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/richstring.hxx"
+#include <com/sun/star/text/XText.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::text::XTextRange;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt8 OOBIN_STRINGFLAG_FONTS = 0x01;
+const sal_uInt8 OOBIN_STRINGFLAG_PHONETICS = 0x02;
+
+} // namespace
+
+// ============================================================================
+
+RichStringPortion::RichStringPortion( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mnFontId( -1 )
+{
+}
+
+void RichStringPortion::setText( const OUString& rText )
+{
+ maText = rText;
+}
+
+FontRef RichStringPortion::importFont( const AttributeList& )
+{
+ mxFont.reset( new Font( *this, false ) );
+ return mxFont;
+}
+
+void RichStringPortion::setFontId( sal_Int32 nFontId )
+{
+ mnFontId = nFontId;
+}
+
+void RichStringPortion::finalizeImport()
+{
+ if( mxFont.get() )
+ mxFont->finalizeImport();
+ else if( mnFontId >= 0 )
+ mxFont = getStyles().getFont( mnFontId );
+}
+
+void RichStringPortion::convert( const Reference< XText >& rxText, sal_Int32 nXfId )
+{
+ Reference< XTextRange > xRange = rxText->getEnd();
+ xRange->setString( maText );
+ if( mxFont.get() )
+ {
+ PropertySet aPropSet( xRange );
+ mxFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_RICHTEXT );
+ }
+ if( const Font* pFont = getStyles().getFontFromCellXf( nXfId ).get() )
+ {
+ if( pFont->needsRichTextFormat() )
+ {
+ PropertySet aPropSet( xRange );
+ pFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_RICHTEXT );
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void BinFontPortionData::read( RecordInputStream& rStrm )
+{
+ mnPos = rStrm.readuInt16();
+ mnFontId = rStrm.readuInt16();
+}
+
+void BinFontPortionData::read( BiffInputStream& rStrm, bool b16Bit )
+{
+ if( b16Bit )
+ {
+ mnPos = rStrm.readuInt16();
+ mnFontId = rStrm.readuInt16();
+ }
+ else
+ {
+ mnPos = rStrm.readuInt8();
+ mnFontId = rStrm.readuInt8();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void BinFontPortionList::appendPortion( const BinFontPortionData& rPortion )
+{
+ // #i33341# real life -- same character index may occur several times
+ OSL_ENSURE( empty() || (back().mnPos <= rPortion.mnPos), "BinFontPortionList::appendPortion - wrong char order" );
+ if( empty() || (back().mnPos < rPortion.mnPos) )
+ push_back( rPortion );
+ else
+ back().mnFontId = rPortion.mnFontId;
+}
+
+void BinFontPortionList::importPortions( RecordInputStream& rStrm )
+{
+ sal_Int32 nCount = rStrm.readInt32();
+ clear();
+ if( nCount > 0 )
+ {
+ reserve( getLimitedValue< size_t, sal_Int32 >( nCount, 0, rStrm.getRecLeft() / 4 ) );
+ /* #i33341# real life -- same character index may occur several times
+ -> use appendPortion() to validate string position. */
+ BinFontPortionData aPortion;
+ for( sal_Int32 nIndex = 0; rStrm.isValid() && (nIndex < nCount); ++nIndex )
+ {
+ aPortion.read( rStrm );
+ appendPortion( aPortion );
+ }
+ }
+}
+
+void BinFontPortionList::importPortions( BiffInputStream& rStrm, sal_uInt16 nCount, bool b16Bit )
+{
+ clear();
+ reserve( nCount );
+ /* #i33341# real life -- same character index may occur several times
+ -> use appendPortion() to validate string position. */
+ BinFontPortionData aPortion;
+ for( sal_uInt16 nIndex = 0; rStrm.isValid() && (nIndex < nCount); ++nIndex )
+ {
+ aPortion.read( rStrm, b16Bit );
+ appendPortion( aPortion );
+ }
+}
+
+void BinFontPortionList::importPortions( BiffInputStream& rStrm, bool b16Bit )
+{
+ sal_uInt16 nCount = b16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
+ importPortions( rStrm, nCount, b16Bit );
+}
+
+// ============================================================================
+
+OoxPhoneticData::OoxPhoneticData() :
+ mnFontId( -1 ),
+ mnType( XML_fullwidthKatakana ),
+ mnAlignment( XML_left )
+{
+}
+
+void OoxPhoneticData::setBinData( sal_Int32 nType, sal_Int32 nAlignment )
+{
+ static const sal_Int32 spnTypeIds[] = { XML_halfwidthKatakana, XML_fullwidthKatakana, XML_hiragana, XML_noConversion };
+ mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_fullwidthKatakana );
+
+ static const sal_Int32 spnAlignments[] = { XML_noControl, XML_left, XML_center, XML_distributed };
+ mnAlignment = STATIC_ARRAY_SELECT( spnAlignments, nAlignment, XML_left );
+}
+
+// ----------------------------------------------------------------------------
+
+PhoneticSettings::PhoneticSettings( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void PhoneticSettings::importPhoneticPr( const AttributeList& rAttribs )
+{
+ maOoxData.mnFontId = rAttribs.getInteger( XML_fontId, -1 );
+ maOoxData.mnType = rAttribs.getToken( XML_type, XML_fullwidthKatakana );
+ maOoxData.mnAlignment = rAttribs.getToken( XML_alignment, XML_left );
+}
+
+void PhoneticSettings::importPhoneticPr( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFontId;
+ sal_Int32 nType, nAlignment;
+ rStrm >> nFontId >> nType >> nAlignment;
+ maOoxData.mnFontId = nFontId;
+ maOoxData.setBinData( nType, nAlignment );
+}
+
+void PhoneticSettings::importPhoneticPr( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFontId, nFlags;
+ rStrm >> nFontId >> nFlags;
+ maOoxData.mnFontId = nFontId;
+ maOoxData.setBinData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) );
+ // following: range list with cells showing phonetic text
+}
+
+void PhoneticSettings::importStringData( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFontId, nFlags;
+ rStrm >> nFontId >> nFlags;
+ maOoxData.mnFontId = nFontId;
+ maOoxData.setBinData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) );
+}
+
+void PhoneticSettings::importStringData( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFontId, nFlags;
+ rStrm >> nFontId >> nFlags;
+ maOoxData.mnFontId = nFontId;
+ maOoxData.setBinData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) );
+}
+
+// ============================================================================
+
+RichStringPhonetic::RichStringPhonetic( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mnBasePos( -1 ),
+ mnBaseEnd( -1 )
+{
+}
+
+void RichStringPhonetic::setText( const OUString& rText )
+{
+ maText = rText;
+}
+
+void RichStringPhonetic::importPhoneticRun( const AttributeList& rAttribs )
+{
+ mnBasePos = rAttribs.getInteger( XML_sb, -1 );
+ mnBaseEnd = rAttribs.getInteger( XML_eb, -1 );
+}
+
+void RichStringPhonetic::setBaseRange( sal_Int32 nBasePos, sal_Int32 nBaseEnd )
+{
+ mnBasePos = nBasePos;
+ mnBaseEnd = nBaseEnd;
+}
+
+// ----------------------------------------------------------------------------
+
+void BinPhoneticPortionData::read( RecordInputStream& rStrm )
+{
+ mnPos = rStrm.readuInt16();
+ mnBasePos = rStrm.readuInt16();
+ mnBaseLen = rStrm.readuInt16();
+}
+
+void BinPhoneticPortionData::read( BiffInputStream& rStrm )
+{
+ mnPos = rStrm.readuInt16();
+ mnBasePos = rStrm.readuInt16();
+ mnBaseLen = rStrm.readuInt16();
+}
+
+// ----------------------------------------------------------------------------
+
+void BinPhoneticPortionList::appendPortion( const BinPhoneticPortionData& rPortion )
+{
+ // same character index may occur several times
+ OSL_ENSURE( empty() || ((back().mnPos <= rPortion.mnPos) &&
+ (back().mnBasePos + back().mnBaseLen <= rPortion.mnBasePos)),
+ "BinPhoneticPortionList::appendPortion - wrong char order" );
+ if( empty() || (back().mnPos < rPortion.mnPos) )
+ {
+ push_back( rPortion );
+ }
+ else if( back().mnPos == rPortion.mnPos )
+ {
+ back().mnBasePos = rPortion.mnBasePos;
+ back().mnBaseLen = rPortion.mnBaseLen;
+ }
+}
+
+void BinPhoneticPortionList::importPortions( RecordInputStream& rStrm )
+{
+ sal_Int32 nCount = rStrm.readInt32();
+ clear();
+ if( nCount > 0 )
+ {
+ reserve( getLimitedValue< size_t, sal_Int32 >( nCount, 0, rStrm.getRecLeft() / 6 ) );
+ BinPhoneticPortionData aPortion;
+ for( sal_Int32 nIndex = 0; rStrm.isValid() && (nIndex < nCount); ++nIndex )
+ {
+ aPortion.read( rStrm );
+ appendPortion( aPortion );
+ }
+ }
+}
+
+OUString BinPhoneticPortionList::importPortions( BiffInputStream& rStrm, sal_uInt32 nPhoneticSize )
+{
+ OUString aPhoneticText;
+ sal_uInt16 nPortionCount, nTextLen1, nTextLen2;
+ rStrm >> nPortionCount >> nTextLen1 >> nTextLen2;
+ OSL_ENSURE( nTextLen1 == nTextLen2, "BinPhoneticPortionList::importPortions - wrong phonetic text length" );
+ if( (nTextLen1 == nTextLen2) && (nTextLen1 > 0) )
+ {
+ sal_uInt32 nMinSize = static_cast< sal_uInt32 >( 2 * nTextLen1 + 6 * nPortionCount + 14 );
+ OSL_ENSURE( nMinSize <= nPhoneticSize, "BinPhoneticPortionList::importPortions - wrong size of phonetic data" );
+ if( nMinSize <= nPhoneticSize )
+ {
+ aPhoneticText = rStrm.readUnicodeArray( nTextLen1 );
+ clear();
+ reserve( nPortionCount );
+ BinPhoneticPortionData aPortion;
+ for( sal_uInt16 nPortion = 0; nPortion < nPortionCount; ++nPortion )
+ {
+ aPortion.read( rStrm );
+ appendPortion( aPortion );
+ }
+ }
+ }
+ return aPhoneticText;
+}
+
+// ============================================================================
+
+RichString::RichString( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maPhonSettings( rHelper )
+{
+}
+
+RichStringPortionRef RichString::importText( const AttributeList& )
+{
+ return createPortion();
+}
+
+RichStringPortionRef RichString::importRun( const AttributeList& )
+{
+ return createPortion();
+}
+
+RichStringPhoneticRef RichString::importPhoneticRun( const AttributeList& rAttribs )
+{
+ RichStringPhoneticRef xPhonetic = createPhonetic();
+ xPhonetic->importPhoneticRun( rAttribs );
+ return xPhonetic;
+}
+
+void RichString::importPhoneticPr( const AttributeList& rAttribs )
+{
+ maPhonSettings.importPhoneticPr( rAttribs );
+}
+
+void RichString::importString( RecordInputStream& rStrm, bool bRich )
+{
+ sal_uInt8 nFlags = bRich ? rStrm.readuInt8() : 0;
+ OUString aBaseText = rStrm.readString();
+
+ if( rStrm.isValid() && getFlag( nFlags, OOBIN_STRINGFLAG_FONTS ) )
+ {
+ BinFontPortionList aPortions;
+ aPortions.importPortions( rStrm );
+ createFontPortions( aBaseText, aPortions );
+ }
+ else
+ {
+ createPortion()->setText( aBaseText );
+ }
+
+ if( rStrm.isValid() && getFlag( nFlags, OOBIN_STRINGFLAG_PHONETICS ) )
+ {
+ OUString aPhoneticText = rStrm.readString();
+ BinPhoneticPortionList aPortions;
+ aPortions.importPortions( rStrm );
+ maPhonSettings.importStringData( rStrm );
+ createPhoneticPortions( aPhoneticText, aPortions, aBaseText.getLength() );
+ }
+}
+
+void RichString::importByteString( BiffInputStream& rStrm, rtl_TextEncoding eDefaultTextEnc, BiffStringFlags nFlags )
+{
+ OSL_ENSURE( !getFlag( nFlags, BIFF_STR_KEEPFONTS ), "RichString::importString - keep fonts not implemented" );
+ OSL_ENSURE( !getFlag( nFlags, static_cast< BiffStringFlags >( ~(BIFF_STR_8BITLENGTH | BIFF_STR_EXTRAFONTS) ) ), "RichString::importByteString - unknown flag" );
+ bool b8BitLength = getFlag( nFlags, BIFF_STR_8BITLENGTH );
+
+ OString aBaseText = rStrm.readByteString( !b8BitLength );
+
+ if( rStrm.isValid() && getFlag( nFlags, BIFF_STR_EXTRAFONTS ) )
+ {
+ BinFontPortionList aPortions;
+ aPortions.importPortions( rStrm, false );
+ createFontPortions( aBaseText, eDefaultTextEnc, aPortions );
+ }
+ else
+ {
+ createPortion()->setText( OStringToOUString( aBaseText, eDefaultTextEnc ) );
+ }
+}
+
+void RichString::importUniString( BiffInputStream& rStrm, BiffStringFlags nFlags )
+{
+ OSL_ENSURE( !getFlag( nFlags, BIFF_STR_KEEPFONTS ), "RichString::importUniString - keep fonts not implemented" );
+ OSL_ENSURE( !getFlag( nFlags, static_cast< BiffStringFlags >( ~(BIFF_STR_8BITLENGTH | BIFF_STR_SMARTFLAGS) ) ), "RichString::importUniString - unknown flag" );
+ bool b8BitLength = getFlag( nFlags, BIFF_STR_8BITLENGTH );
+
+ // --- string header ---
+ sal_uInt16 nChars = b8BitLength ? rStrm.readuInt8() : rStrm.readuInt16();
+ sal_uInt8 nFlagField = 0;
+ if( (nChars > 0) || !getFlag( nFlags, BIFF_STR_SMARTFLAGS ) )
+ rStrm >> nFlagField;
+
+ bool b16Bit, bFonts, bPhonetic;
+ sal_uInt16 nFontCount;
+ sal_uInt32 nPhoneticSize;
+ rStrm.readExtendedUniStringHeader( b16Bit, bFonts, bPhonetic, nFontCount, nPhoneticSize, nFlagField );
+
+ // --- character array ---
+ OUString aBaseText = rStrm.readRawUniString( nChars, b16Bit );
+
+ // --- formatting ---
+ // #122185# bRich flag may be set, but format runs may be missing
+ if( rStrm.isValid() && (nFontCount > 0) )
+ {
+ BinFontPortionList aPortions;
+ aPortions.importPortions( rStrm, nFontCount, true );
+ createFontPortions( aBaseText, aPortions );
+ }
+ else
+ {
+ createPortion()->setText( aBaseText );
+ }
+
+ // --- Asian phonetic information ---
+ // #122185# bPhonetic flag may be set, but phonetic info may be missing
+ if( rStrm.isValid() && (nPhoneticSize > 0) )
+ {
+ sal_uInt32 nPhoneticEnd = rStrm.getRecPos() + nPhoneticSize;
+ OSL_ENSURE( nPhoneticSize > 14, "RichString::importUniString - wrong size of phonetic data" );
+ if( nPhoneticSize > 14 )
+ {
+ sal_uInt16 nId, nSize;
+ rStrm >> nId >> nSize;
+ OSL_ENSURE( nId == 1, "RichString::importUniString - unknown phonetic data identifier" );
+ sal_uInt32 nMinSize = static_cast< sal_uInt32 >( nSize + 4 );
+ OSL_ENSURE( nMinSize <= nPhoneticSize, "RichString::importUniString - wrong size of phonetic data" );
+ if( (nId == 1) && (nMinSize <= nPhoneticSize) )
+ {
+ maPhonSettings.importStringData( rStrm );
+ BinPhoneticPortionList aPortions;
+ OUString aPhoneticText = aPortions.importPortions( rStrm, nPhoneticSize );
+ createPhoneticPortions( aPhoneticText, aPortions, aBaseText.getLength() );
+ }
+ }
+ rStrm.seek( nPhoneticEnd );
+ }
+}
+
+void RichString::finalizeImport()
+{
+ maFontPortions.forEachMem( &RichStringPortion::finalizeImport );
+}
+
+void RichString::convert( const Reference< XText >& rxText, sal_Int32 nXfId ) const
+{
+ for( PortionVec::const_iterator aIt = maFontPortions.begin(), aEnd = maFontPortions.end(); aIt != aEnd; ++aIt )
+ {
+ (*aIt)->convert( rxText, nXfId );
+ nXfId = -1;
+ }
+}
+
+// private --------------------------------------------------------------------
+
+RichStringPortionRef RichString::createPortion()
+{
+ RichStringPortionRef xPortion( new RichStringPortion( *this ) );
+ maFontPortions.push_back( xPortion );
+ return xPortion;
+}
+
+RichStringPhoneticRef RichString::createPhonetic()
+{
+ RichStringPhoneticRef xPhonetic( new RichStringPhonetic( *this ) );
+ maPhonPortions.push_back( xPhonetic );
+ return xPhonetic;
+}
+
+void RichString::createFontPortions( const OString& rText, rtl_TextEncoding eDefaultTextEnc, BinFontPortionList& rPortions )
+{
+ maFontPortions.clear();
+ sal_Int32 nStrLen = rText.getLength();
+ if( nStrLen > 0 )
+ {
+ // add leading and trailing string position to ease the following loop
+ if( rPortions.empty() || (rPortions.front().mnPos > 0) )
+ rPortions.insert( rPortions.begin(), BinFontPortionData( 0, -1 ) );
+ if( rPortions.back().mnPos < nStrLen )
+ rPortions.push_back( BinFontPortionData( nStrLen, -1 ) );
+
+ // create all string portions according to the font id vector
+ for( BinFontPortionList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt )
+ {
+ sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos;
+ if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) )
+ {
+ // convert byte string to unicode string, using current font encoding
+ FontRef xFont = getStyles().getFont( aIt->mnFontId );
+ rtl_TextEncoding eTextEnc = xFont.get() ? xFont->getFontEncoding() : eDefaultTextEnc;
+ OUString aUniStr = OStringToOUString( rText.copy( aIt->mnPos, nPortionLen ), eTextEnc );
+ // create string portion
+ RichStringPortionRef xPortion = createPortion();
+ xPortion->setText( aUniStr );
+ xPortion->setFontId( aIt->mnFontId );
+ }
+ }
+ }
+}
+
+void RichString::createFontPortions( const OUString& rText, BinFontPortionList& rPortions )
+{
+ maFontPortions.clear();
+ sal_Int32 nStrLen = rText.getLength();
+ if( nStrLen > 0 )
+ {
+ // add leading and trailing string position to ease the following loop
+ if( rPortions.empty() || (rPortions.front().mnPos > 0) )
+ rPortions.insert( rPortions.begin(), BinFontPortionData( 0, -1 ) );
+ if( rPortions.back().mnPos < nStrLen )
+ rPortions.push_back( BinFontPortionData( nStrLen, -1 ) );
+
+ // create all string portions according to the font id vector
+ for( BinFontPortionList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt )
+ {
+ sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos;
+ if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) )
+ {
+ RichStringPortionRef xPortion = createPortion();
+ xPortion->setText( rText.copy( aIt->mnPos, nPortionLen ) );
+ xPortion->setFontId( aIt->mnFontId );
+ }
+ }
+ }
+}
+
+void RichString::createPhoneticPortions( const ::rtl::OUString& rText, BinPhoneticPortionList& rPortions, sal_Int32 nBaseLen )
+{
+ maPhonPortions.clear();
+ sal_Int32 nStrLen = rText.getLength();
+ if( nStrLen > 0 )
+ {
+ // no portions - assign phonetic text to entire base text
+ if( rPortions.empty() )
+ rPortions.push_back( BinPhoneticPortionData( 0, 0, nBaseLen ) );
+ // add trailing string position to ease the following loop
+ if( rPortions.back().mnPos < nStrLen )
+ rPortions.push_back( BinPhoneticPortionData( nStrLen, nBaseLen, 0 ) );
+
+ // create all phonetic portions according to the portions vector
+ for( BinPhoneticPortionList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt )
+ {
+ sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos;
+ if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) )
+ {
+ RichStringPhoneticRef xPhonetic = createPhonetic();
+ xPhonetic->setText( rText.copy( aIt->mnPos, nPortionLen ) );
+ xPhonetic->setBaseRange( aIt->mnBasePos, aIt->mnBasePos + aIt->mnBaseLen );
+ }
+ }
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/richstringcontext.cxx b/oox/source/xls/richstringcontext.cxx
new file mode 100644
index 000000000000..fd9b21572cb6
--- /dev/null
+++ b/oox/source/xls/richstringcontext.cxx
@@ -0,0 +1,118 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: richstringcontext.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/richstringcontext.hxx"
+
+using ::rtl::OUString;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxRichStringContext::onCanCreateContext( sal_Int32 nElement ) const
+{
+ sal_Int32 nCurrContext = getCurrentContext();
+ switch( nCurrContext )
+ {
+ case XLS_TOKEN( si ):
+ case XLS_TOKEN( is ):
+ case XLS_TOKEN( text ):
+ return (nElement == XLS_TOKEN( t )) ||
+ (nElement == XLS_TOKEN( r )) ||
+ (nElement == XLS_TOKEN( rPh )) ||
+ (nElement == XLS_TOKEN( phoneticPr ));
+ case XLS_TOKEN( r ):
+ return (nElement == XLS_TOKEN( rPr )) ||
+ (nElement == XLS_TOKEN( t ));
+ case XLS_TOKEN( rPh ):
+ return (nElement == XLS_TOKEN( t ));
+ case XLS_TOKEN( rPr ):
+ return Font::isSupportedContext( nElement, nCurrContext );
+ }
+ return false;
+}
+
+void OoxRichStringContext::onStartElement( const AttributeList& rAttribs )
+{
+ sal_Int32 nCurrContext = getCurrentContext();
+ switch( nCurrContext )
+ {
+ case XLS_TOKEN( t ):
+ if( !isPreviousContext( XLS_TOKEN( r ) ) && !isPreviousContext( XLS_TOKEN( rPh ) ) )
+ mxPortion = mxString->importText( rAttribs );
+ break;
+ case XLS_TOKEN( r ):
+ mxPortion = mxString->importRun( rAttribs );
+ break;
+ case XLS_TOKEN( rPr ):
+ if( mxPortion.get() ) mxFont = mxPortion->importFont( rAttribs );
+ break;
+ case XLS_TOKEN( rPh ):
+ mxPhonetic = mxString->importPhoneticRun( rAttribs );
+ break;
+ case XLS_TOKEN( phoneticPr ):
+ mxString->importPhoneticPr( rAttribs );
+ break;
+ default:
+ if( isPreviousContext( XLS_TOKEN( rPr ) ) && mxFont.get() )
+ mxFont->importAttribs( nCurrContext, rAttribs );
+ }
+}
+
+void OoxRichStringContext::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( t ):
+ switch( getPreviousContext() )
+ {
+ case XLS_TOKEN( rPh ):
+ if( mxPhonetic.get() ) mxPhonetic->setText( rChars );
+ break;
+ default:
+ if( mxPortion.get() ) mxPortion->setText( rChars );
+ }
+ break;
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/sharedformulabuffer.cxx b/oox/source/xls/sharedformulabuffer.cxx
new file mode 100644
index 000000000000..5a09ec22c407
--- /dev/null
+++ b/oox/source/xls/sharedformulabuffer.cxx
@@ -0,0 +1,220 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: sharedformulabuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/sharedformulabuffer.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/defnamesbuffer.hxx"
+#include "oox/xls/formulaparser.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::XFormulaTokens;
+using ::com::sun::star::sheet::XNamedRange;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+bool operator==( const CellAddress& rAddr1, const CellAddress& rAddr2 )
+{
+ return
+ (rAddr1.Sheet == rAddr2.Sheet) &&
+ (rAddr1.Column == rAddr2.Column) &&
+ (rAddr1.Row == rAddr2.Row);
+}
+
+bool lclContains( const CellRangeAddress& rRange, const CellAddress& rAddr )
+{
+ return
+ (rRange.Sheet == rAddr.Sheet) &&
+ (rRange.StartColumn <= rAddr.Column) && (rAddr.Column <= rRange.EndColumn) &&
+ (rRange.StartRow <= rAddr.Row) && (rAddr.Row <= rRange.EndRow);
+}
+
+} // namespace
+
+// ============================================================================
+
+ExtCellFormulaContext::ExtCellFormulaContext( const WorksheetHelper& rHelper,
+ const Reference< XFormulaTokens >& rxTokens, const CellAddress& rCellPos ) :
+ SimpleFormulaContext( rxTokens, false, false ),
+ WorksheetHelper( rHelper )
+{
+ setBaseAddress( rCellPos );
+}
+
+void ExtCellFormulaContext::setSharedFormula( const CellAddress& rBaseAddr )
+{
+ getSharedFormulas().setSharedFormulaCell( *this, rBaseAddr );
+}
+
+// ============================================================================
+
+SharedFormulaBuffer::SharedFormulaBuffer( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+void SharedFormulaBuffer::importSharedFmla( const OUString& rFormula, const OUString& rSharedRange, sal_Int32 nSharedId, const CellAddress& rBaseAddr )
+{
+ CellRangeAddress aFmlaRange;
+ if( getAddressConverter().convertToCellRange( aFmlaRange, rSharedRange, getSheetIndex(), true ) )
+ {
+ // create the defined name representing the shared formula
+ OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SharedFormulaBuffer::importSharedFmla - invalid range for shared formula" );
+ BinAddress aMapKey( nSharedId, 0 );
+ Reference< XNamedRange > xNamedRange = createDefinedName( aMapKey );
+ // convert the formula definition
+ Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY );
+ if( xTokens.is() )
+ {
+ SimpleFormulaContext aContext( xTokens, true, false );
+ aContext.setBaseAddress( rBaseAddr );
+ getFormulaParser().importFormula( aContext, rFormula );
+ updateCachedCell( rBaseAddr, aMapKey );
+ }
+ }
+}
+
+void SharedFormulaBuffer::importSharedFmla( RecordInputStream& rStrm, const CellAddress& rBaseAddr )
+{
+ BinRange aRange;
+ rStrm >> aRange;
+ CellRangeAddress aFmlaRange;
+ if( getAddressConverter().convertToCellRange( aFmlaRange, aRange, getSheetIndex(), true ) )
+ {
+ // create the defined name representing the shared formula
+ OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SharedFormulaBuffer::importSharedFmla - invalid range for shared formula" );
+ BinAddress aMapKey( rBaseAddr );
+ Reference< XNamedRange > xNamedRange = createDefinedName( aMapKey );
+ // load the formula definition
+ Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY );
+ if( xTokens.is() )
+ {
+ SimpleFormulaContext aContext( xTokens, true, false );
+ aContext.setBaseAddress( rBaseAddr );
+ getFormulaParser().importFormula( aContext, rStrm );
+ updateCachedCell( rBaseAddr, aMapKey );
+ }
+ }
+}
+
+void SharedFormulaBuffer::importSharedFmla( BiffInputStream& rStrm, const CellAddress& rBaseAddr )
+{
+ BinRange aRange;
+ aRange.read( rStrm, false ); // always 8bit column indexes
+ CellRangeAddress aFmlaRange;
+ if( getAddressConverter().convertToCellRange( aFmlaRange, aRange, getSheetIndex(), true ) )
+ {
+ // create the defined name representing the shared formula
+ OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SharedFormulaBuffer::importSharedFmla - invalid range for shared formula" );
+ BinAddress aMapKey( rBaseAddr );
+ Reference< XNamedRange > xNamedRange = createDefinedName( aMapKey );
+ // load the formula definition
+ Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY );
+ if( xTokens.is() )
+ {
+ rStrm.skip( 2 ); // flags
+ SimpleFormulaContext aContext( xTokens, true, false );
+ aContext.setBaseAddress( rBaseAddr );
+ getFormulaParser().importFormula( aContext, rStrm );
+ updateCachedCell( rBaseAddr, aMapKey );
+ }
+ }
+}
+
+void SharedFormulaBuffer::setSharedFormulaCell( ExtCellFormulaContext& rContext, const CellAddress& rBaseAddr )
+{
+ if( !implSetSharedFormulaCell( rContext, BinAddress( rBaseAddr ) ) )
+ if( rContext.getBaseAddress() == rBaseAddr )
+ mxLastContext.reset( new ExtCellFormulaContext( rContext ) );
+}
+
+void SharedFormulaBuffer::setSharedFormulaCell( ExtCellFormulaContext& rContext, sal_Int32 nSharedId )
+{
+ implSetSharedFormulaCell( rContext, BinAddress( nSharedId, 0 ) );
+}
+
+Reference< XNamedRange > SharedFormulaBuffer::createDefinedName( const BinAddress& rMapKey )
+{
+ OSL_ENSURE( maIndexMap.count( rMapKey ) == 0, "SharedFormulaBuffer::createDefinedName - shared formula exists already" );
+ // create the defined name representing the shared formula
+ OUString aName = OUStringBuffer().appendAscii( "__shared_" ).
+ append( static_cast< sal_Int32 >( getSheetIndex() + 1 ) ).
+ append( sal_Unicode( '_' ) ).append( rMapKey.mnRow ).
+ append( sal_Unicode( '_' ) ).append( rMapKey.mnCol ).makeStringAndClear();
+ Reference< XNamedRange > xNamedRange = getDefinedNames().createDefinedName( aName );
+ sal_Int32 nTokenIndex = getDefinedNames().getTokenIndex( xNamedRange );
+ if( nTokenIndex >= 0 )
+ maIndexMap[ rMapKey ] = nTokenIndex;
+ return xNamedRange;
+}
+
+bool SharedFormulaBuffer::implSetSharedFormulaCell( ExtCellFormulaContext& rContext, const BinAddress& rMapKey )
+{
+ TokenIndexMap::const_iterator aIt = maIndexMap.find( rMapKey );
+ sal_Int32 nTokenIndex = (aIt == maIndexMap.end()) ? -1 : aIt->second;
+ if( nTokenIndex >= 0 )
+ {
+ getFormulaParser().convertNameToFormula( rContext, nTokenIndex );
+ return true;
+ }
+ return false;
+}
+
+void SharedFormulaBuffer::updateCachedCell( const CellAddress& rBaseAddr, const BinAddress& rMapKey )
+{
+ if( mxLastContext.get() && (mxLastContext->getBaseAddress() == rBaseAddr) )
+ implSetSharedFormulaCell( *mxLastContext, rMapKey );
+ mxLastContext.reset();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/sharedstringsbuffer.cxx b/oox/source/xls/sharedstringsbuffer.cxx
new file mode 100644
index 000000000000..85a6662e3004
--- /dev/null
+++ b/oox/source/xls/sharedstringsbuffer.cxx
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: sharedstringsbuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/sharedstringsbuffer.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::text::XText;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+SharedStringsBuffer::SharedStringsBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+RichStringRef SharedStringsBuffer::createRichString()
+{
+ RichStringRef xString( new RichString( *this ) );
+ maStrings.push_back( xString );
+ return xString;
+}
+
+void SharedStringsBuffer::importSst( BiffInputStream& rStrm )
+{
+ sal_Int32 nStringCount = rStrm.skip( 4 ).readInt32();
+ if( nStringCount > 0 )
+ {
+ maStrings.clear();
+ maStrings.reserve( static_cast< size_t >( nStringCount ) );
+ for( ; rStrm.isValid() && (nStringCount > 0); --nStringCount )
+ {
+ RichStringRef xString( new RichString( *this ) );
+ maStrings.push_back( xString );
+ xString->importUniString( rStrm );
+ }
+ }
+}
+
+void SharedStringsBuffer::finalizeImport()
+{
+ maStrings.forEachMem( &RichString::finalizeImport );
+}
+
+void SharedStringsBuffer::convertString( const Reference< XText >& rxText, sal_Int32 nStringId, sal_Int32 nXfId ) const
+{
+ if( rxText.is() )
+ if( const RichString* pString = maStrings.get( nStringId ).get() )
+ pString->convert( rxText, nXfId );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/sharedstringsfragment.cxx b/oox/source/xls/sharedstringsfragment.cxx
new file mode 100644
index 000000000000..8b7b1c5d6b6e
--- /dev/null
+++ b/oox/source/xls/sharedstringsfragment.cxx
@@ -0,0 +1,110 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: sharedstringsfragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/sharedstringsfragment.hxx"
+#include "oox/xls/sharedstringsbuffer.hxx"
+#include "oox/xls/richstringcontext.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::xml::sax::XFastContextHandler;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxSharedStringsFragment::OoxSharedStringsFragment(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxSharedStringsFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nElement == XLS_TOKEN( sst ));
+ case XLS_TOKEN( sst ):
+ return (nElement == XLS_TOKEN( si ));
+ }
+ return false;
+}
+
+Reference< XFastContextHandler > OoxSharedStringsFragment::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
+{
+ switch( nElement )
+ {
+ case XLS_TOKEN( si ):
+ return new OoxRichStringContext( *this, getSharedStrings().createRichString() );
+ }
+ return this;
+}
+
+bool OoxSharedStringsFragment::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nRecId == OOBIN_ID_SST);
+ case OOBIN_ID_SST:
+ return (nRecId == OOBIN_ID_SI);
+ }
+ return false;
+}
+
+void OoxSharedStringsFragment::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_SI: getSharedStrings().createRichString()->importString( rStrm, true ); break;
+ }
+}
+
+// oox.xls.OoxFragmentHandler interface ---------------------------------------
+
+void OoxSharedStringsFragment::finalizeImport()
+{
+ getSharedStrings().finalizeImport();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/sheetcellrangemap.cxx b/oox/source/xls/sheetcellrangemap.cxx
new file mode 100644
index 000000000000..aeb35953a558
--- /dev/null
+++ b/oox/source/xls/sheetcellrangemap.cxx
@@ -0,0 +1,172 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: sheetcellrangemap.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2007 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/sheetcellrangemap.hxx"
+
+#define DEBUG_OOX_CELLRANGE_MAP 0
+
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+
+#if DEBUG_OOX_CELLRANGE_MAP
+#include <stdio.h>
+#endif
+
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+
+namespace oox {
+namespace xls {
+
+SheetCellRangeMap::SheetCellRangeMap()
+{
+}
+
+SheetCellRangeMap::~SheetCellRangeMap() throw()
+{
+}
+
+void SheetCellRangeMap::addCellRange( const CellRangeAddress& aRangeAddr )
+{
+ size_t nAreaId = maAreas.size();
+
+ // First, find the sheet ID.
+ SheetMapType::iterator posSheet = maSheetMap.find(aRangeAddr.Sheet);
+ if ( posSheet == maSheetMap.end() )
+ {
+ maSheetMap.insert( SheetMapType::value_type(aRangeAddr.Sheet, SheetSet()) );
+ posSheet = maSheetMap.find(aRangeAddr.Sheet);
+ OSL_ENSURE( posSheet != maSheetMap.end(), "SheetCellRangeMap::addCellRange: insertion failure" );
+ }
+ SheetSet& rSheet = posSheet->second;
+
+ addRange(rSheet.maColRanges, aRangeAddr.StartColumn, aRangeAddr.EndColumn, nAreaId);
+ addRange(rSheet.maRowRanges, aRangeAddr.StartRow, aRangeAddr.EndRow, nAreaId);
+
+#if DEBUG_OOX_CELLRANGE_MAP
+ fprintf(stdout, "SheetCellRangeMap::addCellRange: adding (sheet: %d) (col: %ld - %ld) (row: %ld - %ld) (area: %d)\n",
+ aRangeAddr.Sheet, aRangeAddr.StartColumn, aRangeAddr.EndColumn, aRangeAddr.StartRow, aRangeAddr.EndRow, nAreaId);fflush(stdout);
+#endif
+
+ maAreas.push_back(aRangeAddr);
+}
+
+bool SheetCellRangeMap::isOverlapping( const CellAddress& aCellAddr ) const
+{
+ if ( maAreas.empty() )
+ return false;
+
+ SheetMapType::const_iterator pos = maSheetMap.find(aCellAddr.Sheet);
+ if ( pos == maSheetMap.end() )
+ // There is no cell range registered for this sheet.
+ return false;
+
+ const SheetSet& rSheet = pos->second;
+ return searchColumns( rSheet, aCellAddr );
+}
+
+void SheetCellRangeMap::addRange( StartEndMapType& rRangeMap, sal_Int32 nStart, sal_Int32 nEnd, size_t nAreaId )
+{
+ StartEndMapType::iterator posStart = rRangeMap.find(nStart);
+ if ( posStart == rRangeMap.end() )
+ {
+ EndAreaIdMapType aMap;
+ rRangeMap.insert( StartEndMapType::value_type(nStart, aMap) );
+ posStart = rRangeMap.find(nStart);
+ OSL_ENSURE( posStart != rRangeMap.end(), "TableBuffer::addRangeToSet: insertion failure" );
+ }
+ EndAreaIdMapType& rEndMap = posStart->second;
+
+ EndAreaIdMapType::iterator posEnd = rEndMap.find(nEnd);
+ if ( posEnd == rEndMap.end() )
+ {
+ AreaIdSetType aSet;
+ rEndMap.insert( EndAreaIdMapType::value_type(nEnd, aSet) );
+ posEnd = rEndMap.find(nEnd);
+ OSL_ENSURE( posEnd != rEndMap.end(), "TableBuffer::addRangeToSet: insertion failure" );
+ }
+
+ AreaIdSetType& rSet = posEnd->second;
+ rSet.push_back(nAreaId);
+}
+
+bool SheetCellRangeMap::expandSearch( const EndAreaIdMapType& rEndMap, const CellAddress& rCellAddr, bool bColumn ) const
+{
+ sal_Int32 nId = bColumn ? rCellAddr.Column : rCellAddr.Row;
+
+ EndAreaIdMapType::const_reverse_iterator itr, itrBeg = rEndMap.rbegin(), itrEnd = rEndMap.rend();
+ for ( itr = itrBeg; itr != itrEnd; ++itr )
+ {
+ if ( itr->first >= nId )
+ {
+ // The point is in-range.
+ const AreaIdSetType& rSet = itr->second;
+ AreaIdSetType::const_iterator itr2 = rSet.begin(), itr2End = rSet.end();
+ for ( ; itr2 != itr2End; ++itr2 )
+ {
+ OSL_ENSURE( maAreas.size() > *itr2, "SheetCellRangeMap::expandSearch: size mismatch" );
+ const CellRangeAddress& rRange = maAreas[*itr2];
+ if ( bColumn && rCellAddr.Row >= rRange.StartRow && rCellAddr.Row <= rRange.EndRow )
+ return true;
+ if ( !bColumn && rCellAddr.Column >= rRange.StartColumn && rCellAddr.Column <= rRange.EndColumn )
+ return true;
+ }
+ }
+ else if ( itr->first < nId )
+ // No more enclosing ranges.
+ return false;
+ }
+ return false;
+}
+
+bool SheetCellRangeMap::searchColumns( const SheetSet& rSheet, const CellAddress& aCellAddr ) const
+{
+ StartEndMapType::const_iterator itr, itrBeg = rSheet.maColRanges.begin(), itrEnd = rSheet.maColRanges.end();
+ for ( itr = itrBeg; itr != itrEnd; ++itr )
+ {
+ if ( itr->first <= aCellAddr.Column )
+ {
+ if ( expandSearch(itr->second, aCellAddr, true) )
+ return true;
+ }
+ else if ( itr->first > aCellAddr.Column )
+ return false;
+ }
+ return false;
+}
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/sheetdatacontext.cxx b/oox/source/xls/sheetdatacontext.cxx
new file mode 100644
index 000000000000..b605326f2f07
--- /dev/null
+++ b/oox/source/xls/sheetdatacontext.cxx
@@ -0,0 +1,1160 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: sheetdatacontext.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/sheetdatacontext.hxx"
+#include <com/sun/star/table/CellContentType.hpp>
+#include <com/sun/star/table/XCell.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include <com/sun/star/sheet/XArrayFormulaTokens.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/formulaparser.hxx"
+#include "oox/xls/pivottablebuffer.hxx"
+#include "oox/xls/richstringcontext.hxx"
+#include "oox/xls/sharedformulabuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::table::CellContentType_EMPTY;
+using ::com::sun::star::table::XCell;
+using ::com::sun::star::table::XCellRange;
+using ::com::sun::star::sheet::XFormulaTokens;
+using ::com::sun::star::sheet::XArrayFormulaTokens;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::xml::sax::XFastContextHandler;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+// record constants -----------------------------------------------------------
+
+const sal_uInt16 OOBIN_CELL_SHOWPHONETIC = 0x0100;
+
+const sal_uInt8 OOBIN_DATATABLE_ROW = 0x01;
+const sal_uInt8 OOBIN_DATATABLE_2D = 0x02;
+const sal_uInt8 OOBIN_DATATABLE_REF1DEL = 0x04;
+const sal_uInt8 OOBIN_DATATABLE_REF2DEL = 0x08;
+
+const sal_uInt16 OOBIN_ROW_THICKTOP = 0x0001;
+const sal_uInt16 OOBIN_ROW_THICKBOTTOM = 0x0002;
+const sal_uInt16 OOBIN_ROW_COLLAPSED = 0x0800;
+const sal_uInt16 OOBIN_ROW_HIDDEN = 0x1000;
+const sal_uInt16 OOBIN_ROW_CUSTOMHEIGHT = 0x2000;
+const sal_uInt16 OOBIN_ROW_CUSTOMFORMAT = 0x4000;
+
+const sal_uInt8 BIFF_BOOLERR_BOOL = 0;
+const sal_uInt8 BIFF_BOOLERR_ERROR = 1;
+
+const sal_uInt16 BIFF_DATATABLE_ROW = 0x0004;
+const sal_uInt16 BIFF_DATATABLE_2D = 0x0008;
+const sal_uInt16 BIFF_DATATABLE_REF1DEL = 0x0010;
+const sal_uInt16 BIFF_DATATABLE_REF2DEL = 0x0020;
+
+const sal_uInt8 BIFF_FORMULA_RES_STRING = 0; /// Result is a string.
+const sal_uInt8 BIFF_FORMULA_RES_BOOL = 1; /// Result is Boolean value.
+const sal_uInt8 BIFF_FORMULA_RES_ERROR = 2; /// Result is error code.
+const sal_uInt8 BIFF_FORMULA_RES_EMPTY = 3; /// Result is empty cell (BIFF8 only).
+const sal_uInt16 BIFF_FORMULA_SHARED = 0x0008; /// Shared formula cell.
+
+const sal_uInt8 BIFF2_ROW_CUSTOMFORMAT = 0x01;
+const sal_uInt16 BIFF_ROW_DEFAULTHEIGHT = 0x8000;
+const sal_uInt16 BIFF_ROW_HEIGHTMASK = 0x7FFF;
+const sal_uInt32 BIFF_ROW_COLLAPSED = 0x00000010;
+const sal_uInt32 BIFF_ROW_HIDDEN = 0x00000020;
+const sal_uInt32 BIFF_ROW_CUSTOMHEIGHT = 0x00000040;
+const sal_uInt32 BIFF_ROW_CUSTOMFORMAT = 0x00000080;
+const sal_uInt32 BIFF_ROW_THICKTOP = 0x10000000;
+const sal_uInt32 BIFF_ROW_THICKBOTTOM = 0x20000000;
+const sal_uInt32 BIFF_ROW_SHOWPHONETIC = 0x40000000;
+
+const sal_Int32 BIFF_XF_EXTENDED_IDS = 63;
+const sal_uInt8 BIFF2_XF_MASK = 0x3F;
+
+// ----------------------------------------------------------------------------
+
+/** Formula context for cell formulas. */
+class CellFormulaContext : public SimpleFormulaContext
+{
+public:
+ explicit CellFormulaContext(
+ const Reference< XFormulaTokens >& rxTokens,
+ const CellAddress& rCellPos );
+};
+
+CellFormulaContext::CellFormulaContext( const Reference< XFormulaTokens >& rxTokens, const CellAddress& rCellPos ) :
+ SimpleFormulaContext( rxTokens, false, false )
+{
+ setBaseAddress( rCellPos );
+}
+
+// ----------------------------------------------------------------------------
+
+/** Uses the XArrayFormulaTokens interface to set a token sequence. */
+class ArrayFormulaContext : public FormulaContext
+{
+public:
+ explicit ArrayFormulaContext(
+ const Reference< XArrayFormulaTokens >& rxTokens,
+ const CellRangeAddress& rArrayRange );
+
+ virtual void setTokens( const ApiTokenSequence& rTokens );
+
+private:
+ Reference< XArrayFormulaTokens > mxTokens;
+};
+
+ArrayFormulaContext::ArrayFormulaContext(
+ const Reference< XArrayFormulaTokens >& rxTokens, const CellRangeAddress& rArrayRange ) :
+ FormulaContext( false, false ),
+ mxTokens( rxTokens )
+{
+ OSL_ENSURE( mxTokens.is(), "ArrayFormulaContext::ArrayFormulaContext - missing XArrayFormulaTokens interface" );
+ setBaseAddress( CellAddress( rArrayRange.Sheet, rArrayRange.StartColumn, rArrayRange.StartRow ) );
+}
+
+void ArrayFormulaContext::setTokens( const ApiTokenSequence& rTokens )
+{
+ mxTokens->setArrayTokens( rTokens );
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace
+
+// ============================================================================
+
+OoxSheetDataContext::OoxSheetDataContext( const OoxWorksheetFragmentBase& rFragment ) :
+ OoxWorksheetContextBase( rFragment )
+{
+}
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxSheetDataContext::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( sheetData ):
+ return (nElement == XLS_TOKEN( row ));
+ case XLS_TOKEN( row ):
+ return (nElement == XLS_TOKEN( c ));
+ case XLS_TOKEN( c ):
+ return maCurrCell.mxCell.is() &&
+ ((nElement == XLS_TOKEN( v )) ||
+ (nElement == XLS_TOKEN( is )) ||
+ (nElement == XLS_TOKEN( f )));
+ }
+ return false;
+}
+
+Reference< XFastContextHandler > OoxSheetDataContext::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
+{
+ switch( nElement )
+ {
+ case XLS_TOKEN( is ):
+ mxInlineStr.reset( new RichString( *this ) );
+ return new OoxRichStringContext( *this, mxInlineStr );
+ }
+ return this;
+}
+
+void OoxSheetDataContext::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( row ): importRow( rAttribs ); break;
+ case XLS_TOKEN( c ): importCell( rAttribs ); break;
+ case XLS_TOKEN( f ): importFormula( rAttribs ); break;
+ }
+}
+
+void OoxSheetDataContext::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( v ):
+ maCurrCell.maValueStr = rChars;
+ maCurrCell.mbHasValueStr = true;
+ break;
+
+ case XLS_TOKEN( f ):
+ if( maCurrCell.mxCell.is() ) try
+ {
+ switch( maCurrCell.mnFormulaType )
+ {
+ case XML_normal:
+ if( rChars.getLength() > 0 )
+ {
+ Reference< XFormulaTokens > xTokens( maCurrCell.mxCell, UNO_QUERY_THROW );
+ CellFormulaContext aContext( xTokens, maCurrCell.maAddress );
+ getFormulaParser().importFormula( aContext, rChars );
+ }
+ break;
+
+ case XML_array:
+ if( (maCurrCell.maFormulaRef.getLength() > 0) && (rChars.getLength() > 0) )
+ {
+ CellRangeAddress aArrayRange;
+ Reference< XArrayFormulaTokens > xTokens( getCellRange( maCurrCell.maFormulaRef, &aArrayRange ), UNO_QUERY_THROW );
+ ArrayFormulaContext aContext( xTokens, aArrayRange );
+ getFormulaParser().importFormula( aContext, rChars );
+ }
+ break;
+
+ case XML_shared:
+ if( maCurrCell.mnSharedId >= 0 )
+ {
+ if( rChars.getLength() > 0 )
+ getSharedFormulas().importSharedFmla( rChars, maCurrCell.maFormulaRef, maCurrCell.mnSharedId, maCurrCell.maAddress );
+ Reference< XFormulaTokens > xTokens( maCurrCell.mxCell, UNO_QUERY_THROW );
+ ExtCellFormulaContext aContext( *this, xTokens, maCurrCell.maAddress );
+ getSharedFormulas().setSharedFormulaCell( aContext, maCurrCell.mnSharedId );
+ }
+ break;
+
+ case XML_dataTable:
+ if( maCurrCell.maFormulaRef.getLength() > 0 )
+ {
+ CellRangeAddress aTableRange;
+ if( getAddressConverter().convertToCellRange( aTableRange, maCurrCell.maFormulaRef, getSheetIndex(), true ) )
+ setTableOperation( aTableRange, maTableData );
+ }
+ break;
+
+ default:
+ OSL_ENSURE( false, "OoxSheetDataContext::onEndElement - unknown formula type" );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ break;
+
+ case XLS_TOKEN( c ):
+ if( maCurrCell.mxCell.is() )
+ {
+ if( maCurrCell.mxCell->getType() == CellContentType_EMPTY )
+ {
+ if( maCurrCell.mbHasValueStr )
+ {
+ // implemented in WorksheetHelper class
+ setOoxCell( maCurrCell );
+ }
+ else if( (maCurrCell.mnCellType == XML_inlineStr) && mxInlineStr.get() )
+ {
+ // convert font settings
+ mxInlineStr->finalizeImport();
+ // write string to cell
+ Reference< XText > xText( maCurrCell.mxCell, UNO_QUERY );
+ if( xText.is() )
+ mxInlineStr->convert( xText, maCurrCell.mnXfId );
+ }
+ else
+ {
+ // empty cell, update cell type
+ maCurrCell.mnCellType = XML_TOKEN_INVALID;
+ }
+ }
+
+ // store the cell formatting data
+ setCellFormat( maCurrCell );
+ }
+ break;
+ }
+}
+
+bool OoxSheetDataContext::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_SHEETDATA:
+ return (nRecId == OOBIN_ID_ROW);
+ case OOBIN_ID_ROW:
+ return (nRecId == OOBIN_ID_ARRAY) ||
+ (nRecId == OOBIN_ID_CELL_BOOL) ||
+ (nRecId == OOBIN_ID_CELL_BLANK) ||
+ (nRecId == OOBIN_ID_CELL_DOUBLE) ||
+ (nRecId == OOBIN_ID_CELL_ERROR) ||
+ (nRecId == OOBIN_ID_CELL_RK) ||
+ (nRecId == OOBIN_ID_CELL_RSTRING) ||
+ (nRecId == OOBIN_ID_CELL_SI) ||
+ (nRecId == OOBIN_ID_CELL_STRING) ||
+ (nRecId == OOBIN_ID_DATATABLE) ||
+ (nRecId == OOBIN_ID_FORMULA_BOOL) ||
+ (nRecId == OOBIN_ID_FORMULA_DOUBLE) ||
+ (nRecId == OOBIN_ID_FORMULA_ERROR) ||
+ (nRecId == OOBIN_ID_FORMULA_STRING) ||
+ (nRecId == OOBIN_ID_SHAREDFMLA);
+ }
+ return false;
+}
+
+void OoxSheetDataContext::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_ARRAY: importArray( rStrm ); break;
+ case OOBIN_ID_CELL_BOOL: importCellBool( rStrm, false ); break;
+ case OOBIN_ID_CELL_BLANK: importCellBlank( rStrm ); break;
+ case OOBIN_ID_CELL_DOUBLE: importCellDouble( rStrm, false ); break;
+ case OOBIN_ID_CELL_ERROR: importCellError( rStrm, false ); break;
+ case OOBIN_ID_CELL_RK: importCellRk( rStrm ); break;
+ case OOBIN_ID_CELL_RSTRING: importCellRString( rStrm ); break;
+ case OOBIN_ID_CELL_SI: importCellSi( rStrm ); break;
+ case OOBIN_ID_CELL_STRING: importCellString( rStrm, false ); break;
+ case OOBIN_ID_DATATABLE: importDataTable( rStrm ); break;
+ case OOBIN_ID_FORMULA_BOOL: importCellBool( rStrm, true ); break;
+ case OOBIN_ID_FORMULA_DOUBLE: importCellDouble( rStrm, true ); break;
+ case OOBIN_ID_FORMULA_ERROR: importCellError( rStrm, true ); break;
+ case OOBIN_ID_FORMULA_STRING: importCellString( rStrm, true ); break;
+ case OOBIN_ID_ROW: importRow( rStrm ); break;
+ case OOBIN_ID_SHAREDFMLA: importSharedFmla( rStrm ); break;
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void OoxSheetDataContext::importRow( const AttributeList& rAttribs )
+{
+ OoxRowData aData;
+ aData.mnFirstRow = aData.mnLastRow = rAttribs.getInteger( XML_r, -1 );
+ aData.mfHeight = rAttribs.getDouble( XML_ht, -1.0 );
+ aData.mnXfId = rAttribs.getInteger( XML_s, -1 );
+ aData.mnLevel = rAttribs.getInteger( XML_outlineLevel, 0 );
+ aData.mbCustomHeight = rAttribs.getBool( XML_customHeight, false );
+ aData.mbCustomFormat = rAttribs.getBool( XML_customFormat, false );
+ aData.mbShowPhonetic = rAttribs.getBool( XML_ph, false );
+ aData.mbHidden = rAttribs.getBool( XML_hidden, false );
+ aData.mbCollapsed = rAttribs.getBool( XML_collapsed, false );
+ aData.mbThickTop = rAttribs.getBool( XML_thickTop, false );
+ aData.mbThickBottom = rAttribs.getBool( XML_thickBot, false );
+ // set row properties in the current sheet
+ setRowData( aData );
+}
+
+void OoxSheetDataContext::importCell( const AttributeList& rAttribs )
+{
+ maCurrCell.reset();
+ maCurrCell.mxCell = getCell( rAttribs.getString( XML_r ), &maCurrCell.maAddress );
+ maCurrCell.mnCellType = rAttribs.getToken( XML_t, XML_n );
+ maCurrCell.mnXfId = rAttribs.getInteger( XML_s, -1 );
+ maCurrCell.mbShowPhonetic = rAttribs.getBool( XML_ph, false );
+ mxInlineStr.reset();
+
+ if( maCurrCell.mxCell.is() && getPivotTables().isOverlapping( maCurrCell.maAddress ) )
+ // This cell overlaps a pivot table. Skip it.
+ maCurrCell.mxCell.clear();
+}
+
+void OoxSheetDataContext::importFormula( const AttributeList& rAttribs )
+{
+ maCurrCell.maFormulaRef = rAttribs.getString( XML_ref );
+ maCurrCell.mnFormulaType = rAttribs.getToken( XML_t, XML_normal );
+ maCurrCell.mnSharedId = rAttribs.getInteger( XML_si, -1 );
+ maTableData.maRef1 = rAttribs.getString( XML_r1 );
+ maTableData.maRef2 = rAttribs.getString( XML_r2 );
+ maTableData.mb2dTable = rAttribs.getBool( XML_dt2D, false );
+ maTableData.mbRowTable = rAttribs.getBool( XML_dtr, false );
+ maTableData.mbRef1Deleted = rAttribs.getBool( XML_del1, false );
+ maTableData.mbRef2Deleted = rAttribs.getBool( XML_del2, false );
+}
+
+void OoxSheetDataContext::importCellHeader( RecordInputStream& rStrm )
+{
+ maCurrCell.reset();
+ sal_uInt16 nXfId, nFlags;
+ rStrm >> maCurrPos.mnCol >> nXfId >> nFlags;
+
+ maCurrCell.mxCell = getCell( maCurrPos, &maCurrCell.maAddress );
+ maCurrCell.mnXfId = nXfId;
+ maCurrCell.mbShowPhonetic = getFlag( nFlags, OOBIN_CELL_SHOWPHONETIC );
+}
+
+void OoxSheetDataContext::importCellBool( RecordInputStream& rStrm, bool bFormula )
+{
+ importCellHeader( rStrm );
+ maCurrCell.mnCellType = XML_b;
+ if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ {
+ bool bValue = rStrm.readuInt8() != 0;
+ if( bFormula )
+ {
+ importCellFormula( rStrm );
+ }
+ else
+ {
+ setBooleanCell( maCurrCell.mxCell, bValue );
+ // #108770# set 'Standard' number format for all Boolean cells
+ maCurrCell.mnNumFmtId = 0;
+ }
+ }
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellBlank( RecordInputStream& rStrm )
+{
+ importCellHeader( rStrm );
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellDouble( RecordInputStream& rStrm, bool bFormula )
+{
+ importCellHeader( rStrm );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ {
+ double fValue = rStrm.readDouble();
+ if( bFormula )
+ importCellFormula( rStrm );
+ else
+ maCurrCell.mxCell->setValue( fValue );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellError( RecordInputStream& rStrm, bool bFormula )
+{
+ importCellHeader( rStrm );
+ maCurrCell.mnCellType = XML_e;
+ if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ {
+ sal_uInt8 nErrorCode = rStrm.readuInt8();
+ if( bFormula )
+ importCellFormula( rStrm );
+ else
+ setErrorCell( maCurrCell.mxCell, nErrorCode );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellRk( RecordInputStream& rStrm )
+{
+ importCellHeader( rStrm );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ maCurrCell.mxCell->setValue( BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) );
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellRString( RecordInputStream& rStrm )
+{
+ importCellHeader( rStrm );
+ maCurrCell.mnCellType = XML_inlineStr;
+ Reference< XText > xText( maCurrCell.mxCell, UNO_QUERY );
+ if( xText.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ {
+ RichString aString( *this );
+ aString.importString( rStrm, true );
+ aString.finalizeImport();
+ aString.convert( xText, maCurrCell.mnXfId );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellSi( RecordInputStream& rStrm )
+{
+ importCellHeader( rStrm );
+ maCurrCell.mnCellType = XML_s;
+ if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ setSharedStringCell( maCurrCell.mxCell, rStrm.readInt32(), maCurrCell.mnXfId );
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellString( RecordInputStream& rStrm, bool bFormula )
+{
+ importCellHeader( rStrm );
+ maCurrCell.mnCellType = XML_inlineStr;
+ Reference< XText > xText( maCurrCell.mxCell, UNO_QUERY );
+ if( xText.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ {
+ RichString aString( *this );
+ aString.importString( rStrm, false );
+ aString.finalizeImport();
+ if( bFormula )
+ importCellFormula( rStrm );
+ else
+ aString.convert( xText, maCurrCell.mnXfId );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellFormula( RecordInputStream& rStrm )
+{
+ rStrm.skip( 2 );
+ Reference< XFormulaTokens > xTokens( maCurrCell.mxCell, UNO_QUERY );
+ if( xTokens.is() )
+ {
+ ExtCellFormulaContext aContext( *this, xTokens, maCurrCell.maAddress );
+ getFormulaParser().importFormula( aContext, rStrm );
+ }
+}
+
+void OoxSheetDataContext::importRow( RecordInputStream& rStrm )
+{
+ OoxRowData aData;
+
+ sal_uInt16 nHeight, nFlags;
+ rStrm >> maCurrPos.mnRow >> aData.mnXfId >> nHeight >> nFlags;
+
+ // row index is 0-based in OOBIN, but OoxRowData expects 1-based
+ aData.mnFirstRow = aData.mnLastRow = maCurrPos.mnRow + 1;
+ // row height is in twips in OOBIN, convert to points
+ aData.mfHeight = nHeight / 20.0;
+ aData.mnLevel = extractValue< sal_Int32 >( nFlags, 8, 3 );
+ aData.mbCustomHeight = getFlag( nFlags, OOBIN_ROW_CUSTOMHEIGHT );
+ aData.mbCustomFormat = getFlag( nFlags, OOBIN_ROW_CUSTOMFORMAT );
+ // 'show phonetic' missing in OOBIN (bug in Excel 2007)
+ aData.mbHidden = getFlag( nFlags, OOBIN_ROW_HIDDEN );
+ aData.mbCollapsed = getFlag( nFlags, OOBIN_ROW_COLLAPSED );
+ aData.mbThickTop = getFlag( nFlags, OOBIN_ROW_THICKTOP );
+ aData.mbThickBottom = getFlag( nFlags, OOBIN_ROW_THICKBOTTOM );
+ // set row properties in the current sheet
+ setRowData( aData );
+}
+
+void OoxSheetDataContext::importArray( RecordInputStream& rStrm )
+{
+ BinRange aRange;
+ rStrm >> aRange;
+ CellRangeAddress aArrayRange;
+ Reference< XCellRange > xRange = getCellRange( aRange, &aArrayRange );
+ Reference< XArrayFormulaTokens > xTokens( xRange, UNO_QUERY );
+ if( xRange.is() && xTokens.is() )
+ {
+ rStrm.skip( 1 );
+ ArrayFormulaContext aContext( xTokens, aArrayRange );
+ getFormulaParser().importFormula( aContext, rStrm );
+ }
+}
+
+void OoxSheetDataContext::importSharedFmla( RecordInputStream& rStrm )
+{
+ getSharedFormulas().importSharedFmla( rStrm, maCurrCell.maAddress );
+}
+
+void OoxSheetDataContext::importDataTable( RecordInputStream& rStrm )
+{
+ BinRange aRange;
+ rStrm >> aRange;
+ CellRangeAddress aTableRange;
+ if( getAddressConverter().convertToCellRange( aTableRange, aRange, getSheetIndex(), true ) )
+ {
+ OoxDataTableData aTableData;
+ BinAddress aRef1, aRef2;
+ sal_uInt8 nFlags;
+ rStrm >> aRef1 >> aRef2 >> nFlags;
+ aTableData.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false );
+ aTableData.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false );
+ aTableData.mbRowTable = getFlag( nFlags, OOBIN_DATATABLE_ROW );
+ aTableData.mb2dTable = getFlag( nFlags, OOBIN_DATATABLE_2D );
+ aTableData.mbRef1Deleted = getFlag( nFlags, OOBIN_DATATABLE_REF1DEL );
+ aTableData.mbRef2Deleted = getFlag( nFlags, OOBIN_DATATABLE_REF2DEL );
+ setTableOperation( aTableRange, aTableData );
+ }
+}
+
+// ============================================================================
+
+OoxExternalSheetDataContext::OoxExternalSheetDataContext(
+ const OoxWorkbookFragmentBase& rFragment, WorksheetType eSheetType, sal_Int32 nSheet ) :
+ OoxWorksheetContextBase( rFragment, ISegmentProgressBarRef(), eSheetType, nSheet )
+{
+}
+
+// oox.xls.ContextHelper interface --------------------------------------------
+
+bool OoxExternalSheetDataContext::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( sheetData ):
+ return (nElement == XLS_TOKEN( row ));
+ case XLS_TOKEN( row ):
+ return (nElement == XLS_TOKEN( cell ));
+ case XLS_TOKEN( cell ):
+ return (nElement == XLS_TOKEN( v )) && maCurrCell.mxCell.is();
+ }
+ return false;
+}
+
+void OoxExternalSheetDataContext::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( cell ):
+ importCell( rAttribs );
+ break;
+ }
+}
+
+void OoxExternalSheetDataContext::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( v ):
+ maCurrCell.maValueStr = rChars;
+ maCurrCell.mbHasValueStr = true;
+ break;
+
+ case XLS_TOKEN( cell ):
+ if( maCurrCell.mxCell.is() )
+ setOoxCell( maCurrCell, true );
+ break;
+ }
+}
+
+bool OoxExternalSheetDataContext::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_EXTSHEETDATA:
+ return (nRecId == OOBIN_ID_EXTROW);
+ case OOBIN_ID_EXTROW:
+ return (nRecId == OOBIN_ID_EXTCELL_BOOL) ||
+ (nRecId == OOBIN_ID_EXTCELL_DOUBLE) ||
+ (nRecId == OOBIN_ID_EXTCELL_ERROR) ||
+ (nRecId == OOBIN_ID_EXTCELL_STRING);
+ }
+ return false;
+}
+
+void OoxExternalSheetDataContext::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_EXTCELL_BOOL: importExtCellBool( rStrm ); break;
+ case OOBIN_ID_EXTCELL_DOUBLE: importExtCellDouble( rStrm ); break;
+ case OOBIN_ID_EXTCELL_ERROR: importExtCellError( rStrm ); break;
+ case OOBIN_ID_EXTCELL_STRING: importExtCellString( rStrm ); break;
+ case OOBIN_ID_EXTROW: rStrm >> maCurrPos.mnRow; break;
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void OoxExternalSheetDataContext::importCell( const AttributeList& rAttribs )
+{
+ maCurrCell.reset();
+ maCurrCell.mxCell = getCell( rAttribs.getString( XML_r ), &maCurrCell.maAddress );
+ maCurrCell.mnCellType = rAttribs.getToken( XML_t, XML_n );
+}
+
+void OoxExternalSheetDataContext::importCellHeader( RecordInputStream& rStrm )
+{
+ maCurrCell.reset();
+ rStrm >> maCurrPos.mnCol;
+ maCurrCell.mxCell = getCell( maCurrPos, &maCurrCell.maAddress );
+}
+
+void OoxExternalSheetDataContext::importExtCellBool( RecordInputStream& rStrm )
+{
+ importCellHeader( rStrm );
+ if( maCurrCell.mxCell.is() )
+ setBooleanCell( maCurrCell.mxCell, rStrm.readuInt8() != 0 );
+}
+
+void OoxExternalSheetDataContext::importExtCellDouble( RecordInputStream& rStrm )
+{
+ importCellHeader( rStrm );
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( rStrm.readDouble() );
+}
+
+void OoxExternalSheetDataContext::importExtCellError( RecordInputStream& rStrm )
+{
+ importCellHeader( rStrm );
+ if( maCurrCell.mxCell.is() )
+ setErrorCell( maCurrCell.mxCell, rStrm.readuInt8() );
+}
+
+void OoxExternalSheetDataContext::importExtCellString( RecordInputStream& rStrm )
+{
+ importCellHeader( rStrm );
+ if( maCurrCell.mxCell.is() )
+ setStringCell( maCurrCell.mxCell, rStrm.readString(), true );
+}
+
+// ============================================================================
+// ============================================================================
+
+BiffSheetDataContext::BiffSheetDataContext( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper ),
+ mnBiff2XfId( 0 )
+{
+ mnArrayIgnoreSize = (getBiff() == BIFF2) ? 1 : ((getBiff() <= BIFF4) ? 2 : 6);
+ switch( getBiff() )
+ {
+ case BIFF2:
+ mnFormulaIgnoreSize = 9; // double formula result, 1 byte flags
+ mnArrayIgnoreSize = 1; // recalc-always flag
+ break;
+ case BIFF3:
+ case BIFF4:
+ mnFormulaIgnoreSize = 10; // double formula result, 2 byte flags
+ mnArrayIgnoreSize = 2; // 2 byte flags
+ break;
+ case BIFF5:
+ case BIFF8:
+ mnFormulaIgnoreSize = 14; // double formula result, 2 byte flags, 4 bytes nothing
+ mnArrayIgnoreSize = 6; // 2 byte flags, 4 bytes nothing
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+}
+
+void BiffSheetDataContext::importRecord( BiffInputStream& rStrm )
+{
+ sal_uInt16 nRecId = rStrm.getRecId();
+ switch( nRecId )
+ {
+ // records in all BIFF versions
+ case BIFF2_ID_ARRAY: // #i72713#
+ case BIFF3_ID_ARRAY: importArray( rStrm ); break;
+ case BIFF2_ID_BLANK:
+ case BIFF3_ID_BLANK: importBlank( rStrm ); break;
+ case BIFF2_ID_BOOLERR:
+ case BIFF3_ID_BOOLERR: importBoolErr( rStrm ); break;
+ case BIFF2_ID_INTEGER: importInteger( rStrm ); break;
+ case BIFF_ID_IXFE: rStrm >> mnBiff2XfId; break;
+ case BIFF2_ID_LABEL:
+ case BIFF3_ID_LABEL: importLabel( rStrm ); break;
+ case BIFF2_ID_NUMBER:
+ case BIFF3_ID_NUMBER: importNumber( rStrm ); break;
+ case BIFF_ID_RK: importRk( rStrm ); break;
+
+ // BIFF specific records
+ default: switch( getBiff() )
+ {
+ case BIFF2: switch( nRecId )
+ {
+ case BIFF2_ID_DATATABLE: importDataTable( rStrm ); break;
+ case BIFF2_ID_DATATABLE2: importDataTable( rStrm ); break;
+ case BIFF2_ID_FORMULA: importFormula( rStrm ); break;
+ case BIFF2_ID_ROW: importRow( rStrm ); break;
+ }
+ break;
+
+ case BIFF3: switch( nRecId )
+ {
+ case BIFF3_ID_DATATABLE: importDataTable( rStrm ); break;
+ case BIFF3_ID_FORMULA: importFormula( rStrm ); break;
+ case BIFF3_ID_ROW: importRow( rStrm ); break;
+ }
+ break;
+
+ case BIFF4: switch( nRecId )
+ {
+ case BIFF3_ID_DATATABLE: importDataTable( rStrm ); break;
+ case BIFF4_ID_FORMULA: importFormula( rStrm ); break;
+ case BIFF3_ID_ROW: importRow( rStrm ); break;
+ }
+ break;
+
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF3_ID_DATATABLE: importDataTable( rStrm ); break;
+ case BIFF3_ID_FORMULA:
+ case BIFF4_ID_FORMULA:
+ case BIFF5_ID_FORMULA: importFormula( rStrm ); break;
+ case BIFF_ID_MULTBLANK: importMultBlank( rStrm ); break;
+ case BIFF_ID_MULTRK: importMultRk( rStrm ); break;
+ case BIFF3_ID_ROW: importRow( rStrm ); break;
+ case BIFF_ID_RSTRING: importLabel( rStrm ); break;
+ case BIFF_ID_SHAREDFMLA: importSharedFmla( rStrm ); break;
+ }
+ break;
+
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF3_ID_DATATABLE: importDataTable( rStrm ); break;
+ case BIFF3_ID_FORMULA:
+ case BIFF4_ID_FORMULA:
+ case BIFF5_ID_FORMULA: importFormula( rStrm ); break;
+ case BIFF_ID_LABELSST: importLabelSst( rStrm ); break;
+ case BIFF_ID_MULTBLANK: importMultBlank( rStrm ); break;
+ case BIFF_ID_MULTRK: importMultRk( rStrm ); break;
+ case BIFF3_ID_ROW: importRow( rStrm ); break;
+ case BIFF_ID_RSTRING: importLabel( rStrm ); break;
+ case BIFF_ID_SHAREDFMLA: importSharedFmla( rStrm ); break;
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void BiffSheetDataContext::setCurrCell( const BinAddress& rAddr )
+{
+ maCurrCell.reset();
+ maCurrCell.mxCell = getCell( rAddr, &maCurrCell.maAddress );
+}
+
+void BiffSheetDataContext::importXfId( BiffInputStream& rStrm, bool bBiff2 )
+{
+ if( bBiff2 )
+ {
+ sal_uInt8 nBiff2XfId;
+ rStrm >> nBiff2XfId;
+ rStrm.skip( 2 );
+ maCurrCell.mnXfId = nBiff2XfId & BIFF2_XF_MASK;
+ if( maCurrCell.mnXfId == BIFF_XF_EXTENDED_IDS )
+ maCurrCell.mnXfId = mnBiff2XfId;
+ }
+ else
+ {
+ maCurrCell.mnXfId = rStrm.readuInt16();
+ }
+}
+
+void BiffSheetDataContext::importCellHeader( BiffInputStream& rStrm, bool bBiff2 )
+{
+ BinAddress aAddr;
+ rStrm >> aAddr;
+ setCurrCell( aAddr );
+ importXfId( rStrm, bBiff2 );
+}
+
+void BiffSheetDataContext::importBlank( BiffInputStream& rStrm )
+{
+ importCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BLANK );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importBoolErr( BiffInputStream& rStrm )
+{
+ importCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BOOLERR );
+ if( maCurrCell.mxCell.is() )
+ {
+ sal_uInt8 nValue, nType;
+ rStrm >> nValue >> nType;
+ switch( nType )
+ {
+ case BIFF_BOOLERR_BOOL:
+ maCurrCell.mnCellType = XML_b;
+ setBooleanCell( maCurrCell.mxCell, nValue != 0 );
+ // #108770# set 'Standard' number format for all Boolean cells
+ maCurrCell.mnNumFmtId = 0;
+ break;
+ case BIFF_BOOLERR_ERROR:
+ maCurrCell.mnCellType = XML_e;
+ setErrorCell( maCurrCell.mxCell, nValue );
+ break;
+ default:
+ OSL_ENSURE( false, "BiffSheetDataContext::importBoolErr - unknown cell type" );
+ }
+ }
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importFormula( BiffInputStream& rStrm )
+{
+ importCellHeader( rStrm, getBiff() == BIFF2 );
+ maCurrCell.mnCellType = XML_n;
+ Reference< XFormulaTokens > xTokens( maCurrCell.mxCell, UNO_QUERY );
+ if( xTokens.is() )
+ {
+ rStrm.skip( mnFormulaIgnoreSize );
+ ExtCellFormulaContext aContext( *this, xTokens, maCurrCell.maAddress );
+ getFormulaParser().importFormula( aContext, rStrm );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importInteger( BiffInputStream& rStrm )
+{
+ importCellHeader( rStrm, true );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( rStrm.readuInt16() );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importLabel( BiffInputStream& rStrm )
+{
+ bool bBiff2Xf = rStrm.getRecId() == BIFF2_ID_LABEL;
+ importCellHeader( rStrm, bBiff2Xf );
+ maCurrCell.mnCellType = XML_inlineStr;
+ Reference< XText > xText( maCurrCell.mxCell, UNO_QUERY );
+ if( xText.is() )
+ {
+ /* the deep secrets of BIFF type and record identifier...
+ record id BIFF XF type String type
+ 0x0004 2-7 3 byte 8-bit length, byte string
+ 0x0004 8 3 byte 16-bit length, unicode string
+ 0x0204 2-7 2 byte 16-bit length, byte string
+ 0x0204 8 2 byte 16-bit length, unicode string */
+
+ RichString aString( *this );
+ if( getBiff() == BIFF8 )
+ {
+ aString.importUniString( rStrm );
+ }
+ else
+ {
+ // #i63105# use text encoding from FONT record
+ rtl_TextEncoding eTextEnc = getTextEncoding();
+ if( const Font* pFont = getStyles().getFontFromCellXf( maCurrCell.mnXfId ).get() )
+ eTextEnc = pFont->getFontEncoding();
+ BiffStringFlags nFlags = bBiff2Xf ? BIFF_STR_8BITLENGTH : BIFF_STR_DEFAULT;
+ setFlag( nFlags, BIFF_STR_EXTRAFONTS, rStrm.getRecId() == BIFF_ID_RSTRING );
+ aString.importByteString( rStrm, eTextEnc, nFlags );
+ }
+ aString.finalizeImport();
+ aString.convert( xText, maCurrCell.mnXfId );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importLabelSst( BiffInputStream& rStrm )
+{
+ importCellHeader( rStrm, false );
+ maCurrCell.mnCellType = XML_s;
+ if( maCurrCell.mxCell.is() )
+ setSharedStringCell( maCurrCell.mxCell, rStrm.readInt32(), maCurrCell.mnXfId );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importMultBlank( BiffInputStream& rStrm )
+{
+ BinAddress aAddr;
+ for( rStrm >> aAddr; rStrm.getRecLeft() > 2; ++aAddr.mnCol )
+ {
+ setCurrCell( aAddr );
+ importXfId( rStrm, false );
+ setCellFormat( maCurrCell );
+ }
+}
+
+void BiffSheetDataContext::importMultRk( BiffInputStream& rStrm )
+{
+ BinAddress aAddr;
+ for( rStrm >> aAddr; rStrm.getRecLeft() > 2; ++aAddr.mnCol )
+ {
+ setCurrCell( aAddr );
+ maCurrCell.mnCellType = XML_n;
+ importXfId( rStrm, false );
+ sal_Int32 nRkValue = rStrm.readInt32();
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( BiffHelper::calcDoubleFromRk( nRkValue ) );
+ setCellFormat( maCurrCell );
+ }
+}
+
+void BiffSheetDataContext::importNumber( BiffInputStream& rStrm )
+{
+ importCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_NUMBER );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( rStrm.readDouble() );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importRk( BiffInputStream& rStrm )
+{
+ importCellHeader( rStrm, false );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importRow( BiffInputStream& rStrm )
+{
+ OoxRowData aData;
+
+ sal_uInt16 nRow, nHeight;
+ rStrm >> nRow;
+ rStrm.skip( 4 );
+ rStrm >> nHeight;
+ if( getBiff() == BIFF2 )
+ {
+ aData.mbCustomFormat = rStrm.skip( 2 ).readuInt8() == BIFF2_ROW_CUSTOMFORMAT;
+ if( aData.mbCustomFormat )
+ aData.mnXfId = rStrm.skip( 5 ).readuInt16();
+ }
+ else
+ {
+ sal_uInt32 nFlags = rStrm.skip( 4 ).readuInt32();
+ aData.mnXfId = extractValue< sal_Int32 >( nFlags, 16, 12 );
+ aData.mnLevel = extractValue< sal_Int32 >( nFlags, 0, 3 );
+ aData.mbCustomFormat = getFlag( nFlags, BIFF_ROW_CUSTOMFORMAT );
+ aData.mbCustomHeight = getFlag( nFlags, BIFF_ROW_CUSTOMHEIGHT );
+ aData.mbShowPhonetic = getFlag( nFlags, BIFF_ROW_SHOWPHONETIC );
+ aData.mbHidden = getFlag( nFlags, BIFF_ROW_HIDDEN );
+ aData.mbCollapsed = getFlag( nFlags, BIFF_ROW_COLLAPSED );
+ aData.mbThickTop = getFlag( nFlags, BIFF_ROW_THICKTOP );
+ aData.mbThickBottom = getFlag( nFlags, BIFF_ROW_THICKBOTTOM );
+ }
+
+ // row index is 0-based in BIFF, but OoxRowData expects 1-based
+ aData.mnFirstRow = aData.mnLastRow = nRow + 1;
+ // row height is in twips in BIFF, convert to points
+ aData.mfHeight = (nHeight & BIFF_ROW_HEIGHTMASK) / 20.0;
+ // set row properties in the current sheet
+ setRowData( aData );
+}
+
+void BiffSheetDataContext::importArray( BiffInputStream& rStrm )
+{
+ BinRange aRange;
+ aRange.read( rStrm, false ); // columns always 8-bit
+ CellRangeAddress aArrayRange;
+ Reference< XCellRange > xRange = getCellRange( aRange, &aArrayRange );
+ Reference< XArrayFormulaTokens > xTokens( xRange, UNO_QUERY );
+ if( xRange.is() && xTokens.is() )
+ {
+ rStrm.skip( mnArrayIgnoreSize );
+ ArrayFormulaContext aContext( xTokens, aArrayRange );
+ getFormulaParser().importFormula( aContext, rStrm );
+ }
+}
+
+void BiffSheetDataContext::importSharedFmla( BiffInputStream& rStrm )
+{
+ getSharedFormulas().importSharedFmla( rStrm, maCurrCell.maAddress );
+}
+
+void BiffSheetDataContext::importDataTable( BiffInputStream& rStrm )
+{
+ BinRange aRange;
+ aRange.read( rStrm, false ); // columns always 8-bit
+ CellRangeAddress aTableRange;
+ if( getAddressConverter().convertToCellRange( aTableRange, aRange, getSheetIndex(), true ) )
+ {
+ OoxDataTableData aTableData;
+ BinAddress aRef1, aRef2;
+ switch( rStrm.getRecId() )
+ {
+ case BIFF2_ID_DATATABLE:
+ rStrm.skip( 1 );
+ aTableData.mbRowTable = rStrm.readuInt8() != 0;
+ aTableData.mb2dTable = false;
+ rStrm >> aRef1;
+ break;
+ case BIFF2_ID_DATATABLE2:
+ rStrm.skip( 2 );
+ aTableData.mb2dTable = true;
+ rStrm >> aRef1 >> aRef2;
+ break;
+ case BIFF3_ID_DATATABLE:
+ {
+ sal_uInt16 nFlags;
+ rStrm >> nFlags >> aRef1 >> aRef2;
+ aTableData.mbRowTable = getFlag( nFlags, BIFF_DATATABLE_ROW );
+ aTableData.mb2dTable = getFlag( nFlags, BIFF_DATATABLE_2D );
+ aTableData.mbRef1Deleted = getFlag( nFlags, BIFF_DATATABLE_REF1DEL );
+ aTableData.mbRef2Deleted = getFlag( nFlags, BIFF_DATATABLE_REF2DEL );
+ }
+ break;
+ default:
+ OSL_ENSURE( false, "BiffSheetDataContext::importDataTable - unknown record id" );
+ }
+ aTableData.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false );
+ aTableData.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false );
+ setTableOperation( aTableRange, aTableData );
+ }
+}
+
+// ============================================================================
+
+BiffExternalSheetDataContext::BiffExternalSheetDataContext(
+ const WorkbookHelper& rHelper, WorksheetType eSheetType, sal_Int32 nSheet ) :
+ WorksheetHelperRoot( rHelper, ISegmentProgressBarRef(), eSheetType, nSheet )
+{
+}
+
+void BiffExternalSheetDataContext::importCrn( BiffInputStream& rStrm )
+{
+ sal_uInt8 nCol2, nCol1;
+ sal_uInt16 nRow;
+ rStrm >> nCol2 >> nCol1 >> nRow;
+ bool bLoop = true;
+ for( BinAddress aAddr( nCol1, nRow ); bLoop && rStrm.isValid() && (aAddr.mnCol <= nCol2); ++aAddr.mnCol )
+ {
+ Reference< XCell > xCell = getCell( aAddr );
+ bLoop = xCell.is();
+ if( bLoop ) switch( rStrm.readuInt8() )
+ {
+ case BIFF_DATATYPE_EMPTY:
+ rStrm.skip( 8 );
+ setEmptyStringCell( xCell );
+ break;
+ case BIFF_DATATYPE_DOUBLE:
+ xCell->setValue( rStrm.readDouble() );
+ break;
+ case BIFF_DATATYPE_STRING:
+ {
+ OUString aText = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteString( false, getTextEncoding() );
+ setStringCell( xCell, aText, true );
+ }
+ break;
+ case BIFF_DATATYPE_BOOL:
+ setBooleanCell( xCell, rStrm.readuInt8() != 0 );
+ rStrm.skip( 7 );
+ break;
+ case BIFF_DATATYPE_ERROR:
+ setErrorCell( xCell, rStrm.readuInt8() );
+ rStrm.skip( 7 );
+ break;
+ default:
+ OSL_ENSURE( false, "BiffExternalSheetDataContext::importCrn - unknown data type" );
+ bLoop = false;
+ }
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/stylesbuffer.cxx b/oox/source/xls/stylesbuffer.cxx
new file mode 100644
index 000000000000..66b1ea9e8035
--- /dev/null
+++ b/oox/source/xls/stylesbuffer.cxx
@@ -0,0 +1,3214 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: stylesbuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/stylesbuffer.hxx"
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/XDevice.hpp>
+#include <com/sun/star/awt/XFont2.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <rtl/tencinfo.h>
+#include <rtl/ustrbuf.hxx>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/condformatbuffer.hxx"
+#include "oox/xls/ooxtokens.hxx"
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::awt::FontDescriptor;
+using ::com::sun::star::awt::XDevice;
+using ::com::sun::star::awt::XFont2;
+using ::com::sun::star::table::BorderLine;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::style::XStyle;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+// OOXML constants ------------------------------------------------------------
+
+// OOX predefined color indexes (also used in BIFF3-BIFF8)
+const sal_Int32 OOX_COLOR_USEROFFSET = 0; /// First user defined color in palette (OOX).
+const sal_Int32 BIFF_COLOR_USEROFFSET = 8; /// First user defined color in palette (BIFF).
+
+// OOX font family (also used in BIFF)
+const sal_Int32 OOX_FONTFAMILY_NONE = 0;
+const sal_Int32 OOX_FONTFAMILY_ROMAN = 1;
+const sal_Int32 OOX_FONTFAMILY_SWISS = 2;
+const sal_Int32 OOX_FONTFAMILY_MODERN = 3;
+const sal_Int32 OOX_FONTFAMILY_SCRIPT = 4;
+const sal_Int32 OOX_FONTFAMILY_DECORATIVE = 5;
+
+// OOX font charset (also used in BIFF)
+const sal_Int32 OOX_FONTCHARSET_UNUSED = -1;
+const sal_Int32 OOX_FONTCHARSET_ANSI = 0;
+
+// OOX cell text direction (also used in BIFF)
+const sal_Int32 OOX_XF_TEXTDIR_CONTEXT = 0;
+const sal_Int32 OOX_XF_TEXTDIR_LTR = 1;
+const sal_Int32 OOX_XF_TEXTDIR_RTL = 2;
+
+// OOX cell rotation (also used in BIFF)
+const sal_Int32 OOX_XF_ROTATION_NONE = 0;
+const sal_Int32 OOX_XF_ROTATION_90CCW = 90;
+const sal_Int32 OOX_XF_ROTATION_90CW = 180;
+const sal_Int32 OOX_XF_ROTATION_STACKED = 255;
+
+// OOX cell indentation
+const sal_Int32 OOX_XF_INDENT_NONE = 0;
+
+// OOX built-in cell styles (also used in BIFF)
+const sal_Int32 OOX_STYLE_NORMAL = 0; /// Default cell style.
+const sal_Int32 OOX_STYLE_ROWLEVEL = 1; /// RowLevel_x cell style.
+const sal_Int32 OOX_STYLE_COLLEVEL = 2; /// ColLevel_x cell style.
+
+const sal_Int32 OOX_STYLE_LEVELCOUNT = 7; /// Number of outline level styles.
+
+// OOBIN constants ------------------------------------------------------------
+
+// OOBIN color types
+const sal_uInt8 OOBIN_COLOR_AUTO = 1;
+const sal_uInt8 OOBIN_COLOR_INDEXED = 3;
+const sal_uInt8 OOBIN_COLOR_RGB = 5;
+const sal_uInt8 OOBIN_COLOR_THEME = 7;
+
+// OOBIN diagonal borders
+const sal_uInt8 OOBIN_BORDER_DIAG_TLBR = 0x01; /// Top-left to bottom-right.
+const sal_uInt8 OOBIN_BORDER_DIAG_BLTR = 0x02; /// Bottom-left to top-right.
+
+// OOBIN gradient fill
+const sal_Int32 OOBIN_FILL_GRADIENT = 40;
+
+// OOBIN XF flags
+const sal_uInt32 OOBIN_XF_WRAPTEXT = 0x00400000;
+const sal_uInt32 OOBIN_XF_JUSTLASTLINE = 0x00800000;
+const sal_uInt32 OOBIN_XF_SHRINK = 0x01000000;
+const sal_uInt32 OOBIN_XF_LOCKED = 0x10000000;
+const sal_uInt32 OOBIN_XF_HIDDEN = 0x20000000;
+
+// OOBIN XF attribute used flags
+const sal_uInt16 OOBIN_XF_NUMFMT_USED = 0x0001;
+const sal_uInt16 OOBIN_XF_FONT_USED = 0x0002;
+const sal_uInt16 OOBIN_XF_ALIGN_USED = 0x0004;
+const sal_uInt16 OOBIN_XF_BORDER_USED = 0x0008;
+const sal_uInt16 OOBIN_XF_AREA_USED = 0x0010;
+const sal_uInt16 OOBIN_XF_PROT_USED = 0x0020;
+
+// OOBIN DXF constants
+const sal_uInt16 OOBIN_DXF_FILL_PATTERN = 0;
+const sal_uInt16 OOBIN_DXF_FILL_FGCOLOR = 1;
+const sal_uInt16 OOBIN_DXF_FILL_BGCOLOR = 2;
+const sal_uInt16 OOBIN_DXF_FILL_GRADIENT = 3;
+const sal_uInt16 OOBIN_DXF_FILL_STOP = 4;
+const sal_uInt16 OOBIN_DXF_FONT_COLOR = 5;
+const sal_uInt16 OOBIN_DXF_BORDER_TOP = 6;
+const sal_uInt16 OOBIN_DXF_BORDER_BOTTOM = 7;
+const sal_uInt16 OOBIN_DXF_BORDER_LEFT = 8;
+const sal_uInt16 OOBIN_DXF_BORDER_RIGHT = 9;
+const sal_uInt16 OOBIN_DXF_BORDER_DIAG = 10;
+const sal_uInt16 OOBIN_DXF_BORDER_VERT = 11;
+const sal_uInt16 OOBIN_DXF_BORDER_HOR = 12;
+const sal_uInt16 OOBIN_DXF_BORDER_DIAGUP = 13;
+const sal_uInt16 OOBIN_DXF_BORDER_DIAGDOWN = 14;
+const sal_uInt16 OOBIN_DXF_FONT_NAME = 24;
+const sal_uInt16 OOBIN_DXF_FONT_WEIGHT = 25;
+const sal_uInt16 OOBIN_DXF_FONT_UNDERLINE = 26;
+const sal_uInt16 OOBIN_DXF_FONT_ESCAPEMENT = 27;
+const sal_uInt16 OOBIN_DXF_FONT_ITALIC = 28;
+const sal_uInt16 OOBIN_DXF_FONT_STRIKE = 29;
+const sal_uInt16 OOBIN_DXF_FONT_OUTLINE = 30;
+const sal_uInt16 OOBIN_DXF_FONT_SHADOW = 31;
+const sal_uInt16 OOBIN_DXF_FONT_CONDENSE = 32;
+const sal_uInt16 OOBIN_DXF_FONT_EXTEND = 33;
+const sal_uInt16 OOBIN_DXF_FONT_HEIGHT = 36;
+const sal_uInt16 OOBIN_DXF_FONT_SCHEME = 37;
+const sal_uInt16 OOBIN_DXF_NUMFMT_CODE = 38;
+const sal_uInt16 OOBIN_DXF_NUMFMT_ID = 41;
+
+// OOBIN CELLSTYLE flags
+const sal_uInt16 OOBIN_CELLSTYLE_BUILTIN = 0x0001;
+const sal_uInt16 OOBIN_CELLSTYLE_HIDDEN = 0x0002;
+const sal_uInt16 OOBIN_CELLSTYLE_CUSTOM = 0x0004;
+
+// OOBIN and BIFF constants ---------------------------------------------------
+
+// BIFF predefined color indexes
+const sal_uInt16 BIFF2_COLOR_BLACK = 0; /// Black (text) in BIFF2.
+const sal_uInt16 BIFF2_COLOR_WHITE = 1; /// White (background) in BIFF2.
+
+// BIFF font flags, also used in OOBIN
+const sal_uInt16 BIFF_FONTFLAG_BOLD = 0x0001;
+const sal_uInt16 BIFF_FONTFLAG_ITALIC = 0x0002;
+const sal_uInt16 BIFF_FONTFLAG_UNDERLINE = 0x0004;
+const sal_uInt16 BIFF_FONTFLAG_STRIKEOUT = 0x0008;
+const sal_uInt16 BIFF_FONTFLAG_OUTLINE = 0x0010;
+const sal_uInt16 BIFF_FONTFLAG_SHADOW = 0x0020;
+const sal_uInt16 BIFF_FONTFLAG_CONDENSE = 0x0040;
+
+// BIFF font weight
+const sal_uInt16 BIFF_FONTWEIGHT_BOLD = 450;
+
+// BIFF font underline, also used in OOBIN
+const sal_uInt8 BIFF_FONTUNDERL_NONE = 0;
+const sal_uInt8 BIFF_FONTUNDERL_SINGLE = 1;
+const sal_uInt8 BIFF_FONTUNDERL_DOUBLE = 2;
+const sal_uInt8 BIFF_FONTUNDERL_SINGLE_ACC = 33;
+const sal_uInt8 BIFF_FONTUNDERL_DOUBLE_ACC = 34;
+
+// BIFF XF flags
+const sal_uInt16 BIFF_XF_LOCKED = 0x0001;
+const sal_uInt16 BIFF_XF_HIDDEN = 0x0002;
+const sal_uInt16 BIFF_XF_STYLE = 0x0004;
+const sal_uInt16 BIFF_XF_STYLEPARENT = 0x0FFF; /// Syles don't have a parent.
+const sal_uInt16 BIFF_XF_WRAPTEXT = 0x0008; /// Automatic line break.
+const sal_uInt16 BIFF_XF_JUSTLASTLINE = 0x0080;
+const sal_uInt16 BIFF_XF_SHRINK = 0x0010; /// Shrink to fit into cell.
+const sal_uInt16 BIFF_XF_MERGE = 0x0020;
+
+// BIFF XF attribute used flags
+const sal_uInt8 BIFF_XF_NUMFMT_USED = 0x01;
+const sal_uInt8 BIFF_XF_FONT_USED = 0x02;
+const sal_uInt8 BIFF_XF_ALIGN_USED = 0x04;
+const sal_uInt8 BIFF_XF_BORDER_USED = 0x08;
+const sal_uInt8 BIFF_XF_AREA_USED = 0x10;
+const sal_uInt8 BIFF_XF_PROT_USED = 0x20;
+
+// BIFF XF text orientation
+const sal_uInt8 BIFF_XF_ORIENT_NONE = 0;
+const sal_uInt8 BIFF_XF_ORIENT_STACKED = 1; /// Stacked top to bottom.
+const sal_uInt8 BIFF_XF_ORIENT_90CCW = 2; /// 90 degr. counterclockwise.
+const sal_uInt8 BIFF_XF_ORIENT_90CW = 3; /// 90 degr. clockwise.
+
+// BIFF XF line styles
+const sal_uInt8 BIFF_LINE_NONE = 0;
+const sal_uInt8 BIFF_LINE_THIN = 1;
+
+// BIFF XF patterns
+const sal_uInt8 BIFF_PATT_NONE = 0;
+const sal_uInt8 BIFF_PATT_125 = 17;
+
+// BIFF2 XF flags
+const sal_uInt8 BIFF2_XF_VALFMT_MASK = 0x3F;
+const sal_uInt8 BIFF2_XF_LOCKED = 0x40;
+const sal_uInt8 BIFF2_XF_HIDDEN = 0x80;
+const sal_uInt8 BIFF2_XF_LEFTLINE = 0x08;
+const sal_uInt8 BIFF2_XF_RIGHTLINE = 0x10;
+const sal_uInt8 BIFF2_XF_TOPLINE = 0x20;
+const sal_uInt8 BIFF2_XF_BOTTOMLINE = 0x40;
+const sal_uInt8 BIFF2_XF_BACKGROUND = 0x80;
+
+// BIFF8 diagonal borders
+const sal_uInt32 BIFF_XF_DIAG_TLBR = 0x40000000; /// Top-left to bottom-right.
+const sal_uInt32 BIFF_XF_DIAG_BLTR = 0x80000000; /// Bottom-left to top-right.
+
+// BIFF STYLE flags
+const sal_uInt16 BIFF_STYLE_BUILTIN = 0x8000;
+const sal_uInt16 BIFF_STYLE_XFMASK = 0x0FFF;
+
+// BIFF conditional formatting
+const sal_uInt32 BIFF_CFRULE_BORDER_LEFT = 0x00000400;
+const sal_uInt32 BIFF_CFRULE_BORDER_RIGHT = 0x00000800;
+const sal_uInt32 BIFF_CFRULE_BORDER_TOP = 0x00001000;
+const sal_uInt32 BIFF_CFRULE_BORDER_BOTTOM = 0x00002000;
+const sal_uInt32 BIFF_CFRULE_FILL_PATTERN = 0x00010000;
+const sal_uInt32 BIFF_CFRULE_FILL_PATTCOLOR = 0x00020000;
+const sal_uInt32 BIFF_CFRULE_FILL_FILLCOLOR = 0x00040000;
+const sal_uInt32 BIFF_CFRULE_FONTBLOCK = 0x04000000;
+const sal_uInt32 BIFF_CFRULE_ALIGNBLOCK = 0x08000000;
+const sal_uInt32 BIFF_CFRULE_BORDERBLOCK = 0x10000000;
+const sal_uInt32 BIFF_CFRULE_FILLBLOCK = 0x20000000;
+const sal_uInt32 BIFF_CFRULE_PROTBLOCK = 0x40000000;
+
+const sal_uInt32 BIFF_CFRULE_FONT_STYLE = 0x00000002; /// Font posture or weight modified?
+const sal_uInt32 BIFF_CFRULE_FONT_OUTLINE = 0x00000008; /// Font outline modified?
+const sal_uInt32 BIFF_CFRULE_FONT_SHADOW = 0x00000010; /// Font shadow modified?
+const sal_uInt32 BIFF_CFRULE_FONT_STRIKEOUT = 0x00000080; /// Font cancellation modified?
+const sal_uInt32 BIFF_CFRULE_FONT_UNDERL = 0x00000001; /// Font underline type modified?
+const sal_uInt32 BIFF_CFRULE_FONT_ESCAPEM = 0x00000001; /// Font escapement type modified?
+
+// ----------------------------------------------------------------------------
+
+sal_Int32 lclGetRgbColor( sal_uInt8 nR, sal_uInt8 nG, sal_uInt8 nB, sal_uInt8 nA )
+{
+ sal_Int32 nValue = nA;
+ nValue <<= 8;
+ nValue |= nR;
+ nValue <<= 8;
+ nValue |= nG;
+ nValue <<= 8;
+ nValue |= nB;
+ return nValue;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+OoxColor::OoxColor() :
+ mfTint( 0.0 ),
+ mnType( XML_auto ),
+ mnValue( 0 )
+{
+}
+
+OoxColor::OoxColor( sal_Int32 nType, sal_Int32 nValue, double fTint ) :
+ mfTint( fTint ),
+ mnType( nType ),
+ mnValue( nValue )
+{
+}
+
+bool OoxColor::isAuto() const
+{
+ return mnType == XML_auto;
+}
+
+void OoxColor::set( sal_Int32 nType, sal_Int32 nValue, double fTint )
+{
+ mfTint = fTint;
+ mnType = nType;
+ mnValue = nValue;
+}
+
+void OoxColor::importColor( const AttributeList& rAttribs )
+{
+ mfTint = rAttribs.getDouble( XML_tint, 0.0 );
+ if( rAttribs.getBool( XML_auto, false ) )
+ {
+ mnType = XML_auto;
+ }
+ else if( rAttribs.hasAttribute( XML_rgb ) )
+ {
+ mnType = XML_rgb;
+ mnValue = rAttribs.getHex( XML_rgb, API_RGB_TRANSPARENT );
+ }
+ else if( rAttribs.hasAttribute( XML_theme ) )
+ {
+ mnType = XML_theme;
+ mnValue = rAttribs.getInteger( XML_theme, -1 );
+ }
+ else if( rAttribs.hasAttribute( XML_indexed ) )
+ {
+ mnType = XML_indexed;
+ mnValue = rAttribs.getInteger( XML_indexed, -1 );
+ }
+ else
+ {
+ mnType = XML_auto;
+ OSL_ENSURE( false, "OoxColor::importColor - unknown color type" );
+ }
+}
+
+void OoxColor::importColor( RecordInputStream& rStrm )
+{
+ switch( rStrm.readuInt8() )
+ {
+ case OOBIN_COLOR_AUTO:
+ mnType = XML_auto;
+ mfTint = 0.0;
+ rStrm.skip( 7 );
+ break;
+ case OOBIN_COLOR_INDEXED:
+ mnType = XML_indexed;
+ mnValue = rStrm.readuInt8();
+ mfTint = 0.0;
+ rStrm.skip( 6 );
+ break;
+ case OOBIN_COLOR_RGB:
+ rStrm.skip( 3 );
+ importColorRgb( rStrm );
+ break;
+ case OOBIN_COLOR_THEME:
+ mnType = XML_theme;
+ mnValue = rStrm.readuInt8();
+ // scale tint from signed 16-bit to double range -1.0 ... 1.0
+ mfTint = static_cast< double >( rStrm.readInt16() ) / 0x7FFF;
+ rStrm.skip( 4 );
+ break;
+ default:
+ OSL_ENSURE( false, "OoxColor::importColor - unknown color type" );
+ mnType = XML_auto;
+ mfTint = 0.0;
+ rStrm.skip( 7 );
+ }
+}
+
+void OoxColor::importColorId( RecordInputStream& rStrm )
+{
+ mfTint = 0.0;
+ mnType = XML_indexed;
+ rStrm >> mnValue;
+}
+
+void OoxColor::importColorRgb( RecordInputStream& rStrm )
+{
+ mfTint = 0.0;
+ mnType = XML_rgb;
+ sal_uInt8 nR, nG, nB, nA;
+ rStrm >> nR >> nG >> nB >> nA;
+ mnValue = lclGetRgbColor( nR, nG, nB, nA );
+}
+
+void OoxColor::importColorId( BiffInputStream& rStrm, bool b16Bit )
+{
+ mfTint = 0.0;
+ mnType = XML_indexed;
+ mnValue = b16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
+}
+
+void OoxColor::importColorRgb( BiffInputStream& rStrm )
+{
+ mfTint = 0.0;
+ mnType = XML_rgb;
+ sal_uInt8 nR, nG, nB, nA;
+ rStrm >> nR >> nG >> nB >> nA;
+ mnValue = lclGetRgbColor( nR, nG, nB, nA );
+}
+
+RecordInputStream& operator>>( RecordInputStream& rStrm, OoxColor& orColor )
+{
+ orColor.importColor( rStrm );
+ return rStrm;
+}
+
+// ============================================================================
+
+namespace {
+
+/** Standard EGA colors, bright. */
+#define PALETTE_EGA_COLORS_LIGHT \
+ 0x000000, 0xFFFFFF, 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF
+/** Standard EGA colors, dark. */
+#define PALETTE_EGA_COLORS_DARK \
+ 0x800000, 0x008000, 0x000080, 0x808000, 0x800080, 0x008080, 0xC0C0C0, 0x808080
+
+/** Default color table for BIFF2. */
+static const sal_Int32 spnDefColors2[] =
+{
+/* 0 */ PALETTE_EGA_COLORS_LIGHT
+};
+
+/** Default color table for BIFF3/BIFF4. */
+static const sal_Int32 spnDefColors3[] =
+{
+/* 0 */ PALETTE_EGA_COLORS_LIGHT,
+/* 8 */ PALETTE_EGA_COLORS_LIGHT,
+/* 16 */ PALETTE_EGA_COLORS_DARK
+};
+
+/** Default color table for BIFF5. */
+static const sal_Int32 spnDefColors5[] =
+{
+/* 0 */ PALETTE_EGA_COLORS_LIGHT,
+/* 8 */ PALETTE_EGA_COLORS_LIGHT,
+/* 16 */ PALETTE_EGA_COLORS_DARK,
+/* 24 */ 0x8080FF, 0x802060, 0xFFFFC0, 0xA0E0E0, 0x600080, 0xFF8080, 0x0080C0, 0xC0C0FF,
+/* 32 */ 0x000080, 0xFF00FF, 0xFFFF00, 0x00FFFF, 0x800080, 0x800000, 0x008080, 0x0000FF,
+/* 40 */ 0x00CFFF, 0x69FFFF, 0xE0FFE0, 0xFFFF80, 0xA6CAF0, 0xDD9CB3, 0xB38FEE, 0xE3E3E3,
+/* 48 */ 0x2A6FF9, 0x3FB8CD, 0x488436, 0x958C41, 0x8E5E42, 0xA0627A, 0x624FAC, 0x969696,
+/* 56 */ 0x1D2FBE, 0x286676, 0x004500, 0x453E01, 0x6A2813, 0x85396A, 0x4A3285, 0x424242
+};
+
+/** Default color table for BIFF8/OOX. */
+static const sal_Int32 spnDefColors8[] =
+{
+/* 0 */ PALETTE_EGA_COLORS_LIGHT,
+/* 8 */ PALETTE_EGA_COLORS_LIGHT,
+/* 16 */ PALETTE_EGA_COLORS_DARK,
+/* 24 */ 0x9999FF, 0x993366, 0xFFFFCC, 0xCCFFFF, 0x660066, 0xFF8080, 0x0066CC, 0xCCCCFF,
+/* 32 */ 0x000080, 0xFF00FF, 0xFFFF00, 0x00FFFF, 0x800080, 0x800000, 0x008080, 0x0000FF,
+/* 40 */ 0x00CCFF, 0xCCFFFF, 0xCCFFCC, 0xFFFF99, 0x99CCFF, 0xFF99CC, 0xCC99FF, 0xFFCC99,
+/* 48 */ 0x3366FF, 0x33CCCC, 0x99CC00, 0xFFCC00, 0xFF9900, 0xFF6600, 0x666699, 0x969696,
+/* 56 */ 0x003366, 0x339966, 0x003300, 0x333300, 0x993300, 0x993366, 0x333399, 0x333333
+};
+
+#undef PALETTE_EGA_COLORS_LIGHT
+#undef PALETTE_EGA_COLORS_DARK
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+ColorPalette::ColorPalette( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mnWindowColor( ThemeBuffer::getSystemWindowColor() ),
+ mnWinTextColor( ThemeBuffer::getSystemWindowTextColor() )
+{
+ // default colors
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ maColors.insert( maColors.begin(), spnDefColors8, STATIC_ARRAY_END( spnDefColors8 ) );
+ mnAppendIndex = OOX_COLOR_USEROFFSET;
+ break;
+ case FILTER_BIFF:
+ switch( getBiff() )
+ {
+ case BIFF2: maColors.insert( maColors.begin(), spnDefColors2, STATIC_ARRAY_END( spnDefColors2 ) ); break;
+ case BIFF3:
+ case BIFF4: maColors.insert( maColors.begin(), spnDefColors3, STATIC_ARRAY_END( spnDefColors3 ) ); break;
+ case BIFF5: maColors.insert( maColors.begin(), spnDefColors5, STATIC_ARRAY_END( spnDefColors5 ) ); break;
+ case BIFF8: maColors.insert( maColors.begin(), spnDefColors8, STATIC_ARRAY_END( spnDefColors8 ) ); break;
+ case BIFF_UNKNOWN: break;
+ }
+ mnAppendIndex = BIFF_COLOR_USEROFFSET;
+ break;
+ case FILTER_UNKNOWN: break;
+ }
+}
+
+void ColorPalette::importPaletteColor( const AttributeList& rAttribs )
+{
+ appendColor( rAttribs.getHex( XML_rgb, API_RGB_TRANSPARENT ) );
+}
+
+void ColorPalette::importPaletteColor( RecordInputStream& rStrm )
+{
+ OoxColor aColor;
+ aColor.importColorRgb( rStrm );
+ appendColor( aColor.mnValue );
+}
+
+void ColorPalette::importPalette( BiffInputStream& rStrm )
+{
+ sal_uInt16 nCount;
+ rStrm >> nCount;
+ OSL_ENSURE( rStrm.getRecLeft() == static_cast< sal_uInt32 >( 4 * nCount ),
+ "ColorPalette::importPalette - wrong palette size" );
+
+ // fill palette from BIFF_COLOR_USEROFFSET
+ mnAppendIndex = BIFF_COLOR_USEROFFSET;
+ OoxColor aColor;
+ for( sal_uInt16 nIndex = 0; rStrm.isValid() && (nIndex < nCount); ++nIndex )
+ {
+ aColor.importColorRgb( rStrm );
+ appendColor( aColor.mnValue );
+ }
+}
+
+sal_Int32 ColorPalette::getColor( sal_Int32 nIndex ) const
+{
+ sal_Int32 nColor = API_RGB_TRANSPARENT;
+ if( (0 <= nIndex) && (static_cast< size_t >( nIndex ) < maColors.size()) )
+ {
+ nColor = maColors[ nIndex ];
+ }
+ else switch( nIndex )
+ {
+ case OOX_COLOR_WINDOWTEXT3:
+ case OOX_COLOR_WINDOWTEXT:
+ case OOX_COLOR_CHWINDOWTEXT: nColor = mnWinTextColor; break;
+ case OOX_COLOR_WINDOWBACK3:
+ case OOX_COLOR_WINDOWBACK:
+ case OOX_COLOR_CHWINDOWBACK: nColor = mnWindowColor; break;
+// case OOX_COLOR_BUTTONBACK:
+// case OOX_COLOR_CHBORDERAUTO:
+// case OOX_COLOR_NOTEBACK:
+// case OOX_COLOR_NOTETEXT:
+ case OOX_COLOR_FONTAUTO: nColor = API_RGB_TRANSPARENT; break;
+ default:
+ OSL_ENSURE( false, "ColorPalette::getColor - unknown color index" );
+ }
+ return nColor;
+}
+
+void ColorPalette::appendColor( sal_Int32 nRGBValue )
+{
+ if( mnAppendIndex < maColors.size() )
+ maColors[ mnAppendIndex ] = nRGBValue;
+ else
+ maColors.push_back( nRGBValue );
+ ++mnAppendIndex;
+}
+
+// ============================================================================
+
+OoxFontData::OoxFontData() :
+ mnScheme( XML_none ),
+ mnFamily( OOX_FONTFAMILY_NONE ),
+ mnCharSet( OOX_FONTCHARSET_ANSI ),
+ mfHeight( 0.0 ),
+ mnUnderline( XML_none ),
+ mnEscapement( XML_baseline ),
+ mbBold( false ),
+ mbItalic( false ),
+ mbStrikeout( false ),
+ mbOutline( false ),
+ mbShadow( false )
+{
+}
+
+void OoxFontData::setBinScheme( sal_uInt8 nScheme )
+{
+ static const sal_Int32 spnSchemes[] = { XML_none, XML_major, XML_minor };
+ mnScheme = STATIC_ARRAY_SELECT( spnSchemes, nScheme, XML_none );
+}
+
+void OoxFontData::setBiffHeight( sal_uInt16 nHeight )
+{
+ mfHeight = nHeight / 20.0; // convert twips to points
+}
+
+void OoxFontData::setBiffWeight( sal_uInt16 nWeight )
+{
+ mbBold = nWeight >= BIFF_FONTWEIGHT_BOLD;
+}
+
+void OoxFontData::setBiffUnderline( sal_uInt16 nUnderline )
+{
+ switch( nUnderline )
+ {
+ case BIFF_FONTUNDERL_NONE: mnUnderline = XML_none; break;
+ case BIFF_FONTUNDERL_SINGLE: mnUnderline = XML_single; break;
+ case BIFF_FONTUNDERL_DOUBLE: mnUnderline = XML_double; break;
+ case BIFF_FONTUNDERL_SINGLE_ACC: mnUnderline = XML_singleAccounting; break;
+ case BIFF_FONTUNDERL_DOUBLE_ACC: mnUnderline = XML_doubleAccounting; break;
+ default: mnUnderline = XML_none;
+ }
+}
+
+void OoxFontData::setBiffEscapement( sal_uInt16 nEscapement )
+{
+ static const sal_Int32 spnEscapes[] = { XML_baseline, XML_superscript, XML_subscript };
+ mnEscapement = STATIC_ARRAY_SELECT( spnEscapes, nEscapement, XML_baseline );
+}
+
+// ============================================================================
+
+Font::Font( const WorkbookHelper& rHelper, bool bDxf ) :
+ WorkbookHelper( rHelper ),
+ maOoxData( rHelper.getTheme().getDefaultFontData() ),
+ maUsedFlags( !bDxf ),
+ mbDxf( bDxf )
+{
+}
+
+Font::Font( const WorkbookHelper& rHelper, const OoxFontData& rFontData ) :
+ WorkbookHelper( rHelper ),
+ maOoxData( rFontData ),
+ maUsedFlags( true ),
+ mbDxf( false )
+{
+}
+
+bool Font::isSupportedContext( sal_Int32 nElement, sal_Int32 nParentContext )
+{
+ switch( nParentContext )
+ {
+ case XLS_TOKEN( font ):
+ return (nElement == XLS_TOKEN( name )) ||
+ (nElement == XLS_TOKEN( scheme )) ||
+ (nElement == XLS_TOKEN( charset )) ||
+ (nElement == XLS_TOKEN( family )) ||
+ (nElement == XLS_TOKEN( sz )) ||
+ (nElement == XLS_TOKEN( color )) ||
+ (nElement == XLS_TOKEN( u )) ||
+ (nElement == XLS_TOKEN( vertAlign )) ||
+ (nElement == XLS_TOKEN( b )) ||
+ (nElement == XLS_TOKEN( i )) ||
+ (nElement == XLS_TOKEN( outline )) ||
+ (nElement == XLS_TOKEN( shadow )) ||
+ (nElement == XLS_TOKEN( strike ));
+
+ case XLS_TOKEN( rPr ):
+ return (nElement == XLS_TOKEN( rFont )) ||
+ (nElement == XLS_TOKEN( scheme )) ||
+ (nElement == XLS_TOKEN( charset )) ||
+ (nElement == XLS_TOKEN( family )) ||
+ (nElement == XLS_TOKEN( sz )) ||
+ (nElement == XLS_TOKEN( color )) ||
+ (nElement == XLS_TOKEN( u )) ||
+ (nElement == XLS_TOKEN( vertAlign )) ||
+ (nElement == XLS_TOKEN( b )) ||
+ (nElement == XLS_TOKEN( i )) ||
+ (nElement == XLS_TOKEN( outline )) ||
+ (nElement == XLS_TOKEN( shadow )) ||
+ (nElement == XLS_TOKEN( strike )) ||
+ (nElement == XLS_TOKEN( vertAlign ));
+ }
+ return false;
+}
+
+void Font::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ const OoxFontData& rDefFontData = getTheme().getDefaultFontData();
+ switch( nElement )
+ {
+ case XLS_TOKEN( name ):
+ case XLS_TOKEN( rFont ):
+ if( rAttribs.hasAttribute( XML_val ) )
+ {
+ maOoxData.maName = rAttribs.getString( XML_val );
+ maUsedFlags.mbNameUsed = true;
+ }
+ break;
+ case XLS_TOKEN( scheme ):
+ maOoxData.mnScheme = rAttribs.getToken( XML_val, rDefFontData.mnScheme );
+ break;
+ case XLS_TOKEN( family ):
+ maOoxData.mnFamily = rAttribs.getInteger( XML_val, rDefFontData.mnFamily );
+ break;
+ case XLS_TOKEN( charset ):
+ maOoxData.mnCharSet = rAttribs.getInteger( XML_val, rDefFontData.mnCharSet );
+ break;
+ case XLS_TOKEN( sz ):
+ maOoxData.mfHeight = rAttribs.getDouble( XML_val, rDefFontData.mfHeight );
+ maUsedFlags.mbHeightUsed = true;
+ break;
+ case XLS_TOKEN( color ):
+ maOoxData.maColor.importColor( rAttribs );
+ maUsedFlags.mbColorUsed = true;
+ break;
+ case XLS_TOKEN( u ):
+ maOoxData.mnUnderline = rAttribs.getToken( XML_val, XML_single );
+ maUsedFlags.mbUnderlineUsed = true;
+ break;
+ case XLS_TOKEN( vertAlign ):
+ maOoxData.mnEscapement = rAttribs.getToken( XML_val, XML_baseline );
+ maUsedFlags.mbEscapementUsed = true;
+ break;
+ case XLS_TOKEN( b ):
+ maOoxData.mbBold = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbWeightUsed = true;
+ break;
+ case XLS_TOKEN( i ):
+ maOoxData.mbItalic = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbPostureUsed = true;
+ break;
+ case XLS_TOKEN( strike ):
+ maOoxData.mbStrikeout = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbStrikeoutUsed = true;
+ break;
+ case XLS_TOKEN( outline ):
+ maOoxData.mbOutline = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbOutlineUsed = true;
+ break;
+ case XLS_TOKEN( shadow ):
+ maOoxData.mbShadow = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbShadowUsed = true;
+ break;
+ }
+}
+
+void Font::importFont( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( !mbDxf, "Font::importFont - unexpected conditional formatting flag" );
+
+ sal_uInt16 nHeight, nFlags, nWeight, nEscapement;
+ sal_uInt8 nUnderline, nFamily, nCharSet, nScheme;
+ rStrm >> nHeight >> nFlags >> nWeight >> nEscapement >> nUnderline >> nFamily >> nCharSet;
+ rStrm.skip( 1 );
+ rStrm >> maOoxData.maColor >> nScheme >> maOoxData.maName;
+
+ // equal constants in BIFF and OOBIN for weight, underline, and escapement
+ maOoxData.setBinScheme( nScheme );
+ maOoxData.setBiffHeight( nHeight );
+ maOoxData.setBiffWeight( nWeight );
+ maOoxData.setBiffUnderline( nUnderline );
+ maOoxData.setBiffEscapement( nEscapement );
+ maOoxData.mnFamily = nFamily;
+ maOoxData.mnCharSet = nCharSet;
+ // equal flags in BIFF and OOBIN
+ maOoxData.mbItalic = getFlag( nFlags, BIFF_FONTFLAG_ITALIC );
+ maOoxData.mbStrikeout = getFlag( nFlags, BIFF_FONTFLAG_STRIKEOUT );
+ maOoxData.mbOutline = getFlag( nFlags, BIFF_FONTFLAG_OUTLINE );
+ maOoxData.mbShadow = getFlag( nFlags, BIFF_FONTFLAG_SHADOW );
+}
+
+void Font::importDxfName( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfName - missing conditional formatting flag" );
+ maOoxData.maName = rStrm.readString( false );
+ maUsedFlags.mbColorUsed = true;
+}
+
+void Font::importDxfColor( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfColor - missing conditional formatting flag" );
+ rStrm >> maOoxData.maColor;
+ maUsedFlags.mbColorUsed = true;
+}
+
+void Font::importDxfScheme( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfScheme - missing conditional formatting flag" );
+ maOoxData.setBinScheme( rStrm.readuInt8() );
+ maUsedFlags.mbSchemeUsed = true;
+}
+
+void Font::importDxfHeight( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfHeight - missing conditional formatting flag" );
+ maOoxData.setBiffHeight( rStrm.readuInt16() );
+ maUsedFlags.mbHeightUsed = true;
+}
+
+void Font::importDxfWeight( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfWeight - missing conditional formatting flag" );
+ maOoxData.setBiffWeight( rStrm.readuInt16() );
+ maUsedFlags.mbWeightUsed = true;
+}
+
+void Font::importDxfUnderline( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfUnderline - missing conditional formatting flag" );
+ maOoxData.setBiffUnderline( rStrm.readuInt16() );
+ maUsedFlags.mbUnderlineUsed = true;
+}
+
+void Font::importDxfEscapement( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfEscapement - missing conditional formatting flag" );
+ maOoxData.setBiffEscapement( rStrm.readuInt16() );
+ maUsedFlags.mbEscapementUsed = true;
+}
+
+void Font::importDxfFlag( sal_Int32 nElement, RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfFlag - missing conditional formatting flag" );
+ bool bFlag = rStrm.readuInt8() != 0;
+ switch( nElement )
+ {
+ case XML_i:
+ maOoxData.mbItalic = bFlag;
+ maUsedFlags.mbPostureUsed = true;
+ break;
+ case XML_strike:
+ maOoxData.mbStrikeout = bFlag;
+ maUsedFlags.mbStrikeoutUsed = true;
+ break;
+ case XML_outline:
+ maOoxData.mbOutline = bFlag;
+ maUsedFlags.mbOutlineUsed = true;
+ break;
+ case XML_shadow:
+ maOoxData.mbShadow = bFlag;
+ maUsedFlags.mbShadowUsed = true;
+ break;
+ default:
+ OSL_ENSURE( false, "Font::importDxfFlag - unexpected element identifier" );
+ }
+}
+
+void Font::importFont( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !mbDxf, "Font::importFont - unexpected conditional formatting flag" );
+ switch( getBiff() )
+ {
+ case BIFF2:
+ importFontData2( rStrm );
+ importFontName2( rStrm );
+ break;
+ case BIFF3:
+ case BIFF4:
+ importFontData2( rStrm );
+ importFontColor( rStrm );
+ importFontName2( rStrm );
+ break;
+ case BIFF5:
+ importFontData2( rStrm );
+ importFontColor( rStrm );
+ importFontData5( rStrm );
+ importFontName2( rStrm );
+ break;
+ case BIFF8:
+ importFontData2( rStrm );
+ importFontColor( rStrm );
+ importFontData5( rStrm );
+ importFontName8( rStrm );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+}
+
+void Font::importFontColor( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !mbDxf, "Font::importFontColor - unexpected conditional formatting flag" );
+ maOoxData.maColor.importColorId( rStrm );
+}
+
+void Font::importCfRule( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importCfRule - missing conditional formatting flag" );
+
+ sal_Int32 nHeight, nColor;
+ sal_uInt32 nStyle, nFontFlags1, nFontFlags2, nFontFlags3;
+ sal_uInt16 nWeight, nEscapement;
+ sal_uInt8 nUnderline;
+
+ OSL_ENSURE( rStrm.getRecLeft() >= 118, "Font::importCfRule - missing record data" );
+ sal_uInt32 nRecPos = rStrm.getRecPos();
+ maOoxData.maName = rStrm.readUniString( rStrm.readuInt8() );
+ maUsedFlags.mbNameUsed = maOoxData.maName.getLength() > 0;
+ OSL_ENSURE( rStrm.isValid() && (rStrm.getRecPos() <= nRecPos + 64), "Font::importCfRule - font name too long" );
+ rStrm.seek( nRecPos + 64 );
+ rStrm >> nHeight >> nStyle >> nWeight >> nEscapement >> nUnderline;
+ rStrm.skip( 3 );
+ rStrm >> nColor;
+ rStrm.skip( 4 );
+ rStrm >> nFontFlags1 >> nFontFlags2 >> nFontFlags3;
+ rStrm.skip( 18 );
+
+ if( (maUsedFlags.mbColorUsed = (0 <= nColor) && (nColor <= 0x7FFF)) == true )
+ maOoxData.maColor.set( XML_indexed, nColor );
+ if( (maUsedFlags.mbHeightUsed = (0 < nHeight) && (nHeight <= 0x7FFF)) == true )
+ maOoxData.setBiffHeight( static_cast< sal_uInt16 >( nHeight ) );
+ if( (maUsedFlags.mbUnderlineUsed = !getFlag( nFontFlags3, BIFF_CFRULE_FONT_UNDERL )) == true )
+ maOoxData.setBiffUnderline( nUnderline );
+ if( (maUsedFlags.mbEscapementUsed = !getFlag( nFontFlags2, BIFF_CFRULE_FONT_ESCAPEM )) == true )
+ maOoxData.setBiffEscapement( nEscapement );
+ if( (maUsedFlags.mbWeightUsed = maUsedFlags.mbPostureUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_STYLE )) == true )
+ {
+ maOoxData.setBiffWeight( nWeight );
+ maOoxData.mbItalic = getFlag( nStyle, BIFF_CFRULE_FONT_STYLE );
+ }
+ if( (maUsedFlags.mbStrikeoutUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_STRIKEOUT )) == true )
+ maOoxData.mbStrikeout = getFlag( nStyle, BIFF_CFRULE_FONT_STRIKEOUT );
+ if( (maUsedFlags.mbOutlineUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_OUTLINE )) == true )
+ maOoxData.mbOutline = getFlag( nStyle, BIFF_CFRULE_FONT_OUTLINE );
+ if( (maUsedFlags.mbShadowUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_SHADOW )) == true )
+ maOoxData.mbShadow = getFlag( nStyle, BIFF_CFRULE_FONT_SHADOW );
+}
+
+rtl_TextEncoding Font::getFontEncoding() const
+{
+ // #i63105# cells use text encoding from FONT record character set
+ // #i67768# BIFF2-BIFF4 FONT records do not contain character set
+ // #i71033# do not use maApiData, this function is used before finalizeImport()
+ rtl_TextEncoding eFontEnc = RTL_TEXTENCODING_DONTKNOW;
+ if( (0 <= maOoxData.mnCharSet) && (maOoxData.mnCharSet <= SAL_MAX_UINT8) )
+ eFontEnc = rtl_getTextEncodingFromWindowsCharset( static_cast< sal_uInt8 >( maOoxData.mnCharSet ) );
+ return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? getTextEncoding() : eFontEnc;
+}
+
+void Font::finalizeImport()
+{
+ namespace cssawt = ::com::sun::star::awt;
+
+ // font name
+ maApiData.maDesc.Name = maOoxData.maName;
+
+ // font family
+ switch( maOoxData.mnFamily )
+ {
+ case OOX_FONTFAMILY_NONE: maApiData.maDesc.Family = cssawt::FontFamily::DONTKNOW; break;
+ case OOX_FONTFAMILY_ROMAN: maApiData.maDesc.Family = cssawt::FontFamily::ROMAN; break;
+ case OOX_FONTFAMILY_SWISS: maApiData.maDesc.Family = cssawt::FontFamily::SWISS; break;
+ case OOX_FONTFAMILY_MODERN: maApiData.maDesc.Family = cssawt::FontFamily::MODERN; break;
+ case OOX_FONTFAMILY_SCRIPT: maApiData.maDesc.Family = cssawt::FontFamily::SCRIPT; break;
+ case OOX_FONTFAMILY_DECORATIVE: maApiData.maDesc.Family = cssawt::FontFamily::DECORATIVE; break;
+ }
+
+ // character set
+ if( (0 <= maOoxData.mnCharSet) && (maOoxData.mnCharSet <= 255) )
+ maApiData.maDesc.CharSet = static_cast< sal_Int16 >(
+ rtl_getTextEncodingFromWindowsCharset( static_cast< sal_uInt8 >( maOoxData.mnCharSet ) ) );
+
+ // color, height, weight, slant, strikeout, outline, shadow
+ maApiData.mnColor = getStyles().getColor( maOoxData.maColor, API_RGB_TRANSPARENT );
+ maApiData.maDesc.Height = static_cast< sal_Int16 >( maOoxData.mfHeight * 20.0 );
+ maApiData.maDesc.Weight = maOoxData.mbBold ? cssawt::FontWeight::BOLD : cssawt::FontWeight::NORMAL;
+ maApiData.maDesc.Slant = maOoxData.mbItalic ? cssawt::FontSlant_ITALIC : cssawt::FontSlant_NONE;
+ maApiData.maDesc.Strikeout = maOoxData.mbStrikeout ? cssawt::FontStrikeout::SINGLE : cssawt::FontStrikeout::NONE;
+ maApiData.mbOutline = maOoxData.mbOutline;
+ maApiData.mbShadow = maOoxData.mbShadow;
+
+ // underline
+ switch( maOoxData.mnUnderline )
+ {
+ case XML_double: maApiData.maDesc.Underline = cssawt::FontUnderline::DOUBLE; break;
+ case XML_doubleAccounting: maApiData.maDesc.Underline = cssawt::FontUnderline::DOUBLE; break;
+ case XML_none: maApiData.maDesc.Underline = cssawt::FontUnderline::NONE; break;
+ case XML_single: maApiData.maDesc.Underline = cssawt::FontUnderline::SINGLE; break;
+ case XML_singleAccounting: maApiData.maDesc.Underline = cssawt::FontUnderline::SINGLE; break;
+ }
+
+ // escapement
+ switch( maOoxData.mnEscapement )
+ {
+ case XML_baseline:
+ maApiData.mnEscapement = API_ESCAPE_NONE;
+ maApiData.mnEscapeHeight = API_ESCAPEHEIGHT_NONE;
+ break;
+ case XML_superscript:
+ maApiData.mnEscapement = API_ESCAPE_SUPERSCRIPT;
+ maApiData.mnEscapeHeight = API_ESCAPEHEIGHT_DEFAULT;
+ break;
+ case XML_subscript:
+ maApiData.mnEscapement = API_ESCAPE_SUBSCRIPT;
+ maApiData.mnEscapeHeight = API_ESCAPEHEIGHT_DEFAULT;
+ break;
+ }
+
+ // supported script types
+ if( maUsedFlags.mbNameUsed )
+ {
+ Reference< XDevice > xDevice = getReferenceDevice();
+ if( xDevice.is() )
+ {
+ Reference< XFont2 > xFont( xDevice->getFont( maApiData.maDesc ), UNO_QUERY );
+ if( xFont.is() )
+ {
+ // #91658# CJK fonts
+ maApiData.mbHasAsian =
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x3041 ) ) ) || // 3040-309F: Hiragana
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x30A1 ) ) ) || // 30A0-30FF: Katakana
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x3111 ) ) ) || // 3100-312F: Bopomofo
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x3131 ) ) ) || // 3130-318F: Hangul Compatibility Jamo
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x3301 ) ) ) || // 3300-33FF: CJK Compatibility
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x3401 ) ) ) || // 3400-4DBF: CJK Unified Ideographs Extension A
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x4E01 ) ) ) || // 4E00-9FAF: CJK Unified Ideographs
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x7E01 ) ) ) || // 4E00-9FAF: CJK unified ideographs
+ xFont->hasGlyphs( OUString( sal_Unicode( 0xA001 ) ) ) || // A001-A48F: Yi Syllables
+ xFont->hasGlyphs( OUString( sal_Unicode( 0xAC01 ) ) ) || // AC00-D7AF: Hangul Syllables
+ xFont->hasGlyphs( OUString( sal_Unicode( 0xCC01 ) ) ) || // AC00-D7AF: Hangul Syllables
+ xFont->hasGlyphs( OUString( sal_Unicode( 0xF901 ) ) ) || // F900-FAFF: CJK Compatibility Ideographs
+ xFont->hasGlyphs( OUString( sal_Unicode( 0xFF71 ) ) ); // FF00-FFEF: Halfwidth/Fullwidth Forms
+ // #113783# CTL fonts
+ maApiData.mbHasCmplx =
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x05D1 ) ) ) || // 0590-05FF: Hebrew
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x0631 ) ) ) || // 0600-06FF: Arabic
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x0721 ) ) ) || // 0700-074F: Syriac
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x0911 ) ) ) || // 0900-0DFF: Indic scripts
+ xFont->hasGlyphs( OUString( sal_Unicode( 0x0E01 ) ) ) || // 0E00-0E7F: Thai
+ xFont->hasGlyphs( OUString( sal_Unicode( 0xFB21 ) ) ) || // FB1D-FB4F: Hebrew Presentation Forms
+ xFont->hasGlyphs( OUString( sal_Unicode( 0xFB51 ) ) ) || // FB50-FDFF: Arabic Presentation Forms-A
+ xFont->hasGlyphs( OUString( sal_Unicode( 0xFE71 ) ) ); // FE70-FEFF: Arabic Presentation Forms-B
+ // Western fonts
+ maApiData.mbHasWstrn =
+ (!maApiData.mbHasAsian && !maApiData.mbHasCmplx) ||
+ xFont->hasGlyphs( OUString( sal_Unicode( 'A' ) ) );
+ }
+ }
+ }
+}
+
+const FontDescriptor& Font::getFontDescriptor() const
+{
+ return maApiData.maDesc;
+}
+
+bool Font::needsRichTextFormat() const
+{
+ return maApiData.mnEscapement != API_ESCAPE_NONE;
+}
+
+void Font::writeToPropertySet( PropertySet& rPropSet, FontPropertyType ePropType ) const
+{
+ getStylesPropertyHelper().writeFontProperties( rPropSet, maApiData, maUsedFlags, ePropType );
+}
+
+void Font::importFontData2( BiffInputStream& rStrm )
+{
+ sal_uInt16 nHeight, nFlags;
+ rStrm >> nHeight >> nFlags;
+
+ maOoxData.setBiffHeight( nHeight );
+ maOoxData.mnFamily = OOX_FONTFAMILY_NONE;
+ maOoxData.mnCharSet = OOX_FONTCHARSET_UNUSED; // ensure to not use font charset in byte string import
+ maOoxData.mnUnderline = getFlagValue( nFlags, BIFF_FONTFLAG_UNDERLINE, XML_single, XML_none );
+ maOoxData.mnEscapement = XML_none;
+ maOoxData.mbBold = getFlag( nFlags, BIFF_FONTFLAG_BOLD );
+ maOoxData.mbItalic = getFlag( nFlags, BIFF_FONTFLAG_ITALIC );
+ maOoxData.mbStrikeout = getFlag( nFlags, BIFF_FONTFLAG_STRIKEOUT );
+ maOoxData.mbOutline = getFlag( nFlags, BIFF_FONTFLAG_OUTLINE );
+ maOoxData.mbShadow = getFlag( nFlags, BIFF_FONTFLAG_SHADOW );
+}
+
+void Font::importFontData5( BiffInputStream& rStrm )
+{
+ sal_uInt16 nWeight, nEscapement;
+ sal_uInt8 nUnderline, nFamily, nCharSet;
+ rStrm >> nWeight >> nEscapement >> nUnderline >> nFamily >> nCharSet;
+ rStrm.skip( 1 );
+
+ maOoxData.setBiffWeight( nWeight );
+ maOoxData.setBiffUnderline( nUnderline );
+ maOoxData.setBiffEscapement( nEscapement );
+ // equal constants in XML and BIFF for family and charset
+ maOoxData.mnFamily = nFamily;
+ maOoxData.mnCharSet = nCharSet;
+}
+
+void Font::importFontName2( BiffInputStream& rStrm )
+{
+ maOoxData.maName = rStrm.readByteString( false, getTextEncoding() );
+}
+
+void Font::importFontName8( BiffInputStream& rStrm )
+{
+ maOoxData.maName = rStrm.readUniString( rStrm.readuInt8() );
+}
+
+// ============================================================================
+
+OoxAlignmentData::OoxAlignmentData() :
+ mnHorAlign( XML_general ),
+ mnVerAlign( XML_bottom ),
+ mnTextDir( OOX_XF_TEXTDIR_CONTEXT ),
+ mnRotation( OOX_XF_ROTATION_NONE ),
+ mnIndent( OOX_XF_INDENT_NONE ),
+ mbWrapText( false ),
+ mbShrink( false ),
+ mbJustLastLine( false )
+{
+}
+
+void OoxAlignmentData::setBinHorAlign( sal_uInt8 nHorAlign )
+{
+ static const sal_Int32 spnHorAligns[] = {
+ XML_general, XML_left, XML_center, XML_right,
+ XML_fill, XML_justify, XML_centerContinuous, XML_distributed };
+ mnHorAlign = STATIC_ARRAY_SELECT( spnHorAligns, nHorAlign, XML_general );
+}
+
+void OoxAlignmentData::setBinVerAlign( sal_uInt8 nVerAlign )
+{
+ static const sal_Int32 spnVerAligns[] = {
+ XML_top, XML_center, XML_bottom, XML_justify, XML_distributed };
+ mnVerAlign = STATIC_ARRAY_SELECT( spnVerAligns, nVerAlign, XML_bottom );
+}
+
+void OoxAlignmentData::setBinTextOrient( sal_uInt8 nTextOrient )
+{
+ static const sal_Int32 spnRotations[] = {
+ OOX_XF_ROTATION_NONE, OOX_XF_ROTATION_STACKED,
+ OOX_XF_ROTATION_90CCW, OOX_XF_ROTATION_90CW };
+ mnRotation = STATIC_ARRAY_SELECT( spnRotations, nTextOrient, OOX_XF_ROTATION_NONE );
+}
+
+// ============================================================================
+
+Alignment::Alignment( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void Alignment::importAlignment( const AttributeList& rAttribs )
+{
+ maOoxData.mnHorAlign = rAttribs.getToken( XML_horizontal, XML_general );
+ maOoxData.mnVerAlign = rAttribs.getToken( XML_vertical, XML_bottom );
+ maOoxData.mnTextDir = rAttribs.getInteger( XML_readingOrder, OOX_XF_TEXTDIR_CONTEXT );
+ maOoxData.mnRotation = rAttribs.getInteger( XML_textRotation, OOX_XF_ROTATION_NONE );
+ maOoxData.mnIndent = rAttribs.getInteger( XML_indent, OOX_XF_INDENT_NONE );
+ maOoxData.mbWrapText = rAttribs.getBool( XML_wrapText, false );
+ maOoxData.mbShrink = rAttribs.getBool( XML_shrinkToFit, false );
+ maOoxData.mbJustLastLine = rAttribs.getBool( XML_justifyLastLine, false );
+}
+
+void Alignment::setBinData( sal_uInt32 nFlags )
+{
+ maOoxData.setBinHorAlign( extractValue< sal_uInt8 >( nFlags, 16, 3 ) );
+ maOoxData.setBinVerAlign( extractValue< sal_uInt8 >( nFlags, 19, 3 ) );
+ maOoxData.mnTextDir = extractValue< sal_Int32 >( nFlags, 26, 2 );
+ maOoxData.mnRotation = extractValue< sal_Int32 >( nFlags, 0, 8 );
+ maOoxData.mnIndent = extractValue< sal_uInt8 >( nFlags, 8, 8 );
+ maOoxData.mbWrapText = getFlag( nFlags, OOBIN_XF_WRAPTEXT );
+ maOoxData.mbShrink = getFlag( nFlags, OOBIN_XF_SHRINK );
+ maOoxData.mbJustLastLine = getFlag( nFlags, OOBIN_XF_JUSTLASTLINE );
+}
+
+void Alignment::setBiff2Data( sal_uInt8 nFlags )
+{
+ maOoxData.setBinHorAlign( extractValue< sal_uInt8 >( nFlags, 0, 3 ) );
+}
+
+void Alignment::setBiff3Data( sal_uInt16 nAlign )
+{
+ maOoxData.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+ maOoxData.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT ); // new in BIFF3
+}
+
+void Alignment::setBiff4Data( sal_uInt16 nAlign )
+{
+ maOoxData.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+ maOoxData.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 2 ) ); // new in BIFF4
+ maOoxData.setBinTextOrient( extractValue< sal_uInt8 >( nAlign, 6, 2 ) ); // new in BIFF4
+ maOoxData.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT );
+}
+
+void Alignment::setBiff5Data( sal_uInt16 nAlign )
+{
+ maOoxData.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+ maOoxData.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 3 ) );
+ maOoxData.setBinTextOrient( extractValue< sal_uInt8 >( nAlign, 8, 2 ) );
+ maOoxData.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT );
+}
+
+void Alignment::setBiff8Data( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
+{
+ maOoxData.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+ maOoxData.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 3 ) );
+ maOoxData.mnTextDir = extractValue< sal_Int32 >( nMiscAttrib, 6, 2 ); // new in BIFF8
+ maOoxData.mnRotation = extractValue< sal_Int32 >( nAlign, 8, 8 ); // new in BIFF8
+ maOoxData.mnIndent = extractValue< sal_uInt8 >( nMiscAttrib, 0, 4 ); // new in BIFF8
+ maOoxData.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT );
+ maOoxData.mbShrink = getFlag( nMiscAttrib, BIFF_XF_SHRINK ); // new in BIFF8
+ maOoxData.mbJustLastLine = getFlag( nAlign, BIFF_XF_JUSTLASTLINE ); // new in BIFF8(?)
+}
+
+void Alignment::finalizeImport()
+{
+ namespace csstab = ::com::sun::star::table;
+ namespace csstxt = ::com::sun::star::text;
+
+ // horizontal alignment
+ switch( maOoxData.mnHorAlign )
+ {
+ case XML_center: maApiData.meHorJustify = csstab::CellHoriJustify_CENTER; break;
+ case XML_centerContinuous: maApiData.meHorJustify = csstab::CellHoriJustify_CENTER; break;
+ case XML_distributed: maApiData.meHorJustify = csstab::CellHoriJustify_BLOCK; break;
+ case XML_fill: maApiData.meHorJustify = csstab::CellHoriJustify_REPEAT; break;
+ case XML_general: maApiData.meHorJustify = csstab::CellHoriJustify_STANDARD; break;
+ case XML_justify: maApiData.meHorJustify = csstab::CellHoriJustify_BLOCK; break;
+ case XML_left: maApiData.meHorJustify = csstab::CellHoriJustify_LEFT; break;
+ case XML_right: maApiData.meHorJustify = csstab::CellHoriJustify_RIGHT; break;
+ }
+
+ // vertical alignment
+ switch( maOoxData.mnVerAlign )
+ {
+ case XML_bottom: maApiData.meVerJustify = csstab::CellVertJustify_BOTTOM; break;
+ case XML_center: maApiData.meVerJustify = csstab::CellVertJustify_CENTER; break;
+ case XML_distributed: maApiData.meVerJustify = csstab::CellVertJustify_TOP; break;
+ case XML_justify: maApiData.meVerJustify = csstab::CellVertJustify_TOP; break;
+ case XML_top: maApiData.meVerJustify = csstab::CellVertJustify_TOP; break;
+ }
+
+ /* indentation: expressed as number of blocks of 3 space characters in
+ OOX, and as multiple of 10 points in BIFF. */
+ sal_Int32 nIndent = 0;
+ switch( getFilterType() )
+ {
+ case FILTER_OOX: nIndent = getUnitConverter().calcMm100FromSpaces( 3.0 * maOoxData.mnIndent ); break;
+ case FILTER_BIFF: nIndent = getUnitConverter().calcMm100FromPoints( 10.0 * maOoxData.mnIndent ); break;
+ case FILTER_UNKNOWN: break;
+ }
+ if( (0 <= nIndent) && (nIndent <= SAL_MAX_INT16) )
+ maApiData.mnIndent = static_cast< sal_Int16 >( nIndent );
+
+ // complex text direction
+ switch( maOoxData.mnTextDir )
+ {
+ case OOX_XF_TEXTDIR_CONTEXT: maApiData.mnWritingMode = csstxt::WritingMode2::PAGE; break;
+ case OOX_XF_TEXTDIR_LTR: maApiData.mnWritingMode = csstxt::WritingMode2::LR_TB; break;
+ case OOX_XF_TEXTDIR_RTL: maApiData.mnWritingMode = csstxt::WritingMode2::RL_TB; break;
+ }
+
+ // rotation: 0-90 means 0 to 90 degrees ccw, 91-180 means 1 to 90 degrees cw, 255 means stacked
+ sal_Int32 nOoxRot = maOoxData.mnRotation;
+ maApiData.mnRotation = ((0 <= nOoxRot) && (nOoxRot <= 90)) ?
+ (100 * nOoxRot) :
+ (((91 <= nOoxRot) && (nOoxRot <= 180)) ? (100 * (450 - nOoxRot)) : 0);
+
+ // "Orientation" property used for character stacking
+ maApiData.meOrientation = (nOoxRot == OOX_XF_ROTATION_STACKED) ?
+ csstab::CellOrientation_STACKED : csstab::CellOrientation_STANDARD;
+
+ // alignment flags
+ maApiData.mbWrapText = maOoxData.mbWrapText;
+ maApiData.mbShrink = maOoxData.mbShrink;
+
+}
+
+void Alignment::writeToPropertySet( PropertySet& rPropSet ) const
+{
+ getStylesPropertyHelper().writeAlignmentProperties( rPropSet, maApiData );
+}
+
+// ============================================================================
+
+OoxProtectionData::OoxProtectionData() :
+ mbLocked( true ), // default in Excel and Calc
+ mbHidden( false )
+{
+}
+
+// ============================================================================
+
+Protection::Protection( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void Protection::importProtection( const AttributeList& rAttribs )
+{
+ maOoxData.mbLocked = rAttribs.getBool( XML_locked, true );
+ maOoxData.mbHidden = rAttribs.getBool( XML_hidden, false );
+}
+
+void Protection::setBinData( sal_uInt32 nFlags )
+{
+ maOoxData.mbLocked = getFlag( nFlags, OOBIN_XF_LOCKED );
+ maOoxData.mbHidden = getFlag( nFlags, OOBIN_XF_HIDDEN );
+}
+
+void Protection::setBiff2Data( sal_uInt8 nNumFmt )
+{
+ maOoxData.mbLocked = getFlag( nNumFmt, BIFF2_XF_LOCKED );
+ maOoxData.mbHidden = getFlag( nNumFmt, BIFF2_XF_HIDDEN );
+}
+
+void Protection::setBiff3Data( sal_uInt16 nProt )
+{
+ maOoxData.mbLocked = getFlag( nProt, BIFF_XF_LOCKED );
+ maOoxData.mbHidden = getFlag( nProt, BIFF_XF_HIDDEN );
+}
+
+void Protection::finalizeImport()
+{
+ maApiData.maCellProt.IsLocked = maOoxData.mbLocked;
+ maApiData.maCellProt.IsFormulaHidden = maOoxData.mbHidden;
+}
+
+void Protection::writeToPropertySet( PropertySet& rPropSet ) const
+{
+ getStylesPropertyHelper().writeProtectionProperties( rPropSet, maApiData );
+}
+
+// ============================================================================
+
+OoxBorderLineData::OoxBorderLineData( bool bDxf ) :
+ maColor( XML_indexed, OOX_COLOR_WINDOWTEXT ),
+ mnStyle( XML_none ),
+ mbUsed( !bDxf )
+{
+}
+
+void OoxBorderLineData::setBiffStyle( sal_Int32 nLineStyle )
+{
+ static const sal_Int32 spnStyleIds[] = {
+ XML_none, XML_thin, XML_medium, XML_dashed,
+ XML_dotted, XML_thick, XML_double, XML_hair,
+ XML_mediumDashed, XML_dashDot, XML_mediumDashDot, XML_dashDotDot,
+ XML_mediumDashDotDot, XML_slantDashDot };
+ mnStyle = STATIC_ARRAY_SELECT( spnStyleIds, nLineStyle, XML_none );
+}
+
+void OoxBorderLineData::setBiffData( sal_uInt8 nLineStyle, sal_uInt16 nLineColor )
+{
+ maColor.set( XML_indexed, nLineColor );
+ setBiffStyle( nLineStyle );
+}
+
+// ============================================================================
+
+OoxBorderData::OoxBorderData( bool bDxf ) :
+ maLeft( bDxf ),
+ maRight( bDxf ),
+ maTop( bDxf ),
+ maBottom( bDxf ),
+ maDiagonal( bDxf ),
+ mbDiagTLtoBR( false ),
+ mbDiagBLtoTR( false )
+{
+}
+
+// ============================================================================
+
+namespace {
+
+inline void lclSetBorderLineWidth( BorderLine& rBorderLine,
+ sal_Int16 nOuter, sal_Int16 nDist = API_LINE_NONE, sal_Int16 nInner = API_LINE_NONE )
+{
+ rBorderLine.OuterLineWidth = nOuter;
+ rBorderLine.LineDistance = nDist;
+ rBorderLine.InnerLineWidth = nInner;
+}
+
+inline sal_Int32 lclGetBorderLineWidth( const BorderLine& rBorderLine )
+{
+ return rBorderLine.OuterLineWidth + rBorderLine.LineDistance + rBorderLine.InnerLineWidth;
+}
+
+const BorderLine* lclGetThickerLine( const BorderLine& rBorderLine1, sal_Bool bValid1, const BorderLine& rBorderLine2, sal_Bool bValid2 )
+{
+ if( bValid1 && bValid2 )
+ return (lclGetBorderLineWidth( rBorderLine1 ) < lclGetBorderLineWidth( rBorderLine2 )) ? &rBorderLine2 : &rBorderLine1;
+ if( bValid1 )
+ return &rBorderLine1;
+ if( bValid2 )
+ return &rBorderLine2;
+ return 0;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+Border::Border( const WorkbookHelper& rHelper, bool bDxf ) :
+ WorkbookHelper( rHelper ),
+ maOoxData( bDxf ),
+ mbDxf( bDxf )
+{
+}
+
+bool Border::isSupportedContext( sal_Int32 nElement, sal_Int32 nParentContext )
+{
+ switch( nParentContext )
+ {
+ case XLS_TOKEN( border ):
+ return (nElement == XLS_TOKEN( left )) ||
+ (nElement == XLS_TOKEN( right )) ||
+ (nElement == XLS_TOKEN( top )) ||
+ (nElement == XLS_TOKEN( bottom )) ||
+ (nElement == XLS_TOKEN( diagonal ));
+ case XLS_TOKEN( left ):
+ case XLS_TOKEN( right ):
+ case XLS_TOKEN( top ):
+ case XLS_TOKEN( bottom ):
+ case XLS_TOKEN( diagonal ):
+ return (nElement == XLS_TOKEN( color ));
+ }
+ return false;
+}
+
+void Border::importBorder( const AttributeList& rAttribs )
+{
+ maOoxData.mbDiagTLtoBR = rAttribs.getBool( XML_diagonalDown, false );
+ maOoxData.mbDiagBLtoTR = rAttribs.getBool( XML_diagonalUp, false );
+}
+
+void Border::importStyle( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( OoxBorderLineData* pBorderLine = getBorderLine( nElement ) )
+ {
+ pBorderLine->mnStyle = rAttribs.getToken( XML_style, XML_none );
+ pBorderLine->mbUsed = true;
+ }
+}
+
+void Border::importColor( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( OoxBorderLineData* pBorderLine = getBorderLine( nElement ) )
+ pBorderLine->maColor.importColor( rAttribs );
+}
+
+void Border::importBorder( RecordInputStream& rStrm )
+{
+ sal_uInt8 nFlags = rStrm.readuInt8();
+ maOoxData.mbDiagTLtoBR = getFlag( nFlags, OOBIN_BORDER_DIAG_TLBR );
+ maOoxData.mbDiagBLtoTR = getFlag( nFlags, OOBIN_BORDER_DIAG_BLTR );
+ maOoxData.maTop.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maOoxData.maTop.maColor;
+ maOoxData.maBottom.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maOoxData.maBottom.maColor;
+ maOoxData.maLeft.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maOoxData.maLeft.maColor;
+ maOoxData.maRight.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maOoxData.maRight.maColor;
+ maOoxData.maDiagonal.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maOoxData.maDiagonal.maColor;
+}
+
+void Border::importDxfBorder( sal_Int32 nElement, RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Border::importDxfBorder - missing conditional formatting flag" );
+ if( OoxBorderLineData* pBorderLine = getBorderLine( nElement ) )
+ {
+ sal_uInt16 nStyle;
+ rStrm >> pBorderLine->maColor >> nStyle;
+ pBorderLine->setBiffStyle( nStyle );
+ pBorderLine->mbUsed = true;
+ }
+}
+
+void Border::setBiff2Data( sal_uInt8 nFlags )
+{
+ OSL_ENSURE( !mbDxf, "Border::setBiff2Data - unexpected conditional formatting flag" );
+ maOoxData.maLeft.setBiffData( getFlagValue( nFlags, BIFF2_XF_LEFTLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK );
+ maOoxData.maRight.setBiffData( getFlagValue( nFlags, BIFF2_XF_RIGHTLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK );
+ maOoxData.maTop.setBiffData( getFlagValue( nFlags, BIFF2_XF_TOPLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK );
+ maOoxData.maBottom.setBiffData( getFlagValue( nFlags, BIFF2_XF_BOTTOMLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK );
+ maOoxData.maDiagonal.mbUsed = false;
+}
+
+void Border::setBiff3Data( sal_uInt32 nBorder )
+{
+ OSL_ENSURE( !mbDxf, "Border::setBiff3Data - unexpected conditional formatting flag" );
+ maOoxData.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder, 8, 3 ), extractValue< sal_uInt16 >( nBorder, 11, 5 ) );
+ maOoxData.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder, 24, 3 ), extractValue< sal_uInt16 >( nBorder, 27, 5 ) );
+ maOoxData.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder, 0, 3 ), extractValue< sal_uInt16 >( nBorder, 3, 5 ) );
+ maOoxData.maBottom.setBiffData( extractValue< sal_uInt8 >( nBorder, 16, 3 ), extractValue< sal_uInt16 >( nBorder, 19, 5 ) );
+ maOoxData.maDiagonal.mbUsed = false;
+}
+
+void Border::setBiff5Data( sal_uInt32 nBorder, sal_uInt32 nArea )
+{
+ OSL_ENSURE( !mbDxf, "Border::setBiff5Data - unexpected conditional formatting flag" );
+ maOoxData.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder, 3, 3 ), extractValue< sal_uInt16 >( nBorder, 16, 7 ) );
+ maOoxData.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder, 6, 3 ), extractValue< sal_uInt16 >( nBorder, 23, 7 ) );
+ maOoxData.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder, 0, 3 ), extractValue< sal_uInt16 >( nBorder, 9, 7 ) );
+ maOoxData.maBottom.setBiffData( extractValue< sal_uInt8 >( nArea, 22, 3 ), extractValue< sal_uInt16 >( nArea, 25, 7 ) );
+ maOoxData.maDiagonal.mbUsed = false;
+}
+
+void Border::setBiff8Data( sal_uInt32 nBorder1, sal_uInt32 nBorder2 )
+{
+ OSL_ENSURE( !mbDxf, "Border::setBiff8Data - unexpected conditional formatting flag" );
+ maOoxData.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder1, 0, 4 ), extractValue< sal_uInt16 >( nBorder1, 16, 7 ) );
+ maOoxData.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder1, 4, 4 ), extractValue< sal_uInt16 >( nBorder1, 23, 7 ) );
+ maOoxData.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder1, 8, 4 ), extractValue< sal_uInt16 >( nBorder2, 0, 7 ) );
+ maOoxData.maBottom.setBiffData( extractValue< sal_uInt8 >( nBorder1, 12, 4 ), extractValue< sal_uInt16 >( nBorder2, 7, 7 ) );
+ maOoxData.mbDiagTLtoBR = getFlag( nBorder1, BIFF_XF_DIAG_TLBR );
+ maOoxData.mbDiagBLtoTR = getFlag( nBorder1, BIFF_XF_DIAG_BLTR );
+ if( maOoxData.mbDiagTLtoBR || maOoxData.mbDiagBLtoTR )
+ maOoxData.maDiagonal.setBiffData( extractValue< sal_uInt8 >( nBorder2, 21, 4 ), extractValue< sal_uInt16 >( nBorder2, 14, 7 ) );
+}
+
+void Border::importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags )
+{
+ OSL_ENSURE( mbDxf, "Border::importCfRule - missing conditional formatting flag" );
+ OSL_ENSURE( getFlag( nFlags, BIFF_CFRULE_BORDERBLOCK ), "Border::importCfRule - missing border block flag" );
+ sal_uInt16 nStyle;
+ sal_uInt32 nColor;
+ rStrm >> nStyle >> nColor;
+ rStrm.skip( 2 );
+ maOoxData.maLeft.setBiffData( extractValue< sal_uInt8 >( nStyle, 0, 4 ), extractValue< sal_uInt16 >( nColor, 0, 7 ) );
+ maOoxData.maRight.setBiffData( extractValue< sal_uInt8 >( nStyle, 4, 4 ), extractValue< sal_uInt16 >( nColor, 7, 7 ) );
+ maOoxData.maTop.setBiffData( extractValue< sal_uInt8 >( nStyle, 8, 4 ), extractValue< sal_uInt16 >( nColor, 16, 7 ) );
+ maOoxData.maBottom.setBiffData( extractValue< sal_uInt8 >( nStyle, 12, 4 ), extractValue< sal_uInt16 >( nColor, 23, 7 ) );
+ maOoxData.maLeft.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_LEFT );
+ maOoxData.maRight.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_RIGHT );
+ maOoxData.maTop.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_TOP );
+ maOoxData.maBottom.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_BOTTOM );
+}
+
+void Border::finalizeImport()
+{
+ maApiData.mbBorderUsed = maOoxData.maLeft.mbUsed || maOoxData.maRight.mbUsed || maOoxData.maTop.mbUsed || maOoxData.maBottom.mbUsed;
+ maApiData.mbDiagUsed = maOoxData.maDiagonal.mbUsed;
+
+ maApiData.maBorder.IsLeftLineValid = convertBorderLine( maApiData.maBorder.LeftLine, maOoxData.maLeft );
+ maApiData.maBorder.IsRightLineValid = convertBorderLine( maApiData.maBorder.RightLine, maOoxData.maRight );
+ maApiData.maBorder.IsTopLineValid = convertBorderLine( maApiData.maBorder.TopLine, maOoxData.maTop );
+ maApiData.maBorder.IsBottomLineValid = convertBorderLine( maApiData.maBorder.BottomLine, maOoxData.maBottom );
+
+ if( !mbDxf )
+ {
+ maApiData.maBorder.IsVerticalLineValid = maApiData.maBorder.IsLeftLineValid || maApiData.maBorder.IsRightLineValid;
+ if( const BorderLine* pVertLine = lclGetThickerLine( maApiData.maBorder.LeftLine, maApiData.maBorder.IsLeftLineValid, maApiData.maBorder.RightLine, maApiData.maBorder.IsRightLineValid ) )
+ maApiData.maBorder.VerticalLine = *pVertLine;
+
+ maApiData.maBorder.IsHorizontalLineValid = maApiData.maBorder.IsTopLineValid || maApiData.maBorder.IsBottomLineValid;
+ if( const BorderLine* pHorLine = lclGetThickerLine( maApiData.maBorder.TopLine, maApiData.maBorder.IsTopLineValid, maApiData.maBorder.BottomLine, maApiData.maBorder.IsBottomLineValid ) )
+ maApiData.maBorder.HorizontalLine = *pHorLine;
+ }
+
+ if( maOoxData.mbDiagTLtoBR )
+ convertBorderLine( maApiData.maTLtoBR, maOoxData.maDiagonal );
+ if( maOoxData.mbDiagBLtoTR )
+ convertBorderLine( maApiData.maBLtoTR, maOoxData.maDiagonal );
+}
+
+void Border::writeToPropertySet( PropertySet& rPropSet ) const
+{
+ getStylesPropertyHelper().writeBorderProperties( rPropSet, maApiData );
+}
+
+OoxBorderLineData* Border::getBorderLine( sal_Int32 nElement )
+{
+ switch( nElement )
+ {
+ case XLS_TOKEN( left ): return &maOoxData.maLeft;
+ case XLS_TOKEN( right ): return &maOoxData.maRight;
+ case XLS_TOKEN( top ): return &maOoxData.maTop;
+ case XLS_TOKEN( bottom ): return &maOoxData.maBottom;
+ case XLS_TOKEN( diagonal ): return &maOoxData.maDiagonal;
+ }
+ return 0;
+}
+
+bool Border::convertBorderLine( BorderLine& rBorderLine, const OoxBorderLineData& rLineData )
+{
+ rBorderLine.Color = getStyles().getColor( rLineData.maColor, API_RGB_BLACK );
+ switch( rLineData.mnStyle )
+ {
+ case XML_dashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break;
+ case XML_dashDotDot: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break;
+ case XML_dashed: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break;
+ case XML_dotted: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break;
+ case XML_double: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN, API_LINE_THIN, API_LINE_THIN ); break;
+ case XML_hair: lclSetBorderLineWidth( rBorderLine, API_LINE_HAIR ); break;
+ case XML_medium: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break;
+ case XML_mediumDashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break;
+ case XML_mediumDashDotDot: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break;
+ case XML_mediumDashed: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break;
+ case XML_none: lclSetBorderLineWidth( rBorderLine, API_LINE_NONE ); break;
+ case XML_slantDashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break;
+ case XML_thick: lclSetBorderLineWidth( rBorderLine, API_LINE_THICK ); break;
+ case XML_thin: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break;
+ default: lclSetBorderLineWidth( rBorderLine, API_LINE_NONE ); break;
+ }
+ return rLineData.mbUsed;
+}
+
+
+// ============================================================================
+
+OoxPatternFillData::OoxPatternFillData( bool bDxf ) :
+ maPatternColor( XML_indexed, OOX_COLOR_WINDOWTEXT ),
+ maFillColor( XML_indexed, OOX_COLOR_WINDOWBACK ),
+ mnPattern( XML_none ),
+ mbPattColorUsed( !bDxf ),
+ mbFillColorUsed( !bDxf ),
+ mbPatternUsed( !bDxf )
+{
+}
+
+void OoxPatternFillData::setBinPattern( sal_Int32 nPattern )
+{
+ static const sal_Int32 spnPatternIds[] = {
+ XML_none, XML_solid, XML_mediumGray, XML_darkGray,
+ XML_lightGray, XML_darkHorizontal, XML_darkVertical, XML_darkDown,
+ XML_darkUp, XML_darkGrid, XML_darkTrellis, XML_lightHorizontal,
+ XML_lightVertical, XML_lightDown, XML_lightUp, XML_lightGrid,
+ XML_lightTrellis, XML_gray125, XML_gray0625 };
+ mnPattern = STATIC_ARRAY_SELECT( spnPatternIds, nPattern, XML_none );
+}
+
+void OoxPatternFillData::setBiffData( sal_uInt16 nPatternColor, sal_uInt16 nFillColor, sal_uInt8 nPattern )
+{
+ maPatternColor.set( XML_indexed, static_cast< sal_Int32 >( nPatternColor ) );
+ maFillColor.set( XML_indexed, static_cast< sal_Int32 >( nFillColor ) );
+ // patterns equal in BIFF and OOBIN
+ setBinPattern( nPattern );
+}
+
+// ----------------------------------------------------------------------------
+
+OoxGradientFillData::OoxGradientFillData() :
+ mnType( XML_linear ),
+ mfAngle( 0.0 ),
+ mfLeft( 0.0 ),
+ mfRight( 0.0 ),
+ mfTop( 0.0 ),
+ mfBottom( 0.0 )
+{
+}
+
+void OoxGradientFillData::readGradient( RecordInputStream& rStrm )
+{
+ sal_Int32 nType;
+ rStrm >> nType >> mfAngle >> mfLeft >> mfRight >> mfTop >> mfBottom;
+ static const sal_Int32 spnTypes[] = { XML_linear, XML_path };
+ mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_TOKEN_INVALID );
+}
+
+void OoxGradientFillData::readGradientStop( RecordInputStream& rStrm, bool bDxf )
+{
+ OoxColor aColor;
+ double fPosition;
+ if( bDxf )
+ {
+ rStrm.skip( 2 );
+ rStrm >> fPosition >> aColor;
+ }
+ else
+ {
+ rStrm >> aColor >> fPosition;
+ }
+ if( rStrm.isValid() && (fPosition >= 0.0) )
+ maColors[ fPosition ] = aColor;
+}
+
+// ============================================================================
+
+namespace {
+
+inline sal_Int32 lclGetMixedColorComp( sal_Int32 nPatt, sal_Int32 nFill, sal_Int32 nAlpha )
+{
+ return ((nPatt - nFill) * nAlpha) / 0x80 + nFill;
+}
+
+sal_Int32 lclGetMixedColor( sal_Int32 nPattColor, sal_Int32 nFillColor, sal_Int32 nAlpha )
+{
+ return
+ (lclGetMixedColorComp( nPattColor & 0xFF0000, nFillColor & 0xFF0000, nAlpha ) & 0xFF0000) |
+ (lclGetMixedColorComp( nPattColor & 0x00FF00, nFillColor & 0x00FF00, nAlpha ) & 0x00FF00) |
+ (lclGetMixedColorComp( nPattColor & 0x0000FF, nFillColor & 0x0000FF, nAlpha ) & 0x0000FF);
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+Fill::Fill( const WorkbookHelper& rHelper, bool bDxf ) :
+ WorkbookHelper( rHelper ),
+ mbDxf( bDxf )
+{
+}
+
+bool Fill::isSupportedContext( sal_Int32 nElement, sal_Int32 nParentContext )
+{
+ switch( nParentContext )
+ {
+ case XLS_TOKEN( fill ):
+ return (nElement == XLS_TOKEN( patternFill )) ||
+ (nElement == XLS_TOKEN( gradientFill ));
+ case XLS_TOKEN( patternFill ):
+ return (nElement == XLS_TOKEN( fgColor )) ||
+ (nElement == XLS_TOKEN( bgColor ));
+ case XLS_TOKEN( gradientFill ):
+ return (nElement == XLS_TOKEN( stop ));
+ case XLS_TOKEN( stop ):
+ return (nElement == XLS_TOKEN( color ));
+ }
+ return false;
+}
+
+void Fill::importPatternFill( const AttributeList& rAttribs )
+{
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->mnPattern = rAttribs.getToken( XML_patternType, XML_none );
+ if( mbDxf )
+ mxOoxPattData->mbPatternUsed = rAttribs.hasAttribute( XML_patternType );
+}
+
+void Fill::importFgColor( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( mxOoxPattData.get(), "Fill::importFgColor - missing pattern data" );
+ if( mxOoxPattData.get() )
+ {
+ mxOoxPattData->maPatternColor.importColor( rAttribs );
+ mxOoxPattData->mbPattColorUsed = true;
+ }
+}
+
+void Fill::importBgColor( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( mxOoxPattData.get(), "Fill::importBgColor - missing pattern data" );
+ if( mxOoxPattData.get() )
+ {
+ mxOoxPattData->maFillColor.importColor( rAttribs );
+ mxOoxPattData->mbFillColorUsed = true;
+ }
+}
+
+void Fill::importGradientFill( const AttributeList& rAttribs )
+{
+ mxOoxGradData.reset( new OoxGradientFillData );
+ mxOoxGradData->mnType = rAttribs.getToken( XML_type, XML_linear );
+ mxOoxGradData->mfAngle = rAttribs.getDouble( XML_degree, 0.0 );
+ mxOoxGradData->mfLeft = rAttribs.getDouble( XML_left, 0.0 );
+ mxOoxGradData->mfRight = rAttribs.getDouble( XML_right, 0.0 );
+ mxOoxGradData->mfTop = rAttribs.getDouble( XML_top, 0.0 );
+ mxOoxGradData->mfBottom = rAttribs.getDouble( XML_bottom, 0.0 );
+}
+
+void Fill::importColor( const AttributeList& rAttribs, double fPosition )
+{
+ OSL_ENSURE( mxOoxGradData.get(), "Fill::importColor - missing gradient data" );
+ if( mxOoxGradData.get() && (fPosition >= 0.0) )
+ mxOoxGradData->maColors[ fPosition ].importColor( rAttribs );
+}
+
+void Fill::importFill( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( !mbDxf, "Fill::importFill - unexpected conditional formatting flag" );
+ sal_Int32 nPattern = rStrm.readInt32();
+ if( nPattern == OOBIN_FILL_GRADIENT )
+ {
+ mxOoxGradData.reset( new OoxGradientFillData );
+ sal_Int32 nStopCount;
+ rStrm.skip( 16 );
+ mxOoxGradData->readGradient( rStrm );
+ rStrm >> nStopCount;
+ for( sal_Int32 nStop = 0; (nStop < nStopCount) && rStrm.isValid(); ++nStop )
+ mxOoxGradData->readGradientStop( rStrm, false );
+ }
+ else
+ {
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->setBinPattern( nPattern );
+ rStrm >> mxOoxPattData->maPatternColor >> mxOoxPattData->maFillColor;
+ }
+}
+
+void Fill::importDxfPattern( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfPattern - missing conditional formatting flag" );
+ if( !mxOoxPattData )
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->setBinPattern( rStrm.readuInt8() );
+ mxOoxPattData->mbPatternUsed = true;
+}
+
+void Fill::importDxfFgColor( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfFgColor - missing conditional formatting flag" );
+ if( !mxOoxPattData )
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->maPatternColor.importColor( rStrm );
+ mxOoxPattData->mbPattColorUsed = true;
+}
+
+void Fill::importDxfBgColor( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfBgColor - missing conditional formatting flag" );
+ if( !mxOoxPattData )
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->maFillColor.importColor( rStrm );
+ mxOoxPattData->mbFillColorUsed = true;
+}
+
+void Fill::importDxfGradient( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfGradient - missing conditional formatting flag" );
+ if( !mxOoxGradData )
+ mxOoxGradData.reset( new OoxGradientFillData );
+ mxOoxGradData->readGradient( rStrm );
+}
+
+void Fill::importDxfStop( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfStop - missing conditional formatting flag" );
+ if( !mxOoxGradData )
+ mxOoxGradData.reset( new OoxGradientFillData );
+ mxOoxGradData->readGradientStop( rStrm, true );
+}
+
+void Fill::setBiff2Data( sal_uInt8 nFlags )
+{
+ OSL_ENSURE( !mbDxf, "Fill::setBiff2Data - unexpected conditional formatting flag" );
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->setBiffData(
+ BIFF2_COLOR_BLACK,
+ BIFF2_COLOR_WHITE,
+ getFlagValue( nFlags, BIFF2_XF_BACKGROUND, BIFF_PATT_125, BIFF_PATT_NONE ) );
+}
+
+void Fill::setBiff3Data( sal_uInt16 nArea )
+{
+ OSL_ENSURE( !mbDxf, "Fill::setBiff3Data - unexpected conditional formatting flag" );
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->setBiffData(
+ extractValue< sal_uInt16 >( nArea, 6, 5 ),
+ extractValue< sal_uInt16 >( nArea, 11, 5 ),
+ extractValue< sal_uInt8 >( nArea, 0, 6 ) );
+}
+
+void Fill::setBiff5Data( sal_uInt32 nArea )
+{
+ OSL_ENSURE( !mbDxf, "Fill::setBiff5Data - unexpected conditional formatting flag" );
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->setBiffData(
+ extractValue< sal_uInt16 >( nArea, 0, 7 ),
+ extractValue< sal_uInt16 >( nArea, 7, 7 ),
+ extractValue< sal_uInt8 >( nArea, 16, 6 ) );
+}
+
+void Fill::setBiff8Data( sal_uInt32 nBorder2, sal_uInt16 nArea )
+{
+ OSL_ENSURE( !mbDxf, "Fill::setBiff8Data - unexpected conditional formatting flag" );
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ mxOoxPattData->setBiffData(
+ extractValue< sal_uInt16 >( nArea, 0, 7 ),
+ extractValue< sal_uInt16 >( nArea, 7, 7 ),
+ extractValue< sal_uInt8 >( nBorder2, 26, 6 ) );
+}
+
+void Fill::importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags )
+{
+ OSL_ENSURE( mbDxf, "Fill::importCfRule - missing conditional formatting flag" );
+ OSL_ENSURE( getFlag( nFlags, BIFF_CFRULE_FILLBLOCK ), "Fill::importCfRule - missing fill block flag" );
+ mxOoxPattData.reset( new OoxPatternFillData( mbDxf ) );
+ sal_uInt32 nFillData;
+ rStrm >> nFillData;
+ mxOoxPattData->setBiffData(
+ extractValue< sal_uInt16 >( nFillData, 16, 7 ),
+ extractValue< sal_uInt16 >( nFillData, 23, 7 ),
+ extractValue< sal_uInt8 >( nFillData, 10, 6 ) );
+ mxOoxPattData->mbPattColorUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_PATTCOLOR );
+ mxOoxPattData->mbFillColorUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_FILLCOLOR );
+ mxOoxPattData->mbPatternUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_PATTERN );
+}
+
+void Fill::finalizeImport()
+{
+ if( mxOoxPattData.get() )
+ {
+ // finalize the OOX data struct
+ OoxPatternFillData& rOoxData = *mxOoxPattData;
+ if( mbDxf )
+ {
+ if( rOoxData.mbFillColorUsed && (!rOoxData.mbPatternUsed || (rOoxData.mnPattern == XML_solid)) )
+ {
+ rOoxData.maPatternColor = rOoxData.maFillColor;
+ rOoxData.mnPattern = XML_solid;
+ rOoxData.mbPattColorUsed = rOoxData.mbPatternUsed = true;
+ }
+ else if( !rOoxData.mbFillColorUsed && rOoxData.mbPatternUsed && (rOoxData.mnPattern == XML_solid) )
+ {
+ rOoxData.mbPatternUsed = false;
+ }
+ }
+
+ // convert to API fill settings
+ maApiData.mbUsed = rOoxData.mbPatternUsed;
+ if( rOoxData.mnPattern == XML_none )
+ {
+ maApiData.mnColor = API_RGB_TRANSPARENT;
+ maApiData.mbTransparent = true;
+ }
+ else
+ {
+ sal_Int32 nAlpha = 0x80;
+ switch( rOoxData.mnPattern )
+ {
+ case XML_darkDown: nAlpha = 0x40; break;
+ case XML_darkGray: nAlpha = 0x60; break;
+ case XML_darkGrid: nAlpha = 0x40; break;
+ case XML_darkHorizontal: nAlpha = 0x40; break;
+ case XML_darkTrellis: nAlpha = 0x60; break;
+ case XML_darkUp: nAlpha = 0x40; break;
+ case XML_darkVertical: nAlpha = 0x40; break;
+ case XML_gray0625: nAlpha = 0x08; break;
+ case XML_gray125: nAlpha = 0x10; break;
+ case XML_lightDown: nAlpha = 0x20; break;
+ case XML_lightGray: nAlpha = 0x20; break;
+ case XML_lightGrid: nAlpha = 0x38; break;
+ case XML_lightHorizontal: nAlpha = 0x20; break;
+ case XML_lightTrellis: nAlpha = 0x30; break;
+ case XML_lightUp: nAlpha = 0x20; break;
+ case XML_lightVertical: nAlpha = 0x20; break;
+ case XML_mediumGray: nAlpha = 0x40; break;
+ case XML_solid: nAlpha = 0x80; break;
+ }
+
+ if( !rOoxData.mbPattColorUsed )
+ rOoxData.maPatternColor.set( XML_auto, 0 );
+ sal_Int32 nPattColor = getStyles().getColor(
+ rOoxData.maPatternColor, ThemeBuffer::getSystemWindowTextColor() );
+
+ if( !rOoxData.mbFillColorUsed )
+ rOoxData.maFillColor.set( XML_auto, 0 );
+ sal_Int32 nFillColor = getStyles().getColor(
+ rOoxData.maFillColor, ThemeBuffer::getSystemWindowColor() );
+
+ maApiData.mnColor = lclGetMixedColor( nPattColor, nFillColor, nAlpha );
+ maApiData.mbTransparent = false;
+ }
+ }
+ else if( mxOoxGradData.get() && !mxOoxGradData->maColors.empty() )
+ {
+ OoxGradientFillData& rOoxData = *mxOoxGradData;
+ maApiData.mbUsed = true; // no support for differential attributes
+ OoxGradientFillData::OoxColorMap::const_iterator aIt = rOoxData.maColors.begin();
+ OSL_ENSURE( !aIt->second.isAuto(), "Fill::finalizeImport - automatic gradient color" );
+ maApiData.mnColor = getStyles().getColor( aIt->second, API_RGB_TRANSPARENT );
+ if( ++aIt != rOoxData.maColors.end() )
+ {
+ OSL_ENSURE( !aIt->second.isAuto(), "Fill::finalizeImport - automatic gradient color" );
+ sal_Int32 nEndColor = getStyles().getColor( aIt->second, API_RGB_TRANSPARENT );
+ maApiData.mnColor = lclGetMixedColor( maApiData.mnColor, nEndColor, 0x40 );
+ maApiData.mbTransparent = false;
+ }
+ }
+}
+
+void Fill::writeToPropertySet( PropertySet& rPropSet ) const
+{
+ getStylesPropertyHelper().writeSolidFillProperties( rPropSet, maApiData );
+}
+
+// ============================================================================
+
+OoxXfData::OoxXfData() :
+ mnStyleXfId( -1 ),
+ mnFontId( -1 ),
+ mnNumFmtId( -1 ),
+ mnBorderId( -1 ),
+ mnFillId( -1 ),
+ mbCellXf( true ),
+ mbFontUsed( false ),
+ mbNumFmtUsed( false ),
+ mbAlignUsed( false ),
+ mbProtUsed( false ),
+ mbBorderUsed( false ),
+ mbAreaUsed( false )
+{
+}
+
+// ============================================================================
+
+Xf::Xf( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maAlignment( rHelper ),
+ maProtection( rHelper )
+{
+}
+
+void Xf::setAllUsedFlags( bool bUsed )
+{
+ maOoxData.mbAlignUsed = maOoxData.mbProtUsed = maOoxData.mbFontUsed =
+ maOoxData.mbNumFmtUsed = maOoxData.mbBorderUsed = maOoxData.mbAreaUsed = bUsed;
+}
+
+void Xf::importXf( const AttributeList& rAttribs, bool bCellXf )
+{
+ maOoxData.mbCellXf = bCellXf;
+ maOoxData.mnStyleXfId = rAttribs.getInteger( XML_xfId, -1 );
+ maOoxData.mnFontId = rAttribs.getInteger( XML_fontId, -1 );
+ maOoxData.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, -1 );
+ maOoxData.mnBorderId = rAttribs.getInteger( XML_borderId, -1 );
+ maOoxData.mnFillId = rAttribs.getInteger( XML_fillId, -1 );
+
+ /* Default value of the apply*** attributes is dependent on context:
+ true in cellStyleXfs element, false in cellXfs element... */
+ maOoxData.mbAlignUsed = rAttribs.getBool( XML_applyAlignment, !maOoxData.mbCellXf );
+ maOoxData.mbProtUsed = rAttribs.getBool( XML_applyProtection, !maOoxData.mbCellXf );
+ maOoxData.mbFontUsed = rAttribs.getBool( XML_applyFont, !maOoxData.mbCellXf );
+ maOoxData.mbNumFmtUsed = rAttribs.getBool( XML_applyNumberFormat, !maOoxData.mbCellXf );
+ maOoxData.mbBorderUsed = rAttribs.getBool( XML_applyBorder, !maOoxData.mbCellXf );
+ maOoxData.mbAreaUsed = rAttribs.getBool( XML_applyFill, !maOoxData.mbCellXf );
+}
+
+void Xf::importAlignment( const AttributeList& rAttribs )
+{
+ maAlignment.importAlignment( rAttribs );
+}
+
+void Xf::importProtection( const AttributeList& rAttribs )
+{
+ maProtection.importProtection( rAttribs );
+}
+
+void Xf::importXf( RecordInputStream& rStrm, bool bCellXf )
+{
+ maOoxData.mbCellXf = bCellXf;
+ maOoxData.mnStyleXfId = rStrm.readuInt16();
+ maOoxData.mnNumFmtId = rStrm.readuInt16();
+ maOoxData.mnFontId = rStrm.readuInt16();
+ maOoxData.mnFillId = rStrm.readuInt16();
+ maOoxData.mnBorderId = rStrm.readuInt16();
+ sal_uInt32 nFlags = rStrm.readuInt32();
+ maAlignment.setBinData( nFlags );
+ maProtection.setBinData( nFlags );
+ // used flags, see comments in Xf::setBiffUsedFlags()
+ sal_uInt16 nUsedFlags = rStrm.readuInt16();
+ maOoxData.mbFontUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_FONT_USED );
+ maOoxData.mbNumFmtUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_NUMFMT_USED );
+ maOoxData.mbAlignUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_ALIGN_USED );
+ maOoxData.mbProtUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_PROT_USED );
+ maOoxData.mbBorderUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_BORDER_USED );
+ maOoxData.mbAreaUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_AREA_USED );
+}
+
+void Xf::importXf( BiffInputStream& rStrm )
+{
+ BorderRef xBorder = getStyles().createBorder( &maOoxData.mnBorderId );
+ FillRef xFill = getStyles().createFill( &maOoxData.mnFillId );
+
+ switch( getBiff() )
+ {
+ case BIFF2:
+ {
+ sal_uInt8 nFontId, nNumFmtId, nFlags;
+ rStrm >> nFontId;
+ rStrm.skip( 1 );
+ rStrm >> nNumFmtId >> nFlags;
+
+ // only cell XFs in BIFF2, no parent style, used flags always true
+ setAllUsedFlags( true );
+
+ // attributes
+ maAlignment.setBiff2Data( nFlags );
+ maProtection.setBiff2Data( nNumFmtId );
+ xBorder->setBiff2Data( nFlags );
+ xFill->setBiff2Data( nFlags );
+ maOoxData.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maOoxData.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId & BIFF2_XF_VALFMT_MASK );
+ }
+ break;
+
+ case BIFF3:
+ {
+ sal_uInt32 nBorder;
+ sal_uInt16 nTypeProt, nAlign, nArea;
+ sal_uInt8 nFontId, nNumFmtId;
+ rStrm >> nFontId >> nNumFmtId >> nTypeProt >> nAlign >> nArea >> nBorder;
+
+ // XF type/parent
+ maOoxData.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE ); // new in BIFF3
+ maOoxData.mnStyleXfId = extractValue< sal_Int32 >( nAlign, 4, 12 ); // new in BIFF3
+ // attribute used flags
+ setBiffUsedFlags( extractValue< sal_uInt8 >( nTypeProt, 10, 6 ) ); // new in BIFF3
+
+ // attributes
+ maAlignment.setBiff3Data( nAlign );
+ maProtection.setBiff3Data( nTypeProt );
+ xBorder->setBiff3Data( nBorder );
+ xFill->setBiff3Data( nArea );
+ maOoxData.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maOoxData.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId );
+ }
+ break;
+
+ case BIFF4:
+ {
+ sal_uInt32 nBorder;
+ sal_uInt16 nTypeProt, nAlign, nArea;
+ sal_uInt8 nFontId, nNumFmtId;
+ rStrm >> nFontId >> nNumFmtId >> nTypeProt >> nAlign >> nArea >> nBorder;
+
+ // XF type/parent
+ maOoxData.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE );
+ maOoxData.mnStyleXfId = extractValue< sal_Int32 >( nTypeProt, 4, 12 );
+ // attribute used flags
+ setBiffUsedFlags( extractValue< sal_uInt8 >( nAlign, 10, 6 ) );
+
+ // attributes
+ maAlignment.setBiff4Data( nAlign );
+ maProtection.setBiff3Data( nTypeProt );
+ xBorder->setBiff3Data( nBorder );
+ xFill->setBiff3Data( nArea );
+ maOoxData.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maOoxData.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId );
+ }
+ break;
+
+ case BIFF5:
+ {
+ sal_uInt32 nArea, nBorder;
+ sal_uInt16 nFontId, nNumFmtId, nTypeProt, nAlign;
+ rStrm >> nFontId >> nNumFmtId >> nTypeProt >> nAlign >> nArea >> nBorder;
+
+ // XF type/parent
+ maOoxData.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE );
+ maOoxData.mnStyleXfId = extractValue< sal_Int32 >( nTypeProt, 4, 12 );
+ // attribute used flags
+ setBiffUsedFlags( extractValue< sal_uInt8 >( nAlign, 10, 6 ) );
+
+ // attributes
+ maAlignment.setBiff5Data( nAlign );
+ maProtection.setBiff3Data( nTypeProt );
+ xBorder->setBiff5Data( nBorder, nArea );
+ xFill->setBiff5Data( nArea );
+ maOoxData.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maOoxData.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId );
+ }
+ break;
+
+ case BIFF8:
+ {
+ sal_uInt32 nBorder1, nBorder2;
+ sal_uInt16 nFontId, nNumFmtId, nTypeProt, nAlign, nMiscAttrib, nArea;
+ rStrm >> nFontId >> nNumFmtId >> nTypeProt >> nAlign >> nMiscAttrib >> nBorder1 >> nBorder2 >> nArea;
+
+ // XF type/parent
+ maOoxData.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE );
+ maOoxData.mnStyleXfId = extractValue< sal_Int32 >( nTypeProt, 4, 12 );
+ // attribute used flags
+ setBiffUsedFlags( extractValue< sal_uInt8 >( nMiscAttrib, 10, 6 ) );
+
+ // attributes
+ maAlignment.setBiff8Data( nAlign, nMiscAttrib );
+ maProtection.setBiff3Data( nTypeProt );
+ xBorder->setBiff8Data( nBorder1, nBorder2 );
+ xFill->setBiff8Data( nBorder2, nArea );
+ maOoxData.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maOoxData.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId );
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+}
+
+void Xf::finalizeImport()
+{
+ // alignment and protection
+ maAlignment.finalizeImport();
+ maProtection.finalizeImport();
+ // update used flags from cell style
+ if( maOoxData.mbCellXf )
+ if( const Xf* pStyleXf = getStyles().getStyleXf( maOoxData.mnStyleXfId ).get() )
+ updateUsedFlags( *pStyleXf );
+}
+
+FontRef Xf::getFont() const
+{
+ return getStyles().getFont( maOoxData.mnFontId );
+}
+
+bool Xf::hasAnyUsedFlags() const
+{
+ return
+ maOoxData.mbAlignUsed || maOoxData.mbProtUsed || maOoxData.mbFontUsed ||
+ maOoxData.mbNumFmtUsed || maOoxData.mbBorderUsed || maOoxData.mbAreaUsed;
+}
+
+void Xf::writeToPropertySet( PropertySet& rPropSet ) const
+{
+ StylesBuffer& rStyles = getStyles();
+
+ // create and set cell style
+ if( maOoxData.mbCellXf )
+ {
+ const OUString& rStyleName = rStyles.createCellStyle( maOoxData.mnStyleXfId );
+ rPropSet.setProperty( CREATE_OUSTRING( "CellStyle" ), rStyleName );
+ }
+
+ if( maOoxData.mbFontUsed )
+ rStyles.writeFontToPropertySet( rPropSet, maOoxData.mnFontId );
+ if( maOoxData.mbNumFmtUsed )
+ rStyles.writeNumFmtToPropertySet( rPropSet, maOoxData.mnNumFmtId );
+ if( maOoxData.mbAlignUsed )
+ maAlignment.writeToPropertySet( rPropSet );
+ if( maOoxData.mbProtUsed )
+ maProtection.writeToPropertySet( rPropSet );
+ if( maOoxData.mbBorderUsed )
+ rStyles.writeBorderToPropertySet( rPropSet, maOoxData.mnBorderId );
+ if( maOoxData.mbAreaUsed )
+ rStyles.writeFillToPropertySet( rPropSet, maOoxData.mnFillId );
+}
+
+void Xf::setBiffUsedFlags( sal_uInt8 nUsedFlags )
+{
+ /* Notes about finding the used flags:
+ - In cell XFs a *set* bit means a used attribute.
+ - In style XFs a *cleared* bit means a used attribute.
+ The boolean flags always store true, if the attribute is used.
+ The "maOoxData.mbCellXf == getFlag(...)" construct evaluates to true in
+ both mentioned cases: cell XF and set bit; or style XF and cleared bit.
+ */
+ maOoxData.mbFontUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, BIFF_XF_FONT_USED );
+ maOoxData.mbNumFmtUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, BIFF_XF_NUMFMT_USED );
+ maOoxData.mbAlignUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, BIFF_XF_ALIGN_USED );
+ maOoxData.mbProtUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, BIFF_XF_PROT_USED );
+ maOoxData.mbBorderUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, BIFF_XF_BORDER_USED );
+ maOoxData.mbAreaUsed = maOoxData.mbCellXf == getFlag( nUsedFlags, BIFF_XF_AREA_USED );
+}
+
+void Xf::updateUsedFlags( const Xf& rStyleXf )
+{
+ /* Enables the used flags, if the formatting attributes differ from the
+ passed style XF. In cell XFs Excel uses the cell attributes, if they
+ differ from the parent style XF.
+ #109899# ...or if the respective flag is not set in parent style XF.
+ */
+ const OoxXfData& rStyleData = rStyleXf.maOoxData;
+ if( !maOoxData.mbFontUsed )
+ maOoxData.mbFontUsed = !rStyleData.mbFontUsed || (maOoxData.mnFontId != rStyleData.mnFontId);
+ if( !maOoxData.mbNumFmtUsed )
+ maOoxData.mbNumFmtUsed = !rStyleData.mbNumFmtUsed || (maOoxData.mnNumFmtId != rStyleData.mnNumFmtId);
+ if( !maOoxData.mbAlignUsed )
+ maOoxData.mbAlignUsed = !rStyleData.mbAlignUsed || !(maAlignment.getApiData() == rStyleXf.maAlignment.getApiData());
+ if( !maOoxData.mbProtUsed )
+ maOoxData.mbProtUsed = !rStyleData.mbProtUsed || !(maProtection.getApiData() == rStyleXf.maProtection.getApiData());
+ if( !maOoxData.mbBorderUsed )
+ maOoxData.mbBorderUsed = !rStyleData.mbBorderUsed || (maOoxData.mnBorderId != rStyleData.mnBorderId);
+ if( !maOoxData.mbAreaUsed )
+ maOoxData.mbAreaUsed = !rStyleData.mbAreaUsed || (maOoxData.mnFillId != rStyleData.mnFillId);
+}
+
+// ============================================================================
+
+Dxf::Dxf( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+FontRef Dxf::importFont( const AttributeList& )
+{
+ createFont( true );
+ return mxFont;
+}
+
+void Dxf::importNumFmt( const AttributeList& rAttribs )
+{
+ mxNumFmt = getStyles().importNumFmt( rAttribs );
+}
+
+void Dxf::importAlignment( const AttributeList& rAttribs )
+{
+ mxAlignment.reset( new Alignment( *this ) );
+ mxAlignment->importAlignment( rAttribs );
+}
+
+void Dxf::importProtection( const AttributeList& rAttribs )
+{
+ mxProtection.reset( new Protection( *this ) );
+ mxProtection->importProtection( rAttribs );
+}
+
+BorderRef Dxf::importBorder( const AttributeList& rAttribs )
+{
+ createBorder( true );
+ mxBorder->importBorder( rAttribs );
+ return mxBorder;
+}
+
+FillRef Dxf::importFill( const AttributeList& )
+{
+ createFill( true );
+ return mxFill;
+}
+
+void Dxf::importDxf( RecordInputStream& rStrm )
+{
+ sal_Int32 nNumFmtId = -1;
+ OUString aFmtCode;
+ sal_uInt16 nRecCount;
+ rStrm.skip( 4 ); // flags
+ rStrm >> nRecCount;
+ for( sal_uInt16 nRec = 0; rStrm.isValid() && (nRec < nRecCount); ++nRec )
+ {
+ sal_uInt16 nSubRecId, nSubRecSize;
+ sal_Int32 nRecEnd = rStrm.getRecPos();
+ rStrm >> nSubRecId >> nSubRecSize;
+ nRecEnd += nSubRecSize;
+ switch( nSubRecId )
+ {
+ case OOBIN_DXF_FILL_PATTERN: createFill( false ); mxFill->importDxfPattern( rStrm ); break;
+ case OOBIN_DXF_FILL_FGCOLOR: createFill( false ); mxFill->importDxfFgColor( rStrm ); break;
+ case OOBIN_DXF_FILL_BGCOLOR: createFill( false ); mxFill->importDxfBgColor( rStrm ); break;
+ case OOBIN_DXF_FILL_GRADIENT: createFill( false ); mxFill->importDxfGradient( rStrm ); break;
+ case OOBIN_DXF_FILL_STOP: createFill( false ); mxFill->importDxfStop( rStrm ); break;
+ case OOBIN_DXF_FONT_COLOR: createFont( false ); mxFont->importDxfColor( rStrm ); break;
+ case OOBIN_DXF_BORDER_TOP: createBorder( false ); mxBorder->importDxfBorder( XLS_TOKEN( top ), rStrm ); break;
+ case OOBIN_DXF_BORDER_BOTTOM: createBorder( false ); mxBorder->importDxfBorder( XLS_TOKEN( bottom ), rStrm ); break;
+ case OOBIN_DXF_BORDER_LEFT: createBorder( false ); mxBorder->importDxfBorder( XLS_TOKEN( left ), rStrm ); break;
+ case OOBIN_DXF_BORDER_RIGHT: createBorder( false ); mxBorder->importDxfBorder( XLS_TOKEN( right ), rStrm ); break;
+ case OOBIN_DXF_FONT_NAME: createFont( false ); mxFont->importDxfName( rStrm ); break;
+ case OOBIN_DXF_FONT_WEIGHT: createFont( false ); mxFont->importDxfWeight( rStrm ); break;
+ case OOBIN_DXF_FONT_UNDERLINE: createFont( false ); mxFont->importDxfUnderline( rStrm ); break;
+ case OOBIN_DXF_FONT_ESCAPEMENT: createFont( false ); mxFont->importDxfEscapement( rStrm ); break;
+ case OOBIN_DXF_FONT_ITALIC: createFont( false ); mxFont->importDxfFlag( XML_i, rStrm ); break;
+ case OOBIN_DXF_FONT_STRIKE: createFont( false ); mxFont->importDxfFlag( XML_strike, rStrm ); break;
+ case OOBIN_DXF_FONT_OUTLINE: createFont( false ); mxFont->importDxfFlag( XML_outline, rStrm ); break;
+ case OOBIN_DXF_FONT_SHADOW: createFont( false ); mxFont->importDxfFlag( XML_shadow, rStrm ); break;
+ case OOBIN_DXF_FONT_HEIGHT: createFont( false ); mxFont->importDxfHeight( rStrm ); break;
+ case OOBIN_DXF_FONT_SCHEME: createFont( false ); mxFont->importDxfScheme( rStrm ); break;
+ case OOBIN_DXF_NUMFMT_CODE: aFmtCode = rStrm.readString( false ); break;
+ case OOBIN_DXF_NUMFMT_ID: nNumFmtId = rStrm.readuInt16(); break;
+ }
+ rStrm.seek( nRecEnd );
+ }
+ OSL_ENSURE( rStrm.isValid() && (rStrm.getRecLeft() == 0), "Dxf::importDxf - unexpected remaining data" );
+ mxNumFmt = getStyles().createNumFmt( nNumFmtId, aFmtCode );
+}
+
+void Dxf::importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags )
+{
+ if( getFlag( nFlags, BIFF_CFRULE_FONTBLOCK ) )
+ {
+ createFont( true );
+ mxFont->importCfRule( rStrm );
+ }
+ if( getFlag( nFlags, BIFF_CFRULE_ALIGNBLOCK ) )
+ {
+ rStrm.skip( 8 );
+ }
+ if( getFlag( nFlags, BIFF_CFRULE_BORDERBLOCK ) )
+ {
+ createBorder( true );
+ mxBorder->importCfRule( rStrm, nFlags );
+ }
+ if( getFlag( nFlags, BIFF_CFRULE_FILLBLOCK ) )
+ {
+ createFill( true );
+ mxFill->importCfRule( rStrm, nFlags );
+ }
+ if( getFlag( nFlags, BIFF_CFRULE_PROTBLOCK ) )
+ {
+ rStrm.skip( 2 );
+ }
+}
+
+void Dxf::finalizeImport()
+{
+ if( mxFont.get() )
+ mxFont->finalizeImport();
+ // number format already finalized by the number formats buffer
+ if( mxAlignment.get() )
+ mxAlignment->finalizeImport();
+ if( mxProtection.get() )
+ mxProtection->finalizeImport();
+ if( mxBorder.get() )
+ mxBorder->finalizeImport();
+ if( mxFill.get() )
+ mxFill->finalizeImport();
+}
+
+const OUString& Dxf::createDxfStyle( sal_Int32 nDxfId )
+{
+ if( maFinalName.getLength() == 0 )
+ {
+ maFinalName = OUStringBuffer( CREATE_OUSTRING( "ConditionalStyle_" ) ).append( nDxfId + 1 ).makeStringAndClear();
+ Reference< XStyle > xStyle = createStyleObject( maFinalName, false );
+ // write style formatting properties
+ PropertySet aPropSet( xStyle );
+ if( mxFont.get() )
+ mxFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_CELL );
+ if( mxNumFmt.get() )
+ mxNumFmt->writeToPropertySet( aPropSet );
+ if( mxAlignment.get() )
+ mxAlignment->writeToPropertySet( aPropSet );
+ if( mxProtection.get() )
+ mxProtection->writeToPropertySet( aPropSet );
+ if( mxBorder.get() )
+ mxBorder->writeToPropertySet( aPropSet );
+ if( mxFill.get() )
+ mxFill->writeToPropertySet( aPropSet );
+ }
+ return maFinalName;
+}
+
+void Dxf::createFont( bool bAlwaysNew )
+{
+ if( bAlwaysNew || !mxFont )
+ mxFont.reset( new Font( *this, true ) );
+}
+
+void Dxf::createBorder( bool bAlwaysNew )
+{
+ if( bAlwaysNew || !mxBorder )
+ mxBorder.reset( new Border( *this, true ) );
+}
+
+void Dxf::createFill( bool bAlwaysNew )
+{
+ if( bAlwaysNew || !mxFill )
+ mxFill.reset( new Fill( *this, true ) );
+}
+
+// ============================================================================
+
+namespace {
+
+const sal_Char* const spcLegacyStyleNamePrefix = "Excel_BuiltIn_";
+const sal_Char* const sppcLegacyStyleNames[] =
+{
+#if OOX_XLS_USE_DEFAULT_STYLE
+ "", // use existing "Default" style
+#else
+ "Normal",
+#endif
+ "RowLevel_", // outline level will be appended
+ "ColumnLevel_", // outline level will be appended
+ "Comma",
+ "Currency",
+ "Percent",
+ "Comma_0", // new in BIFF4
+ "Currency_0",
+ "Hyperlink", // new in BIFF8
+ "Followed_Hyperlink"
+};
+const sal_Int32 snLegacyStyleNamesCount = static_cast< sal_Int32 >( STATIC_ARRAY_SIZE( sppcLegacyStyleNames ) );
+
+const sal_Char* const spcStyleNamePrefix = "Excel Built-in ";
+const sal_Char* const sppcStyleNames[] =
+{
+#if OOX_XLS_USE_DEFAULT_STYLE
+ "", // use existing "Default" style
+#else
+ "Normal",
+#endif
+ "RowLevel_", // outline level will be appended
+ "ColLevel_", // outline level will be appended
+ "Comma",
+ "Currency",
+ "Percent",
+ "Comma [0]", // new in BIFF4
+ "Currency [0]",
+ "Hyperlink", // new in BIFF8
+ "Followed Hyperlink",
+ "Note", // new in OOX
+ "Warning Text",
+ "",
+ "",
+ "",
+ "Title",
+ "Heading 1",
+ "Heading 2",
+ "Heading 3",
+ "Heading 4",
+ "Input",
+ "Output",
+ "Calculation",
+ "Check Cell",
+ "Linked Cell",
+ "Total",
+ "Good",
+ "Bad",
+ "Neutral",
+ "Accent1",
+ "20% - Accent1",
+ "40% - Accent1",
+ "60% - Accent1",
+ "Accent2",
+ "20% - Accent2",
+ "40% - Accent2",
+ "60% - Accent2",
+ "Accent3",
+ "20% - Accent3",
+ "40% - Accent3",
+ "60% - Accent3",
+ "Accent4",
+ "20% - Accent4",
+ "40% - Accent4",
+ "60% - Accent4",
+ "Accent5",
+ "20% - Accent5",
+ "40% - Accent5",
+ "60% - Accent5",
+ "Accent6",
+ "20% - Accent6",
+ "40% - Accent6",
+ "60% - Accent6",
+ "Explanatory Text"
+};
+const sal_Int32 snStyleNamesCount = static_cast< sal_Int32 >( STATIC_ARRAY_SIZE( sppcStyleNames ) );
+
+#if OOX_XLS_USE_DEFAULT_STYLE
+const sal_Char* const spcDefaultStyleName = "Default";
+#endif
+
+OUString lclGetBuiltinStyleName( sal_Int32 nBuiltinId, const OUString& rName, sal_Int32 nLevel = 0 )
+{
+ OUStringBuffer aStyleName;
+ OSL_ENSURE( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount), "lclGetBuiltinStyleName - unknown builtin style" );
+#if OOX_XLS_USE_DEFAULT_STYLE
+ if( nBuiltinId == OOX_STYLE_NORMAL ) // "Normal" becomes "Default" style
+ {
+ aStyleName.appendAscii( spcDefaultStyleName );
+ }
+ else
+ {
+#endif
+ aStyleName.appendAscii( spcStyleNamePrefix );
+ if( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount) && (sppcStyleNames[ nBuiltinId ][ 0 ] != 0) )
+ aStyleName.appendAscii( sppcStyleNames[ nBuiltinId ] );
+ else if( rName.getLength() > 0 )
+ aStyleName.append( rName );
+ else
+ aStyleName.append( nBuiltinId );
+ if( (nBuiltinId == OOX_STYLE_ROWLEVEL) || (nBuiltinId == OOX_STYLE_COLLEVEL) )
+ aStyleName.append( nLevel );
+#if OOX_XLS_USE_DEFAULT_STYLE
+ }
+#endif
+ return aStyleName.makeStringAndClear();
+}
+
+bool lclIsBuiltinStyleName( const OUString& rStyleName, sal_Int32* pnBuiltinId, sal_Int32* pnNextChar )
+{
+#if OOX_XLS_USE_DEFAULT_STYLE
+ // "Default" becomes "Normal"
+ if( rStyleName.equalsIgnoreAsciiCaseAscii( spcDefaultStyleName ) )
+ {
+ if( pnBuiltinId ) *pnBuiltinId = OOX_STYLE_NORMAL;
+ if( pnNextChar ) *pnNextChar = rStyleName.getLength();
+ return true;
+ }
+#endif
+
+ // try the other builtin styles
+ OUString aPrefix = OUString::createFromAscii( spcStyleNamePrefix );
+ sal_Int32 nPrefixLen = aPrefix.getLength();
+ sal_Int32 nFoundId = 0;
+ sal_Int32 nNextChar = 0;
+ if( rStyleName.matchIgnoreAsciiCase( aPrefix ) )
+ {
+ OUString aShortName;
+ for( sal_Int32 nId = 0; nId < snStyleNamesCount; ++nId )
+ {
+#if OOX_XLS_USE_DEFAULT_STYLE
+ if( nId != OOX_STYLE_NORMAL )
+ {
+#endif
+ aShortName = OUString::createFromAscii( sppcStyleNames[ nId ] );
+ if( rStyleName.matchIgnoreAsciiCase( aShortName, nPrefixLen ) &&
+ (nNextChar < nPrefixLen + aShortName.getLength()) )
+ {
+ nFoundId = nId;
+ nNextChar = nPrefixLen + aShortName.getLength();
+ }
+#if OOX_XLS_USE_DEFAULT_STYLE
+ }
+#endif
+ }
+ }
+
+ if( nNextChar > 0 )
+ {
+ if( pnBuiltinId ) *pnBuiltinId = nFoundId;
+ if( pnNextChar ) *pnNextChar = nNextChar;
+ return true;
+ }
+
+ if( pnBuiltinId ) *pnBuiltinId = -1;
+ if( pnNextChar ) *pnNextChar = 0;
+ return false;
+}
+
+bool lclGetBuiltinStyleId( sal_Int32& rnBuiltinId, sal_Int32& rnLevel, const OUString& rStyleName )
+{
+ sal_Int32 nBuiltinId;
+ sal_Int32 nNextChar;
+ if( lclIsBuiltinStyleName( rStyleName, &nBuiltinId, &nNextChar ) )
+ {
+ if( (nBuiltinId == OOX_STYLE_ROWLEVEL) || (nBuiltinId == OOX_STYLE_COLLEVEL) )
+ {
+ OUString aLevel = rStyleName.copy( nNextChar );
+ sal_Int32 nLevel = aLevel.toInt32();
+ if( (0 < nLevel) && (nLevel <= OOX_STYLE_LEVELCOUNT) )
+ {
+ rnBuiltinId = nBuiltinId;
+ rnLevel = nLevel;
+ return true;
+ }
+ }
+ else if( rStyleName.getLength() == nNextChar )
+ {
+ rnBuiltinId = nBuiltinId;
+ rnLevel = 0;
+ return true;
+ }
+ }
+ rnBuiltinId = -1;
+ rnLevel = 0;
+ return false;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+OoxCellStyleData::OoxCellStyleData() :
+ mnXfId( -1 ),
+ mnBuiltinId( -1 ),
+ mnLevel( 0 ),
+ mbBuiltin( false ),
+ mbCustom( false ),
+ mbHidden( false )
+{
+}
+
+bool OoxCellStyleData::isDefaultStyle() const
+{
+ return mbBuiltin && (mnBuiltinId == OOX_STYLE_NORMAL);
+}
+
+OUString OoxCellStyleData::createStyleName() const
+{
+ return isBuiltin() ? lclGetBuiltinStyleName( mnBuiltinId, maName, mnLevel ) : maName;
+}
+
+// ============================================================================
+
+CellStyle::CellStyle( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void CellStyle::importCellStyle( const AttributeList& rAttribs )
+{
+ maOoxData.maName = rAttribs.getString( XML_name );
+ maOoxData.mnXfId = rAttribs.getInteger( XML_xfId, -1 );
+ maOoxData.mnBuiltinId = rAttribs.getInteger( XML_builtinId, -1 );
+ maOoxData.mnLevel = rAttribs.getInteger( XML_iLevel, 0 );
+ maOoxData.mbBuiltin = rAttribs.hasAttribute( XML_builtinId );
+ maOoxData.mbCustom = rAttribs.getBool( XML_customBuiltin, false );
+ maOoxData.mbHidden = rAttribs.getBool( XML_hidden, false );
+}
+
+void CellStyle::importCellStyle( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> maOoxData.mnXfId >> nFlags;
+ maOoxData.mnBuiltinId = rStrm.readuInt8();
+ maOoxData.mnLevel = rStrm.readuInt8();
+ rStrm >> maOoxData.maName;
+ maOoxData.mbBuiltin = getFlag( nFlags, OOBIN_CELLSTYLE_BUILTIN );
+ maOoxData.mbCustom = getFlag( nFlags, OOBIN_CELLSTYLE_CUSTOM );
+ maOoxData.mbHidden = getFlag( nFlags, OOBIN_CELLSTYLE_HIDDEN );
+}
+
+void CellStyle::importStyle( BiffInputStream& rStrm )
+{
+ sal_uInt16 nStyleXf;
+ rStrm >> nStyleXf;
+ maOoxData.mnXfId = static_cast< sal_Int32 >( nStyleXf & BIFF_STYLE_XFMASK );
+ maOoxData.mbBuiltin = getFlag( nStyleXf, BIFF_STYLE_BUILTIN );
+ if( maOoxData.mbBuiltin )
+ {
+ maOoxData.mnBuiltinId = rStrm.readuInt8();
+ maOoxData.mnLevel = rStrm.readuInt8();
+ }
+ else
+ {
+ maOoxData.maName = (getBiff() == BIFF8) ?
+ rStrm.readUniString() : rStrm.readByteString( false, getTextEncoding() );
+ }
+}
+
+const OUString& CellStyle::createCellStyle( sal_Int32 nXfId, bool bSkipDefaultBuiltin )
+{
+ if( maFinalName.getLength() == 0 )
+ {
+ bool bBuiltin = maOoxData.isBuiltin();
+ if( !bSkipDefaultBuiltin || !bBuiltin || maOoxData.mbCustom )
+ {
+ // name of the style (generate unique name for builtin styles)
+ maFinalName = maOoxData.createStyleName();
+ // #i1624# #i1768# ignore unnamed user styles
+ if( maFinalName.getLength() > 0 )
+ {
+ Reference< XStyle > xStyle;
+#if OOX_XLS_USE_DEFAULT_STYLE
+ // special handling for default style (do not create, but use existing)
+ if( isDefaultStyle() )
+ {
+ /* Set all flags to true to have all properties in the style,
+ even if the used flags are not set (that's what Excel does). */
+ if( Xf* pXf = getStyles().getStyleXf( nXfId ).get() )
+ pXf->setAllUsedFlags( true );
+ // use existing built-in style
+ xStyle = getStyleObject( maFinalName, false );
+ }
+ else
+ {
+#endif
+ /* Insert into cell styles collection, rename existing user styles,
+ if this is a built-in style, but do not do this in BIFF4 workspace
+ files, where built-in styles occur repeatedly. */
+ bool bRenameExisting = bBuiltin && (getBiff() != BIFF4);
+ xStyle = createStyleObject( maFinalName, false, bRenameExisting );
+#if OOX_XLS_USE_DEFAULT_STYLE
+ }
+#endif
+
+ // write style formatting properties
+ PropertySet aPropSet( xStyle );
+ getStyles().writeStyleXfToPropertySet( aPropSet, nXfId );
+#if OOX_XLS_USE_DEFAULT_STYLE
+#else
+ if( !isDefaultStyle() && xStyle.is() )
+ xStyle->setParentStyle( getStyles().getDefaultStyleName() );
+#endif
+ }
+ }
+ }
+ return maFinalName;
+}
+
+// ============================================================================
+
+namespace {
+
+sal_Int32 lclTintToColor( sal_Int32 nColor, double fTint )
+{
+ if( nColor == 0x000000 )
+ return 0x010101 * static_cast< sal_Int32 >( ::std::max( fTint, 0.0 ) * 255.0 );
+ if( nColor == 0xFFFFFF )
+ return 0x010101 * static_cast< sal_Int32 >( ::std::min( fTint + 1.0, 1.0 ) * 255.0 );
+
+ sal_Int32 nR = (nColor >> 16) & 0xFF;
+ sal_Int32 nG = (nColor >> 8) & 0xFF;
+ sal_Int32 nB = nColor & 0xFF;
+
+ double fMean = (::std::min( ::std::min( nR, nG ), nB ) + ::std::max( ::std::max( nR, nG ), nB )) / 2.0;
+ double fTintTh = (fMean <= 127.5) ? ((127.5 - fMean) / (255.0 - fMean)) : (127.5 / fMean - 1.0);
+ if( (fTintTh < 0.0) || ((fTintTh == 0.0) && (fTint <= 0.0)) )
+ {
+ double fTintMax = 255.0 / fMean - 1.0;
+ double fRTh = fTintTh / fTintMax * (255.0 - nR) + nR;
+ double fGTh = fTintTh / fTintMax * (255.0 - nG) + nG;
+ double fBTh = fTintTh / fTintMax * (255.0 - nB) + nB;
+ if( fTint <= fTintTh )
+ {
+ double fFactor = (fTint + 1.0) / (fTintTh + 1.0);
+ nR = static_cast< sal_Int32 >( fFactor * fRTh + 0.5 );
+ nG = static_cast< sal_Int32 >( fFactor * fGTh + 0.5 );
+ nB = static_cast< sal_Int32 >( fFactor * fBTh + 0.5 );
+ }
+ else
+ {
+ double fFactor = (fTint > 0.0) ? (fTint * fTintMax / fTintTh) : (fTint / fTintTh);
+ nR = static_cast< sal_Int32 >( fFactor * fRTh + (1.0 - fFactor) * nR + 0.5 );
+ nG = static_cast< sal_Int32 >( fFactor * fGTh + (1.0 - fFactor) * nG + 0.5 );
+ nB = static_cast< sal_Int32 >( fFactor * fBTh + (1.0 - fFactor) * nB + 0.5 );
+ }
+ }
+ else
+ {
+ double fTintMin = fMean / (fMean - 255.0);
+ double fRTh = (1.0 - fTintTh / fTintMin) * nR;
+ double fGTh = (1.0 - fTintTh / fTintMin) * nG;
+ double fBTh = (1.0 - fTintTh / fTintMin) * nB;
+ if( fTint <= fTintTh )
+ {
+ double fFactor = (fTint < 0.0) ? (fTint * -fTintMin / fTintTh) : (fTint / fTintTh);
+ nR = static_cast< sal_Int32 >( fFactor * fRTh + (1.0 - fFactor) * nR + 0.5 );
+ nG = static_cast< sal_Int32 >( fFactor * fGTh + (1.0 - fFactor) * nG + 0.5 );
+ nB = static_cast< sal_Int32 >( fFactor * fBTh + (1.0 - fFactor) * nB + 0.5 );
+ }
+ else
+ {
+ double fFactor = (1.0 - fTint) / (1.0 - fTintTh);
+ nR = static_cast< sal_Int32 >( 255.5 - fFactor * (255.0 - fRTh) );
+ nG = static_cast< sal_Int32 >( 255.5 - fFactor * (255.0 - fGTh) );
+ nB = static_cast< sal_Int32 >( 255.5 - fFactor * (255.0 - fBTh) );
+ }
+ }
+
+ return (nR << 16) | (nG << 8) | nB;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+StylesBuffer::StylesBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maPalette( rHelper ),
+ maNumFmts( rHelper ),
+ maDefStyleName( lclGetBuiltinStyleName( OOX_STYLE_NORMAL, OUString() ) ),
+ mnDefStyleXf( -1 )
+{
+}
+
+FontRef StylesBuffer::createFont( sal_Int32* opnFontId )
+{
+ if( opnFontId ) *opnFontId = static_cast< sal_Int32 >( maFonts.size() );
+ FontRef xFont( new Font( *this, false ) );
+ maFonts.push_back( xFont );
+ return xFont;
+}
+
+NumberFormatRef StylesBuffer::createNumFmt( sal_Int32 nNumFmtId, const OUString& rFmtCode )
+{
+ return maNumFmts.createNumFmt( nNumFmtId, rFmtCode );
+}
+
+BorderRef StylesBuffer::createBorder( sal_Int32* opnBorderId )
+{
+ if( opnBorderId ) *opnBorderId = static_cast< sal_Int32 >( maBorders.size() );
+ BorderRef xBorder( new Border( *this, false ) );
+ maBorders.push_back( xBorder );
+ return xBorder;
+}
+
+FillRef StylesBuffer::createFill( sal_Int32* opnFillId )
+{
+ if( opnFillId ) *opnFillId = static_cast< sal_Int32 >( maFills.size() );
+ FillRef xFill( new Fill( *this, false ) );
+ maFills.push_back( xFill );
+ return xFill;
+}
+
+XfRef StylesBuffer::createCellXf( sal_Int32* opnXfId )
+{
+ if( opnXfId ) *opnXfId = static_cast< sal_Int32 >( maCellXfs.size() );
+ XfRef xXf( new Xf( *this ) );
+ maCellXfs.push_back( xXf );
+ return xXf;
+}
+
+XfRef StylesBuffer::createStyleXf( sal_Int32* opnXfId )
+{
+ if( opnXfId ) *opnXfId = static_cast< sal_Int32 >( maStyleXfs.size() );
+ XfRef xXf( new Xf( *this ) );
+ maStyleXfs.push_back( xXf );
+ return xXf;
+}
+
+DxfRef StylesBuffer::createDxf( sal_Int32* opnDxfId )
+{
+ if( opnDxfId ) *opnDxfId = static_cast< sal_Int32 >( maDxfs.size() );
+ DxfRef xDxf( new Dxf( *this ) );
+ maDxfs.push_back( xDxf );
+ return xDxf;
+}
+
+void StylesBuffer::importPaletteColor( const AttributeList& rAttribs )
+{
+ maPalette.importPaletteColor( rAttribs );
+}
+
+FontRef StylesBuffer::importFont( const AttributeList& )
+{
+ return createFont();
+}
+
+NumberFormatRef StylesBuffer::importNumFmt( const AttributeList& rAttribs )
+{
+ return maNumFmts.importNumFmt( rAttribs );
+}
+
+BorderRef StylesBuffer::importBorder( const AttributeList& rAttribs )
+{
+ BorderRef xBorder = createBorder();
+ xBorder->importBorder( rAttribs );
+ return xBorder;
+}
+
+FillRef StylesBuffer::importFill( const AttributeList& )
+{
+ return createFill();
+}
+
+XfRef StylesBuffer::importXf( sal_Int32 nContext, const AttributeList& rAttribs )
+{
+ XfRef xXf;
+ switch( nContext )
+ {
+ case XLS_TOKEN( cellXfs ):
+ xXf = createCellXf();
+ xXf->importXf( rAttribs, true );
+ break;
+ case XLS_TOKEN( cellStyleXfs ):
+ xXf = createStyleXf();
+ xXf->importXf( rAttribs, false );
+ break;
+ }
+ return xXf;
+}
+
+DxfRef StylesBuffer::importDxf( const AttributeList& )
+{
+ return createDxf();
+}
+
+CellStyleRef StylesBuffer::importCellStyle( const AttributeList& rAttribs )
+{
+ CellStyleRef xCellStyle( new CellStyle( *this ) );
+ xCellStyle->importCellStyle( rAttribs );
+ insertCellStyle( xCellStyle );
+ return xCellStyle;
+}
+
+void StylesBuffer::importPaletteColor( RecordInputStream& rStrm )
+{
+ maPalette.importPaletteColor( rStrm );
+}
+
+void StylesBuffer::importFont( RecordInputStream& rStrm )
+{
+ createFont()->importFont( rStrm );
+}
+
+void StylesBuffer::importNumFmt( RecordInputStream& rStrm )
+{
+ maNumFmts.importNumFmt( rStrm );
+}
+
+void StylesBuffer::importBorder( RecordInputStream& rStrm )
+{
+ createBorder()->importBorder( rStrm );
+}
+
+void StylesBuffer::importFill( RecordInputStream& rStrm )
+{
+ createFill()->importFill( rStrm );
+}
+
+void StylesBuffer::importXf( sal_Int32 nContext, RecordInputStream& rStrm )
+{
+ switch( nContext )
+ {
+ case OOBIN_ID_CELLXFS:
+ createCellXf()->importXf( rStrm, true );
+ break;
+ case OOBIN_ID_CELLSTYLEXFS:
+ createStyleXf()->importXf( rStrm, false );
+ break;
+ }
+}
+
+void StylesBuffer::importDxf( RecordInputStream& rStrm )
+{
+ createDxf()->importDxf( rStrm );
+}
+
+void StylesBuffer::importCellStyle( RecordInputStream& rStrm )
+{
+ CellStyleRef xCellStyle( new CellStyle( *this ) );
+ xCellStyle->importCellStyle( rStrm );
+ insertCellStyle( xCellStyle );
+}
+
+void StylesBuffer::importPalette( BiffInputStream& rStrm )
+{
+ maPalette.importPalette( rStrm );
+}
+
+void StylesBuffer::importFont( BiffInputStream& rStrm )
+{
+ /* Font with index 4 is not stored in BIFF. This means effectively, first
+ font in the BIFF file has index 0, fourth font has index 3, and fifth
+ font has index 5. Insert a dummy font to correctly map passed font
+ identifiers. */
+ if( maFonts.size() == 4 )
+ maFonts.push_back( maFonts.front() );
+
+ FontRef xFont = createFont();
+ xFont->importFont( rStrm );
+
+ /* #i71033# Set stream text encoding from application font, if CODEPAGE
+ record is missing. Must be done now (not while finalizeImport() runs),
+ to be able to read all following byte strings correctly (e.g. cell
+ style names). */
+ if( maFonts.size() == 1 )
+ setAppFontEncoding( xFont->getFontEncoding() );
+}
+
+void StylesBuffer::importFontColor( BiffInputStream& rStrm )
+{
+ if( !maFonts.empty() )
+ maFonts.back()->importFontColor( rStrm );
+}
+
+void StylesBuffer::importFormat( BiffInputStream& rStrm )
+{
+ maNumFmts.importFormat( rStrm );
+}
+
+void StylesBuffer::importXf( BiffInputStream& rStrm )
+{
+ XfRef xXf( new Xf( *this ) );
+ // store XF in both lists (except BIFF2 which does not support cell styles)
+ maCellXfs.push_back( xXf );
+ if( getBiff() != BIFF2 )
+ maStyleXfs.push_back( xXf );
+ xXf->importXf( rStrm );
+}
+
+void StylesBuffer::importStyle( BiffInputStream& rStrm )
+{
+ CellStyleRef xCellStyle( new CellStyle( *this ) );
+ xCellStyle->importStyle( rStrm );
+ insertCellStyle( xCellStyle );
+}
+
+void StylesBuffer::finalizeImport()
+{
+ // fonts first, are needed to finalize unit converter and XFs below
+ maFonts.forEachMem( &Font::finalizeImport );
+ // finalize unit converter after default font is known
+ getUnitConverter().finalizeImport();
+ // number formats
+ maNumFmts.finalizeImport();
+ // borders and fills
+ maBorders.forEachMem( &Border::finalizeImport );
+ maFills.forEachMem( &Fill::finalizeImport );
+
+ /* Style XFs and cell XFs. The BIFF format stores cell XFs and style XFs
+ mixed in a single list. The import filter has stored the XFs in both
+ lists to make the getStyleXf() function working correctly (e.g. for
+ retrieving the default font, see getDefaultFont() function), except for
+ BIFF2 which does not support cell styles at all. Therefore, if in BIFF
+ filter mode, we do not need to finalize the cell styles list. */
+ if( getFilterType() == FILTER_OOX )
+ maStyleXfs.forEachMem( &Xf::finalizeImport );
+ maCellXfs.forEachMem( &Xf::finalizeImport );
+
+ // conditional formatting
+ maDxfs.forEachMem( &Dxf::finalizeImport );
+
+ // create the default cell style first
+ if( CellStyle* pDefStyle = maCellStyles.get( mnDefStyleXf ).get() )
+ pDefStyle->createCellStyle( mnDefStyleXf );
+ /* Create user-defined and modified builtin cell styles, passing true to
+ createStyleSheet() skips unchanged builtin styles. */
+ for( CellStyleMap::iterator aIt = maCellStyles.begin(), aEnd = maCellStyles.end(); aIt != aEnd; ++aIt )
+ aIt->second->createCellStyle( aIt->first, true );
+}
+
+sal_Int32 StylesBuffer::getColor( const OoxColor& rColor, sal_Int32 nAuto ) const
+{
+ sal_Int32 nColor = API_RGB_TRANSPARENT;
+ switch( rColor.mnType )
+ {
+ case XML_auto:
+ nColor = nAuto;
+ break;
+ case XML_rgb:
+ nColor = rColor.mnValue & 0xFFFFFF;
+ break;
+ case XML_theme:
+ nColor = getTheme().getColorByIndex( rColor.mnValue );
+ break;
+ case XML_indexed:
+ nColor = maPalette.getColor( rColor.mnValue );
+ break;
+ default:
+ OSL_ENSURE( false, "StylesBuffer::getColor - unknown color type" );
+ }
+ if( (rColor.mnType != XML_auto) && (nColor != API_RGB_TRANSPARENT) && (rColor.mfTint >= -1.0) && (rColor.mfTint != 0.0) && (rColor.mfTint <= 1.0) )
+ nColor = lclTintToColor( nColor, rColor.mfTint );
+ return nColor;
+}
+
+FontRef StylesBuffer::getFont( sal_Int32 nFontId ) const
+{
+ return maFonts.get( nFontId );
+}
+
+XfRef StylesBuffer::getCellXf( sal_Int32 nXfId ) const
+{
+ return maCellXfs.get( nXfId );
+}
+
+XfRef StylesBuffer::getStyleXf( sal_Int32 nXfId ) const
+{
+ return maStyleXfs.get( nXfId );
+}
+
+DxfRef StylesBuffer::getDxf( sal_Int32 nDxfId ) const
+{
+ return maDxfs.get( nDxfId );
+}
+
+FontRef StylesBuffer::getFontFromCellXf( sal_Int32 nXfId ) const
+{
+ FontRef xFont;
+ if( const Xf* pXf = getCellXf( nXfId ).get() )
+ xFont = pXf->getFont();
+ return xFont;
+}
+
+FontRef StylesBuffer::getDefaultFont() const
+{
+ FontRef xDefFont;
+ if( const Xf* pXf = getStyleXf( mnDefStyleXf ).get() )
+ xDefFont = pXf->getFont();
+ // no font from styles - try first loaded font (e.g. BIFF2)
+ if( !xDefFont )
+ xDefFont = maFonts.get( 0 );
+ OSL_ENSURE( xDefFont.get(), "StylesBuffer::getDefaultFont - no default font found" );
+ return xDefFont;
+}
+
+const OoxFontData& StylesBuffer::getDefaultFontData() const
+{
+ FontRef xDefFont = getDefaultFont();
+ return xDefFont.get() ? xDefFont->getFontData() : getTheme().getDefaultFontData();
+}
+
+const OUString& StylesBuffer::createCellStyle( sal_Int32 nXfId ) const
+{
+ if( CellStyle* pCellStyle = maCellStyles.get( nXfId ).get() )
+ return pCellStyle->createCellStyle( nXfId );
+ // on error: fallback to default style
+ return maDefStyleName;
+}
+
+const OUString& StylesBuffer::createDxfStyle( sal_Int32 nDxfId ) const
+{
+ if( Dxf* pDxf = maDxfs.get( nDxfId ).get() )
+ return pDxf->createDxfStyle( nDxfId );
+ // on error: fallback to default style
+ return maDefStyleName;
+}
+
+#if OOX_XLS_USE_DEFAULT_STYLE
+#else
+const OUString& StylesBuffer::getDefaultStyleName() const
+{
+ return createCellStyle( mnDefStyleXf );
+}
+#endif
+
+void StylesBuffer::writeFontToPropertySet( PropertySet& rPropSet, sal_Int32 nFontId ) const
+{
+ if( Font* pFont = maFonts.get( nFontId ).get() )
+ pFont->writeToPropertySet( rPropSet, FONT_PROPTYPE_CELL );
+}
+
+void StylesBuffer::writeNumFmtToPropertySet( PropertySet& rPropSet, sal_Int32 nNumFmtId ) const
+{
+ maNumFmts.writeToPropertySet( rPropSet, nNumFmtId );
+}
+
+void StylesBuffer::writeBorderToPropertySet( PropertySet& rPropSet, sal_Int32 nBorderId ) const
+{
+ if( Border* pBorder = maBorders.get( nBorderId ).get() )
+ pBorder->writeToPropertySet( rPropSet );
+}
+
+void StylesBuffer::writeFillToPropertySet( PropertySet& rPropSet, sal_Int32 nFillId ) const
+{
+ if( Fill* pFill = maFills.get( nFillId ).get() )
+ pFill->writeToPropertySet( rPropSet );
+}
+
+void StylesBuffer::writeCellXfToPropertySet( PropertySet& rPropSet, sal_Int32 nXfId ) const
+{
+ if( Xf* pXf = maCellXfs.get( nXfId ).get() )
+ pXf->writeToPropertySet( rPropSet );
+}
+
+void StylesBuffer::writeStyleXfToPropertySet( PropertySet& rPropSet, sal_Int32 nXfId ) const
+{
+ if( Xf* pXf = maStyleXfs.get( nXfId ).get() )
+ pXf->writeToPropertySet( rPropSet );
+}
+
+void StylesBuffer::insertCellStyle( CellStyleRef xCellStyle )
+{
+ if( xCellStyle->getXfId() >= 0 )
+ {
+ maCellStyles[ xCellStyle->getXfId() ] = xCellStyle;
+ if( xCellStyle->isDefaultStyle() )
+ mnDefStyleXf = xCellStyle->getXfId();
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/stylesfragment.cxx b/oox/source/xls/stylesfragment.cxx
new file mode 100644
index 000000000000..0ef9400dcbec
--- /dev/null
+++ b/oox/source/xls/stylesfragment.cxx
@@ -0,0 +1,316 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: stylesfragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/stylesfragment.hxx"
+#include "oox/helper/attributelist.hxx"
+
+using ::rtl::OUString;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxStylesFragment::OoxStylesFragment(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath ),
+ mfGradPos( -1.0 )
+{
+}
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxStylesFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ sal_Int32 nCurrContext = getCurrentContext();
+ switch( nCurrContext )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nElement == XLS_TOKEN( styleSheet ));
+ case XLS_TOKEN( styleSheet ):
+ return (nElement == XLS_TOKEN( colors )) ||
+ (nElement == XLS_TOKEN( fonts )) ||
+ (nElement == XLS_TOKEN( numFmts )) ||
+ (nElement == XLS_TOKEN( borders )) ||
+ (nElement == XLS_TOKEN( fills )) ||
+ (nElement == XLS_TOKEN( cellXfs )) ||
+ (nElement == XLS_TOKEN( cellStyleXfs )) ||
+ (nElement == XLS_TOKEN( dxfs )) ||
+ (nElement == XLS_TOKEN( cellStyles ));
+
+ case XLS_TOKEN( colors ):
+ return (nElement == XLS_TOKEN( indexedColors ));
+ case XLS_TOKEN( indexedColors ):
+ return (nElement == XLS_TOKEN( rgbColor ));
+
+ case XLS_TOKEN( fonts ):
+ return (nElement == XLS_TOKEN( font ));
+ case XLS_TOKEN( font ):
+ return mxFont.get() && Font::isSupportedContext( nElement, nCurrContext );
+
+ case XLS_TOKEN( numFmts ):
+ return (nElement == XLS_TOKEN( numFmt ));
+
+ case XLS_TOKEN( borders ):
+ return (nElement == XLS_TOKEN( border ));
+ case XLS_TOKEN( border ):
+ case XLS_TOKEN( left ):
+ case XLS_TOKEN( right ):
+ case XLS_TOKEN( top ):
+ case XLS_TOKEN( bottom ):
+ case XLS_TOKEN( diagonal ):
+ return mxBorder.get() && Border::isSupportedContext( nElement, nCurrContext );
+
+ case XLS_TOKEN( fills ):
+ return (nElement == XLS_TOKEN( fill ));
+ case XLS_TOKEN( fill ):
+ case XLS_TOKEN( patternFill ):
+ case XLS_TOKEN( gradientFill ):
+ case XLS_TOKEN( stop ):
+ return mxFill.get() && Fill::isSupportedContext( nElement, nCurrContext );
+
+ case XLS_TOKEN( cellStyleXfs ):
+ case XLS_TOKEN( cellXfs ):
+ return (nElement == XLS_TOKEN( xf ));
+ case XLS_TOKEN( xf ):
+ return mxXf.get() &&
+ ((nElement == XLS_TOKEN( alignment )) ||
+ (nElement == XLS_TOKEN( protection )));
+
+ case XLS_TOKEN( dxfs ):
+ return (nElement == XLS_TOKEN( dxf ));
+ case XLS_TOKEN( dxf ):
+ return mxDxf.get() &&
+ ((nElement == XLS_TOKEN( font )) ||
+ (nElement == XLS_TOKEN( numFmt )) ||
+ (nElement == XLS_TOKEN( alignment )) ||
+ (nElement == XLS_TOKEN( protection )) ||
+ (nElement == XLS_TOKEN( border )) ||
+ (nElement == XLS_TOKEN( fill )));
+
+ case XLS_TOKEN( cellStyles ):
+ return (nElement == XLS_TOKEN( cellStyle ));
+ }
+ return false;
+}
+
+void OoxStylesFragment::onStartElement( const AttributeList& rAttribs )
+{
+ sal_Int32 nCurrContext = getCurrentContext();
+ sal_Int32 nPrevContext = getPreviousContext();
+
+ switch( nCurrContext )
+ {
+ case XLS_TOKEN( color ):
+ switch( nPrevContext )
+ {
+ case XLS_TOKEN( font ):
+ OSL_ENSURE( mxFont.get(), "OoxStylesFragment::onStartElement - missing font object" );
+ mxFont->importAttribs( nCurrContext, rAttribs );
+ break;
+ case XLS_TOKEN( stop ):
+ OSL_ENSURE( mxFill.get(), "OoxStylesFragment::onStartElement - missing fill object" );
+ mxFill->importColor( rAttribs, mfGradPos );
+ break;
+ default:
+ OSL_ENSURE( mxBorder.get(), "OoxStylesFragment::onStartElement - missing border object" );
+ mxBorder->importColor( nPrevContext, rAttribs );
+ }
+ break;
+ case XLS_TOKEN( rgbColor ):
+ getStyles().importPaletteColor( rAttribs );
+ break;
+
+ case XLS_TOKEN( font ):
+ mxFont = mxDxf.get() ? mxDxf->importFont( rAttribs ) : getStyles().importFont( rAttribs );
+ break;
+
+ case XLS_TOKEN( numFmt ):
+ if( mxDxf.get() )
+ mxDxf->importNumFmt( rAttribs );
+ else
+ getStyles().importNumFmt( rAttribs );
+ break;
+
+ case XLS_TOKEN( alignment ):
+ OSL_ENSURE( mxXf.get() || mxDxf.get(), "OoxStylesFragment::onStartElement - missing formatting object" );
+ if( mxXf.get() )
+ mxXf->importAlignment( rAttribs );
+#if 0
+ else if( mxDxf.get() )
+ mxDxf->importAlignment( rAttribs );
+#endif
+ break;
+
+ case XLS_TOKEN( protection ):
+ OSL_ENSURE( mxXf.get() || mxDxf.get(), "OoxStylesFragment::onStartElement - missing formatting object" );
+ if( mxXf.get() )
+ mxXf->importProtection( rAttribs );
+#if 0
+ else if( mxDxf.get() )
+ mxDxf->importProtection( rAttribs );
+#endif
+ break;
+
+ case XLS_TOKEN( border ):
+ mxBorder = mxDxf.get() ? mxDxf->importBorder( rAttribs ) : getStyles().importBorder( rAttribs );
+ break;
+
+ case XLS_TOKEN( fill ):
+ mxFill = mxDxf.get() ? mxDxf->importFill( rAttribs ) : getStyles().importFill( rAttribs );
+ break;
+ case XLS_TOKEN( patternFill ):
+ OSL_ENSURE( mxFill.get(), "OoxStylesFragment::onStartElement - missing fill object" );
+ mxFill->importPatternFill( rAttribs );
+ break;
+ case XLS_TOKEN( fgColor ):
+ OSL_ENSURE( mxFill.get(), "OoxStylesFragment::onStartElement - missing fill object" );
+ mxFill->importFgColor( rAttribs );
+ break;
+ case XLS_TOKEN( bgColor ):
+ OSL_ENSURE( mxFill.get(), "OoxStylesFragment::onStartElement - missing fill object" );
+ mxFill->importBgColor( rAttribs );
+ break;
+ case XLS_TOKEN( gradientFill ):
+ OSL_ENSURE( mxFill.get(), "OoxStylesFragment::onStartElement - missing fill object" );
+ mxFill->importGradientFill( rAttribs );
+ break;
+ case XLS_TOKEN( stop ):
+ mfGradPos = rAttribs.getDouble( XML_position, -1.0 );
+ break;
+
+ case XLS_TOKEN( xf ):
+ mxXf = getStyles().importXf( nPrevContext, rAttribs );
+ break;
+ case XLS_TOKEN( dxf ):
+ mxDxf = getStyles().importDxf( rAttribs );
+ break;
+
+ case XLS_TOKEN( cellStyle ):
+ getStyles().importCellStyle( rAttribs );
+ break;
+
+ default: switch( nPrevContext )
+ {
+ case XLS_TOKEN( font ):
+ OSL_ENSURE( mxFont.get(), "OoxStylesFragment::onStartElement - missing font object" );
+ mxFont->importAttribs( nCurrContext, rAttribs );
+ break;
+ case XLS_TOKEN( border ):
+ OSL_ENSURE( mxBorder.get(), "OoxStylesFragment::onStartElement - missing border object" );
+ mxBorder->importStyle( nCurrContext, rAttribs );
+ break;
+ }
+ }
+}
+
+void OoxStylesFragment::onEndElement( const OUString& /*rChars*/ )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( font ): mxFont.reset(); break;
+ case XLS_TOKEN( border ): mxBorder.reset(); break;
+ case XLS_TOKEN( fill ): mxFill.reset(); break;
+ case XLS_TOKEN( xf ): mxXf.reset(); break;
+ case XLS_TOKEN( dxf ): mxDxf.reset(); break;
+ }
+}
+
+bool OoxStylesFragment::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nRecId == OOBIN_ID_STYLESHEET);
+ case OOBIN_ID_STYLESHEET:
+ return (nRecId == OOBIN_ID_COLORS) ||
+ (nRecId == OOBIN_ID_FONTS) ||
+ (nRecId == OOBIN_ID_NUMFMTS) ||
+ (nRecId == OOBIN_ID_BORDERS) ||
+ (nRecId == OOBIN_ID_FILLS) ||
+ (nRecId == OOBIN_ID_CELLSTYLEXFS) ||
+ (nRecId == OOBIN_ID_CELLXFS) ||
+ (nRecId == OOBIN_ID_DXFS) ||
+ (nRecId == OOBIN_ID_CELLSTYLES);
+ case OOBIN_ID_COLORS:
+ return (nRecId == OOBIN_ID_INDEXEDCOLORS);
+ case OOBIN_ID_INDEXEDCOLORS:
+ return (nRecId == OOBIN_ID_RGBCOLOR);
+ case OOBIN_ID_FONTS:
+ return (nRecId == OOBIN_ID_FONT);
+ case OOBIN_ID_NUMFMTS:
+ return (nRecId == OOBIN_ID_NUMFMT);
+ case OOBIN_ID_BORDERS:
+ return (nRecId == OOBIN_ID_BORDER);
+ case OOBIN_ID_FILLS:
+ return (nRecId == OOBIN_ID_FILL);
+ case OOBIN_ID_CELLSTYLEXFS:
+ case OOBIN_ID_CELLXFS:
+ return (nRecId == OOBIN_ID_XF);
+ case OOBIN_ID_DXFS:
+ return (nRecId == OOBIN_ID_DXF);
+ case OOBIN_ID_CELLSTYLES:
+ return (nRecId == OOBIN_ID_CELLSTYLE);
+ }
+ return false;
+}
+
+void OoxStylesFragment::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_RGBCOLOR: getStyles().importPaletteColor( rStrm ); break;
+ case OOBIN_ID_FONT: getStyles().importFont( rStrm ); break;
+ case OOBIN_ID_NUMFMT: getStyles().importNumFmt( rStrm ); break;
+ case OOBIN_ID_BORDER: getStyles().importBorder( rStrm ); break;
+ case OOBIN_ID_FILL: getStyles().importFill( rStrm ); break;
+ case OOBIN_ID_XF: getStyles().importXf( getPreviousContext(), rStrm ); break;
+ case OOBIN_ID_DXF: getStyles().importDxf( rStrm ); break;
+ case OOBIN_ID_CELLSTYLE: getStyles().importCellStyle( rStrm ); break;
+ }
+}
+
+// oox.xls.OoxFragmentHandler interface ---------------------------------------
+
+void OoxStylesFragment::finalizeImport()
+{
+ getStyles().finalizeImport();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/stylespropertyhelper.cxx b/oox/source/xls/stylespropertyhelper.cxx
new file mode 100644
index 000000000000..91a8099de426
--- /dev/null
+++ b/oox/source/xls/stylespropertyhelper.cxx
@@ -0,0 +1,386 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: stylespropertyhelper.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ * * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/stylespropertyhelper.hxx"
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontPitch.hpp>
+#include <com/sun/star/awt/FontType.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include "oox/helper/propertyset.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+
+using ::rtl::OUString;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+ApiFontUsedFlags::ApiFontUsedFlags( bool bAllUsed ) :
+ mbNameUsed( bAllUsed ),
+ mbColorUsed( bAllUsed ),
+ mbSchemeUsed( bAllUsed ),
+ mbHeightUsed( bAllUsed ),
+ mbUnderlineUsed( bAllUsed ),
+ mbEscapementUsed( bAllUsed ),
+ mbWeightUsed( bAllUsed ),
+ mbPostureUsed( bAllUsed ),
+ mbStrikeoutUsed( bAllUsed ),
+ mbOutlineUsed( bAllUsed ),
+ mbShadowUsed( bAllUsed )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ApiFontData::ApiFontData() :
+ maDesc(
+ CREATE_OUSTRING( "Calibri" ),
+ 220, // height 11 points
+ 0,
+ OUString(),
+ ::com::sun::star::awt::FontFamily::DONTKNOW,
+ RTL_TEXTENCODING_DONTKNOW,
+ ::com::sun::star::awt::FontPitch::DONTKNOW,
+ 100.0,
+ ::com::sun::star::awt::FontWeight::NORMAL,
+ ::com::sun::star::awt::FontSlant_NONE,
+ ::com::sun::star::awt::FontUnderline::NONE,
+ ::com::sun::star::awt::FontStrikeout::NONE,
+ 0.0,
+ sal_False,
+ sal_False,
+ ::com::sun::star::awt::FontType::DONTKNOW ),
+ mnColor( API_RGB_TRANSPARENT ),
+ mnEscapement( API_ESCAPE_NONE ),
+ mnEscapeHeight( API_ESCAPEHEIGHT_NONE ),
+ mbOutline( false ),
+ mbShadow( false ),
+ mbHasWstrn( true ),
+ mbHasAsian( false )
+{
+}
+
+// ============================================================================
+
+ApiNumFmtData::ApiNumFmtData() :
+ mnIndex( 0 )
+{
+}
+
+// ============================================================================
+
+ApiAlignmentData::ApiAlignmentData() :
+ meHorJustify( ::com::sun::star::table::CellHoriJustify_STANDARD ),
+ meVerJustify( ::com::sun::star::table::CellVertJustify_STANDARD ),
+ meOrientation( ::com::sun::star::table::CellOrientation_STANDARD ),
+ mnRotation( 0 ),
+ mnWritingMode( ::com::sun::star::text::WritingMode2::PAGE ),
+ mnIndent( 0 ),
+ mbWrapText( false ),
+ mbShrink( false )
+{
+}
+
+bool operator==( const ApiAlignmentData& rLeft, const ApiAlignmentData& rRight )
+{
+ return
+ (rLeft.meHorJustify == rRight.meHorJustify) &&
+ (rLeft.meVerJustify == rRight.meVerJustify) &&
+ (rLeft.meOrientation == rRight.meOrientation) &&
+ (rLeft.mnRotation == rRight.mnRotation) &&
+ (rLeft.mnWritingMode == rRight.mnWritingMode) &&
+ (rLeft.mnIndent == rRight.mnIndent) &&
+ (rLeft.mbWrapText == rRight.mbWrapText) &&
+ (rLeft.mbShrink == rRight.mbShrink);
+}
+
+// ============================================================================
+
+ApiProtectionData::ApiProtectionData() :
+ maCellProt( sal_True, sal_False, sal_False, sal_False )
+{
+}
+
+bool operator==( const ApiProtectionData& rLeft, const ApiProtectionData& rRight )
+{
+ return
+ (rLeft.maCellProt.IsLocked == rRight.maCellProt.IsLocked) &&
+ (rLeft.maCellProt.IsFormulaHidden == rRight.maCellProt.IsFormulaHidden) &&
+ (rLeft.maCellProt.IsHidden == rRight.maCellProt.IsHidden) &&
+ (rLeft.maCellProt.IsPrintHidden == rRight.maCellProt.IsPrintHidden);
+}
+
+// ============================================================================
+
+ApiBorderData::ApiBorderData() :
+ mbBorderUsed( false ),
+ mbDiagUsed( false )
+{
+}
+
+// ============================================================================
+
+ApiSolidFillData::ApiSolidFillData() :
+ mnColor( API_RGB_TRANSPARENT ),
+ mbTransparent( true ),
+ mbUsed( false )
+{
+}
+
+// ============================================================================
+
+namespace {
+
+/** Property names for Western font name settings. */
+const sal_Char* const sppcWstrnFontNameNames[] =
+{
+ "CharFontName",
+ "CharFontFamily",
+ "CharFontCharSet",
+ 0
+};
+
+/** Property names for Asian font name settings. */
+const sal_Char* const sppcAsianFontNameNames[] =
+{
+ "CharFontNameAsian",
+ "CharFontFamilyAsian",
+ "CharFontCharSetAsian",
+ 0
+};
+
+/** Property names for Complex font name settings. */
+const sal_Char* const sppcCmplxFontNameNames[] =
+{
+ "CharFontNameComplex",
+ "CharFontFamilyComplex",
+ "CharFontCharSetComplex",
+ 0
+};
+
+/** Property names for font height settings. */
+const sal_Char* const sppcFontHeightNames[] =
+{
+ "CharHeight",
+ "CharHeightAsian",
+ "CharHeightComplex",
+ 0
+};
+
+/** Property names for font weight settings. */
+const sal_Char* const sppcFontWeightNames[] =
+{
+ "CharWeight",
+ "CharWeightAsian",
+ "CharWeightComplex",
+ 0
+};
+
+/** Property names for font posture settings. */
+const sal_Char* const sppcFontPostureNames[] =
+{
+ "CharPosture",
+ "CharPostureAsian",
+ "CharPostureComplex",
+ 0
+};
+
+/** Property names for font escapement settings. */
+const sal_Char* const sppcFontEscapeNames[] =
+{
+ "CharEscapement",
+ "CharEscapementHeight",
+ 0
+};
+
+/** Property names for alignment. */
+const sal_Char* const sppcAlignmentNames[] =
+{
+ "HoriJustify",
+ "VertJustify",
+ "WritingMode",
+ "RotateAngle",
+ "RotateReference",
+ "Orientation",
+ "ParaIndent",
+ "IsTextWrapped",
+ "ShrinkToFit",
+ 0
+};
+
+/** Property names for diagonal cell borders. */
+const sal_Char* const sppcDiagBorderNames[] =
+{
+ "DiagonalTLBR",
+ "DiagonalBLTR",
+ 0
+};
+
+/** Property names for cell fill. */
+const sal_Char* const sppcSolidFillNames[] =
+{
+ "CellBackColor",
+ "IsCellBackgroundTransparent",
+ 0
+};
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+StylesPropertyHelper::StylesPropertyHelper( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maWstrnFontNameProps( sppcWstrnFontNameNames ),
+ maAsianFontNameProps( sppcAsianFontNameNames ),
+ maCmplxFontNameProps( sppcCmplxFontNameNames ),
+ maFontHeightProps( sppcFontHeightNames ),
+ maFontWeightProps( sppcFontWeightNames ),
+ maFontPostureProps( sppcFontPostureNames ),
+ maFontEscapeProps( sppcFontEscapeNames ),
+ maAlignProps( sppcAlignmentNames ),
+ maDiagBorderProps( sppcDiagBorderNames ),
+ maSolidFillProps( sppcSolidFillNames ),
+ maCharColorProp( CREATE_OUSTRING( "CharColor" ) ),
+ maCharUnderlineProp( CREATE_OUSTRING( "CharUnderline" ) ),
+ maCharStrikeoutProp( CREATE_OUSTRING( "CharStrikeout" ) ),
+ maCharContouredProp( CREATE_OUSTRING( "CharContoured" ) ),
+ maCharShadowedProp( CREATE_OUSTRING( "CharShadowed" ) ),
+ maNumFmtProp( CREATE_OUSTRING( "NumberFormat" ) ),
+ maCellProtProp( CREATE_OUSTRING( "CellProtection" ) ),
+ maBorderProp( CREATE_OUSTRING( "TableBorder" ) )
+{
+}
+
+void StylesPropertyHelper::writeFontProperties( PropertySet& rPropSet,
+ const ApiFontData& rFontData, const ApiFontUsedFlags& rUsedFlags, FontPropertyType ePropType )
+{
+ // font name properties
+ if( rUsedFlags.mbNameUsed )
+ {
+ if( rFontData.mbHasWstrn )
+ maWstrnFontNameProps << rFontData.maDesc.Name << rFontData.maDesc.Family << rFontData.maDesc.CharSet >> rPropSet;
+ if( rFontData.mbHasAsian )
+ maAsianFontNameProps << rFontData.maDesc.Name << rFontData.maDesc.Family << rFontData.maDesc.CharSet >> rPropSet;
+ if( rFontData.mbHasCmplx )
+ maCmplxFontNameProps << rFontData.maDesc.Name << rFontData.maDesc.Family << rFontData.maDesc.CharSet >> rPropSet;
+ }
+ // font height
+ if( rUsedFlags.mbHeightUsed )
+ {
+ float fHeight = static_cast< float >( rFontData.maDesc.Height / 20.0 ); // twips to points
+ maFontHeightProps << fHeight << fHeight << fHeight >> rPropSet;
+ }
+ // font weight
+ if( rUsedFlags.mbWeightUsed )
+ {
+ float fWeight = rFontData.maDesc.Weight;
+ maFontWeightProps << fWeight << fWeight << fWeight >> rPropSet;
+ }
+ // font posture
+ if( rUsedFlags.mbPostureUsed )
+ maFontPostureProps << rFontData.maDesc.Slant << rFontData.maDesc.Slant << rFontData.maDesc.Slant >> rPropSet;
+ // character color
+ if( rUsedFlags.mbColorUsed )
+ rPropSet.setProperty( maCharColorProp, rFontData.mnColor );
+ // underline style
+ if( rUsedFlags.mbUnderlineUsed )
+ rPropSet.setProperty( maCharUnderlineProp, rFontData.maDesc.Underline );
+ // strike out style
+ if( rUsedFlags.mbStrikeoutUsed )
+ rPropSet.setProperty( maCharStrikeoutProp, rFontData.maDesc.Strikeout );
+ // outline style
+ if( rUsedFlags.mbOutlineUsed )
+ rPropSet.setProperty( maCharContouredProp, rFontData.mbOutline );
+ // shadow style
+ if( rUsedFlags.mbShadowUsed )
+ rPropSet.setProperty( maCharShadowedProp, rFontData.mbShadow );
+ // escapement
+ if( rUsedFlags.mbEscapementUsed && (ePropType == FONT_PROPTYPE_RICHTEXT) )
+ maFontEscapeProps << rFontData.mnEscapement << rFontData.mnEscapeHeight >> rPropSet;
+}
+
+void StylesPropertyHelper::writeNumFmtProperties(
+ PropertySet& rPropSet, const ApiNumFmtData& rNumFmtData )
+{
+ rPropSet.setProperty( maNumFmtProp, rNumFmtData.mnIndex );
+}
+
+void StylesPropertyHelper::writeAlignmentProperties(
+ PropertySet& rPropSet, const ApiAlignmentData& rAlignData )
+{
+ maAlignProps
+ << rAlignData.meHorJustify
+ << rAlignData.meVerJustify
+ << rAlignData.mnWritingMode
+ << rAlignData.mnRotation
+ << ::com::sun::star::table::CellVertJustify_STANDARD // rotation reference
+ << rAlignData.meOrientation
+ << rAlignData.mnIndent
+ << rAlignData.mbWrapText
+ << rAlignData.mbShrink
+ >> rPropSet;
+}
+
+void StylesPropertyHelper::writeProtectionProperties(
+ PropertySet& rPropSet, const ApiProtectionData& rProtData )
+{
+ rPropSet.setProperty( maCellProtProp, rProtData.maCellProt );
+}
+
+void StylesPropertyHelper::writeBorderProperties(
+ PropertySet& rPropSet, const ApiBorderData& rBorderData )
+{
+ if( rBorderData.mbBorderUsed )
+ rPropSet.setProperty( maBorderProp, rBorderData.maBorder );
+ if( rBorderData.mbDiagUsed )
+ maDiagBorderProps << rBorderData.maTLtoBR << rBorderData.maBLtoTR >> rPropSet;
+}
+
+void StylesPropertyHelper::writeSolidFillProperties(
+ PropertySet& rPropSet, const ApiSolidFillData& rFillData )
+{
+ if( rFillData.mbUsed )
+ maSolidFillProps << rFillData.mnColor << rFillData.mbTransparent >> rPropSet;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/tablebuffer.cxx b/oox/source/xls/tablebuffer.cxx
new file mode 100644
index 000000000000..5865422f62e5
--- /dev/null
+++ b/oox/source/xls/tablebuffer.cxx
@@ -0,0 +1,172 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: tablebuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/tablebuffer.hxx"
+#include <com/sun/star/sheet/XDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XDatabaseRange.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/addressconverter.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::sheet::XDatabaseRanges;
+using ::com::sun::star::sheet::XDatabaseRange;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxTableData::OoxTableData() :
+ mnId( -1 ),
+ mnType( XML_worksheet ),
+ mnHeaderRows( 1 ),
+ mnTotalsRows( 0 )
+{
+}
+
+// ============================================================================
+
+Table::Table( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mnTokenIndex( -1 )
+{
+}
+
+void Table::importTable( const AttributeList& rAttribs, sal_Int16 nSheet )
+{
+ if( getAddressConverter().convertToCellRange( maOoxData.maRange, rAttribs.getString( XML_ref ), nSheet, true ) )
+ {
+ maOoxData.maProgName = rAttribs.getString( XML_name );
+ maOoxData.maDisplayName = rAttribs.getString( XML_displayName );
+ maOoxData.mnId = rAttribs.getInteger( XML_id, -1 );
+ maOoxData.mnType = rAttribs.getToken( XML_tableType, XML_worksheet );
+ maOoxData.mnHeaderRows = rAttribs.getInteger( XML_headerRowCount, 1 );
+ maOoxData.mnTotalsRows = rAttribs.getInteger( XML_totalsRowCount, 0 );
+ }
+}
+
+void Table::importTable( RecordInputStream& rStrm, sal_Int16 nSheet )
+{
+ BinRange aBinRange;
+ rStrm >> aBinRange;
+ if( getAddressConverter().convertToCellRange( maOoxData.maRange, aBinRange, nSheet, true ) )
+ {
+ sal_Int32 nType;
+ rStrm >> nType >> maOoxData.mnId >> maOoxData.mnHeaderRows >> maOoxData.mnTotalsRows;
+ rStrm.skip( 32 );
+ rStrm >> maOoxData.maProgName >> maOoxData.maDisplayName;
+
+ static const sal_Int32 spnTypes[] = { XML_worksheet, XML_TOKEN_INVALID, XML_TOKEN_INVALID, XML_queryTable };
+ maOoxData.mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_TOKEN_INVALID );
+ }
+}
+
+void Table::finalizeImport()
+{
+ if( maOoxData.maDisplayName.getLength() > 0 ) try
+ {
+ // find an unused name
+ Reference< XDatabaseRanges > xDatabaseRanges = getDatabaseRanges();
+ Reference< XNameAccess > xNameAccess( xDatabaseRanges, UNO_QUERY_THROW );
+ OUString aName = ContainerHelper::getUnusedName( xNameAccess, maOoxData.maDisplayName, '_' );
+ xDatabaseRanges->addNewByName( aName, maOoxData.maRange );
+ Reference< XDatabaseRange > xDatabaseRange( xDatabaseRanges->getByName( aName ), UNO_QUERY_THROW );
+ PropertySet aPropSet( xDatabaseRange );
+ if( !aPropSet.getProperty( mnTokenIndex, CREATE_OUSTRING( "TokenIndex" ) ) )
+ mnTokenIndex = -1;
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "Table::finalizeImport - cannot create database range" );
+ }
+}
+
+// ============================================================================
+
+TableBuffer::TableBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+TableRef TableBuffer::importTable( const AttributeList& rAttribs, sal_Int16 nSheet )
+{
+ TableRef xTable( new Table( *this ) );
+ xTable->importTable( rAttribs, nSheet );
+ insertTable( xTable );
+ return xTable;
+}
+
+TableRef TableBuffer::importTable( RecordInputStream& rStrm, sal_Int16 nSheet )
+{
+ TableRef xTable( new Table( *this ) );
+ xTable->importTable( rStrm, nSheet );
+ insertTable( xTable );
+ return xTable;
+}
+
+void TableBuffer::finalizeImport()
+{
+ maTables.forEachMem( &Table::finalizeImport );
+}
+
+TableRef TableBuffer::getTable( sal_Int32 nTableId ) const
+{
+ return maTables.get( nTableId );
+}
+
+// private --------------------------------------------------------------------
+
+void TableBuffer::insertTable( TableRef xTable )
+{
+ sal_Int32 nTableId = xTable->getTableId();
+ if( nTableId > 0 )
+ {
+ OSL_ENSURE( maTables.find( nTableId ) == maTables.end(), "TableBuffer::insertTable - multiple table identifier" );
+ maTables[ nTableId ] = xTable;
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/tablefragment.cxx b/oox/source/xls/tablefragment.cxx
new file mode 100644
index 000000000000..53097159a05d
--- /dev/null
+++ b/oox/source/xls/tablefragment.cxx
@@ -0,0 +1,92 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: tablefragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/tablefragment.hxx"
+
+using ::rtl::OUString;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxTableFragment::OoxTableFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxTableFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nElement == XLS_TOKEN( table ));
+ }
+ return false;
+}
+
+void OoxTableFragment::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( table ): mxTable = getTables().importTable( rAttribs, getSheetIndex() ); break;
+ }
+}
+
+bool OoxTableFragment::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nRecId == OOBIN_ID_TABLE);
+ }
+ return false;
+}
+
+void OoxTableFragment::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_TABLE: mxTable = getTables().importTable( rStrm, getSheetIndex() ); break;
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/themebuffer.cxx b/oox/source/xls/themebuffer.cxx
new file mode 100644
index 000000000000..1a930aa26845
--- /dev/null
+++ b/oox/source/xls/themebuffer.cxx
@@ -0,0 +1,170 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: themebuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/stylespropertyhelper.hxx"
+
+using ::oox::drawingml::ClrScheme;
+using ::oox::drawingml::Theme;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+/** Specifies default theme fonts for a specific locale. */
+struct BuiltinThemeFont
+{
+ const sal_Char* mpcLocale; /// The locale for this font setting.
+ const sal_Char* mpcHeadFont; /// Default heading font.
+ const sal_Char* mpcBodyFont; /// Default body font.
+};
+
+#define FONT_JA "\357\274\255\357\274\263 \357\274\260\343\202\264\343\202\267\343\203\203\343\202\257"
+#define FONT_KO "\353\247\221\354\235\200 \352\263\240\353\224\225"
+#define FONT_CS "\345\256\213\344\275\223"
+#define FONT_CT "\346\226\260\347\264\260\346\230\216\351\253\224"
+
+static const BuiltinThemeFont spBuiltinThemeFonts[] =
+{ // locale headings font body font
+ { "*", "Cambria", "Calibri" }, // Default
+ { "ar", "Times New Roman", "Arial" }, // Arabic
+ { "bn", "Vrinda", "Vrinda" }, // Bengali
+ { "div", "MV Boli", "MV Boli" }, // Divehi
+ { "fa", "Times New Roman", "Arial" }, // Farsi
+ { "gu", "Shruti", "Shruti" }, // Gujarati
+ { "he", "Times New Roman", "Arial" }, // Hebrew
+ { "hi", "Mangal", "Mangal" }, // Hindi
+ { "ja", FONT_JA, FONT_JA }, // Japanese
+ { "kn", "Tunga", "Tunga" }, // Kannada
+ { "ko", FONT_KO, FONT_KO }, // Korean
+ { "kok", "Mangal", "Mangal" }, // Konkani
+ { "ml", "Kartika", "Kartika" }, // Malayalam
+ { "mr", "Mangal", "Mangal" }, // Marathi
+ { "pa", "Raavi", "Raavi" }, // Punjabi
+ { "sa", "Mangal", "Mangal" }, // Sanskrit
+ { "syr", "Estrangelo Edessa", "Estrangelo Edessa" }, // Syriac
+ { "ta", "Latha", "Latha" }, // Tamil
+ { "te", "Gautami", "Gautami" }, // Telugu
+ { "th", "Tahoma", "Tahoma" }, // Thai
+ { "ur", "Times New Roman", "Arial" }, // Urdu
+ { "vi", "Times New Roman", "Arial" }, // Vietnamese
+ { "zh", FONT_CS, FONT_CS }, // Chinese, Simplified
+ { "zh-HK", FONT_CT, FONT_CT }, // Chinese, Hong Kong
+ { "zh-MO", FONT_CT, FONT_CT }, // Chinese, Macau
+ { "zh-TW", FONT_CT, FONT_CT } // Chinese, Taiwan
+};
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+ThemeBuffer::ThemeBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mxDefFontData( new OoxFontData )
+{
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ //! TODO: locale dependent font name
+ mxDefFontData->maName = CREATE_OUSTRING( "Cambria" );
+ mxDefFontData->mfHeight = 11.0;
+ break;
+ case FILTER_BIFF:
+ //! TODO: BIFF dependent font name
+ mxDefFontData->maName = CREATE_OUSTRING( "Arial" );
+ mxDefFontData->mfHeight = 10.0;
+ break;
+ case FILTER_UNKNOWN: break;
+ }
+}
+
+ThemeBuffer::~ThemeBuffer()
+{
+}
+
+Theme& ThemeBuffer::getCoreTheme() const
+{
+ if( !mxTheme )
+ mxTheme.reset( new Theme );
+ return *mxTheme;
+}
+
+sal_Int32 ThemeBuffer::getColorByToken( sal_Int32 nToken ) const
+{
+ sal_Int32 nColor = 0;
+ if( const ClrScheme* pClrScheme = getCoreTheme().getClrScheme().get() )
+ if( pClrScheme->getColor( nToken, nColor ) )
+ return nColor;
+ return API_RGB_TRANSPARENT;
+}
+
+sal_Int32 ThemeBuffer::getColorByIndex( sal_Int32 nIndex ) const
+{
+ static const sal_Int32 spnColorTokens[] = {
+ XML_lt1, XML_dk1, XML_lt2, XML_dk2, XML_accent1, XML_accent2,
+ XML_accent3, XML_accent4, XML_accent5, XML_accent6, XML_hlink, XML_folHlink };
+
+ sal_Int32 nColor = 0;
+ if( const ClrScheme* pClrScheme = getCoreTheme().getClrScheme().get() )
+ if( pClrScheme->getColor( STATIC_ARRAY_SELECT( spnColorTokens, nIndex, XML_TOKEN_INVALID ), nColor ) )
+ return nColor;
+ return API_RGB_TRANSPARENT;
+}
+
+sal_Int32 ThemeBuffer::getSystemColor( sal_Int32 nElement, sal_Int32 nDefaultColor )
+{
+ sal_Int32 nColor = 0;
+ return ClrScheme::getSystemColor( nColor, nElement ) ? nColor : nDefaultColor;
+}
+
+sal_Int32 ThemeBuffer::getSystemWindowColor()
+{
+ return getSystemColor( XML_window, 0xFFFFFF );
+}
+
+sal_Int32 ThemeBuffer::getSystemWindowTextColor()
+{
+ return getSystemColor( XML_windowText, 0x000000 );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/unitconverter.cxx b/oox/source/xls/unitconverter.cxx
new file mode 100644
index 000000000000..66f92142413b
--- /dev/null
+++ b/oox/source/xls/unitconverter.cxx
@@ -0,0 +1,209 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: unitconverter.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/unitconverter.hxx"
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/awt/XDevice.hpp>
+#include <com/sun/star/awt/DeviceInfo.hpp>
+#include <com/sun/star/awt/XFont.hpp>
+#include "oox/xls/stylesbuffer.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::awt::FontDescriptor;
+using ::com::sun::star::awt::XDevice;
+using ::com::sun::star::awt::DeviceInfo;
+using ::com::sun::star::awt::XFont;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const double MM100_PER_INCH = 2540.0;
+const double INCH_PER_MM100 = 1.0 / MM100_PER_INCH;
+
+const double POINT_PER_INCH = 72.0;
+const double INCH_PER_POINT = 1.0 / POINT_PER_INCH;
+
+const double MM100_PER_POINT = MM100_PER_INCH * INCH_PER_POINT;
+const double POINT_PER_MM100 = 1.0 / MM100_PER_POINT;
+
+const double TWIP_PER_POINT = 20.0;
+const double POINT_PER_TWIP = 1.0 / TWIP_PER_POINT;
+
+const double MM100_PER_TWIP = MM100_PER_POINT * POINT_PER_TWIP;
+const double TWIP_PER_MM100 = 1.0 / MM100_PER_TWIP;
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+UnitConverter::UnitConverter( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mfPixelPerMm100X( 0.08 ),
+ mfPixelPerMm100Y( 0.08 ),
+ mnDigitWidth( 200 ),
+ mnSpaceWidth( 100 )
+{
+ // map error code names to BIFF error codes
+ maErrorCodes[ CREATE_OUSTRING( "#NULL!" ) ] = BIFF_ERR_NULL;
+ maErrorCodes[ CREATE_OUSTRING( "#DIV/0!" ) ] = BIFF_ERR_DIV0;
+ maErrorCodes[ CREATE_OUSTRING( "#VALUE!" ) ] = BIFF_ERR_VALUE;
+ maErrorCodes[ CREATE_OUSTRING( "#REF!" ) ] = BIFF_ERR_REF;
+ maErrorCodes[ CREATE_OUSTRING( "#NAME?" ) ] = BIFF_ERR_NAME;
+ maErrorCodes[ CREATE_OUSTRING( "#NUM!" ) ] = BIFF_ERR_NUM;
+ maErrorCodes[ CREATE_OUSTRING( "#NA" ) ] = BIFF_ERR_NA;
+}
+
+void UnitConverter::finalizeImport()
+{
+ Reference< XDevice > xDevice = getReferenceDevice();
+ if( xDevice.is() )
+ {
+ // get pixel metric first, needed to get character widths below
+ DeviceInfo aInfo = xDevice->getInfo();
+ mfPixelPerMm100X = aInfo.PixelPerMeterX / 100000.0;
+ mfPixelPerMm100Y = aInfo.PixelPerMeterY / 100000.0;
+
+ // get character widths from default font
+ if( const Font* pDefFont = getStyles().getDefaultFont().get() )
+ {
+ // XDevice expects pixels in font descriptor, but font contains twips
+ FontDescriptor aDesc = pDefFont->getFontDescriptor();
+ aDesc.Height = static_cast< sal_Int16 >( calcPixelsXFromMm100( calcMm100FromTwips( aDesc.Height ) ) );
+ Reference< XFont > xFont = xDevice->getFont( aDesc );
+ if( xFont.is() )
+ {
+ // get maximum width of all digits
+ sal_Int32 nDigitWidth = 0;
+ for( sal_Unicode cChar = '0'; cChar <= '9'; ++cChar )
+ nDigitWidth = ::std::max( nDigitWidth, calcMm100FromPixelsX( xFont->getCharWidth( cChar ) ) );
+ if( nDigitWidth > 0 )
+ mnDigitWidth = nDigitWidth;
+ // get width of space character
+ sal_Int32 nSpaceWidth = calcMm100FromPixelsX( xFont->getCharWidth( ' ' ) );
+ if( nSpaceWidth > 0 )
+ mnSpaceWidth = nSpaceWidth;
+ }
+ }
+ }
+}
+
+// conversion -----------------------------------------------------------------
+
+sal_Int32 UnitConverter::calcMm100FromInches( double fInches ) const
+{
+ return static_cast< sal_Int32 >( fInches * MM100_PER_INCH );
+}
+
+sal_Int32 UnitConverter::calcMm100FromPoints( double fPoints ) const
+{
+ return static_cast< sal_Int32 >( fPoints * MM100_PER_POINT + 0.5 );
+}
+
+sal_Int32 UnitConverter::calcMm100FromTwips( double fTwips ) const
+{
+ return static_cast< sal_Int32 >( fTwips * MM100_PER_TWIP + 0.5 );
+}
+
+sal_Int32 UnitConverter::calcMm100FromPixelsX( double fPixels ) const
+{
+ return static_cast< sal_Int32 >( fPixels / mfPixelPerMm100X + 0.5 );
+}
+
+sal_Int32 UnitConverter::calcMm100FromPixelsY( double fPixels ) const
+{
+ return static_cast< sal_Int32 >( fPixels / mfPixelPerMm100Y + 0.5 );
+}
+
+sal_Int32 UnitConverter::calcMm100FromDigits( double fChars ) const
+{
+ return static_cast< sal_Int32 >( fChars * mnDigitWidth + 0.5 );
+}
+
+sal_Int32 UnitConverter::calcMm100FromSpaces( double fSpaces ) const
+{
+ return static_cast< sal_Int32 >( fSpaces * mnSpaceWidth + 0.5 );
+}
+
+double UnitConverter::calcInchesFromMm100( sal_Int32 nMm100 ) const
+{
+ return nMm100 * INCH_PER_MM100;
+}
+
+double UnitConverter::calcPointsFromMm100( sal_Int32 nMm100 ) const
+{
+ return nMm100 * POINT_PER_MM100;
+}
+
+double UnitConverter::calcTwipsFromMm100( sal_Int32 nMm100 ) const
+{
+ return nMm100 * TWIP_PER_MM100;
+}
+
+double UnitConverter::calcPixelsXFromMm100( sal_Int32 nMm100 ) const
+{
+ return nMm100 * mfPixelPerMm100X;
+}
+
+double UnitConverter::calcPixelsYFromMm100( sal_Int32 nMm100 ) const
+{
+ return nMm100 * mfPixelPerMm100Y;
+}
+
+double UnitConverter::calcDigitsFromMm100( sal_Int32 nMm100 ) const
+{
+ return static_cast< double >( nMm100 ) / mnDigitWidth;
+}
+
+double UnitConverter::calcSpacesFromMm100( sal_Int32 nMm100 ) const
+{
+ return static_cast< double >( nMm100 ) / mnSpaceWidth;
+}
+
+sal_uInt8 UnitConverter::calcBiffErrorCode( const OUString& rErrorCode ) const
+{
+ ErrorCodeMap::const_iterator aIt = maErrorCodes.find( rErrorCode );
+ return (aIt == maErrorCodes.end()) ? BIFF_ERR_NA : aIt->second;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/validationpropertyhelper.cxx b/oox/source/xls/validationpropertyhelper.cxx
new file mode 100644
index 000000000000..8784fad81cb0
--- /dev/null
+++ b/oox/source/xls/validationpropertyhelper.cxx
@@ -0,0 +1,174 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: validationpropertyhelper.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ * * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/validationpropertyhelper.hxx"
+#include <com/sun/star/sheet/ValidationType.hpp>
+#include <com/sun/star/sheet/ValidationAlertStyle.hpp>
+#include <com/sun/star/sheet/TableValidationVisibility.hpp>
+#include <com/sun/star/sheet/XSheetCondition.hpp>
+#include <com/sun/star/sheet/XMultiFormulaTokens.hpp>
+#include "oox/helper/propertyset.hxx"
+#include "oox/xls/ooxtokens.hxx"
+#include "oox/xls/worksheethelper.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::sheet::ValidationType;
+using ::com::sun::star::sheet::ValidationAlertStyle;
+using ::com::sun::star::sheet::ConditionOperator;
+using ::com::sun::star::sheet::XSheetCondition;
+using ::com::sun::star::sheet::XMultiFormulaTokens;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_Char* const sppcPropNames[] =
+{
+ "Type",
+ "ShowInputMessage",
+ "InputTitle",
+ "InputMessage",
+ "ShowErrorMessage",
+ "ErrorTitle",
+ "ErrorMessage",
+ "ErrorAlertStyle",
+ "ShowList",
+ "IgnoreBlankCells",
+ 0
+};
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+ValidationPropertyHelper::ValidationPropertyHelper( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maValProps( sppcPropNames ),
+ maValidationProp( CREATE_OUSTRING( "Validation" ) )
+{
+}
+
+void ValidationPropertyHelper::writeValidationProperties( PropertySet& rPropSet, const OoxValidationData& rValData )
+{
+ Reference< XPropertySet > xValidation;
+ if( rPropSet.getProperty( xValidation, maValidationProp ) && xValidation.is() )
+ {
+ PropertySet aValProps( xValidation );
+ namespace csss = ::com::sun::star::sheet;
+
+ // convert validation type to API enum
+ ValidationType eType = csss::ValidationType_ANY;
+ switch( rValData.mnType )
+ {
+ case XML_custom: eType = csss::ValidationType_CUSTOM; break;
+ case XML_date: eType = csss::ValidationType_DATE; break;
+ case XML_decimal: eType = csss::ValidationType_DECIMAL; break;
+ case XML_list: eType = csss::ValidationType_LIST; break;
+ case XML_none: eType = csss::ValidationType_ANY; break;
+ case XML_textLength: eType = csss::ValidationType_TEXT_LEN; break;
+ case XML_time: eType = csss::ValidationType_TIME; break;
+ case XML_whole: eType = csss::ValidationType_WHOLE; break;
+ default: OSL_ENSURE( false, "ValidationPropertyHelper::writeValidationProperties - unknown validation type" );
+ }
+
+ // convert error alert style to API enum
+ ValidationAlertStyle nAlertStyle = csss::ValidationAlertStyle_STOP;
+ switch( rValData.mnErrorStyle )
+ {
+ case XML_information: nAlertStyle = csss::ValidationAlertStyle_INFO; break;
+ case XML_stop: nAlertStyle = csss::ValidationAlertStyle_STOP; break;
+ case XML_warning: nAlertStyle = csss::ValidationAlertStyle_WARNING; break;
+ default: OSL_ENSURE( false, "ValidationPropertyHelper::writeValidationProperties - unknown error style" );
+ }
+
+ // convert dropdown style to API visibility constants
+ sal_Int16 nVisibility = rValData.mbNoDropDown ? csss::TableValidationVisibility::INVISIBLE : csss::TableValidationVisibility::UNSORTED;
+
+ // write all properties
+ maValProps
+ << eType
+ << rValData.mbShowInputMsg << rValData.maInputTitle << rValData.maInputMessage
+ << rValData.mbShowErrorMsg << rValData.maErrorTitle << rValData.maErrorMessage
+ << nAlertStyle << nVisibility << rValData.mbAllowBlank
+ >> aValProps;
+
+ try
+ {
+ // condition operator
+ Reference< XSheetCondition > xSheetCond( xValidation, UNO_QUERY_THROW );
+ xSheetCond->setOperator( convertToApiOperator( rValData.mnOperator ) );
+
+ // condition formulas
+ Reference< XMultiFormulaTokens > xTokens( xValidation, UNO_QUERY_THROW );
+ xTokens->setTokens( 0, rValData.maTokens1 );
+ xTokens->setTokens( 1, rValData.maTokens2 );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // write back validation settings to cell range(s)
+ rPropSet.setProperty( maValidationProp, xValidation );
+ }
+}
+
+ConditionOperator ValidationPropertyHelper::convertToApiOperator( sal_Int32 nToken )
+{
+ using namespace ::com::sun::star::sheet;
+ switch( nToken )
+ {
+ case XML_between: return ConditionOperator_BETWEEN;
+ case XML_equal: return ConditionOperator_EQUAL;
+ case XML_greaterThan: return ConditionOperator_GREATER;
+ case XML_greaterThanOrEqual: return ConditionOperator_GREATER_EQUAL;
+ case XML_lessThan: return ConditionOperator_LESS;
+ case XML_lessThanOrEqual: return ConditionOperator_LESS_EQUAL;
+ case XML_notBetween: return ConditionOperator_NOT_BETWEEN;
+ case XML_notEqual: return ConditionOperator_NOT_EQUAL;
+ }
+ return ConditionOperator_NONE;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/viewsettings.cxx b/oox/source/xls/viewsettings.cxx
new file mode 100644
index 000000000000..7ec207015ae6
--- /dev/null
+++ b/oox/source/xls/viewsettings.cxx
@@ -0,0 +1,789 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: viewsettings.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/viewsettings.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/document/XViewDataSupplier.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertysequence.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/ooxtokens.hxx"
+#include "oox/xls/unitconverter.hxx"
+#include "oox/xls/workbooksettings.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::container::XNameContainer;
+using ::com::sun::star::container::XIndexContainer;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::document::XViewDataSupplier;
+using ::com::sun::star::table::CellAddress;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 OOX_BOOKVIEW_TABBARRATIO_DEF = 600; /// Default tabbar ratio.
+const sal_Int32 OOX_SHEETVIEW_NORMALZOOM_DEF = 100; /// Default zoom for normal view.
+const sal_Int32 OOX_SHEETVIEW_SHEETLAYZOOM_DEF = 60; /// Default zoom for pagebreak preview.
+const sal_Int32 OOX_SHEETVIEW_PAGELAYZOOM_DEF = 100; /// Default zoom for page layout view.
+
+const sal_uInt8 OOBIN_PANE_FROZEN = 0x01;
+const sal_uInt8 OOBIN_PANE_FROZENNOSPLIT = 0x02;
+
+const sal_uInt16 OOBIN_SHEETVIEW_WINPROTECTED = 0x0001;
+const sal_uInt16 OOBIN_SHEETVIEW_SHOWFORMULAS = 0x0002;
+const sal_uInt16 OOBIN_SHEETVIEW_SHOWGRID = 0x0004;
+const sal_uInt16 OOBIN_SHEETVIEW_SHOWHEADINGS = 0x0008;
+const sal_uInt16 OOBIN_SHEETVIEW_SHOWZEROS = 0x0010;
+const sal_uInt16 OOBIN_SHEETVIEW_RIGHTTOLEFT = 0x0020;
+const sal_uInt16 OOBIN_SHEETVIEW_SELECTED = 0x0040;
+const sal_uInt16 OOBIN_SHEETVIEW_SHOWRULER = 0x0080;
+const sal_uInt16 OOBIN_SHEETVIEW_SHOWOUTLINE = 0x0100;
+const sal_uInt16 OOBIN_SHEETVIEW_DEFGRIDCOLOR = 0x0200;
+const sal_uInt16 OOBIN_SHEETVIEW_SHOWWHITESPACE = 0x0400;
+
+const sal_uInt8 OOBIN_WBVIEW_HIDDEN = 0x01;
+const sal_uInt8 OOBIN_WBVIEW_MINIMIZED = 0x02;
+const sal_uInt8 OOBIN_WBVIEW_SHOWHORSCROLL = 0x08;
+const sal_uInt8 OOBIN_WBVIEW_SHOWVERSCROLL = 0x10;
+const sal_uInt8 OOBIN_WBVIEW_SHOWTABBAR = 0x20;
+const sal_uInt8 OOBIN_WBVIEW_AUTOFILTERGROUP = 0x40;
+
+const sal_uInt8 BIFF_PANE_BOTTOMRIGHT = 0; /// Bottom-right pane.
+const sal_uInt8 BIFF_PANE_TOPRIGHT = 1; /// Right, or top-right pane.
+const sal_uInt8 BIFF_PANE_BOTTOMLEFT = 2; /// Bottom, or bottom-left pane.
+const sal_uInt8 BIFF_PANE_TOPLEFT = 3; /// Single, top, left, or top-left pane.
+
+const sal_uInt16 BIFF_WINDOW1_HIDDEN = 0x0001;
+const sal_uInt16 BIFF_WINDOW1_MINIMIZED = 0x0002;
+const sal_uInt16 BIFF_WINDOW1_SHOWHORSCROLL = 0x0008;
+const sal_uInt16 BIFF_WINDOW1_SHOWVERSCROLL = 0x0010;
+const sal_uInt16 BIFF_WINDOW1_SHOWTABBAR = 0x0020;
+
+const sal_uInt16 BIFF_WINDOW2_SHOWFORMULAS = 0x0001;
+const sal_uInt16 BIFF_WINDOW2_SHOWGRID = 0x0002;
+const sal_uInt16 BIFF_WINDOW2_SHOWHEADINGS = 0x0004;
+const sal_uInt16 BIFF_WINDOW2_FROZEN = 0x0008;
+const sal_uInt16 BIFF_WINDOW2_SHOWZEROS = 0x0010;
+const sal_uInt16 BIFF_WINDOW2_DEFGRIDCOLOR = 0x0020;
+const sal_uInt16 BIFF_WINDOW2_RIGHTTOLEFT = 0x0040;
+const sal_uInt16 BIFF_WINDOW2_SHOWOUTLINE = 0x0080;
+const sal_uInt16 BIFF_WINDOW2_FROZENNOSPLIT = 0x0100;
+const sal_uInt16 BIFF_WINDOW2_SELECTED = 0x0200;
+const sal_uInt16 BIFF_WINDOW2_DISPLAYED = 0x0400;
+const sal_uInt16 BIFF_WINDOW2_PAGEBREAKMODE = 0x0800;
+
+// Attention: view settings in Calc do not use com.sun.star.view.DocumentZoomType!
+const sal_Int16 API_ZOOMTYPE_PERCENT = 0; /// Zoom value in percent.
+
+const sal_Int32 API_ZOOMVALUE_MIN = 20; /// Minimum zoom in Calc.
+const sal_Int32 API_ZOOMVALUE_MAX = 400; /// Maximum zoom in Calc.
+
+// no predefined constants for split mode
+const sal_Int16 API_SPLITMODE_NONE = 0; /// No splits in window.
+const sal_Int16 API_SPLITMODE_SPLIT = 1; /// Window is split.
+const sal_Int16 API_SPLITMODE_FREEZE = 2; /// Window has frozen panes.
+
+// no predefined constants for pane idetifiers
+const sal_Int16 API_SPLITPANE_TOPLEFT = 0; /// Top-left, or top pane.
+const sal_Int16 API_SPLITPANE_TOPRIGHT = 1; /// Top-right pane.
+const sal_Int16 API_SPLITPANE_BOTTOMLEFT = 2; /// Bottom-left, bottom, left, or single pane.
+const sal_Int16 API_SPLITPANE_BOTTOMRIGHT = 3; /// Bottom-right, or right pane.
+
+// ----------------------------------------------------------------------------
+
+/** Property names for document view settings. */
+const sal_Char* const sppcDocNames[] =
+{
+ "Tables",
+ "ActiveTable",
+ "HasHorizontalScrollBar",
+ "HasVerticalScrollBar",
+ "HasSheetTabs",
+ "RelativeHorizontalTabbarWidth",
+ "ShowObjects",
+ "ShowCharts",
+ "ShowDrawing",
+ 0
+};
+
+/** Property names for sheet view settings that are document-global in Calc. */
+const sal_Char* const sppcGlobalSheetNames[] =
+{
+ "GridColor",
+ "ZoomType",
+ "ZoomValue",
+ "PageViewZoomValue",
+ "ShowPageBreakPreview",
+ "ShowFormulas",
+ "ShowGrid",
+ "HasColumnRowHeaders",
+ "ShowZeroValues",
+ "IsOutlineSymbolsSet",
+ 0
+};
+
+/** Property names for sheet view settings. */
+const sal_Char* const sppcSheetNames[] =
+{
+ "TableSelected",
+ "CursorPositionX",
+ "CursorPositionY",
+ "HorizontalSplitMode",
+ "VerticalSplitMode",
+ "HorizontalSplitPositionTwips",
+ "VerticalSplitPositionTwips",
+ "ActiveSplitRange",
+ "PositionLeft",
+ "PositionTop",
+ "PositionRight",
+ "PositionBottom",
+ 0
+};
+
+// ----------------------------------------------------------------------------
+
+/** Returns the OOXML pane identifier from the passed OOBIN or BIFF pane id. */
+sal_Int32 lclGetOoxPaneId( sal_Int32 nBinPaneId, sal_Int32 nDefaultPaneId )
+{
+ static const sal_Int32 spnPaneIds[] = { XML_bottomRight, XML_topRight, XML_bottomLeft, XML_topLeft };
+ return STATIC_ARRAY_SELECT( spnPaneIds, nBinPaneId, nDefaultPaneId );
+}
+
+} // namespace
+
+// ============================================================================
+
+OoxSheetSelectionData::OoxSheetSelectionData() :
+ mnActiveCellId( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+OoxSheetViewData::OoxSheetViewData() :
+ maGridColor( XML_indexed, OOX_COLOR_WINDOWTEXT ),
+ mnWorkbookViewId( 0 ),
+ mnViewType( XML_normal ),
+ mnActivePaneId( XML_topLeft ),
+ mnPaneState( XML_split ),
+ mfSplitX( 0.0 ),
+ mfSplitY( 0.0 ),
+ mnCurrentZoom( 0 ),
+ mnNormalZoom( 0 ),
+ mnSheetLayoutZoom( 0 ),
+ mnPageLayoutZoom( 0 ),
+ mbSelected( false ),
+ mbRightToLeft( false ),
+ mbDefGridColor( true ),
+ mbShowFormulas( false ),
+ mbShowGrid( true ),
+ mbShowHeadings( true ),
+ mbShowZeros( true ),
+ mbShowOutline( true )
+{
+}
+
+bool OoxSheetViewData::isPageBreakPreview() const
+{
+ return mnViewType == XML_pageBreakPreview;
+}
+
+sal_Int32 OoxSheetViewData::getNormalZoom() const
+{
+ const sal_Int32& rnZoom = isPageBreakPreview() ? mnNormalZoom : mnCurrentZoom;
+ sal_Int32 nZoom = (rnZoom > 0) ? rnZoom : OOX_SHEETVIEW_NORMALZOOM_DEF;
+ return getLimitedValue< sal_Int32 >( nZoom, API_ZOOMVALUE_MIN, API_ZOOMVALUE_MAX );
+}
+
+sal_Int32 OoxSheetViewData::getPageBreakZoom() const
+{
+ const sal_Int32& rnZoom = isPageBreakPreview() ? mnCurrentZoom : mnSheetLayoutZoom;
+ sal_Int32 nZoom = (rnZoom > 0) ? rnZoom : OOX_SHEETVIEW_SHEETLAYZOOM_DEF;
+ return getLimitedValue< sal_Int32 >( nZoom, API_ZOOMVALUE_MIN, API_ZOOMVALUE_MAX );
+}
+
+const OoxSheetSelectionData* OoxSheetViewData::getSelectionData( sal_Int32 nPaneId ) const
+{
+ return maSelMap.get( nPaneId ).get();
+}
+
+const OoxSheetSelectionData* OoxSheetViewData::getActiveSelectionData() const
+{
+ return getSelectionData( mnActivePaneId );
+}
+
+OoxSheetSelectionData& OoxSheetViewData::createSelectionData( sal_Int32 nPaneId )
+{
+ OoxSelectionDataMap::mapped_type& rxSelData = maSelMap[ nPaneId ];
+ if( !rxSelData )
+ rxSelData.reset( new OoxSheetSelectionData );
+ return *rxSelData;
+}
+
+// ----------------------------------------------------------------------------
+
+SheetViewSettings::SheetViewSettings( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+void SheetViewSettings::importSheetView( const AttributeList& rAttribs )
+{
+ OoxSheetViewData& rData = *createSheetViewData();
+ rData.maGridColor.set( XML_indexed, rAttribs.getInteger( XML_colorId, OOX_COLOR_WINDOWTEXT ) );
+ rData.maFirstPos = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_topLeftCell ), getSheetIndex(), false );
+ rData.mnWorkbookViewId = rAttribs.getToken( XML_workbookViewId, 0 );
+ rData.mnViewType = rAttribs.getToken( XML_view, XML_normal );
+ rData.mnCurrentZoom = rAttribs.getInteger( XML_zoomScale, 100 );
+ rData.mnNormalZoom = rAttribs.getInteger( XML_zoomScaleNormal, 0 );
+ rData.mnSheetLayoutZoom = rAttribs.getInteger( XML_zoomScaleSheetLayoutView, 0 );
+ rData.mnPageLayoutZoom = rAttribs.getInteger( XML_zoomScalePageLayoutView, 0 );
+ rData.mbSelected = rAttribs.getBool( XML_tabSelected, false );
+ rData.mbRightToLeft = rAttribs.getBool( XML_rightToLeft, false );
+ rData.mbDefGridColor = rAttribs.getBool( XML_defaultGridColor, true );
+ rData.mbShowFormulas = rAttribs.getBool( XML_showFormulas, false );
+ rData.mbShowGrid = rAttribs.getBool( XML_showGridLines, true );
+ rData.mbShowHeadings = rAttribs.getBool( XML_showRowColHeaders, true );
+ rData.mbShowZeros = rAttribs.getBool( XML_showZeros, true );
+ rData.mbShowOutline = rAttribs.getBool( XML_showOutlineSymbols, true );
+}
+
+void SheetViewSettings::importPane( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( !maSheetDatas.empty(), "SheetViewSettings::importPane - missing view data" );
+ if( !maSheetDatas.empty() )
+ {
+ OoxSheetViewData& rData = *maSheetDatas.back();
+ rData.maSecondPos = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_topLeftCell ), getSheetIndex(), false );
+ rData.mnActivePaneId = rAttribs.getToken( XML_activePane, XML_topLeft );
+ rData.mnPaneState = rAttribs.getToken( XML_state, XML_split );
+ rData.mfSplitX = rAttribs.getDouble( XML_xSplit, 0.0 );
+ rData.mfSplitY = rAttribs.getDouble( XML_ySplit, 0.0 );
+ }
+}
+
+void SheetViewSettings::importSelection( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( !maSheetDatas.empty(), "SheetViewSettings::importSelection - missing view data" );
+ if( !maSheetDatas.empty() )
+ {
+ // pane this selection belongs to
+ sal_Int32 nPaneId = rAttribs.getToken( XML_pane, XML_topLeft );
+ OoxSheetSelectionData& rSelData = maSheetDatas.back()->createSelectionData( nPaneId );
+ // cursor position
+ rSelData.maActiveCell = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_activeCell ), getSheetIndex(), false );
+ rSelData.mnActiveCellId = rAttribs.getInteger( XML_activeCellId, 0 );
+ // selection
+ rSelData.maSelection.clear();
+ getAddressConverter().convertToCellRangeList( rSelData.maSelection, rAttribs.getString( XML_sqref ), getSheetIndex(), false );
+ }
+}
+
+void SheetViewSettings::importSheetView( RecordInputStream& rStrm )
+{
+ OoxSheetViewData& rData = *createSheetViewData();
+ sal_uInt16 nFlags;
+ sal_Int32 nViewType;
+ BinAddress aFirstPos;
+ rStrm >> nFlags >> nViewType >> aFirstPos;
+ rData.maGridColor.importColorId( rStrm );
+ rData.mnCurrentZoom = rStrm.readuInt16();
+ rData.mnNormalZoom = rStrm.readuInt16();
+ rData.mnSheetLayoutZoom = rStrm.readuInt16();
+ rData.mnPageLayoutZoom = rStrm.readuInt16();
+ rStrm >> rData.mnWorkbookViewId;
+
+ rData.maFirstPos = getAddressConverter().createValidCellAddress( aFirstPos, getSheetIndex(), false );
+ static const sal_Int32 spnViewTypes[] = { XML_normal, XML_pageBreakPreview, XML_pageLayout };
+ rData.mnViewType = STATIC_ARRAY_SELECT( spnViewTypes, nViewType, XML_normal );
+ rData.mbSelected = getFlag( nFlags, OOBIN_SHEETVIEW_SELECTED );
+ rData.mbRightToLeft = getFlag( nFlags, OOBIN_SHEETVIEW_RIGHTTOLEFT );
+ rData.mbDefGridColor = getFlag( nFlags, OOBIN_SHEETVIEW_DEFGRIDCOLOR );
+ rData.mbShowFormulas = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWFORMULAS );
+ rData.mbShowGrid = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWGRID );
+ rData.mbShowHeadings = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWHEADINGS );
+ rData.mbShowZeros = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWZEROS );
+ rData.mbShowOutline = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWOUTLINE );
+}
+
+void SheetViewSettings::importPane( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetDatas.empty(), "SheetViewSettings::importPane - missing view data" );
+ if( !maSheetDatas.empty() )
+ {
+ OoxSheetViewData& rData = *maSheetDatas.back();
+
+ BinAddress aSecondPos;
+ sal_Int32 nActivePaneId;
+ sal_uInt8 nFlags;
+ rStrm >> rData.mfSplitX >> rData.mfSplitY >> aSecondPos >> nActivePaneId >> nFlags;
+
+ rData.maSecondPos = getAddressConverter().createValidCellAddress( aSecondPos, getSheetIndex(), false );
+ rData.mnActivePaneId = lclGetOoxPaneId( nActivePaneId, XML_topLeft );
+ rData.mnPaneState = getFlagValue( nFlags, OOBIN_PANE_FROZEN, getFlagValue( nFlags, OOBIN_PANE_FROZENNOSPLIT, XML_frozen, XML_frozenSplit ), XML_split );
+ }
+}
+
+void SheetViewSettings::importSelection( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetDatas.empty(), "SheetViewSettings::importSelection - missing view data" );
+ if( !maSheetDatas.empty() )
+ {
+ // pane this selection belongs to
+ sal_Int32 nPaneId = rStrm.readInt32();
+ OoxSheetSelectionData& rSelData = maSheetDatas.back()->createSelectionData( lclGetOoxPaneId( nPaneId, -1 ) );
+ // cursor position
+ BinAddress aActiveCell;
+ rStrm >> aActiveCell >> rSelData.mnActiveCellId;
+ rSelData.maActiveCell = getAddressConverter().createValidCellAddress( aActiveCell, getSheetIndex(), false );
+ // selection
+ BinRangeList aSelection;
+ rStrm >> aSelection;
+ rSelData.maSelection.clear();
+ getAddressConverter().convertToCellRangeList( rSelData.maSelection, aSelection, getSheetIndex(), false );
+ }
+}
+
+void SheetViewSettings::importWindow2( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( maSheetDatas.empty(), "SheetViewSettings::importWindow2 - multiple WINDOW2 records" );
+ OoxSheetViewData& rData = *createSheetViewData();
+ if( getBiff() == BIFF2 )
+ {
+ rData.mbShowFormulas = rStrm.readuInt8() != 0;
+ rData.mbShowGrid = rStrm.readuInt8() != 0;
+ rData.mbShowHeadings = rStrm.readuInt8() != 0;
+ rData.mnPaneState = (rStrm.readuInt8() == 0) ? XML_split : XML_frozen;
+ rData.mbShowZeros = rStrm.readuInt8() != 0;
+ BinAddress aFirstPos;
+ rStrm >> aFirstPos;
+ rData.maFirstPos = getAddressConverter().createValidCellAddress( aFirstPos, getSheetIndex(), false );
+ rData.mbDefGridColor = rStrm.readuInt8() != 0;
+ rData.maGridColor.importColorRgb( rStrm );
+ }
+ else
+ {
+ sal_uInt16 nFlags;
+ BinAddress aFirstPos;
+ rStrm >> nFlags >> aFirstPos;
+
+ rData.maFirstPos = getAddressConverter().createValidCellAddress( aFirstPos, getSheetIndex(), false );
+ rData.mnViewType = getFlagValue( nFlags, BIFF_WINDOW2_PAGEBREAKMODE, XML_pageBreakPreview, XML_normal );
+ rData.mnPaneState = getFlagValue( nFlags, BIFF_WINDOW2_FROZEN, getFlagValue( nFlags, BIFF_WINDOW2_FROZENNOSPLIT, XML_frozen, XML_frozenSplit ), XML_split );
+ rData.mbSelected = getFlag( nFlags, BIFF_WINDOW2_SELECTED );
+ rData.mbRightToLeft = getFlag( nFlags, BIFF_WINDOW2_RIGHTTOLEFT );
+ rData.mbDefGridColor = getFlag( nFlags, BIFF_WINDOW2_DEFGRIDCOLOR );
+ rData.mbShowFormulas = getFlag( nFlags, BIFF_WINDOW2_SHOWFORMULAS );
+ rData.mbShowGrid = getFlag( nFlags, BIFF_WINDOW2_SHOWGRID );
+ rData.mbShowHeadings = getFlag( nFlags, BIFF_WINDOW2_SHOWHEADINGS );
+ rData.mbShowZeros = getFlag( nFlags, BIFF_WINDOW2_SHOWZEROS );
+ rData.mbShowOutline = getFlag( nFlags, BIFF_WINDOW2_SHOWOUTLINE );
+
+ if( getBiff() == BIFF8 )
+ {
+ rData.maGridColor.importColorId( rStrm );
+ // zoom data not included in chart sheets
+ if( rStrm.getRecLeft() >= 6 )
+ {
+ rStrm.skip( 2 );
+ sal_uInt16 nPageZoom, nNormalZoom;
+ rStrm >> nPageZoom >> nNormalZoom;
+ rData.mnSheetLayoutZoom = nPageZoom;
+ rData.mnNormalZoom = nNormalZoom;
+ }
+ }
+ else
+ {
+ rData.maGridColor.importColorRgb( rStrm );
+ }
+ }
+}
+
+void SheetViewSettings::importPane( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetDatas.empty(), "SheetViewSettings::importPane - missing leading WINDOW2 record" );
+ if( !maSheetDatas.empty() )
+ {
+ sal_uInt8 nActivePaneId;
+ sal_uInt16 nSplitX, nSplitY;
+ BinAddress aSecondPos;
+ rStrm >> nSplitX >> nSplitY >> aSecondPos >> nActivePaneId;
+
+ OoxSheetViewData& rData = *maSheetDatas.back();
+ rData.mfSplitX = nSplitX;
+ rData.mfSplitY = nSplitY;
+ rData.maSecondPos = getAddressConverter().createValidCellAddress( aSecondPos, getSheetIndex(), false );
+ rData.mnActivePaneId = lclGetOoxPaneId( nActivePaneId, XML_topLeft );
+ }
+}
+
+void SheetViewSettings::importScl( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetDatas.empty(), "SheetViewSettings::importScl - missing leading WINDOW2 record" );
+ if( !maSheetDatas.empty() )
+ {
+ sal_uInt16 nNum, nDenom;
+ rStrm >> nNum >> nDenom;
+ OSL_ENSURE( nDenom > 0, "SheetViewSettings::importScl - invalid denominator" );
+ if( nDenom > 0 )
+ maSheetDatas.back()->mnCurrentZoom = getLimitedValue< sal_Int32, sal_uInt16 >( (nNum * 100) / nDenom, 10, 400 );
+ }
+}
+
+void SheetViewSettings::importSelection( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetDatas.empty(), "SheetViewSettings::importPane - missing leading WINDOW2 record" );
+ if( !maSheetDatas.empty() )
+ {
+ // pane this selection belongs to
+ sal_uInt8 nPaneId = rStrm.readuInt8();
+ OoxSheetSelectionData& rSelData = maSheetDatas.back()->createSelectionData( lclGetOoxPaneId( nPaneId, -1 ) );
+ // cursor position
+ BinAddress aActiveCell;
+ sal_uInt16 nActiveCellId;
+ rStrm >> aActiveCell >> nActiveCellId;
+ rSelData.maActiveCell = getAddressConverter().createValidCellAddress( aActiveCell, getSheetIndex(), false );
+ rSelData.mnActiveCellId = nActiveCellId;
+ // selection
+ rSelData.maSelection.clear();
+ BinRangeList aSelection;
+ aSelection.read( rStrm, false );
+ getAddressConverter().convertToCellRangeList( rSelData.maSelection, aSelection, getSheetIndex(), false );
+ }
+}
+
+void SheetViewSettings::finalizeImport()
+{
+ // force creation of sheet view data to get the Excel defaults
+ OoxSheetViewDataRef xData = maSheetDatas.empty() ? createSheetViewData() : maSheetDatas.front();
+
+ // mirrored sheet (this is not a view setting in Calc)
+ // #i59590# real life: Excel ignores mirror flag in chart sheets
+ if( xData->mbRightToLeft && (getSheetType() != SHEETTYPE_CHART) )
+ {
+ PropertySet aPropSet( getXSpreadsheet() );
+ aPropSet.setProperty( CREATE_OUSTRING( "TableLayout" ), ::com::sun::star::text::WritingMode2::RL_TB );
+ }
+
+ // sheet selected (active sheet must be selected)
+ bool bSelected = xData->mbSelected || (getSheetIndex() == getViewSettings().getActiveSheetIndex());
+
+ // current cursor position (selection not supported via API)
+ const OoxSheetSelectionData* pSelData = xData->getActiveSelectionData();
+ CellAddress aCursor = pSelData ? pSelData->maActiveCell : xData->maFirstPos;
+
+ // freeze/split position
+ sal_Int16 nHSplitMode = API_SPLITMODE_NONE;
+ sal_Int16 nVSplitMode = API_SPLITMODE_NONE;
+ sal_Int32 nHSplitPos = 0;
+ sal_Int32 nVSplitPos = 0;
+ if( (xData->mnPaneState == XML_frozen) || (xData->mnPaneState == XML_frozenSplit) )
+ {
+ /* Frozen panes: handle split position as row/column positions.
+ #i35812# Excel uses number of visible rows/columns in the
+ frozen area (rows/columns scolled outside are not incuded),
+ Calc uses absolute position of first unfrozen row/column. */
+ const CellAddress& rMaxApiPos = getAddressConverter().getMaxApiAddress();
+ if( (xData->mfSplitX >= 1.0) && (xData->maFirstPos.Column + xData->mfSplitX <= rMaxApiPos.Column) )
+ nHSplitPos = static_cast< sal_Int32 >( xData->maFirstPos.Column + xData->mfSplitX );
+ nHSplitMode = (nHSplitPos > 0) ? API_SPLITMODE_FREEZE : API_SPLITMODE_NONE;
+ if( (xData->mfSplitY >= 1.0) && (xData->maFirstPos.Row + xData->mfSplitY <= rMaxApiPos.Row) )
+ nVSplitPos = static_cast< sal_Int32 >( xData->maFirstPos.Row + xData->mfSplitY );
+ nVSplitMode = (nVSplitPos > 0) ? API_SPLITMODE_FREEZE : API_SPLITMODE_NONE;
+ }
+ else if( xData->mnPaneState == XML_split )
+ {
+ // split window: view settings API uses twips...
+ nHSplitPos = getLimitedValue< sal_Int32, double >( xData->mfSplitX + 0.5, 0, SAL_MAX_INT32 );
+ nHSplitMode = (nHSplitPos > 0) ? API_SPLITMODE_SPLIT : API_SPLITMODE_NONE;
+ nVSplitPos = getLimitedValue< sal_Int32, double >( xData->mfSplitY + 0.5, 0, SAL_MAX_INT32 );
+ nVSplitMode = (nVSplitPos > 0) ? API_SPLITMODE_SPLIT : API_SPLITMODE_NONE;
+ }
+
+ // active pane
+ sal_Int16 nActivePane = API_SPLITPANE_BOTTOMLEFT;
+ switch( xData->mnActivePaneId )
+ {
+ // no horizontal split -> always use left panes
+ // no vertical split -> always use *bottom* panes
+ case XML_topLeft:
+ nActivePane = (nVSplitMode == API_SPLITMODE_NONE) ? API_SPLITPANE_BOTTOMLEFT : API_SPLITPANE_TOPLEFT;
+ break;
+ case XML_topRight:
+ nActivePane = (nHSplitMode == API_SPLITMODE_NONE) ?
+ ((nVSplitMode == API_SPLITMODE_NONE) ? API_SPLITPANE_BOTTOMLEFT : API_SPLITPANE_TOPLEFT) :
+ ((nVSplitMode == API_SPLITMODE_NONE) ? API_SPLITPANE_BOTTOMRIGHT : API_SPLITPANE_TOPRIGHT);
+ break;
+ case XML_bottomLeft:
+ nActivePane = API_SPLITPANE_BOTTOMLEFT;
+ break;
+ case XML_bottomRight:
+ nActivePane = (nHSplitMode == API_SPLITMODE_NONE) ? API_SPLITPANE_BOTTOMLEFT : API_SPLITPANE_BOTTOMRIGHT;
+ break;
+ }
+
+ // automatic grid color
+ if( xData->mbDefGridColor )
+ xData->maGridColor.set( XML_auto, 0 );
+
+ // write the sheet view settings into the property sequence
+ PropertySequence aSheetProps( sppcSheetNames, sppcGlobalSheetNames );
+ aSheetProps
+ << bSelected
+ << aCursor.Column
+ << aCursor.Row
+ << nHSplitMode
+ << nVSplitMode
+ << nHSplitPos
+ << nVSplitPos
+ << nActivePane
+ << xData->maFirstPos.Column
+ << xData->maFirstPos.Row
+ << xData->maSecondPos.Column
+ << ((nVSplitPos > 0) ? xData->maSecondPos.Row : xData->maFirstPos.Row)
+ << getStyles().getColor( xData->maGridColor, API_RGB_TRANSPARENT )
+ << API_ZOOMTYPE_PERCENT
+ << static_cast< sal_Int16 >( xData->getNormalZoom() )
+ << static_cast< sal_Int16 >( xData->getPageBreakZoom() )
+ << xData->isPageBreakPreview()
+ << xData->mbShowFormulas
+ << xData->mbShowGrid
+ << xData->mbShowHeadings
+ << xData->mbShowZeros
+ << xData->mbShowOutline;
+
+ // store sheet view settings in global view settings object
+ getViewSettings().setSheetViewSettings( getSheetIndex(), xData, Any( aSheetProps.createPropertySequence() ) );
+}
+
+// private --------------------------------------------------------------------
+
+OoxSheetViewDataRef SheetViewSettings::createSheetViewData()
+{
+ OoxSheetViewDataRef xData( new OoxSheetViewData );
+ maSheetDatas.push_back( xData );
+ return xData;
+}
+
+// ============================================================================
+
+OoxWorkbookViewData::OoxWorkbookViewData() :
+ mnWinX( 0 ),
+ mnWinY( 0 ),
+ mnWinWidth( 0 ),
+ mnWinHeight( 0 ),
+ mnActiveSheet( 0 ),
+ mnFirstVisSheet( 0 ),
+ mnTabBarWidth( OOX_BOOKVIEW_TABBARRATIO_DEF ),
+ mnVisibility( XML_visible ),
+ mbShowTabBar( true ),
+ mbShowHorScroll( true ),
+ mbShowVerScroll( true ),
+ mbMinimized( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ViewSettings::ViewSettings( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void ViewSettings::importWorkbookView( const AttributeList& rAttribs )
+{
+ OoxWorkbookViewData& rData = createWorkbookViewData();
+ rData.mnWinX = rAttribs.getInteger( XML_xWindow, 0 );
+ rData.mnWinY = rAttribs.getInteger( XML_yWindow, 0 );
+ rData.mnWinWidth = rAttribs.getInteger( XML_windowWidth, 0 );
+ rData.mnWinHeight = rAttribs.getInteger( XML_windowHeight, 0 );
+ rData.mnActiveSheet = rAttribs.getInteger( XML_activeTab, 0 );
+ rData.mnFirstVisSheet = rAttribs.getInteger( XML_firstSheet, 0 );
+ rData.mnTabBarWidth = rAttribs.getInteger( XML_tabRatio, 600 );
+ rData.mnVisibility = rAttribs.getToken( XML_visibility, XML_visible );
+ rData.mbShowTabBar = rAttribs.getBool( XML_showSheetTabs, true );
+ rData.mbShowHorScroll = rAttribs.getBool( XML_showHorizontalScroll, true );
+ rData.mbShowVerScroll = rAttribs.getBool( XML_showVerticalScroll, true );
+ rData.mbMinimized = rAttribs.getBool( XML_minimized, false );
+}
+
+void ViewSettings::importWorkbookView( RecordInputStream& rStrm )
+{
+ OoxWorkbookViewData& rData = createWorkbookViewData();
+ sal_uInt8 nFlags;
+ rStrm >> rData.mnWinX >> rData.mnWinY >> rData.mnWinWidth >> rData.mnWinHeight >> rData.mnTabBarWidth >> rData.mnFirstVisSheet >> rData.mnActiveSheet >> nFlags;
+ rData.mnVisibility = getFlagValue( nFlags, OOBIN_WBVIEW_HIDDEN, XML_hidden, XML_visible );
+ rData.mbShowTabBar = getFlag( nFlags, OOBIN_WBVIEW_SHOWTABBAR );
+ rData.mbShowHorScroll = getFlag( nFlags, OOBIN_WBVIEW_SHOWHORSCROLL );
+ rData.mbShowVerScroll = getFlag( nFlags, OOBIN_WBVIEW_SHOWVERSCROLL );
+ rData.mbMinimized = getFlag( nFlags, OOBIN_WBVIEW_MINIMIZED );
+}
+
+void ViewSettings::importWindow1( BiffInputStream& rStrm )
+{
+ sal_uInt16 nWinX, nWinY, nWinWidth, nWinHeight;
+ rStrm >> nWinX >> nWinY >> nWinWidth >> nWinHeight;
+
+ // WINDOW1 record occures in every sheet in BIFF4W
+ OSL_ENSURE( maBookDatas.empty() || ((getBiff() == BIFF4) && isWorkbookFile()),
+ "ViewSettings::importWindow1 - multiple WINDOW1 records" );
+ OoxWorkbookViewData& rData = createWorkbookViewData();
+ rData.mnWinX = nWinX;
+ rData.mnWinY = nWinY;
+ rData.mnWinWidth = nWinWidth;
+ rData.mnWinHeight = nWinHeight;
+
+ if( getBiff() <= BIFF4 )
+ {
+ sal_uInt8 nHidden;
+ rStrm >> nHidden;
+ rData.mnVisibility = (nHidden == 0) ? XML_visible : XML_hidden;
+ }
+ else
+ {
+ sal_uInt16 nFlags, nActiveTab, nFirstVisTab, nSelectCnt, nTabBarWidth;
+ rStrm >> nFlags >> nActiveTab >> nFirstVisTab >> nSelectCnt >> nTabBarWidth;
+
+ rData.mnActiveSheet = nActiveTab;
+ rData.mnFirstVisSheet = nFirstVisTab;
+ rData.mnTabBarWidth = nTabBarWidth;
+ rData.mnVisibility = getFlagValue( nFlags, BIFF_WINDOW1_HIDDEN, XML_hidden, XML_visible );
+ rData.mbMinimized = getFlag( nFlags, BIFF_WINDOW1_MINIMIZED );
+ rData.mbShowHorScroll = getFlag( nFlags, BIFF_WINDOW1_SHOWHORSCROLL );
+ rData.mbShowVerScroll = getFlag( nFlags, BIFF_WINDOW1_SHOWVERSCROLL );
+ rData.mbShowTabBar = getFlag( nFlags, BIFF_WINDOW1_SHOWTABBAR );
+ }
+}
+
+void ViewSettings::setSheetViewSettings( sal_Int32 nSheet, const OoxSheetViewDataRef& rxViewData, const Any& rProperties )
+{
+ maSheetDatas[ nSheet ] = rxViewData;
+ maSheetProps[ nSheet ] = rProperties;
+}
+
+void ViewSettings::finalizeImport()
+{
+ const WorksheetBuffer& rWorksheets = getWorksheets();
+ if( rWorksheets.getInternalSheetCount() <= 0 ) return;
+
+ // force creation of workbook view data to get the Excel defaults
+ const OoxWorkbookViewData& rData = maBookDatas.empty() ? createWorkbookViewData() : *maBookDatas.front();
+
+ // show object mode is part of workbook settings
+ sal_Int16 nShowMode = getWorkbookSettings().getApiShowObjectMode();
+
+ // view settings for all sheets
+ Reference< XNameContainer > xSheetsNC = ContainerHelper::createNameContainer();
+ if( !xSheetsNC.is() ) return;
+ for( SheetPropertiesMap::const_iterator aIt = maSheetProps.begin(), aEnd = maSheetProps.end(); aIt != aEnd; ++aIt )
+ ContainerHelper::insertByName( xSheetsNC, rWorksheets.getFinalSheetName( aIt->first ), aIt->second );
+
+ // use data of active sheet to set sheet properties that are document-global in Calc
+ sal_Int32 nActiveSheet = getActiveSheetIndex();
+ OoxSheetViewDataRef& rxActiveSheetData = maSheetDatas[ nActiveSheet ];
+ OSL_ENSURE( rxActiveSheetData.get(), "ViewSettings::finalizeImport - missing active sheet view settings" );
+ if( !rxActiveSheetData )
+ rxActiveSheetData.reset( new OoxSheetViewData );
+
+ PropertySequence aDocProps( sppcDocNames, sppcGlobalSheetNames );
+ aDocProps
+ << xSheetsNC
+ << rWorksheets.getFinalSheetName( nActiveSheet )
+ << rData.mbShowHorScroll
+ << rData.mbShowVerScroll
+ << rData.mbShowTabBar
+ << double( rData.mnTabBarWidth / 1000.0 )
+ << nShowMode << nShowMode << nShowMode
+ << getStyles().getColor( rxActiveSheetData->maGridColor, API_RGB_TRANSPARENT )
+ << API_ZOOMTYPE_PERCENT
+ << static_cast< sal_Int16 >( rxActiveSheetData->getNormalZoom() )
+ << static_cast< sal_Int16 >( rxActiveSheetData->getPageBreakZoom() )
+ << rxActiveSheetData->isPageBreakPreview()
+ << rxActiveSheetData->mbShowFormulas
+ << rxActiveSheetData->mbShowGrid
+ << rxActiveSheetData->mbShowHeadings
+ << rxActiveSheetData->mbShowZeros
+ << rxActiveSheetData->mbShowOutline;
+
+ Reference< XIndexContainer > xContainer = ContainerHelper::createIndexContainer();
+ if( xContainer.is() ) try
+ {
+ xContainer->insertByIndex( 0, Any( aDocProps.createPropertySequence() ) );
+ Reference< XIndexAccess > xIAccess( xContainer, UNO_QUERY_THROW );
+ Reference< XViewDataSupplier > xViewDataSuppl( getDocument(), UNO_QUERY_THROW );
+ xViewDataSuppl->setViewData( xIAccess );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "ViewSettings::finalizeImport - cannot create document view settings" );
+ }
+}
+
+sal_Int32 ViewSettings::getActiveSheetIndex() const
+{
+ sal_Int32 nSheetCount = getLimitedValue< sal_Int32, sal_Int32 >( getWorksheets().getInternalSheetCount(), 1, SAL_MAX_INT32 );
+ return maBookDatas.empty() ? 0 : getLimitedValue< sal_Int32, sal_Int32 >( maBookDatas.front()->mnActiveSheet, 0, nSheetCount - 1 );
+}
+
+// private --------------------------------------------------------------------
+
+OoxWorkbookViewData& ViewSettings::createWorkbookViewData()
+{
+ OoxWorkbookViewDataRef xData( new OoxWorkbookViewData );
+ maBookDatas.push_back( xData );
+ return *xData;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/webquerybuffer.cxx b/oox/source/xls/webquerybuffer.cxx
new file mode 100644
index 000000000000..c4ce7953dacd
--- /dev/null
+++ b/oox/source/xls/webquerybuffer.cxx
@@ -0,0 +1,207 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: webquerybuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/webquerybuffer.hxx"
+#include "oox/helper/attributelist.hxx"
+
+#define DEBUG_OOX_WEBQUERY_BUFFER 1
+
+#if DEBUG_OOX_WEBQUERY_BUFFER
+#include <stdio.h>
+#endif
+
+using ::rtl::OUString;
+
+namespace oox {
+namespace xls {
+
+const sal_Int32 Connection::CONNECTION_ODBC_SOURCE = 1;
+const sal_Int32 Connection::CONNECTION_DAO_SOURCE = 2;
+const sal_Int32 Connection::CONNECTION_FILE_SOURCE = 3;
+const sal_Int32 Connection::CONNECTION_WEBQUERY = 4;
+const sal_Int32 Connection::CONNECTION_OLEDB_SOURCE = 5;
+const sal_Int32 Connection::CONNECTION_TEXT_SOURCE = 6;
+const sal_Int32 Connection::CONNECTION_ADO_RECORD_SET = 7;
+const sal_Int32 Connection::CONNECTION_DSP = 8;
+
+// ============================================================================
+
+WebQueryBuffer::WebQueryBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+ maQueryTableMap.clear();
+}
+
+void WebQueryBuffer::importQueryTable( const AttributeList& rAttribs )
+{
+ OUString aName = rAttribs.getString( XML_name );
+ if ( !aName.getLength() )
+ return;
+
+ QueryTable aQTable;
+ aQTable.mnConnectionId = rAttribs.getInteger( XML_connectionId, 0 );
+
+ maQueryTableMap.insert( QueryTableHashMap::value_type( aName, aQTable ) );
+
+ // All documented attributes of queryTable:
+ // adjustColumnWidth (bool)
+ // applyAlignmentFormats (bool)
+ // applyBorderFormats (bool)
+ // applyFontFormats (bool)
+ // applyNumberFormats (bool)
+ // applyPatternFormats (bool)
+ // applyWidthHeightFormats (bool)
+ // autoFormatId (unsigned int)
+ // backgroundRefresh (bool)
+ // connectionId (unsigned int)
+ // disableEdit (bool)
+ // disableRefresh (bool)
+ // fillFormulas (bool)
+ // firstBackgroundRefresh (bool)
+ // growShrinkType (insertClear, insertDelete, overwriteClear)
+ // headers (bool)
+ // intermediate (bool)
+ // name (string)
+ // preserveFormatting(bool)
+ // refreshOnLoad (bool)
+ // removeDataOnSave (bool)
+ // rowNumbers (bool)
+}
+
+void WebQueryBuffer::importConnection( const AttributeList& rAttribs )
+{
+ if ( !rAttribs.hasAttribute( XML_id ) || !rAttribs.hasAttribute( XML_name ) )
+ {
+ mnCurConnId = -1;
+ return;
+ }
+
+ sal_uInt32 nId = rAttribs.getUnsignedInteger( XML_id, 0 );
+ if ( maConnections.size() < (nId + 1) )
+ maConnections.resize(nId + 1);
+
+ Connection aConn;
+ aConn.maName = rAttribs.getString( XML_name );
+ aConn.mnType = rAttribs.getInteger( XML_type, 0 );
+ maConnections[nId] = aConn;
+ mnCurConnId = nId;
+
+ // All documented attributes of connection.
+ // background (bool)
+ // credentials (integrated, none, prompt, stored)
+ // deleted (bool)
+ // description (string)
+ // id (unsigned int)
+ // interval (unsigned int)
+ // keepAlive (bool)
+ // minRefreshableVersion (unsigned byte)
+ // name (string)
+ // new (bool)
+ // odcFile (string)
+ // onlyUseConnectionFile (bool)
+ // reconnectionMethod (unsigned int)
+ // refreshedVersion (unsigned byte)
+ // refreshOnLoad (bool)
+ // saveData (bool)
+ // savePassword (bool)
+ // singleSignOnId (string)
+ // sourceFile (string)
+ // type (unsigned int)
+}
+
+void WebQueryBuffer::importWebPr( const AttributeList& rAttribs )
+{
+ if ( 0 > mnCurConnId )
+ return;
+
+ Connection& rConn = maConnections[mnCurConnId];
+ rConn.mpProperties.reset( new WebProperties );
+ WebProperties* pWebPr = static_cast< WebProperties* >( rConn.mpProperties.get() );
+ pWebPr->maURL = rAttribs.getString( XML_url );
+
+ // All available attributes:
+ // consecutive (bool)
+ // editPage (string)
+ // firstRow (bool)
+ // htmlFormat (all, none, rtf)
+ // htmlTables (bool)
+ // parsePre (bool)
+ // post (string)
+ // sourceData (bool)
+ // textDates (bool)
+ // url (string)
+ // xl2000 (bool)
+ // xl97 (bool)
+ // xml (bool)
+}
+
+void WebQueryBuffer::dump() const
+{
+#if DEBUG_OOX_WEBQUERY_BUFFER
+ fprintf(stdout, "----------------------------------------\n");
+ {
+ using ::std::vector;
+ vector< Connection >::const_iterator itr = maConnections.begin(), itrEnd = maConnections.end();
+ sal_Int32 nId = 0;
+ for (; itr != itrEnd; ++itr, ++nId)
+ {
+ if ( itr->mnType == Connection::CONNECTION_WEBQUERY )
+ {
+ WebProperties* pWebPr = static_cast< WebProperties* >( itr->mpProperties.get() );
+ fprintf(stdout, "WebQueryBuffer::dump: id = %d url = %s\n",
+ (int)nId,
+ OUStringToOString(pWebPr->maURL, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ }
+
+ QueryTableHashMap::const_iterator itr = maQueryTableMap.begin(), itrEnd = maQueryTableMap.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ fprintf(stdout, "WebQueryBuffer::dump: name = %s connection ID = %d\n",
+ OUStringToOString(itr->first, RTL_TEXTENCODING_UTF8).getStr(),
+ (int)(itr->second.mnConnectionId));
+ }
+
+ fprintf(stdout, "----------------------------------------\n");
+ fflush(stdout);
+#endif
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/workbookfragment.cxx b/oox/source/xls/workbookfragment.cxx
new file mode 100644
index 000000000000..838711bb1198
--- /dev/null
+++ b/oox/source/xls/workbookfragment.cxx
@@ -0,0 +1,756 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: workbookfragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/workbookfragment.hxx"
+#include <com/sun/star/table/CellAddress.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/progressbar.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/drawingml/themefragmenthandler.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/connectionsfragment.hxx"
+#include "oox/xls/externallinkbuffer.hxx"
+#include "oox/xls/externallinkfragment.hxx"
+#include "oox/xls/pivotcachefragment.hxx"
+#include "oox/xls/sharedstringsbuffer.hxx"
+#include "oox/xls/sharedstringsfragment.hxx"
+#include "oox/xls/stylesfragment.hxx"
+#include "oox/xls/tablebuffer.hxx"
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/viewsettings.hxx"
+#include "oox/xls/workbooksettings.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+#include "oox/xls/worksheetfragment.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::table::CellAddress;
+using ::oox::core::FragmentHandlerRef;
+using ::oox::core::Relation;
+using ::oox::drawingml::ThemeFragmentHandler;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const double PROGRESS_LENGTH_GLOBALS = 0.1; /// 10% of progress bar for globals import.
+
+const sal_uInt16 BIFF_FILEPASS_BIFF2 = 0x0000;
+const sal_uInt16 BIFF_FILEPASS_BIFF8 = 0x0001;
+const sal_uInt16 BIFF_FILEPASS_BIFF8_RCF = 0x0001;
+const sal_uInt16 BIFF_FILEPASS_BIFF8_STRONG = 0x0002;
+
+} // namespace
+
+// ============================================================================
+
+OoxWorkbookFragment::OoxWorkbookFragment(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxWorkbookFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nElement == XLS_TOKEN( workbook ));
+ case XLS_TOKEN( workbook ):
+ return (nElement == XLS_TOKEN( workbookPr )) ||
+ (nElement == XLS_TOKEN( calcPr )) ||
+ (nElement == XLS_TOKEN( sheets )) ||
+ (nElement == XLS_TOKEN( bookViews )) ||
+ (nElement == XLS_TOKEN( externalReferences )) ||
+ (nElement == XLS_TOKEN( definedNames )) ||
+ (nElement == XLS_TOKEN( pivotCaches ));
+ case XLS_TOKEN( sheets ):
+ return (nElement == XLS_TOKEN( sheet ));
+ case XLS_TOKEN( bookViews ):
+ return (nElement == XLS_TOKEN( workbookView ));
+ case XLS_TOKEN( externalReferences ):
+ return (nElement == XLS_TOKEN( externalReference ));
+ case XLS_TOKEN( definedNames ):
+ return (nElement == XLS_TOKEN( definedName ));
+ case XLS_TOKEN( pivotCaches ):
+ return (nElement == XLS_TOKEN( pivotCache ));
+ }
+ return false;
+}
+
+void OoxWorkbookFragment::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( workbookPr ): getWorkbookSettings().importWorkbookPr( rAttribs ); break;
+ case XLS_TOKEN( calcPr ): getWorkbookSettings().importCalcPr( rAttribs ); break;
+ case XLS_TOKEN( sheet ): getWorksheets().importSheet( rAttribs ); break;
+ case XLS_TOKEN( workbookView ): getViewSettings().importWorkbookView( rAttribs ); break;
+ case XLS_TOKEN( externalReference ): importExternalReference( rAttribs ); break;
+ case XLS_TOKEN( definedName ): importDefinedName( rAttribs ); break;
+ case XLS_TOKEN( pivotCache ): importPivotCache( rAttribs ); break;
+ }
+}
+
+void OoxWorkbookFragment::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( definedName ):
+ if( mxCurrName.get() ) mxCurrName->setFormula( rChars );
+ break;
+ }
+}
+
+bool OoxWorkbookFragment::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nRecId == OOBIN_ID_WORKBOOK);
+ case OOBIN_ID_WORKBOOK:
+ return (nRecId == OOBIN_ID_WORKBOOKPR) ||
+ (nRecId == OOBIN_ID_CALCPR) ||
+ (nRecId == OOBIN_ID_SHEETS) ||
+ (nRecId == OOBIN_ID_BOOKVIEWS) ||
+ (nRecId == OOBIN_ID_EXTERNALREFS) ||
+ (nRecId == OOBIN_ID_DEFINEDNAME);
+ case OOBIN_ID_SHEETS:
+ return (nRecId == OOBIN_ID_SHEET);
+ case OOBIN_ID_BOOKVIEWS:
+ return (nRecId == OOBIN_ID_WORKBOOKVIEW);
+ case OOBIN_ID_EXTERNALREFS:
+ return (nRecId == OOBIN_ID_EXTERNALREF) ||
+ (nRecId == OOBIN_ID_EXTERNALSELF) ||
+ (nRecId == OOBIN_ID_EXTERNALSHEETS);
+ }
+ return false;
+}
+
+void OoxWorkbookFragment::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_WORKBOOKPR: getWorkbookSettings().importWorkbookPr( rStrm ); break;
+ case OOBIN_ID_CALCPR: getWorkbookSettings().importCalcPr( rStrm ); break;
+ case OOBIN_ID_SHEET: getWorksheets().importSheet( rStrm ); break;
+ case OOBIN_ID_WORKBOOKVIEW: getViewSettings().importWorkbookView( rStrm ); break;
+ case OOBIN_ID_EXTERNALREF: importExternalRef( rStrm ); break;
+ case OOBIN_ID_EXTERNALSELF: getExternalLinks().importExternalSelf( rStrm ); break;
+ case OOBIN_ID_EXTERNALSHEETS: getExternalLinks().importExternalSheets( rStrm ); break;
+ case OOBIN_ID_DEFINEDNAME: getDefinedNames().importDefinedName( rStrm ); break;
+ }
+}
+
+// oox.xls.OoxFragmentHandler interface ---------------------------------------
+
+void OoxWorkbookFragment::finalizeImport()
+{
+ ISegmentProgressBarRef xGlobalSegment = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
+
+ // read the theme substream
+ OUString aThemeFragmentPath = getFragmentPathFromType( CREATE_RELATIONS_TYPE( "theme" ) );
+ if( aThemeFragmentPath.getLength() > 0 )
+ importOoxFragment( new ThemeFragmentHandler( getFilter(), aThemeFragmentPath, getTheme().getCoreTheme() ) );
+ xGlobalSegment->setPosition( 0.25 );
+
+ // read the styles substream (requires finalized theme buffer)
+ OUString aStylesFragmentPath = getFragmentPathFromType( CREATE_RELATIONS_TYPE( "styles" ) );
+ if( aStylesFragmentPath.getLength() > 0 )
+ importOoxFragment( new OoxStylesFragment( *this, aStylesFragmentPath ) );
+ xGlobalSegment->setPosition( 0.5 );
+
+ // read the shared string table substream (requires finalized styles buffer)
+ OUString aSstFragmentPath = getFragmentPathFromType( CREATE_RELATIONS_TYPE( "sharedStrings" ) );
+ if( aSstFragmentPath.getLength() > 0 )
+ importOoxFragment( new OoxSharedStringsFragment( *this, aSstFragmentPath ) );
+ xGlobalSegment->setPosition( 0.75 );
+
+ // read the connections substream
+ OUString aConnFragmentPath = getFragmentPathFromType( CREATE_RELATIONS_TYPE( "connections" ) );
+ if( aConnFragmentPath.getLength() > 0 )
+ importOoxFragment( new OoxConnectionsFragment( *this, aConnFragmentPath ) );
+ xGlobalSegment->setPosition( 1.0 );
+
+ /* Create fragments for all sheets, before importing them. Needed to do
+ some preprocessing in the fragment constructors, e.g. loading the table
+ fragments for all sheets that are needed before the cell formulas are
+ loaded. */
+ typedef ::std::map< sal_Int32, FragmentHandlerRef > SheetFragmentMap;
+ SheetFragmentMap aSheetFragments;
+ WorksheetBuffer& rWorksheets = getWorksheets();
+ sal_Int32 nSheetCount = rWorksheets.getInternalSheetCount();
+ for( sal_Int32 nSheet = 0; nSheet < nSheetCount; ++nSheet )
+ {
+ if( const Relation* pRelation = getRelations().getRelationFromRelId( rWorksheets.getSheetRelId( nSheet ) ) )
+ {
+ // get fragment path of the sheet
+ OUString aFragmentPath = getFragmentPathFromTarget( pRelation->maTarget );
+ OSL_ENSURE( aFragmentPath.getLength() > 0, "OoxWorkbookFragment::finalizeImport - cannot access sheet fragment" );
+ if( aFragmentPath.getLength() > 0 )
+ {
+ ::rtl::Reference< OoxWorksheetFragmentBase > xFragment;
+ double fSegmentLength = getProgressBar().getFreeLength() / (nSheetCount - nSheet);
+ ISegmentProgressBarRef xSheetSegment = getProgressBar().createSegment( fSegmentLength );
+ // create the fragment according to the sheet type
+ if( pRelation->maType == CREATE_RELATIONS_TYPE( "worksheet" ) )
+ xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_WORKSHEET, nSheet ) );
+ // insert the fragment into the map
+ OSL_ENSURE( xFragment.is(), "OoxWorkbookFragment::finalizeImport - unknown sheet type" );
+ OSL_ENSURE( !xFragment.is() || xFragment->isValidSheet(), "OoxWorkbookFragment::finalizeImport - missing sheet in document" );
+ if( xFragment.is() && xFragment->isValidSheet() )
+ aSheetFragments[ nSheet ].set( xFragment.get() );
+ }
+ }
+ }
+
+ // create all defined names and database ranges
+ getDefinedNames().finalizeImport();
+ getTables().finalizeImport();
+
+ // load all worksheets
+ for( sal_Int32 nSheet = 0; nSheet < nSheetCount; ++nSheet )
+ {
+ SheetFragmentMap::iterator aIt = aSheetFragments.find( nSheet );
+ if( aIt != aSheetFragments.end() )
+ {
+ // import the sheet fragment
+ importOoxFragment( aIt->second );
+ // delete fragment object, will free all allocated sheet buffers
+ aSheetFragments.erase( aIt );
+ }
+ }
+
+ // final conversions, e.g. calculation settings and view settings
+ finalizeWorkbookImport();
+
+ getPivotTables().finalizeImport();
+}
+
+// private --------------------------------------------------------------------
+
+void OoxWorkbookFragment::importExternalReference( const AttributeList& rAttribs )
+{
+ if( ExternalLink* pExtLink = getExternalLinks().importExternalReference( rAttribs ).get() )
+ importExternalLinkFragment( *pExtLink );
+}
+
+void OoxWorkbookFragment::importDefinedName( const AttributeList& rAttribs )
+{
+ mxCurrName = getDefinedNames().importDefinedName( rAttribs );
+}
+
+void OoxWorkbookFragment::importPivotCache( const AttributeList& rAttribs )
+{
+ OUString aFragmentPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ) ) );
+ if( (aFragmentPath.getLength() > 0) && rAttribs.hasAttribute( XML_cacheId ) )
+ {
+ sal_uInt32 nCacheId = rAttribs.getUnsignedInteger( XML_cacheId, 0 );
+ importOoxFragment( new OoxPivotCacheFragment( *this, aFragmentPath, nCacheId ) );
+ }
+}
+
+void OoxWorkbookFragment::importExternalRef( RecordInputStream& rStrm )
+{
+ if( ExternalLink* pExtLink = getExternalLinks().importExternalRef( rStrm ).get() )
+ importExternalLinkFragment( *pExtLink );
+}
+
+void OoxWorkbookFragment::importExternalLinkFragment( ExternalLink& rExtLink )
+{
+ OUString aFragmentPath = getFragmentPathFromRelId( rExtLink.getRelId() );
+ if( aFragmentPath.getLength() > 0 )
+ importOoxFragment( new OoxExternalLinkFragment( *this, aFragmentPath, rExtLink ) );
+}
+
+// ============================================================================
+
+namespace {
+
+BiffDecoderRef lclImportFilePass_XOR( const WorkbookHelper& rHelper, BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+ OSL_ENSURE( rStrm.getRecLeft() == 4, "lclImportFilePass_XOR - wrong record size" );
+ if( rStrm.getRecLeft() == 4 )
+ {
+ sal_uInt16 nBaseKey, nHash;
+ rStrm >> nBaseKey >> nHash;
+ xDecoder.reset( new BiffDecoder_XOR( rHelper, nBaseKey, nHash ) );
+ }
+ return xDecoder;
+}
+
+BiffDecoderRef lclImportFilePass_RCF( const WorkbookHelper& rHelper, BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+ OSL_ENSURE( rStrm.getRecLeft() == 48, "lclImportFilePass_RCF - wrong record size" );
+ if( rStrm.getRecLeft() == 48 )
+ {
+ sal_uInt8 pnDocId[ 16 ];
+ sal_uInt8 pnSaltData[ 16 ];
+ sal_uInt8 pnSaltHash[ 16 ];
+ rStrm.read( pnDocId, 16 );
+ rStrm.read( pnSaltData, 16 );
+ rStrm.read( pnSaltHash, 16 );
+ xDecoder.reset( new BiffDecoder_RCF( rHelper, pnDocId, pnSaltData, pnSaltHash ) );
+ }
+ return xDecoder;
+}
+
+BiffDecoderRef lclImportFilePass_Strong( const WorkbookHelper& /*rHelper*/, BiffInputStream& /*rStrm*/ )
+{
+ // not supported
+ return BiffDecoderRef();
+}
+
+BiffDecoderRef lclImportFilePass2( const WorkbookHelper& rHelper, BiffInputStream& rStrm )
+{
+ return lclImportFilePass_XOR( rHelper, rStrm );
+}
+
+BiffDecoderRef lclImportFilePass8( const WorkbookHelper& rHelper, BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+
+ switch( rStrm.readuInt16() )
+ {
+ case BIFF_FILEPASS_BIFF2:
+ xDecoder = lclImportFilePass_XOR( rHelper, rStrm );
+ break;
+
+ case BIFF_FILEPASS_BIFF8:
+ switch( rStrm.skip( 2 ).readuInt16() )
+ {
+ case BIFF_FILEPASS_BIFF8_RCF:
+ xDecoder = lclImportFilePass_RCF( rHelper, rStrm );
+ break;
+ case BIFF_FILEPASS_BIFF8_STRONG:
+ xDecoder = lclImportFilePass_Strong( rHelper, rStrm );
+ break;
+ default:
+ OSL_ENSURE( false, "lclImportFilePass8 - unknown BIFF8 encryption sub mode" );
+ }
+ break;
+
+ default:
+ OSL_ENSURE( false, "lclImportFilePass8 - unknown encryption mode" );
+ }
+
+ return xDecoder;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+BiffWorkbookFragment::BiffWorkbookFragment( const WorkbookHelper& rHelper ) :
+ BiffWorkbookFragmentBase( rHelper )
+{
+}
+
+bool BiffWorkbookFragment::importFragment( BiffInputStream& rStrm )
+{
+ bool bRet = false;
+
+ BiffFragmentType eFragment = startFragment( rStrm, getBiff() );
+ switch( eFragment )
+ {
+ case BIFF_FRAGMENT_GLOBALS:
+ {
+ // import workbook globals fragment and create sheets in document
+ ISegmentProgressBarRef xGlobalsProgress = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
+ bRet = importGlobalsFragment( rStrm, *xGlobalsProgress );
+ // load sheet fragments (do not return false in bRet on missing/broken sheets)
+ WorksheetBuffer& rWorksheets = getWorksheets();
+ bool bNextSheet = bRet;
+ for( sal_Int32 nSheet = 0, nSheetCount = rWorksheets.getInternalSheetCount(); bNextSheet && (nSheet < nSheetCount); ++nSheet )
+ {
+ // try to start a new sheet fragment
+ double fSegmentLength = getProgressBar().getFreeLength() / (nSheetCount - nSheet);
+ ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength );
+ BiffFragmentType eSheetFragment = startFragment( rStrm, getBiff() );
+ bNextSheet = importSheetFragment( rStrm, *xSheetProgress, eSheetFragment, nSheet );
+ }
+ }
+ break;
+
+ case BIFF_FRAGMENT_WORKSPACE:
+ {
+ bRet = importWorkspaceFragment( rStrm );
+ // sheets are embedded in workspace fragment, nothing to do here
+ }
+ break;
+
+ case BIFF_FRAGMENT_WORKSHEET:
+ case BIFF_FRAGMENT_CHART:
+ case BIFF_FRAGMENT_MACRO:
+ {
+ /* Single sheet without globals
+ - #i62752# possible in all BIFF versions
+ - do not return false in bRet on missing/broken sheets. */
+ getWorksheets().initializeSingleSheet();
+ importSheetFragment( rStrm, getProgressBar(), eFragment, 0 );
+ // success, even if stream is broken
+ bRet = true;
+ }
+ break;
+
+ default:;
+ }
+
+ // final conversions, e.g. calculation settings and view settings
+ finalizeWorkbookImport();
+
+ return bRet;
+}
+
+bool BiffWorkbookFragment::importWorkspaceFragment( BiffInputStream& rStrm )
+{
+ // enable workbook mode, has not been set yet in BIFF4 workspace files
+ setIsWorkbookFile();
+
+ WorksheetBuffer& rWorksheets = getWorksheets();
+ bool bRet = true;
+
+ // import the workspace globals
+ ISegmentProgressBarRef xGlobalsProgress = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
+ bool bLoop = true;
+ while( bRet && bLoop && rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+ {
+ switch( rStrm.getRecId() )
+ {
+ case BIFF_ID_SHEET: rWorksheets.importSheet( rStrm ); break;
+ case BIFF_ID_CODEPAGE: setCodePage( rStrm.readuInt16() ); break;
+ case BIFF_ID_FILEPASS: bRet = importFilePass( rStrm ); break;
+ case BIFF_ID_SHEETHEADER: rStrm.rewindRecord(); bLoop = false; break;
+ }
+ }
+ xGlobalsProgress->setPosition( 1.0 );
+
+ // load sheet fragments (do not return false in bRet on missing/broken sheets)
+ bool bNextSheet = bRet;
+ for( sal_Int32 nSheet = 0, nSheetCount = rWorksheets.getInternalSheetCount(); bNextSheet && (nSheet < nSheetCount); ++nSheet )
+ {
+ // try to start a new sheet fragment (with leading SHEETHEADER record)
+ bNextSheet = rStrm.startNextRecord() && (rStrm.getRecId() == BIFF_ID_SHEETHEADER);
+ if( bNextSheet )
+ {
+ double fSegmentLength = getProgressBar().getFreeLength() / (nSheetCount - nSheet);
+ ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength );
+ /* Read current sheet name (sheet substreams may not be in the
+ same order as SHEET records are). */
+ OUString aSheetName = rStrm.skip( 4 ).readByteString( false, getTextEncoding() );
+ sal_Int32 nCurrSheet = rWorksheets.getFinalSheetIndex( aSheetName );
+ // load the sheet fragment records
+ BiffFragmentType eSheetFragment = startFragment( rStrm, getBiff() );
+ bNextSheet = importSheetFragment( rStrm, *xSheetProgress, eSheetFragment, nCurrSheet );
+ // do not return false in bRet on missing/broken sheets
+ }
+ }
+
+ return bRet;
+}
+
+bool BiffWorkbookFragment::importGlobalsFragment( BiffInputStream& rStrm, ISegmentProgressBar& rProgressBar )
+{
+ WorkbookSettings& rWorkbookSett = getWorkbookSettings();
+ ViewSettings& rViewSett = getViewSettings();
+ SharedStringsBuffer& rSharedStrings = getSharedStrings();
+ StylesBuffer& rStyles = getStyles();
+ WorksheetBuffer& rWorksheets = getWorksheets();
+
+ // collect records that need to be loaded in a second pass
+ typedef ::std::vector< sal_Int64 > RecordHandleVec;
+ RecordHandleVec aExtLinkRecs;
+
+ bool bRet = true;
+ bool bLoop = true;
+ while( bRet && bLoop && rStrm.startNextRecord() )
+ {
+ sal_uInt16 nRecId = rStrm.getRecId();
+ bool bExtLinkRec = false;
+
+ /* #i56376# BIFF5-BIFF8: If an EOF record for globals is missing,
+ simulate it. The issue is about a document where the sheet fragment
+ starts directly after the EXTSST record, without terminating the
+ globals fragment with an EOF record. */
+ if( isBofRecord( nRecId ) || (nRecId == BIFF_ID_EOF) )
+ {
+ bLoop = false;
+ }
+ else switch( nRecId )
+ {
+ // records in all BIFF versions
+ case BIFF_ID_CODEPAGE: setCodePage( rStrm.readuInt16() ); break;
+ case BIFF_ID_DATEMODE: rWorkbookSett.importDateMode( rStrm ); break;
+ case BIFF_ID_FILEPASS: bRet = importFilePass( rStrm ); break;
+ case BIFF_ID_PRECISION: rWorkbookSett.importPrecision( rStrm ); break;
+ case BIFF_ID_WINDOW1: rViewSett.importWindow1( rStrm ); break;
+
+ // BIFF specific records
+ default: switch( getBiff() )
+ {
+ case BIFF2: switch( nRecId )
+ {
+ case BIFF2_ID_DEFINEDNAME: bExtLinkRec = true; break;
+ case BIFF2_ID_EXTERNALNAME: bExtLinkRec = true; break;
+ case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
+ case BIFF2_ID_FONT: rStyles.importFont( rStrm ); break;
+ case BIFF_ID_FONTCOLOR: rStyles.importFontColor( rStrm ); break;
+ case BIFF2_ID_FORMAT: rStyles.importFormat( rStrm ); break;
+ case BIFF2_ID_XF: rStyles.importXf( rStrm ); break;
+ }
+ break;
+
+ case BIFF3: switch( nRecId )
+ {
+ case BIFF_ID_CRN: bExtLinkRec = true; break;
+ case BIFF3_ID_DEFINEDNAME: bExtLinkRec = true; break;
+ case BIFF3_ID_EXTERNALNAME: bExtLinkRec = true; break;
+ case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
+ case BIFF3_ID_FONT: rStyles.importFont( rStrm ); break;
+ case BIFF2_ID_FORMAT: rStyles.importFormat( rStrm ); break;
+ case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( rStrm ); break;
+ case BIFF_ID_PALETTE: rStyles.importPalette( rStrm ); break;
+ case BIFF_ID_STYLE: rStyles.importStyle( rStrm ); break;
+ case BIFF_ID_XCT: bExtLinkRec = true; break;
+ case BIFF3_ID_XF: rStyles.importXf( rStrm ); break;
+ }
+ break;
+
+ case BIFF4: switch( nRecId )
+ {
+ case BIFF_ID_CRN: bExtLinkRec = true; break;
+ case BIFF3_ID_DEFINEDNAME: bExtLinkRec = true; break;
+ case BIFF3_ID_EXTERNALNAME: bExtLinkRec = true; break;
+ case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
+ case BIFF3_ID_FONT: rStyles.importFont( rStrm ); break;
+ case BIFF4_ID_FORMAT: rStyles.importFormat( rStrm ); break;
+ case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( rStrm ); break;
+ case BIFF_ID_PALETTE: rStyles.importPalette( rStrm ); break;
+ case BIFF_ID_STYLE: rStyles.importStyle( rStrm ); break;
+ case BIFF_ID_XCT: bExtLinkRec = true; break;
+ case BIFF4_ID_XF: rStyles.importXf( rStrm ); break;
+ }
+ break;
+
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF_ID_BOOKBOOL: rWorkbookSett.importBookBool( rStrm ); break;
+ case BIFF_ID_CRN: bExtLinkRec = true; break;
+ case BIFF5_ID_DEFINEDNAME: bExtLinkRec = true; break;
+ case BIFF5_ID_EXTERNALNAME: bExtLinkRec = true; break;
+ case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
+ case BIFF5_ID_FONT: rStyles.importFont( rStrm ); break;
+ case BIFF4_ID_FORMAT: rStyles.importFormat( rStrm ); break;
+ case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( rStrm ); break;
+ case BIFF_ID_PALETTE: rStyles.importPalette( rStrm ); break;
+ case BIFF_ID_SHEET: rWorksheets.importSheet( rStrm ); break;
+ case BIFF_ID_STYLE: rStyles.importStyle( rStrm ); break;
+ case BIFF_ID_XCT: bExtLinkRec = true; break;
+ case BIFF5_ID_XF: rStyles.importXf( rStrm ); break;
+ }
+ break;
+
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF_ID_BOOKBOOL: rWorkbookSett.importBookBool( rStrm ); break;
+ case BIFF_ID_CODENAME: rWorkbookSett.importCodeName( rStrm ); break;
+ case BIFF_ID_CRN: bExtLinkRec = true; break;
+ case BIFF5_ID_DEFINEDNAME: bExtLinkRec = true; break;
+ case BIFF_ID_EXTERNALBOOK: bExtLinkRec = true; break;
+ case BIFF5_ID_EXTERNALNAME: bExtLinkRec = true; break;
+ case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
+ case BIFF5_ID_FONT: rStyles.importFont( rStrm ); break;
+ case BIFF4_ID_FORMAT: rStyles.importFormat( rStrm ); break;
+ case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( rStrm ); break;
+ case BIFF_ID_PALETTE: rStyles.importPalette( rStrm ); break;
+ case BIFF_ID_SHEET: rWorksheets.importSheet( rStrm ); break;
+ case BIFF_ID_SST: rSharedStrings.importSst( rStrm ); break;
+ case BIFF_ID_STYLE: rStyles.importStyle( rStrm ); break;
+ case BIFF_ID_USESELFS: rWorkbookSett.importUsesElfs( rStrm ); break;
+ case BIFF_ID_XCT: bExtLinkRec = true; break;
+ case BIFF5_ID_XF: rStyles.importXf( rStrm ); break;
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+ }
+
+ if( bExtLinkRec )
+ aExtLinkRecs.push_back( rStrm.getRecHandle() );
+ }
+
+ // finalize global buffers
+ rProgressBar.setPosition( 0.5 );
+ rSharedStrings.finalizeImport();
+ rStyles.finalizeImport();
+
+ /* Import external link data (EXTERNSHEET, EXTERNALNAME, DEFINEDNAME)
+ which need existing internal sheets (SHEET records). The SHEET records
+ may follow the external links records in some BIFF versions. */
+ if( bRet && !aExtLinkRecs.empty() )
+ {
+ // remember current stream position (the EOF record)
+ sal_Int64 nEofHandle = rStrm.getRecHandle();
+ // this fragment class implements import of external link records
+ BiffExternalLinkFragment aLinkFragment( *this, true );
+ // import all records by using their cached record handle
+ for( RecordHandleVec::const_iterator aIt = aExtLinkRecs.begin(), aEnd = aExtLinkRecs.end(); (aIt != aEnd) && rStrm.startRecordByHandle( *aIt ); ++aIt )
+ aLinkFragment.importRecord( rStrm );
+ // finalize global buffers
+ aLinkFragment.finalizeImport();
+ // seek back to the EOF record of the workbook globals fragment
+ bRet = rStrm.startRecordByHandle( nEofHandle );
+ }
+
+ // #i56376# missing EOF - rewind before worksheet BOF record (see above)
+ if( bRet && isBofRecord( rStrm.getRecId() ) )
+ rStrm.rewindRecord();
+
+ rProgressBar.setPosition( 1.0 );
+ return bRet;
+}
+
+bool BiffWorkbookFragment::importSheetFragment( BiffInputStream& rStrm, ISegmentProgressBar& rProgressBar, BiffFragmentType eFragment, sal_Int32 nSheet )
+{
+ // find the sheet type for this fragment
+ WorksheetType eSheetType = SHEETTYPE_WORKSHEET;
+ bool bSkipSheet = false;
+ switch( eFragment )
+ {
+ case BIFF_FRAGMENT_WORKSHEET: eSheetType = SHEETTYPE_WORKSHEET; break;
+ case BIFF_FRAGMENT_CHART: eSheetType = SHEETTYPE_CHART; break;
+ case BIFF_FRAGMENT_MACRO: eSheetType = SHEETTYPE_MACRO; break;
+ case BIFF_FRAGMENT_EMPTYSHEET: bSkipSheet = true; break;
+ default: return false;
+ }
+
+ // skip this worksheet fragment (e.g. fragment type is BIFF_FRAGMENT_EMPTYSHEET)
+ if( bSkipSheet )
+ {
+ rProgressBar.setPosition( 1.0 );
+ return skipFragment( rStrm );
+ }
+
+ /* #i11183# Clear buffers that are used per-sheet, e.g. external links in
+ BIFF4W and BIFF5 files, or defined names in BIFF4W files. */
+ createBuffersPerSheet();
+
+ // preprocess some records
+ switch( getBiff() )
+ {
+ // load the workbook globals fragment records in BIFF2-BIFF4
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ {
+ // set sheet index in defined names buffer to handle built-in names correctly
+ getDefinedNames().setLocalSheetIndex( nSheet );
+ // remember current record to seek back below
+ sal_Int64 nRecHandle = rStrm.getRecHandle();
+ // import the global records
+ ISegmentProgressBarRef xGlobalsProgress = rProgressBar.createSegment( PROGRESS_LENGTH_GLOBALS );
+ importGlobalsFragment( rStrm, *xGlobalsProgress );
+ // rewind stream to fragment BOF record
+ rStrm.startRecordByHandle( nRecHandle );
+ }
+ break;
+
+ // load the external link records for this sheet in BIFF5
+ case BIFF5:
+ {
+ // remember current record to seek back below
+ sal_Int64 nRecHandle = rStrm.getRecHandle();
+ // fragment implementing import of external link records
+ BiffExternalLinkFragment( *this, false ).importFragment( rStrm );
+ // rewind stream to fragment BOF record
+ rStrm.startRecordByHandle( nRecHandle );
+ }
+ break;
+
+ case BIFF8:
+ break;
+
+ case BIFF_UNKNOWN:
+ break;
+ }
+
+ // create the worksheet fragment
+ ISegmentProgressBarRef xSheetProgress = rProgressBar.createSegment( rProgressBar.getFreeLength() );
+ ::boost::shared_ptr< BiffWorksheetFragmentBase > xFragment;
+ switch( eSheetType )
+ {
+ case SHEETTYPE_WORKSHEET:
+ case SHEETTYPE_MACRO:
+ xFragment.reset( new BiffWorksheetFragment( *this, xSheetProgress, eSheetType, nSheet ) );
+ break;
+ case SHEETTYPE_CHART:
+ xFragment.reset( new BiffWorksheetFragmentBase( *this, xSheetProgress, eSheetType, nSheet ) );
+ break;
+ }
+ // load the sheet fragment records
+ return xFragment->isValidSheet() && xFragment->importFragment( rStrm );
+}
+
+bool BiffWorkbookFragment::importFilePass( BiffInputStream& rStrm )
+{
+ rStrm.enableDecoder( false );
+ BiffDecoderRef xDecoder = (getBiff() == BIFF8) ?
+ lclImportFilePass8( *this, rStrm ) : lclImportFilePass2( *this, rStrm );
+
+ // set decoder at import stream
+ rStrm.setDecoder( xDecoder );
+ //! TODO remember encryption state for export
+// rStrm.GetRoot().GetExtDocOptions().GetDocSettings().mbEncrypted = true;
+
+ return xDecoder.get() && xDecoder->isValid();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/workbookhelper.cxx b/oox/source/xls/workbookhelper.cxx
new file mode 100644
index 000000000000..72c599a75437
--- /dev/null
+++ b/oox/source/xls/workbookhelper.cxx
@@ -0,0 +1,876 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: workbookhelper.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/workbookhelper.hxx"
+#include <osl/thread.h>
+#include <osl/time.h>
+#include <rtl/strbuf.hxx>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/awt/XDevice.hpp>
+#include <com/sun/star/document/XActionLockable.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/sheet/XDatabaseRanges.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include "oox/helper/progressbar.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/core/binaryfilterbase.hxx"
+#include "oox/core/xmlfilterbase.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/defnamesbuffer.hxx"
+#include "oox/xls/externallinkbuffer.hxx"
+#include "oox/xls/formulaparser.hxx"
+#include "oox/xls/pagesettings.hxx"
+#include "oox/xls/pivottablebuffer.hxx"
+#include "oox/xls/sharedstringsbuffer.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/stylespropertyhelper.hxx"
+#include "oox/xls/tablebuffer.hxx"
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+#include "oox/xls/validationpropertyhelper.hxx"
+#include "oox/xls/viewsettings.hxx"
+#include "oox/xls/webquerybuffer.hxx"
+#include "oox/xls/workbooksettings.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNameContainer;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::awt::XDevice;
+using ::com::sun::star::document::XActionLockable;
+using ::com::sun::star::sheet::XSpreadsheetDocument;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::sheet::XNamedRanges;
+using ::com::sun::star::sheet::XDatabaseRanges;
+using ::com::sun::star::style::XStyle;
+using ::com::sun::star::style::XStyleFamiliesSupplier;
+using ::oox::core::BinaryFilterBase;
+using ::oox::core::FilterBase;
+using ::oox::core::FragmentHandler;
+using ::oox::core::XmlFilterBase;
+
+// Set this define to 1 to show the load/save time of a document in an assertion.
+#define OOX_SHOW_LOADSAVE_TIME 0
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+#if OSL_DEBUG_LEVEL > 0
+
+struct WorkbookDataDebug
+{
+#if OOX_SHOW_LOADSAVE_TIME
+ TimeValue maStartTime;
+#endif
+ sal_Int32 mnDebugCount;
+
+ explicit WorkbookDataDebug();
+ ~WorkbookDataDebug();
+};
+
+WorkbookDataDebug::WorkbookDataDebug() :
+ mnDebugCount( 0 )
+{
+#if OOX_SHOW_LOADSAVE_TIME
+ osl_getSystemTime( &maStartTime );
+#endif
+}
+
+WorkbookDataDebug::~WorkbookDataDebug()
+{
+#if OOX_SHOW_LOADSAVE_TIME
+ TimeValue aEndTime;
+ osl_getSystemTime( &aEndTime );
+ sal_Int32 nMillis = (aEndTime.Seconds - maStartTime.Seconds) * 1000 + static_cast< sal_Int32 >( aEndTime.Nanosec - maStartTime.Nanosec ) / 1000000;
+ OSL_ENSURE( false, OStringBuffer( "load/save time = " ).append( nMillis / 1000.0 ).append( " seconds" ).getStr() );
+#endif
+ OSL_ENSURE( mnDebugCount == 0, "WorkbookDataDebug::~WorkbookDataDebug - failed to delete some objects" );
+}
+
+#endif
+
+// ============================================================================
+
+class WorkbookData
+#if OSL_DEBUG_LEVEL > 0
+ : public WorkbookDataDebug
+#endif
+{
+public:
+ explicit WorkbookData( XmlFilterBase& rFilter );
+ explicit WorkbookData( BinaryFilterBase& rFilter, BiffType eBiff );
+ ~WorkbookData();
+
+ /** Returns true, if this helper refers to a valid document. */
+ inline bool isValid() const { return mxDoc.is(); }
+
+ // filter -----------------------------------------------------------------
+
+ /** Returns the base filter object (base class of all filters). */
+ inline FilterBase& getBaseFilter() const { return mrBaseFilter; }
+ /** Returns the filter progress bar. */
+ inline SegmentProgressBar& getProgressBar() const { return *mxProgressBar; }
+ /** Returns the file type of the current filter. */
+ inline FilterType getFilterType() const { return meFilterType; }
+ /** Returns true, if the file is a multi-sheet document, or false if single-sheet. */
+ inline bool isWorkbookFile() const { return mbWorkbook; }
+
+ // document model ---------------------------------------------------------
+
+ /** Returns a reference to the source/target spreadsheet document model. */
+ inline Reference< XSpreadsheetDocument > getDocument() const { return mxDoc; }
+ /** Returns a reference to the specified spreadsheet in the document model. */
+ Reference< XSpreadsheet > getSheet( sal_Int32 nSheet ) const;
+ /** Returns the reference device of the document. */
+ Reference< XDevice > getReferenceDevice() const;
+ /** Returns the container for defined names from the Calc document. */
+ Reference< XNamedRanges > getNamedRanges() const;
+ /** Returns the container for database ranges from the Calc document. */
+ Reference< XDatabaseRanges > getDatabaseRanges() const;
+ /** Returns the container for DDE links from the Calc document. */
+ Reference< XNameAccess > getDdeLinks() const;
+ /** Returns the cell or page styles container from the Calc document. */
+ Reference< XNameContainer > getStyleFamily( bool bPageStyles ) const;
+ /** Returns the specified cell or page style from the Calc document. */
+ Reference< XStyle > getStyleObject( const OUString& rStyleName, bool bPageStyle ) const;
+ /** Creates a com.sun.star.style.Style object and returns its final name. */
+ Reference< XStyle > createStyleObject( OUString& orStyleName, bool bPageStyle, bool bRenameOldExisting );
+
+ // buffers ----------------------------------------------------------------
+
+ /** Returns the global workbook settings object. */
+ inline WorkbookSettings& getWorkbookSettings() const { return *mxWorkbookSettings; }
+ /** Returns the workbook and sheet view settings object. */
+ inline ViewSettings& getViewSettings() const { return *mxViewSettings; }
+ /** Returns the worksheet buffer containing sheet names and properties. */
+ inline WorksheetBuffer& getWorksheets() const { return *mxWorksheets; }
+ /** Returns the office theme object read from the theme substorage. */
+ inline ThemeBuffer& getTheme() const { return *mxTheme; }
+ /** Returns all cell formatting objects read from the styles substream. */
+ inline StylesBuffer& getStyles() const { return *mxStyles; }
+ /** Returns the shared strings read from the shared strings substream. */
+ inline SharedStringsBuffer& getSharedStrings() const { return *mxSharedStrings; }
+ /** Returns the external links read from the external links substream. */
+ inline ExternalLinkBuffer& getExternalLinks() const { return *mxExtLinks; }
+ /** Returns the defined names read from the workbook globals. */
+ inline DefinedNamesBuffer& getDefinedNames() const { return *mxDefNames; }
+ /** Returns the tables collection (equivalent to Calc's database ranges). */
+ inline TableBuffer& getTables() const { return *mxTables; }
+ /** Returns the web queries. */
+ inline WebQueryBuffer& getWebQueries() const { return *mxWebQueries; }
+ /** Returns the pivot tables. */
+ inline PivotTableBuffer& getPivotTables() const { return *mxPivotTables; }
+
+ // converters -------------------------------------------------------------
+
+ /** Returns the import formula parser. */
+ inline FormulaParser& getFormulaParser() const { return *mxFmlaParser; }
+ /** Returns the measurement unit converter. */
+ inline UnitConverter& getUnitConverter() const { return *mxUnitConverter; }
+ /** Returns the converter for string to cell address/range conversion. */
+ inline AddressConverter& getAddressConverter() const { return *mxAddrConverter; }
+ /** Returns the converter for properties related to cell styles. */
+ inline StylesPropertyHelper& getStylesPropertyHelper() const { return *mxStylesPropHlp; }
+ /** Returns the converter for properties related to page/print settings. */
+ inline PageSettingsPropertyHelper& getPageSettingsPropertyHelper() const { return *mxPageSettPropHlp; }
+ /** Returns the converter for properties related to data validation. */
+ inline ValidationPropertyHelper& getValidationPropertyHelper() const { return *mxValidationPropHlp; }
+
+ // OOX specific -----------------------------------------------------------
+
+ /** Returns the base OOX filter object. */
+ inline XmlFilterBase& getOoxFilter() const { return *mpOoxFilter; }
+
+ // BIFF specific ----------------------------------------------------------
+
+ /** Returns the base BIFF filter object. */
+ inline BinaryFilterBase& getBiffFilter() const { return *mpBiffFilter; }
+ /** Returns the BIFF type in binary filter. */
+ inline BiffType getBiff() const { return meBiff; }
+ /** Returns the text encoding used to import/export byte strings. */
+ inline rtl_TextEncoding getTextEncoding() const { return meTextEnc; }
+ /** Sets the text encoding to import/export byte strings. */
+ void setTextEncoding( rtl_TextEncoding eTextEnc );
+ /** Sets code page read from a CODEPAGE record for byte string import. */
+ void setCodePage( sal_uInt16 nCodePage );
+ /** Sets text encoding from the default application font, if CODEPAGE record is missing. */
+ void setAppFontEncoding( rtl_TextEncoding eAppFontEnc );
+ /** Enables workbook file mode, used for BIFF4 workspace files. */
+ void setIsWorkbookFile();
+ /** Recreates global buffers that are used per sheet in specific BIFF versions. */
+ void createBuffersPerSheet();
+ /** Looks for a password provided via API, or queries it via GUI. */
+ OUString queryPassword();
+
+private:
+ /** Initializes some basic members and sets needed document properties. */
+ void initialize();
+ /** Finalizes the filter process (sets some needed document properties). */
+ void finalize();
+
+private:
+ typedef ::std::auto_ptr< SegmentProgressBar > ProgressBarPtr;
+ typedef ::std::auto_ptr< WorkbookSettings > WorkbookSettPtr;
+ typedef ::std::auto_ptr< ViewSettings > ViewSettingsPtr;
+ typedef ::std::auto_ptr< WorksheetBuffer > WorksheetBfrPtr;
+ typedef ::std::auto_ptr< ThemeBuffer > ThemeBfrPtr;
+ typedef ::std::auto_ptr< StylesBuffer > StylesBfrPtr;
+ typedef ::std::auto_ptr< SharedStringsBuffer > SharedStrBfrPtr;
+ typedef ::std::auto_ptr< ExternalLinkBuffer > ExtLinkBfrPtr;
+ typedef ::std::auto_ptr< DefinedNamesBuffer > DefNamesBfrPtr;
+ typedef ::std::auto_ptr< TableBuffer > TableBfrPtr;
+ typedef ::std::auto_ptr< WebQueryBuffer > WebQueryBfrPtr;
+ typedef ::std::auto_ptr< PivotTableBuffer > PivotTableBfrPtr;
+ typedef ::std::auto_ptr< UnitConverter > UnitConvPtr;
+ typedef ::std::auto_ptr< AddressConverter > AddressConvPtr;
+ typedef ::std::auto_ptr< StylesPropertyHelper > StylesPropHlpPtr;
+ typedef ::std::auto_ptr< PageSettingsPropertyHelper > PageSettPropHlpPtr;
+ typedef ::std::auto_ptr< ValidationPropertyHelper > ValidationPropHlpPtr;
+ typedef ::std::auto_ptr< FormulaParser > FormulaParserPtr;
+
+ OUString maRefDeviceProp; /// Property name for reference device.
+ OUString maNamedRangesProp; /// Property name for defined names.
+ OUString maDatabaseRangesProp; /// Property name for database ranges.
+ OUString maDdeLinksProp; /// Property name for DDE links.
+ OUString maCellStylesProp; /// Property name for cell styles.
+ OUString maPageStylesProp; /// Property name for page styles.
+ OUString maCellStyleServ; /// Service name for a cell style.
+ OUString maPageStyleServ; /// Service name for a page style.
+ Reference< XSpreadsheetDocument > mxDoc; /// Document model.
+ FilterBase& mrBaseFilter; /// Base filter object.
+ FilterType meFilterType; /// File type of the filter.
+ ProgressBarPtr mxProgressBar; /// The progress bar.
+ bool mbWorkbook; /// True = multi-sheet file.
+
+ // buffers
+ WorkbookSettPtr mxWorkbookSettings; /// Global workbook settings.
+ ViewSettingsPtr mxViewSettings; /// Workbook and sheet view settings.
+ WorksheetBfrPtr mxWorksheets; /// Sheet info buffer.
+ ThemeBfrPtr mxTheme; /// Formatting theme from theme substream.
+ StylesBfrPtr mxStyles; /// All cell style objects from styles substream.
+ SharedStrBfrPtr mxSharedStrings; /// All strings from shared strings substream.
+ ExtLinkBfrPtr mxExtLinks; /// All external links.
+ DefNamesBfrPtr mxDefNames; /// All defined names.
+ TableBfrPtr mxTables; /// All tables (database ranges).
+ WebQueryBfrPtr mxWebQueries; /// Web queries buffer.
+ PivotTableBfrPtr mxPivotTables; /// Pivot tables buffer.
+
+ // converters/helpers
+ FormulaParserPtr mxFmlaParser; /// Import formula parser.
+ UnitConvPtr mxUnitConverter; /// General unit converter.
+ AddressConvPtr mxAddrConverter; /// Cell address and cell range address converter.
+ StylesPropHlpPtr mxStylesPropHlp; /// Helper for all styles properties.
+ PageSettPropHlpPtr mxPageSettPropHlp; /// Helper for page/print properties.
+ ValidationPropHlpPtr mxValidationPropHlp; /// Helper for data validation properties.
+
+ // OOX specific
+ XmlFilterBase* mpOoxFilter; /// Base OOX filter object.
+
+ // BIFF specific
+ BinaryFilterBase* mpBiffFilter; /// Base BIFF filter object.
+ ::rtl::OUString maPassword; /// Password for stream encoder/decoder.
+ BiffType meBiff; /// BIFF version for BIFF import/export.
+ rtl_TextEncoding meTextEnc; /// BIFF byte string text encoding.
+ bool mbHasCodePage; /// True = CODEPAGE record exists in imported stream.
+ bool mbHasPassword; /// True = password already querried.
+};
+
+// ----------------------------------------------------------------------------
+
+WorkbookData::WorkbookData( XmlFilterBase& rFilter ) :
+ mrBaseFilter( rFilter ),
+ meFilterType( FILTER_OOX ),
+ mpOoxFilter( &rFilter ),
+ meBiff( BIFF_UNKNOWN )
+{
+ initialize();
+}
+
+WorkbookData::WorkbookData( BinaryFilterBase& rFilter, BiffType eBiff ) :
+ mrBaseFilter( rFilter ),
+ meFilterType( FILTER_BIFF ),
+ mpBiffFilter( &rFilter ),
+ meBiff( eBiff )
+{
+ initialize();
+}
+
+WorkbookData::~WorkbookData()
+{
+ finalize();
+}
+
+// document model -------------------------------------------------------------
+
+Reference< XDevice > WorkbookData::getReferenceDevice() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XDevice > xDevice;
+ aPropSet.getProperty( xDevice, maRefDeviceProp );
+ return xDevice;
+}
+
+Reference< XNamedRanges > WorkbookData::getNamedRanges() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XNamedRanges > xNamedRanges;
+ aPropSet.getProperty( xNamedRanges, maNamedRangesProp );
+ return xNamedRanges;
+}
+
+Reference< XDatabaseRanges > WorkbookData::getDatabaseRanges() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XDatabaseRanges > xDatabaseRanges;
+ aPropSet.getProperty( xDatabaseRanges, maDatabaseRangesProp );
+ return xDatabaseRanges;
+}
+
+Reference< XNameAccess > WorkbookData::getDdeLinks() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XNameAccess > xDdeLinks;
+ aPropSet.getProperty( xDdeLinks, maDdeLinksProp );
+ return xDdeLinks;
+}
+
+Reference< XNameContainer > WorkbookData::getStyleFamily( bool bPageStyles ) const
+{
+ Reference< XNameContainer > xStylesNC;
+ try
+ {
+ Reference< XStyleFamiliesSupplier > xFamiliesSup( mxDoc, UNO_QUERY_THROW );
+ Reference< XNameAccess > xFamiliesNA( xFamiliesSup->getStyleFamilies(), UNO_QUERY_THROW );
+ xStylesNC.set( xFamiliesNA->getByName( bPageStyles ? maPageStylesProp : maCellStylesProp ), UNO_QUERY_THROW );
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( xStylesNC.is(), "WorkbookData::getStyleFamily - cannot access style family" );
+ return xStylesNC;
+}
+
+Reference< XStyle > WorkbookData::getStyleObject( const OUString& rStyleName, bool bPageStyle ) const
+{
+ Reference< XStyle > xStyle;
+ Reference< XNameContainer > xStylesNC = getStyleFamily( bPageStyle );
+ if( xStylesNC.is() ) try
+ {
+ xStyle.set( xStylesNC->getByName( rStyleName ), UNO_QUERY_THROW );
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( xStyle.is(), "WorkbookData::getStyleObject - cannot access style object" );
+ return xStyle;
+}
+
+Reference< XStyle > WorkbookData::createStyleObject( OUString& orStyleName, bool bPageStyle, bool bRenameOldExisting )
+{
+ Reference< XStyle > xStyle;
+ Reference< XNameContainer > xStylesNC = getStyleFamily( bPageStyle );
+ if( xStylesNC.is() ) try
+ {
+ Reference< XMultiServiceFactory > xFactory( mxDoc, UNO_QUERY_THROW );
+ xStyle.set( xFactory->createInstance( bPageStyle ? maPageStyleServ : maCellStyleServ ), UNO_QUERY_THROW );
+ orStyleName = ContainerHelper::insertByUnusedName( xStylesNC, Any( xStyle ), orStyleName, ' ', bRenameOldExisting );
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( xStyle.is(), "WorkbookData::createStyleObject - cannot create style" );
+ return xStyle;
+}
+
+// BIFF specific --------------------------------------------------------------
+
+void WorkbookData::setTextEncoding( rtl_TextEncoding eTextEnc )
+{
+ if( eTextEnc != RTL_TEXTENCODING_DONTKNOW )
+ meTextEnc = eTextEnc;
+}
+
+void WorkbookData::setCodePage( sal_uInt16 nCodePage )
+{
+ setTextEncoding( BiffHelper::calcTextEncodingFromCodePage( nCodePage ) );
+ mbHasCodePage = true;
+}
+
+void WorkbookData::setAppFontEncoding( rtl_TextEncoding eAppFontEnc )
+{
+ if( !mbHasCodePage )
+ setTextEncoding( eAppFontEnc );
+}
+
+void WorkbookData::setIsWorkbookFile()
+{
+ OSL_ENSURE( meBiff == BIFF4, "WorkbookData::setIsWorkbookFile - invalid call" );
+ mbWorkbook = true;
+}
+
+void WorkbookData::createBuffersPerSheet()
+{
+ switch( meBiff )
+ {
+ case BIFF2:
+ case BIFF3:
+ break;
+
+ case BIFF4:
+ // #i11183# sheets in BIFF4W files have own styles or names
+ if( mbWorkbook )
+ {
+ mxStyles.reset( new StylesBuffer( WorkbookHelper( *this ) ) );
+ mxDefNames.reset( new DefinedNamesBuffer( WorkbookHelper( *this ) ) );
+ mxExtLinks.reset( new ExternalLinkBuffer( WorkbookHelper( *this ) ) );
+ }
+ break;
+
+ case BIFF5:
+ // BIFF5 stores external references per sheet
+ mxExtLinks.reset( new ExternalLinkBuffer( WorkbookHelper( *this ) ) );
+ break;
+
+ case BIFF8:
+ break;
+
+ case BIFF_UNKNOWN:
+ break;
+ }
+}
+
+OUString WorkbookData::queryPassword()
+{
+ if( !mbHasPassword )
+ {
+ //! TODO
+ maPassword = OUString();
+ // set to true, even if dialog has been cancelled (never ask twice)
+ mbHasPassword = true;
+ }
+ return maPassword;
+}
+
+// private --------------------------------------------------------------------
+
+void WorkbookData::initialize()
+{
+ maRefDeviceProp = CREATE_OUSTRING( "ReferenceDevice" );
+ maNamedRangesProp = CREATE_OUSTRING( "NamedRanges" );
+ maDatabaseRangesProp = CREATE_OUSTRING( "DatabaseRanges" );
+ maDdeLinksProp = CREATE_OUSTRING( "DDELinks" );
+ maCellStylesProp = CREATE_OUSTRING( "CellStyles" );
+ maPageStylesProp = CREATE_OUSTRING( "PageStyles" );
+ maCellStyleServ = CREATE_OUSTRING( "com.sun.star.style.CellStyle" );
+ maPageStyleServ = CREATE_OUSTRING( "com.sun.star.style.PageStyle" );
+ mbWorkbook = false;
+ meTextEnc = osl_getThreadTextEncoding();
+ mbHasCodePage = false;
+ mbHasPassword = false;
+
+ // the spreadsheet document
+ mxDoc.set( mrBaseFilter.getModel(), UNO_QUERY );
+ OSL_ENSURE( mxDoc.is(), "WorkbookData::initialize - no spreadsheet document" );
+
+ mxWorkbookSettings.reset( new WorkbookSettings( WorkbookHelper( *this ) ) );
+ mxViewSettings.reset( new ViewSettings( WorkbookHelper( *this ) ) );
+ mxWorksheets.reset( new WorksheetBuffer( WorkbookHelper( *this ) ) );
+ mxTheme.reset( new ThemeBuffer( WorkbookHelper( *this ) ) );
+ mxStyles.reset( new StylesBuffer( WorkbookHelper( *this ) ) );
+ mxSharedStrings.reset( new SharedStringsBuffer( WorkbookHelper( *this ) ) );
+ mxExtLinks.reset( new ExternalLinkBuffer( WorkbookHelper( *this ) ) );
+ mxDefNames.reset( new DefinedNamesBuffer( WorkbookHelper( *this ) ) );
+ mxTables.reset( new TableBuffer( WorkbookHelper( *this ) ) );
+ mxWebQueries.reset( new WebQueryBuffer( WorkbookHelper( *this ) ) );
+ mxPivotTables.reset( new PivotTableBuffer( WorkbookHelper( *this ) ) );
+
+ mxUnitConverter.reset( new UnitConverter( WorkbookHelper( *this ) ) );
+ mxAddrConverter.reset( new AddressConverter( WorkbookHelper( *this ) ) );
+ mxStylesPropHlp.reset( new StylesPropertyHelper( WorkbookHelper( *this ) ) );
+ mxPageSettPropHlp.reset( new PageSettingsPropertyHelper( WorkbookHelper( *this ) ) );
+ mxValidationPropHlp.reset( new ValidationPropertyHelper( WorkbookHelper( *this ) ) );
+
+ // set some document properties needed during import
+ if( mrBaseFilter.isImportFilter() )
+ {
+ PropertySet aPropSet( mxDoc );
+ // enable editing read-only documents (e.g. from read-only files)
+ aPropSet.setProperty( CREATE_OUSTRING( "IsChangeReadOnlyEnabled" ), true );
+ // #i76026# disable Undo while loading the document
+ aPropSet.setProperty( CREATE_OUSTRING( "IsUndoEnabled" ), false );
+ // #i79826# disable calculating automatic row height while loading the document
+ aPropSet.setProperty( CREATE_OUSTRING( "IsAdjustHeightEnabled" ), false );
+ // disable automatic update of linked sheets and DDE links
+ aPropSet.setProperty( CREATE_OUSTRING( "IsExecuteLinkEnabled" ), false );
+ // #i79890# disable automatic update of defined names
+ Reference< XActionLockable > xLockable( getNamedRanges(), UNO_QUERY );
+ if( xLockable.is() )
+ xLockable->addActionLock();
+
+ //! TODO: localize progress bar text
+ mxProgressBar.reset( new SegmentProgressBar( mrBaseFilter.getStatusIndicator(), CREATE_OUSTRING( "Loading..." ) ) );
+ mxFmlaParser.reset( new FormulaParser( WorkbookHelper( *this ) ) );
+ }
+ else if( mrBaseFilter.isExportFilter() )
+ {
+ //! TODO: localize progress bar text
+ mxProgressBar.reset( new SegmentProgressBar( mrBaseFilter.getStatusIndicator(), CREATE_OUSTRING( "Saving..." ) ) );
+ }
+}
+
+void WorkbookData::finalize()
+{
+ // set some document properties needed after import
+ if( mrBaseFilter.isImportFilter() )
+ {
+ PropertySet aPropSet( mxDoc );
+ // #i74668# do not insert default sheets
+ aPropSet.setProperty( CREATE_OUSTRING( "IsLoaded" ), true );
+ // #i79890# enable automatic update of defined names (before IsAdjustHeightEnabled!)
+ Reference< XActionLockable > xLockable( getNamedRanges(), UNO_QUERY );
+ if( xLockable.is() )
+ xLockable->removeActionLock();
+ // enable automatic update of linked sheets and DDE links
+ aPropSet.setProperty( CREATE_OUSTRING( "IsExecuteLinkEnabled" ), true );
+ // #i79826# enable updating automatic row height after loading the document
+ aPropSet.setProperty( CREATE_OUSTRING( "IsAdjustHeightEnabled" ), true );
+ // #i76026# enable Undo after loading the document
+ aPropSet.setProperty( CREATE_OUSTRING( "IsUndoEnabled" ), true );
+ // disable editing read-only documents (e.g. from read-only files)
+ aPropSet.setProperty( CREATE_OUSTRING( "IsChangeReadOnlyEnabled" ), false );
+ }
+}
+
+// ============================================================================
+
+WorkbookHelper::WorkbookHelper( WorkbookData& rBookData ) :
+#if OSL_DEBUG_LEVEL > 0
+ WorkbookHelperDebug( rBookData.mnDebugCount ),
+#endif
+ mrBookData( rBookData )
+{
+}
+
+WorkbookHelper::~WorkbookHelper()
+{
+}
+
+// filter ---------------------------------------------------------------------
+
+FilterBase& WorkbookHelper::getBaseFilter() const
+{
+ return mrBookData.getBaseFilter();
+}
+
+FilterType WorkbookHelper::getFilterType() const
+{
+ return mrBookData.getFilterType();
+}
+
+SegmentProgressBar& WorkbookHelper::getProgressBar() const
+{
+ return mrBookData.getProgressBar();
+}
+
+bool WorkbookHelper::isWorkbookFile() const
+{
+ return mrBookData.isWorkbookFile();
+}
+
+void WorkbookHelper::finalizeWorkbookImport()
+{
+ // workbook settings, document and sheet view settings
+ mrBookData.getWorkbookSettings().finalizeImport();
+ mrBookData.getViewSettings().finalizeImport();
+}
+
+// document model -------------------------------------------------------------
+
+Reference< XSpreadsheetDocument > WorkbookHelper::getDocument() const
+{
+ return mrBookData.getDocument();
+}
+
+Reference< XSpreadsheet > WorkbookHelper::getSheet( sal_Int32 nSheet ) const
+{
+ Reference< XSpreadsheet > xSheet;
+ try
+ {
+ Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
+ xSheet.set( xSheetsIA->getByIndex( nSheet ), UNO_QUERY_THROW );
+ }
+ catch( Exception& )
+ {
+ }
+ return xSheet;
+}
+
+Reference< XDevice > WorkbookHelper::getReferenceDevice() const
+{
+ return mrBookData.getReferenceDevice();
+}
+
+Reference< XNamedRanges > WorkbookHelper::getNamedRanges() const
+{
+ return mrBookData.getNamedRanges();
+}
+
+Reference< XDatabaseRanges > WorkbookHelper::getDatabaseRanges() const
+{
+ return mrBookData.getDatabaseRanges();
+}
+
+Reference< XNameAccess > WorkbookHelper::getDdeLinks() const
+{
+ return mrBookData.getDdeLinks();
+}
+
+Reference< XNameContainer > WorkbookHelper::getStyleFamily( bool bPageStyles ) const
+{
+ return mrBookData.getStyleFamily( bPageStyles );
+}
+
+Reference< XStyle > WorkbookHelper::getStyleObject( const OUString& rStyleName, bool bPageStyle ) const
+{
+ return mrBookData.getStyleObject( rStyleName, bPageStyle );
+}
+
+Reference< XStyle > WorkbookHelper::createStyleObject( OUString& orStyleName, bool bPageStyle, bool bRenameOldExisting )
+{
+ return mrBookData.createStyleObject( orStyleName, bPageStyle, bRenameOldExisting );
+}
+
+// buffers --------------------------------------------------------------------
+
+WorkbookSettings& WorkbookHelper::getWorkbookSettings() const
+{
+ return mrBookData.getWorkbookSettings();
+}
+
+ViewSettings& WorkbookHelper::getViewSettings() const
+{
+ return mrBookData.getViewSettings();
+}
+
+WorksheetBuffer& WorkbookHelper::getWorksheets() const
+{
+ return mrBookData.getWorksheets();
+}
+
+ThemeBuffer& WorkbookHelper::getTheme() const
+{
+ return mrBookData.getTheme();
+}
+
+StylesBuffer& WorkbookHelper::getStyles() const
+{
+ return mrBookData.getStyles();
+}
+
+SharedStringsBuffer& WorkbookHelper::getSharedStrings() const
+{
+ return mrBookData.getSharedStrings();
+}
+
+ExternalLinkBuffer& WorkbookHelper::getExternalLinks() const
+{
+ return mrBookData.getExternalLinks();
+}
+
+DefinedNamesBuffer& WorkbookHelper::getDefinedNames() const
+{
+ return mrBookData.getDefinedNames();
+}
+
+TableBuffer& WorkbookHelper::getTables() const
+{
+ return mrBookData.getTables();
+}
+
+WebQueryBuffer& WorkbookHelper::getWebQueries() const
+{
+ return mrBookData.getWebQueries();
+}
+
+PivotTableBuffer& WorkbookHelper::getPivotTables() const
+{
+ return mrBookData.getPivotTables();
+}
+
+// converters -----------------------------------------------------------------
+
+FormulaParser& WorkbookHelper::getFormulaParser() const
+{
+ return mrBookData.getFormulaParser();
+}
+
+UnitConverter& WorkbookHelper::getUnitConverter() const
+{
+ return mrBookData.getUnitConverter();
+}
+
+AddressConverter& WorkbookHelper::getAddressConverter() const
+{
+ return mrBookData.getAddressConverter();
+}
+
+StylesPropertyHelper& WorkbookHelper::getStylesPropertyHelper() const
+{
+ return mrBookData.getStylesPropertyHelper();
+}
+
+PageSettingsPropertyHelper& WorkbookHelper::getPageSettingsPropertyHelper() const
+{
+ return mrBookData.getPageSettingsPropertyHelper();
+}
+
+ValidationPropertyHelper& WorkbookHelper::getValidationPropertyHelper() const
+{
+ return mrBookData.getValidationPropertyHelper();
+}
+
+// OOX specific ---------------------------------------------------------------
+
+XmlFilterBase& WorkbookHelper::getOoxFilter() const
+{
+ OSL_ENSURE( mrBookData.getFilterType() == FILTER_OOX, "WorkbookHelper::getOoxFilter - invalid call" );
+ return mrBookData.getOoxFilter();
+}
+
+bool WorkbookHelper::importOoxFragment( const ::rtl::Reference< FragmentHandler >& rxHandler )
+{
+ return getOoxFilter().importFragment( rxHandler );
+}
+
+// BIFF specific --------------------------------------------------------------
+
+BinaryFilterBase& WorkbookHelper::getBiffFilter() const
+{
+ OSL_ENSURE( mrBookData.getFilterType() == FILTER_BIFF, "WorkbookHelper::getBiffFilter - invalid call" );
+ return mrBookData.getBiffFilter();
+}
+
+BiffType WorkbookHelper::getBiff() const
+{
+ return mrBookData.getBiff();
+}
+
+rtl_TextEncoding WorkbookHelper::getTextEncoding() const
+{
+ return mrBookData.getTextEncoding();
+}
+
+void WorkbookHelper::setTextEncoding( rtl_TextEncoding eTextEnc )
+{
+ mrBookData.setTextEncoding( eTextEnc );
+}
+
+void WorkbookHelper::setCodePage( sal_uInt16 nCodePage )
+{
+ mrBookData.setCodePage( nCodePage );
+}
+
+void WorkbookHelper::setAppFontEncoding( rtl_TextEncoding eAppFontEnc )
+{
+ mrBookData.setAppFontEncoding( eAppFontEnc );
+}
+
+void WorkbookHelper::setIsWorkbookFile()
+{
+ mrBookData.setIsWorkbookFile();
+}
+
+void WorkbookHelper::createBuffersPerSheet()
+{
+ mrBookData.createBuffersPerSheet();
+}
+
+OUString WorkbookHelper::queryPassword() const
+{
+ return mrBookData.queryPassword();
+}
+
+// ============================================================================
+
+namespace prv {
+
+WorkbookDataOwner::WorkbookDataOwner( WorkbookDataRef xBookData ) :
+ mxBookData( xBookData )
+{
+}
+
+WorkbookDataOwner::~WorkbookDataOwner()
+{
+}
+
+} // namespace prv
+
+// ----------------------------------------------------------------------------
+
+WorkbookHelperRoot::WorkbookHelperRoot( ::oox::core::XmlFilterBase& rFilter ) :
+ prv::WorkbookDataOwner( prv::WorkbookDataRef( new WorkbookData( rFilter ) ) ),
+ WorkbookHelper( *mxBookData )
+{
+}
+
+WorkbookHelperRoot::WorkbookHelperRoot( ::oox::core::BinaryFilterBase& rFilter, BiffType eBiff ) :
+ prv::WorkbookDataOwner( prv::WorkbookDataRef( new WorkbookData( rFilter, eBiff ) ) ),
+ WorkbookHelper( *mxBookData )
+{
+}
+
+bool WorkbookHelperRoot::isValid() const
+{
+ return mxBookData->isValid();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/workbooksettings.cxx b/oox/source/xls/workbooksettings.cxx
new file mode 100644
index 000000000000..bb758dbb9511
--- /dev/null
+++ b/oox/source/xls/workbooksettings.cxx
@@ -0,0 +1,297 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: workbooksettings.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/workbooksettings.hxx"
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/sheet/XCalculatable.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::util::Date;
+using ::com::sun::star::util::XNumberFormatsSupplier;
+using ::com::sun::star::sheet::XCalculatable;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt32 OOBIN_WORKBOOKPR_DATE1904 = 0x00000001;
+const sal_uInt32 OOBIN_WORKBOOKPR_STRIPEXT = 0x00000080;
+
+const sal_uInt16 OOBIN_CALCPR_A1 = 0x0002;
+const sal_uInt16 OOBIN_CALCPR_ITERATE = 0x0004;
+const sal_uInt16 OOBIN_CALCPR_FULLPRECISION = 0x0008;
+const sal_uInt16 OOBIN_CALCPR_CALCCOMPLETED = 0x0010;
+const sal_uInt16 OOBIN_CALCPR_CALCONSAVE = 0x0020;
+const sal_uInt16 OOBIN_CALCPR_CONCURRENT = 0x0040;
+const sal_uInt16 OOBIN_CALCPR_MANUALPROC = 0x0080;
+
+// no predefined constants for show objects mode
+const sal_Int16 API_SHOWMODE_SHOW = 0; /// Show drawing objects.
+const sal_Int16 API_SHOWMODE_HIDE = 1; /// Hide drawing objects.
+const sal_Int16 API_SHOWMODE_PLACEHOLDER = 2; /// Show placeholders for drawing objects.
+
+} // namespace
+
+// ============================================================================
+
+OoxWorkbookPrData::OoxWorkbookPrData() :
+ mnShowObjectMode( XML_all ),
+ mnUpdateLinksMode( XML_userSet ),
+ mnDefaultThemeVer( -1 ),
+ mbDateMode1904( false ),
+ mbSaveExtLinkValues( true )
+{
+}
+
+void OoxWorkbookPrData::setBinObjectMode( sal_uInt16 nObjMode )
+{
+ static const sal_Int32 spnObjModes[] = { XML_all, XML_placeholders, XML_none };
+ mnShowObjectMode = STATIC_ARRAY_SELECT( spnObjModes, nObjMode, XML_all );
+}
+
+// ============================================================================
+
+OoxCalcPrData::OoxCalcPrData() :
+ mfIterateDelta( 0.001 ),
+ mnCalcId( -1 ),
+ mnRefMode( XML_A1 ),
+ mnCalcMode( XML_auto ),
+ mnIterateCount( 100 ),
+ mnProcCount( -1 ),
+ mbCalcOnSave( true ),
+ mbCalcCompleted( true ),
+ mbFullPrecision( true ),
+ mbIterate( false ),
+ mbConcurrent( true ),
+ mbUseNlr( false )
+{
+}
+
+// ============================================================================
+
+WorkbookSettings::WorkbookSettings( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void WorkbookSettings::importWorkbookPr( const AttributeList& rAttribs )
+{
+ maOoxBookData.maCodeName = rAttribs.getString( XML_codePage );
+ maOoxBookData.mnShowObjectMode = rAttribs.getToken( XML_showObjects, XML_all );
+ maOoxBookData.mnUpdateLinksMode = rAttribs.getToken( XML_updateLinks, XML_userSet );
+ maOoxBookData.mnDefaultThemeVer = rAttribs.getInteger( XML_defaultThemeVersion, -1 );
+ maOoxBookData.mbDateMode1904 = rAttribs.getBool( XML_date1904, false );
+ maOoxBookData.mbSaveExtLinkValues = rAttribs.getBool( XML_saveExternalLinkValues, true );
+}
+
+void WorkbookSettings::importCalcPr( const AttributeList& rAttribs )
+{
+ maOoxCalcData.mfIterateDelta = rAttribs.getDouble( XML_iterateDelta, 0.0001 );
+ maOoxCalcData.mnCalcId = rAttribs.getInteger( XML_calcId, -1 );
+ maOoxCalcData.mnRefMode = rAttribs.getToken( XML_refMode, XML_A1 );
+ maOoxCalcData.mnCalcMode = rAttribs.getToken( XML_calcMode, XML_auto );
+ maOoxCalcData.mnIterateCount = rAttribs.getInteger( XML_iterateCount, 100 );
+ maOoxCalcData.mnProcCount = rAttribs.getInteger( XML_concurrentManualCount, -1 );
+ maOoxCalcData.mbCalcOnSave = rAttribs.getBool( XML_calcOnSave, true );
+ maOoxCalcData.mbCalcCompleted = rAttribs.getBool( XML_calcCompleted, true );
+ maOoxCalcData.mbFullPrecision = rAttribs.getBool( XML_fullPrecision, true );
+ maOoxCalcData.mbIterate = rAttribs.getBool( XML_iterate, false );
+ maOoxCalcData.mbConcurrent = rAttribs.getBool( XML_concurrentCalc, true );
+}
+
+void WorkbookSettings::importWorkbookPr( RecordInputStream& rStrm )
+{
+ sal_uInt32 nFlags;
+ rStrm >> nFlags >> maOoxBookData.mnDefaultThemeVer >> maOoxBookData.maCodeName;
+ maOoxBookData.setBinObjectMode( extractValue< sal_uInt16 >( nFlags, 13, 2 ) );
+ maOoxBookData.mbDateMode1904 = getFlag( nFlags, OOBIN_WORKBOOKPR_DATE1904 );
+ // set flag means: strip external link values
+ maOoxBookData.mbSaveExtLinkValues = !getFlag( nFlags, OOBIN_WORKBOOKPR_STRIPEXT );
+}
+
+void WorkbookSettings::importCalcPr( RecordInputStream& rStrm )
+{
+ sal_Int32 nCalcMode, nProcCount;
+ sal_uInt16 nFlags;
+ rStrm >> maOoxCalcData.mnCalcId >> nCalcMode >> maOoxCalcData.mnIterateCount >> maOoxCalcData.mfIterateDelta >> nProcCount >> nFlags;
+
+ static const sal_Int32 spnCalcModes[] = { XML_manual, XML_auto, XML_autoNoTable };
+ maOoxCalcData.mnRefMode = getFlagValue( nFlags, OOBIN_CALCPR_A1, XML_A1, XML_R1C1 );
+ maOoxCalcData.mnCalcMode = STATIC_ARRAY_SELECT( spnCalcModes, nCalcMode, XML_auto );
+ maOoxCalcData.mnProcCount = getFlagValue< sal_Int32 >( nFlags, OOBIN_CALCPR_MANUALPROC, nProcCount, -1 );
+ maOoxCalcData.mbCalcOnSave = getFlag( nFlags, OOBIN_CALCPR_CALCONSAVE );
+ maOoxCalcData.mbCalcCompleted = getFlag( nFlags, OOBIN_CALCPR_CALCCOMPLETED );
+ maOoxCalcData.mbFullPrecision = getFlag( nFlags, OOBIN_CALCPR_FULLPRECISION );
+ maOoxCalcData.mbIterate = getFlag( nFlags, OOBIN_CALCPR_ITERATE );
+ maOoxCalcData.mbConcurrent = getFlag( nFlags, OOBIN_CALCPR_CONCURRENT );
+}
+
+void WorkbookSettings::setSaveExtLinkValues( bool bSaveExtLinks )
+{
+ maOoxBookData.mbSaveExtLinkValues = bSaveExtLinks;
+}
+
+void WorkbookSettings::importBookBool( BiffInputStream& rStrm )
+{
+ // value of 0 means save external values, value of 1 means strip external values
+ maOoxBookData.mbSaveExtLinkValues = rStrm.readuInt16() == 0;
+}
+
+void WorkbookSettings::importCalcCount( BiffInputStream& rStrm )
+{
+ maOoxCalcData.mnIterateCount = rStrm.readuInt16();
+}
+
+void WorkbookSettings::importCalcMode( BiffInputStream& rStrm )
+{
+ sal_Int16 nCalcMode = rStrm.readInt16() + 1;
+ static const sal_Int32 spnCalcModes[] = { XML_autoNoTable, XML_manual, XML_auto };
+ maOoxCalcData.mnCalcMode = STATIC_ARRAY_SELECT( spnCalcModes, nCalcMode, XML_auto );
+}
+
+void WorkbookSettings::importCodeName( BiffInputStream& rStrm )
+{
+ maOoxBookData.maCodeName = rStrm.readUniString();
+}
+
+void WorkbookSettings::importDateMode( BiffInputStream& rStrm )
+{
+ maOoxBookData.mbDateMode1904 = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::importDelta( BiffInputStream& rStrm )
+{
+ rStrm >> maOoxCalcData.mfIterateDelta;
+}
+
+void WorkbookSettings::importHideObj( BiffInputStream& rStrm )
+{
+ maOoxBookData.setBinObjectMode( rStrm.readuInt16() );
+}
+
+void WorkbookSettings::importIteration( BiffInputStream& rStrm )
+{
+ maOoxCalcData.mbIterate = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::importPrecision( BiffInputStream& rStrm )
+{
+ maOoxCalcData.mbFullPrecision = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::importRefMode( BiffInputStream& rStrm )
+{
+ maOoxCalcData.mnRefMode = (rStrm.readuInt16() == 0) ? XML_R1C1 : XML_A1;
+}
+
+void WorkbookSettings::importSaveRecalc( BiffInputStream& rStrm )
+{
+ maOoxCalcData.mbCalcOnSave = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::importUncalced( BiffInputStream& )
+{
+ // existence of this record indicates incomplete recalc
+ maOoxCalcData.mbCalcCompleted = false;
+}
+
+void WorkbookSettings::importUsesElfs( BiffInputStream& rStrm )
+{
+ maOoxCalcData.mbUseNlr = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::finalizeImport()
+{
+ // default settings
+ PropertySet aPropSet( getDocument() );
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ case FILTER_BIFF:
+ aPropSet.setProperty( CREATE_OUSTRING( "IgnoreCase" ), true ); // always in Excel
+ aPropSet.setProperty( CREATE_OUSTRING( "RegularExpressions" ), false ); // not supported in Excel
+ break;
+ case FILTER_UNKNOWN:
+ break;
+ }
+
+ // calculation settings
+ Date aNullDate = maOoxBookData.mbDateMode1904 ? Date( 1, 1, 1904 ) : Date( 30, 12, 1899 );
+
+ aPropSet.setProperty( CREATE_OUSTRING( "NullDate" ), aNullDate );
+ aPropSet.setProperty( CREATE_OUSTRING( "IsIterationEnabled" ), maOoxCalcData.mbIterate );
+ aPropSet.setProperty( CREATE_OUSTRING( "IterationCount" ), maOoxCalcData.mnIterateCount );
+ aPropSet.setProperty( CREATE_OUSTRING( "IterationEpsilon" ), maOoxCalcData.mfIterateDelta );
+ aPropSet.setProperty( CREATE_OUSTRING( "CalcAsShown" ), !maOoxCalcData.mbFullPrecision );
+ aPropSet.setProperty( CREATE_OUSTRING( "LookUpLabels" ), maOoxCalcData.mbUseNlr );
+
+ Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY );
+ if( xNumFmtsSupp.is() )
+ {
+ PropertySet aNumFmtProp( xNumFmtsSupp->getNumberFormatSettings() );
+ aNumFmtProp.setProperty( CREATE_OUSTRING( "NullDate" ), aNullDate );
+ }
+
+ Reference< XCalculatable > xCalculatable( getDocument(), UNO_QUERY );
+ if( xCalculatable.is() )
+ xCalculatable->enableAutomaticCalculation( (maOoxCalcData.mnCalcMode == XML_auto) || (maOoxCalcData.mnCalcMode == XML_autoNoTable) );
+}
+
+sal_Int16 WorkbookSettings::getApiShowObjectMode() const
+{
+ switch( maOoxBookData.mnShowObjectMode )
+ {
+ case XML_all: return API_SHOWMODE_SHOW;
+ case XML_none: return API_SHOWMODE_HIDE;
+ // #i80528# placeholders not supported anymore, but this is handled internally in Calc
+ case XML_placeholders: return API_SHOWMODE_PLACEHOLDER;
+ }
+ return API_SHOWMODE_SHOW;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/worksheetbuffer.cxx b/oox/source/xls/worksheetbuffer.cxx
new file mode 100644
index 000000000000..d52d75bab6b0
--- /dev/null
+++ b/oox/source/xls/worksheetbuffer.cxx
@@ -0,0 +1,333 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: worksheetbuffer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheetbuffer.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+#include <com/sun/star/i18n/KParseTokens.hpp>
+#include <com/sun/star/i18n/KParseType.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XExternalSheetName.hpp>
+#include <com/sun/star/sheet/XSheetLinkable.hpp>
+#include <comphelper/processfactory.hxx>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/ooxtokens.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::lang::Locale;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::i18n::ParseResult;
+using ::com::sun::star::sheet::XSpreadsheetDocument;
+using ::com::sun::star::sheet::XSpreadsheets;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::sheet::XExternalSheetName;
+using ::com::sun::star::sheet::XSheetLinkable;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+/** Returns the base file name without path and extension. */
+OUString lclGetBaseFileName( const OUString& rUrl )
+{
+ sal_Int32 nFileNamePos = ::std::max< sal_Int32 >( rUrl.lastIndexOf( '/' ) + 1, 0 );
+ sal_Int32 nExtPos = rUrl.lastIndexOf( '.' );
+ if( nExtPos <= nFileNamePos ) nExtPos = rUrl.getLength();
+ return rUrl.copy( nFileNamePos, nExtPos - nFileNamePos );
+}
+
+} // namespace
+
+// ============================================================================
+
+OoxSheetInfo::OoxSheetInfo() :
+ mnSheetId( -1 ),
+ mnState( XML_visible )
+{
+}
+
+// ============================================================================
+
+WorksheetBuffer::WorksheetBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maIsVisibleProp( CREATE_OUSTRING( "IsVisible" ) )
+{
+ // character classification service for conversion to valid sheet names
+ Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
+ mxCharClass.set( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.i18n.CharacterClassification" ) ), UNO_QUERY );
+ OSL_ENSURE( mxCharClass.is(), "WorksheetBuffer::WorksheetBuffer - no character classification service" );
+}
+
+void WorksheetBuffer::initializeSingleSheet()
+{
+ OSL_ENSURE( maSheetInfos.empty(), "WorksheetBuffer::initializeSingleSheet - invalid call" );
+ OoxSheetInfo aSheetInfo;
+ aSheetInfo.maName = lclGetBaseFileName( getBaseFilter().getFileUrl() );
+ insertSheet( aSheetInfo );
+}
+
+void WorksheetBuffer::importSheet( const AttributeList& rAttribs )
+{
+ OoxSheetInfo aSheetInfo;
+ aSheetInfo.maId = rAttribs.getString( R_TOKEN( id ) );
+ aSheetInfo.maName = rAttribs.getString( XML_name );
+ aSheetInfo.mnSheetId = rAttribs.getInteger( XML_sheetId, -1 );
+ aSheetInfo.mnState = rAttribs.getToken( XML_state, XML_visible );
+ insertSheet( aSheetInfo );
+}
+
+void WorksheetBuffer::importSheet( RecordInputStream& rStrm )
+{
+ sal_Int32 nState;
+ OoxSheetInfo aSheetInfo;
+ rStrm >> nState >> aSheetInfo.mnSheetId >> aSheetInfo.maId >> aSheetInfo.maName;
+ static const sal_Int32 spnStates[] = { XML_visible, XML_hidden, XML_veryHidden };
+ aSheetInfo.mnState = STATIC_ARRAY_SELECT( spnStates, nState, XML_visible );
+ insertSheet( aSheetInfo );
+}
+
+void WorksheetBuffer::importSheet( BiffInputStream& rStrm )
+{
+ sal_uInt16 nState = 0;
+ if( getBiff() >= BIFF5 )
+ {
+ rStrm.skip( 4 );
+ rStrm >> nState;
+ }
+
+ OoxSheetInfo aSheetInfo;
+ aSheetInfo.maName = (getBiff() == BIFF8) ?
+ rStrm.readUniString( rStrm.readuInt8() ) :
+ rStrm.readByteString( false, getTextEncoding() );
+ static const sal_Int32 spnStates[] = { XML_visible, XML_hidden, XML_veryHidden };
+ aSheetInfo.mnState = STATIC_ARRAY_SELECT( spnStates, nState, XML_visible );
+ insertSheet( aSheetInfo );
+}
+
+sal_Int32 WorksheetBuffer::insertExternalSheet( const OUString& rTargetUrl, const OUString& rSheetName )
+{
+ // try to find existing external sheet (needed for BIFF4W and BIFF5)
+ ExternalSheetName aExtSheet( rTargetUrl, rSheetName );
+ ExternalSheetMap::iterator aIt = maExternalSheets.find( aExtSheet );
+ if( aIt != maExternalSheets.end() )
+ return aIt->second;
+
+ // create a new external sheet
+ sal_Int16& rnSheet = maExternalSheets[ aExtSheet ];
+ rnSheet = getTotalSheetCount();
+ insertSheet( OUString(), rnSheet, false );
+
+ try
+ {
+ Reference< XSpreadsheet > xSheet = getSheet( rnSheet );
+ // use base file name as sheet name, if sheet name is missing (e.g. links to BIFF2-BIFF4 files)
+ OUString aSheetName = rSheetName;
+ if( aSheetName.getLength() == 0 )
+ aSheetName = lclGetBaseFileName( rTargetUrl );
+ // link the sheet
+ Reference< XSheetLinkable > xLinkable( xSheet, UNO_QUERY_THROW );
+ xLinkable->link( rTargetUrl, aSheetName, OUString(), OUString(), ::com::sun::star::sheet::SheetLinkMode_VALUE );
+ // set the special external sheet name
+ Reference< XExternalSheetName > xSheetName( xSheet, UNO_QUERY_THROW );
+ xSheetName->setExternalName( xLinkable->getLinkUrl(), xLinkable->getLinkSheetName() );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // return sheet index
+ return rnSheet;
+}
+
+sal_Int32 WorksheetBuffer::getInternalSheetCount() const
+{
+ return static_cast< sal_Int32 >( maSheetInfos.size() );
+}
+
+OUString WorksheetBuffer::getSheetRelId( sal_Int32 nSheet ) const
+{
+ OUString aRelId;
+ if( const OoxSheetInfo* pInfo = getSheetInfo( nSheet ) )
+ aRelId = pInfo->maId;
+ return aRelId;
+}
+
+OUString WorksheetBuffer::getFinalSheetName( sal_Int32 nSheet ) const
+{
+ OUString aName;
+ if( const OoxSheetInfo* pInfo = getSheetInfo( nSheet ) )
+ aName = pInfo->maFinalName;
+ return aName;
+}
+
+OUString WorksheetBuffer::getFinalSheetName( const OUString& rName ) const
+{
+ for( SheetInfoVec::const_iterator aIt = maSheetInfos.begin(), aEnd = maSheetInfos.end(); aIt != aEnd; ++aIt )
+ // TODO: handle encoded characters
+ if( aIt->maName.equalsIgnoreAsciiCase( rName ) )
+ return aIt->maFinalName;
+ return OUString();
+}
+
+sal_Int32 WorksheetBuffer::getFinalSheetIndex( const OUString& rName ) const
+{
+ for( SheetInfoVec::const_iterator aIt = maSheetInfos.begin(), aEnd = maSheetInfos.end(); aIt != aEnd; ++aIt )
+ // TODO: handle encoded characters
+ if( aIt->maName.equalsIgnoreAsciiCase( rName ) )
+ return static_cast< sal_Int32 >( aIt - maSheetInfos.begin() );
+ return -1;
+}
+
+// private --------------------------------------------------------------------
+
+sal_Int16 WorksheetBuffer::getTotalSheetCount() const
+{
+ try
+ {
+ Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
+ return static_cast< sal_Int16 >( xSheetsIA->getCount() );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "WorksheetBuffer::getTotalSheetCount - cannot get sheet count" );
+ }
+ return 1;
+}
+
+const OoxSheetInfo* WorksheetBuffer::getSheetInfo( sal_Int32 nSheet ) const
+{
+ return ((0 <= nSheet) && (static_cast< size_t >( nSheet ) < maSheetInfos.size())) ?
+ &maSheetInfos[ static_cast< size_t >( nSheet ) ] : 0;
+}
+
+OUString WorksheetBuffer::convertToValidSheetName( const OUString& rName, sal_Unicode cReplaceChar ) const
+{
+ if( !mxCharClass.is() ) return rName;
+
+ using namespace ::com::sun::star::i18n::KParseTokens;
+ using namespace ::com::sun::star::i18n::KParseType;
+
+ OUStringBuffer aFinalName( rName );
+ Locale aLocale( CREATE_OUSTRING( "en" ), CREATE_OUSTRING( "US" ), OUString() );
+ sal_Int32 nStartFlags = ANY_LETTER_OR_NUMBER | ASC_UNDERSCORE;
+ sal_Int32 nContFlags = nStartFlags;
+ OUString aStartChars;
+ OUString aContChars( sal_Unicode( ' ' ) );
+ sal_Int32 nStartPos = 0;
+ while( nStartPos < aFinalName.getLength() )
+ {
+ ParseResult aRes = mxCharClass->parsePredefinedToken(
+ IDENTNAME, rName, nStartPos, aLocale, nStartFlags, aStartChars, nContFlags, aContChars );
+ if( aRes.EndPos < aFinalName.getLength() )
+ {
+ aFinalName.setCharAt( aRes.EndPos, cReplaceChar );
+ nStartFlags = nContFlags;
+ aStartChars = aContChars;
+ }
+ nStartPos = aRes.EndPos + 1;
+ }
+ return aFinalName.makeStringAndClear();
+}
+
+OUString WorksheetBuffer::insertSheet( const OUString& rName, sal_Int16 nSheet, bool bVisible )
+{
+ OUString aFinalName = (rName.getLength() == 0) ? CREATE_OUSTRING( "Sheet" ) : convertToValidSheetName( rName, '_' );
+ try
+ {
+ Reference< XSpreadsheets > xSheets( getDocument()->getSheets(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSheetsIA( xSheets, UNO_QUERY_THROW );
+ Reference< XNameAccess > xSheetsNA( xSheets, UNO_QUERY_THROW );
+ PropertySet aPropSet;
+ if( nSheet < xSheetsIA->getCount() )
+ {
+ // existing sheet - try to rename
+ Reference< XNamed > xSheetName( xSheetsIA->getByIndex( nSheet ), UNO_QUERY_THROW );
+ if( xSheetName->getName() != aFinalName )
+ {
+ aFinalName = ContainerHelper::getUnusedName( xSheetsNA, aFinalName, ' ' );
+ xSheetName->setName( aFinalName );
+ }
+ aPropSet.set( xSheetName );
+ }
+ else
+ {
+ // new sheet - insert with unused name
+ aFinalName = ContainerHelper::getUnusedName( xSheetsNA, aFinalName, ' ' );
+ xSheets->insertNewByName( aFinalName, nSheet );
+ aPropSet.set( xSheetsIA->getByIndex( nSheet ) );
+ }
+
+ // sheet properties
+ aPropSet.setProperty( maIsVisibleProp, bVisible );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "WorksheetBuffer::insertSheet - cannot insert or rename worksheet" );
+ }
+ return aFinalName;
+}
+
+void WorksheetBuffer::insertSheet( const OoxSheetInfo& rSheetInfo )
+{
+ OSL_ENSURE( maExternalSheets.empty(), "WorksheetBuffer::insertSheet - external sheets exist already" );
+ sal_Int16 nSheet = static_cast< sal_Int16 >( maSheetInfos.size() );
+ maSheetInfos.push_back( rSheetInfo );
+ maSheetInfos.back().maFinalName = insertSheet( rSheetInfo.maName, nSheet, rSheetInfo.mnState == XML_visible );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/worksheetfragment.cxx b/oox/source/xls/worksheetfragment.cxx
new file mode 100644
index 000000000000..0fce487bb5c7
--- /dev/null
+++ b/oox/source/xls/worksheetfragment.cxx
@@ -0,0 +1,1068 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: worksheetfragment.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheetfragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/relations.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/autofiltercontext.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/condformatcontext.hxx"
+#include "oox/xls/externallinkbuffer.hxx"
+#include "oox/xls/pagesettings.hxx"
+#include "oox/xls/pivottablefragment.hxx"
+#include "oox/xls/querytablefragment.hxx"
+#include "oox/xls/sheetdatacontext.hxx"
+#include "oox/xls/tablefragment.hxx"
+#include "oox/xls/viewsettings.hxx"
+#include "oox/xls/workbooksettings.hxx"
+#include "oox/xls/worksheetsettings.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::xml::sax::XFastContextHandler;
+using ::oox::core::Relations;
+using ::oox::core::RelationsRef;
+using ::oox::core::RecordContextRef;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt32 OOBIN_BRK_MANUAL = 0x00000001;
+
+const sal_uInt16 BIFF_COLINFO_HIDDEN = 0x0001;
+const sal_uInt16 BIFF_COLINFO_COLLAPSED = 0x1000;
+
+const sal_uInt16 BIFF_DEFROW_CUSTOMHEIGHT = 0x0001;
+const sal_uInt16 BIFF_DEFROW_HIDDEN = 0x0002;
+const sal_uInt16 BIFF_DEFROW_THICKTOP = 0x0004;
+const sal_uInt16 BIFF_DEFROW_THICKBOTTOM = 0x0008;
+const sal_uInt16 BIFF2_DEFROW_DEFHEIGHT = 0x8000;
+const sal_uInt16 BIFF2_DEFROW_MASK = 0x7FFF;
+
+const sal_uInt32 BIFF_DATAVAL_STRINGLIST = 0x00000080;
+const sal_uInt32 BIFF_DATAVAL_ALLOWBLANK = 0x00000100;
+const sal_uInt32 BIFF_DATAVAL_NODROPDOWN = 0x00000200;
+const sal_uInt32 BIFF_DATAVAL_SHOWINPUT = 0x00040000;
+const sal_uInt32 BIFF_DATAVAL_SHOWERROR = 0x00080000;
+
+const sal_uInt32 BIFF_HYPERLINK_TARGET = 0x00000001; /// File name or URL.
+const sal_uInt32 BIFF_HYPERLINK_ABS = 0x00000002; /// Absolute path.
+const sal_uInt32 BIFF_HYPERLINK_DISPLAY = 0x00000014; /// Display string.
+const sal_uInt32 BIFF_HYPERLINK_LOC = 0x00000008; /// Target location.
+const sal_uInt32 BIFF_HYPERLINK_FRAME = 0x00000080; /// Target frame.
+const sal_uInt32 BIFF_HYPERLINK_UNC = 0x00000100; /// UNC path.
+
+} // namespace
+
+// ============================================================================
+
+OoxWorksheetFragment::OoxWorksheetFragment( const WorkbookHelper& rHelper,
+ const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath, xProgressBar, eSheetType, nSheet )
+{
+ // import data tables related to this worksheet
+ RelationsRef xTableRels = getRelations().getRelationsFromType( CREATE_RELATIONS_TYPE( "table" ) );
+ for( Relations::const_iterator aIt = xTableRels->begin(), aEnd = xTableRels->end(); aIt != aEnd; ++aIt )
+ importOoxFragment( new OoxTableFragment( *this, getFragmentPathFromTarget( aIt->second.maTarget ) ) );
+}
+
+// oox.xls.OoxContextHelper interface -----------------------------------------
+
+bool OoxWorksheetFragment::onCanCreateContext( sal_Int32 nElement ) const
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nElement == XLS_TOKEN( worksheet ));
+ case XLS_TOKEN( worksheet ):
+ return (nElement == XLS_TOKEN( sheetPr )) ||
+ (nElement == XLS_TOKEN( dimension )) ||
+ (nElement == XLS_TOKEN( sheetFormatPr )) ||
+ (nElement == XLS_TOKEN( sheetViews )) ||
+ (nElement == XLS_TOKEN( cols )) ||
+ (nElement == XLS_TOKEN( sheetData )) ||
+ (nElement == XLS_TOKEN( mergeCells )) ||
+ (nElement == XLS_TOKEN( hyperlinks )) ||
+ (nElement == XLS_TOKEN( autoFilter )) ||
+ (nElement == XLS_TOKEN( dataValidations )) ||
+ (nElement == XLS_TOKEN( conditionalFormatting )) ||
+ (nElement == XLS_TOKEN( pageMargins )) ||
+ (nElement == XLS_TOKEN( pageSetup )) ||
+ (nElement == XLS_TOKEN( headerFooter )) ||
+ (nElement == XLS_TOKEN( printOptions )) ||
+ (nElement == XLS_TOKEN( rowBreaks )) ||
+ (nElement == XLS_TOKEN( colBreaks )) ||
+ (nElement == XLS_TOKEN( sheetProtection )) ||
+ (nElement == XLS_TOKEN( phoneticPr ));
+ case XLS_TOKEN( sheetPr ):
+ return (nElement == XLS_TOKEN( outlinePr )) ||
+ (nElement == XLS_TOKEN( pageSetUpPr ));
+ case XLS_TOKEN( sheetViews ):
+ return (nElement == XLS_TOKEN( sheetView ));
+ case XLS_TOKEN( sheetView ):
+ return (nElement == XLS_TOKEN( pane )) ||
+ (nElement == XLS_TOKEN( selection ));
+ case XLS_TOKEN( cols ):
+ return (nElement == XLS_TOKEN( col ));
+ case XLS_TOKEN( mergeCells ):
+ return (nElement == XLS_TOKEN( mergeCell ));
+ case XLS_TOKEN( hyperlinks ):
+ return (nElement == XLS_TOKEN( hyperlink ));
+ case XLS_TOKEN( dataValidations ):
+ return (nElement == XLS_TOKEN( dataValidation ));
+ case XLS_TOKEN( dataValidation ):
+ return (nElement == XLS_TOKEN( formula1 )) ||
+ (nElement == XLS_TOKEN( formula2 ));
+ case XLS_TOKEN( headerFooter ):
+ return (nElement == XLS_TOKEN( firstHeader )) ||
+ (nElement == XLS_TOKEN( firstFooter )) ||
+ (nElement == XLS_TOKEN( oddHeader )) ||
+ (nElement == XLS_TOKEN( oddFooter )) ||
+ (nElement == XLS_TOKEN( evenHeader )) ||
+ (nElement == XLS_TOKEN( evenFooter ));
+ case XLS_TOKEN( rowBreaks ):
+ case XLS_TOKEN( colBreaks ):
+ return (nElement == XLS_TOKEN( brk ));
+ }
+ return false;
+}
+
+Reference< XFastContextHandler > OoxWorksheetFragment::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
+{
+ switch( nElement )
+ {
+ case XLS_TOKEN( sheetData ):
+ return new OoxSheetDataContext( *this );
+ case XLS_TOKEN( autoFilter ):
+ return new OoxAutoFilterContext( *this );
+ case XLS_TOKEN( conditionalFormatting ):
+ return new OoxCondFormatContext( *this );
+ }
+ return this;
+}
+
+void OoxWorksheetFragment::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentContext() )
+ {
+ case XLS_TOKEN( dimension ): importDimension( rAttribs ); break;
+ case XLS_TOKEN( sheetFormatPr ): importSheetFormatPr( rAttribs ); break;
+ case XLS_TOKEN( sheetView ): getSheetViewSettings().importSheetView( rAttribs ); break;
+ case XLS_TOKEN( pane ): getSheetViewSettings().importPane( rAttribs ); break;
+ case XLS_TOKEN( selection ): getSheetViewSettings().importSelection( rAttribs ); break;
+ case XLS_TOKEN( outlinePr ): getWorksheetSettings().importOutlinePr( rAttribs ); break;
+ case XLS_TOKEN( sheetProtection ): getWorksheetSettings().importSheetProtection( rAttribs ); break;
+ case XLS_TOKEN( phoneticPr ): getWorksheetSettings().importPhoneticPr( rAttribs ); break;
+ case XLS_TOKEN( col ): importCol( rAttribs ); break;
+ case XLS_TOKEN( mergeCell ): importMergeCell( rAttribs ); break;
+ case XLS_TOKEN( hyperlink ): importHyperlink( rAttribs ); break;
+ case XLS_TOKEN( dataValidation ): importDataValidation( rAttribs ); break;
+ case XLS_TOKEN( pageMargins ): getPageSettings().importPageMargins( rAttribs ); break;
+ case XLS_TOKEN( pageSetup ): getPageSettings().importPageSetup( rAttribs ); break;
+ case XLS_TOKEN( printOptions ): getPageSettings().importPrintOptions( rAttribs ); break;
+ case XLS_TOKEN( headerFooter ): getPageSettings().importHeaderFooter( rAttribs ); break;
+ case XLS_TOKEN( pageSetUpPr ): importPageSetUpPr( rAttribs ); break;
+ case XLS_TOKEN( brk ): importBrk( rAttribs ); break;
+ }
+}
+
+void OoxWorksheetFragment::onEndElement( const OUString& rChars )
+{
+ sal_Int32 nCurrentContext = getCurrentContext();
+ switch( nCurrentContext )
+ {
+ case XLS_TOKEN( firstHeader ):
+ case XLS_TOKEN( firstFooter ):
+ case XLS_TOKEN( oddHeader ):
+ case XLS_TOKEN( oddFooter ):
+ case XLS_TOKEN( evenHeader ):
+ case XLS_TOKEN( evenFooter ):
+ getPageSettings().importHeaderFooterCharacters( rChars, nCurrentContext );
+ break;
+ case XLS_TOKEN( formula1 ):
+ if( mxValData.get() )
+ {
+ importDataValFormula( mxValData->maTokens1, rChars, mxValData->maRanges.getBaseAddress() );
+ // process string list of a list validation (convert to list of string tokens)
+ if( mxValData->mnType == XML_list )
+ getFormulaParser().convertStringToStringList( mxValData->maTokens1, ',', true );
+ }
+ break;
+ case XLS_TOKEN( formula2 ):
+ if( mxValData.get() )
+ importDataValFormula( mxValData->maTokens2, rChars, mxValData->maRanges.getBaseAddress() );
+ break;
+ case XLS_TOKEN( dataValidation ):
+ if( mxValData.get() )
+ setValidation( *mxValData );
+ mxValData.reset();
+ break;
+ }
+}
+
+bool OoxWorksheetFragment::onCanCreateRecordContext( sal_Int32 nRecId )
+{
+ switch( getCurrentContext() )
+ {
+ case XML_ROOT_CONTEXT:
+ return (nRecId == OOBIN_ID_WORKSHEET);
+ case OOBIN_ID_WORKSHEET:
+ return (nRecId == OOBIN_ID_SHEETPR) ||
+ (nRecId == OOBIN_ID_DIMENSION) ||
+ (nRecId == OOBIN_ID_SHEETFORMATPR) ||
+ (nRecId == OOBIN_ID_SHEETVIEWS) ||
+ (nRecId == OOBIN_ID_COLS) ||
+ (nRecId == OOBIN_ID_SHEETDATA) ||
+ (nRecId == OOBIN_ID_MERGECELLS) ||
+ (nRecId == OOBIN_ID_HYPERLINK) ||
+ (nRecId == OOBIN_ID_DATAVALIDATIONS) ||
+ (nRecId == OOBIN_ID_CONDFORMATTING) ||
+ (nRecId == OOBIN_ID_PAGEMARGINS) ||
+ (nRecId == OOBIN_ID_PAGESETUP) ||
+ (nRecId == OOBIN_ID_PRINTOPTIONS) ||
+ (nRecId == OOBIN_ID_HEADERFOOTER) ||
+ (nRecId == OOBIN_ID_ROWBREAKS) ||
+ (nRecId == OOBIN_ID_COLBREAKS) ||
+ (nRecId == OOBIN_ID_SHEETPROTECTION) ||
+ (nRecId == OOBIN_ID_PHONETICPR);
+ case OOBIN_ID_SHEETVIEWS:
+ return (nRecId == OOBIN_ID_SHEETVIEW);
+ case OOBIN_ID_SHEETVIEW:
+ return (nRecId == OOBIN_ID_PANE) ||
+ (nRecId == OOBIN_ID_SELECTION);
+ case OOBIN_ID_COLS:
+ return (nRecId == OOBIN_ID_COL);
+ case OOBIN_ID_MERGECELLS:
+ return (nRecId == OOBIN_ID_MERGECELL);
+ case OOBIN_ID_DATAVALIDATIONS:
+ return (nRecId == OOBIN_ID_DATAVALIDATION);
+ case OOBIN_ID_ROWBREAKS:
+ case OOBIN_ID_COLBREAKS:
+ return (nRecId == OOBIN_ID_BRK);
+ }
+ return false;
+}
+
+RecordContextRef OoxWorksheetFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& )
+{
+ switch( nRecId )
+ {
+ case OOBIN_ID_SHEETDATA:
+ return new OoxSheetDataContext( *this );
+ case OOBIN_ID_CONDFORMATTING:
+ return new OoxCondFormatContext( *this );
+ }
+ return this;
+}
+
+void OoxWorksheetFragment::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentContext() )
+ {
+ case OOBIN_ID_SHEETPR: getWorksheetSettings().importSheetPr( rStrm ); break;
+ case OOBIN_ID_DIMENSION: importDimension( rStrm ); break;
+ case OOBIN_ID_SHEETPROTECTION: getWorksheetSettings().importSheetProtection( rStrm ); break;
+ case OOBIN_ID_PHONETICPR: getWorksheetSettings().importPhoneticPr( rStrm ); break;
+ case OOBIN_ID_SHEETFORMATPR: importSheetFormatPr( rStrm ); break;
+ case OOBIN_ID_SHEETVIEW: getSheetViewSettings().importSheetView( rStrm ); break;
+ case OOBIN_ID_PANE: getSheetViewSettings().importPane( rStrm ); break;
+ case OOBIN_ID_SELECTION: getSheetViewSettings().importSelection( rStrm ); break;
+ case OOBIN_ID_COL: importCol( rStrm ); break;
+ case OOBIN_ID_MERGECELL: importMergeCell( rStrm ); break;
+ case OOBIN_ID_HYPERLINK: importHyperlink( rStrm ); break;
+ case OOBIN_ID_DATAVALIDATION: importDataValidation( rStrm ); break;
+ case OOBIN_ID_PAGEMARGINS: getPageSettings().importPageMargins( rStrm ); break;
+ case OOBIN_ID_PAGESETUP: getPageSettings().importPageSetup( rStrm ); break;
+ case OOBIN_ID_PRINTOPTIONS: getPageSettings().importPrintOptions( rStrm ); break;
+ case OOBIN_ID_HEADERFOOTER: getPageSettings().importHeaderFooter( rStrm ); break;
+ case OOBIN_ID_BRK: importBrk( rStrm ); break;
+ }
+}
+
+// oox.xls.OoxFragmentHandler interface ---------------------------------------
+
+void OoxWorksheetFragment::initializeImport()
+{
+ // initial processing in base class WorksheetHelper
+ initializeWorksheetImport();
+
+ // import query table fragments related to this worksheet
+ RelationsRef xQueryRels = getRelations().getRelationsFromType( CREATE_RELATIONS_TYPE( "queryTable" ) );
+ for( Relations::const_iterator aIt = xQueryRels->begin(), aEnd = xQueryRels->end(); aIt != aEnd; ++aIt )
+ importOoxFragment( new OoxQueryTableFragment( *this, getFragmentPathFromTarget( aIt->second.maTarget ) ) );
+
+ // import pivot table fragments related to this worksheet
+ RelationsRef xPivotRels = getRelations().getRelationsFromType( CREATE_RELATIONS_TYPE( "pivotTable" ) );
+ for( Relations::const_iterator aIt = xPivotRels->begin(), aEnd = xPivotRels->end(); aIt != aEnd; ++aIt )
+ importOoxFragment( new OoxPivotTableFragment( *this, getFragmentPathFromTarget( aIt->second.maTarget ) ) );
+}
+
+void OoxWorksheetFragment::finalizeImport()
+{
+ // final processing in base class WorksheetHelper
+ finalizeWorksheetImport();
+}
+
+// private --------------------------------------------------------------------
+
+void OoxWorksheetFragment::importDimension( const AttributeList& rAttribs )
+{
+ CellRangeAddress aRange;
+ getAddressConverter().convertToCellRangeUnchecked( aRange, rAttribs.getString( XML_ref ), getSheetIndex() );
+ setDimension( aRange );
+}
+
+void OoxWorksheetFragment::importSheetFormatPr( const AttributeList& rAttribs )
+{
+ // default column settings
+ setBaseColumnWidth( rAttribs.getInteger( XML_baseColWidth, 8 ) );
+ setDefaultColumnWidth( rAttribs.getDouble( XML_defaultColWidth, 0.0 ) );
+ // default row settings
+ setDefaultRowSettings(
+ rAttribs.getDouble( XML_defaultRowHeight, 0.0 ),
+ rAttribs.getBool( XML_customHeight, false ),
+ rAttribs.getBool( XML_zeroHeight, false ),
+ rAttribs.getBool( XML_thickTop, false ),
+ rAttribs.getBool( XML_thickBottom, false ) );
+}
+
+void OoxWorksheetFragment::importCol( const AttributeList& rAttribs )
+{
+ OoxColumnData aData;
+ aData.mnFirstCol = rAttribs.getInteger( XML_min, -1 );
+ aData.mnLastCol = rAttribs.getInteger( XML_max, -1 );
+ aData.mfWidth = rAttribs.getDouble( XML_width, 0.0 );
+ aData.mnXfId = rAttribs.getInteger( XML_style, -1 );
+ aData.mnLevel = rAttribs.getInteger( XML_outlineLevel, 0 );
+ aData.mbHidden = rAttribs.getBool( XML_hidden, false );
+ aData.mbCollapsed = rAttribs.getBool( XML_collapsed, false );
+ // set column properties in the current sheet
+ setColumnData( aData );
+}
+
+void OoxWorksheetFragment::importMergeCell( const AttributeList& rAttribs )
+{
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, rAttribs.getString( XML_ref ), getSheetIndex(), true ) )
+ setMergedRange( aRange );
+}
+
+void OoxWorksheetFragment::importHyperlink( const AttributeList& rAttribs )
+{
+ OoxHyperlinkData aData;
+ if( getAddressConverter().convertToCellRange( aData.maRange, rAttribs.getString( XML_ref ), getSheetIndex(), true ) )
+ {
+ aData.maTarget = getRelations().getTargetFromRelId( rAttribs.getString( R_TOKEN( id ) ) );
+ aData.maLocation = rAttribs.getString( XML_location );
+ aData.maDisplay = rAttribs.getString( XML_display );
+ aData.maTooltip = rAttribs.getString( XML_tooltip );
+ setHyperlink( aData );
+ }
+}
+
+void OoxWorksheetFragment::importDataValidation( const AttributeList& rAttribs )
+{
+ mxValData.reset( new OoxValidationData );
+ getAddressConverter().convertToCellRangeList( mxValData->maRanges, rAttribs.getString( XML_sqref ), getSheetIndex(), true );
+ mxValData->maInputTitle = rAttribs.getString( XML_promptTitle );
+ mxValData->maInputMessage = rAttribs.getString( XML_prompt );
+ mxValData->maErrorTitle = rAttribs.getString( XML_errorTitle );
+ mxValData->maErrorMessage = rAttribs.getString( XML_error );
+ mxValData->mnType = rAttribs.getToken( XML_type, XML_none );
+ mxValData->mnOperator = rAttribs.getToken( XML_operator, XML_between );
+ mxValData->mnErrorStyle = rAttribs.getToken( XML_errorStyle, XML_stop );
+ mxValData->mbShowInputMsg = rAttribs.getBool( XML_showInputMessage, false );
+ mxValData->mbShowErrorMsg = rAttribs.getBool( XML_showErrorMessage, false );
+ /* The attribute showDropDown@dataValidation is in fact a "suppress
+ dropdown" flag, as it was in the BIFF format! ECMA specification
+ and attribute name are plain wrong! */
+ mxValData->mbNoDropDown = rAttribs.getBool( XML_showDropDown, false );
+ mxValData->mbAllowBlank = rAttribs.getBool( XML_allowBlank, false );
+}
+
+void OoxWorksheetFragment::importPageSetUpPr( const AttributeList& rAttribs )
+{
+ // for whatever reason, this flag is still stored separated from the page settings
+ getPageSettings().setFitToPagesMode( rAttribs.getBool( XML_fitToPage, false ) );
+}
+
+void OoxWorksheetFragment::importBrk( const AttributeList& rAttribs )
+{
+ OoxPageBreakData aData;
+ aData.mnColRow = rAttribs.getInteger( XML_id, 0 );
+ aData.mnMin = rAttribs.getInteger( XML_id, 0 );
+ aData.mnMax = rAttribs.getInteger( XML_id, 0 );
+ aData.mbManual = rAttribs.getBool( XML_man, false );
+ switch( getPreviousContext() )
+ {
+ case XLS_TOKEN( rowBreaks ): setPageBreak( aData, true ); break;
+ case XLS_TOKEN( colBreaks ): setPageBreak( aData, false ); break;
+ }
+}
+
+void OoxWorksheetFragment::importDataValFormula( ApiTokenSequence& orTokens,
+ const OUString& rFormula, const CellAddress& rBaseAddress )
+{
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( rBaseAddress );
+ getFormulaParser().importFormula( aContext, rFormula );
+ orTokens = aContext.getTokens();
+}
+
+void OoxWorksheetFragment::importDimension( RecordInputStream& rStrm )
+{
+ BinRange aBinRange;
+ aBinRange.read( rStrm );
+ CellRangeAddress aRange;
+ getAddressConverter().convertToCellRangeUnchecked( aRange, aBinRange, getSheetIndex() );
+ setDimension( aRange );
+}
+
+void OoxWorksheetFragment::importSheetFormatPr( RecordInputStream& rStrm )
+{
+ sal_Int32 nDefaultWidth;
+ sal_uInt16 nBaseWidth, nDefaultHeight, nFlags;
+ rStrm >> nDefaultWidth >> nBaseWidth >> nDefaultHeight >> nFlags;
+
+ // base column with
+ setBaseColumnWidth( nBaseWidth );
+ // default width is stored as 1/256th of a character in OOBIN, convert to entire character
+ setDefaultColumnWidth( static_cast< double >( nDefaultWidth ) / 256.0 );
+ // row height is in twips in OOBIN, convert to points; equal flags in BIFF and OOBIN
+ setDefaultRowSettings(
+ nDefaultHeight / 20.0,
+ getFlag( nFlags, BIFF_DEFROW_CUSTOMHEIGHT ),
+ getFlag( nFlags, BIFF_DEFROW_HIDDEN ),
+ getFlag( nFlags, BIFF_DEFROW_THICKTOP ),
+ getFlag( nFlags, BIFF_DEFROW_THICKBOTTOM ) );
+}
+
+void OoxWorksheetFragment::importCol( RecordInputStream& rStrm )
+{
+ OoxColumnData aData;
+
+ sal_uInt16 nWidth, nFlags;
+ rStrm >> aData.mnFirstCol >> aData.mnLastCol >> nWidth;
+ rStrm.skip( 2 );
+ rStrm >> aData.mnXfId >> nFlags;
+
+ // column indexes are 0-based in OOBIN, but OoxColumnData expects 1-based
+ ++aData.mnFirstCol;
+ ++aData.mnLastCol;
+ // width is stored as 1/256th of a character in OOBIN, convert to entire character
+ aData.mfWidth = static_cast< double >( nWidth ) / 256.0;
+ // equal flags in BIFF and OOBIN
+ aData.mnLevel = extractValue< sal_Int32 >( nFlags, 8, 3 );
+ aData.mbHidden = getFlag( nFlags, BIFF_COLINFO_HIDDEN );
+ aData.mbCollapsed = getFlag( nFlags, BIFF_COLINFO_COLLAPSED );
+ // set column properties in the current sheet
+ setColumnData( aData );
+}
+
+void OoxWorksheetFragment::importMergeCell( RecordInputStream& rStrm )
+{
+ BinRange aBinRange;
+ rStrm >> aBinRange;
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, aBinRange, getSheetIndex(), true ) )
+ setMergedRange( aRange );
+}
+
+void OoxWorksheetFragment::importHyperlink( RecordInputStream& rStrm )
+{
+ BinRange aBinRange;
+ rStrm >> aBinRange;
+ OoxHyperlinkData aData;
+ if( getAddressConverter().convertToCellRange( aData.maRange, aBinRange, getSheetIndex(), true ) )
+ {
+ aData.maTarget = getRelations().getTargetFromRelId( rStrm.readString() );
+ rStrm >> aData.maLocation >> aData.maTooltip >> aData.maDisplay;
+ setHyperlink( aData );
+ }
+}
+
+void OoxWorksheetFragment::importDataValidation( RecordInputStream& rStrm )
+{
+ OoxValidationData aData;
+
+ sal_uInt32 nFlags;
+ BinRangeList aRanges;
+ rStrm >> nFlags >> aRanges >> aData.maErrorTitle >> aData.maErrorMessage >> aData.maInputTitle >> aData.maInputMessage;
+
+ // equal flags in BIFF and OOBIN
+ aData.setBinType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
+ aData.setBinOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
+ aData.setBinErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
+ aData.mbAllowBlank = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
+ aData.mbNoDropDown = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
+ aData.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
+ aData.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
+
+ // cell range list
+ getAddressConverter().convertToCellRangeList( aData.maRanges, aRanges, getSheetIndex(), true );
+
+ // condition formula(s)
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( aData.maRanges.getBaseAddress() );
+ getFormulaParser().importFormula( aContext, rStrm );
+ aData.maTokens1 = aContext.getTokens();
+ getFormulaParser().importFormula( aContext, rStrm );
+ aData.maTokens2 = aContext.getTokens();
+ // process string list of a list validation (convert to list of string tokens)
+ if( (aData.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
+ getFormulaParser().convertStringToStringList( aData.maTokens1, ',', true );
+
+ // set validation data
+ setValidation( aData );
+}
+
+void OoxWorksheetFragment::importBrk( RecordInputStream& rStrm )
+{
+ OoxPageBreakData aData;
+ sal_uInt32 nFlags;
+ rStrm >> aData.mnColRow >> aData.mnMin >> aData.mnMax >> nFlags;
+ aData.mbManual = getFlag( nFlags, OOBIN_BRK_MANUAL );
+ switch( getPreviousContext() )
+ {
+ case OOBIN_ID_ROWBREAKS: setPageBreak( aData, true ); break;
+ case OOBIN_ID_COLBREAKS: setPageBreak( aData, false ); break;
+ }
+}
+
+// ============================================================================
+
+BiffWorksheetFragment::BiffWorksheetFragment( const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) :
+ BiffWorksheetFragmentBase( rHelper, xProgressBar, eSheetType, nSheet )
+{
+}
+
+bool BiffWorksheetFragment::importFragment( BiffInputStream& rStrm )
+{
+ // initial processing in base class WorksheetHelper
+ initializeWorksheetImport();
+
+ // create a SheetDataContext object that implements cell import
+ BiffSheetDataContext aSheetData( *this );
+
+ WorkbookSettings& rWorkbookSett = getWorkbookSettings();
+ WorksheetSettings& rWorksheetSett = getWorksheetSettings();
+ SheetViewSettings& rSheetViewSett = getSheetViewSettings();
+ CondFormatBuffer& rCondFormats = getCondFormats();
+ PageSettings& rPageSett = getPageSettings();
+
+ // process all record in this sheet fragment
+ while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+ {
+ sal_uInt16 nRecId = rStrm.getRecId();
+
+ if( isBofRecord( nRecId ) )
+ {
+ // skip unknown embedded fragments (BOF/EOF blocks)
+ skipFragment( rStrm );
+ }
+ else
+ {
+ // cache core stream position to detect if record is already processed
+ sal_Int64 nStrmPos = rStrm.getCoreStreamPos();
+
+ switch( nRecId )
+ {
+ // records in all BIFF versions
+ case BIFF_ID_BOTTOMMARGIN: rPageSett.importBottomMargin( rStrm ); break;
+ case BIFF_ID_CALCCOUNT: rWorkbookSett.importCalcCount( rStrm ); break;
+ case BIFF_ID_CALCMODE: rWorkbookSett.importCalcMode( rStrm ); break;
+ case BIFF_ID_DEFCOLWIDTH: importDefColWidth( rStrm ); break;
+ case BIFF_ID_DELTA: rWorkbookSett.importDelta( rStrm ); break;
+ case BIFF2_ID_DIMENSION: importDimension( rStrm ); break;
+ case BIFF3_ID_DIMENSION: importDimension( rStrm ); break;
+ case BIFF_ID_FOOTER: rPageSett.importFooter( rStrm ); break;
+ case BIFF_ID_HEADER: rPageSett.importHeader( rStrm ); break;
+ case BIFF_ID_HORPAGEBREAKS: importPageBreaks( rStrm, true ); break;
+ case BIFF_ID_ITERATION: rWorkbookSett.importIteration( rStrm ); break;
+ case BIFF_ID_LEFTMARGIN: rPageSett.importLeftMargin( rStrm ); break;
+ case BIFF_ID_PANE: rSheetViewSett.importPane( rStrm ); break;
+ case BIFF_ID_PASSWORD: rWorksheetSett.importPassword( rStrm ); break;
+ case BIFF_ID_PRINTGRIDLINES: rPageSett.importPrintGridLines( rStrm ); break;
+ case BIFF_ID_PRINTHEADERS: rPageSett.importPrintHeaders( rStrm ); break;
+ case BIFF_ID_PROTECT: rWorksheetSett.importProtect( rStrm ); break;
+ case BIFF_ID_REFMODE: rWorkbookSett.importRefMode( rStrm ); break;
+ case BIFF_ID_RIGHTMARGIN: rPageSett.importRightMargin( rStrm ); break;
+ case BIFF_ID_SELECTION: rSheetViewSett.importSelection( rStrm ); break;
+ case BIFF_ID_TOPMARGIN: rPageSett.importTopMargin( rStrm ); break;
+ case BIFF_ID_VERPAGEBREAKS: importPageBreaks( rStrm, false ); break;
+
+ // BIFF specific records
+ default: switch( getBiff() )
+ {
+ case BIFF2: switch( nRecId )
+ {
+ case BIFF_ID_COLUMNDEFAULT: importColumnDefault( rStrm ); break;
+ case BIFF_ID_COLWIDTH: importColWidth( rStrm ); break;
+ case BIFF2_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
+ case BIFF2_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
+ }
+ break;
+
+ case BIFF3: switch( nRecId )
+ {
+ case BIFF_ID_COLINFO: importColInfo( rStrm ); break;
+ case BIFF_ID_DEFCOLWIDTH: importDefColWidth( rStrm ); break;
+ case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( rStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm ); break;
+ case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( rStrm ); break;
+ case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( rStrm ); break;
+ case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( rStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( rStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
+
+ }
+ break;
+
+ case BIFF4: switch( nRecId )
+ {
+ case BIFF_ID_COLINFO: importColInfo( rStrm ); break;
+ case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( rStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( rStrm ); break;
+ case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( rStrm ); break;
+ case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( rStrm ); break;
+ case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm ); break;
+ case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( rStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( rStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
+ }
+ break;
+
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF_ID_COLINFO: importColInfo( rStrm ); break;
+ case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( rStrm ); break;
+ case BIFF_ID_MERGEDCELLS: importMergedCells( rStrm ); break; // #i62300# also in BIFF5
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( rStrm ); break;
+ case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( rStrm ); break;
+ case BIFF_ID_SCENPROTECT: rWorksheetSett.importScenProtect( rStrm ); break;
+ case BIFF_ID_SCL: rSheetViewSett.importScl( rStrm ); break;
+ case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( rStrm ); break;
+ case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm ); break;
+ case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( rStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( rStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
+ }
+ break;
+
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF_ID_CFHEADER: rCondFormats.importCfHeader( rStrm ); break;
+ case BIFF_ID_COLINFO: importColInfo( rStrm ); break;
+ case BIFF_ID_DATAVALIDATION: importDataValidation( rStrm ); break;
+ case BIFF_ID_DATAVALIDATIONS: importDataValidations( rStrm ); break;
+ case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( rStrm ); break;
+ case BIFF_ID_HYPERLINK: importHyperlink( rStrm ); break;
+ case BIFF_ID_LABELRANGES: importLabelRanges( rStrm ); break;
+ case BIFF_ID_MERGEDCELLS: importMergedCells( rStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm ); break;
+ case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( rStrm ); break;
+ case BIFF_ID_SCENPROTECT: rWorksheetSett.importScenProtect( rStrm ); break;
+ case BIFF_ID_SCL: rSheetViewSett.importScl( rStrm ); break;
+ case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( rStrm ); break;
+ case BIFF_ID_SHEETPROTECTION: rWorksheetSett.importSheetProtection( rStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( rStrm ); break;
+ case BIFF_ID_PHONETICPR: rWorksheetSett.importPhoneticPr( rStrm ); break;
+ case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm ); break;
+ case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( rStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( rStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+ }
+
+ // record not processed, try cell records
+ if( rStrm.getCoreStreamPos() == nStrmPos )
+ aSheetData.importRecord( rStrm );
+ }
+ }
+
+ // final processing in base class WorksheetHelper
+ finalizeWorksheetImport();
+ return rStrm.getRecId() == BIFF_ID_EOF;
+}
+
+// private --------------------------------------------------------------------
+
+void BiffWorksheetFragment::importColInfo( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFirstCol, nLastCol, nWidth, nXfId, nFlags;
+ rStrm >> nFirstCol >> nLastCol >> nWidth >> nXfId >> nFlags;
+
+ OoxColumnData aData;
+ // column indexes are 0-based in BIFF, but OoxColumnData expects 1-based
+ aData.mnFirstCol = static_cast< sal_Int32 >( nFirstCol ) + 1;
+ aData.mnLastCol = static_cast< sal_Int32 >( nLastCol ) + 1;
+ // width is stored as 1/256th of a character in BIFF, convert to entire character
+ aData.mfWidth = static_cast< double >( nWidth ) / 256.0;
+ aData.mnXfId = nXfId;
+ aData.mnLevel = extractValue< sal_Int32 >( nFlags, 8, 3 );
+ aData.mbHidden = getFlag( nFlags, BIFF_COLINFO_HIDDEN );
+ aData.mbCollapsed = getFlag( nFlags, BIFF_COLINFO_COLLAPSED );
+ // set column properties in the current sheet
+ setColumnData( aData );
+}
+
+void BiffWorksheetFragment::importColumnDefault( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFirstCol, nLastCol, nXfId;
+ rStrm >> nFirstCol >> nLastCol >> nXfId;
+ convertColumnFormat( nFirstCol, nLastCol, nXfId );
+}
+
+void BiffWorksheetFragment::importColWidth( BiffInputStream& rStrm )
+{
+ sal_uInt8 nFirstCol, nLastCol;
+ sal_uInt16 nWidth;
+ rStrm >> nFirstCol >> nLastCol >> nWidth;
+
+ OoxColumnData aData;
+ // column indexes are 0-based in BIFF, but OoxColumnData expects 1-based
+ aData.mnFirstCol = static_cast< sal_Int32 >( nFirstCol ) + 1;
+ aData.mnLastCol = static_cast< sal_Int32 >( nLastCol ) + 1;
+ // width is stored as 1/256th of a character in BIFF, convert to entire character
+ aData.mfWidth = static_cast< double >( nWidth ) / 256.0;
+ // set column properties in the current sheet
+ setColumnData( aData );
+}
+
+void BiffWorksheetFragment::importDefColWidth( BiffInputStream& rStrm )
+{
+ /* Stored as entire number of characters without padding pixels, which
+ will be added in setBaseColumnWidth(). Call has no effect, if a
+ width has already been set from the STANDARDWIDTH record. */
+ setBaseColumnWidth( rStrm.readuInt16() );
+}
+
+void BiffWorksheetFragment::importDefRowHeight( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFlags = BIFF_DEFROW_CUSTOMHEIGHT, nHeight;
+ if( getBiff() != BIFF2 )
+ rStrm >> nFlags;
+ rStrm >> nHeight;
+ if( getBiff() == BIFF2 )
+ nHeight &= BIFF2_DEFROW_MASK;
+ // row height is in twips in BIFF, convert to points
+ setDefaultRowSettings(
+ nHeight / 20.0,
+ getFlag( nFlags, BIFF_DEFROW_CUSTOMHEIGHT ),
+ getFlag( nFlags, BIFF_DEFROW_HIDDEN ),
+ getFlag( nFlags, BIFF_DEFROW_THICKTOP ),
+ getFlag( nFlags, BIFF_DEFROW_THICKBOTTOM ) );
+}
+
+void BiffWorksheetFragment::importDataValidations( BiffInputStream& rStrm )
+{
+ sal_Int32 nObjId;
+ rStrm.skip( 10 );
+ rStrm >> nObjId;
+ //! TODO: invalidate object id in drawing object manager
+}
+
+void BiffWorksheetFragment::importDataValidation( BiffInputStream& rStrm )
+{
+ OoxValidationData aData;
+
+ // flags
+ sal_uInt32 nFlags;
+ rStrm >> nFlags;
+ aData.setBinType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
+ aData.setBinOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
+ aData.setBinErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
+ aData.mbAllowBlank = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
+ aData.mbNoDropDown = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
+ aData.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
+ aData.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
+
+ /* Message strings. Empty strings are single NUL characters (string length
+ is 1). Do not let the stream replace them with '?' characters. */
+ rStrm.setNulSubstChar( '\0' );
+ aData.maInputTitle = rStrm.readUniString();
+ aData.maErrorTitle = rStrm.readUniString();
+ aData.maInputMessage = rStrm.readUniString();
+ aData.maErrorMessage = rStrm.readUniString();
+
+ /* Condition formula(s). String list is single tStr token with NUL
+ separators, replace them with LF characters. */
+ rStrm.setNulSubstChar( '\n' );
+ readDataValFormula( aData.maTokens1, rStrm );
+ readDataValFormula( aData.maTokens2, rStrm );
+ rStrm.setNulSubstChar(); // back to default
+ // process string list of a list validation (convert to list of string tokens)
+ if( (aData.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
+ getFormulaParser().convertStringToStringList( aData.maTokens1, '\n', true );
+
+ // cell range list
+ BinRangeList aRanges;
+ rStrm >> aRanges;
+ getAddressConverter().convertToCellRangeList( aData.maRanges, aRanges, getSheetIndex(), true );
+
+ // set validation data
+ setValidation( aData );
+}
+
+void BiffWorksheetFragment::importDimension( BiffInputStream& rStrm )
+{
+ BinRange aBinRange;
+ aBinRange.read( rStrm, true, (rStrm.getRecId() == BIFF3_ID_DIMENSION) && (getBiff() == BIFF8) );
+ // first unused row/column index in BIFF, not last used
+ if( aBinRange.maFirst.mnCol < aBinRange.maLast.mnCol ) --aBinRange.maLast.mnCol;
+ if( aBinRange.maFirst.mnRow < aBinRange.maLast.mnRow ) --aBinRange.maLast.mnRow;
+ // set dimension
+ CellRangeAddress aRange;
+ getAddressConverter().convertToCellRangeUnchecked( aRange, aBinRange, getSheetIndex() );
+ setDimension( aRange );
+}
+
+void BiffWorksheetFragment::importHyperlink( BiffInputStream& rStrm )
+{
+ OoxHyperlinkData aData;
+
+ // read cell range for the hyperlink
+ BinRange aBiffRange;
+ rStrm >> aBiffRange;
+ // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
+ aBiffRange.maFirst.mnCol &= 0xFF;
+ aBiffRange.maLast.mnCol &= 0xFF;
+ if( !getAddressConverter().convertToCellRange( aData.maRange, aBiffRange, getSheetIndex(), true ) )
+ return;
+
+ BiffGuid aGuid;
+ sal_uInt32 nId, nFlags;
+ rStrm >> aGuid >> nId >> nFlags;
+
+ OSL_ENSURE( aGuid == BiffHelper::maGuidStdHlink, "BiffWorksheetFragment::importHyperlink - unexpected header GUID" );
+ OSL_ENSURE( nId == 2, "BiffWorksheetFragment::importHyperlink - unexpected header identifier" );
+ if( !(aGuid == BiffHelper::maGuidStdHlink) )
+ return;
+
+ // display string
+ if( getFlag( nFlags, BIFF_HYPERLINK_DISPLAY ) )
+ aData.maDisplay = readHyperlinkString( rStrm, true );
+ // target frame (ignore) !TODO: DISPLAY/FRAME - right order? (never seen them together)
+ if( getFlag( nFlags, BIFF_HYPERLINK_FRAME ) )
+ skipHyperlinkString( rStrm, true );
+
+ // target
+ if( getFlag( nFlags, BIFF_HYPERLINK_TARGET ) )
+ {
+ if( getFlag( nFlags, BIFF_HYPERLINK_UNC ) )
+ {
+ // UNC path
+ OSL_ENSURE( getFlag( nFlags, BIFF_HYPERLINK_ABS ), "BiffWorksheetFragment::importHyperlink - UNC link not absolute" );
+ aData.maTarget = readHyperlinkString( rStrm, true );
+ }
+ else
+ {
+ rStrm >> aGuid;
+ if( aGuid == BiffHelper::maGuidFileMoniker )
+ {
+ // file name, maybe relative and with directory up-count
+ sal_Int16 nUpLevels;
+ rStrm >> nUpLevels;
+ OSL_ENSURE( (nUpLevels == 0) || !getFlag( nFlags, BIFF_HYPERLINK_ABS ), "BiffWorksheetFragment::importHyperlink - absolute filename with upcount" );
+ OUString aShortName = readHyperlinkString( rStrm, false );
+ if( rStrm.skip( 24 ).readInt32() > 0 )
+ {
+ sal_Int32 nStrLen = rStrm.readInt32() / 2; // byte count to char count
+ rStrm.skip( 2 );
+ aData.maTarget = readHyperlinkString( rStrm, nStrLen, true );
+ }
+ if( aData.maTarget.getLength() == 0 )
+ aData.maTarget = aShortName;
+ if( !getFlag( nFlags, BIFF_HYPERLINK_ABS ) )
+ for( sal_uInt16 nLevel = 0; nLevel < nUpLevels; ++nLevel )
+ aData.maTarget = CREATE_OUSTRING( "..\\" ) + aData.maTarget;
+ }
+ else if( aGuid == BiffHelper::maGuidUrlMoniker )
+ {
+ // URL, maybe relative and with leading '../'
+ sal_Int32 nStrLen = rStrm.readInt32() / 2; // byte count to char count
+ aData.maTarget = readHyperlinkString( rStrm, nStrLen, true );
+ }
+ else
+ {
+ OSL_ENSURE( false, "BiffWorksheetFragment::importHyperlink - unknown content GUID" );
+ return;
+ }
+ }
+ }
+
+ // target location
+ if( getFlag( nFlags, BIFF_HYPERLINK_LOC ) )
+ aData.maLocation = readHyperlinkString( rStrm, true );
+
+ OSL_ENSURE( rStrm.getRecLeft() == 0, "BiffWorksheetFragment::importHyperlink - unknown record data" );
+
+ // try to read the SCREENTIP record
+ if( (rStrm.getNextRecId() == BIFF_ID_SCREENTIP) && rStrm.startNextRecord() )
+ {
+ rStrm.skip( 2 ); // repeated record id
+ // the cell range, again
+ rStrm >> aBiffRange;
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, aBiffRange, getSheetIndex(), true ) &&
+ (aRange.StartColumn == aData.maRange.StartColumn) &&
+ (aRange.StartRow == aData.maRange.StartRow) &&
+ (aRange.EndColumn == aData.maRange.EndColumn) &&
+ (aRange.EndRow == aData.maRange.EndRow) )
+ {
+ /* This time, we have no string length, no flag field, and a
+ null-terminated 16-bit character array. */
+ aData.maTooltip = rStrm.readUnicodeArray( static_cast< sal_uInt16 >( rStrm.getRecLeft() / 2 ) );
+ }
+ }
+
+ // store the hyperlink settings
+ setHyperlink( aData );
+}
+
+void BiffWorksheetFragment::importLabelRanges( BiffInputStream& rStrm )
+{
+ BinRangeList aBiffRowRanges, aBiffColRanges;
+ rStrm >> aBiffRowRanges >> aBiffColRanges;
+ ApiCellRangeList aColRanges, aRowRanges;
+ getAddressConverter().convertToCellRangeList( aColRanges, aBiffColRanges, getSheetIndex(), true );
+ getAddressConverter().convertToCellRangeList( aRowRanges, aBiffRowRanges, getSheetIndex(), true );
+ setLabelRanges( aColRanges, aRowRanges );
+}
+
+void BiffWorksheetFragment::importMergedCells( BiffInputStream& rStrm )
+{
+ BinRangeList aBiffRanges;
+ rStrm >> aBiffRanges;
+ ApiCellRangeList aRanges;
+ getAddressConverter().convertToCellRangeList( aRanges, aBiffRanges, getSheetIndex(), true );
+ for( ApiCellRangeList::const_iterator aIt = aRanges.begin(), aEnd = aRanges.end(); aIt != aEnd; ++aIt )
+ setMergedRange( *aIt );
+}
+
+void BiffWorksheetFragment::importPageBreaks( BiffInputStream& rStrm, bool bRowBreak )
+{
+ OoxPageBreakData aData;
+ aData.mbManual = true; // only manual breaks stored in BIFF
+ bool bBiff8 = getBiff() == BIFF8; // skip start/end columns or rows in BIFF8
+
+ sal_uInt16 nCount;
+ rStrm >> nCount;
+ for( sal_uInt16 nIndex = 0; rStrm.isValid() && (nIndex < nCount); ++nIndex )
+ {
+ aData.mnColRow = rStrm.readuInt16();
+ setPageBreak( aData, bRowBreak );
+ if( bBiff8 )
+ rStrm.skip( 4 );
+ }
+}
+
+void BiffWorksheetFragment::importStandardWidth( BiffInputStream& rStrm )
+{
+ sal_uInt16 nWidth;
+ rStrm >> nWidth;
+ // width is stored as 1/256th of a character in BIFF, convert to entire character
+ double fWidth = static_cast< double >( nWidth ) / 256.0;
+ // set as default width, will override the width from DEFCOLWIDTH record
+ setDefaultColumnWidth( fWidth );
+}
+
+void BiffWorksheetFragment::readDataValFormula( ApiTokenSequence& orTokens, BiffInputStream& rStrm )
+{
+ sal_uInt16 nFmlaSize = rStrm.readuInt16();
+ rStrm.skip( 2 );
+ TokensFormulaContext aContext( true, false );
+ getFormulaParser().importFormula( aContext, rStrm, &nFmlaSize );
+ orTokens = aContext.getTokens();
+}
+
+OUString BiffWorksheetFragment::readHyperlinkString( BiffInputStream& rStrm, sal_Int32 nChars, bool bUnicode )
+{
+ OUString aRet;
+ if( nChars > 0 )
+ {
+ sal_uInt16 nReadChars = getLimitedValue< sal_uInt16, sal_Int32 >( nChars, 0, SAL_MAX_UINT16 );
+ aRet = bUnicode ?
+ rStrm.readUnicodeArray( nReadChars ) :
+ rStrm.readCharArray( nReadChars, getTextEncoding() );
+ // skip remaining chars
+ sal_uInt32 nSkip = static_cast< sal_uInt32 >( nChars - nReadChars );
+ rStrm.skip( bUnicode ? (nSkip * 2) : nSkip );
+ }
+ return aRet;
+}
+
+OUString BiffWorksheetFragment::readHyperlinkString( BiffInputStream& rStrm, bool bUnicode )
+{
+ return readHyperlinkString( rStrm, rStrm.readInt32(), bUnicode );
+}
+
+void BiffWorksheetFragment::skipHyperlinkString( BiffInputStream& rStrm, sal_Int32 nChars, bool bUnicode )
+{
+ if( nChars > 0 )
+ rStrm.skip( static_cast< sal_uInt32 >( bUnicode ? (nChars * 2) : nChars ) );
+}
+
+void BiffWorksheetFragment::skipHyperlinkString( BiffInputStream& rStrm, bool bUnicode )
+{
+ skipHyperlinkString( rStrm, rStrm.readInt32(), bUnicode );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/worksheethelper.cxx b/oox/source/xls/worksheethelper.cxx
new file mode 100644
index 000000000000..e6fdbd88d85a
--- /dev/null
+++ b/oox/source/xls/worksheethelper.cxx
@@ -0,0 +1,1652 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: worksheethelper.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:09 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheethelper.hxx"
+#include <utility>
+#include <list>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/util/XMergeable.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
+#include <com/sun/star/sheet/XCellAddressable.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include <com/sun/star/sheet/XSheetOutline.hpp>
+#include <com/sun/star/sheet/XMultipleOperation.hpp>
+#include <com/sun/star/sheet/XLabelRanges.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/condformatbuffer.hxx"
+#include "oox/xls/formulaparser.hxx"
+#include "oox/xls/ooxtokens.hxx"
+#include "oox/xls/pagesettings.hxx"
+#include "oox/xls/sharedformulabuffer.hxx"
+#include "oox/xls/sharedstringsbuffer.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+#include "oox/xls/validationpropertyhelper.hxx"
+#include "oox/xls/viewsettings.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+#include "oox/xls/worksheetsettings.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::util::XMergeable;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::table::BorderLine;
+using ::com::sun::star::table::XColumnRowRange;
+using ::com::sun::star::table::XTableColumns;
+using ::com::sun::star::table::XTableRows;
+using ::com::sun::star::table::XCell;
+using ::com::sun::star::table::XCellRange;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::sheet::XSheetCellRanges;
+using ::com::sun::star::sheet::XSheetCellRangeContainer;
+using ::com::sun::star::sheet::XCellAddressable;
+using ::com::sun::star::sheet::XCellRangeAddressable;
+using ::com::sun::star::sheet::XFormulaTokens;
+using ::com::sun::star::sheet::XSheetOutline;
+using ::com::sun::star::sheet::XMultipleOperation;
+using ::com::sun::star::sheet::XLabelRanges;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::text::XTextContent;
+using ::com::sun::star::text::XTextRange;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+void lclUpdateProgressBar( ISegmentProgressBarRef xProgressBar, const CellRangeAddress& rDimension, sal_Int32 nRow )
+{
+ if( xProgressBar.get() && (rDimension.StartRow <= nRow) && (nRow <= rDimension.EndRow) )
+ {
+ double fPosition = static_cast< double >( nRow - rDimension.StartRow + 1 ) / (rDimension.EndRow - rDimension.StartRow + 1);
+ if( xProgressBar->getPosition() < fPosition )
+ xProgressBar->setPosition( fPosition );
+ }
+}
+
+} // namespace
+
+// ============================================================================
+// ============================================================================
+
+void OoxCellData::reset()
+{
+ mxCell.clear();
+ maValueStr = maFormulaRef = OUString();
+ mnCellType = mnFormulaType = XML_TOKEN_INVALID;
+ mnSharedId = mnXfId = mnNumFmtId = -1;
+ mbHasValueStr = mbShowPhonetic = false;
+}
+
+// ----------------------------------------------------------------------------
+
+OoxDataTableData::OoxDataTableData() :
+ mb2dTable( false ),
+ mbRowTable( false ),
+ mbRef1Deleted( false ),
+ mbRef2Deleted( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+OoxColumnData::OoxColumnData() :
+ mnFirstCol( -1 ),
+ mnLastCol( -1 ),
+ mfWidth( 0.0 ),
+ mnXfId( -1 ),
+ mnLevel( 0 ),
+ mbHidden( false ),
+ mbCollapsed( false )
+{
+}
+
+bool OoxColumnData::tryExpand( const OoxColumnData& rNewData )
+{
+ bool bExpandable =
+ (mnFirstCol <= rNewData.mnFirstCol) &&
+ (rNewData.mnFirstCol <= mnLastCol + 1) &&
+ (mfWidth == rNewData.mfWidth) &&
+ // ignore mnXfId, cell formatting is always set directly
+ (mnLevel == rNewData.mnLevel) &&
+ (mbHidden == rNewData.mbHidden) &&
+ (mbCollapsed == rNewData.mbCollapsed);
+ if( bExpandable )
+ mnLastCol = rNewData.mnLastCol;
+ return bExpandable;
+}
+
+// ----------------------------------------------------------------------------
+
+OoxRowData::OoxRowData() :
+ mnFirstRow( -1 ),
+ mnLastRow( -1 ),
+ mfHeight( 0.0 ),
+ mnXfId( -1 ),
+ mnLevel( 0 ),
+ mbCustomHeight( false ),
+ mbCustomFormat( false ),
+ mbShowPhonetic( false ),
+ mbHidden( false ),
+ mbCollapsed( false ),
+ mbThickTop( false ),
+ mbThickBottom( false )
+{
+}
+
+bool OoxRowData::tryExpand( const OoxRowData& rNewData )
+{
+ bool bExpandable =
+ (mnFirstRow <= rNewData.mnFirstRow) &&
+ (rNewData.mnFirstRow <= mnLastRow + 1) &&
+ (mfHeight == rNewData.mfHeight) &&
+ // ignore mnXfId, mbCustomFormat, mbShowPhonetic - cell formatting is always set directly
+ (mnLevel == rNewData.mnLevel) &&
+ (mbCustomHeight == rNewData.mbCustomHeight) &&
+ (mbHidden == rNewData.mbHidden) &&
+ (mbCollapsed == rNewData.mbCollapsed);
+ if( bExpandable )
+ mnLastRow = rNewData.mnLastRow;
+ return bExpandable;
+}
+
+// ----------------------------------------------------------------------------
+
+OoxPageBreakData::OoxPageBreakData() :
+ mnColRow( 0 ),
+ mbManual( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+OoxHyperlinkData::OoxHyperlinkData()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+OoxValidationData::OoxValidationData() :
+ mnType( XML_none ),
+ mnOperator( XML_between ),
+ mnErrorStyle( XML_stop ),
+ mbShowInputMsg( false ),
+ mbShowErrorMsg( false ),
+ mbNoDropDown( false ),
+ mbAllowBlank( false )
+{
+}
+
+void OoxValidationData::setBinType( sal_uInt8 nType )
+{
+ static const sal_Int32 spnTypeIds[] = {
+ XML_none, XML_whole, XML_decimal, XML_list, XML_date, XML_time, XML_textLength, XML_custom };
+ mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_none );
+}
+
+void OoxValidationData::setBinOperator( sal_uInt8 nOperator )
+{
+ static const sal_Int32 spnOperators[] = {
+ XML_between, XML_notBetween, XML_equal, XML_notEqual,
+ XML_greaterThan, XML_lessThan, XML_greaterThanOrEqual, XML_lessThanOrEqual };
+ mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
+}
+
+void OoxValidationData::setBinErrorStyle( sal_uInt8 nErrorStyle )
+{
+ static const sal_Int32 spnErrorStyles[] = { XML_stop, XML_warning, XML_information };
+ mnErrorStyle = STATIC_ARRAY_SELECT( spnErrorStyles, nErrorStyle, XML_stop );
+}
+
+// ============================================================================
+// ============================================================================
+
+class WorksheetData : public WorkbookHelper
+{
+public:
+ explicit WorksheetData(
+ const WorkbookHelper& rHelper,
+ ISegmentProgressBarRef xProgressBar,
+ WorksheetType eSheetType,
+ sal_Int32 nSheet );
+
+ /** Returns true, if this helper refers to an existing Calc sheet. */
+ inline bool isValidSheet() const { return mxSheet.is(); }
+
+ /** Returns a cell formula simulating an empty string result. */
+ inline const OUString& getEmptyStringFormula() const { return maEmptyStrFormula; }
+ /** Returns a cell formula simulating the passed boolean value. */
+ const OUString& getBooleanFormula( bool bValue ) const;
+
+ /** Returns the type of this sheet. */
+ inline WorksheetType getSheetType() const { return meSheetType; }
+ /** Returns the index of the current sheet. */
+ inline sal_Int16 getSheetIndex() const { return mnSheet; }
+ /** Returns the XSpreadsheet interface of the current sheet. */
+ inline const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheet >&
+ getXSpreadsheet() const { return mxSheet; }
+
+ /** Returns the XCell interface for the passed cell address. */
+ Reference< XCell > getCell( const CellAddress& rAddress ) const;
+ /** Returns the XCellRange interface for the passed cell range address. */
+ Reference< XCellRange > getCellRange( const CellRangeAddress& rRange ) const;
+ /** Returns the XSheetCellRanges interface for the passed cell range addresses. */
+ Reference< XSheetCellRanges > getCellRangeList( const ApiCellRangeList& rRanges ) const;
+
+ /** Returns the XCellRange interface for a column. */
+ Reference< XCellRange > getColumn( sal_Int32 nCol ) const;
+ /** Returns the XCellRange interface for a row. */
+ Reference< XCellRange > getRow( sal_Int32 nRow ) const;
+
+ /** Returns the XTableColumns interface for a range of columns. */
+ Reference< XTableColumns > getColumns( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const;
+ /** Returns the XTableRows interface for a range of rows. */
+ Reference< XTableRows > getRows( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const;
+
+ /** Returns the worksheet settings object. */
+ inline WorksheetSettings& getWorksheetSettings() { return maSheetSett; }
+ /** Returns the buffer containing all shared formulas in this sheet. */
+ inline SharedFormulaBuffer& getSharedFormulas() { return maSharedFmlas; }
+ /** Returns the conditional formattings in this sheet. */
+ inline CondFormatBuffer& getCondFormats() { return maCondFormats; }
+ /** Returns the page/print settings for this sheet. */
+ inline PageSettings& getPageSettings() { return maPageSett; }
+ /** Returns the view settings for this sheet. */
+ inline SheetViewSettings& getSheetViewSettings() { return maSheetViewSett; }
+
+ /** Sets the dimension (used area) of the sheet. */
+ void setDimension( const CellRangeAddress& rRange );
+ /** Stores the cell format at the passed address. */
+ void setCellFormat( const OoxCellData& rCellData );
+ /** Merges the cells in the passed cell range. */
+ void setMergedRange( const CellRangeAddress& rRange );
+ /** Sets a column or row page break described in the passed struct. */
+ void setPageBreak( const OoxPageBreakData& rData, bool bRowBreak );
+ /** Inserts the hyperlink URL into the spreadsheet. */
+ void setHyperlink( const OoxHyperlinkData& rHyperlink );
+ /** Inserts the data validation settings into the spreadsheet. */
+ void setValidation( const OoxValidationData& rValData );
+
+ /** Sets base width for all columns (without padding pixels). This value
+ is only used, if base width has not been set with setDefaultColumnWidth(). */
+ void setBaseColumnWidth( sal_Int32 nWidth );
+ /** Sets default width for all columns. This function overrides the base
+ width set with the setBaseColumnWidth() function. */
+ void setDefaultColumnWidth( double fWidth );
+ /** Sets column settings for a specific column range.
+ @descr Column default formatting is converted directly, other settings
+ are cached and converted in the finalizeImport() call. */
+ void setColumnData( const OoxColumnData& rData );
+
+ /** Sets default height and hidden state for all unused rows in the sheet. */
+ void setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom );
+ /** Sets row settings for a specific row.
+ @descr Row default formatting is converted directly, other settings
+ are cached and converted in the finalizeImport() call. */
+ void setRowData( const OoxRowData& rData );
+
+ /** Converts column default cell formatting. */
+ void convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId );
+ /** Converts row default cell formatting. */
+ void convertRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId );
+
+ /** Initial conversion before importing the worksheet. */
+ void initializeWorksheetImport();
+ /** Final conversion after importing the worksheet. */
+ void finalizeWorksheetImport();
+
+private:
+ typedef ::std::vector< sal_Int32 > OutlineLevelVec;
+ typedef ::std::map< sal_Int32, OoxColumnData > OoxColumnDataMap;
+ typedef ::std::map< sal_Int32, OoxRowData > OoxRowDataMap;
+ typedef ::std::list< OoxHyperlinkData > OoxHyperlinkList;
+ typedef ::std::list< OoxValidationData > OoxValidationList;
+
+ struct XfIdRange
+ {
+ CellRangeAddress maRange; /// The formatted cell range.
+ sal_Int32 mnXfId; /// XF identifier for the range.
+ sal_Int32 mnNumFmtId; /// Number format id overriding the XF.
+
+ void set( const OoxCellData& rCellData );
+ bool tryExpand( const OoxCellData& rCellData );
+ bool tryMerge( const XfIdRange& rXfIdRange );
+ };
+
+ struct MergedRange
+ {
+ CellRangeAddress maRange; /// The formatted cell range.
+ sal_Int32 mnHorAlign; /// Horizontal alignment in the range.
+
+ explicit MergedRange( const CellRangeAddress& rAddress );
+ explicit MergedRange( const CellAddress& rAddress, sal_Int32 nHorAlign );
+ bool tryExpand( const CellAddress& rAddress, sal_Int32 nHorAlign );
+ };
+
+ typedef ::std::pair< sal_Int32, sal_Int32 > RowColKey;
+ typedef ::std::map< RowColKey, XfIdRange > XfIdRangeMap;
+ typedef ::std::list< MergedRange > MergedRangeList;
+
+ /** Writes all cell formatting attributes to the passed cell range. */
+ void writeXfIdRangeProperties( const XfIdRange& rXfIdRange ) const;
+ /** Tries to merge the ranges last inserted in maXfIdRanges with existing ranges. */
+ void mergeXfIdRanges();
+ /** Finalizes the remaining ranges in maXfIdRanges. */
+ void finalizeXfIdRanges();
+
+ /** Inserts all imported hyperlinks into their cell ranges. */
+ void finalizeHyperlinkRanges() const;
+ /** Inserts a hyperlinks into the specified cell. */
+ void finalizeHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const;
+
+ /** Inserts all imported data validations into their cell ranges. */
+ void finalizeValidationRanges() const;
+
+ /** Merges all cached merged ranges and updates right/bottom cell borders. */
+ void finalizeMergedRanges() const;
+ /** Merges the passed merged range and updates right/bottom cell borders. */
+ void finalizeMergedRange( const CellRangeAddress& rRange ) const;
+
+ /** Converts column properties for all columns in the sheet. */
+ void convertColumns();
+ /** Converts column properties. */
+ void convertColumns( OutlineLevelVec& orColLevels, sal_Int32 nFirstCol, sal_Int32 nLastCol, const OoxColumnData& rData );
+
+ /** Converts row properties for all rows in the sheet. */
+ void convertRows();
+ /** Converts row properties. */
+ void convertRows( OutlineLevelVec& orRowLevels, sal_Int32 nFirstRow, sal_Int32 nLastRow, const OoxRowData& rData, double fDefHeight = -1.0 );
+
+ /** Converts outline grouping for the passed column or row. */
+ void convertOutlines( OutlineLevelVec& orLevels, sal_Int32 nColRow, sal_Int32 nLevel, bool bCollapsed, bool bRows );
+ /** Groups columns or rows for the given range. */
+ void groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLastColRow, bool bCollapsed, bool bRows );
+
+private:
+ const OUString maEmptyStrFormula; /// Replacement formula for empty string result.
+ const OUString maTrueFormula; /// Replacement formula for TRUE boolean cells.
+ const OUString maFalseFormula; /// Replacement formula for FALSE boolean cells.
+ const OUString maSheetCellRanges; /// Service name for a SheetCellRanges object.
+ const OUString maRightBorderProp; /// Property name of the right border of a cell.
+ const OUString maBottomBorderProp; /// Property name of the bottom border of a cell.
+ const OUString maWidthProp; /// Property name for column width.
+ const OUString maHeightProp; /// Property name for row height.
+ const OUString maVisibleProp; /// Property name for column/row visibility.
+ const OUString maPageBreakProp; /// Property name of a page break.
+ const OUString maUrlTextField; /// Service name for a URL text field.
+ const OUString maUrlProp; /// Property name for the URL string in a URL text field.
+ const OUString maReprProp; /// Property name for the URL representation in a URL text field.
+ const CellAddress& mrMaxApiPos; /// Reference to maximum Calc cell address from address converter.
+ CellRangeAddress maDimension; /// Dimension (used) area of the sheet.
+ OoxColumnData maDefColData; /// Default column formatting.
+ OoxColumnDataMap maColDatas; /// Column data sorted by first column index.
+ OoxRowData maDefRowData; /// Default row formatting.
+ OoxRowDataMap maRowDatas; /// Row data sorted by row index.
+ OoxHyperlinkList maHyperlinks; /// Cell ranges containing hyperlinks.
+ OoxValidationList maValidations; /// Cell ranges containing data validation settings.
+ XfIdRangeMap maXfIdRanges; /// Collected XF identifiers for cell ranges.
+ MergedRangeList maMergedRanges; /// Merged cell ranges.
+ MergedRangeList maCenterFillRanges; /// Merged cell ranges from 'center across' or 'fill' alignment.
+ WorksheetSettings maSheetSett; /// Global settings for this sheet.
+ SharedFormulaBuffer maSharedFmlas; /// Buffer for shared formulas in this sheet.
+ CondFormatBuffer maCondFormats; /// Buffer for conditional formattings.
+ PageSettings maPageSett; /// Page/print settings for this sheet.
+ SheetViewSettings maSheetViewSett; /// View settings for this sheet.
+ ISegmentProgressBarRef mxProgressBar; /// Sheet progress bar.
+ ISegmentProgressBarRef mxRowProgress; /// Progress bar for row/cell processing.
+ ISegmentProgressBarRef mxFinalProgress; /// Progress bar for finalization.
+ const WorksheetType meSheetType; /// Type of thes sheet.
+ Reference< XSpreadsheet > mxSheet; /// Reference to the current sheet.
+ sal_Int16 mnSheet; /// Index of the current sheet.
+ bool mbHasDefWidth; /// True = default column width is set from defaultColWidth attribute.
+};
+
+// ----------------------------------------------------------------------------
+
+WorksheetData::WorksheetData( const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) :
+ WorkbookHelper( rHelper ),
+ maEmptyStrFormula( CREATE_OUSTRING( "=\"\"" ) ),
+ maTrueFormula( CREATE_OUSTRING( "=TRUE()" ) ),
+ maFalseFormula( CREATE_OUSTRING( "=FALSE()" ) ),
+ maSheetCellRanges( CREATE_OUSTRING( "com.sun.star.sheet.SheetCellRanges" ) ),
+ maRightBorderProp( CREATE_OUSTRING( "RightBorder" ) ),
+ maBottomBorderProp( CREATE_OUSTRING( "BottomBorder" ) ),
+ maWidthProp( CREATE_OUSTRING( "Width" ) ),
+ maHeightProp( CREATE_OUSTRING( "Height" ) ),
+ maVisibleProp( CREATE_OUSTRING( "IsVisible" ) ),
+ maPageBreakProp( CREATE_OUSTRING( "IsStartOfNewPage" ) ),
+ maUrlTextField( CREATE_OUSTRING( "com.sun.star.text.TextField.URL" ) ),
+ maUrlProp( CREATE_OUSTRING( "URL" ) ),
+ maReprProp( CREATE_OUSTRING( "Representation" ) ),
+ mrMaxApiPos( rHelper.getAddressConverter().getMaxApiAddress() ),
+ maSheetSett( WorksheetHelper( *this ) ),
+ maSharedFmlas( WorksheetHelper( *this ) ),
+ maCondFormats( WorksheetHelper( *this ) ),
+ maPageSett( WorksheetHelper( *this ) ),
+ maSheetViewSett( WorksheetHelper( *this ) ),
+ mxProgressBar( xProgressBar ),
+ meSheetType( eSheetType ),
+ mnSheet( static_cast< sal_Int16 >( nSheet ) ),
+ mbHasDefWidth( false )
+{
+ OSL_ENSURE( nSheet <= SAL_MAX_INT16, "WorksheetData::WorksheetData - invalid sheet index" );
+ mxSheet = getSheet( nSheet );
+ if( !mxSheet.is() )
+ mnSheet = -1;
+
+ maDimension.Sheet = mnSheet;
+
+ // default column settings (width and hidden state may be updated later)
+ maDefColData.mfWidth = 8.5;
+ maDefColData.mnXfId = -1;
+ maDefColData.mnLevel = 0;
+ maDefColData.mbHidden = false;
+ maDefColData.mbCollapsed = false;
+
+ // default row settings (height and hidden state may be updated later)
+ maDefRowData.mfHeight = 0.0;
+ maDefRowData.mnXfId = -1;
+ maDefRowData.mnLevel = 0;
+ maDefRowData.mbCustomHeight = false;
+ maDefRowData.mbCustomFormat = false;
+ maDefRowData.mbShowPhonetic = false;
+ maDefRowData.mbHidden = false;
+ maDefRowData.mbCollapsed = false;
+
+ if( mxProgressBar.get() )
+ {
+ mxRowProgress = mxProgressBar->createSegment( 0.5 );
+ mxFinalProgress = mxProgressBar->createSegment( 0.5 );
+ }
+}
+
+const OUString& WorksheetData::getBooleanFormula( bool bValue ) const
+{
+ return bValue ? maTrueFormula : maFalseFormula;
+}
+
+Reference< XCell > WorksheetData::getCell( const CellAddress& rAddress ) const
+{
+ Reference< XCell > xCell;
+ if( mxSheet.is() ) try
+ {
+ xCell = mxSheet->getCellByPosition( rAddress.Column, rAddress.Row );
+ }
+ catch( Exception& )
+ {
+ }
+ return xCell;
+}
+
+Reference< XCellRange > WorksheetData::getCellRange( const CellRangeAddress& rRange ) const
+{
+ Reference< XCellRange > xRange;
+ if( mxSheet.is() ) try
+ {
+ xRange = mxSheet->getCellRangeByPosition( rRange.StartColumn, rRange.StartRow, rRange.EndColumn, rRange.EndRow );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRange;
+}
+
+Reference< XSheetCellRanges > WorksheetData::getCellRangeList( const ApiCellRangeList& rRanges ) const
+{
+ Reference< XSheetCellRanges > xRanges;
+ if( mxSheet.is() && !rRanges.empty() ) try
+ {
+ Reference< XMultiServiceFactory > xFactory( getDocument(), UNO_QUERY_THROW );
+ xRanges.set( xFactory->createInstance( maSheetCellRanges ), UNO_QUERY_THROW );
+ Reference< XSheetCellRangeContainer > xRangeCont( xRanges, UNO_QUERY_THROW );
+ xRangeCont->addRangeAddresses( ContainerHelper::vectorToSequence( rRanges ), sal_False );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRanges;
+}
+
+Reference< XCellRange > WorksheetData::getColumn( sal_Int32 nCol ) const
+{
+ Reference< XCellRange > xColumn;
+ try
+ {
+ Reference< XColumnRowRange > xColRowRange( mxSheet, UNO_QUERY_THROW );
+ Reference< XTableColumns > xColumns = xColRowRange->getColumns();
+ if( xColumns.is() )
+ xColumn.set( xColumns->getByIndex( nCol ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ return xColumn;
+}
+
+Reference< XCellRange > WorksheetData::getRow( sal_Int32 nRow ) const
+{
+ Reference< XCellRange > xRow;
+ try
+ {
+ Reference< XColumnRowRange > xColRowRange( mxSheet, UNO_QUERY_THROW );
+ Reference< XTableRows > xRows = xColRowRange->getRows();
+ xRow.set( xRows->getByIndex( nRow ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRow;
+}
+
+Reference< XTableColumns > WorksheetData::getColumns( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const
+{
+ Reference< XTableColumns > xColumns;
+ nLastCol = ::std::min( nLastCol, mrMaxApiPos.Column );
+ if( (0 <= nFirstCol) && (nFirstCol <= nLastCol) )
+ {
+ Reference< XColumnRowRange > xRange( getCellRange( CellRangeAddress( mnSheet, nFirstCol, 0, nLastCol, 0 ) ), UNO_QUERY );
+ if( xRange.is() )
+ xColumns = xRange->getColumns();
+ }
+ return xColumns;
+}
+
+Reference< XTableRows > WorksheetData::getRows( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const
+{
+ Reference< XTableRows > xRows;
+ nLastRow = ::std::min( nLastRow, mrMaxApiPos.Row );
+ if( (0 <= nFirstRow) && (nFirstRow <= nLastRow) )
+ {
+ Reference< XColumnRowRange > xRange( getCellRange( CellRangeAddress( mnSheet, 0, nFirstRow, 0, nLastRow ) ), UNO_QUERY );
+ if( xRange.is() )
+ xRows = xRange->getRows();
+ }
+ return xRows;
+}
+
+void WorksheetData::setDimension( const CellRangeAddress& rRange )
+{
+ maDimension = rRange;
+}
+
+void WorksheetData::setCellFormat( const OoxCellData& rCellData )
+{
+ if( rCellData.mxCell.is() && (rCellData.mnXfId >= 0) || (rCellData.mnNumFmtId >= 0) )
+ {
+ // try to merge existing ranges and to write some formatting properties
+ if( !maXfIdRanges.empty() )
+ {
+ // get row index of last inserted cell
+ sal_Int32 nLastRow = maXfIdRanges.rbegin()->second.maRange.StartRow;
+ // row changed - try to merge ranges of last row with existing ranges
+ if( rCellData.maAddress.Row != nLastRow )
+ {
+ mergeXfIdRanges();
+ // write format properties of all ranges above last row and remove them
+ XfIdRangeMap::iterator aIt = maXfIdRanges.begin(), aEnd = maXfIdRanges.end();
+ while( aIt != aEnd )
+ {
+ if( aIt->second.maRange.EndRow < nLastRow )
+ {
+ writeXfIdRangeProperties( aIt->second );
+ maXfIdRanges.erase( aIt++ );
+ }
+ else
+ ++aIt;
+ }
+ }
+ }
+
+ // try to expand last existing range, or create new range entry
+ if( maXfIdRanges.empty() || !maXfIdRanges.rbegin()->second.tryExpand( rCellData ) )
+ maXfIdRanges[ RowColKey( rCellData.maAddress.Row, rCellData.maAddress.Column ) ].set( rCellData );
+
+ // update merged ranges for 'center across selection' and 'fill'
+ if( const Xf* pXf = getStyles().getCellXf( rCellData.mnXfId ).get() )
+ {
+ sal_Int32 nHorAlign = pXf->getAlignment().getOoxData().mnHorAlign;
+ if( (nHorAlign == XML_centerContinuous) || (nHorAlign == XML_fill) )
+ {
+ /* start new merged range, if cell is not empty (#108781#),
+ or try to expand last range with empty cell */
+ if( rCellData.mnCellType != XML_TOKEN_INVALID )
+ maCenterFillRanges.push_back( MergedRange( rCellData.maAddress, nHorAlign ) );
+ else if( !maCenterFillRanges.empty() )
+ maCenterFillRanges.rbegin()->tryExpand( rCellData.maAddress, nHorAlign );
+ }
+ }
+ }
+}
+
+void WorksheetData::setMergedRange( const CellRangeAddress& rRange )
+{
+ maMergedRanges.push_back( MergedRange( rRange ) );
+}
+
+void WorksheetData::setPageBreak( const OoxPageBreakData& rData, bool bRowBreak )
+{
+ if( rData.mbManual && (rData.mnColRow > 0) )
+ {
+ PropertySet aPropSet( bRowBreak ? getRow( rData.mnColRow ) : getColumn( rData.mnColRow ) );
+ aPropSet.setProperty( maPageBreakProp, true );
+ }
+}
+
+void WorksheetData::setHyperlink( const OoxHyperlinkData& rHyperlink )
+{
+ maHyperlinks.push_back( rHyperlink );
+}
+
+void WorksheetData::setValidation( const OoxValidationData& rValData )
+{
+ maValidations.push_back( rValData );
+}
+
+void WorksheetData::setBaseColumnWidth( sal_Int32 nWidth )
+{
+ // do not modify width, if setDefaultColumnWidth() has been used
+ if( !mbHasDefWidth && (nWidth > 0) )
+ {
+ /* #i3006# add 5 pixels padding to the width, assuming 1 pixel =
+ 1/96 inch. => 5/96 inch == 1.32 mm. */
+ const UnitConverter& rUnitConv = getUnitConverter();
+ maDefColData.mfWidth = rUnitConv.calcDigitsFromMm100( rUnitConv.calcMm100FromDigits( nWidth ) + 132 );
+ }
+}
+
+void WorksheetData::setDefaultColumnWidth( double fWidth )
+{
+ // overrides a width set with setBaseColumnWidth()
+ if( fWidth > 0.0 )
+ {
+ maDefColData.mfWidth = fWidth;
+ mbHasDefWidth = true;
+ }
+}
+
+void WorksheetData::setColumnData( const OoxColumnData& rData )
+{
+ // convert 1-based OOX column indexes to 0-based API column indexes
+ sal_Int32 nFirstCol = rData.mnFirstCol - 1;
+ sal_Int32 nLastCol = rData.mnLastCol - 1;
+ if( (0 <= nFirstCol) && (nFirstCol <= mrMaxApiPos.Column) )
+ {
+ // set column formatting directly, nLastCol is checked inside the function
+ convertColumnFormat( nFirstCol, nLastCol, rData.mnXfId );
+ // expand last entry or add new entry
+ if( maColDatas.empty() || !maColDatas.rbegin()->second.tryExpand( rData ) )
+ maColDatas[ nFirstCol ] = rData;
+ }
+}
+
+void WorksheetData::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
+{
+ maDefRowData.mfHeight = fHeight;
+ maDefRowData.mbCustomHeight = bCustomHeight;
+ maDefRowData.mbHidden = bHidden;
+ maDefRowData.mbThickTop = bThickTop;
+ maDefRowData.mbThickBottom = bThickBottom;
+}
+
+void WorksheetData::setRowData( const OoxRowData& rData )
+{
+ // convert 1-based OOX row indexes to 0-based API row indexes
+ sal_Int32 nFirstRow = rData.mnFirstRow - 1;
+ sal_Int32 nLastRow = rData.mnLastRow - 1;
+ if( (0 <= nFirstRow) && (nFirstRow <= mrMaxApiPos.Row) )
+ {
+ // set row formatting directly
+ if( rData.mbCustomFormat )
+ convertRowFormat( nFirstRow, nLastRow, rData.mnXfId );
+ // expand last entry or add new entry
+ if( maRowDatas.empty() || !maRowDatas.rbegin()->second.tryExpand( rData ) )
+ maRowDatas[ nFirstRow ] = rData;
+ }
+ lclUpdateProgressBar( mxRowProgress, maDimension, nLastRow );
+}
+
+void WorksheetData::convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId )
+{
+ CellRangeAddress aRange( mnSheet, nFirstCol, 0, nLastCol, mrMaxApiPos.Row );
+ if( getAddressConverter().validateCellRange( aRange, false ) )
+ {
+ PropertySet aPropSet( getCellRange( aRange ) );
+ getStyles().writeCellXfToPropertySet( aPropSet, nXfId );
+ }
+}
+
+void WorksheetData::convertRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId )
+{
+ CellRangeAddress aRange( mnSheet, 0, nFirstRow, mrMaxApiPos.Column, nLastRow );
+ if( getAddressConverter().validateCellRange( aRange, false ) )
+ {
+ PropertySet aPropSet( getCellRange( aRange ) );
+ getStyles().writeCellXfToPropertySet( aPropSet, nXfId );
+ }
+}
+
+void WorksheetData::initializeWorksheetImport()
+{
+#if OOX_XLS_USE_DEFAULT_STYLE
+#else
+ // set default cell style for unused cells
+ PropertySet aPropSet( mxSheet );
+ aPropSet.setProperty( CREATE_OUSTRING( "CellStyle" ), getStyles().getDefaultStyleName() );
+#endif
+}
+
+void WorksheetData::finalizeWorksheetImport()
+{
+ finalizeXfIdRanges();
+ finalizeHyperlinkRanges();
+ finalizeValidationRanges();
+ finalizeMergedRanges();
+ maCondFormats.finalizeImport();
+ maPageSett.finalizeImport();
+ maSheetViewSett.finalizeImport();
+ convertColumns();
+ convertRows();
+}
+
+// private --------------------------------------------------------------------
+
+void WorksheetData::XfIdRange::set( const OoxCellData& rCellData )
+{
+ maRange.Sheet = rCellData.maAddress.Sheet;
+ maRange.StartColumn = maRange.EndColumn = rCellData.maAddress.Column;
+ maRange.StartRow = maRange.EndRow = rCellData.maAddress.Row;
+ mnXfId = rCellData.mnXfId;
+ mnNumFmtId = rCellData.mnNumFmtId;
+}
+
+bool WorksheetData::XfIdRange::tryExpand( const OoxCellData& rCellData )
+{
+ if( (mnXfId == rCellData.mnXfId) && (mnNumFmtId == rCellData.mnNumFmtId) &&
+ (maRange.StartRow == rCellData.maAddress.Row) &&
+ (maRange.EndRow == rCellData.maAddress.Row) &&
+ (maRange.EndColumn + 1 == rCellData.maAddress.Column) )
+ {
+ ++maRange.EndColumn;
+ return true;
+ }
+ return false;
+}
+
+bool WorksheetData::XfIdRange::tryMerge( const XfIdRange& rXfIdRange )
+{
+ if( (mnXfId == rXfIdRange.mnXfId) &&
+ (mnNumFmtId == rXfIdRange.mnNumFmtId) &&
+ (maRange.EndRow + 1 == rXfIdRange.maRange.StartRow) &&
+ (maRange.StartColumn == rXfIdRange.maRange.StartColumn) &&
+ (maRange.EndColumn == rXfIdRange.maRange.EndColumn) )
+ {
+ maRange.EndRow = rXfIdRange.maRange.EndRow;
+ return true;
+ }
+ return false;
+}
+
+
+WorksheetData::MergedRange::MergedRange( const CellRangeAddress& rRange ) :
+ maRange( rRange ),
+ mnHorAlign( XML_TOKEN_INVALID )
+{
+}
+
+WorksheetData::MergedRange::MergedRange( const CellAddress& rAddress, sal_Int32 nHorAlign ) :
+ maRange( rAddress.Sheet, rAddress.Column, rAddress.Row, rAddress.Column, rAddress.Row ),
+ mnHorAlign( nHorAlign )
+{
+}
+
+bool WorksheetData::MergedRange::tryExpand( const CellAddress& rAddress, sal_Int32 nHorAlign )
+{
+ if( (mnHorAlign == nHorAlign) && (maRange.StartRow == rAddress.Row) &&
+ (maRange.EndRow == rAddress.Row) && (maRange.EndColumn + 1 == rAddress.Column) )
+ {
+ ++maRange.EndColumn;
+ return true;
+ }
+ return false;
+}
+
+void WorksheetData::writeXfIdRangeProperties( const XfIdRange& rXfIdRange ) const
+{
+ StylesBuffer& rStyles = getStyles();
+ PropertySet aPropSet( getCellRange( rXfIdRange.maRange ) );
+ if( rXfIdRange.mnXfId >= 0 )
+ rStyles.writeCellXfToPropertySet( aPropSet, rXfIdRange.mnXfId );
+ if( rXfIdRange.mnNumFmtId >= 0 )
+ rStyles.writeNumFmtToPropertySet( aPropSet, rXfIdRange.mnNumFmtId );
+}
+
+void WorksheetData::mergeXfIdRanges()
+{
+ if( !maXfIdRanges.empty() )
+ {
+ // get row index of last range
+ sal_Int32 nLastRow = maXfIdRanges.rbegin()->second.maRange.StartRow;
+ // process all ranges located in the same row of the last range
+ XfIdRangeMap::iterator aMergeIt = maXfIdRanges.end();
+ while( (aMergeIt != maXfIdRanges.begin()) && ((--aMergeIt)->second.maRange.StartRow == nLastRow) )
+ {
+ const XfIdRange& rMergeXfIdRange = aMergeIt->second;
+ // try to find a range that can be merged with rMergeRange
+ bool bFound = false;
+ for( XfIdRangeMap::iterator aIt = maXfIdRanges.begin(); !bFound && (aIt != aMergeIt); ++aIt )
+ if( (bFound = aIt->second.tryMerge( rMergeXfIdRange )) == true )
+ maXfIdRanges.erase( aMergeIt++ );
+ }
+ }
+}
+
+void WorksheetData::finalizeXfIdRanges()
+{
+ // try to merge remaining inserted ranges
+ mergeXfIdRanges();
+ // write all formatting
+ sal_Int32 nLastRow = -1;
+ for( XfIdRangeMap::const_iterator aIt = maXfIdRanges.begin(), aEnd = maXfIdRanges.end(); aIt != aEnd; ++aIt )
+ {
+ writeXfIdRangeProperties( aIt->second );
+ if( aIt->first.first > nLastRow )
+ lclUpdateProgressBar( mxFinalProgress, maDimension, nLastRow = aIt->first.first );
+ }
+}
+
+void WorksheetData::finalizeHyperlinkRanges() const
+{
+ for( OoxHyperlinkList::const_iterator aIt = maHyperlinks.begin(), aEnd = maHyperlinks.end(); aIt != aEnd; ++aIt )
+ {
+ OUStringBuffer aUrlBuffer( getBaseFilter().getAbsoluteUrl( aIt->maTarget ) );
+ if( aIt->maLocation.getLength() > 0 )
+ aUrlBuffer.append( sal_Unicode( '#' ) ).append( aIt->maLocation );
+ OUString aUrl = aUrlBuffer.makeStringAndClear();
+ if( aUrl.getLength() > 0 )
+ {
+ // convert '#SheetName!A1' to '#SheetName.A1'
+ if( aUrl[ 0 ] == '#' )
+ {
+ sal_Int32 nSepPos = aUrl.lastIndexOf( '!' );
+ if( nSepPos > 0 )
+ {
+ // replace the exclamation mark with a period
+ aUrl = aUrl.replaceAt( nSepPos, 1, OUString( sal_Unicode( '.' ) ) );
+ // #i66592# convert renamed sheets
+ bool bQuotedName = (nSepPos > 3) && (aUrl[ 1 ] == '\'') && (aUrl[ nSepPos - 1 ] == '\'');
+ sal_Int32 nNamePos = bQuotedName ? 2 : 1;
+ sal_Int32 nNameLen = nSepPos - (bQuotedName ? 3 : 1);
+ OUString aSheetName = aUrl.copy( nNamePos, nNameLen );
+ OUString aFinalName = getWorksheets().getFinalSheetName( aSheetName );
+ if( aFinalName.getLength() > 0 )
+ aUrl = aUrl.replaceAt( nNamePos, nNameLen, aFinalName );
+ }
+ }
+
+ // try to insert URL into each cell of the range
+ for( CellAddress aAddress( mnSheet, aIt->maRange.StartColumn, aIt->maRange.StartRow ); aAddress.Row <= aIt->maRange.EndRow; ++aAddress.Row )
+ for( aAddress.Column = aIt->maRange.StartColumn; aAddress.Column <= aIt->maRange.EndColumn; ++aAddress.Column )
+ finalizeHyperlink( aAddress, aUrl );
+ }
+ }
+}
+
+void WorksheetData::finalizeHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const
+{
+ Reference< XMultiServiceFactory > xFactory( getDocument(), UNO_QUERY );
+ Reference< XCell > xCell = getCell( rAddress );
+ Reference< XText > xText( xCell, UNO_QUERY );
+ // hyperlinks only supported in text cells
+ if( xFactory.is() && xCell.is() && (xCell->getType() == ::com::sun::star::table::CellContentType_TEXT) && xText.is() )
+ {
+ // create a URL field object and set its properties
+ Reference< XTextContent > xUrlField( xFactory->createInstance( maUrlTextField ), UNO_QUERY );
+ OSL_ENSURE( xUrlField.is(), "WorksheetData::finalizeHyperlink - cannot create text field" );
+ if( xUrlField.is() )
+ {
+ // properties of the URL field
+ PropertySet aPropSet( xUrlField );
+ aPropSet.setProperty( maUrlProp, rUrl );
+ aPropSet.setProperty( maReprProp, xText->getString() );
+ try
+ {
+ // insert the field into the cell
+ xText->setString( OUString() );
+ Reference< XTextRange > xRange( xText->createTextCursor(), UNO_QUERY_THROW );
+ xText->insertTextContent( xRange, xUrlField, sal_False );
+ }
+ catch( const Exception& )
+ {
+ OSL_ENSURE( false, "WorksheetData::finalizeHyperlink - cannot insert text field" );
+ }
+ }
+ }
+}
+
+void WorksheetData::finalizeValidationRanges() const
+{
+ ValidationPropertyHelper& rPropHelper = getValidationPropertyHelper();
+ for( OoxValidationList::const_iterator aIt = maValidations.begin(), aEnd = maValidations.end(); aIt != aEnd; ++aIt )
+ {
+ PropertySet aPropSet( getCellRangeList( aIt->maRanges ) );
+ rPropHelper.writeValidationProperties( aPropSet, *aIt );
+ }
+}
+
+void WorksheetData::finalizeMergedRanges() const
+{
+ MergedRangeList::const_iterator aIt, aEnd;
+ for( aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt )
+ finalizeMergedRange( aIt->maRange );
+ for( aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt )
+ finalizeMergedRange( aIt->maRange );
+}
+
+void WorksheetData::finalizeMergedRange( const CellRangeAddress& rRange ) const
+{
+ bool bMultiCol = rRange.StartColumn < rRange.EndColumn;
+ bool bMultiRow = rRange.StartRow < rRange.EndRow;
+
+ if( bMultiCol || bMultiRow ) try
+ {
+ // merge the cell range
+ Reference< XMergeable > xMerge( getCellRange( rRange ), UNO_QUERY_THROW );
+ xMerge->merge( sal_True );
+
+ // if merging this range worked (no overlapping merged ranges), update cell borders
+ PropertySet aTopLeft( getCell( CellAddress( mnSheet, rRange.StartColumn, rRange.StartRow ) ) );
+
+ // copy right border of top-right cell to right border of top-left cell
+ if( bMultiCol )
+ {
+ PropertySet aTopRight( getCell( CellAddress( mnSheet, rRange.EndColumn, rRange.StartRow ) ) );
+ BorderLine aLine;
+ if( aTopRight.getProperty( aLine, maRightBorderProp ) )
+ aTopLeft.setProperty( maRightBorderProp, aLine );
+ }
+
+ // copy bottom border of bottom-left cell to bottom border of top-left cell
+ if( bMultiRow )
+ {
+ PropertySet aBottomLeft( getCell( CellAddress( mnSheet, rRange.StartColumn, rRange.EndRow ) ) );
+ BorderLine aLine;
+ if( aBottomLeft.getProperty( aLine, maBottomBorderProp ) )
+ aTopLeft.setProperty( maBottomBorderProp, aLine );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void WorksheetData::convertColumns()
+{
+ sal_Int32 nNextCol = 0;
+ sal_Int32 nMaxCol = mrMaxApiPos.Column;
+ // stores first grouped column index for each level
+ OutlineLevelVec aColLevels;
+
+ for( OoxColumnDataMap::const_iterator aIt = maColDatas.begin(), aEnd = maColDatas.end(); aIt != aEnd; ++aIt )
+ {
+ // convert 1-based OOX column indexes to 0-based API column indexes
+ sal_Int32 nFirstCol = ::std::max( aIt->second.mnFirstCol - 1, nNextCol );
+ sal_Int32 nLastCol = ::std::min( aIt->second.mnLastCol - 1, nMaxCol );
+
+ // process gap between two column datas, use default column data
+ if( nNextCol < nFirstCol )
+ convertColumns( aColLevels, nNextCol, nFirstCol - 1, maDefColData );
+ // process the column data
+ convertColumns( aColLevels, nFirstCol, nLastCol, aIt->second );
+
+ // cache next column to be processed
+ nNextCol = nLastCol + 1;
+ }
+
+ // remaining default columns to end of sheet
+ convertColumns( aColLevels, nNextCol, nMaxCol, maDefColData );
+ // close remaining column outlines spanning to end of sheet
+ convertOutlines( aColLevels, nMaxCol + 1, 0, false, false );
+}
+
+void WorksheetData::convertColumns( OutlineLevelVec& orColLevels,
+ sal_Int32 nFirstCol, sal_Int32 nLastCol, const OoxColumnData& rData )
+{
+ Reference< XTableColumns > xColumns = getColumns( nFirstCol, nLastCol );
+ if( xColumns.is() )
+ {
+ PropertySet aPropSet( xColumns );
+ // column width: convert 'number of characters' to column width in 1/100 mm
+ sal_Int32 nWidth = getUnitConverter().calcMm100FromDigits( rData.mfWidth );
+ if( nWidth > 0 )
+ aPropSet.setProperty( maWidthProp, nWidth );
+ // hidden columns: TODO: #108683# hide columns later?
+ if( rData.mbHidden )
+ aPropSet.setProperty( maVisibleProp, false );
+ }
+ // outline settings for this column range
+ convertOutlines( orColLevels, nFirstCol, rData.mnLevel, rData.mbCollapsed, false );
+}
+
+void WorksheetData::convertRows()
+{
+ sal_Int32 nNextRow = 0;
+ sal_Int32 nMaxRow = mrMaxApiPos.Row;
+ // stores first grouped row index for each level
+ OutlineLevelVec aRowLevels;
+
+ for( OoxRowDataMap::const_iterator aIt = maRowDatas.begin(), aEnd = maRowDatas.end(); aIt != aEnd; ++aIt )
+ {
+ // convert 1-based OOX row indexes to 0-based API row indexes
+ sal_Int32 nFirstRow = ::std::max( aIt->second.mnFirstRow - 1, nNextRow );
+ sal_Int32 nLastRow = ::std::min( aIt->second.mnLastRow - 1, nMaxRow );
+
+ // process gap between two row datas, use default row data
+ if( nNextRow < nFirstRow )
+ convertRows( aRowLevels, nNextRow, nFirstRow - 1, maDefRowData );
+ // process the row data
+ convertRows( aRowLevels, nFirstRow, nLastRow, aIt->second, maDefRowData.mfHeight );
+
+ // cache next row to be processed
+ nNextRow = nLastRow + 1;
+ }
+
+ // remaining default rows to end of sheet
+ convertRows( aRowLevels, nNextRow, nMaxRow, maDefRowData );
+ // close remaining row outlines spanning to end of sheet
+ convertOutlines( aRowLevels, nMaxRow + 1, 0, false, true );
+}
+
+void WorksheetData::convertRows( OutlineLevelVec& orRowLevels,
+ sal_Int32 nFirstRow, sal_Int32 nLastRow, const OoxRowData& rData, double fDefHeight )
+{
+ Reference< XTableRows > xRows = getRows( nFirstRow, nLastRow );
+ if( xRows.is() )
+ {
+ PropertySet aPropSet( xRows );
+ /* Row height:
+ - convert points to row height in 1/100 mm
+ - ignore rData.mbCustomHeight, Excel does not set optimal height
+ correctly, if a merged cell contains multi-line text.
+ */
+ double fHeight = (rData.mfHeight >= 0.0) ? rData.mfHeight : fDefHeight;
+ sal_Int32 nHeight = getUnitConverter().calcMm100FromPoints( fHeight );
+ if( nHeight > 0 )
+ aPropSet.setProperty( maHeightProp, nHeight );
+ // hidden rows: TODO: #108683# hide rows later?
+ if( rData.mbHidden )
+ aPropSet.setProperty( maVisibleProp, false );
+ }
+ // outline settings for this row range
+ convertOutlines( orRowLevels, nFirstRow, rData.mnLevel, rData.mbCollapsed, true );
+}
+
+void WorksheetData::convertOutlines( OutlineLevelVec& orLevels,
+ sal_Int32 nColRow, sal_Int32 nLevel, bool bCollapsed, bool bRows )
+{
+ /* It is ensured from caller functions, that this function is called
+ without any gaps between the processed column or row ranges. */
+
+ OSL_ENSURE( nLevel >= 0, "WorksheetData::convertOutlines - negative outline level" );
+ nLevel = ::std::max< sal_Int32 >( nLevel, 0 );
+
+ sal_Int32 nSize = orLevels.size();
+ if( nSize < nLevel )
+ {
+ // Outline level increased. Push the begin column position.
+ for( sal_Int32 nIndex = nSize; nIndex < nLevel; ++nIndex )
+ orLevels.push_back( nColRow );
+ }
+ else if( nLevel < nSize )
+ {
+ // Outline level decreased. Pop them all out.
+ for( sal_Int32 nIndex = nLevel; nIndex < nSize; ++nIndex )
+ {
+ sal_Int32 nFirstInLevel = orLevels.back();
+ orLevels.pop_back();
+ groupColumnsOrRows( nFirstInLevel, nColRow - 1, bCollapsed, bRows );
+ bCollapsed = false; // collapse only once
+ }
+ }
+}
+
+void WorksheetData::groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLastColRow, bool bCollapse, bool bRows )
+{
+ try
+ {
+ Reference< XSheetOutline > xOutline( mxSheet, UNO_QUERY_THROW );
+ if( bRows )
+ {
+ CellRangeAddress aRange( mnSheet, 0, nFirstColRow, 0, nLastColRow );
+ xOutline->group( aRange, ::com::sun::star::table::TableOrientation_ROWS );
+ if( bCollapse )
+ xOutline->hideDetail( aRange );
+ }
+ else
+ {
+ CellRangeAddress aRange( mnSheet, nFirstColRow, 0, nLastColRow, 0 );
+ xOutline->group( aRange, ::com::sun::star::table::TableOrientation_COLUMNS );
+ if( bCollapse )
+ xOutline->hideDetail( aRange );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+// ============================================================================
+
+WorksheetHelper::WorksheetHelper( WorksheetData& rSheetData ) :
+ WorkbookHelper( rSheetData ),
+ mrSheetData( rSheetData )
+{
+}
+
+WorksheetType WorksheetHelper::getSheetType() const
+{
+ return mrSheetData.getSheetType();
+}
+
+sal_Int16 WorksheetHelper::getSheetIndex() const
+{
+ return mrSheetData.getSheetIndex();
+}
+
+const Reference< XSpreadsheet >& WorksheetHelper::getXSpreadsheet() const
+{
+ return mrSheetData.getXSpreadsheet();
+}
+
+Reference< XCell > WorksheetHelper::getCell( const CellAddress& rAddress ) const
+{
+ return mrSheetData.getCell( rAddress );
+}
+
+Reference< XCell > WorksheetHelper::getCell( const OUString& rAddressStr, CellAddress* opAddress ) const
+{
+ CellAddress aAddress;
+ if( getAddressConverter().convertToCellAddress( aAddress, rAddressStr, mrSheetData.getSheetIndex(), true ) )
+ {
+ if( opAddress ) *opAddress = aAddress;
+ return mrSheetData.getCell( aAddress );
+ }
+ return Reference< XCell >();
+}
+
+Reference< XCell > WorksheetHelper::getCell( const BinAddress& rBinAddress, CellAddress* opAddress ) const
+{
+ CellAddress aAddress;
+ if( getAddressConverter().convertToCellAddress( aAddress, rBinAddress, mrSheetData.getSheetIndex(), true ) )
+ {
+ if( opAddress ) *opAddress = aAddress;
+ return mrSheetData.getCell( aAddress );
+ }
+ return Reference< XCell >();
+}
+
+Reference< XCellRange > WorksheetHelper::getCellRange( const CellRangeAddress& rRange ) const
+{
+ return mrSheetData.getCellRange( rRange );
+}
+
+Reference< XCellRange > WorksheetHelper::getCellRange( const OUString& rRangeStr, CellRangeAddress* opRange ) const
+{
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, rRangeStr, mrSheetData.getSheetIndex(), true ) )
+ {
+ if( opRange ) *opRange = aRange;
+ return mrSheetData.getCellRange( aRange );
+ }
+ return Reference< XCellRange >();
+}
+
+Reference< XCellRange > WorksheetHelper::getCellRange( const BinRange& rBinRange, CellRangeAddress* opRange ) const
+{
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, rBinRange, mrSheetData.getSheetIndex(), true ) )
+ {
+ if( opRange ) *opRange = aRange;
+ return mrSheetData.getCellRange( aRange );
+ }
+ return Reference< XCellRange >();
+}
+
+Reference< XSheetCellRanges > WorksheetHelper::getCellRangeList( const ApiCellRangeList& rRanges ) const
+{
+ return mrSheetData.getCellRangeList( rRanges );
+}
+
+Reference< XSheetCellRanges > WorksheetHelper::getCellRangeList(
+ const OUString& rRangesStr, ApiCellRangeList* opRanges ) const
+{
+ ApiCellRangeList aRanges;
+ getAddressConverter().convertToCellRangeList( aRanges, rRangesStr, mrSheetData.getSheetIndex(), true );
+ if( opRanges ) *opRanges = aRanges;
+ return mrSheetData.getCellRangeList( aRanges );
+}
+
+Reference< XSheetCellRanges > WorksheetHelper::getCellRangeList(
+ const BinRangeList& rBinRanges, ApiCellRangeList* opRanges ) const
+{
+ ApiCellRangeList aRanges;
+ getAddressConverter().convertToCellRangeList( aRanges, rBinRanges, mrSheetData.getSheetIndex(), true );
+ if( opRanges ) *opRanges = aRanges;
+ return mrSheetData.getCellRangeList( aRanges );
+}
+
+CellAddress WorksheetHelper::getCellAddress( const Reference< XCell >& rxCell )
+{
+ CellAddress aAddress;
+ Reference< XCellAddressable > xAddressable( rxCell, UNO_QUERY );
+ OSL_ENSURE( xAddressable.is(), "WorksheetHelper::getCellAddress - cell reference not addressable" );
+ if( xAddressable.is() )
+ aAddress = xAddressable->getCellAddress();
+ return aAddress;
+}
+
+CellRangeAddress WorksheetHelper::getRangeAddress( const Reference< XCellRange >& rxRange )
+{
+ CellRangeAddress aRange;
+ Reference< XCellRangeAddressable > xAddressable( rxRange, UNO_QUERY );
+ OSL_ENSURE( xAddressable.is(), "WorksheetHelper::getRangeAddress - cell range reference not addressable" );
+ if( xAddressable.is() )
+ aRange = xAddressable->getRangeAddress();
+ return aRange;
+}
+
+Reference< XCellRange > WorksheetHelper::getColumn( sal_Int32 nCol ) const
+{
+ return mrSheetData.getColumn( nCol );
+}
+
+Reference< XCellRange > WorksheetHelper::getRow( sal_Int32 nRow ) const
+{
+ return mrSheetData.getRow( nRow );
+}
+
+Reference< XTableColumns > WorksheetHelper::getColumns( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const
+{
+ return mrSheetData.getColumns( nFirstCol, nLastCol );
+}
+
+Reference< XTableRows > WorksheetHelper::getRows( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const
+{
+ return mrSheetData.getRows( nFirstRow, nLastRow );
+}
+
+WorksheetSettings& WorksheetHelper::getWorksheetSettings() const
+{
+ return mrSheetData.getWorksheetSettings();
+}
+
+SharedFormulaBuffer& WorksheetHelper::getSharedFormulas() const
+{
+ return mrSheetData.getSharedFormulas();
+}
+
+CondFormatBuffer& WorksheetHelper::getCondFormats() const
+{
+ return mrSheetData.getCondFormats();
+}
+
+PageSettings& WorksheetHelper::getPageSettings() const
+{
+ return mrSheetData.getPageSettings();
+}
+
+SheetViewSettings& WorksheetHelper::getSheetViewSettings() const
+{
+ return mrSheetData.getSheetViewSettings();
+}
+
+void WorksheetHelper::setEmptyStringCell( const Reference< XCell >& rxCell ) const
+{
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setEmptyStringCell - missing cell interface" );
+ rxCell->setFormula( mrSheetData.getEmptyStringFormula() );
+}
+
+void WorksheetHelper::setStringCell( const Reference< XCell >& rxCell, const OUString& rText, bool bEmptyStringAsFormula ) const
+{
+ if( bEmptyStringAsFormula && (rText.getLength() == 0) )
+ {
+ setEmptyStringCell( rxCell );
+ }
+ else
+ {
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setStringCell - missing cell interface" );
+ Reference< XText > xText( rxCell, UNO_QUERY );
+ if( xText.is() )
+ xText->setString( rText );
+ }
+}
+
+void WorksheetHelper::setSharedStringCell( const Reference< XCell >& rxCell, sal_Int32 nStringId, sal_Int32 nXfId ) const
+{
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setSharedStringCell - missing cell interface" );
+ getSharedStrings().convertString( Reference< XText >( rxCell, UNO_QUERY ), nStringId, nXfId );
+}
+
+void WorksheetHelper::setBooleanCell( const Reference< XCell >& rxCell, bool bValue ) const
+{
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setBooleanCell - missing cell interface" );
+ rxCell->setFormula( mrSheetData.getBooleanFormula( bValue ) );
+}
+
+void WorksheetHelper::setErrorCell( const Reference< XCell >& rxCell, const OUString& rErrorCode ) const
+{
+ setErrorCell( rxCell, getUnitConverter().calcBiffErrorCode( rErrorCode ) );
+}
+
+void WorksheetHelper::setErrorCell( const Reference< XCell >& rxCell, sal_uInt8 nErrorCode ) const
+{
+ Reference< XFormulaTokens > xTokens( rxCell, UNO_QUERY );
+ OSL_ENSURE( xTokens.is(), "WorksheetHelper::setErrorCell - missing cell interface" );
+ if( xTokens.is() )
+ {
+ SimpleFormulaContext aContext( xTokens, false, false );
+ getFormulaParser().convertErrorToFormula( aContext, nErrorCode );
+ }
+}
+
+void WorksheetHelper::setOoxCell( OoxCellData& orCellData, bool bEmptyStringAsFormula ) const
+{
+ OSL_ENSURE( orCellData.mxCell.is(), "WorksheetHelper::setCell - missing cell interface" );
+ if( orCellData.mbHasValueStr ) switch( orCellData.mnCellType )
+ {
+ case XML_b:
+ setBooleanCell( orCellData.mxCell, orCellData.maValueStr.toDouble() != 0.0 );
+ // #108770# set 'Standard' number format for all Boolean cells
+ orCellData.mnNumFmtId = 0;
+ break;
+ case XML_n:
+ orCellData.mxCell->setValue( orCellData.maValueStr.toDouble() );
+ break;
+ case XML_e:
+ setErrorCell( orCellData.mxCell, orCellData.maValueStr );
+ break;
+ case XML_str:
+ setStringCell( orCellData.mxCell, orCellData.maValueStr, bEmptyStringAsFormula );
+ break;
+ case XML_s:
+ setSharedStringCell( orCellData.mxCell, orCellData.maValueStr.toInt32(), orCellData.mnXfId );
+ break;
+ }
+}
+
+void WorksheetHelper::setDimension( const CellRangeAddress& rRange )
+{
+ mrSheetData.setDimension( rRange );
+}
+
+void WorksheetHelper::setCellFormat( const OoxCellData& rCellData )
+{
+ mrSheetData.setCellFormat( rCellData );
+}
+
+void WorksheetHelper::setMergedRange( const CellRangeAddress& rRange )
+{
+ mrSheetData.setMergedRange( rRange );
+}
+
+void WorksheetHelper::setPageBreak( const OoxPageBreakData& rData, bool bRowBreak )
+{
+ mrSheetData.setPageBreak( rData, bRowBreak );
+}
+
+void WorksheetHelper::setHyperlink( const OoxHyperlinkData& rHyperlink )
+{
+ mrSheetData.setHyperlink( rHyperlink );
+}
+
+void WorksheetHelper::setValidation( const OoxValidationData& rValData )
+{
+ mrSheetData.setValidation( rValData );
+}
+
+void WorksheetHelper::setTableOperation( const CellRangeAddress& rRange, const OoxDataTableData& rTableData ) const
+{
+ OSL_ENSURE( getAddressConverter().checkCellRange( rRange, false ), "WorksheetHelper::setTableOperation - invalid range" );
+ bool bOk = false;
+ if( !rTableData.mbRef1Deleted && (rTableData.maRef1.getLength() > 0) && (rRange.StartColumn > 0) && (rRange.StartRow > 0) )
+ {
+ CellRangeAddress aOpRange = rRange;
+ CellAddress aRef1, aRef2;
+ if( getAddressConverter().convertToCellAddress( aRef1, rTableData.maRef1, mrSheetData.getSheetIndex(), true ) ) try
+ {
+ if( rTableData.mb2dTable )
+ {
+ if( !rTableData.mbRef2Deleted && getAddressConverter().convertToCellAddress( aRef2, rTableData.maRef2, mrSheetData.getSheetIndex(), true ) )
+ {
+ // API call expects input values inside operation range
+ --aOpRange.StartColumn;
+ --aOpRange.StartRow;
+ // formula range is top-left cell of operation range
+ CellRangeAddress aFormulaRange( mrSheetData.getSheetIndex(), aOpRange.StartColumn, aOpRange.StartRow, aOpRange.StartColumn, aOpRange.StartRow );
+ // set multiple operation
+ Reference< XMultipleOperation > xMultOp( mrSheetData.getCellRange( aOpRange ), UNO_QUERY_THROW );
+ xMultOp->setTableOperation( aFormulaRange, ::com::sun::star::sheet::TableOperationMode_BOTH, aRef2, aRef1 );
+ bOk = true;
+ }
+ }
+ else if( rTableData.mbRowTable )
+ {
+ // formula range is column to the left of operation range
+ CellRangeAddress aFormulaRange( mrSheetData.getSheetIndex(), aOpRange.StartColumn - 1, aOpRange.StartRow, aOpRange.StartColumn - 1, aOpRange.EndRow );
+ // API call expects input values (top row) inside operation range
+ --aOpRange.StartRow;
+ // set multiple operation
+ Reference< XMultipleOperation > xMultOp( mrSheetData.getCellRange( aOpRange ), UNO_QUERY_THROW );
+ xMultOp->setTableOperation( aFormulaRange, ::com::sun::star::sheet::TableOperationMode_ROW, aRef1, aRef1 );
+ bOk = true;
+ }
+ else
+ {
+ // formula range is row above operation range
+ CellRangeAddress aFormulaRange( mrSheetData.getSheetIndex(), aOpRange.StartColumn, aOpRange.StartRow - 1, aOpRange.EndColumn, aOpRange.StartRow - 1 );
+ // API call expects input values (left column) inside operation range
+ --aOpRange.StartColumn;
+ // set multiple operation
+ Reference< XMultipleOperation > xMultOp( mrSheetData.getCellRange( aOpRange ), UNO_QUERY_THROW );
+ xMultOp->setTableOperation( aFormulaRange, ::com::sun::star::sheet::TableOperationMode_COLUMN, aRef1, aRef1 );
+ bOk = true;
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ // on error: fill cell range with error codes
+ if( !bOk )
+ {
+ for( CellAddress aPos( mrSheetData.getSheetIndex(), rRange.StartColumn, rRange.StartRow ); aPos.Row <= rRange.EndRow; ++aPos.Row )
+ for( aPos.Column = rRange.StartColumn; aPos.Column <= rRange.EndColumn; ++aPos.Column )
+ setErrorCell( mrSheetData.getCell( aPos ), BIFF_ERR_REF );
+ }
+}
+
+void WorksheetHelper::setLabelRanges( const ApiCellRangeList& rColRanges, const ApiCellRangeList& rRowRanges )
+{
+ const CellAddress& rMaxPos = getAddressConverter().getMaxApiAddress();
+ Reference< XLabelRanges > xLabelRanges;
+ PropertySet aPropSet( getXSpreadsheet() );
+
+ if( !rColRanges.empty() && aPropSet.getProperty( xLabelRanges, CREATE_OUSTRING( "ColumnLabelRanges" ) ) && xLabelRanges.is() )
+ {
+ for( ApiCellRangeList::const_iterator aIt = rColRanges.begin(), aEnd = rColRanges.end(); aIt != aEnd; ++aIt )
+ {
+ CellRangeAddress aDataRange = *aIt;
+ if( aDataRange.EndRow < rMaxPos.Row )
+ {
+ aDataRange.StartRow = aDataRange.EndRow + 1;
+ aDataRange.EndRow = rMaxPos.Row;
+ }
+ else if( aDataRange.StartRow > 0 )
+ {
+ aDataRange.EndRow = aDataRange.StartRow - 1;
+ aDataRange.StartRow = 0;
+ }
+ xLabelRanges->addNew( *aIt, aDataRange );
+ }
+ }
+
+ if( !rRowRanges.empty() && aPropSet.getProperty( xLabelRanges, CREATE_OUSTRING( "RowLabelRanges" ) ) && xLabelRanges.is() )
+ {
+ for( ApiCellRangeList::const_iterator aIt = rRowRanges.begin(), aEnd = rRowRanges.end(); aIt != aEnd; ++aIt )
+ {
+ CellRangeAddress aDataRange = *aIt;
+ if( aDataRange.EndColumn < rMaxPos.Column )
+ {
+ aDataRange.StartColumn = aDataRange.EndColumn + 1;
+ aDataRange.EndColumn = rMaxPos.Column;
+ }
+ else if( aDataRange.StartColumn > 0 )
+ {
+ aDataRange.EndColumn = aDataRange.StartColumn - 1;
+ aDataRange.StartColumn = 0;
+ }
+ xLabelRanges->addNew( *aIt, aDataRange );
+ }
+ }
+}
+
+void WorksheetHelper::setBaseColumnWidth( sal_Int32 nWidth )
+{
+ mrSheetData.setBaseColumnWidth( nWidth );
+}
+
+void WorksheetHelper::setDefaultColumnWidth( double fWidth )
+{
+ mrSheetData.setDefaultColumnWidth( fWidth );
+}
+
+void WorksheetHelper::setColumnData( const OoxColumnData& rData )
+{
+ mrSheetData.setColumnData( rData );
+}
+
+void WorksheetHelper::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
+{
+ mrSheetData.setDefaultRowSettings( fHeight, bCustomHeight, bHidden, bThickTop, bThickBottom );
+}
+
+void WorksheetHelper::setRowData( const OoxRowData& rData )
+{
+ mrSheetData.setRowData( rData );
+}
+
+void WorksheetHelper::convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId )
+{
+ mrSheetData.convertColumnFormat( nFirstCol, nLastCol, nXfId );
+}
+
+void WorksheetHelper::convertRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId )
+{
+ mrSheetData.convertRowFormat( nFirstRow, nLastRow, nXfId );
+}
+
+void WorksheetHelper::initializeWorksheetImport()
+{
+ mrSheetData.initializeWorksheetImport();
+}
+
+void WorksheetHelper::finalizeWorksheetImport()
+{
+ mrSheetData.finalizeWorksheetImport();
+}
+
+// ============================================================================
+
+namespace prv {
+
+WorksheetDataOwner::WorksheetDataOwner( WorksheetDataRef xSheetData ) :
+ mxSheetData( xSheetData )
+{
+}
+
+WorksheetDataOwner::~WorksheetDataOwner()
+{
+}
+
+} // namespace prv
+
+// ----------------------------------------------------------------------------
+
+WorksheetHelperRoot::WorksheetHelperRoot( const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) :
+ prv::WorksheetDataOwner( prv::WorksheetDataRef( new WorksheetData( rHelper, xProgressBar, eSheetType, nSheet ) ) ),
+ WorksheetHelper( *mxSheetData )
+{
+}
+
+WorksheetHelperRoot::WorksheetHelperRoot( const WorksheetHelper& rHelper ) :
+ prv::WorksheetDataOwner( prv::WorksheetDataRef() ),
+ WorksheetHelper( rHelper )
+{
+}
+
+WorksheetHelperRoot::WorksheetHelperRoot( const WorksheetHelperRoot& rHelper ) :
+ prv::WorksheetDataOwner( rHelper.mxSheetData ),
+ WorksheetHelper( rHelper )
+{
+}
+
+bool WorksheetHelperRoot::isValidSheet() const
+{
+ return mxSheetData->isValidSheet();
+}
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
diff --git a/oox/source/xls/worksheetsettings.cxx b/oox/source/xls/worksheetsettings.cxx
new file mode 100644
index 000000000000..d827fc1ff70d
--- /dev/null
+++ b/oox/source/xls/worksheetsettings.cxx
@@ -0,0 +1,270 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: worksheetsettings.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-17 08:06:10 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheetsettings.hxx"
+#include <com/sun/star/util/XProtectable.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/pagesettings.hxx"
+#include "oox/xls/workbooksettings.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::util::XProtectable;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF_SHEETPR_APPLYSTYLES = 0x0020;
+const sal_uInt16 BIFF_SHEETPR_SYMBOLSBELOW = 0x0040;
+const sal_uInt16 BIFF_SHEETPR_SYMBOLSRIGHT = 0x0080;
+const sal_uInt16 BIFF_SHEETPR_FITTOPAGES = 0x0100;
+const sal_uInt16 BIFF_SHEETPR_SKIPEXT = 0x0200; /// BIFF3-BIFF4
+
+const sal_uInt16 BIFF_SHEETPROT_OBJECTS = 0x0001;
+const sal_uInt16 BIFF_SHEETPROT_SCENARIOS = 0x0002;
+const sal_uInt16 BIFF_SHEETPROT_FORMAT_CELLS = 0x0004;
+const sal_uInt16 BIFF_SHEETPROT_FORMAT_COLUMNS = 0x0008;
+const sal_uInt16 BIFF_SHEETPROT_FORMAT_ROWS = 0x0010;
+const sal_uInt16 BIFF_SHEETPROT_INSERT_COLUMNS = 0x0020;
+const sal_uInt16 BIFF_SHEETPROT_INSERT_ROWS = 0x0040;
+const sal_uInt16 BIFF_SHEETPROT_INSERT_HLINKS = 0x0080;
+const sal_uInt16 BIFF_SHEETPROT_DELETE_COLUMNS = 0x0100;
+const sal_uInt16 BIFF_SHEETPROT_DELETE_ROWS = 0x0200;
+const sal_uInt16 BIFF_SHEETPROT_SELECT_LOCKED = 0x0400;
+const sal_uInt16 BIFF_SHEETPROT_SORT = 0x0800;
+const sal_uInt16 BIFF_SHEETPROT_AUTOFILTER = 0x1000;
+const sal_uInt16 BIFF_SHEETPROT_PIVOTTABLES = 0x2000;
+const sal_uInt16 BIFF_SHEETPROT_SELECT_UNLOCKED = 0x4000;
+
+} // namespace
+
+// ============================================================================
+
+OoxOutlinePrData::OoxOutlinePrData() :
+ mbApplyStyles( false ),
+ mbSummaryBelow( true ),
+ mbSummaryRight( true )
+{
+}
+
+// ============================================================================
+
+OoxSheetProtectionData::OoxSheetProtectionData() :
+ mnPasswordHash( 0 ),
+ mbSheet( false ),
+ mbObjects( false ),
+ mbScenarios( false ),
+ mbFormatCells( true ),
+ mbFormatColumns( true ),
+ mbFormatRows( true ),
+ mbInsertColumns( true ),
+ mbInsertRows( true ),
+ mbInsertHyperlinks( true ),
+ mbDeleteColumns( true ),
+ mbDeleteRows( true ),
+ mbSelectLocked( false ),
+ mbSort( true ),
+ mbAutoFilter( true ),
+ mbPivotTables( true ),
+ mbSelectUnlocked( false )
+{
+}
+
+// ============================================================================
+
+WorksheetSettings::WorksheetSettings( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper ),
+ maPhoneticSett( rHelper )
+{
+}
+
+void WorksheetSettings::importOutlinePr( const AttributeList& rAttribs )
+{
+ maOoxOutlineData.mbApplyStyles = rAttribs.getBool( XML_applyStyles, false );
+ maOoxOutlineData.mbSummaryBelow = rAttribs.getBool( XML_summaryBelow, true );
+ maOoxOutlineData.mbSummaryRight = rAttribs.getBool( XML_summaryRight, true );
+}
+
+void WorksheetSettings::importSheetProtection( const AttributeList& rAttribs )
+{
+ sal_Int32 nHash = rAttribs.getHex( XML_password, 0 );
+ OSL_ENSURE( (0 <= nHash) && (nHash <= SAL_MAX_UINT16), "WorksheetSettings::importSheetProtection - invalid password hash" );
+ maOoxProtData.mnPasswordHash = static_cast< sal_uInt16 >( nHash );
+ maOoxProtData.mbSheet = rAttribs.getBool( XML_sheet, false );
+ maOoxProtData.mbObjects = rAttribs.getBool( XML_objects, false );
+ maOoxProtData.mbScenarios = rAttribs.getBool( XML_scenarios, false );
+ maOoxProtData.mbFormatCells = rAttribs.getBool( XML_formatCells, true );
+ maOoxProtData.mbFormatColumns = rAttribs.getBool( XML_formatColumns, true );
+ maOoxProtData.mbFormatRows = rAttribs.getBool( XML_formatRows, true );
+ maOoxProtData.mbInsertColumns = rAttribs.getBool( XML_insertColumns, true );
+ maOoxProtData.mbInsertRows = rAttribs.getBool( XML_insertRows, true );
+ maOoxProtData.mbInsertHyperlinks = rAttribs.getBool( XML_insertHyperlinks, true );
+ maOoxProtData.mbDeleteColumns = rAttribs.getBool( XML_deleteColumns, true );
+ maOoxProtData.mbDeleteRows = rAttribs.getBool( XML_deleteRows, true );
+ maOoxProtData.mbSelectLocked = rAttribs.getBool( XML_selectLockedCells, false );
+ maOoxProtData.mbSort = rAttribs.getBool( XML_sort, true );
+ maOoxProtData.mbAutoFilter = rAttribs.getBool( XML_autoFilter, true );
+ maOoxProtData.mbPivotTables = rAttribs.getBool( XML_pivotTables, true );
+ maOoxProtData.mbSelectUnlocked = rAttribs.getBool( XML_selectUnlockedCells, false );
+}
+
+void WorksheetSettings::importPhoneticPr( const AttributeList& rAttribs )
+{
+ maPhoneticSett.importPhoneticPr( rAttribs );
+}
+
+void WorksheetSettings::importSheetPr( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ // outline settings, equal flags in BIFF and OOBIN
+ maOoxOutlineData.mbApplyStyles = getFlag( nFlags, BIFF_SHEETPR_APPLYSTYLES );
+ maOoxOutlineData.mbSummaryRight = getFlag( nFlags, BIFF_SHEETPR_SYMBOLSRIGHT );
+ maOoxOutlineData.mbSummaryBelow = getFlag( nFlags, BIFF_SHEETPR_SYMBOLSBELOW );
+ /* Fit printout to width/height - for whatever reason, this flag is still
+ stored separated from the page settings */
+ getPageSettings().setFitToPagesMode( getFlag( nFlags, BIFF_SHEETPR_FITTOPAGES ) );
+}
+
+void WorksheetSettings::importSheetProtection( RecordInputStream& rStrm )
+{
+ rStrm >> maOoxProtData.mnPasswordHash;
+ // no flags field for all these boolean flags?!?
+ maOoxProtData.mbSheet = rStrm.readInt32() != 0;
+ maOoxProtData.mbObjects = rStrm.readInt32() != 0;
+ maOoxProtData.mbScenarios = rStrm.readInt32() != 0;
+ maOoxProtData.mbFormatCells = rStrm.readInt32() != 0;
+ maOoxProtData.mbFormatColumns = rStrm.readInt32() != 0;
+ maOoxProtData.mbFormatRows = rStrm.readInt32() != 0;
+ maOoxProtData.mbInsertColumns = rStrm.readInt32() != 0;
+ maOoxProtData.mbInsertRows = rStrm.readInt32() != 0;
+ maOoxProtData.mbInsertHyperlinks = rStrm.readInt32() != 0;
+ maOoxProtData.mbDeleteColumns = rStrm.readInt32() != 0;
+ maOoxProtData.mbDeleteRows = rStrm.readInt32() != 0;
+ maOoxProtData.mbSelectLocked = rStrm.readInt32() != 0;
+ maOoxProtData.mbSort = rStrm.readInt32() != 0;
+ maOoxProtData.mbAutoFilter = rStrm.readInt32() != 0;
+ maOoxProtData.mbPivotTables = rStrm.readInt32() != 0;
+ maOoxProtData.mbSelectUnlocked = rStrm.readInt32() != 0;
+}
+
+void WorksheetSettings::importPhoneticPr( RecordInputStream& rStrm )
+{
+ maPhoneticSett.importPhoneticPr( rStrm );
+}
+
+void WorksheetSettings::importSheetPr( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ // outline settings
+ maOoxOutlineData.mbApplyStyles = getFlag( nFlags, BIFF_SHEETPR_APPLYSTYLES );
+ maOoxOutlineData.mbSummaryRight = getFlag( nFlags, BIFF_SHEETPR_SYMBOLSRIGHT );
+ maOoxOutlineData.mbSummaryBelow = getFlag( nFlags, BIFF_SHEETPR_SYMBOLSBELOW );
+ // fit printout to width/height
+ getPageSettings().setFitToPagesMode( getFlag( nFlags, BIFF_SHEETPR_FITTOPAGES ) );
+ // save external linked values, in BIFF5-BIFF8 moved to BOOKBOOK record
+ if( getBiff() <= BIFF4 )
+ getWorkbookSettings().setSaveExtLinkValues( !getFlag( nFlags, BIFF_SHEETPR_SKIPEXT ) );
+}
+
+void WorksheetSettings::importProtect( BiffInputStream& rStrm )
+{
+ maOoxProtData.mbSheet = rStrm.readuInt16() != 0;
+}
+
+void WorksheetSettings::importObjectProtect( BiffInputStream& rStrm )
+{
+ maOoxProtData.mbObjects = rStrm.readuInt16() != 0;
+}
+
+void WorksheetSettings::importScenProtect( BiffInputStream& rStrm )
+{
+ maOoxProtData.mbScenarios = rStrm.readuInt16() != 0;
+}
+
+void WorksheetSettings::importPassword( BiffInputStream& rStrm )
+{
+ rStrm >> maOoxProtData.mnPasswordHash;
+}
+
+void WorksheetSettings::importSheetProtection( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFlags = rStrm.skip( 19 ).readuInt16();
+ // set flag means protection is disabled
+ maOoxProtData.mbObjects = !getFlag( nFlags, BIFF_SHEETPROT_OBJECTS );
+ maOoxProtData.mbScenarios = !getFlag( nFlags, BIFF_SHEETPROT_SCENARIOS );
+ maOoxProtData.mbFormatCells = !getFlag( nFlags, BIFF_SHEETPROT_FORMAT_CELLS );
+ maOoxProtData.mbFormatColumns = !getFlag( nFlags, BIFF_SHEETPROT_FORMAT_COLUMNS );
+ maOoxProtData.mbFormatRows = !getFlag( nFlags, BIFF_SHEETPROT_FORMAT_ROWS );
+ maOoxProtData.mbInsertColumns = !getFlag( nFlags, BIFF_SHEETPROT_INSERT_COLUMNS );
+ maOoxProtData.mbInsertRows = !getFlag( nFlags, BIFF_SHEETPROT_INSERT_ROWS );
+ maOoxProtData.mbInsertHyperlinks = !getFlag( nFlags, BIFF_SHEETPROT_INSERT_HLINKS );
+ maOoxProtData.mbDeleteColumns = !getFlag( nFlags, BIFF_SHEETPROT_DELETE_COLUMNS );
+ maOoxProtData.mbDeleteRows = !getFlag( nFlags, BIFF_SHEETPROT_DELETE_ROWS );
+ maOoxProtData.mbSelectLocked = !getFlag( nFlags, BIFF_SHEETPROT_SELECT_LOCKED );
+ maOoxProtData.mbSort = !getFlag( nFlags, BIFF_SHEETPROT_SORT );
+ maOoxProtData.mbAutoFilter = !getFlag( nFlags, BIFF_SHEETPROT_AUTOFILTER );
+ maOoxProtData.mbPivotTables = !getFlag( nFlags, BIFF_SHEETPROT_PIVOTTABLES );
+ maOoxProtData.mbSelectUnlocked = !getFlag( nFlags, BIFF_SHEETPROT_SELECT_UNLOCKED );
+}
+
+void WorksheetSettings::importPhoneticPr( BiffInputStream& rStrm )
+{
+ maPhoneticSett.importPhoneticPr( rStrm );
+}
+
+void WorksheetSettings::finalizeImport()
+{
+ if( maOoxProtData.mbSheet )
+ {
+ Reference< XProtectable > xProtectable( getXSpreadsheet(), UNO_QUERY );
+ if( xProtectable.is() )
+ xProtectable->protect( OUString() );
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+