summaryrefslogtreecommitdiff
path: root/oox/source/xls
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/xls')
-rw-r--r--oox/source/xls/addressconverter.cxx786
-rw-r--r--oox/source/xls/autofiltercontext.cxx777
-rw-r--r--oox/source/xls/biffcodec.cxx336
-rw-r--r--oox/source/xls/biffdetector.cxx235
-rw-r--r--oox/source/xls/biffhelper.cxx289
-rw-r--r--oox/source/xls/biffinputstream.cxx633
-rw-r--r--oox/source/xls/biffoutputstream.cxx210
-rw-r--r--oox/source/xls/chartsheetfragment.cxx294
-rw-r--r--oox/source/xls/commentsbuffer.cxx276
-rw-r--r--oox/source/xls/commentsfragment.cxx176
-rw-r--r--oox/source/xls/condformatbuffer.cxx789
-rw-r--r--oox/source/xls/condformatcontext.cxx109
-rw-r--r--oox/source/xls/connectionsfragment.cxx115
-rw-r--r--oox/source/xls/defnamesbuffer.cxx714
-rw-r--r--oox/source/xls/drawingfragment.cxx682
-rw-r--r--oox/source/xls/excelchartconverter.cxx127
-rw-r--r--oox/source/xls/excelfilter.cxx280
-rw-r--r--oox/source/xls/excelhandlers.cxx261
-rw-r--r--oox/source/xls/externallinkbuffer.cxx1145
-rw-r--r--oox/source/xls/externallinkfragment.cxx553
-rw-r--r--oox/source/xls/formulabase.cxx1752
-rw-r--r--oox/source/xls/formulaparser.cxx2863
-rw-r--r--oox/source/xls/makefile.mk100
-rw-r--r--oox/source/xls/numberformatsbuffer.cxx2125
-rw-r--r--oox/source/xls/ooxformulaparser.cxx227
-rw-r--r--oox/source/xls/pagesettings.cxx1287
-rw-r--r--oox/source/xls/pivotcachebuffer.cxx1550
-rw-r--r--oox/source/xls/pivotcachefragment.cxx467
-rw-r--r--oox/source/xls/pivottablebuffer.cxx1555
-rw-r--r--oox/source/xls/pivottablefragment.cxx319
-rw-r--r--oox/source/xls/querytablefragment.cxx58
-rw-r--r--oox/source/xls/richstring.cxx639
-rw-r--r--oox/source/xls/richstringcontext.cxx97
-rw-r--r--oox/source/xls/scenariobuffer.cxx308
-rw-r--r--oox/source/xls/scenariocontext.cxx126
-rw-r--r--oox/source/xls/sharedformulabuffer.cxx217
-rw-r--r--oox/source/xls/sharedstringsbuffer.cxx86
-rw-r--r--oox/source/xls/sharedstringsfragment.cxx106
-rw-r--r--oox/source/xls/sheetdatacontext.cxx994
-rw-r--r--oox/source/xls/stylesbuffer.cxx3522
-rw-r--r--oox/source/xls/stylesfragment.cxx333
-rw-r--r--oox/source/xls/tablebuffer.cxx175
-rw-r--r--oox/source/xls/tablefragment.cxx88
-rw-r--r--oox/source/xls/themebuffer.cxx124
-rw-r--r--oox/source/xls/unitconverter.cxx260
-rw-r--r--oox/source/xls/viewsettings.cxx835
-rw-r--r--oox/source/xls/webquerybuffer.cxx201
-rw-r--r--oox/source/xls/workbookfragment.cxx740
-rw-r--r--oox/source/xls/workbookhelper.cxx1007
-rw-r--r--oox/source/xls/workbooksettings.cxx387
-rw-r--r--oox/source/xls/worksheetbuffer.cxx263
-rw-r--r--oox/source/xls/worksheetfragment.cxx1204
-rw-r--r--oox/source/xls/worksheethelper.cxx2297
-rw-r--r--oox/source/xls/worksheetsettings.cxx340
54 files changed, 35439 insertions, 0 deletions
diff --git a/oox/source/xls/addressconverter.cxx b/oox/source/xls/addressconverter.cxx
new file mode 100644
index 000000000000..5dd8f99991e9
--- /dev/null
+++ b/oox/source/xls/addressconverter.cxx
@@ -0,0 +1,786 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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_LIBRARY = '\x08'; /// Library directory in application installation.
+const sal_Unicode BIFF4_URL_SHEET = '\x09'; /// BIFF4 internal sheet.
+const sal_Unicode BIFF_URL_UNC = '@'; /// UNC path root.
+
+const sal_Unicode BIFF_DCON_ENCODED = '\x01'; /// First character of an encoded path from DCON* records.
+const sal_Unicode BIFF_DCON_INTERN = '\x02'; /// First character of an encoded sheet name from DCON* records.
+
+
+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_Int64 >( nCount, 0, rStrm.getRemaining() / 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_Int64 >( nCount, 0, rStrm.getRemaining() / 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 ),
+ mbColOverflow( false ),
+ mbRowOverflow( false ),
+ mbTabOverflow( false )
+{
+ maDConChars.set( 0xFFFF, '\x01', 0xFFFF, '\x02', 0xFFFF );
+ 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 );
+ maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
+ break;
+ case BIFF3:
+ initializeMaxPos( BIFF3_MAXTAB, BIFF3_MAXCOL, BIFF3_MAXROW );
+ maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
+ break;
+ case BIFF4:
+ initializeMaxPos( BIFF4_MAXTAB, BIFF4_MAXCOL, BIFF4_MAXROW );
+ maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, '\x00' );
+ break;
+ case BIFF5:
+ initializeMaxPos( BIFF5_MAXTAB, BIFF5_MAXCOL, BIFF5_MAXROW );
+ maLinkChars.set( '\x04', '\x01', '\x02', '\x03', '\x00' );
+ break;
+ case BIFF8:
+ initializeMaxPos( BIFF8_MAXTAB, BIFF8_MAXCOL, BIFF8_MAXROW );
+ maLinkChars.set( '\x04', '\x01', 0xFFFF, '\x02', '\x00' );
+ 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
+
+BiffTargetType AddressConverter::parseBiffTargetUrl(
+ OUString& orClassName, OUString& orTargetUrl, OUString& orSheetName,
+ const OUString& rBiffTargetUrl, bool bFromDConRec )
+{
+ OUStringBuffer aTargetUrl;
+ OUStringBuffer aSheetName;
+ // default target type: some URL with/without sheet name, may be overridden below
+ BiffTargetType eTargetType = BIFF_TARGETTYPE_URL;
+ const ControlCharacters& rCChars = bFromDConRec ? maDConChars : maLinkChars;
+
+ 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 )
+ {
+ sal_Unicode cChar = *pcChar;
+ switch( eState )
+ {
+ case STATE_START:
+ if( (cChar == rCChars.mcThisWorkbook) || (cChar == rCChars.mcThisSheet) || (cChar == rCChars.mcSameSheet) )
+ {
+ if( pcChar + 1 < pcEnd )
+ eState = STATE_ERROR;
+ if( cChar == rCChars.mcSameSheet )
+ eTargetType = BIFF_TARGETTYPE_SAMESHEET;
+ }
+ else if( cChar == rCChars.mcExternal )
+ eState = (pcChar + 1 < pcEnd) ? STATE_ENCODED_PATH_START : STATE_ERROR;
+ else if( cChar == rCChars.mcInternal )
+ 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_LIBRARY )
+ {
+ eState = STATE_ENCODED_PATH;
+ eTargetType = BIFF_TARGETTYPE_LIBRARY;
+ }
+ 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 = bFromDConRec ? STATE_ERROR : STATE_DDE_OLE;
+ eTargetType = BIFF_TARGETTYPE_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;
+ }
+ }
+
+ OSL_ENSURE( (eState != STATE_ERROR) && (pcChar == pcEnd),
+ OStringBuffer( "AddressConverter::parseBiffTargetUrl - parser error in target \"" ).
+ append( OUStringToOString( rBiffTargetUrl, RTL_TEXTENCODING_UTF8 ) ).append( '"' ).getStr() );
+ bool bParserOk = (eState != STATE_ERROR) && (eState != STATE_UNSUPPORTED) && (pcChar == pcEnd);
+
+ if( bParserOk )
+ {
+ orTargetUrl = aTargetUrl.makeStringAndClear();
+ orSheetName = aSheetName.makeStringAndClear();
+ }
+ else
+ {
+ orClassName = orTargetUrl = orSheetName = OUString();
+ }
+
+ return bParserOk ? eTargetType : BIFF_TARGETTYPE_UNKNOWN;
+}
+
+// ----------------------------------------------------------------------------
+
+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::convertToCellAddressUnchecked( 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
+ convertToCellAddressUnchecked( 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::convertToCellAddressUnchecked( 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 )
+{
+ convertToCellAddressUnchecked( 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 bAllowOverflow, bool bTrackOverflow )
+{
+ return
+ (checkCol( rRange.EndColumn, bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkCol to track overflow!
+ (checkRow( rRange.EndRow, bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkRow to track overflow!
+ checkTab( rRange.Sheet, bTrackOverflow ) &&
+ checkCol( rRange.StartColumn, bTrackOverflow ) &&
+ checkRow( rRange.StartRow, bTrackOverflow );
+}
+
+bool AddressConverter::validateCellRange( CellRangeAddress& orRange, bool bAllowOverflow, 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, bAllowOverflow, 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 bAllowOverflow, bool bTrackOverflow )
+{
+ return
+ convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
+ validateCellRange( orRange, bAllowOverflow, 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 bAllowOverflow, bool bTrackOverflow )
+{
+ convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
+ return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
+}
+
+// ----------------------------------------------------------------------------
+
+bool AddressConverter::checkCellRangeList( const ApiCellRangeList& rRanges, bool bAllowOverflow, bool bTrackOverflow )
+{
+ for( ApiCellRangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt )
+ if( !checkCellRange( *aIt, bAllowOverflow, 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 ], true, 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, true, 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, true, bTrackOverflow ) )
+ orRanges.push_back( aRange );
+}
+
+// private --------------------------------------------------------------------
+
+void AddressConverter::ControlCharacters::set(
+ sal_Unicode cThisWorkbook, sal_Unicode cExternal,
+ sal_Unicode cThisSheet, sal_Unicode cInternal, sal_Unicode cSameSheet )
+{
+ mcThisWorkbook = cThisWorkbook;
+ mcExternal = cExternal;
+ mcThisSheet = cThisSheet;
+ mcInternal = cInternal;
+ mcSameSheet = cSameSheet;
+}
+
+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" );
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/autofiltercontext.cxx b/oox/source/xls/autofiltercontext.cxx
new file mode 100644
index 000000000000..ccf3f880c7f9
--- /dev/null
+++ b/oox/source/xls/autofiltercontext.cxx
@@ -0,0 +1,777 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/autofiltercontext.hxx"
+#include <rtl/ustrbuf.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/i18n/XLocaleData.hpp>
+#include "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/addressconverter.hxx"
+
+#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 ::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::Locale;
+using ::oox::core::ContextHandlerRef;
+
+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( OoxWorksheetFragmentBase& rFragment ) :
+ OoxWorksheetContextBase( rFragment ),
+ mbValidAddress( false ),
+ mbUseRegex( false ),
+ mbShowBlank( false ),
+ mbConnectionAnd( false )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxAutoFilterContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( autoFilter ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( filterColumn ): return this;
+ }
+ break;
+
+ case XLS_TOKEN( filterColumn ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( filters ):
+ case XLS_TOKEN( customFilters ):
+ case XLS_TOKEN( top10 ):
+ case XLS_TOKEN( dynamicFilter ): return this;
+ }
+ break;
+
+ case XLS_TOKEN( filters ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( filter ): return this;
+ }
+ break;
+
+ case XLS_TOKEN( customFilters ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( customFilter ): return this;
+ }
+ break;
+ }
+ return 0;
+}
+
+void OoxAutoFilterContext::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ 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( getCurrentElement() )
+ {
+ 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 = getDatabaseRanges();
+ 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( PROP_AutoFilter, true );
+ }
+
+ sal_Int32 nSize = maFields.size();
+ sal_Int32 nMaxFieldCount = nSize;
+ Reference< XSheetFilterDescriptor > xDescriptor = xDB->getFilterDescriptor();
+ if ( xDescriptor.is() )
+ {
+ PropertySet aProp( xDescriptor );
+ aProp.setProperty( PROP_ContainsHeader, true );
+ aProp.setProperty( PROP_UseRegularExpressions, mbUseRegex );
+ aProp.getProperty( nMaxFieldCount, PROP_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();
+
+ ::std::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);
+ ::std::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);
+ ::std::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;
+ }
+
+ ::std::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, OUString() ), getSheetIndex(), true, 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, OUString() );
+ 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< XLocaleData > xLocale( getGlobalFactory()->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, OUString() );
+ 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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/biffcodec.cxx b/oox/source/xls/biffcodec.cxx
new file mode 100644
index 000000000000..a5ba02204d2e
--- /dev/null
+++ b/oox/source/xls/biffcodec.cxx
@@ -0,0 +1,336 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffcodec.hxx"
+#include <osl/thread.h>
+#include <string.h>
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OStringToOUString;
+using ::oox::core::FilterBase;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+BiffDecoderBase::BiffDecoderBase() :
+ mbValid( false )
+{
+}
+
+BiffDecoderBase::~BiffDecoderBase()
+{
+}
+
+::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyPassword( const OUString& rPassword )
+{
+ mbValid = implVerify( rPassword );
+ return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+}
+
+void BiffDecoderBase::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes )
+{
+ if( pnDestData && pnSrcData && (nBytes > 0) )
+ {
+ if( mbValid )
+ implDecode( pnDestData, pnSrcData, nStreamPos, nBytes );
+ else
+ memcpy( pnDestData, pnSrcData, nBytes );
+ }
+}
+
+// ============================================================================
+
+BiffDecoder_XOR::BiffDecoder_XOR( sal_uInt16 nKey, sal_uInt16 nHash ) :
+ maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL ),
+ maPassword( 16 ),
+ mnKey( nKey ),
+ mnHash( nHash )
+{
+}
+
+BiffDecoder_XOR::BiffDecoder_XOR( const BiffDecoder_XOR& rDecoder ) :
+ BiffDecoderBase(), // must be called to prevent compiler warning
+ maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL ),
+ maPassword( rDecoder.maPassword ),
+ mnKey( rDecoder.mnKey ),
+ mnHash( rDecoder.mnHash )
+{
+ if( isValid() )
+ maCodec.initKey( &maPassword.front() );
+}
+
+BiffDecoder_XOR* BiffDecoder_XOR::implClone()
+{
+ return new BiffDecoder_XOR( *this );
+}
+
+bool BiffDecoder_XOR::implVerify( const OUString& rPassword )
+{
+ /* Convert password to a byte string. TODO: this needs some finetuning
+ according to the spec... */
+ OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() );
+ sal_Int32 nLen = aBytePassword.getLength();
+ if( (0 < nLen) && (nLen < 16) )
+ {
+ // copy byte string to sal_uInt8 array
+ maPassword.clear();
+ maPassword.resize( 16, 0 );
+ memcpy( &maPassword.front(), aBytePassword.getStr(), static_cast< size_t >( nLen ) );
+
+ // init codec
+ maCodec.initKey( &maPassword.front() );
+ return maCodec.verifyKey( mnKey, mnHash );
+ }
+ return false;
+}
+
+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( sal_uInt8 pnSalt[ 16 ], sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) :
+ maPassword( 16, 0 ),
+ maSalt( pnSalt, pnSalt + 16 ),
+ maVerifier( pnVerifier, pnVerifier + 16 ),
+ maVerifierHash( pnVerifierHash, pnVerifierHash + 16 )
+{
+}
+
+BiffDecoder_RCF::BiffDecoder_RCF( const BiffDecoder_RCF& rDecoder ) :
+ BiffDecoderBase(), // must be called to prevent compiler warning
+ maPassword( rDecoder.maPassword ),
+ maSalt( rDecoder.maSalt ),
+ maVerifier( rDecoder.maVerifier ),
+ maVerifierHash( rDecoder.maVerifierHash )
+{
+ if( isValid() )
+ maCodec.initKey( &maPassword.front(), &maSalt.front() );
+}
+
+BiffDecoder_RCF* BiffDecoder_RCF::implClone()
+{
+ return new BiffDecoder_RCF( *this );
+}
+
+bool BiffDecoder_RCF::implVerify( const OUString& rPassword )
+{
+ sal_Int32 nLen = rPassword.getLength();
+ if( (0 < nLen) && (nLen < 16) )
+ {
+ // copy string to sal_uInt16 array
+ maPassword.clear();
+ maPassword.resize( 16, 0 );
+ const sal_Unicode* pcChar = rPassword.getStr();
+ const sal_Unicode* pcCharEnd = pcChar + nLen;
+ ::std::vector< sal_uInt16 >::iterator aIt = maPassword.begin();
+ for( ; pcChar < pcCharEnd; ++pcChar, ++aIt )
+ *aIt = static_cast< sal_uInt16 >( *pcChar );
+
+ // init codec
+ maCodec.initKey( &maPassword.front(), &maSalt.front() );
+ return maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() );
+ }
+ return false;
+}
+
+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 {
+
+const sal_uInt16 BIFF_FILEPASS_XOR = 0;
+const sal_uInt16 BIFF_FILEPASS_RCF = 1;
+
+const sal_uInt16 BIFF_FILEPASS_BIFF8_RCF = 1;
+const sal_uInt16 BIFF_FILEPASS_BIFF8_CRYPTOAPI_2003 = 2;
+const sal_uInt16 BIFF_FILEPASS_BIFF8_CRYPTOAPI_2007 = 3;
+
+// ----------------------------------------------------------------------------
+
+BiffDecoderRef lclReadFilePass_XOR( BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+ OSL_ENSURE( rStrm.getRemaining() == 4, "lclReadFilePass_XOR - wrong record size" );
+ if( rStrm.getRemaining() == 4 )
+ {
+ sal_uInt16 nBaseKey, nHash;
+ rStrm >> nBaseKey >> nHash;
+ xDecoder.reset( new BiffDecoder_XOR( nBaseKey, nHash ) );
+ }
+ return xDecoder;
+}
+
+BiffDecoderRef lclReadFilePass_RCF( BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+ OSL_ENSURE( rStrm.getRemaining() == 48, "lclReadFilePass_RCF - wrong record size" );
+ if( rStrm.getRemaining() == 48 )
+ {
+ sal_uInt8 pnSalt[ 16 ];
+ sal_uInt8 pnVerifier[ 16 ];
+ sal_uInt8 pnVerifierHash[ 16 ];
+ rStrm.readMemory( pnSalt, 16 );
+ rStrm.readMemory( pnVerifier, 16 );
+ rStrm.readMemory( pnVerifierHash, 16 );
+ xDecoder.reset( new BiffDecoder_RCF( pnSalt, pnVerifier, pnVerifierHash ) );
+ }
+ return xDecoder;
+}
+
+BiffDecoderRef lclReadFilePass_CryptoApi( BiffInputStream& /*rStrm*/ )
+{
+ // not supported
+ return BiffDecoderRef();
+}
+
+BiffDecoderRef lclReadFilePassBiff8( BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+ switch( rStrm.readuInt16() )
+ {
+ case BIFF_FILEPASS_XOR:
+ xDecoder = lclReadFilePass_XOR( rStrm );
+ break;
+
+ case BIFF_FILEPASS_RCF:
+ {
+ sal_uInt16 nMajor = rStrm.readuInt16();
+ rStrm.skip( 2 );
+ switch( nMajor )
+ {
+ case BIFF_FILEPASS_BIFF8_RCF:
+ xDecoder = lclReadFilePass_RCF( rStrm );
+ break;
+ case BIFF_FILEPASS_BIFF8_CRYPTOAPI_2003:
+ case BIFF_FILEPASS_BIFF8_CRYPTOAPI_2007:
+ xDecoder = lclReadFilePass_CryptoApi( rStrm );
+ break;
+ default:
+ OSL_ENSURE( false, "lclReadFilePassBiff8 - unknown BIFF8 encryption sub mode" );
+ }
+ }
+ break;
+
+ default:
+ OSL_ENSURE( false, "lclReadFilePassBiff8 - unknown encryption mode" );
+ }
+ return xDecoder;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+BiffCodecHelper::BiffCodecHelper( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+/*static*/ BiffDecoderRef BiffCodecHelper::implReadFilePass( BiffInputStream& rStrm, BiffType eBiff )
+{
+ rStrm.enableDecoder( false );
+ BiffDecoderRef xDecoder = (eBiff == BIFF8) ? lclReadFilePassBiff8( rStrm ) : lclReadFilePass_XOR( rStrm );
+ rStrm.setDecoder( xDecoder );
+ return xDecoder;
+}
+
+bool BiffCodecHelper::importFilePass( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !mxDecoder, "BiffCodecHelper::importFilePass - multiple FILEPASS records" );
+ mxDecoder = implReadFilePass( rStrm, getBiff() );
+ // request and verify a password (decoder implements IDocPasswordVerifier)
+ if( mxDecoder.get() )
+ getBaseFilter().requestPassword( *mxDecoder );
+ // correct password is indicated by isValid() function of decoder
+ return mxDecoder.get() && mxDecoder->isValid();
+}
+
+void BiffCodecHelper::cloneDecoder( BiffInputStream& rStrm )
+{
+ if( mxDecoder.get() )
+ rStrm.setDecoder( BiffDecoderRef( mxDecoder->clone() ) );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/biffdetector.cxx b/oox/source/xls/biffdetector.cxx
new file mode 100644
index 000000000000..8bb708d3b415
--- /dev/null
+++ b/oox/source/xls/biffdetector.cxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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/ole/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.isEof() && rInStream.isSeekable() && (rInStream.getLength() > 4) )
+ {
+ sal_Int64 nOldPos = rInStream.tell();
+ rInStream.seekToStart();
+ 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
+ BinaryXInputStream aBookStrm5( xStorage->openInputStream( saBookName ), true );
+ BiffType eBookStrm5Biff = detectStreamBiffVersion( aBookStrm5 );
+
+ // try to open the "Workbook" stream
+ BinaryXInputStream 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+)
+ BinaryXInputStream 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 ::oox::ole::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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/biffhelper.cxx b/oox/source/xls/biffhelper.cxx
new file mode 100644
index 000000000000..ad790fc9f2e9
--- /dev/null
+++ b/oox/source/xls/biffhelper.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffhelper.hxx"
+#include <rtl/math.hxx>
+#include <rtl/tencinfo.h>
+#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 {
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 BIFF_RK_100FLAG = 0x00000001;
+const sal_Int32 BIFF_RK_INTFLAG = 0x00000002;
+const sal_Int32 BIFF_RK_VALUEMASK = 0xFFFFFFFC;
+
+const sal_Int32 BITMAPFILEHEADER_SIZE = 14;
+const sal_Int32 BITMAPCOREHEADER_SIZE = 12;
+const sal_Int32 BITMAPINFOHEADER_SIZE = 40;
+
+const sal_uInt16 BIFF_IMGDATA_WMF = 2;
+const sal_uInt16 BIFF_IMGDATA_DIB = 9;
+const sal_uInt16 BIFF_IMGDATA_NATIVE = 14;
+
+// ----------------------------------------------------------------------------
+
+union DecodedDouble
+{
+ double mfValue;
+ sal_math_Double maStruct;
+
+ inline explicit DecodedDouble() {}
+ inline explicit DecodedDouble( double fValue ) : mfValue( fValue ) {}
+};
+
+bool lclCalcRkFromDouble( sal_Int32& ornRkValue, const DecodedDouble& rDecDbl )
+{
+ // double
+ if( (rDecDbl.maStruct.w32_parts.lsw == 0) && ((rDecDbl.maStruct.w32_parts.msw & 0x3) == 0) )
+ {
+ ornRkValue = static_cast< sal_Int32 >( rDecDbl.maStruct.w32_parts.msw );
+ return true;
+ }
+
+ // integer
+ double fInt = 0.0;
+ double fFrac = modf( rDecDbl.mfValue, &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;
+}
+
+bool lclCalcRkFromDouble( sal_Int32& ornRkValue, double fValue )
+{
+ DecodedDouble aDecDbl( fValue );
+ if( lclCalcRkFromDouble( ornRkValue, aDecDbl ) )
+ return true;
+
+ aDecDbl.mfValue *= 100.0;
+ if( lclCalcRkFromDouble( ornRkValue, aDecDbl ) )
+ {
+ ornRkValue |= BIFF_RK_100FLAG;
+ return true;
+ }
+
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+void lclImportImgDataDib( StreamDataSequence& orDataSeq, BiffInputStream& rStrm, sal_Int32 nBytes, BiffType eBiff )
+{
+ /* The IMGDATA record for bitmap format contains a Windows DIB (a bitmap
+ file without the 'BITMAPFILEHEADER' header structure). Usually, the DIB
+ header consists of 12 bytes (called 'OS/2 V1 header' or
+ 'BITMAPCOREHEADER', see http://en.wikipedia.org/wiki/BMP_file_format)
+ followed by the remaining pixel data, but the 'Windows V3' or
+ 'BITMAPINFOHEADER' is also supported here. This function creates a
+ complete 'BMP file' that can be read by the OOo graphic provider used
+ to import graphic objects. For that, the BITMAPFILEHEADER has to be
+ inserted before the DIB data, and it has to contain the correct offset
+ to the pixel data. Currently, in real life there are only 24-bit and
+ 32-bit DIBs (without color palette) in use. This code relies on this
+ fact and calculates the offset to the pixel data according to the size
+ of the DIB header.
+ Remaining tasks are (if really used somewhere):
+ - Support of DIBs with color palette,
+ - Support of 'Windows V4' and 'Windows V5' DIB header. */
+
+ // read and check validity of DIB header
+ sal_Int64 nInStrmPos = rStrm.tell();
+ sal_Int32 nDibHdrSize = rStrm.readInt32();
+ sal_uInt16 nPlanes = 0, nDepth = 0;
+ switch( nDibHdrSize )
+ {
+ case BITMAPCOREHEADER_SIZE:
+ rStrm.skip( 4 ); // width/height as 16-bit integer
+ rStrm >> nPlanes >> nDepth;
+ break;
+ case BITMAPINFOHEADER_SIZE:
+ rStrm.skip( 8 ); // width/height as 32-bit integer
+ rStrm >> nPlanes >> nDepth;
+ break;
+ }
+ rStrm.seek( nInStrmPos );
+
+ if( (nPlanes == 1) && ((nDepth == 24) || (nDepth == 32)) )
+ {
+ // allocate enough space for the BITMAPFILEHEADER and the DIB data
+ orDataSeq.realloc( BITMAPFILEHEADER_SIZE + nBytes );
+ SequenceOutputStream aOutStrm( orDataSeq );
+
+ // write the BITMAPFILEHEADER of a regular BMP file
+ sal_Int32 nBmpSize = BITMAPFILEHEADER_SIZE + nBytes;
+ sal_Int32 nOffset = BITMAPFILEHEADER_SIZE + nDibHdrSize;
+ aOutStrm << sal_uInt16( 0x4D42 ) << nBmpSize << sal_Int32( 0 ) << nOffset;
+
+ // copy the DIB header
+ rStrm.copyToStream( aOutStrm, nDibHdrSize );
+ nBytes -= nDibHdrSize;
+
+ /* Excel 3.x and Excel 4.x seem to write broken or out-dated DIB data.
+ Usually they write a BITMAPCOREHEADER containing width, height,
+ planes as usual. The pixel depth field is set to 32 bit (though
+ this is not allowed according to documentation). Between that
+ header and the actual pixel data, 3 unused bytes are inserted. This
+ does even confuse Excel 5.x and later, which cannot read the image
+ data correctly. */
+ if( (eBiff <= BIFF4) && (nDibHdrSize == BITMAPCOREHEADER_SIZE) && (nDepth == 32) )
+ {
+ // skip the dummy bytes in input stream
+ rStrm.skip( 3 );
+ nBytes -= 3;
+ // correct the total BMP file size in output stream
+ sal_Int64 nOutStrmPos = aOutStrm.tell();
+ aOutStrm.seek( 2 );
+ aOutStrm << sal_Int32( nBmpSize - 3 );
+ aOutStrm.seek( nOutStrmPos );
+ }
+
+ // copy remaining pixel data to output stream
+ rStrm.copyToStream( aOutStrm, nBytes );
+ }
+ rStrm.seek( nInStrmPos + nBytes );
+}
+
+} // namespace
+
+// ============================================================================
+
+/*static*/ double BiffHelper::calcDoubleFromRk( sal_Int32 nRkValue )
+{
+ DecodedDouble aDecDbl( 0.0 );
+ if( getFlag( nRkValue, BIFF_RK_INTFLAG ) )
+ {
+ sal_Int32 nTemp = nRkValue >> 2;
+ setFlag< sal_Int32 >( nTemp, 0xE0000000, nRkValue < 0 );
+ aDecDbl.mfValue = nTemp;
+ }
+ else
+ {
+ aDecDbl.maStruct.w32_parts.msw = static_cast< sal_uInt32 >( nRkValue & BIFF_RK_VALUEMASK );
+ }
+
+ if( getFlag( nRkValue, BIFF_RK_100FLAG ) )
+ aDecDbl.mfValue /= 100.0;
+
+ return aDecDbl.mfValue;
+}
+
+/*static*/ 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;
+}
+
+/*static*/ 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" );
+ }
+ DecodedDouble aDecDbl;
+ ::rtl::math::setNan( &aDecDbl.mfValue );
+ aDecDbl.maStruct.nan_parts.fraction_lo = nApiError;
+ return aDecDbl.mfValue;
+}
+
+/*static*/ rtl_TextEncoding BiffHelper::calcTextEncodingFromCodePage( sal_uInt16 nCodePage )
+{
+ // some specials for BIFF
+ switch( nCodePage )
+ {
+ case 1200: return RTL_TEXTENCODING_DONTKNOW; // BIFF8 Unicode
+ case 32768: return RTL_TEXTENCODING_APPLE_ROMAN;
+ case 32769: return RTL_TEXTENCODING_MS_1252; // BIFF2-BIFF3
+ }
+
+ rtl_TextEncoding eTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
+ OSL_ENSURE( eTextEnc != RTL_TEXTENCODING_DONTKNOW, "BiffHelper::calcTextEncodingFromCodePage - unknown code page" );
+ return eTextEnc;
+}
+
+/*static*/ sal_uInt16 BiffHelper::calcCodePageFromTextEncoding( rtl_TextEncoding eTextEnc )
+{
+ sal_uInt32 nCodePage = rtl_getWindowsCodePageFromTextEncoding( eTextEnc );
+ OSL_ENSURE( (0 < nCodePage) && (nCodePage <= SAL_MAX_UINT16), "BiffHelper::calcCodePageFromTextEncoding - unknown text encoding" );
+ return static_cast< sal_uInt16 >( (nCodePage == 0) ? 1252 : nCodePage );
+}
+
+/*static*/ void BiffHelper::importImgData( StreamDataSequence& orDataSeq, BiffInputStream& rStrm, BiffType eBiff )
+{
+ sal_uInt16 nFormat, nEnv;
+ sal_Int32 nBytes;
+ rStrm >> nFormat >> nEnv >> nBytes;
+ OSL_ENSURE( nBytes > 0, "BiffHelper::importImgData - invalid data size" );
+ if( (0 < nBytes) && (nBytes <= rStrm.getRemaining()) )
+ {
+ switch( nFormat )
+ {
+// case BIFF_IMGDATA_WMF: /* TODO */ break;
+ case BIFF_IMGDATA_DIB: lclImportImgDataDib( orDataSeq, rStrm, nBytes, eBiff ); break;
+// case BIFF_IMGDATA_NATIVE: /* TODO */ break;
+ default: OSL_ENSURE( false, "BiffHelper::importImgData - unknown image format" );
+ }
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/biffinputstream.cxx b/oox/source/xls/biffinputstream.cxx
new file mode 100644
index 000000000000..dd8d5baede5c
--- /dev/null
+++ b/oox/source/xls/biffinputstream.cxx
@@ -0,0 +1,633 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffinputstream.hxx"
+#include <algorithm>
+#include <rtl/ustrbuf.hxx>
+
+using ::rtl::OString;
+using ::rtl::OStringToOUString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+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( const BiffDecoderRef& rxDecoder )
+{
+ mxDecoder = rxDecoder;
+ 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 = !mrInStrm.isEof() && (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;
+}
+
+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.readMemory( &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 ),
+ mbCont( bContLookup )
+{
+ mbEof = true; // EOF will be true if stream is not inside a record
+}
+
+// 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( const BiffDecoderRef& rxDecoder )
+{
+ maRecBuffer.setDecoder( rxDecoder );
+}
+
+void BiffInputStream::enableDecoder( bool bEnable )
+{
+ maRecBuffer.enableDecoder( bEnable );
+}
+
+// stream/record state and info -----------------------------------------------
+
+sal_uInt16 BiffInputStream::getNextRecId()
+{
+ sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
+ if( isInRecord() )
+ {
+ sal_Int64 nCurrPos = tell(); // 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;
+}
+
+// BinaryStreamBase interface (seeking) ---------------------------------------
+
+bool BiffInputStream::isSeekable() const
+{
+ return true;
+}
+
+sal_Int64 BiffInputStream::tell() const
+{
+ return mbEof ? -1 : (mnCurrRecSize - maRecBuffer.getRecLeft());
+}
+
+sal_Int64 BiffInputStream::getLength() const
+{
+ if( !mbHasComplRec )
+ const_cast< BiffInputStream* >( this )->calcRecordLength();
+ return mnComplRecSize;
+}
+
+void BiffInputStream::seek( sal_Int64 nRecPos )
+{
+ if( isInRecord() )
+ {
+ if( mbEof || (nRecPos < tell()) )
+ restartRecord( false );
+ if( !mbEof && (nRecPos > tell()) )
+ skip( static_cast< sal_Int32 >( nRecPos - tell() ) );
+ }
+}
+
+sal_Int64 BiffInputStream::tellBase() const
+{
+ return maRecBuffer.getBaseStream().tell();
+}
+
+sal_Int64 BiffInputStream::getBaseLength() const
+{
+ return maRecBuffer.getBaseStream().getLength();
+}
+
+// BinaryInputStream interface (stream read access) ---------------------------
+
+sal_Int32 BiffInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes )
+{
+ sal_Int32 nRet = 0;
+ if( !mbEof )
+ {
+ orData.realloc( ::std::max< sal_Int32 >( nBytes, 0 ) );
+ if( nBytes > 0 )
+ {
+ nRet = readMemory( orData.getArray(), nBytes );
+ if( nRet < nBytes )
+ orData.realloc( nRet );
+ }
+ }
+ return nRet;
+}
+
+sal_Int32 BiffInputStream::readMemory( void* opMem, sal_Int32 nBytes )
+{
+ sal_Int32 nRet = 0;
+ if( !mbEof && opMem && (nBytes > 0) )
+ {
+ sal_uInt8* pnBuffer = reinterpret_cast< sal_uInt8* >( opMem );
+ sal_Int32 nBytesLeft = nBytes;
+
+ while( !mbEof && (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( !mbEof, "BiffInputStream::readMemory - record overread" );
+ }
+ }
+ return nRet;
+}
+
+void BiffInputStream::skip( sal_Int32 nBytes )
+{
+ sal_Int32 nBytesLeft = nBytes;
+ while( !mbEof && (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( !mbEof, "BiffInputStream::skip - record overread" );
+ }
+}
+
+// byte strings ---------------------------------------------------------------
+
+OString BiffInputStream::readByteString( bool b16BitLen, bool bAllowNulChars )
+{
+ sal_Int32 nStrLen = b16BitLen ? readuInt16() : readuInt8();
+ return readCharArray( nStrLen, bAllowNulChars );
+}
+
+OUString BiffInputStream::readByteStringUC( bool b16BitLen, rtl_TextEncoding eTextEnc, bool bAllowNulChars )
+{
+ return OStringToOUString( readByteString( b16BitLen, bAllowNulChars ), eTextEnc );
+}
+
+void BiffInputStream::skipByteString( bool b16BitLen )
+{
+ skip( b16BitLen ? readuInt16() : readuInt8() );
+}
+
+// Unicode strings ------------------------------------------------------------
+
+OUString BiffInputStream::readUniStringChars( sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars )
+{
+ OUStringBuffer aBuffer;
+ aBuffer.ensureCapacity( nChars );
+
+ /* This function has to react on CONTINUE records to read the repeated
+ flags field, so readUnicodeArray() cannot be used here. */
+ sal_uInt16 nCharsLeft = nChars;
+ while( !mbEof && (nCharsLeft > 0) )
+ {
+ sal_uInt16 nPortionCount = 0;
+ if( b16BitChars )
+ {
+ nPortionCount = ::std::min< sal_uInt16 >( nCharsLeft, maRecBuffer.getRecLeft() / 2 );
+ OSL_ENSURE( (nPortionCount <= nCharsLeft) || ((maRecBuffer.getRecLeft() & 1) == 0),
+ "BiffInputStream::readUniStringChars - missing a byte" );
+ }
+ else
+ {
+ nPortionCount = getMaxRawReadSize( nCharsLeft );
+ }
+
+ // read the character array
+ appendUnicodeArray( aBuffer, nPortionCount, b16BitChars, bAllowNulChars );
+
+ // prepare for next CONTINUE record
+ nCharsLeft = nCharsLeft - nPortionCount;
+ if( nCharsLeft > 0 )
+ jumpToNextStringContinue( b16BitChars );
+ }
+
+ return aBuffer.makeStringAndClear();
+}
+
+OUString BiffInputStream::readUniStringBody( sal_uInt16 nChars, bool bAllowNulChars )
+{
+ bool b16BitChars;
+ sal_Int32 nAddSize;
+ readUniStringHeader( b16BitChars, nAddSize );
+ OUString aString = readUniStringChars( nChars, b16BitChars, bAllowNulChars );
+ skip( nAddSize );
+ return aString;
+}
+
+OUString BiffInputStream::readUniString( bool bAllowNulChars )
+{
+ return readUniStringBody( readuInt16(), bAllowNulChars );
+}
+
+void BiffInputStream::skipUniStringChars( sal_uInt16 nChars, bool b16BitChars )
+{
+ sal_uInt16 nCharsLeft = nChars;
+ while( !mbEof && (nCharsLeft > 0) )
+ {
+ sal_uInt16 nPortionCount;
+ if( b16BitChars )
+ {
+ nPortionCount = ::std::min< sal_uInt16 >( nCharsLeft, maRecBuffer.getRecLeft() / 2 );
+ OSL_ENSURE( (nPortionCount <= nCharsLeft) || ((maRecBuffer.getRecLeft() & 1) == 0),
+ "BiffInputStream::skipUniStringChars - missing a byte" );
+ skip( 2 * nPortionCount );
+ }
+ else
+ {
+ nPortionCount = getMaxRawReadSize( nCharsLeft );
+ skip( nPortionCount );
+ }
+
+ // prepare for next CONTINUE record
+ nCharsLeft = nCharsLeft - nPortionCount;
+ if( nCharsLeft > 0 )
+ jumpToNextStringContinue( b16BitChars );
+ }
+}
+
+void BiffInputStream::skipUniStringBody( sal_uInt16 nChars )
+{
+ bool b16BitChars;
+ sal_Int32 nAddSize;
+ readUniStringHeader( b16BitChars, nAddSize );
+ skipUniStringChars( nChars, b16BitChars );
+ skip( nAddSize );
+}
+
+void BiffInputStream::skipUniString()
+{
+ skipUniStringBody( readuInt16() );
+}
+
+// private --------------------------------------------------------------------
+
+void BiffInputStream::readAtom( void* opMem, sal_uInt8 nSize )
+{
+ // byte swapping is done in calling BinaryInputStream::readValue() template function
+ if( ensureRawReadSize( nSize ) )
+ maRecBuffer.read( opMem, nSize );
+}
+
+void BiffInputStream::setupRecord()
+{
+ // initialize class members
+ mnRecHandle = maRecBuffer.getRecHeaderPos();
+ mnRecId = maRecBuffer.getRecId();
+ mnAltContId = BIFF_ID_UNKNOWN;
+ mnCurrRecSize = mnComplRecSize = maRecBuffer.getRecSize();
+ mbHasComplRec = !mbCont;
+ mbEof = !isInRecord();
+ // 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;
+ }
+ mbEof = false;
+ }
+}
+
+void BiffInputStream::rewindToRecord( sal_Int64 nRecHandle )
+{
+ if( nRecHandle >= 0 )
+ {
+ maRecBuffer.restartAt( nRecHandle );
+ mnRecHandle = -1;
+ mbEof = true; // as long as the record is not started
+ }
+}
+
+bool BiffInputStream::isContinueId( sal_uInt16 nRecId ) const
+{
+ return (nRecId == BIFF_ID_CONT) || (nRecId == mnAltContId);
+}
+
+bool BiffInputStream::jumpToNextContinue()
+{
+ mbEof = mbEof || !mbCont || !isContinueId( maRecBuffer.getNextRecId() ) || !maRecBuffer.startNextRecord();
+ if( !mbEof )
+ mnCurrRecSize += maRecBuffer.getRecSize();
+ return !mbEof;
+}
+
+bool BiffInputStream::jumpToNextStringContinue( bool& rb16BitChars )
+{
+ OSL_ENSURE( maRecBuffer.getRecLeft() == 0, "BiffInputStream::jumpToNextStringContinue - unexpected garbage" );
+
+ if( mbCont && (getRemaining() > 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. */
+ mbEof = mbEof || (maRecBuffer.getNextRecId() != BIFF_ID_CONT) || !maRecBuffer.startNextRecord();
+ if( !mbEof )
+ setupRecord();
+ }
+
+ // trying to read the flags invalidates stream, if no CONTINUE record has been found
+ sal_uInt8 nFlags;
+ readValue( nFlags );
+ rb16BitChars = getFlag( nFlags, BIFF_STRF_16BIT );
+ return !mbEof;
+}
+
+void BiffInputStream::calcRecordLength()
+{
+ sal_Int64 nCurrPos = tell(); // save current position in record
+ while( jumpToNextContinue() ) {} // jumpToNextContinue() adds up mnCurrRecSize
+ mnComplRecSize = mnCurrRecSize;
+ mbHasComplRec = true;
+ seek( nCurrPos ); // restore position, seek() resets old mbValid state
+}
+
+bool BiffInputStream::ensureRawReadSize( sal_uInt16 nBytes )
+{
+ if( !mbEof && (nBytes > 0) )
+ {
+ while( !mbEof && (maRecBuffer.getRecLeft() == 0) ) jumpToNextContinue();
+ mbEof = mbEof || (nBytes > maRecBuffer.getRecLeft());
+ OSL_ENSURE( !mbEof, "BiffInputStream::ensureRawReadSize - record overread" );
+ }
+ return !mbEof;
+}
+
+sal_uInt16 BiffInputStream::getMaxRawReadSize( sal_Int32 nBytes ) const
+{
+ return getLimitedValue< sal_uInt16, sal_Int32 >( nBytes, 0, maRecBuffer.getRecLeft() );
+}
+
+void BiffInputStream::appendUnicodeArray( OUStringBuffer& orBuffer, sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars )
+{
+ orBuffer.ensureCapacity( orBuffer.getLength() + nChars );
+ sal_uInt16 nChar;
+ for( sal_uInt16 nCharIdx = 0; !mbEof && (nCharIdx < nChars); ++nCharIdx )
+ {
+ if( b16BitChars ) readValue( nChar ); else nChar = readuInt8();
+ orBuffer.append( static_cast< sal_Unicode >( (!bAllowNulChars && (nChar == 0)) ? '?' : nChar ) );
+ }
+}
+
+void BiffInputStream::readUniStringHeader( bool& orb16BitChars, sal_Int32& ornAddSize )
+{
+ sal_uInt8 nFlags = readuInt8();
+ OSL_ENSURE( !getFlag( nFlags, BIFF_STRF_UNKNOWN ), "BiffInputStream::readUniStringHeader - unknown flags" );
+ orb16BitChars = getFlag( nFlags, BIFF_STRF_16BIT );
+ sal_uInt16 nFontCount = getFlag( nFlags, BIFF_STRF_RICH ) ? readuInt16() : 0;
+ sal_Int32 nPhoneticSize = getFlag( nFlags, BIFF_STRF_PHONETIC ) ? readInt32() : 0;
+ ornAddSize = 4 * nFontCount + ::std::max< sal_Int32 >( 0, nPhoneticSize );
+}
+
+// ============================================================================
+
+BiffInputStreamPos::BiffInputStreamPos( BiffInputStream& rStrm ) :
+ mrStrm( rStrm ),
+ mnRecHandle( rStrm.getRecHandle() ),
+ mnRecPos( rStrm.tell() )
+{
+}
+
+bool BiffInputStreamPos::restorePosition()
+{
+ bool bValidRec = mrStrm.startRecordByHandle( mnRecHandle );
+ if( bValidRec )
+ mrStrm.seek( mnRecPos );
+ return bValidRec && !mrStrm.isEof();
+}
+
+// ============================================================================
+
+BiffInputStreamPosGuard::BiffInputStreamPosGuard( BiffInputStream& rStrm ) :
+ BiffInputStreamPos( rStrm )
+{
+}
+
+BiffInputStreamPosGuard::~BiffInputStreamPosGuard()
+{
+ restorePosition();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/biffoutputstream.cxx b/oox/source/xls/biffoutputstream.cxx
new file mode 100644
index 000000000000..5e87e683e075
--- /dev/null
+++ b/oox/source/xls/biffoutputstream.cxx
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffoutputstream.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.writeMemory( &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 )
+{
+}
+
+// record control -------------------------------------------------------------
+
+void BiffOutputStream::startRecord( sal_uInt16 nRecId )
+{
+ maRecBuffer.startRecord( nRecId );
+ setPortionSize( 0 );
+}
+
+void BiffOutputStream::endRecord()
+{
+ setPortionSize( 0 );
+ maRecBuffer.endRecord();
+}
+
+void BiffOutputStream::setPortionSize( sal_uInt16 nSize )
+{
+ OSL_ENSURE( mnPortionPos == 0, "BiffOutputStream::setPortionSize - block operation inside portion" );
+ mnPortionSize = nSize;
+ mnPortionPos = 0;
+}
+
+// BinaryStreamBase interface (seeking) ---------------------------------------
+
+sal_Int64 BiffOutputStream::tellBase() const
+{
+ return maRecBuffer.getBaseStream().tell();
+}
+
+sal_Int64 BiffOutputStream::getBaseLength() const
+{
+ return maRecBuffer.getBaseStream().getLength();
+}
+
+// BinaryOutputStream interface (stream write access) -------------------------
+
+void BiffOutputStream::writeData( const StreamDataSequence& rData )
+{
+ if( rData.hasElements() )
+ writeMemory( rData.getConstArray(), rData.getLength() );
+}
+
+void BiffOutputStream::writeMemory( const void* pMem, sal_Int32 nBytes )
+{
+ if( pMem && (nBytes > 0) )
+ {
+ const sal_uInt8* pnBuffer = reinterpret_cast< const sal_uInt8* >( pMem );
+ sal_Int32 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_Int32 nBytes )
+{
+ sal_Int32 nBytesLeft = nBytes;
+ while( nBytesLeft > 0 )
+ {
+ sal_uInt16 nBlockSize = prepareRawBlock( nBytesLeft );
+ maRecBuffer.fill( nValue, nBlockSize );
+ nBytesLeft -= nBlockSize;
+ }
+}
+
+void BiffOutputStream::writeBlock( const void* pMem, sal_uInt16 nBytes )
+{
+ ensureRawBlock( nBytes );
+ maRecBuffer.write( pMem, nBytes );
+}
+
+// private --------------------------------------------------------------------
+
+void BiffOutputStream::writeAtom( const void* pMem, sal_uInt8 nSize )
+{
+ // byte swapping is done in calling BinaryOutputStream::writeValue() template function
+ writeBlock( pMem, nSize );
+}
+
+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, "BiffOutputStream::ensureRawBlock - portion overflow" );
+ mnPortionPos = (mnPortionPos + nSize) % mnPortionSize; // prevent compiler warning, do not use operator+=, operator%=
+ }
+}
+
+sal_uInt16 BiffOutputStream::prepareRawBlock( sal_Int32 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_Int32 >( nTotalSize, 0, nRecLeft );
+ ensureRawBlock( nSize );
+ return nSize;
+}
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/chartsheetfragment.cxx b/oox/source/xls/chartsheetfragment.cxx
new file mode 100644
index 000000000000..61fc356b5ec5
--- /dev/null
+++ b/oox/source/xls/chartsheetfragment.cxx
@@ -0,0 +1,294 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/chartsheetfragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/pagesettings.hxx"
+#include "oox/xls/viewsettings.hxx"
+#include "oox/xls/workbooksettings.hxx"
+#include "oox/xls/worksheetsettings.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxChartsheetFragment::OoxChartsheetFragment( const WorkbookHelper& rHelper,
+ const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, sal_Int16 nSheet ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath, xProgressBar, SHEETTYPE_CHARTSHEET, nSheet )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxChartsheetFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( chartsheet ) ) return this;
+ break;
+
+ case XLS_TOKEN( chartsheet ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( sheetViews ): return this;
+
+ case XLS_TOKEN( sheetPr ): getWorksheetSettings().importChartSheetPr( rAttribs ); break;
+ case XLS_TOKEN( sheetProtection ): getWorksheetSettings().importChartProtection( rAttribs ); break;
+ case XLS_TOKEN( pageMargins ): getPageSettings().importPageMargins( rAttribs ); break;
+ case XLS_TOKEN( pageSetup ): getPageSettings().importChartPageSetup( getRelations(), rAttribs ); break;
+ case XLS_TOKEN( headerFooter ): getPageSettings().importHeaderFooter( rAttribs ); return this;
+ case XLS_TOKEN( picture ): getPageSettings().importPicture( getRelations(), rAttribs ); break;
+ case XLS_TOKEN( drawing ): importDrawing( rAttribs ); break;
+ }
+ break;
+
+ case XLS_TOKEN( sheetViews ):
+ if( nElement == XLS_TOKEN( sheetView ) ) getSheetViewSettings().importChartSheetView( rAttribs );
+ break;
+
+ case XLS_TOKEN( headerFooter ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( firstHeader ):
+ case XLS_TOKEN( firstFooter ):
+ case XLS_TOKEN( oddHeader ):
+ case XLS_TOKEN( oddFooter ):
+ case XLS_TOKEN( evenHeader ):
+ case XLS_TOKEN( evenFooter ): return this; // collect contents in onEndElement()
+ }
+ break;
+ }
+ return 0;
+}
+
+void OoxChartsheetFragment::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentElement() )
+ {
+ 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, getCurrentElement() );
+ break;
+ }
+}
+
+ContextHandlerRef OoxChartsheetFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_WORKSHEET ) return this;
+ break;
+
+ case OOBIN_ID_WORKSHEET:
+ switch( nRecId )
+ {
+ case OOBIN_ID_CHARTSHEETVIEWS: return this;
+
+ case OOBIN_ID_CHARTSHEETPR: getWorksheetSettings().importChartSheetPr( rStrm ); break;
+ case OOBIN_ID_CHARTPROTECTION: getWorksheetSettings().importChartProtection( rStrm ); break;
+ case OOBIN_ID_PAGEMARGINS: getPageSettings().importPageMargins( rStrm ); break;
+ case OOBIN_ID_CHARTPAGESETUP: getPageSettings().importChartPageSetup( getRelations(), rStrm ); break;
+ case OOBIN_ID_HEADERFOOTER: getPageSettings().importHeaderFooter( rStrm ); break;
+ case OOBIN_ID_PICTURE: getPageSettings().importPicture( getRelations(), rStrm ); break;
+ case OOBIN_ID_DRAWING: importDrawing( rStrm ); break;
+ }
+ break;
+
+ case OOBIN_ID_CHARTSHEETVIEWS:
+ if( nRecId == OOBIN_ID_CHARTSHEETVIEW ) getSheetViewSettings().importChartSheetView( rStrm );
+ break;
+ }
+ return 0;
+}
+
+// oox.core.FragmentHandler2 interface ----------------------------------------
+
+const RecordInfo* OoxChartsheetFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_CHARTSHEETVIEW, OOBIN_ID_CHARTSHEETVIEW + 1 },
+ { OOBIN_ID_CHARTSHEETVIEWS, OOBIN_ID_CHARTSHEETVIEWS + 1 },
+ { OOBIN_ID_CUSTOMCHARTVIEW, OOBIN_ID_CUSTOMCHARTVIEW + 1 },
+ { OOBIN_ID_CUSTOMCHARTVIEWS, OOBIN_ID_CUSTOMCHARTVIEWS + 1 },
+ { OOBIN_ID_HEADERFOOTER, OOBIN_ID_HEADERFOOTER + 1 },
+ { OOBIN_ID_WORKSHEET, OOBIN_ID_WORKSHEET + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+void OoxChartsheetFragment::initializeImport()
+{
+ // initial processing in base class WorksheetHelper
+ initializeWorksheetImport();
+}
+
+void OoxChartsheetFragment::finalizeImport()
+{
+ // final processing in base class WorksheetHelper
+ finalizeWorksheetImport();
+}
+
+// private --------------------------------------------------------------------
+
+void OoxChartsheetFragment::importDrawing( const AttributeList& rAttribs )
+{
+ setDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
+}
+
+void OoxChartsheetFragment::importDrawing( RecordInputStream& rStrm )
+{
+ setDrawingPath( getFragmentPathFromRelId( rStrm.readString() ) );
+}
+
+// ============================================================================
+
+BiffChartsheetFragment::BiffChartsheetFragment( const BiffWorkbookFragmentBase& rParent,
+ ISegmentProgressBarRef xProgressBar, sal_Int16 nSheet ) :
+ BiffWorksheetFragmentBase( rParent, xProgressBar, SHEETTYPE_CHARTSHEET, nSheet )
+{
+}
+
+bool BiffChartsheetFragment::importFragment()
+{
+ // initial processing in base class WorksheetHelper
+ initializeWorksheetImport();
+
+ WorksheetSettings& rWorksheetSett = getWorksheetSettings();
+ SheetViewSettings& rSheetViewSett = getSheetViewSettings();
+ PageSettings& rPageSett = getPageSettings();
+
+ // process all record in this sheet fragment
+ while( mrStrm.startNextRecord() && (mrStrm.getRecId() != BIFF_ID_EOF) )
+ {
+ if( isBofRecord() )
+ {
+ // skip unknown embedded fragments (BOF/EOF blocks)
+ skipFragment();
+ }
+ else
+ {
+ sal_uInt16 nRecId = mrStrm.getRecId();
+ switch( nRecId )
+ {
+ // records in all BIFF versions
+ case BIFF_ID_BOTTOMMARGIN: rPageSett.importBottomMargin( mrStrm ); break;
+ case BIFF_ID_CHBEGIN: skipRecordBlock( BIFF_ID_CHEND ); break;
+ case BIFF_ID_FOOTER: rPageSett.importFooter( mrStrm ); break;
+ case BIFF_ID_HEADER: rPageSett.importHeader( mrStrm ); break;
+ case BIFF_ID_LEFTMARGIN: rPageSett.importLeftMargin( mrStrm ); break;
+ case BIFF_ID_PASSWORD: rWorksheetSett.importPassword( mrStrm ); break;
+ case BIFF_ID_PROTECT: rWorksheetSett.importProtect( mrStrm ); break;
+ case BIFF_ID_RIGHTMARGIN: rPageSett.importRightMargin( mrStrm ); break;
+ case BIFF_ID_TOPMARGIN: rPageSett.importTopMargin( mrStrm ); break;
+
+ // BIFF specific records
+ default: switch( getBiff() )
+ {
+ case BIFF2: switch( nRecId )
+ {
+ case BIFF2_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+ }
+ break;
+
+ case BIFF3: switch( nRecId )
+ {
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( mrStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+
+ }
+ break;
+
+ case BIFF4: switch( nRecId )
+ {
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( mrStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( mrStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+ }
+ break;
+
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( mrStrm ); break;
+ case BIFF_ID_SCENPROTECT: rWorksheetSett.importScenProtect( mrStrm ); break;
+ case BIFF_ID_SCL: rSheetViewSett.importScl( mrStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( mrStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+ }
+ break;
+
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF_ID_CODENAME: rWorksheetSett.importCodeName( mrStrm ); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
+ case BIFF_ID_PICTURE: rPageSett.importPicture( mrStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( mrStrm ); break;
+ case BIFF_ID_SCL: rSheetViewSett.importScl( mrStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( mrStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+ }
+ }
+ }
+
+ // final processing in base class WorksheetHelper
+ finalizeWorksheetImport();
+ return mrStrm.getRecId() == BIFF_ID_EOF;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/commentsbuffer.cxx b/oox/source/xls/commentsbuffer.cxx
new file mode 100644
index 000000000000..159bde83b22c
--- /dev/null
+++ b/oox/source/xls/commentsbuffer.cxx
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/commentsbuffer.hxx"
+#include <com/sun/star/sheet/XSheetAnnotationAnchor.hpp>
+#include <com/sun/star/sheet/XSheetAnnotationShapeSupplier.hpp>
+#include <com/sun/star/sheet/XSheetAnnotations.hpp>
+#include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/vml/vmlshape.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/drawingfragment.hxx"
+#include "properties.hxx"
+#include "svx/sdtaitm.hxx"
+#include "oox/xls/unitconverter.hxx"
+
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+
+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::uno::UNO_SET_THROW;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::sheet::XSheetAnnotation;
+using ::com::sun::star::sheet::XSheetAnnotationAnchor;
+using ::com::sun::star::sheet::XSheetAnnotationShapeSupplier;
+using ::com::sun::star::sheet::XSheetAnnotations;
+using ::com::sun::star::sheet::XSheetAnnotationsSupplier;
+
+using ::com::sun::star::text::XText;
+using ::com::sun::star::text::XTextRange;
+using ::com::sun::star::awt::Size;
+using ::com::sun::star::awt::Point;
+
+
+static sal_Int32 lcl_ToHorizAlign( sal_Int32 nAlign )
+{
+ switch( nAlign )
+ {
+ case XML_left:
+ return SDRTEXTHORZADJUST_LEFT;
+ case XML_right:
+ return SDRTEXTHORZADJUST_RIGHT;
+ case XML_center:
+ return SDRTEXTHORZADJUST_CENTER;
+ default:
+ return SDRTEXTHORZADJUST_BLOCK;
+ }
+ return SDRTEXTHORZADJUST_LEFT;
+}
+
+static sal_Int32 lcl_ToVertAlign( sal_Int32 nAlign )
+{
+ switch( nAlign )
+ {
+ case XML_top:
+ return SDRTEXTVERTADJUST_TOP;
+ case XML_center:
+ return SDRTEXTVERTADJUST_CENTER;
+ case XML_bottom:
+ return SDRTEXTVERTADJUST_BOTTOM;
+ default:
+ return SDRTEXTVERTADJUST_BLOCK;
+ }
+ return SDRTEXTVERTADJUST_TOP;
+}
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+CommentModel::CommentModel() :
+ mnAuthorId( -1 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+Comment::Comment( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+void Comment::importComment( const AttributeList& rAttribs )
+{
+ maModel.mnAuthorId = rAttribs.getInteger( XML_authorId, -1 );
+ // cell range will be checked while inserting the comment into the document
+ getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex() );
+}
+
+void Comment::importCommentPr( const AttributeList& rAttribs )
+{
+ maModel.mbAutoFill = rAttribs.getBool( XML_autoFill, true );
+ maModel.mbAutoScale = rAttribs.getBool( XML_autoScale, false );
+ maModel.mbColHidden = rAttribs.getBool( XML_colHidden, false );
+ maModel.mbLocked = rAttribs.getBool( XML_locked, false );
+ maModel.mbRowHidden = rAttribs.getBool( XML_rowHidden, false );
+ maModel.mnTHA = rAttribs.getToken( XML_textHAlign, XML_left );
+ maModel.mnTVA = rAttribs.getToken( XML_textVAlign, XML_top );
+}
+
+void Comment::importAnchor( bool bFrom, sal_Int32 nWhich, const OUString &rChars )
+{
+ sal_Int32 nRow, nCol;
+ Point aPoint;
+ UnitConverter& rUnitConv = getUnitConverter();
+ if( bFrom )
+ {
+ nCol = maModel.maAnchor.X;
+ nRow = maModel.maAnchor.Y;
+ }
+ else
+ {
+ nCol = maModel.maAnchor.Width + maModel.maAnchor.X ;
+ nRow = maModel.maAnchor.Height + maModel.maAnchor.Y;
+ }
+ switch( nWhich )
+ {
+ case XDR_TOKEN( col ):
+ aPoint = getCellPosition( rChars.toInt32(), 1 );
+ nCol = aPoint.X;
+ break;
+ case XDR_TOKEN( colOff ):
+ nCol += rUnitConv.scaleToMm100( static_cast< double >( rChars.toInt32() ), UNIT_SCREENX );
+ break;
+ case XDR_TOKEN( row ):
+ aPoint = getCellPosition( 1, rChars.toInt32() );
+ nRow = aPoint.Y;
+ break;
+ case XDR_TOKEN( rowOff ):
+ nRow += rUnitConv.scaleToMm100( static_cast< double >( rChars.toInt32() ), UNIT_SCREENY );
+ break;
+ }
+ if( bFrom )
+ {
+ maModel.maAnchor.X = nCol;
+ maModel.maAnchor.Y = nRow;
+ }
+ else
+ {
+ maModel.maAnchor.Width = nCol - maModel.maAnchor.X;
+ maModel.maAnchor.Height = nRow - maModel.maAnchor.Y;
+ }
+}
+
+void Comment::importComment( RecordInputStream& rStrm )
+{
+ BinRange aBinRange;
+ rStrm >> maModel.mnAuthorId >> aBinRange;
+ // cell range will be checked while inserting the comment into the document
+ getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, aBinRange, getSheetIndex() );
+}
+
+RichStringRef Comment::createText()
+{
+ maModel.mxText.reset( new RichString( *this ) );
+ return maModel.mxText;
+}
+
+void Comment::finalizeImport()
+{
+ // OOBIN format stores cell range instead of cell address, use first cell of this range
+ OSL_ENSURE( (maModel.maRange.StartColumn == maModel.maRange.EndColumn) &&
+ (maModel.maRange.StartRow == maModel.maRange.EndRow),
+ "Comment::finalizeImport - comment anchor should be a single cell" );
+ CellAddress aNotePos( maModel.maRange.Sheet, maModel.maRange.StartColumn, maModel.maRange.StartRow );
+ if( getAddressConverter().checkCellAddress( aNotePos, true ) && maModel.mxText.get() ) try
+ {
+ maModel.mxText->finalizeImport();
+ OUString aNoteText = maModel.mxText->getPlainText();
+ // non-empty string required by note implementation
+ if( aNoteText.getLength() > 0 )
+ {
+ Reference< XSheetAnnotationsSupplier > xAnnosSupp( getSheet(), UNO_QUERY_THROW );
+ Reference< XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), UNO_SET_THROW );
+ xAnnos->insertNew( aNotePos, aNoteText );
+ // receive craeted note from cell (insertNew does not return the note)
+ Reference< XSheetAnnotationAnchor > xAnnoAnchor( getCell( aNotePos ), UNO_QUERY_THROW );
+ Reference< XSheetAnnotation > xAnno( xAnnoAnchor->getAnnotation(), UNO_SET_THROW );
+ Reference< XSheetAnnotationShapeSupplier > xAnnoShapeSupp( xAnno, UNO_QUERY_THROW );
+ Reference< XShape > xAnnoShape( xAnnoShapeSupp->getAnnotationShape(), UNO_SET_THROW );
+ Reference <XText> xText( xAnnoShape, UNO_QUERY_THROW );
+ Reference <XTextRange> xTextRange( xText, UNO_QUERY_THROW );
+ xTextRange->setString( OUString::createFromAscii("") ); // Clear contents
+ maModel.mxText->convert( xText, -1 );
+
+ // Add shape formatting properties (autoFill, colHidden and rowHidden are dropped)
+ PropertySet aCommentPr( xAnnoShape );
+ aCommentPr.setProperty( PROP_TextFitToSize, maModel.mbAutoScale );
+ aCommentPr.setProperty( PROP_MoveProtect, maModel.mbLocked );
+ aCommentPr.setProperty( PROP_TextHorizontalAdjust, lcl_ToHorizAlign( maModel.mnTHA ) );
+ aCommentPr.setProperty( PROP_TextVerticalAdjust, lcl_ToVertAlign( maModel.mnTVA ) );
+ if( maModel.maAnchor.Width > 0 && maModel.maAnchor.Height > 0 )
+ {
+ xAnnoShape->setPosition( Point( maModel.maAnchor.X, maModel.maAnchor.Y ) );
+ xAnnoShape->setSize( Size( maModel.maAnchor.Width, maModel.maAnchor.Height ) );
+ }
+
+
+ // convert shape formatting
+ if( const ::oox::vml::ShapeBase* pNoteShape = getVmlDrawing().getNoteShape( aNotePos ) )
+ {
+ // position and formatting
+ pNoteShape->convertFormatting( xAnnoShape );
+ // visibility
+ const ::oox::vml::ShapeModel::ShapeClientDataPtr& rxClientData = pNoteShape->getShapeModel().mxClientData;
+ bool bVisible = rxClientData.get() && rxClientData->mbVisible;
+ xAnno->setIsVisible( bVisible );
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+
+CommentsBuffer::CommentsBuffer( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+void CommentsBuffer::appendAuthor( const OUString& rAuthor )
+{
+ maAuthors.push_back( rAuthor );
+}
+
+CommentRef CommentsBuffer::createComment()
+{
+ CommentRef xComment( new Comment( *this ) );
+ maComments.push_back( xComment );
+ return xComment;
+}
+
+void CommentsBuffer::finalizeImport()
+{
+ maComments.forEachMem( &Comment::finalizeImport );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/commentsfragment.cxx b/oox/source/xls/commentsfragment.cxx
new file mode 100644
index 000000000000..6ab15d29eda4
--- /dev/null
+++ b/oox/source/xls/commentsfragment.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/commentsfragment.hxx"
+#include "oox/xls/richstringcontext.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxCommentsFragment::OoxCommentsFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxCommentsFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( comments ) ) return this;
+ break;
+ case XLS_TOKEN( comments ):
+ if( nElement == XLS_TOKEN( authors ) ) return this;
+ if( nElement == XLS_TOKEN( commentList ) ) return this;
+ break;
+ case XLS_TOKEN( authors ):
+ if( nElement == XLS_TOKEN( author ) ) return this; // collect author in onEndElement()
+ break;
+ case XLS_TOKEN( commentList ):
+ if( nElement == XLS_TOKEN( comment ) ) { importComment( rAttribs ); return this; }
+ break;
+ case XLS_TOKEN( commentPr ):
+ if( nElement == XLS_TOKEN( anchor ) )
+ return this;
+ break;
+ case XLS_TOKEN( anchor ):
+ if( nElement == XDR_TOKEN( from ) || nElement == XDR_TOKEN( to ) )
+ return this;
+ break;
+ case XDR_TOKEN( from ):
+ case XDR_TOKEN( to ):
+ return this;
+ case XLS_TOKEN( comment ):
+ if( (nElement == XLS_TOKEN( text )) && mxComment.get() )
+ return new OoxRichStringContext( *this, mxComment->createText() );
+ if( nElement == XLS_TOKEN( commentPr ) ) { mxComment->importCommentPr( rAttribs ); return this; }
+ break;
+ }
+ return 0;
+}
+
+void OoxCommentsFragment::onEndElement( const OUString& rChars )
+{
+ bool bFrom = false;
+ if( getPreviousElement() == XDR_TOKEN( from ) )
+ bFrom = true;
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( author ):
+ getComments().appendAuthor( rChars );
+ break;
+ case XDR_TOKEN( col ):
+ case XDR_TOKEN( colOff ):
+ case XDR_TOKEN( row ):
+ case XDR_TOKEN( rowOff ):
+ mxComment->importAnchor( bFrom, getCurrentElement(), rChars );
+ break;
+ case XLS_TOKEN( comment ):
+ mxComment.reset();
+ break;
+ }
+}
+
+ContextHandlerRef OoxCommentsFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_COMMENTS ) return this;
+ break;
+ case OOBIN_ID_COMMENTS:
+ if( nRecId == OOBIN_ID_COMMENTAUTHORS ) return this;
+ if( nRecId == OOBIN_ID_COMMENTLIST ) return this;
+ break;
+ case OOBIN_ID_COMMENTAUTHORS:
+ if( nRecId == OOBIN_ID_COMMENTAUTHOR ) getComments().appendAuthor( rStrm.readString() );
+ break;
+ case OOBIN_ID_COMMENTLIST:
+ if( nRecId == OOBIN_ID_COMMENT ) { importComment( rStrm ); return this; }
+ break;
+ case OOBIN_ID_COMMENT:
+ if( (nRecId == OOBIN_ID_COMMENTTEXT) && mxComment.get() )
+ mxComment->createText()->importString( rStrm, true );
+ break;
+ }
+ return 0;
+}
+
+void OoxCommentsFragment::onEndRecord()
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_COMMENT:
+ mxComment.reset();
+ break;
+ }
+}
+
+// oox.core.FragmentHandler2 interface ----------------------------------------
+
+const RecordInfo* OoxCommentsFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_COMMENT, OOBIN_ID_COMMENT + 1 },
+ { OOBIN_ID_COMMENTAUTHORS, OOBIN_ID_COMMENTAUTHORS + 1 },
+ { OOBIN_ID_COMMENTLIST, OOBIN_ID_COMMENTLIST + 1 },
+ { OOBIN_ID_COMMENTS, OOBIN_ID_COMMENTS + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+// private --------------------------------------------------------------------
+
+void OoxCommentsFragment::importComment( const AttributeList& rAttribs )
+{
+ mxComment = getComments().createComment();
+ mxComment->importComment( rAttribs );
+}
+
+void OoxCommentsFragment::importComment( RecordInputStream& rStrm )
+{
+ mxComment = getComments().createComment();
+ mxComment->importComment( rStrm );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/condformatbuffer.cxx b/oox/source/xls/condformatbuffer.cxx
new file mode 100644
index 000000000000..c6857c075fd1
--- /dev/null
+++ b/oox/source/xls/condformatbuffer.cxx
@@ -0,0 +1,789 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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/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 "properties.hxx"
+#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"
+
+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::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
+
+// ============================================================================
+
+CondFormatRuleModel::CondFormatRuleModel() :
+ 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 CondFormatRuleModel::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 CondFormatRuleModel::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 )
+{
+ maModel.maText = rAttribs.getString( XML_text, OUString() );
+ maModel.mnPriority = rAttribs.getInteger( XML_priority, -1 );
+ maModel.mnType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
+ maModel.mnOperator = rAttribs.getToken( XML_operator, XML_TOKEN_INVALID );
+ maModel.mnTimePeriod = rAttribs.getToken( XML_timePeriod, XML_TOKEN_INVALID );
+ maModel.mnRank = rAttribs.getInteger( XML_rank, 0 );
+ maModel.mnStdDev = rAttribs.getInteger( XML_stdDev, 0 );
+ maModel.mnDxfId = rAttribs.getInteger( XML_dxfId, -1 );
+ maModel.mbStopIfTrue = rAttribs.getBool( XML_stopIfTrue, false );
+ maModel.mbBottom = rAttribs.getBool( XML_bottom, false );
+ maModel.mbPercent = rAttribs.getBool( XML_percent, false );
+ maModel.mbAboveAverage = rAttribs.getBool( XML_aboveAverage, true );
+ maModel.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 );
+ maModel.maFormulas.push_back( aContext );
+}
+
+void CondFormatRule::importCfRule( RecordInputStream& rStrm )
+{
+ sal_Int32 nType, nSubType, nOperator, nFmla1Size, nFmla2Size, nFmla3Size;
+ sal_uInt16 nFlags;
+ rStrm >> nType >> nSubType >> maModel.mnDxfId >> maModel.mnPriority >> nOperator;
+ rStrm.skip( 8 );
+ rStrm >> nFlags >> nFmla1Size >> nFmla2Size >> nFmla3Size >> maModel.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.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
+ if( rStrm.getRemaining() >= 8 )
+ {
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( mrCondFormat.getRanges().getBaseAddress() );
+ getFormulaParser().importFormula( aContext, rStrm );
+ maModel.maFormulas.push_back( aContext );
+
+ // second formula
+ OSL_ENSURE( (nFmla2Size >= 0) || (nFmla3Size == 0), "CondFormatRule::importCfRule - missing second formula" );
+ OSL_ENSURE( (nFmla2Size > 0) == (rStrm.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
+ if( rStrm.getRemaining() >= 8 )
+ {
+ getFormulaParser().importFormula( aContext, rStrm );
+ maModel.maFormulas.push_back( aContext );
+
+ // third formula
+ OSL_ENSURE( (nFmla3Size > 0) == (rStrm.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
+ if( rStrm.getRemaining() >= 8 )
+ {
+ getFormulaParser().importFormula( aContext, rStrm );
+ maModel.maFormulas.push_back( aContext );
+ }
+ }
+ }
+
+ // flags
+ maModel.mbStopIfTrue = getFlag( nFlags, OOBIN_CFRULE_STOPIFTRUE );
+ maModel.mbBottom = getFlag( nFlags, OOBIN_CFRULE_BOTTOM );
+ maModel.mbPercent = getFlag( nFlags, OOBIN_CFRULE_PERCENT );
+ maModel.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" );
+ maModel.mnType = XML_cellIs;
+ maModel.setBinOperator( nOperator );
+ OSL_ENSURE( maModel.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" );
+ maModel.mnType = XML_expression;
+ break;
+ case OOBIN_CFRULE_SUB_UNIQUE:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maModel.mnType = XML_uniqueValues;
+ break;
+ case OOBIN_CFRULE_SUB_TEXT:
+ maModel.setOobTextType( nOperator );
+ OSL_ENSURE( maModel.mnType != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unexpected operator value" );
+ break;
+ case OOBIN_CFRULE_SUB_BLANK:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maModel.mnType = XML_containsBlanks;
+ break;
+ case OOBIN_CFRULE_SUB_NOTBLANK:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maModel.mnType = XML_notContainsBlanks;
+ break;
+ case OOBIN_CFRULE_SUB_ERROR:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maModel.mnType = XML_containsErrors;
+ break;
+ case OOBIN_CFRULE_SUB_NOTERROR:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maModel.mnType = XML_notContainsErrors;
+ break;
+ case OOBIN_CFRULE_SUB_TODAY:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_TODAY, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_today;
+ break;
+ case OOBIN_CFRULE_SUB_TOMORROW:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_TOMORROW, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_tomorrow;
+ break;
+ case OOBIN_CFRULE_SUB_YESTERDAY:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_YESTERDAY, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_yesterday;
+ break;
+ case OOBIN_CFRULE_SUB_LAST7DAYS:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_LAST7DAYS, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_last7Days;
+ break;
+ case OOBIN_CFRULE_SUB_LASTMONTH:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_LASTMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_lastMonth;
+ break;
+ case OOBIN_CFRULE_SUB_NEXTMONTH:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_NEXTMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_nextMonth;
+ break;
+ case OOBIN_CFRULE_SUB_THISWEEK:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_THISWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_thisWeek;
+ break;
+ case OOBIN_CFRULE_SUB_NEXTWEEK:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_NEXTWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_nextWeek;
+ break;
+ case OOBIN_CFRULE_SUB_LASTWEEK:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_LASTWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_lastWeek;
+ break;
+ case OOBIN_CFRULE_SUB_THISMONTH:
+ OSL_ENSURE( nOperator == OOBIN_CFRULE_TIMEOP_THISMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+ maModel.mnType = XML_timePeriod;
+ maModel.mnTimePeriod = XML_thisMonth;
+ break;
+ case OOBIN_CFRULE_SUB_ABOVEAVERAGE:
+ OSL_ENSURE( maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
+ maModel.mnType = XML_aboveAverage;
+ maModel.mnStdDev = nOperator; // operator field used for standard deviation
+ maModel.mbAboveAverage = true;
+ maModel.mbEqualAverage = false; // does not exist as real flag...
+ break;
+ case OOBIN_CFRULE_SUB_BELOWAVERAGE:
+ OSL_ENSURE( !maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
+ maModel.mnType = XML_aboveAverage;
+ maModel.mnStdDev = nOperator; // operator field used for standard deviation
+ maModel.mbAboveAverage = false;
+ maModel.mbEqualAverage = false; // does not exist as real flag...
+ break;
+ case OOBIN_CFRULE_SUB_DUPLICATE:
+ OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+ maModel.mnType = XML_duplicateValues;
+ break;
+ case OOBIN_CFRULE_SUB_EQABOVEAVERAGE:
+ OSL_ENSURE( maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
+ maModel.mnType = XML_aboveAverage;
+ maModel.mnStdDev = nOperator; // operator field used for standard deviation
+ maModel.mbAboveAverage = true;
+ maModel.mbEqualAverage = true; // does not exist as real flag...
+ break;
+ case OOBIN_CFRULE_SUB_EQBELOWAVERAGE:
+ OSL_ENSURE( !maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
+ maModel.mnType = XML_aboveAverage;
+ maModel.mnStdDev = nOperator; // operator field used for standard deviation
+ maModel.mbAboveAverage = false;
+ maModel.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" );
+ maModel.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" );
+ maModel.mnType = XML_dataBar;
+ break;
+ case OOBIN_CFRULE_TYPE_TOPTEN:
+ OSL_ENSURE( nSubType == OOBIN_CFRULE_SUB_TOPTEN, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+ maModel.mnType = XML_top10;
+ maModel.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" );
+ maModel.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 };
+ maModel.mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_TOKEN_INVALID );
+
+ maModel.setBinOperator( nOperator );
+ maModel.mnPriority = nPriority;
+ maModel.mbStopIfTrue = true;
+
+ DxfRef xDxf = getStyles().createDxf( &maModel.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 );
+ maModel.maFormulas.push_back( aContext );
+ if( nFmla2Size > 0 )
+ {
+ getFormulaParser().importFormula( aContext, rStrm, &nFmla2Size );
+ maModel.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 relative 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.
+ - '#C' will be replaced by one of the comparison operators <, >, <=, or
+ >=, according to the 'aboveAverage' and 'equalAverage' flags.
+ */
+ OUString aReplaceFormula;
+
+ switch( maModel.mnType )
+ {
+ case XML_cellIs:
+ eOperator = CondFormatBuffer::convertToApiOperator( maModel.mnOperator );
+ break;
+ case XML_expression:
+ eOperator = ::com::sun::star::sheet::ConditionOperator_FORMULA;
+ break;
+ case XML_containsText:
+ OSL_ENSURE( maModel.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( maModel.mnOperator == XML_notContains, "CondFormatRule::finalizeImport - unexpected operator" );
+ aReplaceFormula = CREATE_OUSTRING( "ISERROR(SEARCH(#T,#B))" );
+ break;
+ case XML_beginsWith:
+ OSL_ENSURE( maModel.mnOperator == XML_beginsWith, "CondFormatRule::finalizeImport - unexpected operator" );
+ aReplaceFormula = CREATE_OUSTRING( "LEFT(#B,#L)=#T" );
+ break;
+ case XML_endsWith:
+ OSL_ENSURE( maModel.mnOperator == XML_endsWith, "CondFormatRule::finalizeImport - unexpected operator" );
+ aReplaceFormula = CREATE_OUSTRING( "RIGHT(#B,#L)=#T" );
+ break;
+ case XML_timePeriod:
+ switch( maModel.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( maModel.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( maModel.mnStdDev == 0 )
+ aReplaceFormula = CREATE_OUSTRING( "#B#CAVERAGE(#R)" );
+ break;
+ }
+
+ if( aReplaceFormula.getLength() > 0 )
+ {
+ OUString aAddress, aRanges, aText, aComp;
+ 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 )
+ // quote the comparison text, and handle embedded quote characters
+ aText = FormulaProcessorBase::generateApiString( maModel.maText );
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aText );
+ break;
+ case 'L': // length of comparison text
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2,
+ OUString::valueOf( maModel.maText.getLength() ) );
+ break;
+ case 'K': // top-10 rank
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2,
+ OUString::valueOf( maModel.mnRank ) );
+ break;
+ case 'M': // top-10 top/bottom flag
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2,
+ OUString::valueOf( static_cast< sal_Int32 >( maModel.mbBottom ? 1 : 0 ) ) );
+ break;
+ case 'C': // average comparison operator
+ if( aComp.getLength() == 0 )
+ aComp = maModel.mbAboveAverage ?
+ (maModel.mbEqualAverage ? CREATE_OUSTRING( ">=" ) : CREATE_OUSTRING( ">" )) :
+ (maModel.mbEqualAverage ? CREATE_OUSTRING( "<=" ) : CREATE_OUSTRING( "<" ));
+ aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aComp );
+ break;
+ default:
+ OSL_ENSURE( false, "CondFormatRule::finalizeImport - unknown placeholder" );
+ }
+ }
+
+ // set the replacement formula
+ maModel.maFormulas.clear();
+ appendFormula( aReplaceFormula );
+ eOperator = ::com::sun::star::sheet::ConditionOperator_FORMULA;
+ }
+
+ if( rxEntries.is() && (eOperator != ::com::sun::star::sheet::ConditionOperator_NONE) && !maModel.maFormulas.empty() )
+ {
+ ::std::vector< PropertyValue > aProps;
+ // create condition properties
+ lclAppendProperty( aProps, CREATE_OUSTRING( "Operator" ), eOperator );
+ lclAppendProperty( aProps, CREATE_OUSTRING( "Formula1" ), maModel.maFormulas[ 0 ].getTokens() );
+ if( maModel.maFormulas.size() >= 2 )
+ lclAppendProperty( aProps, CREATE_OUSTRING( "Formula2" ), maModel.maFormulas[ 1 ].getTokens() );
+
+ // style name for the formatting attributes
+ OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
+ if( aStyleName.getLength() > 0 )
+ lclAppendProperty( aProps, CREATE_OUSTRING( "StyleName" ), aStyleName );
+
+ // append the new rule
+ try
+ {
+ rxEntries->addNew( ContainerHelper::vectorToSequence( aProps ) );
+ }
+ catch( Exception& )
+ {
+ }
+ }
+}
+
+// ============================================================================
+
+CondFormatModel::CondFormatModel() :
+ mbPivot( false )
+{
+}
+
+// ============================================================================
+
+CondFormat::CondFormat( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+void CondFormat::importConditionalFormatting( const AttributeList& rAttribs )
+{
+ getAddressConverter().convertToCellRangeList( maModel.maRanges, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), true );
+ maModel.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( maModel.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( maModel.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( maModel.maRanges );
+ if( xRanges.is() )
+ {
+ PropertySet aPropSet( xRanges );
+ Reference< XSheetConditionalEntries > xEntries;
+ aPropSet.getProperty( xEntries, PROP_ConditionalFormat );
+ if( xEntries.is() )
+ {
+ // maRules is sorted by rule priority
+ maRules.forEachMem( &CondFormatRule::finalizeImport, ::boost::cref( xEntries ) );
+ aPropSet.setProperty( PROP_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 );
+}
+
+ConditionOperator CondFormatBuffer::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;
+}
+
+// private --------------------------------------------------------------------
+
+CondFormatRef CondFormatBuffer::createCondFormat()
+{
+ CondFormatRef xCondFmt( new CondFormat( *this ) );
+ maCondFormats.push_back( xCondFmt );
+ return xCondFmt;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/condformatcontext.cxx b/oox/source/xls/condformatcontext.cxx
new file mode 100644
index 000000000000..d9421d7232e9
--- /dev/null
+++ b/oox/source/xls/condformatcontext.cxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/condformatcontext.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxCondFormatContext::OoxCondFormatContext( OoxWorksheetFragmentBase& rFragment ) :
+ OoxWorksheetContextBase( rFragment )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxCondFormatContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( conditionalFormatting ):
+ return (nElement == XLS_TOKEN( cfRule )) ? this : 0;
+ case XLS_TOKEN( cfRule ):
+ return (nElement == XLS_TOKEN( formula )) ? this : 0;
+ }
+ return 0;
+}
+
+void OoxCondFormatContext::onStartElement( const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ 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( getCurrentElement() )
+ {
+ case XLS_TOKEN( formula ):
+ if( mxCondFmt.get() && mxRule.get() ) mxRule->appendFormula( rChars );
+ break;
+ }
+}
+
+ContextHandlerRef OoxCondFormatContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_CONDFORMATTING:
+ return (nRecId == OOBIN_ID_CFRULE) ? this : 0;
+ }
+ return 0;
+}
+
+void OoxCondFormatContext::onStartRecord( RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_CONDFORMATTING:
+ mxCondFmt = getCondFormats().importCondFormatting( rStrm );
+ break;
+ case OOBIN_ID_CFRULE:
+ if( mxCondFmt.get() ) mxCondFmt->importCfRule( rStrm );
+ break;
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/connectionsfragment.cxx b/oox/source/xls/connectionsfragment.cxx
new file mode 100644
index 000000000000..fb4c19890882
--- /dev/null
+++ b/oox/source/xls/connectionsfragment.cxx
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/connectionsfragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/xls/webquerybuffer.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+
+namespace oox {
+namespace xls {
+
+OoxConnectionsFragment::OoxConnectionsFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+ContextHandlerRef OoxConnectionsFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( connections ) ) return this;
+ break;
+
+ case XLS_TOKEN( connections ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( connection ): importConnection( rAttribs ); return this;
+ }
+ break;
+
+ case XLS_TOKEN( connection ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( webPr ): importWebPr( rAttribs ); return this;
+ }
+ break;
+
+ case XLS_TOKEN( webPr ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( tables ): importTables( rAttribs ); return this;
+ }
+ break;
+
+ case XLS_TOKEN( tables ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( s ): importS( rAttribs ); break;
+ case XLS_TOKEN( x ): importX( rAttribs ); break;
+ }
+ break;
+ }
+ return 0;
+}
+
+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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/defnamesbuffer.cxx b/oox/source/xls/defnamesbuffer.cxx
new file mode 100644
index 000000000000..6b1708c19858
--- /dev/null
+++ b/oox/source/xls/defnamesbuffer.cxx
@@ -0,0 +1,714 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/defnamesbuffer.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/ExternalReference.hpp>
+#include <com/sun/star/sheet/NamedRangeFlag.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+#include <com/sun/star/sheet/SingleReference.hpp>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include <com/sun/star/sheet/XPrintAreas.hpp>
+#include "properties.hxx"
+#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/worksheetbuffer.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::ComplexReference;
+using ::com::sun::star::sheet::ExternalReference;
+using ::com::sun::star::sheet::SingleReference;
+using ::com::sun::star::sheet::XFormulaTokens;
+using ::com::sun::star::sheet::XPrintAreas;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt32 OOBIN_DEFNAME_HIDDEN = 0x00000001;
+const sal_uInt32 OOBIN_DEFNAME_FUNC = 0x00000002;
+const sal_uInt32 OOBIN_DEFNAME_VBNAME = 0x00000004;
+const sal_uInt32 OOBIN_DEFNAME_MACRO = 0x00000008;
+const sal_uInt32 OOBIN_DEFNAME_CALCEXP = 0x00000010;
+const sal_uInt32 OOBIN_DEFNAME_BUILTIN = 0x00000020;
+const sal_uInt32 OOBIN_DEFNAME_PUBLISHED = 0x00008000;
+const sal_uInt32 OOBIN_DEFNAME_WBPARAM = 0x00010000;
+
+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_BIG = 0x1000;
+
+const sal_uInt8 BIFF2_DEFNAME_FUNC = 0x02; /// BIFF2 function/command flag.
+
+const sal_uInt16 BIFF_DEFNAME_GLOBAL = 0; /// 0 = Globally defined name.
+
+// ----------------------------------------------------------------------------
+
+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 lclGetBuiltinName( 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
+
+// ============================================================================
+
+DefinedNameModel::DefinedNameModel() :
+ mnSheet( -1 ),
+ mnFuncGroupId( -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 )
+{
+ using namespace ::com::sun::star::sheet::ReferenceFlags;
+ lclConvertRefFlags(
+ orApiRef.Flags, orApiRef.Column, orApiRef.RelativeColumn,
+ rBaseAddress.Column, COLUMN_RELATIVE, bColRel );
+ lclConvertRefFlags(
+ orApiRef.Flags, orApiRef.Row, orApiRef.RelativeRow,
+ rBaseAddress.Row, ROW_RELATIVE, bRowRel );
+}
+
+Any lclConvertReference( const Any& rRefAny, const CellAddress& rBaseAddress, sal_uInt16 nRelFlags )
+{
+ if( rRefAny.has< SingleReference >() && !getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ) && !getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) )
+ {
+ SingleReference aApiRef;
+ rRefAny >>= aApiRef;
+ lclConvertSingleRefFlags( aApiRef, rBaseAddress, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) );
+ return Any( aApiRef );
+ }
+ if( rRefAny.has< ComplexReference >() )
+ {
+ ComplexReference aApiRef;
+ rRefAny >>= aApiRef;
+ lclConvertSingleRefFlags( aApiRef.Reference1, rBaseAddress, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) );
+ lclConvertSingleRefFlags( aApiRef.Reference2, rBaseAddress, getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) );
+ return Any( aApiRef );
+ }
+ return Any();
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+DefinedNameBase::DefinedNameBase( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+const OUString& DefinedNameBase::getUpcaseModelName() const
+{
+ if( maUpModelName.getLength() == 0 )
+ maUpModelName = maModel.maName.toAsciiUpperCase();
+ return maUpModelName;
+}
+
+Any DefinedNameBase::getReference( const CellAddress& rBaseAddress ) const
+{
+ if( maRefAny.hasValue() && (maModel.maName.getLength() >= 2) && (maModel.maName[ 0 ] == '\x01') )
+ {
+ sal_Unicode cFlagsChar = getUpcaseModelName()[ 1 ];
+ if( ('A' <= cFlagsChar) && (cFlagsChar <= 'P') )
+ {
+ sal_uInt16 nRelFlags = static_cast< sal_uInt16 >( cFlagsChar - 'A' );
+ if( maRefAny.has< ExternalReference >() )
+ {
+ ExternalReference aApiExtRef;
+ maRefAny >>= aApiExtRef;
+ Any aRefAny = lclConvertReference( aApiExtRef.Reference, rBaseAddress, nRelFlags );
+ if( aRefAny.hasValue() )
+ {
+ aApiExtRef.Reference <<= aRefAny;
+ return Any( aApiExtRef );
+ }
+ }
+ else
+ {
+ return lclConvertReference( maRefAny, rBaseAddress, nRelFlags );
+ }
+ }
+ }
+ return Any();
+}
+
+void DefinedNameBase::importOoxFormula( FormulaContext& rContext, sal_Int16 nBaseSheet )
+{
+ if( maModel.maFormula.getLength() > 0 )
+ {
+ rContext.setBaseAddress( CellAddress( nBaseSheet, 0, 0 ) );
+ getFormulaParser().importFormula( rContext, maModel.maFormula );
+ }
+ else
+ getFormulaParser().convertErrorToFormula( rContext, BIFF_ERR_NAME );
+}
+
+void DefinedNameBase::importOobFormula( FormulaContext& rContext, sal_Int16 nBaseSheet, RecordInputStream& rStrm )
+{
+ rContext.setBaseAddress( CellAddress( nBaseSheet, 0, 0 ) );
+ getFormulaParser().importFormula( rContext, rStrm );
+}
+
+void DefinedNameBase::importBiffFormula( FormulaContext& rContext, sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
+{
+ rContext.setBaseAddress( CellAddress( nBaseSheet, 0, 0 ) );
+ if( !pnFmlaSize || (*pnFmlaSize > 0) )
+ getFormulaParser().importFormula( rContext, rStrm, pnFmlaSize );
+ else
+ getFormulaParser().convertErrorToFormula( rContext, BIFF_ERR_NAME );
+}
+
+void DefinedNameBase::extractReference( const ApiTokenSequence& rTokens )
+{
+ OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "DefinedNameBase::extractReference - unexpected call" );
+ maRefAny = getFormulaParser().extractReference( rTokens );
+}
+
+// ============================================================================
+
+DefinedName::DefinedName( const WorkbookHelper& rHelper ) :
+ DefinedNameBase( rHelper ),
+ mnTokenIndex( -1 ),
+ mcBuiltinId( OOX_DEFNAME_UNKNOWN ),
+ mnFmlaSize( 0 )
+{
+}
+
+void DefinedName::importDefinedName( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ maModel.mnSheet = rAttribs.getInteger( XML_localSheetId, -1 );
+ maModel.mnFuncGroupId = rAttribs.getInteger( XML_functionGroupId, -1 );
+ maModel.mbMacro = rAttribs.getBool( XML_xlm, false );
+ maModel.mbFunction = rAttribs.getBool( XML_function, false );
+ maModel.mbVBName = rAttribs.getBool( XML_vbProcedure, false );
+ maModel.mbHidden = rAttribs.getBool( XML_hidden, false );
+ mcBuiltinId = lclGetBuiltinIdFromOox( maModel.maName );
+ mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1;
+}
+
+void DefinedName::setFormula( const OUString& rFormula )
+{
+ maModel.maFormula = rFormula;
+}
+
+void DefinedName::importDefinedName( RecordInputStream& rStrm )
+{
+ sal_uInt32 nFlags;
+ rStrm >> nFlags;
+ rStrm.skip( 1 ); // keyboard shortcut
+ rStrm >> maModel.mnSheet >> maModel.maName;
+ mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1;
+
+ // macro function/command, hidden flag
+ maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 9 );
+ maModel.mbMacro = getFlag( nFlags, OOBIN_DEFNAME_MACRO );
+ maModel.mbFunction = getFlag( nFlags, OOBIN_DEFNAME_FUNC );
+ maModel.mbVBName = getFlag( nFlags, OOBIN_DEFNAME_VBNAME );
+ maModel.mbHidden = getFlag( nFlags, OOBIN_DEFNAME_HIDDEN );
+
+ // get builtin name index from name
+ if( getFlag( nFlags, OOBIN_DEFNAME_BUILTIN ) )
+ mcBuiltinId = lclGetBuiltinIdFromOob( maModel.maName );
+ // unhide built-in names (_xlnm._FilterDatabase is always hidden)
+ if( isBuiltinName() )
+ maModel.mbHidden = false;
+
+ // store token array data
+ sal_Int64 nRecPos = rStrm.tell();
+ sal_Int32 nFmlaSize = rStrm.readInt32();
+ rStrm.skip( nFmlaSize );
+ sal_Int32 nAddDataSize = rStrm.readInt32();
+ if( !rStrm.isEof() && (nFmlaSize > 0) && (nAddDataSize >= 0) && (rStrm.getRemaining() >= nAddDataSize) )
+ {
+ sal_Int32 nTotalSize = 8 + nFmlaSize + nAddDataSize;
+ mxFormula.reset( new StreamDataSequence );
+ rStrm.seek( nRecPos );
+ rStrm.readData( *mxFormula, nTotalSize );
+ }
+}
+
+void DefinedName::importDefinedName( BiffInputStream& rStrm, sal_Int16 nCalcSheet )
+{
+ 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 ) );
+ maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
+ }
+ break;
+ case BIFF3:
+ case BIFF4:
+ rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize;
+ maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
+ break;
+ case BIFF5:
+ rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId;
+ rStrm.skip( 4 );
+ maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
+ break;
+ case BIFF8:
+ rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId;
+ rStrm.skip( 4 );
+ maModel.maName = rStrm.readUniStringBody( nNameLen, true );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+
+ // macro function/command, hidden flag
+ maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 6 );
+ maModel.mbMacro = getFlag( nFlags, BIFF_DEFNAME_MACRO );
+ maModel.mbFunction = getFlag( nFlags, BIFF_DEFNAME_FUNC );
+ maModel.mbVBName = getFlag( nFlags, BIFF_DEFNAME_VBNAME );
+ maModel.mbHidden = getFlag( nFlags, BIFF_DEFNAME_HIDDEN );
+
+ // get builtin name index from name
+ if( getFlag( nFlags, BIFF_DEFNAME_BUILTIN ) )
+ {
+ OSL_ENSURE( maModel.maName.getLength() == 1, "DefinedName::importDefinedName - wrong builtin name" );
+ if( maModel.maName.getLength() > 0 )
+ mcBuiltinId = maModel.maName[ 0 ];
+ }
+ /* In BIFF5, _xlnm._FilterDatabase appears as hidden user name without
+ built-in flag, and even worse, localized. */
+ else if( (eBiff == BIFF5) && lclIsFilterDatabaseName( maModel.maName ) )
+ {
+ mcBuiltinId = OOX_DEFNAME_FILTERDATABASE;
+ }
+
+ // unhide built-in names (_xlnm._FilterDatabase is always hidden)
+ if( isBuiltinName() )
+ maModel.mbHidden = false;
+
+ // get sheet index for sheet-local names in BIFF5-BIFF8
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ // BIFF2-BIFF4: all defined names are sheet-local
+ mnCalcSheet = nCalcSheet;
+ 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 )
+ mnCalcSheet = pExtLink->getCalcSheetIndex();
+ break;
+ case BIFF8:
+ // convert one-based worksheet index to zero-based Calc sheet index
+ OSL_ENSURE( nTabId >= 0, "DefinedName::importDefinedName - invalid local sheet index" );
+ if( nTabId != BIFF_DEFNAME_GLOBAL )
+ mnCalcSheet = getWorksheets().getCalcSheetIndex( nTabId - 1 );
+ break;
+ case BIFF_UNKNOWN:
+ break;
+ }
+
+ if( (getBiff() <= BIFF4) && maModel.mbHidden && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') )
+ {
+ /* Read the token array of special internal names containing addresses
+ for BIFF3-BIFF4 3D references immediately. It is expected that
+ these names contain a simple cell reference or range reference.
+ Other regular defined names and external names rely on existence of
+ this reference. */
+ TokensFormulaContext aContext( true, true );
+ importBiffFormula( aContext, mnCalcSheet, rStrm, &mnFmlaSize );
+ extractReference( aContext.getTokens() );
+ }
+ else
+ {
+ /* Store record position of other defined names to be able to import
+ token array later. This is needed to correctly resolve references
+ to names that are stored later in the defined names list following
+ this name. */
+ mxBiffStrm.reset( new BiffInputStreamPos( rStrm ) );
+ }
+}
+
+void DefinedName::createNameObject()
+{
+ // do not create names for (macro) functions
+ // #163146# do not ignore hidden names (may be regular names created by VBA scripts)
+ if( /*maModel.mbHidden ||*/ maModel.mbFunction )
+ return;
+
+ // convert original name to final Calc name
+ if( maModel.mbVBName )
+ maCalcName = maModel.maName;
+ else if( isBuiltinName() )
+ maCalcName = lclGetBuiltinName( mcBuiltinId );
+ else
+ maCalcName = maModel.maName; //! TODO convert to valid name
+
+ // #163146# do not rename sheet-local names by default, this breaks VBA scripts
+#if 0
+ // append sheet index for local names in multi-sheet documents
+ if( isWorkbookFile() && !isGlobalName() )
+ maCalcName = OUStringBuffer( maCalcName ).append( sal_Unicode( '_' ) ).
+ append( static_cast< sal_Int32 >( mnCalcSheet + 1 ) ).makeStringAndClear();
+#endif
+
+ // 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, maCalcName will be changed to the resulting name
+ mxNamedRange = createNamedRangeObject( maCalcName, nNameFlags );
+ // index of this defined name used in formula token arrays
+ PropertySet aPropSet( mxNamedRange );
+ aPropSet.getProperty( mnTokenIndex, PROP_TokenIndex );
+}
+
+void DefinedName::convertFormula()
+{
+ Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY );
+ if( xTokens.is() )
+ {
+ // convert and set formula of the defined name
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ {
+ SimpleFormulaContext aContext( xTokens, true, false );
+ implImportOoxFormula( aContext );
+ }
+ break;
+ case FILTER_BIFF:
+ {
+ SimpleFormulaContext aContext( xTokens, true, getBiff() <= BIFF4 );
+ 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( getSheetFromDoc( mnCalcSheet ), UNO_QUERY );
+ ApiCellRangeList aPrintRanges;
+ getFormulaParser().extractCellRangeList( aPrintRanges, xTokens->getTokens(), false, mnCalcSheet );
+ if( xPrintAreas.is() && !aPrintRanges.empty() )
+ xPrintAreas->setPrintAreas( ContainerHelper::vectorToSequence( aPrintRanges ) );
+ }
+ break;
+ case OOX_DEFNAME_PRINTTITLES:
+ {
+ Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY );
+ ApiCellRangeList aTitleRanges;
+ getFormulaParser().extractCellRangeList( aTitleRanges, xTokens->getTokens(), false, mnCalcSheet );
+ 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;
+ }
+ }
+}
+
+bool DefinedName::getAbsoluteRange( CellRangeAddress& orRange ) const
+{
+ /* ScNamedRangeObj::XCellRangeReferrer::getReferredCells is buggy with
+ relative references, so we extract an absolute reference by hand. */
+ Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY );
+ return xTokens.is() && getFormulaParser().extractCellRange( orRange, xTokens->getTokens(), false );
+}
+
+void DefinedName::implImportOoxFormula( FormulaContext& rContext )
+{
+ if( mxFormula.get() )
+ {
+ RecordInputStream aStrm( *mxFormula );
+ importOobFormula( rContext, mnCalcSheet, aStrm );
+ }
+ else
+ importOoxFormula( rContext, mnCalcSheet );
+}
+
+void DefinedName::implImportBiffFormula( FormulaContext& rContext )
+{
+ OSL_ENSURE( mxBiffStrm.get(), "DefinedName::implImportBiffFormula - missing BIFF stream" );
+ BiffInputStream& rStrm = mxBiffStrm->getStream();
+ BiffInputStreamPosGuard aStrmGuard( rStrm );
+ if( mxBiffStrm->restorePosition() )
+ importBiffFormula( rContext, mnCalcSheet, rStrm, &mnFmlaSize );
+}
+
+// ============================================================================
+
+DefinedNamesBuffer::DefinedNamesBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mnCalcSheet( -1 )
+{
+}
+
+void DefinedNamesBuffer::setLocalCalcSheet( sal_Int16 nCalcSheet )
+{
+ OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4),
+ "DefinedNamesBuffer::setLocalCalcSheet - invalid call" );
+ mnCalcSheet = nCalcSheet;
+}
+
+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, mnCalcSheet );
+}
+
+void DefinedNamesBuffer::finalizeImport()
+{
+ // first insert all names without formula definition into the document
+ for( DefNameVector::iterator aIt = maDefNames.begin(), aEnd = maDefNames.end(); aIt != aEnd; ++aIt )
+ {
+ DefinedNameRef xDefName = *aIt;
+ xDefName->createNameObject();
+ sal_Int32 nTokenIndex = xDefName->getTokenIndex();
+ if( nTokenIndex >= 0 )
+ maDefNameMap[ nTokenIndex ] = xDefName;
+ }
+
+ /* 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::getByTokenIndex( sal_Int32 nIndex ) const
+{
+ return maDefNameMap.get( nIndex );
+}
+
+DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, sal_Int16 nCalcSheet ) const
+{
+ DefinedNameRef xGlobalName; // a found global name
+ DefinedNameRef xLocalName; // a found local name
+ for( DefNameVector::const_iterator aIt = maDefNames.begin(), aEnd = maDefNames.end(); (aIt != aEnd) && !xLocalName; ++aIt )
+ {
+ DefinedNameRef xCurrName = *aIt;
+ if( xCurrName->getModelName() == rModelName )
+ {
+ if( xCurrName->getLocalCalcSheet() == nCalcSheet )
+ xLocalName = xCurrName;
+ else if( xCurrName->isGlobalName() )
+ xGlobalName = xCurrName;
+ }
+ }
+ return xLocalName.get() ? xLocalName : xGlobalName;
+}
+
+DefinedNameRef DefinedNamesBuffer::createDefinedName()
+{
+ DefinedNameRef xDefName( new DefinedName( *this ) );
+ maDefNames.push_back( xDefName );
+ return xDefName;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/drawingfragment.cxx b/oox/source/xls/drawingfragment.cxx
new file mode 100644
index 000000000000..ad6bb97cdea9
--- /dev/null
+++ b/oox/source/xls/drawingfragment.cxx
@@ -0,0 +1,682 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/drawingfragment.hxx"
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <com/sun/star/form/binding/XListEntrySource.hpp>
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/drawingml/connectorshapecontext.hxx"
+#include "oox/drawingml/graphicshapecontext.hxx"
+#include "oox/drawingml/shapecontext.hxx"
+#include "oox/drawingml/shapegroupcontext.hxx"
+#include "oox/vml/vmlshape.hxx"
+#include "oox/vml/vmlshapecontainer.hxx"
+#include "oox/xls/formulaparser.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+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::beans::NamedValue;
+using ::com::sun::star::awt::Point;
+using ::com::sun::star::awt::Rectangle;
+using ::com::sun::star::awt::Size;
+using ::com::sun::star::awt::XControlModel;
+using ::com::sun::star::form::binding::XBindableValue;
+using ::com::sun::star::form::binding::XListEntrySink;
+using ::com::sun::star::form::binding::XListEntrySource;
+using ::com::sun::star::form::binding::XValueBinding;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::oox::core::ContextHandlerRef;
+using ::oox::drawingml::ConnectorShapeContext;
+using ::oox::drawingml::GraphicalObjectFrameContext;
+using ::oox::drawingml::GraphicShapeContext;
+using ::oox::drawingml::Shape;
+using ::oox::drawingml::ShapePtr;
+using ::oox::drawingml::ShapeContext;
+using ::oox::drawingml::ShapeGroupContext;
+// no using's for ::oox::vml, that may clash with ::oox::drawingml types
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+/** Converts the passed 64-bit integer value from the passed unit to EMUs. */
+sal_Int64 lclCalcEmu( const UnitConverter& rUnitConv, sal_Int64 nValue, Unit eFromUnit )
+{
+ return (eFromUnit == UNIT_EMU) ? nValue :
+ static_cast< sal_Int64 >( rUnitConv.scaleValue( static_cast< double >( nValue ), eFromUnit, UNIT_EMU ) + 0.5 );
+}
+
+} // namespace
+
+// ============================================================================
+
+AnchorCellModel::AnchorCellModel() :
+ mnCol( -1 ),
+ mnRow( -1 ),
+ mnColOffset( 0 ),
+ mnRowOffset( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+AnchorClientDataModel::AnchorClientDataModel() :
+ mbLocksWithSheet( true ),
+ mbPrintsWithSheet( true )
+{
+}
+
+// ============================================================================
+
+ShapeAnchor::ShapeAnchor( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper ),
+ meType( ANCHOR_INVALID ),
+ mnEditAs( XML_twoCell )
+{
+}
+
+void ShapeAnchor::importAnchor( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( nElement )
+ {
+ case XDR_TOKEN( absoluteAnchor ):
+ meType = ANCHOR_ABSOLUTE;
+ break;
+ case XDR_TOKEN( oneCellAnchor ):
+ meType = ANCHOR_ONECELL;
+ break;
+ case XDR_TOKEN( twoCellAnchor ):
+ meType = ANCHOR_TWOCELL;
+ mnEditAs = rAttribs.getToken( XML_editAs, XML_twoCell );
+ break;
+ default:
+ OSL_ENSURE( false, "ShapeAnchor::importAnchor - unexpected element" );
+ }
+}
+
+void ShapeAnchor::importPos( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( meType == ANCHOR_ABSOLUTE, "ShapeAnchor::importPos - unexpected 'xdr:pos' element" );
+ maPos.X = rAttribs.getHyper( XML_x, 0 );
+ maPos.Y = rAttribs.getHyper( XML_y, 0 );
+}
+
+void ShapeAnchor::importExt( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( (meType == ANCHOR_ABSOLUTE) || (meType == ANCHOR_ONECELL), "ShapeAnchor::importExt - unexpected 'xdr:ext' element" );
+ maSize.Width = rAttribs.getHyper( XML_cx, 0 );
+ maSize.Height = rAttribs.getHyper( XML_cy, 0 );
+}
+
+void ShapeAnchor::importClientData( const AttributeList& rAttribs )
+{
+ maClientData.mbLocksWithSheet = rAttribs.getBool( XML_fLocksWithSheet, true );
+ maClientData.mbPrintsWithSheet = rAttribs.getBool( XML_fPrintsWithSheet, true );
+}
+
+void ShapeAnchor::setCellPos( sal_Int32 nElement, sal_Int32 nParentContext, const OUString& rValue )
+{
+ AnchorCellModel* pAnchorCell = 0;
+ switch( nParentContext )
+ {
+ case XDR_TOKEN( from ):
+ OSL_ENSURE( (meType == ANCHOR_ONECELL) || (meType == ANCHOR_TWOCELL), "ShapeAnchor::setCellPos - unexpected 'xdr:from' element" );
+ pAnchorCell = &maFrom;
+ break;
+ case XDR_TOKEN( to ):
+ OSL_ENSURE( meType == ANCHOR_TWOCELL, "ShapeAnchor::setCellPos - unexpected 'xdr:to' element" );
+ pAnchorCell = &maTo;
+ break;
+ default:
+ OSL_ENSURE( false, "ShapeAnchor::setCellPos - unexpected parent element" );
+ }
+ if( pAnchorCell ) switch( nElement )
+ {
+ case XDR_TOKEN( col ): pAnchorCell->mnCol = rValue.toInt32(); break;
+ case XDR_TOKEN( row ): pAnchorCell->mnRow = rValue.toInt32(); break;
+ case XDR_TOKEN( colOff ): pAnchorCell->mnColOffset = rValue.toInt64(); break;
+ case XDR_TOKEN( rowOff ): pAnchorCell->mnRowOffset = rValue.toInt64(); break;
+ default: OSL_ENSURE( false, "ShapeAnchor::setCellPos - unexpected element" );
+ }
+}
+
+void ShapeAnchor::importVmlAnchor( const OUString& rAnchor )
+{
+ meType = ANCHOR_VML;
+
+ ::std::vector< OUString > aTokens;
+ sal_Int32 nIndex = 0;
+ while( nIndex >= 0 )
+ aTokens.push_back( rAnchor.getToken( 0, ',', nIndex ).trim() );
+
+ OSL_ENSURE( aTokens.size() >= 8, "ShapeAnchor::importVmlAnchor - missing anchor tokens" );
+ if( aTokens.size() >= 8 )
+ {
+ maFrom.mnCol = aTokens[ 0 ].toInt32();
+ maFrom.mnColOffset = aTokens[ 1 ].toInt32();
+ maFrom.mnRow = aTokens[ 2 ].toInt32();
+ maFrom.mnRowOffset = aTokens[ 3 ].toInt32();
+ maTo.mnCol = aTokens[ 4 ].toInt32();
+ maTo.mnColOffset = aTokens[ 5 ].toInt32();
+ maTo.mnRow = aTokens[ 6 ].toInt32();
+ maTo.mnRowOffset = aTokens[ 7 ].toInt32();
+ }
+}
+
+bool ShapeAnchor::isValidAnchor() const
+{
+ bool bValid = false;
+ switch( meType )
+ {
+ case ANCHOR_ABSOLUTE:
+ OSL_ENSURE( maPos.isValid(), "ShapeAnchor::isValidAnchor - invalid position" );
+ OSL_ENSURE( maSize.isValid(), "ShapeAnchor::isValidAnchor - invalid size" );
+ bValid = maPos.isValid() && maSize.isValid() && (maSize.Width > 0) && (maSize.Height > 0);
+ break;
+ case ANCHOR_ONECELL:
+ OSL_ENSURE( maFrom.isValid(), "ShapeAnchor::isValidAnchor - invalid from position" );
+ OSL_ENSURE( maSize.isValid(), "ShapeAnchor::isValidAnchor - invalid size" );
+ bValid = maFrom.isValid() && maSize.isValid() && (maSize.Width > 0) && (maSize.Height > 0);
+ break;
+ case ANCHOR_TWOCELL:
+ case ANCHOR_VML:
+ OSL_ENSURE( maFrom.isValid(), "ShapeAnchor::isValidAnchor - invalid from position" );
+ OSL_ENSURE( maTo.isValid(), "ShapeAnchor::isValidAnchor - invalid to position" );
+ bValid = maFrom.isValid() && maTo.isValid() &&
+ ((maFrom.mnCol < maTo.mnCol) || ((maFrom.mnCol == maTo.mnCol) && (maFrom.mnColOffset < maTo.mnColOffset))) &&
+ ((maFrom.mnRow < maTo.mnRow) || ((maFrom.mnRow == maTo.mnRow) && (maFrom.mnRowOffset < maTo.mnRowOffset)));
+ break;
+ case ANCHOR_INVALID:
+ OSL_ENSURE( false, "ShapeAnchor::isValidAnchor - invalid anchor" );
+ break;
+ }
+ return bValid;
+}
+
+Rectangle ShapeAnchor::calcApiLocation( const Size& rApiSheetSize, const AnchorSizeModel& rEmuSheetSize ) const
+{
+ AddressConverter& rAddrConv = getAddressConverter();
+ UnitConverter& rUnitConv = getUnitConverter();
+ Rectangle aApiLoc( -1, -1, -1, -1 );
+ Unit eUnitX = (meType == ANCHOR_VML) ? UNIT_SCREENX : UNIT_EMU;
+ Unit eUnitY = (meType == ANCHOR_VML) ? UNIT_SCREENY : UNIT_EMU;
+
+ // calculate shape position
+ switch( meType )
+ {
+ case ANCHOR_ABSOLUTE:
+ OSL_ENSURE( maPos.isValid(), "ShapeAnchor::calcApiLocation - invalid position" );
+ if( maPos.isValid() && (maPos.X < rEmuSheetSize.Width) && (maPos.Y < rEmuSheetSize.Height) )
+ {
+ aApiLoc.X = rUnitConv.scaleToMm100( static_cast< double >( maPos.X ), UNIT_EMU );
+ aApiLoc.Y = rUnitConv.scaleToMm100( static_cast< double >( maPos.Y ), UNIT_EMU );
+ }
+ break;
+ case ANCHOR_ONECELL:
+ case ANCHOR_TWOCELL:
+ case ANCHOR_VML:
+ OSL_ENSURE( maFrom.isValid(), "ShapeAnchor::calcApiLocation - invalid position" );
+ if( maFrom.isValid() && rAddrConv.checkCol( maFrom.mnCol, true ) && rAddrConv.checkRow( maFrom.mnRow, true ) )
+ {
+ Point aPoint = getCellPosition( maFrom.mnCol, maFrom.mnRow );
+ aApiLoc.X = aPoint.X + rUnitConv.scaleToMm100( static_cast< double >( maFrom.mnColOffset ), eUnitX );
+ aApiLoc.Y = aPoint.Y + rUnitConv.scaleToMm100( static_cast< double >( maFrom.mnRowOffset ), eUnitY );
+ }
+ break;
+ case ANCHOR_INVALID:
+ OSL_ENSURE( false, "ShapeAnchor::calcApiLocation - invalid anchor" );
+ break;
+ }
+
+ // calculate shape size
+ if( (aApiLoc.X >= 0) && (aApiLoc.Y >= 0) ) switch( meType )
+ {
+ case ANCHOR_ABSOLUTE:
+ case ANCHOR_ONECELL:
+ OSL_ENSURE( maSize.isValid(), "ShapeAnchor::calcApiLocation - invalid size" );
+ if( maSize.isValid() )
+ {
+ aApiLoc.Width = ::std::min< sal_Int32 >(
+ rUnitConv.scaleToMm100( static_cast< double >( maSize.Width ), UNIT_EMU ),
+ rApiSheetSize.Width - aApiLoc.X );
+ aApiLoc.Height = ::std::min< sal_Int32 >(
+ rUnitConv.scaleToMm100( static_cast< double >( maSize.Height ), UNIT_EMU ),
+ rApiSheetSize.Height - aApiLoc.Y );
+ }
+ break;
+ case ANCHOR_TWOCELL:
+ case ANCHOR_VML:
+ OSL_ENSURE( maTo.isValid(), "ShapeAnchor::calcApiLocation - invalid position" );
+ if( maTo.isValid() )
+ {
+ /* Pass a valid cell address to getCellPosition(), otherwise
+ nothing is returned, even if either row or column is valid. */
+ CellAddress aToCell = rAddrConv.createValidCellAddress( BinAddress( maTo.mnCol, maTo.mnRow ), getSheetIndex(), true );
+ Point aPoint = getCellPosition( aToCell.Column, aToCell.Row );
+ // width
+ aApiLoc.Width = rApiSheetSize.Width - aApiLoc.X;
+ if( aToCell.Column == maTo.mnCol )
+ {
+ aPoint.X += rUnitConv.scaleToMm100( static_cast< double >( maTo.mnColOffset ), eUnitX );
+ aApiLoc.Width = ::std::min< sal_Int32 >( aPoint.X - aApiLoc.X + 1, aApiLoc.Width );
+ }
+ // height
+ aApiLoc.Height = rApiSheetSize.Height - aApiLoc.Y;
+ if( aToCell.Row == maTo.mnRow )
+ {
+ aPoint.Y += rUnitConv.scaleToMm100( static_cast< double >( maTo.mnRowOffset ), eUnitY );
+ aApiLoc.Height = ::std::min< sal_Int32 >( aPoint.Y - aApiLoc.Y + 1, aApiLoc.Height );
+ }
+ }
+ break;
+ case ANCHOR_INVALID:
+ break;
+ }
+
+ return aApiLoc;
+}
+
+Rectangle ShapeAnchor::calcEmuLocation( const AnchorSizeModel& rEmuSheetSize ) const
+{
+ AddressConverter& rAddrConv = getAddressConverter();
+ UnitConverter& rUnitConv = getUnitConverter();
+
+ Size aSheetSize(
+ getLimitedValue< sal_Int32, sal_Int64 >( rEmuSheetSize.Width, 0, SAL_MAX_INT32 ),
+ getLimitedValue< sal_Int32, sal_Int64 >( rEmuSheetSize.Height, 0, SAL_MAX_INT32 ) );
+ Rectangle aLoc( -1, -1, -1, -1 );
+ Unit eUnitX = (meType == ANCHOR_VML) ? UNIT_SCREENX : UNIT_EMU;
+ Unit eUnitY = (meType == ANCHOR_VML) ? UNIT_SCREENY : UNIT_EMU;
+
+ // calculate shape position
+ switch( meType )
+ {
+ case ANCHOR_ABSOLUTE:
+ OSL_ENSURE( maPos.isValid(), "ShapeAnchor::calcEmuLocation - invalid position" );
+ if( maPos.isValid() && (maPos.X < aSheetSize.Width) && (maPos.Y < aSheetSize.Height) )
+ {
+ aLoc.X = static_cast< sal_Int32 >( maPos.X );
+ aLoc.Y = static_cast< sal_Int32 >( maPos.Y );
+ }
+ break;
+ case ANCHOR_ONECELL:
+ case ANCHOR_TWOCELL:
+ case ANCHOR_VML:
+ OSL_ENSURE( maFrom.isValid(), "ShapeAnchor::calcEmuLocation - invalid position" );
+ if( maFrom.isValid() && rAddrConv.checkCol( maFrom.mnCol, true ) && rAddrConv.checkRow( maFrom.mnRow, true ) )
+ {
+ Point aPoint = getCellPosition( maFrom.mnCol, maFrom.mnRow );
+ sal_Int64 nX = static_cast< sal_Int64 >( rUnitConv.scaleFromMm100( aPoint.X, UNIT_EMU ) ) + lclCalcEmu( rUnitConv, maFrom.mnColOffset, eUnitX );
+ sal_Int64 nY = static_cast< sal_Int64 >( rUnitConv.scaleFromMm100( aPoint.Y, UNIT_EMU ) ) + lclCalcEmu( rUnitConv, maFrom.mnRowOffset, eUnitY );
+ if( (nX < aSheetSize.Width) && (nY < aSheetSize.Height) )
+ {
+ aLoc.X = static_cast< sal_Int32 >( nX );
+ aLoc.Y = static_cast< sal_Int32 >( nY );
+ }
+ }
+ break;
+ case ANCHOR_INVALID:
+ OSL_ENSURE( false, "ShapeAnchor::calcEmuLocation - invalid anchor" );
+ break;
+ }
+
+ // calculate shape size
+ if( (aLoc.X >= 0) && (aLoc.Y >= 0) ) switch( meType )
+ {
+ case ANCHOR_ABSOLUTE:
+ case ANCHOR_ONECELL:
+ OSL_ENSURE( maSize.isValid(), "ShapeAnchor::calcEmuLocation - invalid size" );
+ if( maSize.isValid() )
+ {
+ aLoc.Width = static_cast< sal_Int32 >( ::std::min< sal_Int64 >( maSize.Width, aSheetSize.Width - aLoc.X ) );
+ aLoc.Height = static_cast< sal_Int32 >( ::std::min< sal_Int64 >( maSize.Height, aSheetSize.Height - aLoc.Y ) );
+ }
+ break;
+ case ANCHOR_TWOCELL:
+ case ANCHOR_VML:
+ OSL_ENSURE( maTo.isValid(), "ShapeAnchor::calcEmuLocation - invalid position" );
+ if( maTo.isValid() )
+ {
+ /* Pass a valid cell address to getCellPosition(), otherwise
+ nothing is returned, even if either row or column is valid. */
+ CellAddress aToCell = rAddrConv.createValidCellAddress( BinAddress( maTo.mnCol, maTo.mnRow ), getSheetIndex(), true );
+ Point aPoint = getCellPosition( aToCell.Column, aToCell.Row );
+ sal_Int64 nX = static_cast< sal_Int64 >( rUnitConv.scaleFromMm100( aPoint.X, UNIT_EMU ) );
+ sal_Int64 nY = static_cast< sal_Int64 >( rUnitConv.scaleFromMm100( aPoint.Y, UNIT_EMU ) );
+ // width
+ aLoc.Width = aSheetSize.Width - aLoc.X;
+ if( aToCell.Column == maTo.mnCol )
+ {
+ nX += lclCalcEmu( rUnitConv, maTo.mnColOffset, eUnitX );
+ aLoc.Width = static_cast< sal_Int32 >( ::std::min< sal_Int64 >( nX - aLoc.X + 1, aLoc.Width ) );
+ }
+ // height
+ aLoc.Height = aSheetSize.Height - aLoc.Y;
+ if( aToCell.Row == maTo.mnRow )
+ {
+ nY += lclCalcEmu( rUnitConv, maTo.mnRowOffset, eUnitY );
+ aLoc.Height = static_cast< sal_Int32 >( ::std::min< sal_Int64 >( nY - aLoc.Y + 1, aLoc.Height ) );
+ }
+ }
+ break;
+ case ANCHOR_INVALID:
+ break;
+ }
+
+ // add 0.75 mm (27,000 EMUs) in X direction to correct display error
+ if( aLoc.X >= 0 )
+ aLoc.X += 27000;
+ // remove 0.25 mm (9,000 EMUs) in Y direction to correct display error
+ if( aLoc.Y >= 9000 )
+ aLoc.Y -= 9000;
+
+ return aLoc;
+}
+
+// ============================================================================
+
+OoxDrawingFragment::OoxDrawingFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath ),
+ mxDrawPage( rHelper.getDrawPage(), UNO_QUERY )
+{
+ OSL_ENSURE( mxDrawPage.is(), "OoxDrawingFragment::OoxDrawingFragment - missing drawing page" );
+ maApiSheetSize = getDrawPageSize();
+ maEmuSheetSize.Width = static_cast< sal_Int64 >( getUnitConverter().scaleFromMm100( maApiSheetSize.Width, UNIT_EMU ) );
+ maEmuSheetSize.Height = static_cast< sal_Int64 >( getUnitConverter().scaleFromMm100( maApiSheetSize.Height, UNIT_EMU ) );
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxDrawingFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XDR_TOKEN( wsDr ) ) return this;
+ break;
+
+ case XDR_TOKEN( wsDr ):
+ switch( nElement )
+ {
+ case XDR_TOKEN( absoluteAnchor ):
+ case XDR_TOKEN( oneCellAnchor ):
+ case XDR_TOKEN( twoCellAnchor ):
+ mxAnchor.reset( new ShapeAnchor( *this ) );
+ mxAnchor->importAnchor( nElement, rAttribs );
+ return this;
+ }
+ break;
+
+ case XDR_TOKEN( absoluteAnchor ):
+ case XDR_TOKEN( oneCellAnchor ):
+ case XDR_TOKEN( twoCellAnchor ):
+ switch( nElement )
+ {
+ case XDR_TOKEN( sp ):
+ mxShape.reset( new Shape( "com.sun.star.drawing.CustomShape" ) );
+ return new ShapeContext( *this, ShapePtr(), mxShape );
+ case XDR_TOKEN( cxnSp ):
+ mxShape.reset( new Shape( "com.sun.star.drawing.ConnectorShape" ) );
+ return new ConnectorShapeContext( *this, ShapePtr(), mxShape );
+ case XDR_TOKEN( pic ):
+ mxShape.reset( new Shape( "com.sun.star.drawing.GraphicObjectShape" ) );
+ return new GraphicShapeContext( *this, ShapePtr(), mxShape );
+ case XDR_TOKEN( graphicFrame ):
+ mxShape.reset( new Shape( "com.sun.star.drawing.OLE2Shape" ) );
+ return new GraphicalObjectFrameContext( *this, ShapePtr(), mxShape, getSheetType() != SHEETTYPE_CHARTSHEET );
+ case XDR_TOKEN( grpSp ):
+ mxShape.reset( new Shape( "com.sun.star.drawing.GroupShape" ) );
+ return new ShapeGroupContext( *this, ShapePtr(), mxShape );
+
+ case XDR_TOKEN( from ):
+ case XDR_TOKEN( to ): return this;
+
+ case XDR_TOKEN( pos ): if( mxAnchor.get() ) mxAnchor->importPos( rAttribs ); break;
+ case XDR_TOKEN( ext ): if( mxAnchor.get() ) mxAnchor->importExt( rAttribs ); break;
+ case XDR_TOKEN( clientData ): if( mxAnchor.get() ) mxAnchor->importClientData( rAttribs ); break;
+ }
+ break;
+
+ case XDR_TOKEN( from ):
+ case XDR_TOKEN( to ):
+ switch( nElement )
+ {
+ case XDR_TOKEN( col ):
+ case XDR_TOKEN( row ):
+ case XDR_TOKEN( colOff ):
+ case XDR_TOKEN( rowOff ): return this; // collect index in onEndElement()
+ }
+ break;
+ }
+ return 0;
+}
+
+void OoxDrawingFragment::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentElement() )
+ {
+ case XDR_TOKEN( col ):
+ case XDR_TOKEN( row ):
+ case XDR_TOKEN( colOff ):
+ case XDR_TOKEN( rowOff ):
+ if( mxAnchor.get() ) mxAnchor->setCellPos( getCurrentElement(), getPreviousElement(), rChars );
+ break;
+ case XDR_TOKEN( absoluteAnchor ):
+ case XDR_TOKEN( oneCellAnchor ):
+ case XDR_TOKEN( twoCellAnchor ):
+ if( mxDrawPage.is() && mxShape.get() && mxAnchor.get() && mxAnchor->isValidAnchor() )
+ {
+ Rectangle aShapeRect = mxAnchor->calcEmuLocation( maEmuSheetSize );
+ if( (aShapeRect.X >= 0) && (aShapeRect.Y >= 0) && (aShapeRect.Width >= 0) && (aShapeRect.Height >= 0) )
+ {
+ mxShape->addShape( getOoxFilter(), &getTheme(), mxDrawPage, &aShapeRect );
+ // collect all shape positions in the WorksheetHelper base class
+ extendShapeBoundingBox( aShapeRect );
+ }
+ }
+ mxShape.reset();
+ mxAnchor.reset();
+ break;
+ }
+}
+
+// ============================================================================
+
+namespace {
+
+class VmlFindNoteFunc
+{
+public:
+ explicit VmlFindNoteFunc( const CellAddress& rPos );
+ bool operator()( const ::oox::vml::ShapeBase& rShape ) const;
+
+private:
+ sal_Int32 mnCol;
+ sal_Int32 mnRow;
+};
+
+VmlFindNoteFunc::VmlFindNoteFunc( const CellAddress& rPos ) :
+ mnCol( rPos.Column ),
+ mnRow( rPos.Row )
+{
+}
+
+bool VmlFindNoteFunc::operator()( const ::oox::vml::ShapeBase& rShape ) const
+{
+ const ::oox::vml::ShapeModel::ShapeClientDataPtr& rxClientData = rShape.getShapeModel().mxClientData;
+ return rxClientData.get() && (rxClientData->mnCol == mnCol) && (rxClientData->mnRow == mnRow);
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+VmlDrawing::VmlDrawing( const WorksheetHelper& rHelper ) :
+ ::oox::vml::Drawing( rHelper.getOoxFilter(), rHelper.getDrawPage(), ::oox::vml::VMLDRAWING_EXCEL ),
+ WorksheetHelper( rHelper )
+{
+}
+
+const ::oox::vml::ShapeBase* VmlDrawing::getNoteShape( const CellAddress& rPos ) const
+{
+ return getShapes().findShape( VmlFindNoteFunc( rPos ) );
+}
+
+bool VmlDrawing::isShapeSupported( const ::oox::vml::ShapeBase& rShape ) const
+{
+ const ::oox::vml::ShapeModel::ShapeClientDataPtr& rxClientData = rShape.getShapeModel().mxClientData;
+ return !rxClientData.get() || (rxClientData->mnObjType != XML_Note);
+}
+
+bool VmlDrawing::convertShapeClientAnchor( Rectangle& orShapeRect, const OUString& rShapeAnchor ) const
+{
+ if( rShapeAnchor.getLength() == 0 )
+ return false;
+ ShapeAnchor aAnchor( *this );
+ aAnchor.importVmlAnchor( rShapeAnchor );
+ orShapeRect = aAnchor.calcApiLocation( getDrawPageSize(), AnchorSizeModel() );
+ return (orShapeRect.Width >= 0) && (orShapeRect.Height >= 0);
+}
+
+void VmlDrawing::convertControlClientData( const Reference< XControlModel >& rxCtrlModel,
+ const ::oox::vml::ShapeClientData& rClientData ) const
+{
+ if( rxCtrlModel.is() )
+ {
+ PropertySet aPropSet( rxCtrlModel );
+
+ // printable
+ aPropSet.setProperty( PROP_Printable, rClientData.mbPrintObject );
+
+ // linked cell
+ if( rClientData.maLinkedCell.getLength() > 0 ) try
+ {
+ Reference< XBindableValue > xBindable( rxCtrlModel, UNO_QUERY_THROW );
+
+ // convert formula string to cell address
+ FormulaParser& rParser = getFormulaParser();
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( CellAddress( getSheetIndex(), 0, 0 ) );
+ rParser.importFormula( aContext, rClientData.maLinkedCell );
+ CellAddress aAddress;
+ if( rParser.extractCellAddress( aAddress, aContext.getTokens(), true ) )
+ {
+ // create argument sequence for createInstanceWithArguments()
+ NamedValue aValue;
+ aValue.Name = CREATE_OUSTRING( "BoundCell" );
+ aValue.Value <<= aAddress;
+ Sequence< Any > aArgs( 1 );
+ aArgs[ 0 ] <<= aValue;
+
+ // create the CellValueBinding instance and set at the control model
+ Reference< XValueBinding > xBinding( getDocumentFactory()->createInstanceWithArguments(
+ CREATE_OUSTRING( "com.sun.star.table.CellValueBinding" ), aArgs ), UNO_QUERY_THROW );
+ xBindable->setValueBinding( xBinding );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ // source range
+ if( rClientData.maSourceRange.getLength() > 0 ) try
+ {
+ Reference< XListEntrySink > xEntrySink( rxCtrlModel, UNO_QUERY_THROW );
+
+ // convert formula string to cell range
+ FormulaParser& rParser = getFormulaParser();
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( CellAddress( getSheetIndex(), 0, 0 ) );
+ rParser.importFormula( aContext, rClientData.maSourceRange );
+ CellRangeAddress aRange;
+ if( rParser.extractCellRange( aRange, aContext.getTokens(), true ) )
+ {
+ // create argument sequence for createInstanceWithArguments()
+ NamedValue aValue;
+ aValue.Name = CREATE_OUSTRING( "CellRange" );
+ aValue.Value <<= aRange;
+ Sequence< Any > aArgs( 1 );
+ aArgs[ 0 ] <<= aValue;
+
+ // create the EntrySource instance and set at the control model
+ Reference< XListEntrySource > xEntrySource( getDocumentFactory()->createInstanceWithArguments(
+ CREATE_OUSTRING( "com.sun.star.table.CellRangeListSource" ), aArgs ), UNO_QUERY_THROW );
+ xEntrySink->setListEntrySource( xEntrySource );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ }
+}
+
+void VmlDrawing::notifyShapeInserted( const Reference< XShape >& /*rxShape*/, const Rectangle& rShapeRect )
+{
+ // collect all shape positions in the WorksheetHelper base class
+ extendShapeBoundingBox( rShapeRect );
+}
+
+// ============================================================================
+
+OoxVmlDrawingFragment::OoxVmlDrawingFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+ ::oox::vml::DrawingFragment( rHelper.getOoxFilter(), rFragmentPath, rHelper.getVmlDrawing() ),
+ WorksheetHelper( rHelper )
+{
+}
+
+void OoxVmlDrawingFragment::finalizeImport()
+{
+ ::oox::vml::DrawingFragment::finalizeImport();
+ getVmlDrawing().convertAndInsert();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/excelchartconverter.cxx b/oox/source/xls/excelchartconverter.cxx
new file mode 100644
index 000000000000..412239a30732
--- /dev/null
+++ b/oox/source/xls/excelchartconverter.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/excelchartconverter.hxx"
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/chart2/data/XDataProvider.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+#include "oox/drawingml/chart/datasourcemodel.hxx"
+#include "oox/xls/formulaparser.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_THROW;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::chart2::XChartDocument;
+using ::com::sun::star::chart2::data::XDataProvider;
+using ::com::sun::star::chart2::data::XDataReceiver;
+using ::com::sun::star::chart2::data::XDataSequence;
+using ::oox::drawingml::chart::DataSequenceModel;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+ExcelChartConverter::ExcelChartConverter( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+ExcelChartConverter::~ExcelChartConverter()
+{
+}
+
+void ExcelChartConverter::createDataProvider( const Reference< XChartDocument >& rxChartDoc )
+{
+ try
+ {
+ Reference< XDataReceiver > xDataRec( rxChartDoc, UNO_QUERY_THROW );
+ Reference< XMultiServiceFactory > xFactory( getDocument(), UNO_QUERY_THROW );
+ Reference< XDataProvider > xDataProv( xFactory->createInstance(
+ CREATE_OUSTRING( "com.sun.star.chart2.data.DataProvider" ) ), UNO_QUERY_THROW );
+ xDataRec->attachDataProvider( xDataProv );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+Reference< XDataSequence > ExcelChartConverter::createDataSequence(
+ const Reference< XDataProvider >& rxDataProvider, const DataSequenceModel& rDataSeq )
+{
+ Reference< XDataSequence > xDataSeq;
+ if( rxDataProvider.is() )
+ {
+ OUString aRangeRep;
+ if( rDataSeq.maFormula.getLength() > 0 )
+ {
+ // parse the formula string, create a token sequence
+ FormulaParser& rParser = getFormulaParser();
+ TokensFormulaContext aContext( true, true );
+ aContext.setBaseAddress( CellAddress( getCurrentSheetIndex(), 0, 0 ) );
+ rParser.importFormula( aContext, rDataSeq.maFormula );
+
+ // create a range list from the token sequence
+ ApiCellRangeList aRanges;
+ rParser.extractCellRangeList( aRanges, aContext.getTokens(), false );
+ aRangeRep = rParser.generateApiRangeListString( aRanges );
+ }
+ else if( !rDataSeq.maData.empty() )
+ {
+ // create a single-row array from constant source data
+ Matrix< Any > aMatrix( rDataSeq.maData.size(), 1 );
+ Matrix< Any >::iterator aMIt = aMatrix.begin();
+ // TODO: how to handle missing values in the map?
+ for( DataSequenceModel::AnyMap::const_iterator aDIt = rDataSeq.maData.begin(), aDEnd = rDataSeq.maData.end(); aDIt != aDEnd; ++aDIt, ++aMIt )
+ *aMIt = aDIt->second;
+ aRangeRep = FormulaProcessorBase::generateApiArray( aMatrix );
+ }
+
+ if( aRangeRep.getLength() > 0 ) try
+ {
+ // create the data sequence
+ xDataSeq = rxDataProvider->createDataSequenceByRangeRepresentation( aRangeRep );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "ExcelChartConverter::createDataSequence - cannot create data sequence" );
+ }
+ }
+ return xDataSeq;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/excelfilter.cxx b/oox/source/xls/excelfilter.cxx
new file mode 100644
index 000000000000..783ff493c268
--- /dev/null
+++ b/oox/source/xls/excelfilter.cxx
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/excelfilter.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/xls/biffdetector.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/excelchartconverter.hxx"
+#include "oox/xls/stylesbuffer.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::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::XInterface;
+using ::com::sun::star::lang::XComponent;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::xml::sax::XFastDocumentHandler;
+using ::oox::core::BinaryFilterBase;
+using ::oox::core::FragmentHandlerRef;
+using ::oox::core::Relation;
+using ::oox::core::Relations;
+using ::oox::core::XmlFilterBase;
+using ::oox::drawingml::table::TableStyleListPtr;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+ExcelFilterBase::ExcelFilterBase() :
+ mpData( 0 )
+{
+}
+
+ExcelFilterBase::~ExcelFilterBase()
+{
+ OSL_ENSURE( !mpData, "ExcelFilterBase::~ExcelFilterBase - workbook data not cleared" );
+}
+
+void ExcelFilterBase::registerWorkbookData( WorkbookData& rData )
+{
+ mpData = &rData;
+}
+
+WorkbookData& ExcelFilterBase::getWorkbookData() const
+{
+ OSL_ENSURE( mpData, "ExcelFilterBase::getWorkbookData - missing workbook data" );
+ return *mpData;
+}
+
+void ExcelFilterBase::unregisterWorkbookData()
+{
+ mpData = 0;
+}
+
+// ============================================================================
+
+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 >& rxGlobalFactory ) throw( Exception )
+{
+ return static_cast< ::cppu::OWeakObject* >( new ExcelFilter( rxGlobalFactory ) );
+}
+
+// ----------------------------------------------------------------------------
+
+ExcelFilter::ExcelFilter( const Reference< XMultiServiceFactory >& rxGlobalFactory ) :
+ XmlFilterBase( rxGlobalFactory )
+{
+}
+
+ExcelFilter::~ExcelFilter()
+{
+}
+
+bool ExcelFilter::importDocument() throw()
+{
+ /* To activate the XLSX/XLSB dumper, insert the full path to the file
+ file:///<path-to-oox-module>/source/dump/xlsbdumper.ini
+ into the environment variable OOO_XLSBDUMPER and start the office with
+ this variable (nonpro only). */
+ OOX_DUMP_FILE( ::oox::dump::xlsb::Dumper );
+
+ OUString aWorkbookPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATIONSTYPE( "officeDocument" ) );
+ if( aWorkbookPath.getLength() == 0 )
+ return false;
+
+ WorkbookHelperRoot aHelper( *this );
+ if( aHelper.isValid() && importFragment( new OoxWorkbookFragment( aHelper, aWorkbookPath ) ) )
+ {
+ importDocumentProperties();
+ return true;
+ }
+ return false;
+}
+
+bool ExcelFilter::exportDocument() throw()
+{
+ return false;
+}
+
+const ::oox::drawingml::Theme* ExcelFilter::getCurrentTheme() const
+{
+ return &WorkbookHelper( getWorkbookData() ).getTheme();
+}
+
+::oox::vml::Drawing* ExcelFilter::getVmlDrawing()
+{
+ return 0;
+}
+
+const TableStyleListPtr ExcelFilter::getTableStyles()
+{
+ return TableStyleListPtr();
+}
+
+::oox::drawingml::chart::ChartConverter& ExcelFilter::getChartConverter()
+{
+ return WorkbookHelper( getWorkbookData() ).getChartConverter();
+}
+
+GraphicHelper* ExcelFilter::implCreateGraphicHelper() const
+{
+ return new ExcelGraphicHelper( getWorkbookData() );
+}
+
+sal_Bool SAL_CALL ExcelFilter::filter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rDescriptor ) throw( ::com::sun::star::uno::RuntimeException )
+{
+ if ( XmlFilterBase::filter( rDescriptor ) )
+ return true;
+
+ if ( isExportFilter() )
+ {
+ Reference< XExporter > xExporter( getGlobalFactory()->createInstance( CREATE_OUSTRING( "com.sun.star.comp.oox.ExcelFilterExport" ) ), UNO_QUERY );
+
+ if ( xExporter.is() )
+ {
+ Reference< XComponent > xDocument( getModel(), UNO_QUERY );
+ Reference< XFilter > xFilter( xExporter, UNO_QUERY );
+
+ if ( xFilter.is() )
+ {
+ xExporter->setSourceDocument( xDocument );
+ if ( xFilter->filter( rDescriptor ) )
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+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 >& rxGlobalFactory ) throw( Exception )
+{
+ return static_cast< ::cppu::OWeakObject* >( new ExcelBiffFilter( rxGlobalFactory ) );
+}
+
+// ----------------------------------------------------------------------------
+
+ExcelBiffFilter::ExcelBiffFilter( const Reference< XMultiServiceFactory >& rxGlobalFactory ) :
+ BinaryFilterBase( rxGlobalFactory )
+{
+}
+
+ExcelBiffFilter::~ExcelBiffFilter()
+{
+}
+
+bool ExcelBiffFilter::importDocument() throw()
+{
+ /* To activate the BIFF dumper, insert the full path to the file
+ file:///<path-to-oox-module>/source/dump/biffdumper.ini
+ into the environment variable OOO_BIFFDUMPER and start the office with
+ this variable (nonpro only). */
+ OOX_DUMP_FILE( ::oox::dump::biff::Dumper );
+
+ /* The boolean argument "UseBiffFilter" passed through XInitialisation
+ decides whether to import/export the document with this filter (true),
+ or to only use the BIFF file dumper implemented in this filter (false
+ or missing) */
+ Any aUseBiffFilter = getArgument( CREATE_OUSTRING( "UseBiffFilter" ) );
+ bool bUseBiffFilter = false;
+ if( !(aUseBiffFilter >>= bUseBiffFilter) || !bUseBiffFilter )
+ return true;
+
+ // detect BIFF version and workbook stream name
+ OUString aWorkbookName;
+ BiffType eBiff = BiffDetector::detectStorageBiffVersion( aWorkbookName, getStorage() );
+ OSL_ENSURE( eBiff != BIFF_UNKNOWN, "ExcelBiffFilter::ExcelBiffFilter - invalid file format" );
+ if( eBiff == BIFF_UNKNOWN )
+ return false;
+
+ WorkbookHelperRoot aHelper( *this, eBiff );
+ return aHelper.isValid() && BiffWorkbookFragment( aHelper, aWorkbookName ).importFragment();
+}
+
+bool ExcelBiffFilter::exportDocument() throw()
+{
+ return false;
+}
+
+GraphicHelper* ExcelBiffFilter::implCreateGraphicHelper() const
+{
+ return new ExcelGraphicHelper( getWorkbookData() );
+}
+
+OUString ExcelBiffFilter::implGetImplementationName() const
+{
+ return ExcelBiffFilter_getImplementationName();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/excelhandlers.cxx b/oox/source/xls/excelhandlers.cxx
new file mode 100644
index 000000000000..a341484992ea
--- /dev/null
+++ b/oox/source/xls/excelhandlers.cxx
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/excelhandlers.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::FilterBase;
+using ::oox::core::FragmentHandler2;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+// ============================================================================
+
+OoxWorkbookFragmentBase::OoxWorkbookFragmentBase(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ FragmentHandler2( rHelper.getOoxFilter(), rFragmentPath ),
+ WorkbookHelper( rHelper )
+{
+}
+
+// ============================================================================
+
+OoxWorksheetFragmentBase::OoxWorksheetFragmentBase( const WorkbookHelper& rHelper,
+ const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
+ FragmentHandler2( rHelper.getOoxFilter(), rFragmentPath ),
+ WorksheetHelperRoot( rHelper, xProgressBar, eSheetType, nSheet )
+{
+}
+
+OoxWorksheetFragmentBase::OoxWorksheetFragmentBase(
+ const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+ FragmentHandler2( rHelper.getOoxFilter(), rFragmentPath ),
+ WorksheetHelperRoot( rHelper )
+{
+}
+
+// ============================================================================
+// ============================================================================
+
+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
+
+// ============================================================================
+
+BiffHandlerBase::~BiffHandlerBase()
+{
+}
+
+bool BiffHandlerBase::skipRecordBlock( sal_uInt16 nEndRecId )
+{
+ sal_uInt16 nStartRecId = mrStrm.getRecId();
+ while( mrStrm.startNextRecord() && (mrStrm.getRecId() != nEndRecId) )
+ if( mrStrm.getRecId() == nStartRecId )
+ skipRecordBlock( nEndRecId );
+ return !mrStrm.isEof() && (mrStrm.getRecId() == nEndRecId);
+}
+
+bool BiffHandlerBase::isBofRecord() const
+{
+ return
+ (mrStrm.getRecId() == BIFF2_ID_BOF) ||
+ (mrStrm.getRecId() == BIFF3_ID_BOF) ||
+ (mrStrm.getRecId() == BIFF4_ID_BOF) ||
+ (mrStrm.getRecId() == BIFF5_ID_BOF);
+}
+
+// ============================================================================
+
+BiffContextHandler::BiffContextHandler( const BiffHandlerBase& rParent ) :
+ BiffHandlerBase( rParent )
+{
+}
+
+// ============================================================================
+
+namespace prv {
+
+BiffFragmentStreamOwner::BiffFragmentStreamOwner( const FilterBase& rFilter, const OUString& rStrmName )
+{
+ // do not automatically close the root stream (indicated by empty stream name)
+ mxXInStrm.reset( new BinaryXInputStream( rFilter.openInputStream( rStrmName ), rStrmName.getLength() > 0 ) );
+ mxBiffStrm.reset( new BiffInputStream( *mxXInStrm ) );
+}
+
+BiffFragmentStreamOwner::~BiffFragmentStreamOwner()
+{
+}
+
+} // namespace prv
+
+// ----------------------------------------------------------------------------
+
+BiffFragmentHandler::BiffFragmentHandler( const FilterBase& rFilter, const OUString& rStrmName ) :
+ prv::BiffFragmentStreamOwner( rFilter, rStrmName ),
+ BiffHandlerBase( *mxBiffStrm )
+{
+}
+
+BiffFragmentHandler::BiffFragmentHandler( const BiffFragmentHandler& rHandler ) :
+ prv::BiffFragmentStreamOwner( rHandler ),
+ BiffHandlerBase( rHandler )
+{
+}
+
+BiffFragmentType BiffFragmentHandler::startFragment( BiffType eBiff )
+{
+ return mrStrm.startNextRecord() ? implStartFragment( eBiff ) : BIFF_FRAGMENT_UNKNOWN;
+}
+
+BiffFragmentType BiffFragmentHandler::startFragment( BiffType eBiff, sal_Int64 nRecHandle )
+{
+ return mrStrm.startRecordByHandle( nRecHandle ) ? implStartFragment( eBiff ) : BIFF_FRAGMENT_UNKNOWN;
+}
+
+bool BiffFragmentHandler::skipFragment()
+{
+ while( mrStrm.startNextRecord() && (mrStrm.getRecId() != BIFF_ID_EOF) )
+ if( isBofRecord() )
+ skipFragment();
+ return !mrStrm.isEof() && (mrStrm.getRecId() == BIFF_ID_EOF);
+}
+
+BiffFragmentType BiffFragmentHandler::implStartFragment( BiffType eBiff )
+{
+ BiffFragmentType eFragment = BIFF_FRAGMENT_UNKNOWN;
+ /* #i23425# Don't rely on BOF record ID to read BOF contents, but on
+ the detected BIFF version. */
+ if( isBofRecord() )
+ {
+ // BOF is always written unencrypted
+ mrStrm.enableDecoder( false );
+ mrStrm.skip( 2 );
+ sal_uInt16 nType = mrStrm.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_MACROSHEET; 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_MACROSHEET; 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_MACROSHEET; 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_CHARTSHEET; break;
+ case BIFF_BOF_MACRO: eFragment = BIFF_FRAGMENT_MACROSHEET; break;
+ case BIFF_BOF_MODULE: eFragment = BIFF_FRAGMENT_MODULESHEET; 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;
+}
+
+// ============================================================================
+
+BiffWorkbookFragmentBase::BiffWorkbookFragmentBase( const WorkbookHelper& rHelper, const OUString& rStrmName, bool bCloneDecoder ) :
+ BiffFragmentHandler( rHelper.getBaseFilter(), rStrmName ),
+ WorkbookHelper( rHelper )
+{
+ if( bCloneDecoder )
+ getCodecHelper().cloneDecoder( mrStrm );
+}
+
+// ============================================================================
+
+BiffWorksheetFragmentBase::BiffWorksheetFragmentBase( const BiffWorkbookFragmentBase& rParent,
+ ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
+ BiffFragmentHandler( rParent ),
+ WorksheetHelperRoot( rParent, xProgressBar, eSheetType, nSheet )
+{
+}
+
+// ============================================================================
+
+BiffSkipWorksheetFragment::BiffSkipWorksheetFragment(
+ const BiffWorkbookFragmentBase& rParent, ISegmentProgressBarRef xProgressBar, sal_Int16 nSheet ) :
+ BiffWorksheetFragmentBase( rParent, xProgressBar, SHEETTYPE_EMPTYSHEET, nSheet )
+{
+}
+
+bool BiffSkipWorksheetFragment::importFragment()
+{
+ return skipFragment();
+}
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/externallinkbuffer.cxx b/oox/source/xls/externallinkbuffer.cxx
new file mode 100644
index 000000000000..f057f42ca73f
--- /dev/null
+++ b/oox/source/xls/externallinkbuffer.cxx
@@ -0,0 +1,1145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/externallinkbuffer.hxx"
+#include <rtl/strbuf.hxx>
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/DDELinkInfo.hpp>
+#include <com/sun/star/sheet/ExternalLinkType.hpp>
+#include <com/sun/star/sheet/ExternalReference.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+#include <com/sun/star/sheet/SingleReference.hpp>
+#include <com/sun/star/sheet/XDDELinks.hpp>
+#include <com/sun/star/sheet/XDDELink.hpp>
+#include <com/sun/star/sheet/XDDELinkResults.hpp>
+#include <com/sun/star/sheet/XExternalDocLink.hpp>
+#include <com/sun/star/sheet/XExternalDocLinks.hpp>
+#include "oox/helper/attributelist.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/excelhandlers.hxx"
+#include "oox/xls/formulaparser.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::Sequence;
+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::ComplexReference;
+using ::com::sun::star::sheet::DDEItemInfo;
+using ::com::sun::star::sheet::DDELinkInfo;
+using ::com::sun::star::sheet::ExternalLinkInfo;
+using ::com::sun::star::sheet::ExternalReference;
+using ::com::sun::star::sheet::SingleReference;
+using ::com::sun::star::sheet::XDDELinks;
+using ::com::sun::star::sheet::XDDELinkResults;
+using ::com::sun::star::sheet::XExternalDocLinks;
+using ::com::sun::star::sheet::XExternalSheetCache;
+using ::oox::core::Relation;
+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
+
+// ============================================================================
+
+ExternalNameModel::ExternalNameModel() :
+ mbBuiltIn( false ),
+ mbNotify( false ),
+ mbPreferPic( false ),
+ mbStdDocName( false ),
+ mbOleObj( false ),
+ mbIconified( false )
+{
+}
+
+// ============================================================================
+
+ExternalName::ExternalName( const ExternalLink& rParentLink ) :
+ DefinedNameBase( rParentLink ),
+ mrParentLink( rParentLink ),
+ mnStorageId( 0 ),
+ mbDdeLinkCreated( false )
+{
+}
+
+void ExternalName::importDefinedName( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importDefinedName - empty name" );
+ // zero-based index into sheet list of externalBook
+ maModel.mnSheet = rAttribs.getInteger( XML_sheetId, -1 );
+}
+
+void ExternalName::importDdeItem( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importDdeItem - empty name" );
+ maExtNameModel.mbOleObj = false;
+ maExtNameModel.mbStdDocName = rAttribs.getBool( XML_ole, false );
+ maExtNameModel.mbNotify = rAttribs.getBool( XML_advise, false );
+ maExtNameModel.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 )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importOleItem - empty name" );
+ maExtNameModel.mbOleObj = true;
+ maExtNameModel.mbNotify = rAttribs.getBool( XML_advise, false );
+ maExtNameModel.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
+ maExtNameModel.mbIconified = rAttribs.getBool( XML_icon, false );
+}
+
+void ExternalName::importExternalName( RecordInputStream& rStrm )
+{
+ rStrm >> maModel.maName;
+ OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importExternalName - empty name" );
+}
+
+void ExternalName::importExternalNameFlags( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ sal_Int32 nSheetId;
+ rStrm >> nFlags >> nSheetId;
+ // index into sheet list of EXTSHEETNAMES (one-based in OOBIN)
+ maModel.mnSheet = nSheetId - 1;
+ // no flag for built-in names, as in OOX...
+ maExtNameModel.mbNotify = getFlag( nFlags, OOBIN_EXTNAME_AUTOMATIC );
+ maExtNameModel.mbPreferPic = getFlag( nFlags, OOBIN_EXTNAME_PREFERPIC );
+ maExtNameModel.mbStdDocName = getFlag( nFlags, OOBIN_EXTNAME_STDDOCNAME );
+ maExtNameModel.mbOleObj = getFlag( nFlags, OOBIN_EXTNAME_OLEOBJECT );
+ maExtNameModel.mbIconified = getFlag( nFlags, OOBIN_EXTNAME_ICONIFIED );
+ OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_OLE) == maExtNameModel.mbOleObj,
+ "ExternalName::importExternalNameFlags - wrong OLE flag 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;
+ maExtNameModel.mbBuiltIn = getFlag( nFlags, BIFF_EXTNAME_BUILTIN );
+ maExtNameModel.mbNotify = getFlag( nFlags, BIFF_EXTNAME_AUTOMATIC );
+ maExtNameModel.mbPreferPic = getFlag( nFlags, BIFF_EXTNAME_PREFERPIC );
+
+ // BIFF5-BIFF8: sheet index for sheet-local names, OLE settings
+ if( getBiff() >= BIFF5 )
+ {
+ maExtNameModel.mbStdDocName = getFlag( nFlags, BIFF_EXTNAME_STDDOCNAME );
+ maExtNameModel.mbOleObj = getFlag( nFlags, BIFF_EXTNAME_OLEOBJECT );
+ maExtNameModel.mbIconified = getFlag( nFlags, BIFF_EXTNAME_ICONIFIED );
+
+ if( maExtNameModel.mbOleObj )
+ {
+ rStrm >> mnStorageId;
+ }
+ else
+ {
+ /* Import the reference ID for names that are sheet-local in
+ the external document. This index will be resolved later to
+ the index of the external sheet cache which is able to
+ provide the name of the sheet related to this defined name.
+ - BIFF5: one-based index to EXTERNSHEET record containing
+ the document and sheet name
+ - BIFF8: one-based index into EXTERNALBOOK sheet name list
+ The value zero means this external name is a global name.
+ */
+ rStrm.skip( 2 );
+ maModel.mnSheet = rStrm.readuInt16();
+ }
+ }
+ }
+
+ maModel.maName = (getBiff() == BIFF8) ?
+ rStrm.readUniStringBody( rStrm.readuInt8() ) :
+ rStrm.readByteStringUC( false, getTextEncoding() );
+ OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importExternalName - empty name" );
+
+ // load cell references that are stored in hidden external names (seen in BIFF3-BIFF4)
+ bool bHiddenRef = (getBiff() <= BIFF4) && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') && (rStrm.getRemaining() > 2);
+ switch( mrParentLink.getLinkType() )
+ {
+ case LINKTYPE_INTERNAL:
+ // cell references to other internal sheets are stored in hidden external names
+ if( bHiddenRef && (getBiff() == BIFF4) && isWorkbookFile() )
+ {
+ TokensFormulaContext aContext( true, true );
+ importBiffFormula( aContext, mrParentLink.getCalcSheetIndex(), rStrm );
+ extractReference( aContext.getTokens() );
+ }
+ break;
+
+ case LINKTYPE_EXTERNAL:
+ // cell references to other documents are stored in hidden external names
+ if( bHiddenRef )
+ {
+ TokensFormulaContext aContext( true, true );
+ importBiffFormula( aContext, 0, rStrm );
+ extractExternalReference( aContext.getTokens() );
+ }
+ break;
+
+ case LINKTYPE_DDE:
+ case LINKTYPE_OLE:
+ case LINKTYPE_MAYBE_DDE_OLE:
+ // DDE/OLE link results
+ if( rStrm.getRemaining() > 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.isEof() && (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.readByteStringUC( 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.isEof() && (maCurrIt == maResults.end()),
+ "ExternalName::importExternalName - stream error in result set" );
+ }
+ break;
+
+ default:;
+ }
+}
+
+#if 0
+sal_Int32 ExternalName::getSheetCacheIndex() const
+{
+ OSL_ENSURE( mrParentLink.getLinkType() == LINKTYPE_DDE, "ExternalName::getSheetCacheIndex - unexpected link type" );
+ sal_Int32 nCacheIdx = -1;
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ // OOXML/OOBIN: zero-based index into sheet list, -1 means global name
+ if( maModel.mnSheet >= 0 )
+ nCacheIdx = mrParentLink.getSheetIndex( maModel.mnSheet );
+ break;
+ case FILTER_BIFF:
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ break;
+ case BIFF5:
+ if( maModel.mnSheet > 0 )
+ if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( maModel.mnSheet ).get() )
+ if( pExtLink->getLinkType() == LINKTYPE_EXTERNAL )
+ nCacheIdx = pExtLink->getSheetIndex();
+ break;
+ case BIFF8:
+ if( maModel.mnSheet > 0 )
+ nCacheIdx = mrParentLink.getSheetIndex( maModel.mnSheet - 1 );
+ break;
+ case BIFF_UNKNOWN:
+ break;
+ }
+ break;
+ case FILTER_UNKNOWN:
+ break;
+ }
+ return nCacheIdx;
+}
+#endif
+
+bool ExternalName::getDdeItemInfo( DDEItemInfo& orItemInfo ) const
+{
+ if( (mrParentLink.getLinkType() == LINKTYPE_DDE) && (maModel.maName.getLength() > 0) )
+ {
+ orItemInfo.Item = maModel.maName;
+ orItemInfo.Results = ContainerHelper::matrixToSequenceSequence( maResults );
+ return true;
+ }
+ return false;
+}
+
+bool ExternalName::getDdeLinkData( OUString& orDdeServer, OUString& orDdeTopic, OUString& orDdeItem )
+{
+ if( (mrParentLink.getLinkType() == LINKTYPE_DDE) && (maModel.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(), maModel.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;
+}
+
+// private --------------------------------------------------------------------
+
+namespace {
+
+void lclSetSheetCacheIndex( SingleReference& orApiRef, sal_Int32 nCacheIdx )
+{
+ using namespace ::com::sun::star::sheet::ReferenceFlags;
+ setFlag( orApiRef.Flags, SHEET_RELATIVE, false );
+ setFlag( orApiRef.Flags, SHEET_3D, true );
+ orApiRef.Sheet = nCacheIdx;
+}
+
+} // namespace
+
+void ExternalName::extractExternalReference( const ApiTokenSequence& rTokens )
+{
+ OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "ExternalName::setExternalReference - unexpected call" );
+ sal_Int32 nDocLinkIdx = mrParentLink.getDocumentLinkIndex();
+ sal_Int32 nCacheIdx = mrParentLink.getSheetCacheIndex();
+ if( (nDocLinkIdx >= 0) && (nCacheIdx >= 0) )
+ {
+ ExternalReference aExtApiRef;
+ aExtApiRef.Index = nDocLinkIdx;
+
+ Any aRefAny = getFormulaParser().extractReference( rTokens );
+ if( aRefAny.has< SingleReference >() )
+ {
+ SingleReference aApiRef;
+ aRefAny >>= aApiRef;
+ lclSetSheetCacheIndex( aApiRef, nCacheIdx );
+ aExtApiRef.Reference <<= aApiRef;
+ maRefAny <<= aExtApiRef;
+ }
+ else if( aRefAny.has< ComplexReference >() )
+ {
+ ComplexReference aApiRef;
+ aRefAny >>= aApiRef;
+ lclSetSheetCacheIndex( aApiRef.Reference1, nCacheIdx );
+ lclSetSheetCacheIndex( aApiRef.Reference2, nCacheIdx );
+ aExtApiRef.Reference <<= aApiRef;
+ maRefAny <<= aExtApiRef;
+ }
+ }
+}
+
+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();
+}
+
+// ============================================================================
+
+void LinkSheetRange::setDeleted()
+{
+ meType = LINKSHEETRANGE_INTERNAL;
+ mnDocLink = mnFirst = mnLast = -1;
+}
+
+void LinkSheetRange::setSameSheet()
+{
+ meType = LINKSHEETRANGE_SAMESHEET;
+ mnDocLink = -1;
+ mnFirst = mnLast = 0;
+}
+
+void LinkSheetRange::setRange( sal_Int32 nFirst, sal_Int32 nLast )
+{
+ meType = LINKSHEETRANGE_INTERNAL;
+ mnDocLink = -1;
+ mnFirst = ::std::min( nFirst, nLast );
+ mnLast = ::std::max( nFirst, nLast );
+}
+
+void LinkSheetRange::setExternalRange( sal_Int32 nDocLink, sal_Int32 nFirst, sal_Int32 nLast )
+{
+ if( nDocLink < 0 )
+ {
+ setDeleted();
+ }
+ else
+ {
+ meType = LINKSHEETRANGE_EXTERNAL;
+ mnDocLink = nDocLink;
+ mnFirst = ::std::min( nFirst, nLast );
+ mnLast = ::std::max( nFirst, nLast );
+ }
+}
+
+// ============================================================================
+
+ExternalLink::ExternalLink( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ meLinkType( LINKTYPE_UNKNOWN ),
+ meFuncLibType( FUNCLIB_UNKNOWN )
+{
+}
+
+void ExternalLink::importExternalReference( const AttributeList& rAttribs )
+{
+ maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
+}
+
+void ExternalLink::importExternalBook( const Relations& rRelations, const AttributeList& rAttribs )
+{
+ parseExternalReference( rRelations, rAttribs.getString( R_TOKEN( id ), OUString() ) );
+}
+
+void ExternalLink::importSheetName( const AttributeList& rAttribs )
+{
+ insertExternalSheet( rAttribs.getXString( XML_val, OUString() ) );
+}
+
+void ExternalLink::importDefinedName( const AttributeList& rAttribs )
+{
+ createExternalName()->importDefinedName( rAttribs );
+}
+
+void ExternalLink::importDdeLink( const AttributeList& rAttribs )
+{
+ OUString aDdeService = rAttribs.getXString( XML_ddeService, OUString() );
+ OUString aDdeTopic = rAttribs.getXString( XML_ddeTopic, OUString() );
+ 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.getXString( XML_progId, OUString() );
+ OUString aTargetUrl = rRelations.getExternalTargetFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ 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::importExternalSame( RecordInputStream& )
+{
+ meLinkType = LINKTYPE_SAME;
+}
+
+void ExternalLink::importExternalAddin( RecordInputStream& )
+{
+ meLinkType = LINKTYPE_UNKNOWN;
+}
+
+void ExternalLink::importExternalBook( const Relations& rRelations, RecordInputStream& rStrm )
+{
+ switch( rStrm.readuInt16() )
+ {
+ case OOBIN_EXTERNALBOOK_BOOK:
+ parseExternalReference( rRelations, rStrm.readString() );
+ break;
+ case OOBIN_EXTERNALBOOK_DDE:
+ {
+ OUString aDdeService, aDdeTopic;
+ rStrm >> aDdeService >> aDdeTopic;
+ setDdeOleTargetUrl( aDdeService, aDdeTopic, LINKTYPE_DDE );
+ }
+ break;
+ case OOBIN_EXTERNALBOOK_OLE:
+ {
+ OUString aTargetUrl = rRelations.getExternalTargetFromRelId( 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 sheet caches in the Calc document
+ OSL_ENSURE( (meLinkType == LINKTYPE_EXTERNAL) || (meLinkType == LINKTYPE_LIBRARY),
+ "ExternalLink::importExtSheetNames - invalid link type" );
+ if( meLinkType == LINKTYPE_EXTERNAL ) // ignore sheets of external libraries
+ for( sal_Int32 nSheet = 0, nCount = rStrm.readInt32(); !rStrm.isEof() && (nSheet < nCount); ++nSheet )
+ insertExternalSheet( rStrm.readString() );
+}
+
+ExternalNameRef ExternalLink::importExternalName( RecordInputStream& rStrm )
+{
+ ExternalNameRef xExtName = createExternalName();
+ xExtName->importExternalName( rStrm );
+ return xExtName;
+}
+
+void ExternalLink::importExternSheet( BiffInputStream& rStrm )
+{
+ OStringBuffer aTargetBuffer( rStrm.readByteString( false, true ) );
+ // 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:
+ maCalcSheets.push_back( getWorksheets().getCalcSheetIndex( aSheetName ) );
+ break;
+ case LINKTYPE_EXTERNAL:
+ insertExternalSheet( (aSheetName.getLength() > 0) ? aSheetName : WorksheetBuffer::getBaseFileName( maTargetUrl ) );
+ break;
+ default:;
+ }
+}
+
+void ExternalLink::importExternalBook( BiffInputStream& rStrm )
+{
+ OUString aTarget;
+ sal_uInt16 nSheetCount;
+ rStrm >> nSheetCount;
+ if( rStrm.getRemaining() == 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.getRemaining() >= 3 )
+ {
+ // NUL characters may occur
+ aTarget = rStrm.readUniString( true );
+ }
+
+ // 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 sheet caches in the Calc document
+ if( meLinkType == LINKTYPE_EXTERNAL )
+ for( sal_uInt16 nSheet = 0; !rStrm.isEof() && (nSheet < nSheetCount); ++nSheet )
+ insertExternalSheet( rStrm.readUniString() );
+}
+
+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" );
+ }
+}
+
+ExternalLinkInfo ExternalLink::getLinkInfo() const
+{
+ ExternalLinkInfo aLinkInfo;
+ switch( meLinkType )
+ {
+ case LINKTYPE_EXTERNAL:
+ aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::DOCUMENT;
+ aLinkInfo.Data <<= maTargetUrl;
+ break;
+ case LINKTYPE_DDE:
+ {
+ aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::DDE;
+ DDELinkInfo aDdeLinkInfo;
+ aDdeLinkInfo.Service = maClassName;
+ aDdeLinkInfo.Topic = maTargetUrl;
+ ::std::vector< DDEItemInfo > aItemInfos;
+ DDEItemInfo aItemInfo;
+ for( ExternalNameVector::const_iterator aIt = maExtNames.begin(), aEnd = maExtNames.end(); aIt != aEnd; ++aIt )
+ if( (*aIt)->getDdeItemInfo( aItemInfo ) )
+ aItemInfos.push_back( aItemInfo );
+ aDdeLinkInfo.Items = ContainerHelper::vectorToSequence( aItemInfos );
+ aLinkInfo.Data <<= aDdeLinkInfo;
+ }
+ break;
+ default:
+ aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::UNKNOWN;
+ }
+ return aLinkInfo;
+}
+
+FunctionLibraryType ExternalLink::getFuncLibraryType() const
+{
+ return (meLinkType == LINKTYPE_LIBRARY) ? meFuncLibType : FUNCLIB_UNKNOWN;
+}
+
+sal_Int16 ExternalLink::getCalcSheetIndex( sal_Int32 nTabId ) const
+{
+ OSL_ENSURE( meLinkType == LINKTYPE_INTERNAL, "ExternalLink::getCalcSheetIndex - invalid link type" );
+ OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOX) || (getBiff() == BIFF8),
+ "ExternalLink::getCalcSheetIndex - invalid sheet index" );
+ return ContainerHelper::getVectorElement< sal_Int16 >( maCalcSheets, nTabId, -1 );
+}
+
+sal_Int32 ExternalLink::getDocumentLinkIndex() const
+{
+ OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::getDocumentLinkIndex - invalid link type" );
+ return mxDocLink.is() ? mxDocLink->getTokenIndex() : -1;
+}
+
+sal_Int32 ExternalLink::getSheetCacheIndex( sal_Int32 nTabId ) const
+{
+ OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::getSheetCacheIndex - invalid link type" );
+ OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOX) || (getBiff() == BIFF8),
+ "ExternalLink::getSheetCacheIndex - invalid sheet index" );
+ return ContainerHelper::getVectorElement< sal_Int32 >( maSheetCaches, nTabId, -1 );
+}
+
+Reference< XExternalSheetCache > ExternalLink::getSheetCache( sal_Int32 nTabId ) const
+{
+ sal_Int32 nCacheIdx = getSheetCacheIndex( nTabId );
+ if( mxDocLink.is() && (nCacheIdx >= 0) ) try
+ {
+ // existing mxDocLink implies that this is an external link
+ Reference< XExternalSheetCache > xSheetCache( mxDocLink->getByIndex( nCacheIdx ), UNO_QUERY_THROW );
+ return xSheetCache;
+ }
+ catch( Exception& )
+ {
+ }
+ return 0;
+}
+
+void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId1, sal_Int32 nTabId2 ) const
+{
+ switch( meLinkType )
+ {
+ case LINKTYPE_SAME:
+ orSheetRange.setSameSheet();
+ break;
+
+ case LINKTYPE_SELF:
+ case LINKTYPE_INTERNAL:
+ orSheetRange.setRange( nTabId1, nTabId2 );
+ break;
+
+ case LINKTYPE_EXTERNAL:
+ {
+ sal_Int32 nDocLinkIdx = getDocumentLinkIndex();
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ // OOBIN: passed indexes point into sheet list of EXTSHEETLIST
+ orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
+ break;
+ case FILTER_BIFF:
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( 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.setExternalRange( nDocLinkIdx, getSheetCacheIndex(), pExtLink2->getSheetCacheIndex() );
+ break;
+ case BIFF8:
+ // BIFF8: passed indexes point into sheet list of EXTERNALBOOK
+ orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+ break;
+ case FILTER_UNKNOWN: break;
+ }
+ }
+ break;
+
+ default:
+ // unsupported/unexpected link type: #REF! error
+ orSheetRange.setDeleted();
+ }
+}
+
+ExternalNameRef ExternalLink::getNameByIndex( sal_Int32 nIndex ) const
+{
+ return maExtNames.get( nIndex );
+}
+
+// private --------------------------------------------------------------------
+
+#define OOX_TARGETTYPE_EXTLINK CREATE_OFFICEDOC_RELATIONSTYPE( "externalLinkPath" )
+#define OOX_TARGETTYPE_LIBRARY CREATE_MSOFFICE_RELATIONSTYPE( "xlExternalLinkPath/xlLibrary" )
+
+void ExternalLink::setExternalTargetUrl( const OUString& rTargetUrl, const OUString& rTargetType )
+{
+ meLinkType = LINKTYPE_UNKNOWN;
+ if( rTargetType == OOX_TARGETTYPE_EXTLINK )
+ {
+ maTargetUrl = getBaseFilter().getAbsoluteUrl( rTargetUrl );
+ if( maTargetUrl.getLength() > 0 )
+ meLinkType = LINKTYPE_EXTERNAL;
+ }
+ else if( rTargetType == OOX_TARGETTYPE_LIBRARY )
+ {
+ meLinkType = LINKTYPE_LIBRARY;
+ meFuncLibType = getFormulaParser().getFuncLibTypeFromLibraryName( rTargetUrl );
+ }
+ OSL_ENSURE( meLinkType != LINKTYPE_UNKNOWN, "ExternalLink::setExternalTargetUrl - empty target URL or unknown target type" );
+
+ // create the external document link API object that will contain the sheet caches
+ if( meLinkType == LINKTYPE_EXTERNAL )
+ {
+ Reference< XExternalDocLinks > xDocLinks = getExternalDocLinks();
+ if( xDocLinks.is() )
+ mxDocLink = xDocLinks->addDocLink( maTargetUrl );
+ }
+}
+
+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" );
+}
+
+void ExternalLink::parseExternalReference( const Relations& rRelations, const OUString& rRelId )
+{
+ if( const Relation* pRelation = rRelations.getRelationFromRelId( rRelId ) )
+ setExternalTargetUrl( pRelation->maTarget, pRelation->maType );
+}
+
+OUString ExternalLink::parseBiffTargetUrl( const OUString& rBiffTargetUrl )
+{
+ meLinkType = LINKTYPE_UNKNOWN;
+
+ OUString aClassName, aTargetUrl, aSheetName;
+ switch( getAddressConverter().parseBiffTargetUrl( aClassName, aTargetUrl, aSheetName, rBiffTargetUrl ) )
+ {
+ case BIFF_TARGETTYPE_URL:
+ 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 ] != ' ') )
+ {
+ setExternalTargetUrl( aTargetUrl, OOX_TARGETTYPE_EXTLINK );
+ }
+ break;
+
+ case BIFF_TARGETTYPE_SAMESHEET:
+ OSL_ENSURE( (aTargetUrl.getLength() == 0) && (aSheetName.getLength() == 0), "ExternalLink::parseBiffTargetUrl - unexpected target or sheet name" );
+ meLinkType = LINKTYPE_SAME;
+ break;
+
+ case BIFF_TARGETTYPE_LIBRARY:
+ OSL_ENSURE( aSheetName.getLength() == 0, "ExternalLink::parseBiffTargetUrl - unexpected sheet name" );
+ setExternalTargetUrl( aTargetUrl, OOX_TARGETTYPE_LIBRARY );
+ break;
+
+ case BIFF_TARGETTYPE_DDE_OLE:
+ setDdeOleTargetUrl( aClassName, aTargetUrl, LINKTYPE_MAYBE_DDE_OLE );
+ break;
+
+ case BIFF_TARGETTYPE_UNKNOWN:
+ break;
+ }
+ return aSheetName;
+}
+
+void ExternalLink::insertExternalSheet( const OUString& rSheetName )
+{
+ OSL_ENSURE( rSheetName.getLength() > 0, "ExternalLink::insertExternalSheet - empty sheet name" );
+ if( mxDocLink.is() )
+ {
+ Reference< XExternalSheetCache > xSheetCache = mxDocLink->addSheetCache( rSheetName, false );
+ sal_Int32 nCacheIdx = xSheetCache.is() ? xSheetCache->getTokenIndex() : -1;
+ maSheetCaches.push_back( nCacheIdx );
+ }
+}
+
+ExternalNameRef ExternalLink::createExternalName()
+{
+ ExternalNameRef xExtName( new ExternalName( *this ) );
+ maExtNames.push_back( xExtName );
+ return xExtName;
+}
+
+// ============================================================================
+
+RefSheetsModel::RefSheetsModel() :
+ mnExtRefId( -1 ),
+ mnTabId1( -1 ),
+ mnTabId2( -1 )
+{
+}
+
+void RefSheetsModel::readOobData( RecordInputStream& rStrm )
+{
+ rStrm >> mnExtRefId >> mnTabId1 >> mnTabId2;
+}
+
+void RefSheetsModel::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 );
+ maExtLinks.push_back( xExtLink );
+ return xExtLink;
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternalRef( RecordInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ ExternalLinkRef xExtLink = createExternalLink();
+ xExtLink->importExternalRef( rStrm );
+ maExtLinks.push_back( xExtLink );
+ return xExtLink;
+}
+
+void ExternalLinkBuffer::importExternalSelf( RecordInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ createExternalLink()->importExternalSelf( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalSame( RecordInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ createExternalLink()->importExternalSame( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalAddin( RecordInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ createExternalLink()->importExternalAddin( 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_Int64 >( nRefCount, 0, rStrm.getRemaining() / 12 );
+ maRefSheets.reserve( nMaxCount );
+ for( size_t nRefId = 0; !rStrm.isEof() && (nRefId < nMaxCount); ++nRefId )
+ {
+ RefSheetsModel 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( !maLinks.empty() )
+ maLinks.back()->importExternalName( rStrm );
+}
+
+void ExternalLinkBuffer::importExternSheet8( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( getBiff() == BIFF8, "ExternalLinkBuffer::importExternSheet8 - wrong BIFF version" );
+
+ sal_uInt16 nRefCount;
+ rStrm >> nRefCount;
+ OSL_ENSURE( static_cast< sal_Int64 >( nRefCount * 6 ) == rStrm.getRemaining(), "ExternalLinkBuffer::importExternSheet8 - invalid count" );
+ nRefCount = static_cast< sal_uInt16 >( ::std::min< sal_Int64 >( nRefCount, rStrm.getRemaining() / 6 ) );
+
+ /* #i104057# A weird external XLS generator writes multiple EXTERNSHEET
+ records instead of only one as expected. Surprisingly, Excel seems to
+ insert the entries of the second record before the entries of the first
+ record. */
+ maRefSheets.insert( maRefSheets.begin(), nRefCount, RefSheetsModel() );
+ for( RefSheetsModelVec::iterator aIt = maRefSheets.begin(); !rStrm.isEof() && (nRefCount > 0); --nRefCount )
+ aIt->readBiff8Data( rStrm );
+}
+
+Sequence< ExternalLinkInfo > ExternalLinkBuffer::getLinkInfos() const
+{
+ ::std::vector< ExternalLinkInfo > aLinkInfos;
+ // dummy entry for index 0
+ aLinkInfos.push_back( ExternalLinkInfo( ::com::sun::star::sheet::ExternalLinkType::UNKNOWN, Any() ) );
+ for( ExternalLinkVec::const_iterator aIt = maExtLinks.begin(), aEnd = maExtLinks.end(); aIt != aEnd; ++aIt )
+ aLinkInfos.push_back( (*aIt)->getLinkInfo() );
+ return ContainerHelper::vectorToSequence( aLinkInfos );
+}
+
+ExternalLinkRef ExternalLinkBuffer::getExternalLink( sal_Int32 nRefId ) const
+{
+ ExternalLinkRef xExtLink;
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ // OOXML: one-based index
+ if( !mbUseRefSheets )
+ xExtLink = maLinks.get( nRefId - 1 );
+ // OOBIN: zero-based index into ref-sheets list
+ else if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
+ xExtLink = maLinks.get( pRefSheets->mnExtRefId );
+ break;
+ case FILTER_BIFF:
+ switch( getBiff() )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ // one-based index to EXTERNSHEET records
+ xExtLink = maLinks.get( nRefId - 1 );
+ break;
+ case BIFF5:
+ if( nRefId < 0 )
+ {
+ // internal links in formula tokens have negative index
+ xExtLink = maLinks.get( -nRefId - 1 );
+ if( xExtLink.get() && !xExtLink->isInternalLink() )
+ xExtLink.reset();
+ }
+ else
+ {
+ // one-based index to EXTERNSHEET records
+ xExtLink = maLinks.get( nRefId - 1 );
+ }
+ break;
+ case BIFF8:
+ // zero-based index into REF list in EXTERNSHEET record
+ if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
+ xExtLink = maLinks.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 RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
+ pExtLink->getSheetRange( aSheetRange, pRefSheets->mnTabId1, pRefSheets->mnTabId2 );
+ return aSheetRange;
+}
+
+// private --------------------------------------------------------------------
+
+ExternalLinkRef ExternalLinkBuffer::createExternalLink()
+{
+ ExternalLinkRef xExtLink( new ExternalLink( *this ) );
+ maLinks.push_back( xExtLink );
+ return xExtLink;
+}
+
+const RefSheetsModel* 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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/externallinkfragment.cxx b/oox/source/xls/externallinkfragment.cxx
new file mode 100644
index 000000000000..3a451a2610b6
--- /dev/null
+++ b/oox/source/xls/externallinkfragment.cxx
@@ -0,0 +1,553 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/externallinkfragment.hxx"
+#include <com/sun/star/sheet/XExternalSheetCache.hpp>
+#include "oox/helper/attributelist.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::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::sheet::XExternalSheetCache;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+using ::oox::core::Relation;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxExternalSheetDataContext::OoxExternalSheetDataContext(
+ OoxWorkbookFragmentBase& rFragment, const Reference< XExternalSheetCache >& rxSheetCache ) :
+ OoxWorkbookContextBase( rFragment ),
+ mxSheetCache( rxSheetCache )
+{
+ OSL_ENSURE( mxSheetCache.is(), "OoxExternalSheetDataContext::OoxExternalSheetDataContext - missing sheet cache" );
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxExternalSheetDataContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( sheetData ):
+ if( nElement == XLS_TOKEN( row ) ) return this;
+ break;
+ case XLS_TOKEN( row ):
+ if( nElement == XLS_TOKEN( cell ) ) { importCell( rAttribs ); return this; }
+ break;
+ case XLS_TOKEN( cell ):
+ if( nElement == XLS_TOKEN( v ) ) return this; // collect characters in onEndElement()
+ break;
+ }
+ return 0;
+}
+
+void OoxExternalSheetDataContext::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( v ):
+ switch( mnCurrType )
+ {
+ case XML_b:
+ case XML_n:
+ setCellValue( Any( rChars.toDouble() ) );
+ break;
+ case XML_e:
+ setCellValue( Any( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( rChars ) ) ) );
+ break;
+ case XML_str:
+ setCellValue( Any( rChars ) );
+ break;
+ }
+ mnCurrType = XML_TOKEN_INVALID;
+ break;
+ }
+}
+
+ContextHandlerRef OoxExternalSheetDataContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_EXTSHEETDATA:
+ if( nRecId == OOBIN_ID_EXTROW ) { maCurrPos.Row = rStrm.readInt32(); return this; }
+ break;
+ case OOBIN_ID_EXTROW:
+ switch( nRecId )
+ {
+ case OOBIN_ID_EXTCELL_BLANK: importExtCellBlank( rStrm ); break;
+ 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;
+ }
+ break;
+ }
+ return 0;
+}
+
+// private --------------------------------------------------------------------
+
+void OoxExternalSheetDataContext::importCell( const AttributeList& rAttribs )
+{
+ if( getAddressConverter().convertToCellAddress( maCurrPos, rAttribs.getString( XML_r, OUString() ), 0, false ) )
+ mnCurrType = rAttribs.getToken( XML_t, XML_n );
+ else
+ mnCurrType = XML_TOKEN_INVALID;
+}
+
+void OoxExternalSheetDataContext::importExtCellBlank( RecordInputStream& rStrm )
+{
+ maCurrPos.Column = rStrm.readInt32();
+ setCellValue( Any( OUString() ) );
+}
+
+void OoxExternalSheetDataContext::importExtCellBool( RecordInputStream& rStrm )
+{
+ maCurrPos.Column = rStrm.readInt32();
+ double fValue = (rStrm.readuInt8() == 0) ? 0.0 : 1.0;
+ setCellValue( Any( fValue ) );
+}
+
+void OoxExternalSheetDataContext::importExtCellDouble( RecordInputStream& rStrm )
+{
+ maCurrPos.Column = rStrm.readInt32();
+ setCellValue( Any( rStrm.readDouble() ) );
+}
+
+void OoxExternalSheetDataContext::importExtCellError( RecordInputStream& rStrm )
+{
+ maCurrPos.Column = rStrm.readInt32();
+ setCellValue( Any( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) ) );
+}
+
+void OoxExternalSheetDataContext::importExtCellString( RecordInputStream& rStrm )
+{
+ maCurrPos.Column = rStrm.readInt32();
+ setCellValue( Any( rStrm.readString() ) );
+}
+
+void OoxExternalSheetDataContext::setCellValue( const Any& rValue )
+{
+ if( mxSheetCache.is() && getAddressConverter().checkCellAddress( maCurrPos, false ) ) try
+ {
+ mxSheetCache->setCellValue( maCurrPos.Column, maCurrPos.Row, rValue );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+
+OoxExternalLinkFragment::OoxExternalLinkFragment( const WorkbookHelper& rHelper,
+ const OUString& rFragmentPath, ExternalLink& rExtLink ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath ),
+ mrExtLink( rExtLink ),
+ mnResultType( XML_TOKEN_INVALID )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxExternalLinkFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( externalLink ) ) return this;
+ break;
+
+ case XLS_TOKEN( externalLink ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( externalBook ): mrExtLink.importExternalBook( getRelations(), rAttribs ); return this;
+ case XLS_TOKEN( ddeLink ): mrExtLink.importDdeLink( rAttribs ); return this;
+ case XLS_TOKEN( oleLink ): mrExtLink.importOleLink( getRelations(), rAttribs ); return this;
+ }
+ break;
+
+ case XLS_TOKEN( externalBook ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( sheetNames ):
+ case XLS_TOKEN( definedNames ):
+ case XLS_TOKEN( sheetDataSet ): return this;
+ }
+ break;
+
+ case XLS_TOKEN( sheetNames ):
+ if( nElement == XLS_TOKEN( sheetName ) ) mrExtLink.importSheetName( rAttribs );
+ break;
+ case XLS_TOKEN( definedNames ):
+ if( nElement == XLS_TOKEN( definedName ) ) mrExtLink.importDefinedName( rAttribs );
+ break;
+ case XLS_TOKEN( sheetDataSet ):
+ if( (nElement == XLS_TOKEN( sheetData )) && (mrExtLink.getLinkType() == LINKTYPE_EXTERNAL) )
+ return createSheetDataContext( rAttribs.getInteger( XML_sheetId, -1 ) );
+ break;
+
+ case XLS_TOKEN( ddeLink ):
+ if( nElement == XLS_TOKEN( ddeItems ) ) return this;
+ break;
+ case XLS_TOKEN( ddeItems ):
+ if( nElement == XLS_TOKEN( ddeItem ) )
+ {
+ mxExtName = mrExtLink.importDdeItem( rAttribs );
+ return this;
+ }
+ break;
+ case XLS_TOKEN( ddeItem ):
+ if( nElement == XLS_TOKEN( values ) )
+ {
+ if( mxExtName.get() ) mxExtName->importValues( rAttribs );
+ return this;
+ }
+ break;
+ case XLS_TOKEN( values ):
+ if( nElement == XLS_TOKEN( value ) )
+ {
+ mnResultType = rAttribs.getToken( XML_t, XML_n );
+ return this;
+ }
+ break;
+ case XLS_TOKEN( value ):
+ if( nElement == XLS_TOKEN( val ) ) return this; // collect value in onEndElement()
+ break;
+
+ case XLS_TOKEN( oleLink ):
+ if( nElement == XLS_TOKEN( oleItems ) ) return this;
+ break;
+ case XLS_TOKEN( oleItems ):
+ if( nElement == XLS_TOKEN( oleItem ) ) mxExtName = mrExtLink.importOleItem( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+void OoxExternalLinkFragment::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentElement() )
+ {
+ 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;
+ }
+}
+
+ContextHandlerRef OoxExternalLinkFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_EXTERNALBOOK )
+ {
+ mrExtLink.importExternalBook( getRelations(), rStrm );
+ return this;
+ }
+ break;
+
+ case OOBIN_ID_EXTERNALBOOK:
+ switch( nRecId )
+ {
+ case OOBIN_ID_EXTSHEETDATA:
+ if( mrExtLink.getLinkType() == LINKTYPE_EXTERNAL )
+ return createSheetDataContext( rStrm.readInt32() );
+ break;
+
+ case OOBIN_ID_EXTSHEETNAMES: mrExtLink.importExtSheetNames( rStrm ); break;
+ case OOBIN_ID_EXTERNALNAME: mxExtName = mrExtLink.importExternalName( rStrm ); return this;
+ }
+ break;
+
+ case OOBIN_ID_EXTERNALNAME:
+ switch( nRecId )
+ {
+ case OOBIN_ID_EXTERNALNAMEFLAGS: if( mxExtName.get() ) mxExtName->importExternalNameFlags( rStrm ); break;
+ case OOBIN_ID_DDEITEMVALUES: if( mxExtName.get() ) mxExtName->importDdeItemValues( rStrm ); return this;
+ }
+ break;
+
+ case OOBIN_ID_DDEITEMVALUES:
+ switch( nRecId )
+ {
+ 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;
+ }
+ break;
+ }
+ return 0;
+}
+
+ContextHandlerRef OoxExternalLinkFragment::createSheetDataContext( sal_Int32 nSheetId )
+{
+ return new OoxExternalSheetDataContext( *this, mrExtLink.getSheetCache( nSheetId ) );
+}
+
+// oox.core.FragmentHandler2 interface ----------------------------------------
+
+const RecordInfo* OoxExternalLinkFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_DDEITEMVALUES, OOBIN_ID_DDEITEMVALUES + 1 },
+ { OOBIN_ID_EXTERNALBOOK, OOBIN_ID_EXTERNALBOOK + 228 },
+ { OOBIN_ID_EXTERNALNAME, OOBIN_ID_EXTERNALNAME + 10 },
+ { OOBIN_ID_EXTROW, -1 },
+ { OOBIN_ID_EXTSHEETDATA, OOBIN_ID_EXTSHEETDATA + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+// ============================================================================
+
+BiffExternalLinkFragment::BiffExternalLinkFragment( const BiffWorkbookFragmentBase& rParent, bool bImportDefNames ) :
+ BiffWorkbookFragmentBase( rParent ),
+ mbImportDefNames( bImportDefNames )
+{
+}
+
+BiffExternalLinkFragment::~BiffExternalLinkFragment()
+{
+}
+
+bool BiffExternalLinkFragment::importFragment()
+{
+ // process all record in this sheet fragment
+ while( mrStrm.startNextRecord() && (mrStrm.getRecId() != BIFF_ID_EOF) )
+ {
+ if( isBofRecord() )
+ skipFragment(); // skip unknown embedded fragments
+ else
+ importRecord();
+ }
+ return !mrStrm.isEof() && (mrStrm.getRecId() == BIFF_ID_EOF);
+}
+
+void BiffExternalLinkFragment::importRecord()
+{
+ sal_uInt16 nRecId = mrStrm.getRecId();
+ switch( getBiff() )
+ {
+ case BIFF2: switch( nRecId )
+ {
+ case BIFF2_ID_EXTERNALNAME: importExternalName(); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet(); break;
+ case BIFF2_ID_DEFINEDNAME: importDefinedName(); break;
+ }
+ break;
+ case BIFF3: switch( nRecId )
+ {
+ case BIFF_ID_CRN: importCrn(); break;
+ case BIFF3_ID_EXTERNALNAME: importExternalName(); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet(); break;
+ case BIFF3_ID_DEFINEDNAME: importDefinedName(); break;
+ case BIFF_ID_XCT: importXct(); break;
+ }
+ break;
+ case BIFF4: switch( nRecId )
+ {
+ case BIFF_ID_CRN: importCrn(); break;
+ case BIFF3_ID_EXTERNALNAME: importExternalName(); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet(); break;
+ case BIFF3_ID_DEFINEDNAME: importDefinedName(); break;
+ case BIFF_ID_XCT: importXct(); break;
+ }
+ break;
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF_ID_CRN: importCrn(); break;
+ case BIFF5_ID_EXTERNALNAME: importExternalName(); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet(); break;
+ case BIFF5_ID_DEFINEDNAME: importDefinedName(); break;
+ case BIFF_ID_XCT: importXct(); break;
+ }
+ break;
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF_ID_CRN: importCrn(); break;
+ case BIFF_ID_EXTERNALBOOK: importExternalBook(); break;
+ case BIFF5_ID_EXTERNALNAME: importExternalName(); break;
+ case BIFF_ID_EXTERNSHEET: importExternSheet(); break;
+ case BIFF5_ID_DEFINEDNAME: importDefinedName(); break;
+ case BIFF_ID_XCT: importXct(); break;
+ }
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+}
+
+void BiffExternalLinkFragment::finalizeImport()
+{
+ getDefinedNames().finalizeImport();
+}
+
+// private --------------------------------------------------------------------
+
+void BiffExternalLinkFragment::importExternSheet()
+{
+ mxSheetCache.clear();
+ if( getBiff() == BIFF8 )
+ getExternalLinks().importExternSheet8( mrStrm );
+ else
+ mxExtLink = getExternalLinks().importExternSheet( mrStrm );
+}
+
+void BiffExternalLinkFragment::importExternalBook()
+{
+ mxSheetCache.clear();
+ mxExtLink = getExternalLinks().importExternalBook( mrStrm );
+}
+
+void BiffExternalLinkFragment::importExternalName()
+{
+ if( mxExtLink.get() )
+ mxExtLink->importExternalName( mrStrm );
+}
+
+void BiffExternalLinkFragment::importXct()
+{
+ mxSheetCache.clear();
+ if( mxExtLink.get() && (mxExtLink->getLinkType() == LINKTYPE_EXTERNAL) )
+ {
+ switch( getBiff() )
+ {
+ case BIFF2:
+ break;
+ case BIFF3:
+ case BIFF4:
+ case BIFF5:
+ mxSheetCache = mxExtLink->getSheetCache( 0 );
+ break;
+ case BIFF8:
+ mrStrm.skip( 2 );
+ mxSheetCache = mxExtLink->getSheetCache( mrStrm.readInt16() );
+ break;
+ case BIFF_UNKNOWN: break;
+ }
+ }
+}
+
+void BiffExternalLinkFragment::importCrn()
+{
+ if( !mxSheetCache.is() ) return;
+
+ sal_uInt8 nCol2, nCol1;
+ sal_uInt16 nRow;
+ mrStrm >> nCol2 >> nCol1 >> nRow;
+ bool bLoop = true;
+ for( BinAddress aBinAddr( nCol1, nRow ); bLoop && !mrStrm.isEof() && (aBinAddr.mnCol <= nCol2); ++aBinAddr.mnCol )
+ {
+ switch( mrStrm.readuInt8() )
+ {
+ case BIFF_DATATYPE_EMPTY:
+ mrStrm.skip( 8 );
+ setCellValue( aBinAddr, Any( OUString() ) );
+ break;
+ case BIFF_DATATYPE_DOUBLE:
+ setCellValue( aBinAddr, Any( mrStrm.readDouble() ) );
+ break;
+ case BIFF_DATATYPE_STRING:
+ {
+ OUString aText = (getBiff() == BIFF8) ? mrStrm.readUniString() : mrStrm.readByteStringUC( false, getTextEncoding() );
+ setCellValue( aBinAddr, Any( aText ) );
+ }
+ break;
+ case BIFF_DATATYPE_BOOL:
+ {
+ double fValue = (mrStrm.readuInt8() == 0) ? 0.0 : 1.0;
+ setCellValue( aBinAddr, Any( fValue ) );
+ mrStrm.skip( 7 );
+ }
+ break;
+ case BIFF_DATATYPE_ERROR:
+ setCellValue( aBinAddr, Any( BiffHelper::calcDoubleFromError( mrStrm.readuInt8() ) ) );
+ mrStrm.skip( 7 );
+ break;
+ default:
+ OSL_ENSURE( false, "BiffExternalLinkFragment::importCrn - unknown data type" );
+ bLoop = false;
+ }
+ }
+}
+
+void BiffExternalLinkFragment::importDefinedName()
+{
+ if( mbImportDefNames )
+ getDefinedNames().importDefinedName( mrStrm );
+}
+
+void BiffExternalLinkFragment::setCellValue( const BinAddress& rBinAddr, const Any& rValue )
+{
+ CellAddress aCellPos;
+ if( mxSheetCache.is() && getAddressConverter().convertToCellAddress( aCellPos, rBinAddr, 0, false ) ) try
+ {
+ mxSheetCache->setCellValue( aCellPos.Column, aCellPos.Row, rValue );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/formulabase.cxx b/oox/source/xls/formulabase.cxx
new file mode 100644
index 000000000000..fbde6fd1721c
--- /dev/null
+++ b/oox/source/xls/formulabase.cxx
@@ -0,0 +1,1752 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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/table/XCellRange.hpp>
+#include <com/sun/star/sheet/AddressConvention.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/XFormulaParser.hpp>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include "properties.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::lang::XMultiServiceFactory;
+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::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::table::XCellRange;
+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;
+
+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 );
+}
+
+// token vector, sequence =====================================================
+
+ApiTokenVector::ApiTokenVector()
+{
+}
+
+Any& ApiTokenVector::append( sal_Int32 nOpCode )
+{
+ resize( size() + 1 );
+ back().OpCode = nOpCode;
+ return back().Data;
+}
+
+// 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;
+}
+
+// function data ==============================================================
+
+namespace {
+
+const size_t FUNCINFO_PARAMINFOCOUNT = 5; /// Number of parameter type entries.
+
+const sal_uInt16 FUNCFLAG_VOLATILE = 0x0001; /// Result is volatile (e.g. NOW() function).
+const sal_uInt16 FUNCFLAG_IMPORTONLY = 0x0002; /// Only used in import filter.
+const sal_uInt16 FUNCFLAG_EXPORTONLY = 0x0004; /// Only used in export filter.
+const sal_uInt16 FUNCFLAG_MACROCALL = 0x0008; /// Function is stored as macro call in Excel (_xlfn. prefix). OOXML name MUST exist.
+const sal_uInt16 FUNCFLAG_MACROCALLODF = 0x0010; /// ODF-only function stored as macro call in Excel (_xlfnodf. prefix). ODF name MUST exist.
+const sal_uInt16 FUNCFLAG_EXTERNAL = 0x0020; /// Function is external in Calc.
+const sal_uInt16 FUNCFLAG_MACROFUNC = 0x0040; /// Function is a macro-sheet function.
+const sal_uInt16 FUNCFLAG_MACROCMD = 0x0080; /// Function is a macro-sheet command.
+const sal_uInt16 FUNCFLAG_ALWAYSVAR = 0x0100; /// Function is always represented by a tFuncVar token.
+const sal_uInt16 FUNCFLAG_PARAMPAIRS = 0x0200; /// Optional parameters are expected to appear in pairs.
+
+const sal_uInt16 FUNCFLAG_FUNCLIBMASK = 0xF000; /// Mask for function library bits.
+const sal_uInt16 FUNCFLAG_EUROTOOL = 0x1000; /// Function is part of the EuroTool add-in.
+
+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.
+ FunctionParamInfo mpParamInfos[ FUNCINFO_PARAMINFOCOUNT ]; /// Information about all parameters.
+ sal_uInt16 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_uInt16 NOID = SAL_MAX_UINT16; /// No BIFF/OOBIN function identifier available.
+const sal_uInt8 MX = SAL_MAX_UINT8; /// Maximum parameter count.
+
+// abbreviations for function return token class
+const sal_uInt8 R = BIFF_TOKCLASS_REF;
+const sal_uInt8 V = BIFF_TOKCLASS_VAL;
+const sal_uInt8 A = BIFF_TOKCLASS_ARR;
+
+// abbreviations for parameter infos
+#define RO { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_ORG, false }
+#define RV { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_VAL, false }
+#define RA { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_ARR, false }
+#define RR { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_RPT, false }
+#define RX { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_RPX, false }
+#define VO { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_ORG, true }
+#define VV { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_VAL, true }
+#define VA { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_ARR, true }
+#define VR { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_RPT, true }
+#define VX { FUNC_PARAM_REGULAR, FUNC_PARAMCONV_RPX, true }
+#define RO_E { FUNC_PARAM_EXCELONLY, FUNC_PARAMCONV_ORG, false }
+#define VR_E { FUNC_PARAM_EXCELONLY, FUNC_PARAMCONV_RPT, true }
+#define C { FUNC_PARAM_CALCONLY, FUNC_PARAMCONV_ORG, false }
+
+// Note: parameter types of all macro sheet functions (FUNCFLAG_MACROFUNC/FUNCFLAG_MACROCMD) untested!
+
+/** Functions new in BIFF2. */
+static const FunctionData saFuncTableBiff2[] =
+{
+ { "COUNT", "COUNT", 0, 0, 0, MX, V, { RX }, 0 },
+ { "IF", "IF", 1, 1, 2, 3, R, { VO, RO }, 0 },
+ { "ISNA", "ISNA", 2, 2, 1, 1, V, { VR }, 0 },
+ { "ISERROR", "ISERROR", 3, 3, 1, 1, V, { VR }, 0 },
+ { "SUM", "SUM", 4, 4, 0, MX, V, { RX }, 0 },
+ { "AVERAGE", "AVERAGE", 5, 5, 1, MX, V, { RX }, 0 },
+ { "MIN", "MIN", 6, 6, 1, MX, V, { RX }, 0 },
+ { "MAX", "MAX", 7, 7, 1, MX, V, { RX }, 0 },
+ { "ROW", "ROW", 8, 8, 0, 1, V, { RO }, 0 },
+ { "COLUMN", "COLUMN", 9, 9, 0, 1, V, { RO }, 0 },
+ { "NA", "NA", 10, 10, 0, 0, V, {}, 0 },
+ { "NPV", "NPV", 11, 11, 2, MX, V, { VR, RX }, 0 },
+ { "STDEV", "STDEV", 12, 12, 1, MX, V, { RX }, 0 },
+ { "DOLLAR", "DOLLAR", 13, 13, 1, 2, V, { VR }, 0 },
+ { "FIXED", "FIXED", 14, 14, 1, 2, V, { VR, VR, C }, 0 },
+ { "SIN", "SIN", 15, 15, 1, 1, V, { VR }, 0 },
+ { "COS", "COS", 16, 16, 1, 1, V, { VR }, 0 },
+ { "TAN", "TAN", 17, 17, 1, 1, V, { VR }, 0 },
+ { "COT", "TAN", 17, 17, 1, 1, V, { VR }, FUNCFLAG_EXPORTONLY },
+ { "ATAN", "ATAN", 18, 18, 1, 1, V, { VR }, 0 },
+ { "ACOT", "ATAN", 18, 18, 1, 1, V, { VR }, FUNCFLAG_EXPORTONLY },
+ { "PI", "PI", 19, 19, 0, 0, V, {}, 0 },
+ { "SQRT", "SQRT", 20, 20, 1, 1, V, { VR }, 0 },
+ { "EXP", "EXP", 21, 21, 1, 1, V, { VR }, 0 },
+ { "LN", "LN", 22, 22, 1, 1, V, { VR }, 0 },
+ { "LOG10", "LOG10", 23, 23, 1, 1, V, { VR }, 0 },
+ { "ABS", "ABS", 24, 24, 1, 1, V, { VR }, 0 },
+ { "INT", "INT", 25, 25, 1, 1, V, { VR }, 0 },
+ { "SIGN", "SIGN", 26, 26, 1, 1, V, { VR }, 0 },
+ { "ROUND", "ROUND", 27, 27, 2, 2, V, { VR }, 0 },
+ { "LOOKUP", "LOOKUP", 28, 28, 2, 3, V, { VR, RA }, 0 },
+ { "INDEX", "INDEX", 29, 29, 2, 4, R, { RA, VV }, 0 },
+ { "REPT", "REPT", 30, 30, 2, 2, V, { VR }, 0 },
+ { "MID", "MID", 31, 31, 3, 3, V, { VR }, 0 },
+ { "LEN", "LEN", 32, 32, 1, 1, V, { VR }, 0 },
+ { "VALUE", "VALUE", 33, 33, 1, 1, V, { VR }, 0 },
+ { "TRUE", "TRUE", 34, 34, 0, 0, V, {}, 0 },
+ { "FALSE", "FALSE", 35, 35, 0, 0, V, {}, 0 },
+ { "AND", "AND", 36, 36, 1, MX, V, { RX }, 0 },
+ { "OR", "OR", 37, 37, 1, MX, V, { RX }, 0 },
+ { "NOT", "NOT", 38, 38, 1, 1, V, { VR }, 0 },
+ { "MOD", "MOD", 39, 39, 2, 2, V, { VR }, 0 },
+ { "DCOUNT", "DCOUNT", 40, 40, 3, 3, V, { RO, RR }, 0 },
+ { "DSUM", "DSUM", 41, 41, 3, 3, V, { RO, RR }, 0 },
+ { "DAVERAGE", "DAVERAGE", 42, 42, 3, 3, V, { RO, RR }, 0 },
+ { "DMIN", "DMIN", 43, 43, 3, 3, V, { RO, RR }, 0 },
+ { "DMAX", "DMAX", 44, 44, 3, 3, V, { RO, RR }, 0 },
+ { "DSTDEV", "DSTDEV", 45, 45, 3, 3, V, { RO, RR }, 0 },
+ { "VAR", "VAR", 46, 46, 1, MX, V, { RX }, 0 },
+ { "DVAR", "DVAR", 47, 47, 3, 3, V, { RO, RR }, 0 },
+ { "TEXT", "TEXT", 48, 48, 2, 2, V, { VR }, 0 },
+ { "LINEST", "LINEST", 49, 49, 1, 2, A, { RA, RA, C, C }, 0 },
+ { "TREND", "TREND", 50, 50, 1, 3, A, { RA, RA, RA, C }, 0 },
+ { "LOGEST", "LOGEST", 51, 51, 1, 2, A, { RA, RA, C, C }, 0 },
+ { "GROWTH", "GROWTH", 52, 52, 1, 3, A, { RA, RA, RA, C }, 0 },
+ { "PV", "PV", 56, 56, 3, 5, V, { VR }, 0 },
+ { "FV", "FV", 57, 57, 3, 5, V, { VR }, 0 },
+ { "NPER", "NPER", 58, 58, 3, 5, V, { VR }, 0 },
+ { "PMT", "PMT", 59, 59, 3, 5, V, { VR }, 0 },
+ { "RATE", "RATE", 60, 60, 3, 6, V, { VR }, 0 },
+ { "MIRR", "MIRR", 61, 61, 3, 3, V, { RA, VR }, 0 },
+ { "IRR", "IRR", 62, 62, 1, 2, V, { RA, VR }, 0 },
+ { "RAND", "RAND", 63, 63, 0, 0, V, {}, FUNCFLAG_VOLATILE },
+ { "MATCH", "MATCH", 64, 64, 2, 3, V, { VR, RX, RR }, 0 },
+ { "DATE", "DATE", 65, 65, 3, 3, V, { VR }, 0 },
+ { "TIME", "TIME", 66, 66, 3, 3, V, { VR }, 0 },
+ { "DAY", "DAY", 67, 67, 1, 1, V, { VR }, 0 },
+ { "MONTH", "MONTH", 68, 68, 1, 1, V, { VR }, 0 },
+ { "YEAR", "YEAR", 69, 69, 1, 1, V, { VR }, 0 },
+ { "WEEKDAY", "WEEKDAY", 70, 70, 1, 1, V, { VR, C }, 0 },
+ { "HOUR", "HOUR", 71, 71, 1, 1, V, { VR }, 0 },
+ { "MINUTE", "MINUTE", 72, 72, 1, 1, V, { VR }, 0 },
+ { "SECOND", "SECOND", 73, 73, 1, 1, V, { VR }, 0 },
+ { "NOW", "NOW", 74, 74, 0, 0, V, {}, FUNCFLAG_VOLATILE },
+ { "AREAS", "AREAS", 75, 75, 1, 1, V, { RO }, 0 },
+ { "ROWS", "ROWS", 76, 76, 1, 1, V, { RO }, 0 },
+ { "COLUMNS", "COLUMNS", 77, 77, 1, 1, V, { RO }, 0 },
+ { "OFFSET", "OFFSET", 78, 78, 3, 5, R, { RO, VR }, FUNCFLAG_VOLATILE },
+ { "SEARCH", "SEARCH", 82, 82, 2, 3, V, { VR }, 0 },
+ { "TRANSPOSE", "TRANSPOSE", 83, 83, 1, 1, A, { VO }, 0 },
+ { "TYPE", "TYPE", 86, 86, 1, 1, V, { VX }, 0 },
+ { "ATAN2", "ATAN2", 97, 97, 2, 2, V, { VR }, 0 },
+ { "ASIN", "ASIN", 98, 98, 1, 1, V, { VR }, 0 },
+ { "ACOS", "ACOS", 99, 99, 1, 1, V, { VR }, 0 },
+ { "CHOOSE", "CHOOSE", 100, 100, 2, MX, R, { VO, RO }, 0 },
+ { "HLOOKUP", "HLOOKUP", 101, 101, 3, 3, V, { VV, RO, RO, C }, 0 },
+ { "VLOOKUP", "VLOOKUP", 102, 102, 3, 3, V, { VV, RO, RO, C }, 0 },
+ { "ISREF", "ISREF", 105, 105, 1, 1, V, { RX }, 0 },
+ { "LOG", "LOG", 109, 109, 1, 2, V, { VR }, 0 },
+ { "CHAR", "CHAR", 111, 111, 1, 1, V, { VR }, 0 },
+ { "LOWER", "LOWER", 112, 112, 1, 1, V, { VR }, 0 },
+ { "UPPER", "UPPER", 113, 113, 1, 1, V, { VR }, 0 },
+ { "PROPER", "PROPER", 114, 114, 1, 1, V, { VR }, 0 },
+ { "LEFT", "LEFT", 115, 115, 1, 2, V, { VR }, 0 },
+ { "RIGHT", "RIGHT", 116, 116, 1, 2, V, { VR }, 0 },
+ { "EXACT", "EXACT", 117, 117, 2, 2, V, { VR }, 0 },
+ { "TRIM", "TRIM", 118, 118, 1, 1, V, { VR }, 0 },
+ { "REPLACE", "REPLACE", 119, 119, 4, 4, V, { VR }, 0 },
+ { "SUBSTITUTE", "SUBSTITUTE", 120, 120, 3, 4, V, { VR }, 0 },
+ { "CODE", "CODE", 121, 121, 1, 1, V, { VR }, 0 },
+ { "FIND", "FIND", 124, 124, 2, 3, V, { VR }, 0 },
+ { "CELL", "CELL", 125, 125, 1, 2, V, { VV, RO }, FUNCFLAG_VOLATILE },
+ { "ISERR", "ISERR", 126, 126, 1, 1, V, { VR }, 0 },
+ { "ISTEXT", "ISTEXT", 127, 127, 1, 1, V, { VR }, 0 },
+ { "ISNUMBER", "ISNUMBER", 128, 128, 1, 1, V, { VR }, 0 },
+ { "ISBLANK", "ISBLANK", 129, 129, 1, 1, V, { VR }, 0 },
+ { "T", "T", 130, 130, 1, 1, V, { RO }, 0 },
+ { "N", "N", 131, 131, 1, 1, V, { RO }, 0 },
+ { "DATEVALUE", "DATEVALUE", 140, 140, 1, 1, V, { VR }, 0 },
+ { "TIMEVALUE", "TIMEVALUE", 141, 141, 1, 1, V, { VR }, 0 },
+ { "SLN", "SLN", 142, 142, 3, 3, V, { VR }, 0 },
+ { "SYD", "SYD", 143, 143, 4, 4, V, { VR }, 0 },
+ { "DDB", "DDB", 144, 144, 4, 5, V, { VR }, 0 },
+ { "INDIRECT", "INDIRECT", 148, 148, 1, 2, R, { VR }, FUNCFLAG_VOLATILE },
+ { "CLEAN", "CLEAN", 162, 162, 1, 1, V, { VR }, 0 },
+ { "MDETERM", "MDETERM", 163, 163, 1, 1, V, { VA }, 0 },
+ { "MINVERSE", "MINVERSE", 164, 164, 1, 1, A, { VA }, 0 },
+ { "MMULT", "MMULT", 165, 165, 2, 2, A, { VA }, 0 },
+ { "IPMT", "IPMT", 167, 167, 4, 6, V, { VR }, 0 },
+ { "PPMT", "PPMT", 168, 168, 4, 6, V, { VR }, 0 },
+ { "COUNTA", "COUNTA", 169, 169, 0, MX, V, { RX }, 0 },
+ { "PRODUCT", "PRODUCT", 183, 183, 0, MX, V, { RX }, 0 },
+ { "FACT", "FACT", 184, 184, 1, 1, V, { VR }, 0 },
+ { "DPRODUCT", "DPRODUCT", 189, 189, 3, 3, V, { RO, RR }, 0 },
+ { "ISNONTEXT", "ISNONTEXT", 190, 190, 1, 1, V, { VR }, 0 },
+ { "STDEVP", "STDEVP", 193, 193, 1, MX, V, { RX }, 0 },
+ { "VARP", "VARP", 194, 194, 1, MX, V, { RX }, 0 },
+ { "DSTDEVP", "DSTDEVP", 195, 195, 3, 3, V, { RO, RR }, 0 },
+ { "DVARP", "DVARP", 196, 196, 3, 3, V, { RO, RR }, 0 },
+ { "TRUNC", "TRUNC", 197, 197, 1, 1, V, { VR, C }, 0 },
+ { "ISLOGICAL", "ISLOGICAL", 198, 198, 1, 1, V, { VR }, 0 },
+ { "DCOUNTA", "DCOUNTA", 199, 199, 3, 3, V, { RO, RR }, 0 },
+ { 0, "EXTERN.CALL", 255, 255, 1, MX, R, { RO_E, RO }, FUNCFLAG_IMPORTONLY },
+
+ // *** macro sheet commands ***
+
+ { 0, "A1.R1C1", 30, 30, 0, 1, V, { VR }, FUNCFLAG_MACROCMD },
+ { 0, "RETURN", 55, 55, 0, 1, R, { RO }, FUNCFLAG_MACROFUNC },
+ { 0, "ABSREF", 79, 79, 2, 2, R, { VR, RO }, FUNCFLAG_MACROFUNC },
+ { 0, "ADD.ARROW", 81, 81, 0, 0, V, {}, FUNCFLAG_MACROCMD },
+ { 0, "ACTIVE.CELL", 94, 94, 0, 0, R, {}, FUNCFLAG_MACROFUNC },
+ { 0, "ACTIVATE", 103, 103, 0, 2, V, { VR }, FUNCFLAG_MACROCMD },
+ { 0, "ACTIVATE.NEXT", 104, 104, 0, 0, V, {}, FUNCFLAG_MACROCMD },
+ { 0, "ACTIVATE.PREV", 105, 105, 0, 0, V, {}, FUNCFLAG_MACROCMD },
+ { 0, "ADD.BAR", 151, 151, 0, 0, V, {}, FUNCFLAG_MACROFUNC | FUNCFLAG_ALWAYSVAR },
+ { 0, "ADD.MENU", 152, 152, 2, 2, V, { VR, RO }, FUNCFLAG_MACROFUNC | FUNCFLAG_ALWAYSVAR },
+ { 0, "ADD.COMMAND", 153, 153, 3, 3, V, { VR, RO }, FUNCFLAG_MACROFUNC | FUNCFLAG_ALWAYSVAR }
+};
+
+/** Functions new in BIFF3. */
+static const FunctionData saFuncTableBiff3[] =
+{
+ { "LINEST", "LINEST", 49, 49, 1, 4, A, { RA, RA, VV }, 0 }, // BIFF2: 1-2, BIFF3: 1-4
+ { "TREND", "TREND", 50, 50, 1, 4, A, { RA, RA, RA, VV }, 0 }, // BIFF2: 1-3, BIFF3: 1-4
+ { "LOGEST", "LOGEST", 51, 51, 1, 4, A, { RA, RA, VV }, 0 }, // BIFF2: 1-2, BIFF3: 1-4
+ { "GROWTH", "GROWTH", 52, 52, 1, 4, A, { RA, RA, RA, VV }, 0 }, // BIFF2: 1-3, BIFF3: 1-4
+ { "TRUNC", "TRUNC", 197, 197, 1, 2, V, { VR }, 0 }, // BIFF2: 1, BIFF3: 1-2
+ { "DOLLAR", "USDOLLAR", 204, 204, 1, 2, V, { VR }, FUNCFLAG_IMPORTONLY },
+ { 0/*"FIND"*/, "FINDB", 205, 205, 2, 3, V, { VR }, 0 },
+ { 0/*"SEARCH"*/, "SEARCHB", 206, 206, 2, 3, V, { VR }, 0 },
+ { 0/*"REPLACE"*/, "REPLACEB", 207, 207, 4, 4, V, { VR }, 0 },
+ { 0/*"LEFT"*/, "LEFTB", 208, 208, 1, 2, V, { VR }, 0 },
+ { 0/*"RIGHT"*/, "RIGHTB", 209, 209, 1, 2, V, { VR }, 0 },
+ { 0/*"MID"*/, "MIDB", 210, 210, 3, 3, V, { VR }, 0 },
+ { 0/*"LEN"*/, "LENB", 211, 211, 1, 1, V, { VR }, 0 },
+ { "ROUNDUP", "ROUNDUP", 212, 212, 2, 2, V, { VR }, 0 },
+ { "ROUNDDOWN", "ROUNDDOWN", 213, 213, 2, 2, V, { VR }, 0 },
+ { "ASC", "ASC", 214, 214, 1, 1, V, { VR }, 0 },
+ { "JIS", "DBCS", 215, 215, 1, 1, V, { VR }, 0 },
+ { "ADDRESS", "ADDRESS", 219, 219, 2, 5, V, { VR }, 0 },
+ { "DAYS360", "DAYS360", 220, 220, 2, 2, V, { VR, VR, C }, 0 },
+ { "TODAY", "TODAY", 221, 221, 0, 0, V, {}, FUNCFLAG_VOLATILE },
+ { "VDB", "VDB", 222, 222, 5, 7, V, { VR }, 0 },
+ { "MEDIAN", "MEDIAN", 227, 227, 1, MX, V, { RX }, 0 },
+ { "SUMPRODUCT", "SUMPRODUCT", 228, 228, 1, MX, V, { VA }, 0 },
+ { "SINH", "SINH", 229, 229, 1, 1, V, { VR }, 0 },
+ { "COSH", "COSH", 230, 230, 1, 1, V, { VR }, 0 },
+ { "TANH", "TANH", 231, 231, 1, 1, V, { VR }, 0 },
+ { "COTH", "TANH", 231, 231, 1, 1, V, { VR }, FUNCFLAG_EXPORTONLY },
+ { "ASINH", "ASINH", 232, 232, 1, 1, V, { VR }, 0 },
+ { "ACOSH", "ACOSH", 233, 233, 1, 1, V, { VR }, 0 },
+ { "ATANH", "ATANH", 234, 234, 1, 1, V, { VR }, 0 },
+ { "ACOTH", "ATANH", 234, 234, 1, 1, V, { VR }, FUNCFLAG_EXPORTONLY },
+ { "DGET", "DGET", 235, 235, 3, 3, V, { RO, RR }, 0 },
+ { "INFO", "INFO", 244, 244, 1, 1, V, { VR }, FUNCFLAG_VOLATILE },
+
+ // *** macro sheet commands ***
+
+ { 0, "ADD.BAR", 151, 151, 0, 1, V, { VR }, FUNCFLAG_MACROFUNC }, // BIFF2: 0, BIFF3: 0-1
+ { 0, "ADD.MENU", 152, 152, 2, 3, V, { VR, RO }, FUNCFLAG_MACROFUNC }, // BIFF2: 2, BIFF3: 2-3
+ { 0, "ADD.COMMAND", 153, 153, 3, 4, V, { VR, RO }, FUNCFLAG_MACROFUNC } // BIFF2: 3, BIFF3: 3-4
+};
+
+/** Functions new in BIFF4. */
+static const FunctionData saFuncTableBiff4[] =
+{
+ { "FIXED", "FIXED", 14, 14, 1, 3, V, { VR }, 0 }, // BIFF2-3: 1-2, BIFF4: 1-3
+ { "RANK", "RANK", 216, 216, 2, 3, V, { VR, RO, VR }, 0 },
+ { "DB", "DB", 247, 247, 4, 5, V, { VR }, 0 },
+ { "FREQUENCY", "FREQUENCY", 252, 252, 2, 2, A, { RA }, 0 },
+ { "ORG.OPENOFFICE.ERRORTYPE","ERROR.TYPE", 261, 261, 1, 1, V, { VR }, 0 },
+ { "AVEDEV", "AVEDEV", 269, 269, 1, MX, V, { RX }, 0 },
+ { "BETADIST", "BETADIST", 270, 270, 3, 5, V, { VR }, 0 },
+ { "GAMMALN", "GAMMALN", 271, 271, 1, 1, V, { VR }, 0 },
+ { "BETAINV", "BETAINV", 272, 272, 3, 5, V, { VR }, 0 },
+ { "BINOMDIST", "BINOMDIST", 273, 273, 4, 4, V, { VR }, 0 },
+ { "LEGACY.CHIDIST", "CHIDIST", 274, 274, 2, 2, V, { VR }, 0 },
+ { "LEGACY.CHIINV", "CHIINV", 275, 275, 2, 2, V, { VR }, 0 },
+ { "COMBIN", "COMBIN", 276, 276, 2, 2, V, { VR }, 0 },
+ { "CONFIDENCE", "CONFIDENCE", 277, 277, 3, 3, V, { VR }, 0 },
+ { "CRITBINOM", "CRITBINOM", 278, 278, 3, 3, V, { VR }, 0 },
+ { "EVEN", "EVEN", 279, 279, 1, 1, V, { VR }, 0 },
+ { "EXPONDIST", "EXPONDIST", 280, 280, 3, 3, V, { VR }, 0 },
+ { "LEGACY.FDIST", "FDIST", 281, 281, 3, 3, V, { VR }, 0 },
+ { "LEGACY.FINV", "FINV", 282, 282, 3, 3, V, { VR }, 0 },
+ { "FISHER", "FISHER", 283, 283, 1, 1, V, { VR }, 0 },
+ { "FISHERINV", "FISHERINV", 284, 284, 1, 1, V, { VR }, 0 },
+ { "FLOOR", "FLOOR", 285, 285, 2, 2, V, { VR, VR, C }, 0 },
+ { "GAMMADIST", "GAMMADIST", 286, 286, 4, 4, V, { VR }, 0 },
+ { "GAMMAINV", "GAMMAINV", 287, 287, 3, 3, V, { VR }, 0 },
+ { "CEILING", "CEILING", 288, 288, 2, 2, V, { VR, VR, C }, 0 },
+ { "HYPGEOMDIST", "HYPGEOMDIST", 289, 289, 4, 4, V, { VR }, 0 },
+ { "LOGNORMDIST", "LOGNORMDIST", 290, 290, 3, 3, V, { VR }, 0 },
+ { "LOGINV", "LOGINV", 291, 291, 3, 3, V, { VR }, 0 },
+ { "NEGBINOMDIST", "NEGBINOMDIST", 292, 292, 3, 3, V, { VR }, 0 },
+ { "NORMDIST", "NORMDIST", 293, 293, 4, 4, V, { VR }, 0 },
+ { "LEGACY.NORMSDIST", "NORMSDIST", 294, 294, 1, 1, V, { VR }, 0 },
+ { "NORMINV", "NORMINV", 295, 295, 3, 3, V, { VR }, 0 },
+ { "LEGACY.NORMSINV", "NORMSINV", 296, 296, 1, 1, V, { VR }, 0 },
+ { "STANDARDIZE", "STANDARDIZE", 297, 297, 3, 3, V, { VR }, 0 },
+ { "ODD", "ODD", 298, 298, 1, 1, V, { VR }, 0 },
+ { "PERMUT", "PERMUT", 299, 299, 2, 2, V, { VR }, 0 },
+ { "POISSON", "POISSON", 300, 300, 3, 3, V, { VR }, 0 },
+ { "TDIST", "TDIST", 301, 301, 3, 3, V, { VR }, 0 },
+ { "WEIBULL", "WEIBULL", 302, 302, 4, 4, V, { VR }, 0 },
+ { "SUMXMY2", "SUMXMY2", 303, 303, 2, 2, V, { VA }, 0 },
+ { "SUMX2MY2", "SUMX2MY2", 304, 304, 2, 2, V, { VA }, 0 },
+ { "SUMX2PY2", "SUMX2PY2", 305, 305, 2, 2, V, { VA }, 0 },
+ { "LEGACY.CHITEST", "CHITEST", 306, 306, 2, 2, V, { VA }, 0 },
+ { "CORREL", "CORREL", 307, 307, 2, 2, V, { VA }, 0 },
+ { "COVAR", "COVAR", 308, 308, 2, 2, V, { VA }, 0 },
+ { "FORECAST", "FORECAST", 309, 309, 3, 3, V, { VR, VA }, 0 },
+ { "FTEST", "FTEST", 310, 310, 2, 2, V, { VA }, 0 },
+ { "INTERCEPT", "INTERCEPT", 311, 311, 2, 2, V, { VA }, 0 },
+ { "PEARSON", "PEARSON", 312, 312, 2, 2, V, { VA }, 0 },
+ { "RSQ", "RSQ", 313, 313, 2, 2, V, { VA }, 0 },
+ { "STEYX", "STEYX", 314, 314, 2, 2, V, { VA }, 0 },
+ { "SLOPE", "SLOPE", 315, 315, 2, 2, V, { VA }, 0 },
+ { "TTEST", "TTEST", 316, 316, 4, 4, V, { VA, VA, VR }, 0 },
+ { "PROB", "PROB", 317, 317, 3, 4, V, { VA, VA, VR }, 0 },
+ { "DEVSQ", "DEVSQ", 318, 318, 1, MX, V, { RX }, 0 },
+ { "GEOMEAN", "GEOMEAN", 319, 319, 1, MX, V, { RX }, 0 },
+ { "HARMEAN", "HARMEAN", 320, 320, 1, MX, V, { RX }, 0 },
+ { "SUMSQ", "SUMSQ", 321, 321, 0, MX, V, { RX }, 0 },
+ { "KURT", "KURT", 322, 322, 1, MX, V, { RX }, 0 },
+ { "SKEW", "SKEW", 323, 323, 1, MX, V, { RX }, 0 },
+ { "ZTEST", "ZTEST", 324, 324, 2, 3, V, { RX, VR }, 0 },
+ { "LARGE", "LARGE", 325, 325, 2, 2, V, { RX, VR }, 0 },
+ { "SMALL", "SMALL", 326, 326, 2, 2, V, { RX, VR }, 0 },
+ { "QUARTILE", "QUARTILE", 327, 327, 2, 2, V, { RX, VR }, 0 },
+ { "PERCENTILE", "PERCENTILE", 328, 328, 2, 2, V, { RX, VR }, 0 },
+ { "PERCENTRANK", "PERCENTRANK", 329, 329, 2, 3, V, { RX, VR, VR_E }, 0 },
+ { "MODE", "MODE", 330, 330, 1, MX, V, { VA }, 0 },
+ { "TRIMMEAN", "TRIMMEAN", 331, 331, 2, 2, V, { RX, VR }, 0 },
+ { "TINV", "TINV", 332, 332, 2, 2, V, { VR }, 0 },
+
+ // *** Analysis add-in ***
+
+ { "HEX2BIN", "HEX2BIN", 384, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "HEX2DEC", "HEX2DEC", 385, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "HEX2OCT", "HEX2OCT", 386, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "DEC2BIN", "DEC2BIN", 387, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "DEC2HEX", "DEC2HEX", 388, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "DEC2OCT", "DEC2OCT", 389, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "OCT2BIN", "OCT2BIN", 390, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "OCT2HEX", "OCT2HEX", 391, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "OCT2DEC", "OCT2DEC", 392, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "BIN2DEC", "BIN2DEC", 393, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "BIN2OCT", "BIN2OCT", 394, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "BIN2HEX", "BIN2HEX", 395, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMSUB", "IMSUB", 396, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMDIV", "IMDIV", 397, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMPOWER", "IMPOWER", 398, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMABS", "IMABS", 399, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMSQRT", "IMSQRT", 400, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMLN", "IMLN", 401, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMLOG2", "IMLOG2", 402, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMLOG10", "IMLOG10", 403, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMSIN", "IMSIN", 404, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMCOS", "IMCOS", 405, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMEXP", "IMEXP", 406, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMARGUMENT", "IMARGUMENT", 407, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMCONJUGATE", "IMCONJUGATE", 408, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMAGINARY", "IMAGINARY", 409, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMREAL", "IMREAL", 410, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "COMPLEX", "COMPLEX", 411, NOID, 2, 3, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "IMSUM", "IMSUM", 412, NOID, 1, MX, V, { RX }, FUNCFLAG_EXTERNAL },
+ { "IMPRODUCT", "IMPRODUCT", 413, NOID, 1, MX, V, { RX }, FUNCFLAG_EXTERNAL },
+ { "SERIESSUM", "SERIESSUM", 414, NOID, 4, 4, V, { RR, RR, RR, RX }, FUNCFLAG_EXTERNAL },
+ { "FACTDOUBLE", "FACTDOUBLE", 415, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "SQRTPI", "SQRTPI", 416, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "QUOTIENT", "QUOTIENT", 417, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "DELTA", "DELTA", 418, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "GESTEP", "GESTEP", 419, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "ISEVEN", "ISEVEN", 420, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "ISODD", "ISODD", 421, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "MROUND", "MROUND", 422, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "ERF", "ERF", 423, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "ERFC", "ERFC", 424, NOID, 1, 1, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "BESSELJ", "BESSELJ", 425, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "BESSELK", "BESSELK", 426, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "BESSELY", "BESSELY", 427, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "BESSELI", "BESSELI", 428, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "XIRR", "XIRR", 429, NOID, 2, 3, V, { RX, RX, RR }, FUNCFLAG_EXTERNAL },
+ { "XNPV", "XNPV", 430, NOID, 3, 3, V, { RR, RX, RX }, FUNCFLAG_EXTERNAL },
+ { "PRICEMAT", "PRICEMAT", 431, NOID, 5, 6, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "YIELDMAT", "YIELDMAT", 432, NOID, 5, 6, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "INTRATE", "INTRATE", 433, NOID, 4, 5, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "RECEIVED", "RECEIVED", 434, NOID, 4, 5, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "DISC", "DISC", 435, NOID, 4, 5, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "PRICEDISC", "PRICEDISC", 436, NOID, 4, 5, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "YIELDDISC", "YIELDDISC", 437, NOID, 4, 5, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "TBILLEQ", "TBILLEQ", 438, NOID, 3, 3, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "TBILLPRICE", "TBILLPRICE", 439, NOID, 3, 3, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "TBILLYIELD", "TBILLYIELD", 440, NOID, 3, 3, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "PRICE", "PRICE", 441, NOID, 6, 7, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "YIELD", "YIELD", 442, NOID, 6, 7, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "DOLLARDE", "DOLLARDE", 443, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "DOLLARFR", "DOLLARFR", 444, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "NOMINAL", "NOMINAL", 445, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "EFFECT", "EFFECT", 446, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "CUMPRINC", "CUMPRINC", 447, NOID, 6, 6, V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "CUMIPMT", "CUMIPMT", 448, NOID, 6, 6, V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "EDATE", "EDATE", 449, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "EOMONTH", "EOMONTH", 450, NOID, 2, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "YEARFRAC", "YEARFRAC", 451, NOID, 2, 3, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "COUPDAYBS", "COUPDAYBS", 452, NOID, 3, 4, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "COUPDAYS", "COUPDAYS", 453, NOID, 3, 4, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "COUPDAYSNC", "COUPDAYSNC", 454, NOID, 3, 4, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "COUPNCD", "COUPNCD", 455, NOID, 3, 4, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "COUPNUM", "COUPNUM", 456, NOID, 3, 4, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "COUPPCD", "COUPPCD", 457, NOID, 3, 4, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "DURATION", "DURATION", 458, NOID, 5, 6, V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "MDURATION", "MDURATION", 459, NOID, 5, 6, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "ODDLPRICE", "ODDLPRICE", 460, NOID, 7, 8, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "ODDLYIELD", "ODDLYIELD", 461, NOID, 8, 9, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "ODDFPRICE", "ODDFPRICE", 462, NOID, 8, 9, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "ODDFYIELD", "ODDFYIELD", 463, NOID, 8, 9, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "RANDBETWEEN", "RANDBETWEEN", 464, NOID, 2, 2, V, { RR }, FUNCFLAG_VOLATILE | FUNCFLAG_EXTERNAL },
+ { "WEEKNUM", "WEEKNUM", 465, NOID, 1, 2, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "AMORDEGRC", "AMORDEGRC", 466, NOID, 6, 7, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "AMORLINC", "AMORLINC", 467, NOID, 6, 7, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "CONVERT", "CONVERT", 468, NOID, 3, 3, V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "ACCRINT", "ACCRINT", 469, NOID, 6, 7, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "ACCRINTM", "ACCRINTM", 470, NOID, 4, 5, V, { RR }, FUNCFLAG_EXTERNAL },
+ { "WORKDAY", "WORKDAY", 471, NOID, 2, 3, V, { RR, RR, RX, C }, FUNCFLAG_EXTERNAL },
+ { "NETWORKDAYS", "NETWORKDAYS", 472, NOID, 2, 3, V, { RR, RR, RX, C }, FUNCFLAG_EXTERNAL },
+ { "GCD", "GCD", 473, NOID, 1, MX, V, { RX }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "MULTINOMIAL", "MULTINOMIAL", 474, NOID, 1, MX, V, { RX }, FUNCFLAG_EXTERNAL },
+ { "LCM", "LCM", 475, NOID, 1, MX, V, { RX }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in
+ { "FVSCHEDULE", "FVSCHEDULE", 476, NOID, 2, 2, V, { RR, RX }, FUNCFLAG_EXTERNAL },
+
+ // *** macro sheet commands ***
+
+ { 0, "ACTIVATE.NEXT", 104, 104, 0, 1, V, { VR }, FUNCFLAG_MACROCMD }, // BIFF2-3: 0, BIFF4: 0-1
+ { 0, "ACTIVATE.PREV", 105, 105, 0, 1, V, { VR }, FUNCFLAG_MACROCMD } // BIFF2-3: 0, BIFF4: 0-1
+};
+
+/** Functions new in BIFF5/BIFF7. */
+static const FunctionData saFuncTableBiff5[] =
+{
+ { "WEEKDAY", "WEEKDAY", 70, 70, 1, 2, V, { VR }, 0 }, // BIFF2-4: 1, BIFF5: 1-2
+ { "HLOOKUP", "HLOOKUP", 101, 101, 3, 4, V, { VV, RO, RO, VV }, 0 }, // BIFF2-4: 3, BIFF5: 3-4
+ { "VLOOKUP", "VLOOKUP", 102, 102, 3, 4, V, { VV, RO, RO, VV }, 0 }, // BIFF2-4: 3, BIFF5: 3-4
+ { "DAYS360", "DAYS360", 220, 220, 2, 3, V, { VR }, 0 }, // BIFF3-4: 2, BIFF5: 2-3
+ { 0, "EXTERN.CALL", 255, 255, 1, MX, R, { RO_E, RO }, FUNCFLAG_EXPORTONLY }, // MACRO or EXTERNAL
+ { "CONCATENATE", "CONCATENATE", 336, 336, 0, MX, V, { VR }, 0 },
+ { "POWER", "POWER", 337, 337, 2, 2, V, { VR }, 0 },
+ { "RADIANS", "RADIANS", 342, 342, 1, 1, V, { VR }, 0 },
+ { "DEGREES", "DEGREES", 343, 343, 1, 1, V, { VR }, 0 },
+ { "SUBTOTAL", "SUBTOTAL", 344, 344, 2, MX, V, { VR, RO }, 0 },
+ { "SUMIF", "SUMIF", 345, 345, 2, 3, V, { RO, VR, RO }, 0 },
+ { "COUNTIF", "COUNTIF", 346, 346, 2, 2, V, { RO, VR }, 0 },
+ { "COUNTBLANK", "COUNTBLANK", 347, 347, 1, 1, V, { RO }, 0 },
+ { "ISPMT", "ISPMT", 350, 350, 4, 4, V, { VR }, 0 },
+ { 0, "DATEDIF", 351, 351, 3, 3, V, { VR }, FUNCFLAG_IMPORTONLY }, // not supported in Calc
+ { 0, "DATESTRING", 352, 352, 1, 1, V, { VR }, FUNCFLAG_IMPORTONLY }, // not supported in Calc, missing in OOX spec
+ { 0, "NUMBERSTRING", 353, 353, 2, 2, V, { VR }, FUNCFLAG_IMPORTONLY }, // not supported in Calc, missing in OOX spec
+ { "ROMAN", "ROMAN", 354, 354, 1, 2, V, { VR }, 0 },
+
+ // *** EuroTool add-in ***
+
+ { "EUROCONVERT", "EUROCONVERT", NOID, NOID, 3, 5, V, { VR }, FUNCFLAG_EUROTOOL },
+
+ // *** macro sheet commands ***
+
+ { 0, "ADD.MENU", 152, 152, 2, 4, V, { VR, RO, RO, VR }, FUNCFLAG_MACROFUNC }, // BIFF3-4: 2-3, BIFF5: 2-4
+ { 0, "ADD.COMMAND", 153, 153, 3, 5, V, { VR, RO, RO, RO, VR }, FUNCFLAG_MACROFUNC }, // BIFF3-4: 3-4, BIFF5: 3-5
+ { 0, "ADD.CHART.AUTOFORMAT", 390, 390, 0, 2, V, { VR }, FUNCFLAG_MACROCMD },
+ { 0, "ADD.LIST.ITEM", 451, 451, 0, 2, V, { VR }, FUNCFLAG_MACROCMD },
+ { 0, "ACTIVE.CELL.FONT", 476, 476, 0, 14, V, { VR }, FUNCFLAG_MACROCMD }
+};
+
+/** Functions new in BIFF8. */
+static const FunctionData saFuncTableBiff8[] =
+{
+ { "GETPIVOTDATA", "GETPIVOTDATA", 358, 358, 2, MX, V, { RR, RR, VR, VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_PARAMPAIRS },
+ { "HYPERLINK", "HYPERLINK", 359, 359, 1, 2, V, { VV, VO }, 0 },
+ { 0, "PHONETIC", 360, 360, 1, 1, V, { RO }, FUNCFLAG_IMPORTONLY },
+ { "AVERAGEA", "AVERAGEA", 361, 361, 1, MX, V, { RX }, 0 },
+ { "MAXA", "MAXA", 362, 362, 1, MX, V, { RX }, 0 },
+ { "MINA", "MINA", 363, 363, 1, MX, V, { RX }, 0 },
+ { "STDEVPA", "STDEVPA", 364, 364, 1, MX, V, { RX }, 0 },
+ { "VARPA", "VARPA", 365, 365, 1, MX, V, { RX }, 0 },
+ { "STDEVA", "STDEVA", 366, 366, 1, MX, V, { RX }, 0 },
+ { "VARA", "VARA", 367, 367, 1, MX, V, { RX }, 0 },
+ { "COM.MICROSOFT.BAHTTEXT", "BAHTTEXT", 368, 368, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "THAIDAYOFWEEK", 369, 369, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "THAIDIGIT", 370, 370, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "THAIMONTHOFYEAR", 371, 371, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "THAINUMSOUND", 372, 372, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "THAINUMSTRING", 373, 373, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "THAISTRINGLENGTH", 374, 374, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "ISTHAIDIGIT", 375, 375, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "ROUNDBAHTDOWN", 376, 376, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "ROUNDBAHTUP", 377, 377, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "THAIYEAR", 378, 378, 1, 1, V, { VR }, FUNCFLAG_MACROCALL },
+ { 0, "RTD", 379, 379, 3, 3, A, { VR, VR, RO }, 0 }
+};
+
+/** Functions new in OOX. */
+static const FunctionData saFuncTableOox[] =
+{
+ { 0, "CUBEVALUE", 380, NOID, 1, MX, V, { VR, RX }, 0 },
+ { 0, "CUBEMEMBER", 381, NOID, 2, 3, V, { VR, RX, VR }, 0 },
+ { 0, "CUBEMEMBERPROPERTY", 382, NOID, 3, 3, V, { VR }, 0 },
+ { 0, "CUBERANKEDMEMBER", 383, NOID, 3, 4, V, { VR }, 0 },
+ { 0, "CUBEKPIMEMBER", 477, NOID, 3, 4, V, { VR }, 0 },
+ { 0, "CUBESET", 478, NOID, 2, 5, V, { VR, RX, VR }, 0 },
+ { 0, "CUBESETCOUNT", 479, NOID, 1, 1, V, { VR }, 0 },
+ { 0, "IFERROR", 480, NOID, 2, 2, V, { VO, RO }, 0 },
+ { 0, "COUNTIFS", 481, NOID, 2, MX, V, { RO, VR }, FUNCFLAG_PARAMPAIRS },
+ { 0, "SUMIFS", 482, NOID, 3, MX, V, { RO, RO, VR }, FUNCFLAG_PARAMPAIRS },
+ { 0, "AVERAGEIF", 483, NOID, 2, 3, V, { RO, VR, RO }, 0 },
+ { 0, "AVERAGEIFS", 484, NOID, 3, MX, V, { RO, RO, VR }, 0 }
+};
+
+/** Functions defined by OpenFormula, but not supported by Calc or by Excel. */
+static const FunctionData saFuncTableOdf[] =
+{
+ { "ARABIC", 0, NOID, NOID, 1, 1, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "B", 0, NOID, NOID, 3, 4, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "BASE", 0, NOID, NOID, 2, 3, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "BITAND", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "BITLSHIFT", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "BITOR", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "BITRSHIFT", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "BITXOR", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "CHISQDIST", 0, NOID, NOID, 2, 3, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "CHISQINV", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "COMBINA", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "DAYS", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "DECIMAL", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "FDIST", 0, NOID, NOID, 3, 4, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "FINV", 0, NOID, NOID, 3, 3, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "FORMULA", 0, NOID, NOID, 1, 1, V, { RO }, FUNCFLAG_MACROCALLODF },
+ { "GAMMA", 0, NOID, NOID, 1, 1, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "GAUSS", 0, NOID, NOID, 1, 1, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "IFNA", 0, NOID, NOID, 2, 2, V, { VR, RO }, FUNCFLAG_MACROCALLODF },
+ { "ISFORMULA", 0, NOID, NOID, 1, 1, V, { RO }, FUNCFLAG_MACROCALLODF },
+ { "ISOWEEKNUM", 0, NOID, NOID, 1, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "MUNIT", 0, NOID, NOID, 1, 1, A, { VR }, FUNCFLAG_MACROCALLODF },
+ { "NUMBERVALUE", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "PDURATION", 0, NOID, NOID, 3, 3, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "PERMUTATIONA", 0, NOID, NOID, 2, 2, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "PHI", 0, NOID, NOID, 1, 1, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "RRI", 0, NOID, NOID, 3, 3, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "SHEET", 0, NOID, NOID, 1, 1, V, { RO }, FUNCFLAG_MACROCALLODF },
+ { "SHEETS", 0, NOID, NOID, 0, 1, V, { RO }, FUNCFLAG_MACROCALLODF },
+ { "SKEWP", 0, NOID, NOID, 1, MX, V, { RX }, FUNCFLAG_MACROCALLODF },
+ { "UNICHAR", 0, NOID, NOID, 1, 1, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "UNICODE", 0, NOID, NOID, 1, 1, V, { VR }, FUNCFLAG_MACROCALLODF },
+ { "XOR", 0, NOID, NOID, 1, MX, V, { RX }, FUNCFLAG_MACROCALLODF }
+};
+
+// ----------------------------------------------------------------------------
+
+const sal_Unicode API_TOKEN_OPEN = '(';
+const sal_Unicode API_TOKEN_CLOSE = ')';
+const sal_Unicode API_TOKEN_SEP = ';';
+
+const sal_Unicode API_TOKEN_ARRAY_OPEN = '{';
+const sal_Unicode API_TOKEN_ARRAY_CLOSE = '}';
+const sal_Unicode API_TOKEN_ARRAY_ROWSEP = '|';
+const sal_Unicode API_TOKEN_ARRAY_COLSEP = ';';
+
+} // namespace
+
+// function info parameter class iterator =====================================
+
+FunctionParamInfoIterator::FunctionParamInfoIterator( const FunctionInfo& rFuncInfo ) :
+ mpParamInfo( rFuncInfo.mpParamInfos ),
+ mpParamInfoEnd( rFuncInfo.mpParamInfos + FUNCINFO_PARAMINFOCOUNT ),
+ mbParamPairs( rFuncInfo.mbParamPairs )
+{
+ OSL_ENSURE( !mbParamPairs || (mpParamInfo + 1 < mpParamInfoEnd),
+ "FunctionParamInfoIterator::FunctionParamInfoIterator - expecting at least 2 infos for paired parameters" );
+}
+
+const FunctionParamInfo& FunctionParamInfoIterator::getParamInfo() const
+{
+ static const FunctionParamInfo saInvalidInfo = { FUNC_PARAM_NONE, FUNC_PARAMCONV_ORG, false };
+ return mpParamInfo ? *mpParamInfo : saInvalidInfo;
+}
+
+bool FunctionParamInfoIterator::isCalcOnlyParam() const
+{
+ return mpParamInfo && (mpParamInfo->meValid == FUNC_PARAM_CALCONLY);
+}
+
+bool FunctionParamInfoIterator::isExcelOnlyParam() const
+{
+ return mpParamInfo && (mpParamInfo->meValid == FUNC_PARAM_EXCELONLY);
+}
+
+FunctionParamInfoIterator& FunctionParamInfoIterator::operator++()
+{
+ if( mpParamInfo )
+ {
+ // move pointer to next entry, if something explicit follows
+ if( (mpParamInfo + 1 < mpParamInfoEnd) && (mpParamInfo[ 1 ].meValid != FUNC_PARAM_NONE) )
+ ++mpParamInfo;
+ // points to last info, but parameter pairs expected, move to previous info
+ else if( mbParamPairs )
+ --mpParamInfo;
+ // if last parameter type is 'Excel-only' or 'Calc-only', do not repeat it
+ else if( isExcelOnlyParam() || isCalcOnlyParam() )
+ mpParamInfo = 0;
+ // otherwise: repeat last parameter class
+ }
+ return *this;
+}
+
+// function provider ==========================================================
+
+struct FunctionProviderImpl
+{
+ typedef RefMap< OUString, FunctionInfo > FuncNameMap;
+ typedef RefMap< sal_uInt16, FunctionInfo > FuncIdMap;
+
+ FunctionInfoVector maFuncs; /// All function infos in one list.
+ FuncNameMap maOdfFuncs; /// Maps ODF function names to function data.
+ FuncNameMap maOoxFuncs; /// Maps OOXML 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 macro function names to function data.
+
+ explicit FunctionProviderImpl( FilterType eFilter, BiffType eBiff, bool bImportFilter );
+
+private:
+ /** Creates and inserts a function info struct from the passed function data. */
+ void initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxParam );
+
+ /** Initializes the members from the passed function data list. */
+ void initFuncs(
+ const FunctionData* pBeg, const FunctionData* pEnd,
+ sal_uInt8 nMaxParam, bool bImportFilter );
+};
+
+// ----------------------------------------------------------------------------
+
+FunctionProviderImpl::FunctionProviderImpl( FilterType eFilter, BiffType eBiff, bool bImportFilter )
+{
+ OSL_ENSURE( bImportFilter, "FunctionProviderImpl::FunctionProviderImpl - need special handling for macro call functions" );
+ sal_uInt8 nMaxParam = 0;
+ switch( eFilter )
+ {
+ case FILTER_OOX:
+ nMaxParam = OOX_MAX_PARAMCOUNT;
+ eBiff = BIFF8; // insert all BIFF function tables, then the OOX table
+ break;
+ case FILTER_BIFF:
+ nMaxParam = BIFF_MAX_PARAMCOUNT;
+ break;
+ case FILTER_UNKNOWN:
+ OSL_ENSURE( false, "FunctionProviderImpl::FunctionProviderImpl - invalid filter type" );
+ break;
+ }
+ OSL_ENSURE( eBiff != BIFF_UNKNOWN, "FunctionProviderImpl::FunctionProviderImpl - invalid BIFF type" );
+
+ /* 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 )
+ initFuncs( saFuncTableBiff2, STATIC_ARRAY_END( saFuncTableBiff2 ), nMaxParam, bImportFilter );
+ if( eBiff >= BIFF3 )
+ initFuncs( saFuncTableBiff3, STATIC_ARRAY_END( saFuncTableBiff3 ), nMaxParam, bImportFilter );
+ if( eBiff >= BIFF4 )
+ initFuncs( saFuncTableBiff4, STATIC_ARRAY_END( saFuncTableBiff4 ), nMaxParam, bImportFilter );
+ if( eBiff >= BIFF5 )
+ initFuncs( saFuncTableBiff5, STATIC_ARRAY_END( saFuncTableBiff5 ), nMaxParam, bImportFilter );
+ if( eBiff >= BIFF8 )
+ initFuncs( saFuncTableBiff8, STATIC_ARRAY_END( saFuncTableBiff8 ), nMaxParam, bImportFilter );
+ if( eFilter == FILTER_OOX )
+ initFuncs( saFuncTableOox, STATIC_ARRAY_END( saFuncTableOox ), nMaxParam, bImportFilter );
+ initFuncs( saFuncTableOdf, STATIC_ARRAY_END( saFuncTableOdf ), nMaxParam, bImportFilter );
+}
+
+void FunctionProviderImpl::initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxParam )
+{
+ // create a function info object
+ FunctionInfoRef xFuncInfo( new FunctionInfo );
+ if( rFuncData.mpcOdfFuncName )
+ xFuncInfo->maOdfFuncName = OUString::createFromAscii( rFuncData.mpcOdfFuncName );
+ if( rFuncData.mpcOoxFuncName )
+ xFuncInfo->maOoxFuncName = OUString::createFromAscii( rFuncData.mpcOoxFuncName );
+
+ if( getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCALL ) )
+ {
+ OSL_ENSURE( xFuncInfo->maOoxFuncName.getLength() > 0, "FunctionProviderImpl::initFunc - missing OOXML function name" );
+ OSL_ENSURE( !getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCALLODF ), "FunctionProviderImpl::initFunc - unexpected flag FUNCFLAG_MACROCALLODF" );
+ xFuncInfo->maBiffMacroName = CREATE_OUSTRING( "_xlfn." ) + xFuncInfo->maOoxFuncName;
+ }
+ else if( getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCALLODF ) )
+ {
+ OSL_ENSURE( xFuncInfo->maOdfFuncName.getLength() > 0, "FunctionProviderImpl::initFunc - missing ODF function name" );
+ xFuncInfo->maBiffMacroName = CREATE_OUSTRING( "_xlfnodf." ) + xFuncInfo->maOdfFuncName;
+ }
+
+ switch( rFuncData.mnFlags & FUNCFLAG_FUNCLIBMASK )
+ {
+ case FUNCFLAG_EUROTOOL: xFuncInfo->meFuncLibType = FUNCLIB_EUROTOOL; break;
+ default: xFuncInfo->meFuncLibType = FUNCLIB_UNKNOWN;
+ }
+
+ xFuncInfo->mnApiOpCode = -1;
+ xFuncInfo->mnOobFuncId = rFuncData.mnOobFuncId;
+ xFuncInfo->mnBiffFuncId = rFuncData.mnBiffFuncId;
+ xFuncInfo->mnMinParamCount = rFuncData.mnMinParamCount;
+ xFuncInfo->mnMaxParamCount = (rFuncData.mnMaxParamCount == MX) ? nMaxParam : rFuncData.mnMaxParamCount;
+ xFuncInfo->mnRetClass = rFuncData.mnRetClass;
+ xFuncInfo->mpParamInfos = rFuncData.mpParamInfos;
+ xFuncInfo->mbParamPairs = getFlag( rFuncData.mnFlags, FUNCFLAG_PARAMPAIRS );
+ xFuncInfo->mbVolatile = getFlag( rFuncData.mnFlags, FUNCFLAG_VOLATILE );
+ xFuncInfo->mbExternal = getFlag( rFuncData.mnFlags, FUNCFLAG_EXTERNAL );
+ bool bMacroCmd = getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCMD );
+ xFuncInfo->mbMacroFunc = bMacroCmd || getFlag( rFuncData.mnFlags, FUNCFLAG_MACROFUNC );
+ xFuncInfo->mbVarParam = bMacroCmd || (rFuncData.mnMinParamCount != rFuncData.mnMaxParamCount) || getFlag( rFuncData.mnFlags, FUNCFLAG_ALWAYSVAR );
+
+ setFlag( xFuncInfo->mnOobFuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
+ setFlag( xFuncInfo->mnBiffFuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
+
+ // insert the function info into the member maps
+ maFuncs.push_back( xFuncInfo );
+ if( xFuncInfo->maOdfFuncName.getLength() > 0 )
+ maOdfFuncs[ xFuncInfo->maOdfFuncName ] = 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->maBiffMacroName.getLength() > 0 )
+ maMacroFuncs[ xFuncInfo->maBiffMacroName ] = xFuncInfo;
+}
+
+void FunctionProviderImpl::initFuncs( const FunctionData* pBeg, const FunctionData* pEnd, sal_uInt8 nMaxParam, bool bImportFilter )
+{
+ for( const FunctionData* pIt = pBeg; pIt != pEnd; ++pIt )
+ if( pIt->isSupported( bImportFilter ) )
+ initFunc( *pIt, nMaxParam );
+}
+
+// ----------------------------------------------------------------------------
+
+FunctionProvider::FunctionProvider( FilterType eFilter, BiffType eBiff, bool bImportFilter ) :
+ mxFuncImpl( new FunctionProviderImpl( eFilter, eBiff, bImportFilter ) )
+{
+}
+
+FunctionProvider::~FunctionProvider()
+{
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromOdfFuncName( const OUString& rFuncName ) const
+{
+ return mxFuncImpl->maOdfFuncs.get( rFuncName ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
+{
+ return mxFuncImpl->maOoxFuncs.get( rFuncName ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromOobFuncId( sal_uInt16 nFuncId ) const
+{
+ return mxFuncImpl->maOobFuncs.get( nFuncId ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const
+{
+ return mxFuncImpl->maBiffFuncs.get( nFuncId ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromMacroName( const OUString& rFuncName ) const
+{
+ return mxFuncImpl->maMacroFuncs.get( rFuncName ).get();
+}
+
+FunctionLibraryType FunctionProvider::getFuncLibTypeFromLibraryName( const OUString& rLibraryName ) const
+{
+#define OOX_XLS_IS_LIBNAME( libname, basename ) (libname.equalsIgnoreAsciiCaseAscii( basename ".XLA" ) || libname.equalsIgnoreAsciiCaseAscii( basename ".XLAM" ))
+
+ // the EUROTOOL add-in containing the EUROCONVERT function
+ if( OOX_XLS_IS_LIBNAME( rLibraryName, "EUROTOOL" ) )
+ return FUNCLIB_EUROTOOL;
+
+#undef OOX_XLS_IS_LIBNAME
+
+ // default: unknown library
+ return FUNCLIB_UNKNOWN;
+}
+
+const FunctionInfoVector& FunctionProvider::getFuncs() const
+{
+ return mxFuncImpl->maFuncs;
+}
+
+// op-code and function provider ==============================================
+
+struct OpCodeProviderImpl : public ApiOpCodes
+{
+ typedef RefMap< sal_Int32, FunctionInfo > OpCodeFuncMap;
+ typedef RefMap< OUString, FunctionInfo > FuncNameMap;
+ typedef ::std::vector< FormulaOpCodeMapEntry > OpCodeEntryVector;
+
+ OpCodeFuncMap maOpCodeFuncs; /// Maps API function op-codes to function data.
+ FuncNameMap maExtProgFuncs; /// Maps programmatical API function names to function data.
+ OpCodeEntryVector maParserMap; /// OOXML token mapping for formula parser service.
+
+ explicit OpCodeProviderImpl(
+ const FunctionInfoVector& rFuncInfos,
+ const Reference< XMultiServiceFactory >& rxFactory );
+
+private:
+ typedef ::std::map< OUString, ApiToken > ApiTokenMap;
+ typedef Sequence< FormulaOpCodeMapEntry > OpCodeEntrySequence;
+
+ static bool fillEntrySeq( OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
+ static bool fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
+ bool fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const;
+
+ static bool initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId );
+ bool initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName );
+ bool initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName );
+ bool initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName );
+
+ bool initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap );
+ bool initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos );
+};
+
+// ----------------------------------------------------------------------------
+
+OpCodeProviderImpl::OpCodeProviderImpl( const FunctionInfoVector& rFuncInfos,
+ const Reference< XMultiServiceFactory >& rxFactory )
+{
+ if( rxFactory.is() ) try
+ {
+ Reference< XFormulaOpCodeMapper > xMapper( rxFactory->createInstance(
+ CREATE_OUSTRING( "com.sun.star.sheet.FormulaOpCodeMapper" ) ), UNO_QUERY_THROW );
+
+ // op-codes provided as attributes
+ OPCODE_UNKNOWN = xMapper->getOpCodeUnknown();
+ OPCODE_EXTERNAL = xMapper->getOpCodeExternal();
+
+ using namespace ::com::sun::star::sheet::FormulaMapGroup;
+ using namespace ::com::sun::star::sheet::FormulaMapGroupSpecialOffset;
+
+ OpCodeEntrySequence aEntrySeq;
+ ApiTokenMap aTokenMap, aExtFuncTokenMap;
+ bool bIsValid =
+ // special
+ fillEntrySeq( aEntrySeq, xMapper, SPECIAL ) &&
+ initOpCode( OPCODE_PUSH, aEntrySeq, PUSH ) &&
+ initOpCode( OPCODE_MISSING, aEntrySeq, MISSING ) &&
+ initOpCode( OPCODE_SPACES, aEntrySeq, SPACES ) &&
+ initOpCode( OPCODE_NAME, aEntrySeq, NAME ) &&
+ initOpCode( OPCODE_DBAREA, aEntrySeq, DB_AREA ) &&
+ initOpCode( OPCODE_NLR, aEntrySeq, COL_ROW_NAME ) &&
+ initOpCode( OPCODE_MACRO, aEntrySeq, MACRO ) &&
+ initOpCode( OPCODE_BAD, aEntrySeq, BAD ) &&
+ initOpCode( OPCODE_NONAME, aEntrySeq, NO_NAME ) &&
+ // separators
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, SEPARATORS ) &&
+ initOpCode( OPCODE_OPEN, aTokenMap, API_TOKEN_OPEN, '(' ) &&
+ initOpCode( OPCODE_CLOSE, aTokenMap, API_TOKEN_CLOSE, ')' ) &&
+ initOpCode( OPCODE_SEP, aTokenMap, API_TOKEN_SEP, ',' ) &&
+ // array separators
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, ARRAY_SEPARATORS ) &&
+ initOpCode( OPCODE_ARRAY_OPEN, aTokenMap, API_TOKEN_ARRAY_OPEN, '{' ) &&
+ initOpCode( OPCODE_ARRAY_CLOSE, aTokenMap, API_TOKEN_ARRAY_CLOSE, '}' ) &&
+ initOpCode( OPCODE_ARRAY_ROWSEP, aTokenMap, API_TOKEN_ARRAY_ROWSEP, ';' ) &&
+ initOpCode( OPCODE_ARRAY_COLSEP, aTokenMap, API_TOKEN_ARRAY_COLSEP, ',' ) &&
+ // unary operators
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, UNARY_OPERATORS ) &&
+ initOpCode( OPCODE_PLUS_SIGN, aTokenMap, '+', '\0' ) && // same op-code as OPCODE_ADD
+ initOpCode( OPCODE_MINUS_SIGN, aTokenMap, '-', '-' ) &&
+ initOpCode( OPCODE_PERCENT, aTokenMap, '%', '%' ) &&
+ // binary operators
+ fillTokenMap( aTokenMap, aEntrySeq, xMapper, BINARY_OPERATORS ) &&
+ initOpCode( OPCODE_ADD, aTokenMap, '+', '+' ) &&
+ initOpCode( OPCODE_SUB, aTokenMap, '-', '-' ) &&
+ initOpCode( OPCODE_MULT, aTokenMap, '*', '*' ) &&
+ initOpCode( OPCODE_DIV, aTokenMap, '/', '/' ) &&
+ initOpCode( OPCODE_POWER, aTokenMap, '^', '^' ) &&
+ initOpCode( OPCODE_CONCAT, aTokenMap, '&', '&' ) &&
+ initOpCode( OPCODE_EQUAL, aTokenMap, '=', '=' ) &&
+ initOpCode( OPCODE_NOT_EQUAL, aTokenMap, "<>", "<>" ) &&
+ initOpCode( OPCODE_LESS, aTokenMap, '<', '<' ) &&
+ initOpCode( OPCODE_LESS_EQUAL, aTokenMap, "<=", "<=" ) &&
+ initOpCode( OPCODE_GREATER, aTokenMap, '>', '>' ) &&
+ initOpCode( OPCODE_GREATER_EQUAL, aTokenMap, ">=", ">=" ) &&
+ initOpCode( OPCODE_INTERSECT, aTokenMap, '!', ' ' ) &&
+ initOpCode( OPCODE_LIST, aTokenMap, '~', ',' ) &&
+ initOpCode( OPCODE_RANGE, aTokenMap, ':', ':' ) &&
+ // functions
+ fillFuncTokenMaps( aTokenMap, aExtFuncTokenMap, aEntrySeq, xMapper ) &&
+ initFuncOpCodes( aTokenMap, aExtFuncTokenMap, rFuncInfos ) &&
+ initOpCode( OPCODE_DDE, aTokenMap, "DDE", 0 );
+
+ OSL_ENSURE( bIsValid, "OpCodeProviderImpl::OpCodeProviderImpl - opcodes not initialized" );
+ (void)bIsValid;
+
+ // OPCODE_PLUS_SIGN and OPCODE_ADD should be equal, otherwise "+" has to be passed above
+ OSL_ENSURE( OPCODE_PLUS_SIGN == OPCODE_ADD, "OpCodeProviderImpl::OpCodeProviderImpl - need opcode mapping for OPCODE_PLUS_SIGN" );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "OpCodeProviderImpl::OpCodeProviderImpl - cannot receive formula opcode mapper" );
+ }
+}
+
+bool OpCodeProviderImpl::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 OpCodeProviderImpl::fillTokenMap( ApiTokenMap& 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 orEntrySeq.hasElements();
+}
+
+bool OpCodeProviderImpl::fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const
+{
+ orIntFuncTokenMap.clear();
+ orExtFuncTokenMap.clear();
+ if( fillEntrySeq( orEntrySeq, rxMapper, ::com::sun::star::sheet::FormulaMapGroup::FUNCTIONS ) )
+ {
+ const FormulaOpCodeMapEntry* pEntry = orEntrySeq.getConstArray();
+ const FormulaOpCodeMapEntry* pEntryEnd = pEntry + orEntrySeq.getLength();
+ for( ; pEntry != pEntryEnd; ++pEntry )
+ ((pEntry->Token.OpCode == OPCODE_EXTERNAL) ? orExtFuncTokenMap : orIntFuncTokenMap)[ pEntry->Name ] = pEntry->Token;
+ }
+ return orEntrySeq.hasElements();
+}
+
+bool OpCodeProviderImpl::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( "OpCodeProviderImpl::initOpCode - opcode for special offset " ).
+ append( nSpecialId ).append( " not found" ).getStr() );
+ return false;
+}
+
+bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName )
+{
+ ApiTokenMap::const_iterator aIt = rTokenMap.find( rOdfName );
+ if( aIt != rTokenMap.end() )
+ {
+ ornOpCode = aIt->second.OpCode;
+ if( rOoxName.getLength() > 0 )
+ {
+ FormulaOpCodeMapEntry aEntry;
+ aEntry.Name = rOoxName;
+ aEntry.Token.OpCode = ornOpCode;
+ maParserMap.push_back( aEntry );
+ }
+ return true;
+ }
+ OSL_ENSURE( false,
+ OStringBuffer( "OpCodeProviderImpl::initOpCode - opcode for \"" ).
+ append( OUStringToOString( rOdfName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( "\" not found" ).getStr() );
+ return false;
+}
+
+bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName )
+{
+ OUString aOoxName;
+ if( pcOoxName ) aOoxName = OUString::createFromAscii( pcOoxName );
+ return initOpCode( ornOpCode, rTokenMap, OUString::createFromAscii( pcOdfName ), aOoxName );
+}
+
+bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName )
+{
+ OUString aOoxName;
+ if( cOoxName ) aOoxName = OUString( cOoxName );
+ return initOpCode( ornOpCode, rTokenMap, OUString( cOdfName ), aOoxName );
+}
+
+bool OpCodeProviderImpl::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap )
+{
+ bool bIsValid = false;
+ if( orFuncInfo.maOdfFuncName.getLength() > 0 )
+ {
+ ApiTokenMap::const_iterator aIt = rFuncTokenMap.find( orFuncInfo.maOdfFuncName );
+ if( aIt != rFuncTokenMap.end() )
+ {
+ orFuncInfo.mnApiOpCode = aIt->second.OpCode;
+ bIsValid =
+ (orFuncInfo.mnApiOpCode >= 0) &&
+ (orFuncInfo.mnApiOpCode != OPCODE_UNKNOWN) &&
+ (orFuncInfo.mnApiOpCode != OPCODE_NONAME);
+ OSL_ENSURE( bIsValid,
+ OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no valid opcode for ODF function \"" ).
+ append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( '"' ).getStr() );
+
+ if( bIsValid && (orFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) )
+ {
+ bIsValid = (aIt->second.Data >>= orFuncInfo.maExtProgName) && (orFuncInfo.maExtProgName.getLength() > 0);
+ OSL_ENSURE( bIsValid,
+ OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no programmatical name for external function \"" ).
+ append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( '"' ).getStr() );
+ }
+
+ // add to parser map, if OOX function name exists
+ if( bIsValid && (orFuncInfo.maOoxFuncName.getLength() > 0) )
+ {
+ // create the parser map entry
+ FormulaOpCodeMapEntry aEntry;
+ aEntry.Name = orFuncInfo.maOoxFuncName;
+ aEntry.Token = aIt->second;
+ maParserMap.push_back( aEntry );
+ }
+ }
+ else
+ {
+ // ignore entries for functions unknown by Calc *and* by Excel
+ bIsValid = orFuncInfo.maOoxFuncName.getLength() == 0;
+ }
+ }
+ else if( orFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
+ {
+ orFuncInfo.mnApiOpCode = OPCODE_EXTERNAL;
+ bIsValid = true;
+ }
+ else if( orFuncInfo.maOoxFuncName.getLength() > 0 )
+ {
+ orFuncInfo.mnApiOpCode = OPCODE_BAD;
+ bIsValid = true;
+ }
+
+ if( !bIsValid || (orFuncInfo.mnApiOpCode == OPCODE_UNKNOWN) || (orFuncInfo.mnApiOpCode < 0) )
+ orFuncInfo.mnApiOpCode = OPCODE_NONAME;
+ return bIsValid;
+}
+
+bool OpCodeProviderImpl::initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos )
+{
+ bool bIsValid = true;
+ for( FunctionInfoVector::const_iterator aIt = rFuncInfos.begin(), aEnd = rFuncInfos.end(); aIt != aEnd; ++aIt )
+ {
+ FunctionInfoRef xFuncInfo = *aIt;
+ // set API opcode from ODF function name
+ bIsValid &= initFuncOpCode( *xFuncInfo, xFuncInfo->mbExternal ? rExtFuncTokenMap : rIntFuncTokenMap );
+ // insert the function info into the maps
+ if( xFuncInfo->mnApiOpCode != OPCODE_NONAME )
+ {
+ if( (xFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && (xFuncInfo->maExtProgName.getLength() > 0) )
+ maExtProgFuncs[ xFuncInfo->maExtProgName ] = xFuncInfo;
+ else
+ maOpCodeFuncs[ xFuncInfo->mnApiOpCode ] = xFuncInfo;
+ }
+ }
+ return bIsValid;
+}
+
+// ----------------------------------------------------------------------------
+
+OpCodeProvider::OpCodeProvider( const Reference< XMultiServiceFactory >& rxFactory,
+ FilterType eFilter, BiffType eBiff, bool bImportFilter ) :
+ FunctionProvider( eFilter, eBiff, bImportFilter ),
+ mxOpCodeImpl( new OpCodeProviderImpl( getFuncs(), rxFactory ) )
+{
+}
+
+OpCodeProvider::~OpCodeProvider()
+{
+}
+
+const ApiOpCodes& OpCodeProvider::getOpCodes() const
+{
+ return *mxOpCodeImpl;
+}
+
+const FunctionInfo* OpCodeProvider::getFuncInfoFromApiToken( const ApiToken& rToken ) const
+{
+ const FunctionInfo* pFuncInfo = 0;
+ if( (rToken.OpCode == mxOpCodeImpl->OPCODE_EXTERNAL) && rToken.Data.has< OUString >() )
+ pFuncInfo = mxOpCodeImpl->maExtProgFuncs.get( rToken.Data.get< OUString >() ).get();
+ else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_MACRO) && rToken.Data.has< OUString >() )
+ pFuncInfo = getFuncInfoFromMacroName( rToken.Data.get< OUString >() );
+ else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_BAD) && rToken.Data.has< OUString >() )
+ pFuncInfo = getFuncInfoFromOoxFuncName( rToken.Data.get< OUString >() );
+ else
+ pFuncInfo = mxOpCodeImpl->maOpCodeFuncs.get( rToken.OpCode ).get();
+ return pFuncInfo;
+}
+
+Sequence< FormulaOpCodeMapEntry > OpCodeProvider::getOoxParserMap() const
+{
+ return ContainerHelper::vectorToSequence( mxOpCodeImpl->maParserMap );
+}
+
+// API formula parser wrapper =================================================
+
+ApiParserWrapper::ApiParserWrapper(
+ const Reference< XMultiServiceFactory >& rxFactory, const OpCodeProvider& rOpCodeProv ) :
+ OpCodeProvider( rOpCodeProv )
+{
+ if( rxFactory.is() ) try
+ {
+ mxParser.set( rxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.sheet.FormulaParser" ) ), UNO_QUERY_THROW );
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( mxParser.is(), "ApiParserWrapper::ApiParserWrapper - cannot create API formula parser object" );
+ maParserProps.set( mxParser );
+ maParserProps.setProperty( PROP_CompileEnglish, true );
+ maParserProps.setProperty( PROP_FormulaConvention, ::com::sun::star::sheet::AddressConvention::XL_OOX );
+ maParserProps.setProperty( PROP_IgnoreLeadingSpaces, false );
+ maParserProps.setProperty( PROP_OpCodeMap, getOoxParserMap() );
+}
+
+ApiTokenSequence ApiParserWrapper::parseFormula( const OUString& rFormula, const CellAddress& rRefPos )
+{
+ ApiTokenSequence aTokenSeq;
+ if( mxParser.is() ) try
+ {
+ aTokenSeq = mxParser->parseFormula( rFormula, rRefPos );
+ }
+ catch( Exception& )
+ {
+ }
+ return aTokenSeq;
+}
+
+// formula contexts ===========================================================
+
+FormulaContext::FormulaContext( bool bRelativeAsOffset, bool b2dRefsAs3dRefs, bool bAllowNulChars ) :
+ maBaseAddress( 0, 0, 0 ),
+ mbRelativeAsOffset( bRelativeAsOffset ),
+ mb2dRefsAs3dRefs( b2dRefsAs3dRefs ),
+ mbAllowNulChars( bAllowNulChars )
+{
+}
+
+FormulaContext::~FormulaContext()
+{
+}
+
+void FormulaContext::setSharedFormula( const CellAddress& )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+TokensFormulaContext::TokensFormulaContext( bool bRelativeAsOffset, bool b2dRefsAs3dRefs, bool bAllowNulChars ) :
+ FormulaContext( bRelativeAsOffset, b2dRefsAs3dRefs, bAllowNulChars )
+{
+}
+
+void TokensFormulaContext::setTokens( const ApiTokenSequence& rTokens )
+{
+ maTokens = rTokens;
+}
+
+// ----------------------------------------------------------------------------
+
+SimpleFormulaContext::SimpleFormulaContext( const Reference< XFormulaTokens >& rxTokens,
+ bool bRelativeAsOffset, bool b2dRefsAs3dRefs, bool bAllowNulChars ) :
+ FormulaContext( bRelativeAsOffset, b2dRefsAs3dRefs, bAllowNulChars ),
+ mxTokens( rxTokens )
+{
+ OSL_ENSURE( mxTokens.is(), "SimpleFormulaContext::SimpleFormulaContext - missing XFormulaTokens interface" );
+}
+
+void SimpleFormulaContext::setTokens( const ApiTokenSequence& rTokens )
+{
+ mxTokens->setTokens( rTokens );
+}
+
+// formula parser/printer base class for filters ==============================
+
+namespace {
+
+bool lclConvertToCellAddress( CellAddress& orAddress, const SingleReference& rSingleRef, sal_Int32 nForbiddenFlags, sal_Int32 nFilterBySheet )
+{
+ orAddress = CellAddress( static_cast< sal_Int16 >( rSingleRef.Sheet ),
+ rSingleRef.Column, rSingleRef.Row );
+ return
+ !getFlag( rSingleRef.Flags, nForbiddenFlags ) &&
+ ((nFilterBySheet < 0) || (nFilterBySheet == rSingleRef.Sheet));
+}
+
+bool lclConvertToCellRange( CellRangeAddress& orRange, const ComplexReference& rComplexRef, sal_Int32 nForbiddenFlags, sal_Int32 nFilterBySheet )
+{
+ orRange = CellRangeAddress( static_cast< sal_Int16 >( rComplexRef.Reference1.Sheet ),
+ rComplexRef.Reference1.Column, rComplexRef.Reference1.Row,
+ rComplexRef.Reference2.Column, rComplexRef.Reference2.Row );
+ return
+ !getFlag( rComplexRef.Reference1.Flags, nForbiddenFlags ) &&
+ !getFlag( rComplexRef.Reference2.Flags, nForbiddenFlags ) &&
+ (rComplexRef.Reference1.Sheet == rComplexRef.Reference2.Sheet) &&
+ ((nFilterBySheet < 0) || (nFilterBySheet == rComplexRef.Reference1.Sheet));
+}
+
+enum TokenToRangeListState { STATE_REF, STATE_SEP, STATE_OPEN, STATE_CLOSE, STATE_ERROR };
+
+TokenToRangeListState lclProcessRef( ApiCellRangeList& orRanges, const Any& rData, bool bAllowRelative, sal_Int32 nFilterBySheet )
+{
+ using namespace ::com::sun::star::sheet::ReferenceFlags;
+ const sal_Int32 FORBIDDEN_FLAGS_DEL = COLUMN_DELETED | ROW_DELETED | SHEET_DELETED;
+ const sal_Int32 FORBIDDEN_FLAGS_REL = FORBIDDEN_FLAGS_DEL | COLUMN_RELATIVE | ROW_RELATIVE | SHEET_RELATIVE | RELATIVE_NAME;
+
+ sal_Int32 nForbiddenFlags = bAllowRelative ? FORBIDDEN_FLAGS_DEL : FORBIDDEN_FLAGS_REL;
+ SingleReference aSingleRef;
+ if( rData >>= aSingleRef )
+ {
+ CellAddress aAddress;
+ // ignore invalid addresses (with #REF! errors), but do not stop parsing
+ if( lclConvertToCellAddress( aAddress, aSingleRef, nForbiddenFlags, nFilterBySheet ) )
+ 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 do not stop parsing
+ if( lclConvertToCellRange( aRange, aComplexRef, nForbiddenFlags, nFilterBySheet ) )
+ 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 ) :
+ OpCodeProvider( rHelper.getDocumentFactory(), rHelper.getFilterType(), rHelper.getBiff(), rHelper.getBaseFilter().isImportFilter() ),
+ ApiOpCodes( getOpCodes() ),
+ WorkbookHelper( 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();
+}
+
+// ----------------------------------------------------------------------------
+
+OUString FormulaProcessorBase::generateApiAddressString( const CellAddress& rAddress ) const
+{
+ OUString aCellName;
+ PropertySet aCellProp( getCellFromDoc( rAddress ) );
+ aCellProp.getProperty( aCellName, PROP_AbsoluteName );
+ OSL_ENSURE( aCellName.getLength() > 0, "FormulaProcessorBase::generateApiAddressString - cannot create cell address string" );
+ return aCellName;
+}
+
+OUString FormulaProcessorBase::generateApiRangeString( const CellRangeAddress& rRange ) const
+{
+ OUString aRangeName;
+ PropertySet aRangeProp( getCellRangeFromDoc( rRange ) );
+ aRangeProp.getProperty( aRangeName, PROP_AbsoluteName );
+ OSL_ENSURE( aRangeName.getLength() > 0, "FormulaProcessorBase::generateApiRangeString - cannot create cell range string" );
+ return aRangeName;
+}
+
+OUString FormulaProcessorBase::generateApiRangeListString( const ApiCellRangeList& rRanges ) const
+{
+ OUStringBuffer aBuffer;
+ for( ApiCellRangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt )
+ {
+ OUString aRangeName = generateApiRangeString( *aIt );
+ if( aRangeName.getLength() > 0 )
+ {
+ if( aBuffer.getLength() > 0 )
+ aBuffer.append( API_TOKEN_SEP );
+ aBuffer.append( aRangeName );
+ }
+ }
+ return aBuffer.makeStringAndClear();
+}
+
+OUString FormulaProcessorBase::generateApiString( const OUString& rString )
+{
+ OUString aRetString = rString;
+ sal_Int32 nQuotePos = aRetString.getLength();
+ while( (nQuotePos = aRetString.lastIndexOf( '"', nQuotePos )) >= 0 )
+ aRetString = aRetString.replaceAt( nQuotePos, 1, CREATE_OUSTRING( "\"\"" ) );
+ return OUStringBuffer().append( sal_Unicode( '"' ) ).append( aRetString ).append( sal_Unicode( '"' ) ).makeStringAndClear();
+}
+
+OUString FormulaProcessorBase::generateApiArray( const Matrix< Any >& rMatrix )
+{
+ OSL_ENSURE( !rMatrix.empty(), "FormulaProcessorBase::generateApiArray - missing matrix values" );
+ OUStringBuffer aBuffer;
+ aBuffer.append( API_TOKEN_ARRAY_OPEN );
+ for( size_t nRow = 0, nHeight = rMatrix.height(); nRow < nHeight; ++nRow )
+ {
+ if( nRow > 0 )
+ aBuffer.append( API_TOKEN_ARRAY_ROWSEP );
+ for( Matrix< Any >::const_iterator aBeg = rMatrix.row_begin( nRow ), aIt = aBeg, aEnd = rMatrix.row_end( nRow ); aIt != aEnd; ++aIt )
+ {
+ double fValue = 0.0;
+ OUString aString;
+ if( aIt != aBeg )
+ aBuffer.append( API_TOKEN_ARRAY_COLSEP );
+ if( *aIt >>= fValue )
+ aBuffer.append( fValue );
+ else if( *aIt >>= aString )
+ aBuffer.append( generateApiString( aString ) );
+ else
+ aBuffer.appendAscii( "\"\"" );
+ }
+ }
+ aBuffer.append( API_TOKEN_ARRAY_CLOSE );
+ return aBuffer.makeStringAndClear();
+}
+
+// ----------------------------------------------------------------------------
+
+Any FormulaProcessorBase::extractReference( const ApiTokenSequence& rTokens ) const
+{
+ ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES, true );
+ if( aTokenIt.is() && (aTokenIt->OpCode == OPCODE_PUSH) )
+ {
+ Any aRefAny = aTokenIt->Data;
+ if( !(++aTokenIt).is() && (aRefAny.has< SingleReference >() || aRefAny.has< ComplexReference >()) )
+ return aRefAny;
+ }
+ return Any();
+}
+
+bool FormulaProcessorBase::extractCellAddress( CellAddress& orAddress,
+ const ApiTokenSequence& rTokens, bool bAllowRelative ) const
+{
+ CellRangeAddress aRange;
+ if( extractCellRange( aRange, rTokens, bAllowRelative ) && (aRange.StartColumn == aRange.EndColumn) && (aRange.StartRow == aRange.EndRow) )
+ {
+ orAddress.Sheet = aRange.Sheet;
+ orAddress.Column = aRange.StartColumn;
+ orAddress.Row = aRange.StartRow;
+ return true;
+ }
+ return false;
+}
+
+bool FormulaProcessorBase::extractCellRange( CellRangeAddress& orRange,
+ const ApiTokenSequence& rTokens, bool bAllowRelative ) const
+{
+ ApiCellRangeList aRanges;
+ lclProcessRef( aRanges, extractReference( rTokens ), bAllowRelative, -1 );
+ if( !aRanges.empty() )
+ {
+ orRange = aRanges.front();
+ return true;
+ }
+ return false;
+}
+
+void FormulaProcessorBase::extractCellRangeList( ApiCellRangeList& orRanges,
+ const ApiTokenSequence& rTokens, bool bAllowRelative, sal_Int32 nFilterBySheet ) const
+{
+ orRanges.clear();
+ TokenToRangeListState eState = STATE_OPEN;
+ sal_Int32 nParenLevel = 0;
+ for( ApiTokenIterator aIt( rTokens, OPCODE_SPACES, true ); aIt.is() && (eState != STATE_ERROR); ++aIt )
+ {
+ sal_Int32 nOpCode = aIt->OpCode;
+ switch( eState )
+ {
+ // #i107275# accept OPCODE_SEP and OPCODE_LIST as separator token
+ case STATE_REF:
+ if( nOpCode == OPCODE_SEP ) eState = STATE_SEP;
+ else if( nOpCode == OPCODE_LIST ) eState = STATE_SEP;
+ else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
+ else eState = STATE_ERROR;
+ break;
+ case STATE_SEP:
+ if( nOpCode == OPCODE_PUSH ) eState = lclProcessRef( orRanges, aIt->Data, bAllowRelative, nFilterBySheet );
+ else if( nOpCode == OPCODE_SEP ) eState = STATE_SEP;
+ else if( nOpCode == OPCODE_LIST ) eState = STATE_SEP;
+ else if( nOpCode == OPCODE_OPEN ) eState = lclProcessOpen( nParenLevel );
+ else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
+ else eState = STATE_ERROR;
+ break;
+ case STATE_OPEN:
+ if( nOpCode == OPCODE_PUSH ) eState = lclProcessRef( orRanges, aIt->Data, bAllowRelative, nFilterBySheet );
+ else if( nOpCode == OPCODE_SEP ) eState = STATE_SEP;
+ else if( nOpCode == OPCODE_LIST ) eState = STATE_SEP;
+ else if( nOpCode == OPCODE_OPEN ) eState = lclProcessOpen( nParenLevel );
+ else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
+ else eState = STATE_ERROR;
+ break;
+ case STATE_CLOSE:
+ if( nOpCode == OPCODE_SEP ) eState = STATE_SEP;
+ else if( nOpCode == OPCODE_LIST ) eState = STATE_SEP;
+ else if( nOpCode == 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, OPCODE_SPACES, true );
+ return aTokenIt.is() && (aTokenIt->OpCode == 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( OPCODE_SEP, Any() ) );
+ aNewTokens.push_back( ApiToken( OPCODE_PUSH, Any( aEntry ) ) );
+ }
+ orTokens = ContainerHelper::vectorToSequence( aNewTokens );
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/formulaparser.cxx b/oox/source/xls/formulaparser.cxx
new file mode 100644
index 000000000000..34d87336f776
--- /dev/null
+++ b/oox/source/xls/formulaparser.cxx
@@ -0,0 +1,2863 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/formulaparser.hxx"
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/ExternalReference.hpp>
+#include <com/sun/star/sheet/FormulaToken.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+#include <com/sun/star/sheet/SingleReference.hpp>
+#include "properties.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.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::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::ComplexReference;
+using ::com::sun::star::sheet::ExternalReference;
+using ::com::sun::star::sheet::SingleReference;
+using ::com::sun::star::sheet::XFormulaParser;
+using namespace ::com::sun::star::sheet::ReferenceFlags;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+sal_uInt16 lclReadFmlaSize( BiffInputStream& rStrm, BiffType eBiff, const sal_uInt16* pnFmlaSize )
+{
+ return pnFmlaSize ? *pnFmlaSize : ((eBiff == BIFF2) ? rStrm.readuInt8() : rStrm.readuInt16());
+}
+
+} // namespace
+
+// formula finalizer ==========================================================
+
+FormulaFinalizer::FormulaFinalizer( const OpCodeProvider& rOpCodeProv ) :
+ OpCodeProvider( rOpCodeProv ),
+ ApiOpCodes( getOpCodes() )
+{
+ maTokens.reserve( 0x2000 );
+}
+
+ApiTokenSequence FormulaFinalizer::finalizeTokenArray( const ApiTokenSequence& rTokens )
+{
+ maTokens.clear();
+ if( rTokens.hasElements() )
+ {
+ const ApiToken* pToken = rTokens.getConstArray();
+ processTokens( pToken, pToken + rTokens.getLength() );
+ }
+ return ContainerHelper::vectorToSequence( maTokens );
+}
+
+const FunctionInfo* FormulaFinalizer::resolveBadFuncName( const OUString& ) const
+{
+ return 0;
+}
+
+OUString FormulaFinalizer::resolveDefinedName( sal_Int32 ) const
+{
+ return OUString();
+}
+
+const FunctionInfo* FormulaFinalizer::getFunctionInfo( ApiToken& orFuncToken )
+{
+ // first, try to find a regular function info from token op-code
+ if( const FunctionInfo* pRegFuncInfo = getFuncInfoFromApiToken( orFuncToken ) )
+ return pRegFuncInfo;
+
+ // try to recognize a function from an external library
+ if( (orFuncToken.OpCode == OPCODE_BAD) && orFuncToken.Data.has< OUString >() )
+ {
+ // virtual call to resolveBadFuncName()
+ if( const FunctionInfo* pLibFuncInfo = resolveBadFuncName( orFuncToken.Data.get< OUString >() ) )
+ {
+ // write function op-code to the OPCODE_BAD token
+ orFuncToken.OpCode = pLibFuncInfo->mnApiOpCode;
+ // if it is an external function, insert programmatic function name
+ if( (orFuncToken.OpCode == OPCODE_EXTERNAL) && (pLibFuncInfo->maExtProgName.getLength() > 0) )
+ orFuncToken.Data <<= pLibFuncInfo->maExtProgName;
+ else
+ orFuncToken.Data.clear(); // clear string from OPCODE_BAD
+ return pLibFuncInfo;
+ }
+ }
+
+ // no success - return null
+ return 0;
+
+}
+
+const FunctionInfo* FormulaFinalizer::getExternCallInfo( ApiToken& orFuncToken, const ApiToken& rECToken )
+{
+ // try to resolve the passed token to a supported sheet function
+ if( const FunctionInfo* pFuncInfo = getFuncInfoFromApiToken( rECToken ) )
+ {
+ orFuncToken.OpCode = pFuncInfo->mnApiOpCode;
+ // programmatic add-in function name
+ if( (pFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && (pFuncInfo->maExtProgName.getLength() > 0) )
+ orFuncToken.Data <<= pFuncInfo->maExtProgName;
+ // name of unsupported function, convert to OPCODE_BAD to preserve the name
+ else if( (pFuncInfo->mnApiOpCode == OPCODE_BAD) && (pFuncInfo->maOoxFuncName.getLength() > 0) )
+ orFuncToken.Data <<= pFuncInfo->maOoxFuncName;
+ return pFuncInfo;
+ }
+
+ // macro call or unknown function name, move data to function token
+ if( (rECToken.OpCode == OPCODE_MACRO) || (rECToken.OpCode == OPCODE_BAD) )
+ orFuncToken = rECToken;
+
+ // defined name used as function call, convert to OPCODE_BAD to preserve the name
+ if( (rECToken.OpCode == OPCODE_NAME) && rECToken.Data.has< sal_Int32 >() )
+ {
+ OUString aDefName = resolveDefinedName( rECToken.Data.get< sal_Int32 >() );
+ if( aDefName.getLength() > 0 )
+ {
+ orFuncToken.OpCode = OPCODE_BAD;
+ orFuncToken.Data <<= aDefName;
+ }
+ }
+
+ return 0;
+}
+
+void FormulaFinalizer::processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd )
+{
+ while( pToken < pTokenEnd )
+ {
+ // push the current token into the vector
+ bool bValid = appendFinalToken( *pToken );
+ // try to process a function
+ if( const FunctionInfo* pFuncInfo = bValid ? getFunctionInfo( maTokens.back() ) : 0 )
+ pToken = processParameters( *pFuncInfo, pToken + 1, pTokenEnd );
+ // otherwise, go to next token
+ else
+ ++pToken;
+ }
+}
+
+const ApiToken* FormulaFinalizer::processParameters(
+ const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd )
+{
+ // remember position of the token containing the function op-code
+ size_t nFuncNameIdx = maTokens.size() - 1;
+
+ // process a function, if an OPCODE_OPEN token is following
+ OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::processParameters - OPCODE_OPEN expected" );
+ if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN) )
+ {
+ // append the OPCODE_OPEN token to the vector
+ maTokens.append( OPCODE_OPEN );
+
+ // store positions of OPCODE_OPEN, parameter separators, and OPCODE_CLOSE
+ ParameterPosVector aParams;
+ pToken = findParameters( aParams, pToken, pTokenEnd );
+ OSL_ENSURE( aParams.size() >= 2, "FormulaFinalizer::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 EXTERN.CALL functions. The actual function name is
+ contained as reference to a defined name in the first (hidden)
+ parameter. */
+ if( rFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
+ {
+ ApiToken& rFuncToken = maTokens[ nFuncNameIdx ];
+ rFuncToken.OpCode = OPCODE_NONAME;
+
+ // try to initialize function token from first parameter
+ if( const ApiToken* pECToken = getSingleToken( *aPosIt + 1, *(aPosIt + 1) ) )
+ if( const FunctionInfo* pECFuncInfo = getExternCallInfo( rFuncToken, *pECToken ) )
+ pRealFuncInfo = pECFuncInfo;
+
+ /* On success (something has been inserted into rFuncToken),
+ skip the first parameter. */
+ if( rFuncToken.OpCode != OPCODE_NONAME )
+ {
+ --nParamCount;
+ ++aPosIt;
+ }
+ }
+
+ // process all parameters
+ FunctionParamInfoIterator aParamInfoIt( *pRealFuncInfo );
+ size_t nLastValidSize = maTokens.size();
+ size_t nLastValidCount = 0;
+ for( size_t nParam = 0; nParam < nParamCount; ++nParam, ++aPosIt, ++aParamInfoIt )
+ {
+ // add embedded Calc-only parameters
+ if( aParamInfoIt.isCalcOnlyParam() )
+ {
+ appendCalcOnlyParameter( *pRealFuncInfo, nParam );
+ while( aParamInfoIt.isCalcOnlyParam() ) ++aParamInfoIt;
+ }
+
+ const ApiToken* pParamBegin = *aPosIt + 1;
+ const ApiToken* pParamEnd = *(aPosIt + 1);
+ bool bIsEmpty = isEmptyParameter( pParamBegin, pParamEnd );
+
+ if( !aParamInfoIt.isExcelOnlyParam() )
+ {
+ // replace empty second and third parameter in IF function with zeros
+ if( (pRealFuncInfo->mnOobFuncId == OOBIN_FUNC_IF) && ((nParam == 1) || (nParam == 2)) && bIsEmpty )
+ {
+ maTokens.append< double >( OPCODE_PUSH, 0.0 );
+ bIsEmpty = false;
+ }
+ else
+ {
+ // process all tokens of the parameter
+ processTokens( pParamBegin, pParamEnd );
+ }
+ // append parameter separator token
+ maTokens.append( 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 = maTokens.size();
+ nLastValidCount = nParam + 1;
+ }
+ }
+
+ // #84453# remove trailing optional empty parameters
+ maTokens.resize( nLastValidSize );
+
+ // add trailing Calc-only parameters
+ if( aParamInfoIt.isCalcOnlyParam() )
+ appendCalcOnlyParameter( *pRealFuncInfo, nLastValidCount );
+
+ // add optional parameters that are required in Calc
+ appendRequiredParameters( *pRealFuncInfo, nLastValidCount );
+
+ // remove last parameter separator token
+ if( maTokens.back().OpCode == OPCODE_SEP )
+ maTokens.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 != OPCODE_BAD )
+ maTokens.append( OPCODE_CLOSE );
+ }
+
+ /* Replace OPCODE_EXTERNAL with OPCODE_NONAME to get #NAME! error in cell,
+ if no matching add-in function was found. */
+ ApiToken& rFuncNameToken = maTokens[ nFuncNameIdx ];
+ if( (rFuncNameToken.OpCode == OPCODE_EXTERNAL) && !rFuncNameToken.Data.hasValue() )
+ rFuncNameToken.OpCode = OPCODE_NONAME;
+
+ return pToken;
+}
+
+bool FormulaFinalizer::isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+ while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
+ if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_MISSING) ) ++pToken;
+ while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
+ return pToken == pTokenEnd;
+}
+
+const ApiToken* FormulaFinalizer::getSingleToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+ const ApiToken* pSingleToken = 0;
+ // skip leading whitespace tokens
+ while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
+ // remember first non-whitespace token
+ if( pToken < pTokenEnd ) pSingleToken = pToken++;
+ // skip trailing whitespace tokens
+ while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
+ // return null, if other non-whitespace tokens follow
+ return (pToken == pTokenEnd) ? pSingleToken : 0;
+}
+
+const ApiToken* FormulaFinalizer::skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+ // skip tokens between OPCODE_OPEN and OPCODE_CLOSE
+ OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "skipParentheses - OPCODE_OPEN expected" );
+ ++pToken;
+ while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
+ {
+ if( pToken->OpCode == OPCODE_OPEN )
+ pToken = skipParentheses( pToken, pTokenEnd );
+ else
+ ++pToken;
+ }
+ // skip the OPCODE_CLOSE token
+ OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "skipParentheses - OPCODE_CLOSE expected" );
+ return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
+}
+
+const ApiToken* FormulaFinalizer::findParameters( ParameterPosVector& rParams,
+ const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+ // push position of OPCODE_OPEN
+ OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::findParameters - OPCODE_OPEN expected" );
+ rParams.push_back( pToken++ );
+
+ // find positions of parameter separators
+ while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
+ {
+ if( pToken->OpCode == OPCODE_OPEN )
+ pToken = skipParentheses( pToken, pTokenEnd );
+ else if( pToken->OpCode == OPCODE_SEP )
+ rParams.push_back( pToken++ );
+ else
+ ++pToken;
+ }
+
+ // push position of OPCODE_CLOSE
+ OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "FormulaFinalizer::findParameters - OPCODE_CLOSE expected" );
+ rParams.push_back( pToken );
+ return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
+}
+
+void FormulaFinalizer::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, "FormulaFinalizer::appendCalcOnlyParameter - unexpected parameter index" );
+ maTokens.append< double >( OPCODE_PUSH, 1.0 );
+ maTokens.append( OPCODE_SEP );
+ break;
+ }
+}
+
+void FormulaFinalizer::appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount )
+{
+ switch( rFuncInfo.mnOobFuncId )
+ {
+ case OOBIN_FUNC_WEEKNUM:
+ if( nParamCount == 1 )
+ {
+ maTokens.append< double >( OPCODE_PUSH, 1.0 );
+ maTokens.append( OPCODE_SEP );
+ }
+ break;
+ }
+}
+
+bool FormulaFinalizer::appendFinalToken( const ApiToken& rToken )
+{
+ // replace OPCODE_MACRO without macro name with #NAME? error code
+ bool bValid = (rToken.OpCode != OPCODE_MACRO) || rToken.Data.hasValue();
+ if( bValid )
+ {
+ maTokens.push_back( rToken );
+ }
+ else
+ {
+ maTokens.append( OPCODE_ARRAY_OPEN );
+ maTokens.append( OPCODE_PUSH, BiffHelper::calcDoubleFromError( BIFF_ERR_NAME ) );
+ maTokens.append( OPCODE_ARRAY_CLOSE );
+ }
+ return bValid;
+}
+
+// parser implementation base =================================================
+
+class FormulaParserImpl : public FormulaFinalizer, public WorkbookHelper
+{
+public:
+ explicit FormulaParserImpl( const FormulaParser& rParent );
+
+ /** 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 );
+
+ /** Tries to resolve the passed ref-id to an OLE target URL. */
+ OUString resolveOleTarget( sal_Int32 nRefId ) const;
+
+protected:
+ typedef ::std::pair< sal_Int32, bool > WhiteSpace;
+ typedef ::std::vector< WhiteSpace > WhiteSpaceVec;
+
+ /** 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();
+ static void appendSpaces( WhiteSpaceVec& orSpaces, sal_Int32 nCount, bool bLineFeed );
+ void appendLeadingSpaces( sal_Int32 nCount, bool bLineFeed );
+ void appendOpeningSpaces( sal_Int32 nCount, bool bLineFeed );
+ void appendClosingSpaces( sal_Int32 nCount, bool bLineFeed );
+
+ size_t getFormulaSize() const;
+ Any& appendRawToken( sal_Int32 nOpCode );
+ Any& insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd );
+ size_t appendWhiteSpaceTokens( const WhiteSpaceVec* pSpaces );
+ size_t insertWhiteSpaceTokens( const WhiteSpaceVec* pSpaces, 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, const WhiteSpaceVec* pSpaces = 0 );
+ bool pushAnyOperandToken( const Any& rAny, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
+ template< typename Type >
+ bool pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
+ template< typename Type >
+ inline bool pushValueOperandToken( const Type& rValue, const WhiteSpaceVec* pSpaces = 0 )
+ { return pushValueOperandToken( rValue, OPCODE_PUSH, pSpaces ); }
+ bool pushParenthesesOperandToken( const WhiteSpaceVec* pOpeningSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
+ bool pushUnaryPreOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
+ bool pushUnaryPostOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
+ bool pushBinaryOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
+ bool pushParenthesesOperatorToken( const WhiteSpaceVec* pOpeningSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
+ bool pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
+ bool pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
+
+ 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, OPCODE_PUSH ); }
+ bool pushBoolOperand( bool bValue );
+ bool pushErrorOperand( double fEncodedError );
+ bool pushBiffBoolOperand( sal_uInt8 nValue );
+ 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 );
+ template< typename Type >
+ bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const Type& rApiRef );
+ 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 bPushBadToken );
+ bool pushDefinedNameOperand( const DefinedNameRef& rxDefName );
+ bool pushExternalFuncOperand( const FunctionInfo& rFuncInfo );
+ bool pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem );
+ bool pushExternalNameOperand( const ExternalNameRef& rxExtName, const ExternalLink& rExtLink );
+
+ 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, bool bSameSheet ) 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, bool bSameSheet, 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;
+
+private:
+ // finalize token sequence ------------------------------------------------
+
+ virtual const FunctionInfo* resolveBadFuncName( const OUString& rTokenData ) const;
+ virtual ::rtl::OUString resolveDefinedName( sal_Int32 nTokenIndex ) const;
+
+protected:
+ 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< size_t > SizeTypeVector;
+
+ ApiTokenVector maTokenStorage; /// Raw unordered token storage.
+ SizeTypeVector maTokenIndexes; /// Indexes into maTokenStorage.
+ SizeTypeVector maOperandSizeStack; /// Stack with token sizes per operand.
+ WhiteSpaceVec maLeadingSpaces; /// List of whitespaces before next token.
+ WhiteSpaceVec maOpeningSpaces; /// List of whitespaces before opening parenthesis.
+ WhiteSpaceVec maClosingSpaces; /// List of whitespaces before closing parenthesis.
+ FormulaContext* mpContext; /// Current formula context.
+};
+
+// ----------------------------------------------------------------------------
+
+FormulaParserImpl::FormulaParserImpl( const FormulaParser& rParent ) :
+ FormulaFinalizer( rParent ),
+ WorkbookHelper( rParent ),
+ mnMaxApiCol( rParent.getAddressConverter().getMaxApiAddress().Column ),
+ mnMaxApiRow( rParent.getAddressConverter().getMaxApiAddress().Row ),
+ mnMaxXlsCol( rParent.getAddressConverter().getMaxXlsAddress().Column ),
+ mnMaxXlsRow( rParent.getAddressConverter().getMaxXlsAddress().Row ),
+ mpContext( 0 )
+{
+ // reserve enough space to make resize(), push_back() etc. cheap
+ maTokenStorage.reserve( 0x2000 );
+ maTokenIndexes.reserve( 0x2000 );
+ maOperandSizeStack.reserve( 256 );
+ maLeadingSpaces.reserve( 256 );
+ maOpeningSpaces.reserve( 256 );
+ maClosingSpaces.reserve( 256 );
+}
+
+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 );
+}
+
+OUString FormulaParserImpl::resolveOleTarget( sal_Int32 nRefId ) const
+{
+ const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get();
+ OSL_ENSURE( pExtLink && (pExtLink->getLinkType() == LINKTYPE_OLE), "FormulaParserImpl::resolveOleTarget - missing or wrong link" );
+ if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_OLE) )
+ return getBaseFilter().getAbsoluteUrl( pExtLink->getTargetUrl() );
+ return OUString();
+}
+
+void FormulaParserImpl::initializeImport( FormulaContext& rContext )
+{
+ maTokenStorage.clear();
+ maTokenIndexes.clear();
+ maOperandSizeStack.clear();
+ mpContext = &rContext;
+}
+
+void FormulaParserImpl::finalizeImport( const ApiTokenSequence& rTokens )
+{
+ ApiTokenSequence aFinalTokens = finalizeTokenArray( rTokens );
+ if( aFinalTokens.hasElements() )
+ mpContext->setTokens( aFinalTokens );
+}
+
+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()
+{
+ maLeadingSpaces.clear();
+ maOpeningSpaces.clear();
+ maClosingSpaces.clear();
+ return true;
+}
+
+void FormulaParserImpl::appendSpaces( WhiteSpaceVec& orSpaces, sal_Int32 nCount, bool bLineFeed )
+{
+ OSL_ENSURE( nCount >= 0, "FormulaParserImpl::appendSpaces - negative count" );
+ if( nCount > 0 )
+ orSpaces.push_back( WhiteSpace( nCount, bLineFeed ) );
+}
+
+void FormulaParserImpl::appendLeadingSpaces( sal_Int32 nCount, bool bLineFeed )
+{
+ appendSpaces( maLeadingSpaces, nCount, bLineFeed );
+}
+
+void FormulaParserImpl::appendOpeningSpaces( sal_Int32 nCount, bool bLineFeed )
+{
+ appendSpaces( maOpeningSpaces, nCount, bLineFeed );
+}
+
+void FormulaParserImpl::appendClosingSpaces( sal_Int32 nCount, bool bLineFeed )
+{
+ appendSpaces( maClosingSpaces, nCount, bLineFeed );
+}
+
+size_t FormulaParserImpl::getFormulaSize() const
+{
+ return maTokenIndexes.size();
+}
+
+Any& FormulaParserImpl::appendRawToken( sal_Int32 nOpCode )
+{
+ maTokenIndexes.push_back( maTokenStorage.size() );
+ return maTokenStorage.append( nOpCode );
+}
+
+Any& FormulaParserImpl::insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd )
+{
+ maTokenIndexes.insert( maTokenIndexes.end() - nIndexFromEnd, maTokenStorage.size() );
+ return maTokenStorage.append( nOpCode );
+}
+
+size_t FormulaParserImpl::appendWhiteSpaceTokens( const WhiteSpaceVec* pSpaces )
+{
+ if( pSpaces && !pSpaces->empty() )
+ for( WhiteSpaceVec::const_iterator aIt = pSpaces->begin(), aEnd = pSpaces->end(); aIt != aEnd; ++aIt )
+ appendRawToken( OPCODE_SPACES ) <<= aIt->first;
+ return pSpaces ? pSpaces->size() : 0;
+}
+
+size_t FormulaParserImpl::insertWhiteSpaceTokens( const WhiteSpaceVec* pSpaces, size_t nIndexFromEnd )
+{
+ if( pSpaces && !pSpaces->empty() )
+ for( WhiteSpaceVec::const_iterator aIt = pSpaces->begin(), aEnd = pSpaces->end(); aIt != aEnd; ++aIt )
+ insertRawToken( OPCODE_SPACES, nIndexFromEnd ) <<= aIt->first;
+ return pSpaces ? pSpaces->size() : 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, const WhiteSpaceVec* pSpaces )
+{
+ size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
+ appendRawToken( nOpCode );
+ pushOperandSize( nSpacesSize + 1 );
+ return true;
+}
+
+bool FormulaParserImpl::pushAnyOperandToken( const Any& rAny, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
+{
+ size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
+ appendRawToken( nOpCode ) = rAny;
+ pushOperandSize( nSpacesSize + 1 );
+ return true;
+}
+
+template< typename Type >
+bool FormulaParserImpl::pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
+{
+ size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
+ appendRawToken( nOpCode ) <<= rValue;
+ pushOperandSize( nSpacesSize + 1 );
+ return true;
+}
+
+bool FormulaParserImpl::pushParenthesesOperandToken( const WhiteSpaceVec* pOpeningSpaces, const WhiteSpaceVec* pClosingSpaces )
+{
+ size_t nSpacesSize = appendWhiteSpaceTokens( pOpeningSpaces );
+ appendRawToken( OPCODE_OPEN );
+ nSpacesSize += appendWhiteSpaceTokens( pClosingSpaces );
+ appendRawToken( OPCODE_CLOSE );
+ pushOperandSize( nSpacesSize + 2 );
+ return true;
+}
+
+bool FormulaParserImpl::pushUnaryPreOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
+{
+ bool bOk = maOperandSizeStack.size() >= 1;
+ if( bOk )
+ {
+ size_t nOpSize = popOperandSize();
+ size_t nSpacesSize = insertWhiteSpaceTokens( pSpaces, nOpSize );
+ insertRawToken( nOpCode, nOpSize );
+ pushOperandSize( nOpSize + nSpacesSize + 1 );
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushUnaryPostOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
+{
+ bool bOk = maOperandSizeStack.size() >= 1;
+ if( bOk )
+ {
+ size_t nOpSize = popOperandSize();
+ size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
+ appendRawToken( nOpCode );
+ pushOperandSize( nOpSize + nSpacesSize + 1 );
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushBinaryOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
+{
+ bool bOk = maOperandSizeStack.size() >= 2;
+ if( bOk )
+ {
+ size_t nOp2Size = popOperandSize();
+ size_t nOp1Size = popOperandSize();
+ size_t nSpacesSize = insertWhiteSpaceTokens( pSpaces, nOp2Size );
+ insertRawToken( nOpCode, nOp2Size );
+ pushOperandSize( nOp1Size + nSpacesSize + 1 + nOp2Size );
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushParenthesesOperatorToken( const WhiteSpaceVec* pOpeningSpaces, const WhiteSpaceVec* pClosingSpaces )
+{
+ bool bOk = maOperandSizeStack.size() >= 1;
+ if( bOk )
+ {
+ size_t nOpSize = popOperandSize();
+ size_t nSpacesSize = insertWhiteSpaceTokens( pOpeningSpaces, nOpSize );
+ insertRawToken( OPCODE_OPEN, nOpSize );
+ nSpacesSize += appendWhiteSpaceTokens( pClosingSpaces );
+ appendRawToken( OPCODE_CLOSE );
+ pushOperandSize( nOpSize + nSpacesSize + 2 );
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces, const WhiteSpaceVec* pClosingSpaces )
+{
+ /* #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( OPCODE_SEP );
+
+ // add function parentheses and function name
+ return bOk &&
+ ((nParamCount > 0) ? pushParenthesesOperatorToken( 0, pClosingSpaces ) : pushParenthesesOperandToken( 0, pClosingSpaces )) &&
+ pushUnaryPreOperatorToken( nOpCode, pLeadingSpaces );
+}
+
+bool FormulaParserImpl::pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces, const WhiteSpaceVec* pClosingSpaces )
+{
+ bool bOk = pushFunctionOperatorToken( rFuncInfo.mnApiOpCode, nParamCount, pLeadingSpaces, pClosingSpaces );
+ if( bOk )
+ {
+ // create an external add-in call for the passed built-in function
+ if( (rFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) && (rFuncInfo.maExtProgName.getLength() > 0) )
+ getOperandToken( 1, 0, 0 ).Data <<= rFuncInfo.maExtProgName;
+ // create a bad token with unsupported function name
+ else if( (rFuncInfo.mnApiOpCode == OPCODE_BAD) && (rFuncInfo.maOoxFuncName.getLength() > 0) )
+ getOperandToken( 1, 0, 0 ).Data <<= rFuncInfo.maOoxFuncName;
+ }
+ return bOk;
+}
+
+bool FormulaParserImpl::pushOperand( sal_Int32 nOpCode )
+{
+ return pushOperandToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushAnyOperand( const Any& rAny, sal_Int32 nOpCode )
+{
+ return pushAnyOperandToken( rAny, nOpCode, &maLeadingSpaces ) && resetSpaces();
+}
+
+template< typename Type >
+bool FormulaParserImpl::pushValueOperand( const Type& rValue, sal_Int32 nOpCode )
+{
+ return pushValueOperandToken( rValue, nOpCode, &maLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushBoolOperand( bool bValue )
+{
+ if( const FunctionInfo* pFuncInfo = 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( OPCODE_ARRAY_OPEN );
+ size_t nOpSize = popOperandSize();
+ size_t nOldArraySize = maTokenIndexes.size();
+ // push a double containing the Calc error code
+ appendRawToken( OPCODE_PUSH ) <<= fEncodedError;
+ // close token array and set resulting operand size
+ appendRawToken( OPCODE_ARRAY_CLOSE );
+ pushOperandSize( nOpSize + maTokenIndexes.size() - nOldArraySize );
+ return true;
+}
+
+bool FormulaParserImpl::pushBiffBoolOperand( sal_uInt8 nValue )
+{
+ return pushBoolOperand( nValue != BIFF_TOK_BOOL_FALSE );
+}
+
+bool FormulaParserImpl::pushBiffErrorOperand( sal_uInt8 nErrorCode )
+{
+ return pushErrorOperand( BiffHelper::calcDoubleFromError( nErrorCode ) );
+}
+
+bool FormulaParserImpl::pushParenthesesOperand()
+{
+ return pushParenthesesOperandToken( &maOpeningSpaces, &maClosingSpaces ) && 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 );
+}
+
+template< typename Type >
+bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const Type& rApiRef )
+{
+ if( rSheetRange.isExternal() )
+ {
+ ExternalReference aApiExtRef;
+ aApiExtRef.Index = rSheetRange.getDocLinkIndex();
+ aApiExtRef.Reference <<= rApiRef;
+ return pushValueOperand( aApiExtRef );
+ }
+ return pushValueOperand( rApiRef );
+}
+
+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 pushReferenceOperand( rSheetRange, aApiRef );
+ }
+ SingleReference aApiRef;
+ convertReference3d( aApiRef, rSheetRange.getFirstSheet(), rSheetRange.isSameSheet(), rRef, bDeleted, bRelativeAsOffset );
+ return pushReferenceOperand( rSheetRange, 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 pushReferenceOperand( rSheetRange, aApiRef );
+}
+
+bool FormulaParserImpl::pushNlrOperand( const BinSingleRef2d& rRef )
+{
+ SingleReference aApiRef;
+ convertReference2d( aApiRef, rRef, false, false );
+ return pushValueOperand( aApiRef, OPCODE_NLR );
+}
+
+bool FormulaParserImpl::pushEmbeddedRefOperand( const DefinedNameBase& rName, bool bPushBadToken )
+{
+ Any aRefAny = rName.getReference( mpContext->getBaseAddress() );
+ if( aRefAny.hasValue() )
+ return pushAnyOperand( aRefAny, OPCODE_PUSH );
+ if( bPushBadToken && (rName.getModelName().getLength() > 0) && (rName.getModelName()[ 0 ] >= ' ') )
+ return pushValueOperand( rName.getModelName(), OPCODE_BAD );
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool FormulaParserImpl::pushDefinedNameOperand( const DefinedNameRef& rxDefName )
+{
+ if( !rxDefName || (rxDefName->getModelName().getLength() == 0) )
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+ if( rxDefName->isMacroFunction() )
+ return pushValueOperand( rxDefName->getModelName(), OPCODE_MACRO );
+ if( rxDefName->getTokenIndex() >= 0 )
+ return pushValueOperand( rxDefName->getTokenIndex(), OPCODE_NAME );
+ return pushEmbeddedRefOperand( *rxDefName, true );
+}
+
+bool FormulaParserImpl::pushExternalFuncOperand( const FunctionInfo& rFuncInfo )
+{
+ return (rFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) ?
+ pushValueOperand( rFuncInfo.maExtProgName, OPCODE_EXTERNAL ) :
+ pushOperand( rFuncInfo.mnApiOpCode );
+}
+
+bool FormulaParserImpl::pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem )
+{
+ // create the function call DDE("server";"topic";"item")
+ return
+ pushValueOperandToken( rDdeServer ) &&
+ pushValueOperandToken( rDdeTopic ) &&
+ pushValueOperandToken( rDdeItem ) &&
+ pushFunctionOperator( OPCODE_DDE, 3 );
+}
+
+bool FormulaParserImpl::pushExternalNameOperand( const ExternalNameRef& rxExtName, const ExternalLink& rExtLink )
+{
+ if( rxExtName.get() ) switch( rExtLink.getLinkType() )
+ {
+ case LINKTYPE_INTERNAL:
+ case LINKTYPE_EXTERNAL:
+ return pushEmbeddedRefOperand( *rxExtName, false );
+
+ case LINKTYPE_ANALYSIS:
+ // TODO: need support for localized addin function names
+ if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( rxExtName->getUpcaseModelName() ) )
+ return pushExternalFuncOperand( *pFuncInfo );
+ break;
+
+ case LINKTYPE_LIBRARY:
+ if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( rxExtName->getUpcaseModelName() ) )
+ if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == rExtLink.getFuncLibraryType()) )
+ return pushExternalFuncOperand( *pFuncInfo );
+ break;
+
+ case LINKTYPE_DDE:
+ {
+ OUString aDdeServer, aDdeTopic, aDdeItem;
+ if( rxExtName->getDdeLinkData( aDdeServer, aDdeTopic, aDdeItem ) )
+ return pushDdeLinkOperand( aDdeServer, aDdeTopic, aDdeItem );
+ }
+ break;
+
+ default:
+ OSL_ENSURE( rExtLink.getLinkType() != LINKTYPE_SELF, "FormulaParserImpl::pushExternalNameOperand - invalid call" );
+ }
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool FormulaParserImpl::pushUnaryPreOperator( sal_Int32 nOpCode )
+{
+ return pushUnaryPreOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushUnaryPostOperator( sal_Int32 nOpCode )
+{
+ return pushUnaryPostOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushBinaryOperator( sal_Int32 nOpCode )
+{
+ return pushBinaryOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushParenthesesOperator()
+{
+ return pushParenthesesOperatorToken( &maOpeningSpaces, &maClosingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount )
+{
+ return pushFunctionOperatorToken( nOpCode, nParamCount, &maLeadingSpaces, &maClosingSpaces ) && resetSpaces();
+}
+
+bool FormulaParserImpl::pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount )
+{
+ return pushFunctionOperatorToken( rFuncInfo, nParamCount, &maLeadingSpaces, &maClosingSpaces ) && resetSpaces();
+}
+
+// reference conversion -------------------------------------------------------
+
+void FormulaParserImpl::initReference2d( SingleReference& orApiRef ) const
+{
+ if( mpContext->is2dRefsAs3dRefs() )
+ {
+ initReference3d( orApiRef, mpContext->getBaseAddress().Sheet, false );
+ }
+ 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, bool bSameSheet ) const
+{
+ orApiRef.Flags = SHEET_3D;
+ if( nSheet < 0 )
+ {
+ orApiRef.Sheet = 0;
+ orApiRef.Flags |= SHEET_DELETED;
+ }
+ else if( bSameSheet )
+ {
+ OSL_ENSURE( nSheet == 0, "FormulaParserImpl::initReference3d - invalid sheet index" );
+ orApiRef.Flags |= SHEET_RELATIVE;
+ orApiRef.RelativeSheet = 0;
+ }
+ 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, bool bSameSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
+{
+ initReference3d( orApiRef, nSheet, bSameSheet );
+ convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
+}
+
+void FormulaParserImpl::convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
+{
+ bool bSameSheet = rSheetRange.isSameSheet();
+ initReference3d( orApiRef.Reference1, rSheetRange.getFirstSheet(), bSameSheet );
+ initReference3d( orApiRef.Reference2, rSheetRange.getLastSheet(), bSameSheet );
+ 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 ----------------------------------------------------
+
+const FunctionInfo* FormulaParserImpl::resolveBadFuncName( const OUString& rTokenData ) const
+{
+ /* Try to parse calls to library functions. The format of such a function
+ call is "[n]!funcname", n>0 being the link identifier of the function
+ library spreadsheet file. */
+ sal_Int32 nBracketOpen = rTokenData.indexOf( '[' );
+ sal_Int32 nBracketClose = rTokenData.indexOf( ']' );
+ sal_Int32 nExclamation = rTokenData.indexOf( '!' );
+ if( (0 == nBracketOpen) && (nBracketOpen + 1 < nBracketClose) && (nBracketClose + 1 == nExclamation) && (nExclamation + 1 < rTokenData.getLength()) )
+ {
+ sal_Int32 nRefId = rTokenData.copy( nBracketOpen + 1, nBracketClose - nBracketOpen - 1 ).toInt32();
+ const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get();
+ if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_LIBRARY) )
+ {
+ OUString aFuncName = rTokenData.copy( nExclamation + 1 ).toAsciiUpperCase();
+ if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aFuncName ) )
+ if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == pExtLink->getFuncLibraryType()) )
+ return pFuncInfo;
+ }
+ }
+ return 0;
+}
+
+OUString FormulaParserImpl::resolveDefinedName( sal_Int32 nTokenIndex ) const
+{
+ if( const DefinedName* pDefName = getDefinedNames().getByTokenIndex( nTokenIndex ).get() )
+ return pDefName->getCalcName();
+ return OUString();
+}
+
+// OOX parser implementation ==================================================
+
+class OoxFormulaParserImpl : public FormulaParserImpl
+{
+public:
+ explicit OoxFormulaParserImpl( const FormulaParser& rParent );
+
+ 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:
+ ApiParserWrapper maApiParser; /// Wrapper for the API formula parser object.
+ sal_Int64 mnAddDataPos; /// Current stream position for additional data (tExp, tArray, tMemArea).
+ bool mbNeedExtRefs; /// True = parser needs initialization of external reference info.
+};
+
+// ----------------------------------------------------------------------------
+
+OoxFormulaParserImpl::OoxFormulaParserImpl( const FormulaParser& rParent ) :
+ FormulaParserImpl( rParent ),
+ maApiParser( rParent.getDocumentFactory(), rParent ),
+ mnAddDataPos( 0 ),
+ mbNeedExtRefs( true )
+{
+}
+
+void OoxFormulaParserImpl::importOoxFormula( FormulaContext& rContext, const OUString& rFormulaString )
+{
+ if( mbNeedExtRefs )
+ {
+ maApiParser.getParserProperties().setProperty( PROP_ExternalLinks, getExternalLinks().getLinkInfos() );
+ mbNeedExtRefs = false;
+ }
+ initializeImport( rContext );
+ finalizeImport( maApiParser.parseFormula( rFormulaString, rContext.getBaseAddress() ) );
+}
+
+void OoxFormulaParserImpl::importOobFormula( FormulaContext& rContext, RecordInputStream& rStrm )
+{
+ initializeImport( rContext );
+
+ sal_Int32 nFmlaSize = rStrm.readInt32();
+ sal_Int64 nFmlaPos = rStrm.tell();
+ sal_Int64 nFmlaEndPos = nFmlaPos + nFmlaSize;
+
+ rStrm.seek( nFmlaEndPos );
+ sal_Int32 nAddDataSize = rStrm.readInt32();
+ mnAddDataPos = rStrm.tell();
+ sal_Int64 nAddDataEndPos = mnAddDataPos + nAddDataSize;
+ rStrm.seek( nFmlaPos );
+
+ bool bOk = (nFmlaSize >= 0) && (nAddDataSize >= 0);
+ bool bRelativeAsOffset = getFormulaContext().isRelativeAsOffset();
+
+ while( bOk && !rStrm.isEof() && (rStrm.tell() < 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( OPCODE_ADD ); break;
+ case BIFF_TOKID_SUB: bOk = pushBinaryOperator( OPCODE_SUB ); break;
+ case BIFF_TOKID_MUL: bOk = pushBinaryOperator( OPCODE_MULT ); break;
+ case BIFF_TOKID_DIV: bOk = pushBinaryOperator( OPCODE_DIV ); break;
+ case BIFF_TOKID_POWER: bOk = pushBinaryOperator( OPCODE_POWER ); break;
+ case BIFF_TOKID_CONCAT: bOk = pushBinaryOperator( OPCODE_CONCAT ); break;
+ case BIFF_TOKID_LT: bOk = pushBinaryOperator( OPCODE_LESS ); break;
+ case BIFF_TOKID_LE: bOk = pushBinaryOperator( OPCODE_LESS_EQUAL ); break;
+ case BIFF_TOKID_EQ: bOk = pushBinaryOperator( OPCODE_EQUAL ); break;
+ case BIFF_TOKID_GE: bOk = pushBinaryOperator( OPCODE_GREATER_EQUAL ); break;
+ case BIFF_TOKID_GT: bOk = pushBinaryOperator( OPCODE_GREATER ); break;
+ case BIFF_TOKID_NE: bOk = pushBinaryOperator( OPCODE_NOT_EQUAL ); break;
+ case BIFF_TOKID_ISECT: bOk = pushBinaryOperator( OPCODE_INTERSECT ); break;
+ case BIFF_TOKID_LIST: bOk = pushBinaryOperator( OPCODE_LIST ); break;
+ case BIFF_TOKID_RANGE: bOk = pushBinaryOperator( OPCODE_RANGE ); break;
+ case BIFF_TOKID_UPLUS: bOk = pushUnaryPreOperator( OPCODE_PLUS_SIGN ); break;
+ case BIFF_TOKID_UMINUS: bOk = pushUnaryPreOperator( OPCODE_MINUS_SIGN ); break;
+ case BIFF_TOKID_PERCENT: bOk = pushUnaryPostOperator( OPCODE_PERCENT ); break;
+ case BIFF_TOKID_PAREN: bOk = pushParenthesesOperator(); break;
+ case BIFF_TOKID_MISSARG: bOk = pushOperand( 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 = pushBiffBoolOperand( rStrm.readuInt8() ); 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.tell() == 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 0: // sometimes, tAttrSkip tokens miss the type flag
+ 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:
+ appendLeadingSpaces( nCount, false );
+ break;
+ case BIFF_TOK_ATTR_SPACE_BR:
+ appendLeadingSpaces( nCount, true );
+ break;
+ case BIFF_TOK_ATTR_SPACE_SP_OPEN:
+ appendOpeningSpaces( nCount, false );
+ break;
+ case BIFF_TOK_ATTR_SPACE_BR_OPEN:
+ appendOpeningSpaces( nCount, true );
+ break;
+ case BIFF_TOK_ATTR_SPACE_SP_CLOSE:
+ appendClosingSpaces( nCount, false );
+ break;
+ case BIFF_TOK_ATTR_SPACE_BR_CLOSE:
+ appendClosingSpaces( nCount, true );
+ 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, OPCODE_DBAREA );
+ // create an OFFSET function call to refer to a subrange of the table
+ const FunctionInfo* pRowsInfo = getFuncInfoFromOobFuncId( OOBIN_FUNC_ROWS );
+ const FunctionInfo* pColumnsInfo = getFuncInfoFromOobFuncId( OOBIN_FUNC_COLUMNS );
+ return
+ pRowsInfo && pColumnsInfo &&
+ pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
+ (bFixedStartRow ?
+ pushValueOperandToken< double >( nStartRow ) :
+ (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
+ pushFunctionOperatorToken( *pRowsInfo, 1 ) &&
+ pushValueOperandToken< double >( nHeight - nStartRow ) &&
+ pushBinaryOperatorToken( OPCODE_SUB ))) &&
+ pushValueOperandToken< double >( nStartCol ) &&
+ (bFixedHeight ?
+ pushValueOperandToken< double >( nEndRow - nStartRow + 1 ) :
+ (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
+ pushFunctionOperatorToken( *pRowsInfo, 1 ) &&
+ (((nStartRow == 0) && (nEndRow + 1 == nHeight)) ||
+ (pushValueOperandToken< double >( nHeight - (nEndRow - nStartRow + 1) ) &&
+ pushBinaryOperatorToken( OPCODE_SUB ))))) &&
+ (((nStartCol == 0) && (nEndCol + 1 == nWidth)) ?
+ (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
+ pushFunctionOperatorToken( *pColumnsInfo, 1 )) :
+ pushValueOperandToken< double >( nEndCol - nStartCol + 1 )) &&
+ 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( 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.isEof() && (nRow < nRows); ++nRow )
+ {
+ if( nRow > 0 )
+ appendRawToken( OPCODE_ARRAY_ROWSEP );
+ for( sal_Int32 nCol = 0; !rStrm.isEof() && (nCol < nCols); ++nCol )
+ {
+ if( nCol > 0 )
+ appendRawToken( OPCODE_ARRAY_COLSEP );
+ switch( rStrm.readuInt8() )
+ {
+ case OOBIN_TOK_ARRAY_DOUBLE:
+ appendRawToken( OPCODE_PUSH ) <<= rStrm.readDouble();
+ break;
+ case OOBIN_TOK_ARRAY_STRING:
+ appendRawToken( OPCODE_PUSH ) <<= rStrm.readString( false );
+ break;
+ case OOBIN_TOK_ARRAY_BOOL:
+ appendRawToken( OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == BIFF_TOK_BOOL_FALSE) ? 0.0 : 1.0 );
+ break;
+ case OOBIN_TOK_ARRAY_ERROR:
+ appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
+ rStrm.skip( 3 );
+ break;
+ default:
+ OSL_ENSURE( false, "OoxFormulaParserImpl::importArrayToken - unknown data type" );
+ appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
+ }
+ }
+ }
+ swapStreamPosition( rStrm );
+
+ // close token array and set resulting operand size
+ appendRawToken( 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_Int64 nRecPos = rStrm.tell();
+ 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 );
+ }
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool OoxFormulaParserImpl::pushOobFunction( sal_uInt16 nFuncId )
+{
+ if( const FunctionInfo* pFuncInfo = getFuncInfoFromOobFuncId( nFuncId ) )
+ if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
+ return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
+ return pushFunctionOperator( 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 = getFuncInfoFromOobFuncId( nFuncId ) )
+ return pushFunctionOperator( *pFuncInfo, nParamCount );
+ return pushFunctionOperator( 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 FormulaParser& rParent );
+
+ 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_Int64 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 FormulaParser& rParent ) :
+ FormulaParserImpl( rParent ),
+ 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 = lclReadFmlaSize( rStrm, getBiff(), pnFmlaSize );
+ sal_Int64 nEndPos = mnAddDataPos = rStrm.tell() + nFmlaSize;
+ bool bRelativeAsOffset = getFormulaContext().isRelativeAsOffset();
+
+ bool bOk = true;
+ while( bOk && !rStrm.isEof() && (rStrm.tell() < nEndPos) )
+ {
+ sal_uInt8 nTokenId;
+ rStrm >> nTokenId;
+ sal_uInt8 nTokenClass = nTokenId & BIFF_TOKCLASS_MASK;
+ sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
+
+ bOk = !getFlag( nTokenId, BIFF_TOKFLAG_INVALID );
+ if( bOk )
+ {
+ 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( OPCODE_ADD ); break;
+ case BIFF_TOKID_SUB: bOk = pushBinaryOperator( OPCODE_SUB ); break;
+ case BIFF_TOKID_MUL: bOk = pushBinaryOperator( OPCODE_MULT ); break;
+ case BIFF_TOKID_DIV: bOk = pushBinaryOperator( OPCODE_DIV ); break;
+ case BIFF_TOKID_POWER: bOk = pushBinaryOperator( OPCODE_POWER ); break;
+ case BIFF_TOKID_CONCAT: bOk = pushBinaryOperator( OPCODE_CONCAT ); break;
+ case BIFF_TOKID_LT: bOk = pushBinaryOperator( OPCODE_LESS ); break;
+ case BIFF_TOKID_LE: bOk = pushBinaryOperator( OPCODE_LESS_EQUAL ); break;
+ case BIFF_TOKID_EQ: bOk = pushBinaryOperator( OPCODE_EQUAL ); break;
+ case BIFF_TOKID_GE: bOk = pushBinaryOperator( OPCODE_GREATER_EQUAL ); break;
+ case BIFF_TOKID_GT: bOk = pushBinaryOperator( OPCODE_GREATER ); break;
+ case BIFF_TOKID_NE: bOk = pushBinaryOperator( OPCODE_NOT_EQUAL ); break;
+ case BIFF_TOKID_ISECT: bOk = pushBinaryOperator( OPCODE_INTERSECT ); break;
+ case BIFF_TOKID_LIST: bOk = pushBinaryOperator( OPCODE_LIST ); break;
+ case BIFF_TOKID_RANGE: bOk = pushBinaryOperator( OPCODE_RANGE ); break;
+ case BIFF_TOKID_UPLUS: bOk = pushUnaryPreOperator( OPCODE_PLUS_SIGN ); break;
+ case BIFF_TOKID_UMINUS: bOk = pushUnaryPreOperator( OPCODE_MINUS_SIGN ); break;
+ case BIFF_TOKID_PERCENT: bOk = pushUnaryPostOperator( OPCODE_PERCENT ); break;
+ case BIFF_TOKID_PAREN: bOk = pushParenthesesOperator(); break;
+ case BIFF_TOKID_MISSARG: bOk = pushOperand( 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 = pushBiffBoolOperand( rStrm.readuInt8() ); 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.tell() == 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.readByteStringUC( false, getTextEncoding(), getFormulaContext().isNulCharsAllowed() ) );
+}
+
+bool BiffFormulaParserImpl::importStrToken8( BiffInputStream& rStrm )
+{
+ // read flags field for empty strings also
+ return pushValueOperand( rStrm.readUniStringBody( rStrm.readuInt8(), getFormulaContext().isNulCharsAllowed() ) );
+}
+
+bool BiffFormulaParserImpl::importAttrToken( BiffInputStream& rStrm )
+{
+ bool bOk = true;
+ sal_uInt8 nType;
+ rStrm >> nType;
+ switch( nType )
+ {
+ case 0: // sometimes, tAttrSkip tokens miss the type flag
+ 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:
+ appendLeadingSpaces( nCount, false );
+ break;
+ case BIFF_TOK_ATTR_SPACE_BR:
+ appendLeadingSpaces( nCount, true );
+ break;
+ case BIFF_TOK_ATTR_SPACE_SP_OPEN:
+ appendOpeningSpaces( nCount, false );
+ break;
+ case BIFF_TOK_ATTR_SPACE_BR_OPEN:
+ appendOpeningSpaces( nCount, true );
+ break;
+ case BIFF_TOK_ATTR_SPACE_SP_CLOSE:
+ appendClosingSpaces( nCount, false );
+ break;
+ case BIFF_TOK_ATTR_SPACE_BR_CLOSE:
+ appendClosingSpaces( nCount, true );
+ 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( OPCODE_ARRAY_OPEN );
+ size_t nOpSize = popOperandSize();
+ size_t nOldArraySize = getFormulaSize();
+ bool bBiff8 = getBiff() == BIFF8;
+ bool bNulChars = getFormulaContext().isNulCharsAllowed();
+
+ // 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.isEof() && (nRow < nRows); ++nRow )
+ {
+ if( nRow > 0 )
+ appendRawToken( OPCODE_ARRAY_ROWSEP );
+ for( sal_uInt16 nCol = 0; !rStrm.isEof() && (nCol < nCols); ++nCol )
+ {
+ if( nCol > 0 )
+ appendRawToken( OPCODE_ARRAY_COLSEP );
+ switch( rStrm.readuInt8() )
+ {
+ case BIFF_DATATYPE_EMPTY:
+ appendRawToken( OPCODE_PUSH ) <<= OUString();
+ rStrm.skip( 8 );
+ break;
+ case BIFF_DATATYPE_DOUBLE:
+ appendRawToken( OPCODE_PUSH ) <<= rStrm.readDouble();
+ break;
+ case BIFF_DATATYPE_STRING:
+ appendRawToken( OPCODE_PUSH ) <<= bBiff8 ?
+ rStrm.readUniString( bNulChars ) :
+ rStrm.readByteStringUC( false, getTextEncoding(), bNulChars );
+ break;
+ case BIFF_DATATYPE_BOOL:
+ appendRawToken( OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == BIFF_TOK_BOOL_FALSE) ? 0.0 : 1.0 );
+ rStrm.skip( 7 );
+ break;
+ case BIFF_DATATYPE_ERROR:
+ appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
+ rStrm.skip( 7 );
+ break;
+ default:
+ OSL_ENSURE( false, "BiffFormulaParserImpl::importArrayToken - unknown data type" );
+ appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
+ }
+ }
+ }
+ swapStreamPosition( rStrm );
+
+ // close token array and set resulting operand size
+ appendRawToken( 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_Int64 nRecPos = rStrm.tell();
+ rStrm.seek( mnAddDataPos );
+ mnAddDataPos = nRecPos;
+}
+
+void BiffFormulaParserImpl::skipMemAreaAddData( BiffInputStream& rStrm )
+{
+ swapStreamPosition( rStrm );
+ sal_Int32 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_Int64 nEndPos = rStrm.tell() + 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.isEof() && 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 );
+ }
+ return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool BiffFormulaParserImpl::pushBiffFunction( sal_uInt16 nFuncId )
+{
+ if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiffFuncId( nFuncId ) )
+ if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
+ return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
+ return pushFunctionOperator( 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 = getFuncInfoFromBiffFuncId( nFuncId ) )
+ return pushFunctionOperator( *pFuncInfo, nParamCount );
+ return pushFunctionOperator( OPCODE_NONAME, nParamCount );
+}
+
+// ============================================================================
+
+FormulaParser::FormulaParser( const WorkbookHelper& rHelper ) :
+ FormulaProcessorBase( rHelper )
+{
+ switch( getFilterType() )
+ {
+ case FILTER_OOX: mxImpl.reset( new OoxFormulaParserImpl( *this ) ); break;
+ case FILTER_BIFF: mxImpl.reset( new BiffFormulaParserImpl( *this ) ); 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 = OPCODE_ARRAY_OPEN;
+ aTokens[ 1 ].OpCode = OPCODE_PUSH;
+ aTokens[ 1 ].Data <<= BiffHelper::calcDoubleFromError( nErrorCode );
+ aTokens[ 2 ].OpCode = 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 = OPCODE_NAME;
+ aTokens[ 0 ].Data <<= nTokenIndex;
+ mxImpl->setFormula( rContext, aTokens );
+ }
+ else
+ convertErrorToFormula( rContext, BIFF_ERR_REF );
+}
+
+void FormulaParser::convertNumberToHyperlink( FormulaContext& rContext, const OUString& rUrl, double fValue ) const
+{
+ OSL_ENSURE( rUrl.getLength() > 0, "FormulaParser::convertNumberToHyperlink - missing URL" );
+ if( const FunctionInfo* pFuncInfo = getFuncInfoFromOobFuncId( OOBIN_FUNC_HYPERLINK ) )
+ {
+ ApiTokenSequence aTokens( 6 );
+ aTokens[ 0 ].OpCode = pFuncInfo->mnApiOpCode;
+ aTokens[ 1 ].OpCode = OPCODE_OPEN;
+ aTokens[ 2 ].OpCode = OPCODE_PUSH;
+ aTokens[ 2 ].Data <<= rUrl;
+ aTokens[ 3 ].OpCode = OPCODE_SEP;
+ aTokens[ 4 ].OpCode = OPCODE_PUSH;
+ aTokens[ 4 ].Data <<= fValue;
+ aTokens[ 5 ].OpCode = OPCODE_CLOSE;
+ mxImpl->setFormula( rContext, aTokens );
+ }
+}
+
+OUString FormulaParser::importOleTargetLink( const OUString& rFormulaString )
+{
+ // obviously, this would overburden our formula parser, so we parse it manually
+ OUString aTargetLink;
+ sal_Int32 nFmlaLen = rFormulaString.getLength();
+ if( (nFmlaLen >= 8) && (rFormulaString[ 0 ] == '[') )
+ {
+ // passed string is trimmed already
+ sal_Int32 nBracketClose = rFormulaString.indexOf( ']' );
+ sal_Int32 nExclamation = rFormulaString.indexOf( '!' );
+ if( (nBracketClose >= 2) &&
+ (nBracketClose + 1 == nExclamation) &&
+ (rFormulaString[ nExclamation + 1 ] == '\'') &&
+ (rFormulaString[ nFmlaLen - 1 ] == '\'') )
+ {
+ sal_Int32 nRefId = rFormulaString.copy( 1, nBracketClose - 1 ).toInt32();
+ aTargetLink = mxImpl->resolveOleTarget( nRefId );
+ }
+ }
+ return aTargetLink;
+}
+
+OUString FormulaParser::importOleTargetLink( RecordInputStream& rStrm )
+{
+ OUString aTargetLink;
+ sal_Int32 nFmlaSize = rStrm.readInt32();
+ sal_Int64 nFmlaEndPos = rStrm.tell() + ::std::max< sal_Int32 >( nFmlaSize, 0 );
+ if( (nFmlaSize == 7) && (rStrm.getRemaining() >= 7) )
+ {
+ sal_uInt8 nToken;
+ sal_Int16 nRefId;
+ sal_Int32 nNameId;
+ rStrm >> nToken >> nRefId >> nNameId;
+ if( nToken == (BIFF_TOKCLASS_VAL|BIFF_TOKID_NAMEX) )
+ aTargetLink = mxImpl->resolveOleTarget( nRefId );
+ }
+ rStrm.seek( nFmlaEndPos );
+ return aTargetLink;
+}
+
+OUString FormulaParser::importOleTargetLink( BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) const
+{
+ OUString aTargetLink;
+ sal_uInt16 nFmlaSize = lclReadFmlaSize( rStrm, getBiff(), pnFmlaSize );
+ rStrm.skip( nFmlaSize );
+ return aTargetLink;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/makefile.mk b/oox/source/xls/makefile.mk
new file mode 100644
index 000000000000..cdb2e18c262d
--- /dev/null
+++ b/oox/source/xls/makefile.mk
@@ -0,0 +1,100 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+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)$/biffhelper.obj \
+ $(SLO)$/biffinputstream.obj \
+ $(SLO)$/biffoutputstream.obj \
+ $(SLO)$/chartsheetfragment.obj \
+ $(SLO)$/commentsbuffer.obj \
+ $(SLO)$/commentsfragment.obj \
+ $(SLO)$/condformatbuffer.obj \
+ $(SLO)$/condformatcontext.obj \
+ $(SLO)$/connectionsfragment.obj \
+ $(SLO)$/defnamesbuffer.obj \
+ $(SLO)$/drawingfragment.obj \
+ $(SLO)$/excelchartconverter.obj \
+ $(SLO)$/excelfilter.obj \
+ $(SLO)$/excelhandlers.obj \
+ $(SLO)$/externallinkbuffer.obj \
+ $(SLO)$/externallinkfragment.obj \
+ $(SLO)$/formulabase.obj \
+ $(SLO)$/formulaparser.obj \
+ $(SLO)$/numberformatsbuffer.obj \
+ $(SLO)$/ooxformulaparser.obj \
+ $(SLO)$/pagesettings.obj \
+ $(SLO)$/pivotcachebuffer.obj \
+ $(SLO)$/pivotcachefragment.obj \
+ $(SLO)$/pivottablebuffer.obj \
+ $(SLO)$/pivottablefragment.obj \
+ $(SLO)$/querytablefragment.obj \
+ $(SLO)$/richstring.obj \
+ $(SLO)$/richstringcontext.obj \
+ $(SLO)$/scenariobuffer.obj \
+ $(SLO)$/scenariocontext.obj \
+ $(SLO)$/sharedformulabuffer.obj \
+ $(SLO)$/sharedstringsbuffer.obj \
+ $(SLO)$/sharedstringsfragment.obj \
+ $(SLO)$/sheetdatacontext.obj \
+ $(SLO)$/stylesbuffer.obj \
+ $(SLO)$/stylesfragment.obj \
+ $(SLO)$/tablebuffer.obj \
+ $(SLO)$/tablefragment.obj \
+ $(SLO)$/themebuffer.obj \
+ $(SLO)$/unitconverter.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..d7a055469b48
--- /dev/null
+++ b/oox/source/xls/numberformatsbuffer.cxx
@@ -0,0 +1,2125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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 "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertymap.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 ::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
+};
+
+} // namespace
+
+// ============================================================================
+
+NumFmtModel::NumFmtModel() :
+ mnPredefId( -1 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ApiNumFmtData::ApiNumFmtData() :
+ mnIndex( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+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;
+}
+
+// ----------------------------------------------------------------------------
+
+/** Functor for converting an XML number format to an API number format index. */
+class NumberFormatFinalizer
+{
+public:
+ explicit NumberFormatFinalizer( 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;
+};
+
+NumberFormatFinalizer::NumberFormatFinalizer( 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(), "NumberFormatFinalizer::NumberFormatFinalizer - cannot get number formats" );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+NumberFormat::NumberFormat( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void NumberFormat::setFormatCode( const OUString& rFmtCode )
+{
+ maModel.maFmtCode = rFmtCode;
+}
+
+void NumberFormat::setFormatCode( const Locale& rLocale, const sal_Char* pcFmtCode )
+{
+ maModel.maLocale = rLocale;
+ maModel.maFmtCode = OStringToOUString( OString( pcFmtCode ), RTL_TEXTENCODING_UTF8 );
+ maModel.mnPredefId = -1;
+}
+
+void NumberFormat::setPredefinedId( const Locale& rLocale, sal_Int16 nPredefId )
+{
+ maModel.maLocale = rLocale;
+ maModel.maFmtCode = OUString();
+ maModel.mnPredefId = nPredefId;
+}
+
+sal_Int32 NumberFormat::finalizeImport( const Reference< XNumberFormats >& rxNumFmts, const Locale& rFromLocale )
+{
+ if( rxNumFmts.is() && (maModel.maFmtCode.getLength() > 0) )
+ maApiData.mnIndex = lclCreateFormat( rxNumFmts, maModel.maFmtCode, maModel.maLocale, rFromLocale );
+ else
+ maApiData.mnIndex = lclCreatePredefinedFormat( rxNumFmts, maModel.mnPredefId, maModel.maLocale );
+ return maApiData.mnIndex;
+}
+
+void NumberFormat::writeToPropertyMap( PropertyMap& rPropMap ) const
+{
+ rPropMap[ PROP_NumberFormat ] <<= maApiData.mnIndex;
+}
+
+// ============================================================================
+
+NumberFormatsBuffer::NumberFormatsBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mnNextBiffIndex( 0 )
+{
+ // get the current locale
+ try
+ {
+ Reference< XMultiServiceFactory > xConfigProv( getGlobalFactory()->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.getXString( XML_formatCode, OUString() );
+ 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.readByteStringUC( false, getTextEncoding() );
+ break;
+ case BIFF4:
+ rStrm.skip( 2 ); // in BIFF4 the index field exists, but is undefined
+ aFmtCode = rStrm.readByteStringUC( false, getTextEncoding() );
+ break;
+ case BIFF5:
+ mnNextBiffIndex = rStrm.readuInt16();
+ aFmtCode = rStrm.readByteStringUC( 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( NumberFormatFinalizer( *this ) );
+}
+
+void NumberFormatsBuffer::writeToPropertyMap( PropertyMap& rPropMap, sal_Int32 nNumFmtId ) const
+{
+ if( const NumberFormat* pNumFmt = maNumFmts.get( nNumFmtId ).get() )
+ pNumFmt->writeToPropertyMap( rPropMap );
+}
+
+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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/ooxformulaparser.cxx b/oox/source/xls/ooxformulaparser.cxx
new file mode 100644
index 000000000000..dea7bcb2c161
--- /dev/null
+++ b/oox/source/xls/ooxformulaparser.cxx
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/ooxformulaparser.hxx"
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include "oox/xls/formulaparser.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::XComponentContext;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::sheet::FormulaToken;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+class OOXMLFormulaParserImpl : private FormulaFinalizer
+{
+public:
+ explicit OOXMLFormulaParserImpl( const Reference< XMultiServiceFactory >& rxFactory );
+
+ Sequence< FormulaToken > parseFormula( const OUString& rFormula, const CellAddress& rReferencePos );
+
+protected:
+ virtual const FunctionInfo* resolveBadFuncName( const OUString& rTokenData ) const;
+
+private:
+ ApiParserWrapper maApiParser;
+};
+
+// ----------------------------------------------------------------------------
+
+OOXMLFormulaParserImpl::OOXMLFormulaParserImpl( const Reference< XMultiServiceFactory >& rxFactory ) :
+ FormulaFinalizer( OpCodeProvider( rxFactory, FILTER_OOX, BIFF_UNKNOWN, true ) ),
+ maApiParser( rxFactory, *this )
+{
+}
+
+Sequence< FormulaToken > OOXMLFormulaParserImpl::parseFormula( const OUString& rFormula, const CellAddress& rReferencePos )
+{
+ return finalizeTokenArray( maApiParser.parseFormula( rFormula, rReferencePos ) );
+}
+
+const FunctionInfo* OOXMLFormulaParserImpl::resolveBadFuncName( const OUString& rTokenData ) const
+{
+ /* Try to parse calls to library functions. The format of such a function
+ call is assumed to be
+ "'<path-to-office-install>\Library\<libname>'!<funcname>". */
+
+ // the string has to start with an apostroph (followed by the library URL)
+ if( (rTokenData.getLength() >= 6) && (rTokenData[ 0 ] == '\'') )
+ {
+ // library URL and function name are separated by an exclamation mark
+ sal_Int32 nExclamPos = rTokenData.lastIndexOf( '!' );
+ if( (1 < nExclamPos) && (nExclamPos + 1 < rTokenData.getLength()) && (rTokenData[ nExclamPos - 1 ] == '\'') )
+ {
+ // find the last backslash that separates library path and name
+ sal_Int32 nFileSep = rTokenData.lastIndexOf( '\\', nExclamPos - 2 );
+ if( nFileSep > 1 )
+ {
+ // find preceding backslash that separates the last directory name
+ sal_Int32 nDirSep = rTokenData.lastIndexOf( '\\', nFileSep - 1 );
+ // function library is located in a directory called 'library'
+ if( (nDirSep > 0) && rTokenData.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "\\LIBRARY\\" ), nDirSep ) )
+ {
+ // try to find a function info for the function name
+ OUString aFuncName = rTokenData.copy( nExclamPos + 1 ).toAsciiUpperCase();
+ const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aFuncName );
+ if( pFuncInfo && (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) )
+ {
+ // check that the name of the library matches
+ OUString aLibName = rTokenData.copy( nFileSep + 1, nExclamPos - nFileSep - 2 );
+ if( pFuncInfo->meFuncLibType == getFuncLibTypeFromLibraryName( aLibName ) )
+ return pFuncInfo;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+// ============================================================================
+
+class OOXMLFormulaPrinterImpl : public OpCodeProvider
+{
+public:
+ explicit OOXMLFormulaPrinterImpl( const Reference< XMultiServiceFactory >& rxFactory );
+
+private:
+ ApiParserWrapper maApiParser;
+};
+
+// ----------------------------------------------------------------------------
+
+OOXMLFormulaPrinterImpl::OOXMLFormulaPrinterImpl( const Reference< XMultiServiceFactory >& rxFactory ) :
+ OpCodeProvider( rxFactory, FILTER_OOX, BIFF_UNKNOWN, false ),
+ maApiParser( rxFactory, *this )
+{
+}
+
+// ============================================================================
+
+Sequence< OUString > OOXMLFormulaParser_getSupportedServiceNames()
+{
+ Sequence< OUString > aServiceNames( 1 );
+ aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.sheet.FilterFormulaParser" );
+ return aServiceNames;
+}
+
+OUString OOXMLFormulaParser_getImplementationName()
+{
+ return CREATE_OUSTRING( "com.sun.star.comp.oox.OOXMLFormulaParser" );
+}
+
+Reference< XInterface > SAL_CALL OOXMLFormulaParser_createInstance( const Reference< XComponentContext >& ) throw( Exception )
+{
+ return static_cast< ::cppu::OWeakObject* >( new OOXMLFormulaParser );
+}
+
+// ============================================================================
+
+OOXMLFormulaParser::OOXMLFormulaParser()
+{
+}
+
+OOXMLFormulaParser::~OOXMLFormulaParser()
+{
+}
+
+// com.sun.star.lang.XServiceInfo interface -----------------------------------
+
+OUString SAL_CALL OOXMLFormulaParser::getImplementationName() throw( RuntimeException )
+{
+ return OOXMLFormulaParser_getImplementationName();
+}
+
+sal_Bool SAL_CALL OOXMLFormulaParser::supportsService( const OUString& rService ) throw( RuntimeException )
+{
+ const Sequence< OUString > aServices( OOXMLFormulaParser_getSupportedServiceNames() );
+ const OUString* pArray = aServices.getConstArray();
+ const OUString* pArrayEnd = pArray + aServices.getLength();
+ return ::std::find( pArray, pArrayEnd, rService ) != pArrayEnd;
+}
+
+Sequence< OUString > SAL_CALL OOXMLFormulaParser::getSupportedServiceNames() throw( RuntimeException )
+{
+ return OOXMLFormulaParser_getSupportedServiceNames();
+}
+
+// com.sun.star.lang.XInitialization interface --------------------------------
+
+void SAL_CALL OOXMLFormulaParser::initialize( const Sequence< Any >& rArgs ) throw( Exception, RuntimeException )
+{
+ OSL_ENSURE( rArgs.hasElements(), "OOXMLFormulaParser::initialize - missing arguments" );
+ if( !rArgs.hasElements() )
+ throw RuntimeException();
+ mxComponent.set( rArgs[ 0 ], UNO_QUERY_THROW );
+}
+
+// com.sun.star.sheet.XFilterFormulaParser interface --------------------------
+
+OUString SAL_CALL OOXMLFormulaParser::getSupportedNamespace() throw( RuntimeException )
+{
+ return CREATE_OUSTRING( "http://schemas.microsoft.com/office/excel/formula" );
+}
+
+// com.sun.star.sheet.XFormulaParser interface --------------------------------
+
+Sequence< FormulaToken > SAL_CALL OOXMLFormulaParser::parseFormula(
+ const OUString& rFormula, const CellAddress& rReferencePos ) throw( RuntimeException )
+{
+ if( !mxParserImpl )
+ {
+ Reference< XMultiServiceFactory > xFactory( mxComponent, UNO_QUERY_THROW );
+ mxParserImpl.reset( new OOXMLFormulaParserImpl( xFactory ) );
+ }
+ return mxParserImpl->parseFormula( rFormula, rReferencePos );
+}
+
+OUString SAL_CALL OOXMLFormulaParser::printFormula(
+ const Sequence< FormulaToken >& /*rTokens*/, const CellAddress& /*rReferencePos*/ ) throw( RuntimeException )
+{
+ // not implemented
+ throw RuntimeException();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/pagesettings.cxx b/oox/source/xls/pagesettings.cxx
new file mode 100644
index 000000000000..907cdf2a384d
--- /dev/null
+++ b/oox/source/xls/pagesettings.cxx
@@ -0,0 +1,1287 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/pagesettings.hxx"
+#include <set>
+#include <algorithm>
+#include <rtl/strbuf.hxx>
+#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 <com/sun/star/style/GraphicLocation.hpp>
+#include <com/sun/star/text/FilenameDisplayFormat.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/graphichelper.hxx"
+#include "oox/helper/propertymap.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/xmlfilterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/excelhandlers.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+#include "tools/mapunit.hxx"
+#include "xmloff/xmluconv.hxx"
+
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+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 ::com::sun::star::container::XNamed;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::awt::Size;
+using ::com::sun::star::sheet::XHeaderFooterContent;
+using ::com::sun::star::style::XStyle;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::text::XTextCursor;
+using ::com::sun::star::text::XTextContent;
+using ::com::sun::star::text::XTextRange;
+using ::oox::core::Relations;
+
+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_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 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_CHARTPAGESETUP_LANDSCAPE = 0x0001;
+const sal_uInt16 OOBIN_CHARTPAGESETUP_INVALID = 0x0002;
+const sal_uInt16 OOBIN_CHARTPAGESETUP_BLACKWHITE = 0x0004;
+const sal_uInt16 OOBIN_CHARTPAGESETUP_DEFAULTORIENT = 0x0008;
+const sal_uInt16 OOBIN_CHARTPAGESETUP_USEFIRSTPAGE = 0x0010;
+const sal_uInt16 OOBIN_CHARTPAGESETUP_DRAFTQUALITY = 0x0020;
+
+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
+
+// ============================================================================
+
+PageSettingsModel::PageSettingsModel() :
+ 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 ),
+ mnPaperWidth( 0 ),
+ mnPaperHeight( 0 ),
+ 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 PageSettingsModel::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::importPrintOptions( const AttributeList& rAttribs )
+{
+ maModel.mbHorCenter = rAttribs.getBool( XML_horizontalCentered, false );
+ maModel.mbVerCenter = rAttribs.getBool( XML_verticalCentered, false );
+ maModel.mbPrintGrid = rAttribs.getBool( XML_gridLines, false );
+ maModel.mbPrintHeadings = rAttribs.getBool( XML_headings, false );
+}
+
+void PageSettings::importPageMargins( const AttributeList& rAttribs )
+{
+ maModel.mfLeftMargin = rAttribs.getDouble( XML_left, OOX_MARGIN_DEFAULT_LR );
+ maModel.mfRightMargin = rAttribs.getDouble( XML_right, OOX_MARGIN_DEFAULT_LR );
+ maModel.mfTopMargin = rAttribs.getDouble( XML_top, OOX_MARGIN_DEFAULT_TB );
+ maModel.mfBottomMargin = rAttribs.getDouble( XML_bottom, OOX_MARGIN_DEFAULT_TB );
+ maModel.mfHeaderMargin = rAttribs.getDouble( XML_header, OOX_MARGIN_DEFAULT_HF );
+ maModel.mfFooterMargin = rAttribs.getDouble( XML_footer, OOX_MARGIN_DEFAULT_HF );
+}
+
+void PageSettings::importPageSetup( const Relations& rRelations, const AttributeList& rAttribs )
+{
+ OUString aStr;
+ maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ maModel.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 );
+ aStr = rAttribs.getString ( XML_paperWidth, OUString() );
+ SvXMLUnitConverter::convertMeasure( maModel.mnPaperWidth, aStr, MAP_100TH_MM );
+ aStr = rAttribs.getString ( XML_paperHeight, OUString() );
+ SvXMLUnitConverter::convertMeasure( maModel.mnPaperHeight, aStr, MAP_100TH_MM );
+ maModel.mnCopies = rAttribs.getInteger( XML_copies, 1 );
+ maModel.mnScale = rAttribs.getInteger( XML_scale, 100 );
+ maModel.mnFirstPage = rAttribs.getInteger( XML_firstPageNumber, 1 );
+ maModel.mnFitToWidth = rAttribs.getInteger( XML_fitToWidth, 1 );
+ maModel.mnFitToHeight = rAttribs.getInteger( XML_fitToHeight, 1 );
+ maModel.mnHorPrintRes = rAttribs.getInteger( XML_horizontalDpi, 600 );
+ maModel.mnVerPrintRes = rAttribs.getInteger( XML_verticalDpi, 600 );
+ maModel.mnOrientation = rAttribs.getToken( XML_orientation, XML_default );
+ maModel.mnPageOrder = rAttribs.getToken( XML_pageOrder, XML_downThenOver );
+ maModel.mnCellComments = rAttribs.getToken( XML_cellComments, XML_none );
+ maModel.mnPrintErrors = rAttribs.getToken( XML_errors, XML_displayed );
+ maModel.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, true );
+ maModel.mbUseFirstPage = rAttribs.getBool( XML_useFirstPageNumber, false );
+ maModel.mbBlackWhite = rAttribs.getBool( XML_blackAndWhite, false );
+ maModel.mbDraftQuality = rAttribs.getBool( XML_draft, false );
+}
+
+void PageSettings::importChartPageSetup( const Relations& rRelations, const AttributeList& rAttribs )
+{
+ OUString aStr;
+ maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ maModel.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 );
+ aStr = rAttribs.getString ( XML_paperWidth, OUString() );
+ SvXMLUnitConverter::convertMeasure( maModel.mnPaperWidth, aStr, MAP_100TH_MM );
+ aStr = rAttribs.getString ( XML_paperHeight, OUString() );
+ SvXMLUnitConverter::convertMeasure( maModel.mnPaperHeight, aStr, MAP_100TH_MM );
+ maModel.mnCopies = rAttribs.getInteger( XML_copies, 1 );
+ maModel.mnFirstPage = rAttribs.getInteger( XML_firstPageNumber, 1 );
+ maModel.mnHorPrintRes = rAttribs.getInteger( XML_horizontalDpi, 600 );
+ maModel.mnVerPrintRes = rAttribs.getInteger( XML_verticalDpi, 600 );
+ maModel.mnOrientation = rAttribs.getToken( XML_orientation, XML_default );
+ maModel.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, true );
+ maModel.mbUseFirstPage = rAttribs.getBool( XML_useFirstPageNumber, false );
+ maModel.mbBlackWhite = rAttribs.getBool( XML_blackAndWhite, false );
+ maModel.mbDraftQuality = rAttribs.getBool( XML_draft, false );
+}
+
+void PageSettings::importHeaderFooter( const AttributeList& rAttribs )
+{
+ maModel.mbUseEvenHF = rAttribs.getBool( XML_differentOddEven, false );
+ maModel.mbUseFirstHF = rAttribs.getBool( XML_differentFirst, false );
+}
+
+void PageSettings::importHeaderFooterCharacters( const OUString& rChars, sal_Int32 nElement )
+{
+ switch( nElement )
+ {
+ case XLS_TOKEN( oddHeader ): maModel.maOddHeader += rChars; break;
+ case XLS_TOKEN( oddFooter ): maModel.maOddFooter += rChars; break;
+ case XLS_TOKEN( evenHeader ): maModel.maEvenHeader += rChars; break;
+ case XLS_TOKEN( evenFooter ): maModel.maEvenFooter += rChars; break;
+ case XLS_TOKEN( firstHeader ): maModel.maFirstHeader += rChars; break;
+ case XLS_TOKEN( firstFooter ): maModel.maFirstFooter += rChars; break;
+ }
+}
+
+void PageSettings::importPicture( const Relations& rRelations, const AttributeList& rAttribs )
+{
+ importPictureData( rRelations, rAttribs.getString( R_TOKEN( id ), OUString() ) );
+}
+
+void PageSettings::importPageMargins( RecordInputStream& rStrm )
+{
+ rStrm >> maModel.mfLeftMargin >> maModel.mfRightMargin
+ >> maModel.mfTopMargin >> maModel.mfBottomMargin
+ >> maModel.mfHeaderMargin >> maModel.mfFooterMargin;
+}
+
+void PageSettings::importPrintOptions( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ maModel.mbHorCenter = getFlag( nFlags, OOBIN_PRINTOPT_HORCENTER );
+ maModel.mbVerCenter = getFlag( nFlags, OOBIN_PRINTOPT_VERCENTER );
+ maModel.mbPrintGrid = getFlag( nFlags, OOBIN_PRINTOPT_PRINTGRID );
+ maModel.mbPrintHeadings = getFlag( nFlags, OOBIN_PRINTOPT_PRINTHEADING );
+}
+
+void PageSettings::importPageSetup( const Relations& rRelations, RecordInputStream& rStrm )
+{
+ OUString aRelId;
+ sal_uInt16 nFlags;
+ rStrm >> maModel.mnPaperSize >> maModel.mnScale
+ >> maModel.mnHorPrintRes >> maModel.mnVerPrintRes
+ >> maModel.mnCopies >> maModel.mnFirstPage
+ >> maModel.mnFitToWidth >> maModel.mnFitToHeight
+ >> nFlags >> aRelId;
+ maModel.setBinPrintErrors( extractValue< sal_uInt8 >( nFlags, 9, 2 ) );
+ maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( aRelId );
+ maModel.mnOrientation = getFlagValue( nFlags, OOBIN_PAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, OOBIN_PAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
+ maModel.mnPageOrder = getFlagValue( nFlags, OOBIN_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
+ maModel.mnCellComments = getFlagValue( nFlags, OOBIN_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, OOBIN_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
+ maModel.mbValidSettings = !getFlag( nFlags, OOBIN_PAGESETUP_INVALID );
+ maModel.mbUseFirstPage = getFlag( nFlags, OOBIN_PAGESETUP_USEFIRSTPAGE );
+ maModel.mbBlackWhite = getFlag( nFlags, OOBIN_PAGESETUP_BLACKWHITE );
+ maModel.mbDraftQuality = getFlag( nFlags, OOBIN_PAGESETUP_DRAFTQUALITY );
+}
+
+void PageSettings::importChartPageSetup( const Relations& rRelations, RecordInputStream& rStrm )
+{
+ OUString aRelId;
+ sal_uInt16 nFirstPage, nFlags;
+ rStrm >> maModel.mnPaperSize >> maModel.mnHorPrintRes >> maModel.mnVerPrintRes
+ >> maModel.mnCopies >> nFirstPage >> nFlags >> aRelId;
+ maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( aRelId );
+ maModel.mnFirstPage = nFirstPage; // 16-bit in CHARTPAGESETUP
+ maModel.mnOrientation = getFlagValue( nFlags, OOBIN_CHARTPAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, OOBIN_CHARTPAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
+ maModel.mbValidSettings = !getFlag( nFlags, OOBIN_CHARTPAGESETUP_INVALID );
+ maModel.mbUseFirstPage = getFlag( nFlags, OOBIN_CHARTPAGESETUP_USEFIRSTPAGE );
+ maModel.mbBlackWhite = getFlag( nFlags, OOBIN_CHARTPAGESETUP_BLACKWHITE );
+ maModel.mbDraftQuality = getFlag( nFlags, OOBIN_CHARTPAGESETUP_DRAFTQUALITY );
+}
+
+void PageSettings::importHeaderFooter( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags
+ >> maModel.maOddHeader >> maModel.maOddFooter
+ >> maModel.maEvenHeader >> maModel.maEvenFooter
+ >> maModel.maFirstHeader >> maModel.maFirstFooter;
+ maModel.mbUseEvenHF = getFlag( nFlags, OOBIN_HEADERFOOTER_DIFFEVEN );
+ maModel.mbUseFirstHF = getFlag( nFlags, OOBIN_HEADERFOOTER_DIFFFIRST );
+}
+
+void PageSettings::importPicture( const Relations& rRelations, RecordInputStream& rStrm )
+{
+ importPictureData( rRelations, rStrm.readString() );
+}
+
+void PageSettings::importLeftMargin( BiffInputStream& rStrm )
+{
+ rStrm >> maModel.mfLeftMargin;
+}
+
+void PageSettings::importRightMargin( BiffInputStream& rStrm )
+{
+ rStrm >> maModel.mfRightMargin;
+}
+
+void PageSettings::importTopMargin( BiffInputStream& rStrm )
+{
+ rStrm >> maModel.mfTopMargin;
+}
+
+void PageSettings::importBottomMargin( BiffInputStream& rStrm )
+{
+ rStrm >> maModel.mfBottomMargin;
+}
+
+void PageSettings::importPageSetup( BiffInputStream& rStrm )
+{
+ sal_uInt16 nPaperSize, nScale, nFirstPage, nFitToWidth, nFitToHeight, nFlags;
+ rStrm >> nPaperSize >> nScale >> nFirstPage >> nFitToWidth >> nFitToHeight >> nFlags;
+
+ maModel.mnPaperSize = nPaperSize; // equal in BIFF and OOX
+ maModel.mnScale = nScale;
+ maModel.mnFirstPage = nFirstPage;
+ maModel.mnFitToWidth = nFitToWidth;
+ maModel.mnFitToHeight = nFitToHeight;
+ maModel.mnOrientation = getFlagValue( nFlags, BIFF_PAGESETUP_PORTRAIT, XML_portrait, XML_landscape );
+ maModel.mnPageOrder = getFlagValue( nFlags, BIFF_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
+ maModel.mbValidSettings = !getFlag( nFlags, BIFF_PAGESETUP_INVALID );
+ maModel.mbUseFirstPage = true;
+ maModel.mbBlackWhite = getFlag( nFlags, BIFF_PAGESETUP_BLACKWHITE );
+
+ if( getBiff() >= BIFF5 )
+ {
+ sal_uInt16 nHorPrintRes, nVerPrintRes, nCopies;
+ rStrm >> nHorPrintRes >> nVerPrintRes >> maModel.mfHeaderMargin >> maModel.mfFooterMargin >> nCopies;
+
+ maModel.mnCopies = nCopies;
+ maModel.mnOrientation = getFlagValue( nFlags, BIFF_PAGESETUP_DEFAULTORIENT, XML_default, maModel.mnOrientation );
+ maModel.mnHorPrintRes = nHorPrintRes;
+ maModel.mnVerPrintRes = nVerPrintRes;
+ maModel.mnCellComments = getFlagValue( nFlags, BIFF_PAGESETUP_PRINTNOTES, XML_asDisplayed, XML_none );
+ maModel.mbUseFirstPage = getFlag( nFlags, BIFF_PAGESETUP_USEFIRSTPAGE );
+ maModel.mbDraftQuality = getFlag( nFlags, BIFF_PAGESETUP_DRAFTQUALITY );
+
+ if( getBiff() == BIFF8 )
+ {
+ maModel.setBinPrintErrors( extractValue< sal_uInt8 >( nFlags, 10, 2 ) );
+ maModel.mnCellComments = getFlagValue( nFlags, BIFF_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, BIFF_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
+ }
+ }
+}
+
+void PageSettings::importHorCenter( BiffInputStream& rStrm )
+{
+ maModel.mbHorCenter = rStrm.readuInt16() != 0;
+}
+
+void PageSettings::importVerCenter( BiffInputStream& rStrm )
+{
+ maModel.mbVerCenter = rStrm.readuInt16() != 0;
+}
+
+void PageSettings::importPrintHeaders( BiffInputStream& rStrm )
+{
+ maModel.mbPrintHeadings = rStrm.readuInt16() != 0;
+}
+
+void PageSettings::importPrintGridLines( BiffInputStream& rStrm )
+{
+ maModel.mbPrintGrid = rStrm.readuInt16() != 0;
+}
+
+void PageSettings::importHeader( BiffInputStream& rStrm )
+{
+ if( rStrm.getRemaining() > 0 )
+ maModel.maOddHeader = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
+ else
+ maModel.maOddHeader = OUString();
+}
+
+void PageSettings::importFooter( BiffInputStream& rStrm )
+{
+ if( rStrm.getRemaining() > 0 )
+ maModel.maOddFooter = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
+ else
+ maModel.maOddFooter = OUString();
+}
+
+void PageSettings::importPicture( BiffInputStream& rStrm )
+{
+ StreamDataSequence aPictureData;
+ BiffHelper::importImgData( aPictureData, rStrm, getBiff() );
+ maModel.maGraphicUrl = getBaseFilter().getGraphicHelper().importGraphicObject( aPictureData );
+}
+
+void PageSettings::setFitToPagesMode( bool bFitToPages )
+{
+ maModel.mbFitToPages = bFitToPages;
+}
+
+void PageSettings::finalizeImport()
+{
+ OUStringBuffer aStyleNameBuffer( CREATE_OUSTRING( "PageStyle_" ) );
+ Reference< XNamed > xSheetName( getSheet(), 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 );
+ getPageSettingsConverter().writePageSettingsProperties( aStyleProps, maModel, getSheetType() );
+
+ PropertySet aSheetProps( getSheet() );
+ aSheetProps.setProperty( PROP_PageStyle, aStyleName );
+}
+
+void PageSettings::importPictureData( const Relations& rRelations, const OUString& rRelId )
+{
+ OUString aPicturePath = rRelations.getFragmentPathFromRelId( rRelId );
+ if( aPicturePath.getLength() > 0 )
+ maModel.maGraphicUrl = getBaseFilter().getGraphicHelper().importEmbeddedGraphicObject( aPicturePath );
+}
+
+// ============================================================================
+// ============================================================================
+
+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 HeaderFooterParser : public WorkbookHelper
+{
+public:
+ explicit HeaderFooterParser( const WorkbookHelper& rHelper );
+
+ /** Parses the passed string and creates the header/footer contents.
+ @returns The total height of the converted header or footer in points. */
+ double parse(
+ const Reference< XHeaderFooterContent >& rxContext,
+ const OUString& rData );
+
+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;
+
+ const OUString maPageNumberService;
+ const OUString maPageCountService;
+ const OUString maSheetNameService;
+ const OUString maFileNameService;
+ const OUString maDateTimeService;
+ const OStringSet maBoldNames; /// All names for bold font style in lowercase UTF-8.
+ const 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.
+ FontModel maFontModel; /// Font attributes of current text range.
+};
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+// different names for bold font style (lowercase)
+static const sal_Char* const sppcBoldNames[] =
+{
+ "bold",
+ "fett", // German 'bold'
+ "demibold",
+ "halbfett", // German 'demibold'
+ "black",
+ "heavy"
+};
+
+// different names for italic font style (lowercase)
+static const sal_Char* const sppcItalicNames[] =
+{
+ "italic",
+ "kursiv", // German 'italic'
+ "oblique",
+ "schr\303\204g", // German 'oblique' with uppercase A umlaut
+ "schr\303\244g" // German 'oblique' with lowercase A umlaut
+};
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+HeaderFooterParser::HeaderFooterParser( 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" ) ),
+ maBoldNames( sppcBoldNames, STATIC_ARRAY_END( sppcBoldNames ) ),
+ maItalicNames( sppcItalicNames, STATIC_ARRAY_END( sppcItalicNames ) ),
+ maPortions( static_cast< size_t >( HF_COUNT ) ),
+ meCurrPortion( HF_CENTER )
+{
+}
+
+double HeaderFooterParser::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 0.0;
+
+ meCurrPortion = HF_CENTER;
+ maBuffer.setLength( 0 );
+ maFontModel = getStyles().getDefaultFontModel();
+ 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( PROP_FileFormat, ::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( PROP_FileFormat, ::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( PROP_IsDate, true );
+ appendField( xContent );
+ }
+ break;
+ case 'T': // time
+ {
+ Reference< XTextContent > xContent = createField( maDateTimeService );
+ PropertySet aPropSet( xContent );
+ aPropSet.setProperty( PROP_IsDate, false );
+ appendField( xContent );
+ }
+ break;
+
+ case 'B': // bold
+ setAttributes();
+ maFontModel.mbBold = !maFontModel.mbBold;
+ break;
+ case 'I': // italic
+ setAttributes();
+ maFontModel.mbItalic = !maFontModel.mbItalic;
+ break;
+ case 'U': // underline
+ setAttributes();
+ maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_single) ? XML_none : XML_single;
+ break;
+ case 'E': // double underline
+ setAttributes();
+ maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_double) ? XML_none : XML_double;
+ break;
+ case 'S': // strikeout
+ setAttributes();
+ maFontModel.mbStrikeout = !maFontModel.mbStrikeout;
+ break;
+ case 'X': // superscript
+ setAttributes();
+ maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_superscript) ? XML_baseline : XML_superscript;
+ break;
+ case 'Y': // subsrcipt
+ setAttributes();
+ maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_subscript) ? XML_baseline : XML_subscript;
+ break;
+ case 'O': // outlined
+ setAttributes();
+ maFontModel.mbOutline = !maFontModel.mbOutline;
+ break;
+ case 'H': // shadow
+ setAttributes();
+ maFontModel.mbShadow = !maFontModel.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();
+ maFontModel.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 );
+
+ return ::std::max( maPortions[ HF_LEFT ].mfTotalHeight,
+ ::std::max( maPortions[ HF_CENTER ].mfTotalHeight, maPortions[ HF_RIGHT ].mfTotalHeight ) );
+}
+
+// private --------------------------------------------------------------------
+
+double HeaderFooterParser::getCurrHeight( HFPortionId ePortion ) const
+{
+ double fMaxHt = maPortions[ ePortion ].mfCurrHeight;
+ return (fMaxHt == 0.0) ? maFontModel.mfHeight : fMaxHt;
+}
+
+double HeaderFooterParser::getCurrHeight() const
+{
+ return getCurrHeight( meCurrPortion );
+}
+
+void HeaderFooterParser::updateCurrHeight( HFPortionId ePortion )
+{
+ double& rfMaxHt = maPortions[ ePortion ].mfCurrHeight;
+ rfMaxHt = ::std::max( rfMaxHt, maFontModel.mfHeight );
+}
+
+void HeaderFooterParser::updateCurrHeight()
+{
+ updateCurrHeight( meCurrPortion );
+}
+
+void HeaderFooterParser::setAttributes()
+{
+ Reference< XTextRange > xRange( getStartPos(), UNO_QUERY );
+ getEndPos()->gotoRange( xRange, sal_False );
+ getEndPos()->gotoEnd( sal_True );
+ if( !getEndPos()->isCollapsed() )
+ {
+ Font aFont( *this, maFontModel );
+ aFont.finalizeImport();
+ PropertySet aPropSet( getEndPos() );
+ aFont.writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
+ getStartPos()->gotoEnd( sal_False );
+ getEndPos()->gotoEnd( sal_False );
+ }
+}
+
+void HeaderFooterParser::appendText()
+{
+ if( maBuffer.getLength() > 0 )
+ {
+ getEndPos()->gotoEnd( sal_False );
+ getEndPos()->setString( maBuffer.makeStringAndClear() );
+ updateCurrHeight();
+ }
+}
+
+void HeaderFooterParser::appendLineBreak()
+{
+ getEndPos()->gotoEnd( sal_False );
+ getEndPos()->setString( OUString( sal_Unicode( '\n' ) ) );
+ getPortion().mfTotalHeight += getCurrHeight();
+ getPortion().mfCurrHeight = 0;
+}
+
+Reference< XTextContent > HeaderFooterParser::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( "HeaderFooterParser::createField - error while creating text field \"" ).
+ append( OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( '"' ).getStr() );
+ }
+ return xContent;
+}
+
+void HeaderFooterParser::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 HeaderFooterParser::convertFontName( const OUString& rName )
+{
+ if( rName.getLength() > 0 )
+ {
+ // single dash is document default font
+ if( (rName.getLength() == 1) && (rName[ 0 ] == '-') )
+ maFontModel.maName = getStyles().getDefaultFontModel().maName;
+ else
+ maFontModel.maName = rName;
+ }
+}
+
+void HeaderFooterParser::convertFontStyle( const OUString& rStyle )
+{
+ maFontModel.mbBold = maFontModel.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 )
+ maFontModel.mbBold = true;
+ else if( maItalicNames.count( aToken ) > 0 )
+ maFontModel.mbItalic = true;
+ }
+ }
+}
+
+void HeaderFooterParser::convertFontColor( const OUString& rColor )
+{
+ OSL_ENSURE( rColor.getLength() == 6, "HeaderFooterParser::convertFontColor - invalid font color code" );
+ if( (rColor[ 2 ] == '+') || (rColor[ 2 ] == '-') )
+ // theme color: TTSNNN (TT = decimal theme index, S = +/-, NNN = decimal tint/shade in percent)
+ maFontModel.maColor.setTheme(
+ rColor.copy( 0, 2 ).toInt32(),
+ static_cast< double >( rColor.copy( 2 ).toInt32() ) / 100.0 );
+ else
+ // RGB color: RRGGBB
+ maFontModel.maColor.setRgb( rColor.toInt32( 16 ) );
+}
+
+void HeaderFooterParser::finalizePortion()
+{
+ appendText();
+ setAttributes();
+}
+
+void HeaderFooterParser::setNewPortion( HFPortionId ePortion )
+{
+ if( ePortion != meCurrPortion )
+ {
+ finalizePortion();
+ meCurrPortion = ePortion;
+ maFontModel = getStyles().getDefaultFontModel();
+ }
+}
+
+// ============================================================================
+
+namespace {
+
+/** 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
+
+// ----------------------------------------------------------------------------
+
+PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId, sal_Int32 nRightPropId ) :
+ mnLeftPropId( nLeftPropId ),
+ mnRightPropId( nRightPropId ),
+ mnHeight( 0 ),
+ mnBodyDist( 0 ),
+ mbHasContent( false ),
+ mbShareOddEven( false ),
+ mbDynamicHeight( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PageSettingsConverter::PageSettingsConverter( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mxHFParser( new HeaderFooterParser( rHelper ) ),
+ maHeaderData( PROP_LeftPageHeaderContent, PROP_RightPageHeaderContent ),
+ maFooterData( PROP_LeftPageFooterContent, PROP_RightPageFooterContent )
+{
+}
+
+PageSettingsConverter::~PageSettingsConverter()
+{
+}
+
+void PageSettingsConverter::writePageSettingsProperties(
+ PropertySet& rPropSet, const PageSettingsModel& rModel, WorksheetType eSheetType )
+{
+ // special handling for chart sheets
+ bool bChartSheet = eSheetType == SHEETTYPE_CHARTSHEET;
+
+ // printout scaling
+ if( bChartSheet )
+ {
+ // always fit chart sheet to 1 page
+ rPropSet.setProperty< sal_Int16 >( PROP_ScaleToPages, 1 );
+ }
+ else if( rModel.mbFitToPages )
+ {
+ // fit to number of pages
+ rPropSet.setProperty( PROP_ScaleToPagesX, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnFitToWidth, 0, 1000 ) );
+ rPropSet.setProperty( PROP_ScaleToPagesY, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnFitToHeight, 0, 1000 ) );
+ }
+ else
+ {
+ // scale may be 0 which indicates uninitialized
+ sal_Int16 nScale = (rModel.mbValidSettings && (rModel.mnScale > 0)) ? getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnScale, 10, 400 ) : 100;
+ rPropSet.setProperty( PROP_PageScale, nScale );
+ }
+
+ // paper orientation
+ bool bLandscape = rModel.mnOrientation == XML_landscape;
+ // default orientation for current sheet type (chart sheets default to landscape)
+ if( !rModel.mbValidSettings || (rModel.mnOrientation == XML_default) )
+ bLandscape = bChartSheet;
+
+ // paper size
+ if( !rModel.mbValidSettings )
+ {
+ Size aSize;
+ bool bValid = false;
+
+ if( (0 < rModel.mnPaperSize) && (rModel.mnPaperSize < static_cast< sal_Int32 >( STATIC_ARRAY_SIZE( spPaperSizeTable ) )) )
+ {
+ const ApiPaperSize& rPaperSize = spPaperSizeTable[ rModel.mnPaperSize ];
+ aSize = Size( rPaperSize.mnWidth, rPaperSize.mnHeight );
+ bValid = true;
+ }
+ if( rModel.mnPaperWidth > 0 && rModel.mnPaperHeight > 0 )
+ {
+ aSize = Size( rModel.mnPaperWidth, rModel.mnPaperHeight );
+ bValid = true;
+ }
+
+ if( bValid )
+ {
+ if( bLandscape )
+ ::std::swap( aSize.Width, aSize.Height );
+ rPropSet.setProperty( PROP_Size, aSize );
+ }
+ }
+
+ // header/footer
+ convertHeaderFooterData( rPropSet, maHeaderData, rModel.maOddHeader, rModel.maEvenHeader, rModel.mbUseEvenHF, rModel.mfTopMargin, rModel.mfHeaderMargin );
+ convertHeaderFooterData( rPropSet, maFooterData, rModel.maOddFooter, rModel.maEvenFooter, rModel.mbUseEvenHF, rModel.mfBottomMargin, rModel.mfFooterMargin );
+
+ // write all properties to property set
+ const UnitConverter& rUnitConv = getUnitConverter();
+ PropertyMap aPropMap;
+ aPropMap[ PROP_IsLandscape ] <<= bLandscape;
+ aPropMap[ PROP_FirstPageNumber ] <<= getLimitedValue< sal_Int16, sal_Int32 >( rModel.mbUseFirstPage ? rModel.mnFirstPage : 0, 0, 9999 );
+ aPropMap[ PROP_PrintDownFirst ] <<= (rModel.mnPageOrder == XML_downThenOver);
+ aPropMap[ PROP_PrintAnnotations ] <<= (rModel.mnCellComments == XML_asDisplayed);
+ aPropMap[ PROP_CenterHorizontally ] <<= rModel.mbHorCenter;
+ aPropMap[ PROP_CenterVertically ] <<= rModel.mbVerCenter;
+ aPropMap[ PROP_PrintGrid ] <<= (!bChartSheet && rModel.mbPrintGrid); // no gridlines in chart sheets
+ aPropMap[ PROP_PrintHeaders ] <<= (!bChartSheet && rModel.mbPrintHeadings); // no column/row headings in chart sheets
+ aPropMap[ PROP_LeftMargin ] <<= rUnitConv.scaleToMm100( rModel.mfLeftMargin, UNIT_INCH );
+ aPropMap[ PROP_RightMargin ] <<= rUnitConv.scaleToMm100( rModel.mfRightMargin, UNIT_INCH );
+ // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled
+ aPropMap[ PROP_TopMargin ] <<= rUnitConv.scaleToMm100( maHeaderData.mbHasContent ? rModel.mfHeaderMargin : rModel.mfTopMargin, UNIT_INCH );
+ // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled
+ aPropMap[ PROP_BottomMargin ] <<= rUnitConv.scaleToMm100( maFooterData.mbHasContent ? rModel.mfFooterMargin : rModel.mfBottomMargin, UNIT_INCH );
+ aPropMap[ PROP_HeaderIsOn ] <<= maHeaderData.mbHasContent;
+ aPropMap[ PROP_HeaderIsShared ] <<= maHeaderData.mbShareOddEven;
+ aPropMap[ PROP_HeaderIsDynamicHeight ] <<= maHeaderData.mbDynamicHeight;
+ aPropMap[ PROP_HeaderHeight ] <<= maHeaderData.mnHeight;
+ aPropMap[ PROP_HeaderBodyDistance ] <<= maHeaderData.mnBodyDist;
+ aPropMap[ PROP_FooterIsOn ] <<= maFooterData.mbHasContent;
+ aPropMap[ PROP_FooterIsShared ] <<= maFooterData.mbShareOddEven;
+ aPropMap[ PROP_FooterIsDynamicHeight ] <<= maFooterData.mbDynamicHeight;
+ aPropMap[ PROP_FooterHeight ] <<= maFooterData.mnHeight;
+ aPropMap[ PROP_FooterBodyDistance ] <<= maFooterData.mnBodyDist;
+ // background image
+ if( rModel.maGraphicUrl.getLength() > 0 )
+ {
+ aPropMap[ PROP_BackGraphicURL ] <<= rModel.maGraphicUrl;
+ aPropMap[ PROP_BackGraphicLocation ] <<= ::com::sun::star::style::GraphicLocation_TILED;
+ }
+
+ rPropSet.setProperties( aPropMap );
+}
+
+void PageSettingsConverter::convertHeaderFooterData(
+ PropertySet& rPropSet, HFHelperData& orHFData,
+ 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, orHFData.mnRightPropId, rOddContent ) : 0;
+ sal_Int32 nEvenHeight = bHasEvenContent ? writeHeaderFooter( rPropSet, orHFData.mnLeftPropId, rEvenContent ) : 0;
+
+ orHFData.mnHeight = 750;
+ orHFData.mnBodyDist = 250;
+ orHFData.mbHasContent = bHasOddContent || bHasEvenContent;
+ orHFData.mbShareOddEven = !bUseEvenContent;
+ orHFData.mbDynamicHeight = true;
+
+ if( orHFData.mbHasContent )
+ {
+ // use maximum height of odd/even header/footer
+ orHFData.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 */
+ orHFData.mnBodyDist = getUnitConverter().scaleToMm100( fPageMargin - fContentMargin, UNIT_INCH ) - orHFData.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. */
+ orHFData.mbDynamicHeight = orHFData.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"). */
+ orHFData.mnHeight += orHFData.mnBodyDist;
+ // negative body distance not allowed
+ orHFData.mnBodyDist = ::std::max< sal_Int32 >( orHFData.mnBodyDist, 0 );
+ }
+}
+
+sal_Int32 PageSettingsConverter::writeHeaderFooter(
+ PropertySet& rPropSet, sal_Int32 nPropId, const OUString& rContent )
+{
+ OSL_ENSURE( rContent.getLength() > 0, "PageSettingsConverter::writeHeaderFooter - empty h/f string found" );
+ sal_Int32 nHeight = 0;
+ if( rContent.getLength() > 0 )
+ {
+ Reference< XHeaderFooterContent > xHFContent;
+ if( rPropSet.getProperty( xHFContent, nPropId ) && xHFContent.is() )
+ {
+ double fTotalHeight = mxHFParser->parse( xHFContent, rContent );
+ rPropSet.setProperty( nPropId, xHFContent );
+ nHeight = getUnitConverter().scaleToMm100( fTotalHeight, UNIT_POINT );
+ }
+ }
+ return nHeight;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/pivotcachebuffer.cxx b/oox/source/xls/pivotcachebuffer.cxx
new file mode 100644
index 000000000000..aeaade3b0640
--- /dev/null
+++ b/oox/source/xls/pivotcachebuffer.cxx
@@ -0,0 +1,1550 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/pivotcachebuffer.hxx"
+#include <set>
+#include <rtl/ustrbuf.hxx>
+#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/table/XCell.hpp>
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+#include <com/sun/star/sheet/DataPilotFieldGroupInfo.hpp>
+#include <com/sun/star/sheet/XDataPilotFieldGrouping.hpp>
+#include "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/defnamesbuffer.hxx"
+#include "oox/xls/excelhandlers.hxx"
+#include "oox/xls/pivotcachefragment.hxx"
+#include "oox/xls/tablebuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Any;
+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 ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::util::DateTime;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::sheet::DataPilotFieldGroupInfo;
+using ::com::sun::star::table::XCell;
+using ::com::sun::star::sheet::XDataPilotField;
+using ::com::sun::star::sheet::XDataPilotFieldGrouping;
+using ::oox::core::Relations;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 OOBIN_PCDFIELD_SERVERFIELD = 0x0001;
+const sal_uInt16 OOBIN_PCDFIELD_NOUNIQUEITEMS = 0x0002;
+const sal_uInt16 OOBIN_PCDFIELD_DATABASEFIELD = 0x0004;
+const sal_uInt16 OOBIN_PCDFIELD_HASCAPTION = 0x0008;
+const sal_uInt16 OOBIN_PCDFIELD_MEMBERPROPFIELD = 0x0010;
+const sal_uInt16 OOBIN_PCDFIELD_HASFORMULA = 0x0100;
+const sal_uInt16 OOBIN_PCDFIELD_HASPROPERTYNAME = 0x0200;
+
+const sal_uInt16 OOBIN_PCDFSITEMS_HASSEMIMIXED = 0x0001;
+const sal_uInt16 OOBIN_PCDFSITEMS_HASNONDATE = 0x0002;
+const sal_uInt16 OOBIN_PCDFSITEMS_HASDATE = 0x0004;
+const sal_uInt16 OOBIN_PCDFSITEMS_HASSTRING = 0x0008;
+const sal_uInt16 OOBIN_PCDFSITEMS_HASBLANK = 0x0010;
+const sal_uInt16 OOBIN_PCDFSITEMS_HASMIXED = 0x0020;
+const sal_uInt16 OOBIN_PCDFSITEMS_ISNUMERIC = 0x0040;
+const sal_uInt16 OOBIN_PCDFSITEMS_ISINTEGER = 0x0080;
+const sal_uInt16 OOBIN_PCDFSITEMS_HASMINMAX = 0x0100;
+const sal_uInt16 OOBIN_PCDFSITEMS_HASLONGTEXT = 0x0200;
+
+const sal_uInt16 OOBIN_PCITEM_ARRAY_DOUBLE = 0x0001;
+const sal_uInt16 OOBIN_PCITEM_ARRAY_STRING = 0x0002;
+const sal_uInt16 OOBIN_PCITEM_ARRAY_ERROR = 0x0010;
+const sal_uInt16 OOBIN_PCITEM_ARRAY_DATE = 0x0020;
+
+const sal_uInt8 OOBIN_PCDFRANGEPR_AUTOSTART = 0x01;
+const sal_uInt8 OOBIN_PCDFRANGEPR_AUTOEND = 0x02;
+const sal_uInt8 OOBIN_PCDFRANGEPR_DATEGROUP = 0x04;
+
+const sal_uInt8 OOBIN_PCDEFINITION_SAVEDATA = 0x01;
+const sal_uInt8 OOBIN_PCDEFINITION_INVALID = 0x02;
+const sal_uInt8 OOBIN_PCDEFINITION_REFRESHONLOAD = 0x04;
+const sal_uInt8 OOBIN_PCDEFINITION_OPTIMIZEMEMORY = 0x08;
+const sal_uInt8 OOBIN_PCDEFINITION_ENABLEREFRESH = 0x10;
+const sal_uInt8 OOBIN_PCDEFINITION_BACKGROUNDQUERY = 0x20;
+const sal_uInt8 OOBIN_PCDEFINITION_UPGRADEONREFR = 0x40;
+const sal_uInt8 OOBIN_PCDEFINITION_TUPELCACHE = 0x80;
+
+const sal_uInt8 OOBIN_PCDEFINITION_HASUSERNAME = 0x01;
+const sal_uInt8 OOBIN_PCDEFINITION_HASRELID = 0x02;
+const sal_uInt8 OOBIN_PCDEFINITION_SUPPORTSUBQUERY = 0x04;
+const sal_uInt8 OOBIN_PCDEFINITION_SUPPORTDRILL = 0x08;
+
+const sal_uInt8 OOBIN_PCDWBSOURCE_HASRELID = 0x01;
+const sal_uInt8 OOBIN_PCDWBSOURCE_HASSHEET = 0x02;
+
+const sal_uInt16 BIFF_PCDSOURCE_WORKSHEET = 0x0001;
+const sal_uInt16 BIFF_PCDSOURCE_EXTERNAL = 0x0002;
+const sal_uInt16 BIFF_PCDSOURCE_CONSOLIDATION = 0x0004;
+const sal_uInt16 BIFF_PCDSOURCE_SCENARIO = 0x0010;
+
+const sal_uInt16 BIFF_PC_NOSTRING = 0xFFFF;
+
+const sal_uInt16 BIFF_PCDFIELD_HASITEMS = 0x0001;
+const sal_uInt16 BIFF_PCDFIELD_HASUNSHAREDITEMS = 0x0002;
+const sal_uInt16 BIFF_PCDFIELD_CALCULATED = 0x0004;
+const sal_uInt16 BIFF_PCDFIELD_HASPARENT = 0x0008;
+const sal_uInt16 BIFF_PCDFIELD_RANGEGROUP = 0x0010;
+const sal_uInt16 BIFF_PCDFIELD_ISNUMERIC = 0x0020;
+const sal_uInt16 BIFF_PCDFIELD_HASSEMIMIXED = 0x0080;
+const sal_uInt16 BIFF_PCDFIELD_HASMINMAX = 0x0100;
+const sal_uInt16 BIFF_PCDFIELD_HASLONGINDEX = 0x0200;
+const sal_uInt16 BIFF_PCDFIELD_HASNONDATE = 0x0400;
+const sal_uInt16 BIFF_PCDFIELD_HASDATE = 0x0800;
+const sal_uInt16 BIFF_PCDFIELD_SERVERFIELD = 0x2000;
+const sal_uInt16 BIFF_PCDFIELD_NOUNIQUEITEMS = 0x4000;
+
+const sal_uInt16 BIFF_PCDFRANGEPR_AUTOSTART = 0x0001;
+const sal_uInt16 BIFF_PCDFRANGEPR_AUTOEND = 0x0002;
+
+const sal_uInt16 BIFF_PCDEFINITION_SAVEDATA = 0x0001;
+const sal_uInt16 BIFF_PCDEFINITION_INVALID = 0x0002;
+const sal_uInt16 BIFF_PCDEFINITION_REFRESHONLOAD = 0x0004;
+const sal_uInt16 BIFF_PCDEFINITION_OPTIMIZEMEMORY = 0x0008;
+const sal_uInt16 BIFF_PCDEFINITION_BACKGROUNDQUERY = 0x0010;
+const sal_uInt16 BIFF_PCDEFINITION_ENABLEREFRESH = 0x0020;
+
+// ----------------------------------------------------------------------------
+
+/** Adjusts the weird date format read from binary streams.
+
+ Dates before 1900-Mar-01 are stored including the non-existing leap day
+ 1900-02-29. Time values (without date) are stored as times of day
+ 1900-Jan-00. Nothing has to be done when the workbook is stored in 1904
+ date mode (dates before 1904-Jan-01 will not occur in this case).
+ */
+void lclAdjustBinDateTime( DateTime& orDateTime )
+{
+ if( (orDateTime.Year == 1900) && (orDateTime.Month <= 2) )
+ {
+ OSL_ENSURE( (orDateTime.Month == 1) || ((orDateTime.Month == 2) && (orDateTime.Day > 0)), "lclAdjustBinDateTime - invalid date" );
+ switch( orDateTime.Month )
+ {
+ case 2: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; --orDateTime.Month; } break;
+ case 1: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; orDateTime.Month = 12; --orDateTime.Year; } break;
+ }
+ }
+}
+
+} // namespace
+
+// ============================================================================
+
+PivotCacheItem::PivotCacheItem() :
+ mnType( XML_m )
+{
+}
+
+void PivotCacheItem::readString( const AttributeList& rAttribs )
+{
+ maValue <<= rAttribs.getXString( XML_v, OUString() );
+ mnType = XML_s;
+}
+
+void PivotCacheItem::readNumeric( const AttributeList& rAttribs )
+{
+ maValue <<= rAttribs.getDouble( XML_v, 0.0 );
+ mnType = XML_n;
+}
+
+void PivotCacheItem::readDate( const AttributeList& rAttribs )
+{
+ maValue <<= rAttribs.getDateTime( XML_v, DateTime() );
+ mnType = XML_d;
+}
+
+void PivotCacheItem::readBool( const AttributeList& rAttribs )
+{
+ maValue <<= rAttribs.getBool( XML_v, false );
+ mnType = XML_b;
+}
+
+void PivotCacheItem::readError( const AttributeList& rAttribs, const UnitConverter& rUnitConverter )
+{
+ maValue <<= static_cast< sal_Int32 >( rUnitConverter.calcBiffErrorCode( rAttribs.getXString( XML_v, OUString() ) ) );
+ mnType = XML_e;
+}
+
+void PivotCacheItem::readIndex( const AttributeList& rAttribs )
+{
+ maValue <<= rAttribs.getInteger( XML_v, -1 );
+ mnType = XML_x;
+}
+
+void PivotCacheItem::readString( RecordInputStream& rStrm )
+{
+ maValue <<= rStrm.readString();
+ mnType = XML_s;
+}
+
+void PivotCacheItem::readDouble( RecordInputStream& rStrm )
+{
+ maValue <<= rStrm.readDouble();
+ mnType = XML_n;
+}
+
+void PivotCacheItem::readDate( RecordInputStream& rStrm )
+{
+ DateTime aDateTime;
+ aDateTime.Year = rStrm.readuInt16();
+ aDateTime.Month = rStrm.readuInt16();
+ aDateTime.Day = rStrm.readuInt8();
+ aDateTime.Hours = rStrm.readuInt8();
+ aDateTime.Minutes = rStrm.readuInt8();
+ aDateTime.Seconds = rStrm.readuInt8();
+ lclAdjustBinDateTime( aDateTime );
+ maValue <<= aDateTime;
+ mnType = XML_d;
+}
+
+void PivotCacheItem::readBool( RecordInputStream& rStrm )
+{
+ maValue <<= (rStrm.readuInt8() != 0);
+ mnType = XML_b;
+}
+
+void PivotCacheItem::readError( RecordInputStream& rStrm )
+{
+ maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
+ mnType = XML_e;
+}
+
+void PivotCacheItem::readIndex( RecordInputStream& rStrm )
+{
+ maValue <<= rStrm.readInt32();
+ mnType = XML_x;
+}
+
+void PivotCacheItem::readString( BiffInputStream& rStrm, const WorkbookHelper& rHelper )
+{
+ maValue <<= (rHelper.getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, rHelper.getTextEncoding() );
+ mnType = XML_s;
+}
+
+void PivotCacheItem::readDouble( BiffInputStream& rStrm )
+{
+ maValue <<= rStrm.readDouble();
+ mnType = XML_n;
+}
+
+void PivotCacheItem::readInteger( BiffInputStream& rStrm )
+{
+ maValue <<= rStrm.readInt16();
+ mnType = XML_i; // fake, used for BIFF only
+}
+
+void PivotCacheItem::readDate( BiffInputStream& rStrm )
+{
+ DateTime aDateTime;
+ aDateTime.Year = rStrm.readuInt16();
+ aDateTime.Month = rStrm.readuInt16();
+ aDateTime.Day = rStrm.readuInt8();
+ aDateTime.Hours = rStrm.readuInt8();
+ aDateTime.Minutes = rStrm.readuInt8();
+ aDateTime.Seconds = rStrm.readuInt8();
+ lclAdjustBinDateTime( aDateTime );
+ maValue <<= aDateTime;
+ mnType = XML_d;
+}
+
+void PivotCacheItem::readBool( BiffInputStream& rStrm )
+{
+ maValue <<= (rStrm.readuInt8() != 0);
+ mnType = XML_b;
+}
+
+void PivotCacheItem::readError( BiffInputStream& rStrm )
+{
+ maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
+ mnType = XML_e;
+}
+
+OUString PivotCacheItem::getName() const
+{
+ switch( mnType )
+ {
+ case XML_m: return OUString();
+ case XML_s: return maValue.get< OUString >();
+ case XML_n: return OUString::valueOf( maValue.get< double >() ); // !TODO
+ case XML_i: return OUString::valueOf( maValue.get< sal_Int32 >() );
+ case XML_d: return OUString(); // !TODO
+ case XML_b: return OUString::valueOf( static_cast< sal_Bool >( maValue.get< bool >() ) ); // !TODO
+ case XML_e: return OUString(); // !TODO
+ }
+ OSL_ENSURE( false, "PivotCacheItem::getName - invalid data type" );
+ return OUString();
+}
+
+// ----------------------------------------------------------------------------
+
+PivotCacheItemList::PivotCacheItemList( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void PivotCacheItemList::importItem( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ PivotCacheItem& rItem = createItem();
+ switch( nElement )
+ {
+ case XLS_TOKEN( m ): break;
+ case XLS_TOKEN( s ): rItem.readString( rAttribs ); break;
+ case XLS_TOKEN( n ): rItem.readNumeric( rAttribs ); break;
+ case XLS_TOKEN( d ): rItem.readDate( rAttribs ); break;
+ case XLS_TOKEN( b ): rItem.readBool( rAttribs ); break;
+ case XLS_TOKEN( e ): rItem.readError( rAttribs, getUnitConverter() ); break;
+ default: OSL_ENSURE( false, "PivotCacheItemList::importItem - unknown element type" );
+ }
+}
+
+void PivotCacheItemList::importItem( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ if( nRecId == OOBIN_ID_PCITEM_ARRAY )
+ {
+ importArray( rStrm );
+ return;
+ }
+
+ PivotCacheItem& rItem = createItem();
+ switch( nRecId )
+ {
+ case OOBIN_ID_PCITEM_MISSING:
+ case OOBIN_ID_PCITEMA_MISSING: break;
+ case OOBIN_ID_PCITEM_STRING:
+ case OOBIN_ID_PCITEMA_STRING: rItem.readString( rStrm ); break;
+ case OOBIN_ID_PCITEM_DOUBLE:
+ case OOBIN_ID_PCITEMA_DOUBLE: rItem.readDouble( rStrm ); break;
+ case OOBIN_ID_PCITEM_DATE:
+ case OOBIN_ID_PCITEMA_DATE: rItem.readDate( rStrm ); break;
+ case OOBIN_ID_PCITEM_BOOL:
+ case OOBIN_ID_PCITEMA_BOOL: rItem.readBool( rStrm ); break;
+ case OOBIN_ID_PCITEM_ERROR:
+ case OOBIN_ID_PCITEMA_ERROR: rItem.readError( rStrm ); break;
+ default: OSL_ENSURE( false, "PivotCacheItemList::importItem - unknown record type" );
+ }
+}
+
+void PivotCacheItemList::importItemList( BiffInputStream& rStrm, sal_uInt16 nCount )
+{
+ bool bLoop = true;
+ for( sal_uInt16 nItemIdx = 0; bLoop && (nItemIdx < nCount); ++nItemIdx )
+ {
+ bLoop = rStrm.startNextRecord();
+ if( bLoop ) switch( rStrm.getRecId() )
+ {
+ case BIFF_ID_PCITEM_MISSING: createItem(); break;
+ case BIFF_ID_PCITEM_STRING: createItem().readString( rStrm, *this ); break;
+ case BIFF_ID_PCITEM_DOUBLE: createItem().readDouble( rStrm ); break;
+ case BIFF_ID_PCITEM_INTEGER: createItem().readInteger( rStrm ); break;
+ case BIFF_ID_PCITEM_DATE: createItem().readDate( rStrm ); break;
+ case BIFF_ID_PCITEM_BOOL: createItem().readBool( rStrm ); break;
+ case BIFF_ID_PCITEM_ERROR: createItem().readError( rStrm ); break;
+ default: rStrm.rewindRecord(); bLoop = false;
+ }
+ }
+ OSL_ENSURE( bLoop, "PivotCacheItemList::importItemList - could not read all cache item records" );
+}
+
+const PivotCacheItem* PivotCacheItemList::getCacheItem( sal_Int32 nItemIdx ) const
+{
+ return ContainerHelper::getVectorElement( maItems, nItemIdx );
+}
+
+void PivotCacheItemList::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
+{
+ orItemNames.clear();
+ orItemNames.reserve( maItems.size() );
+ for( CacheItemVector::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
+ orItemNames.push_back( aIt->getName() );
+}
+
+// private --------------------------------------------------------------------
+
+PivotCacheItem& PivotCacheItemList::createItem()
+{
+ maItems.resize( maItems.size() + 1 );
+ return maItems.back();
+}
+
+void PivotCacheItemList::importArray( RecordInputStream& rStrm )
+{
+ sal_uInt16 nType = rStrm.readuInt16();
+ sal_Int32 nCount = rStrm.readInt32();
+ for( sal_Int32 nIdx = 0; !rStrm.isEof() && (nIdx < nCount); ++nIdx )
+ {
+ switch( nType )
+ {
+ case OOBIN_PCITEM_ARRAY_DOUBLE: createItem().readDouble( rStrm ); break;
+ case OOBIN_PCITEM_ARRAY_STRING: createItem().readString( rStrm ); break;
+ case OOBIN_PCITEM_ARRAY_ERROR: createItem().readError( rStrm ); break;
+ case OOBIN_PCITEM_ARRAY_DATE: createItem().readDate( rStrm ); break;
+ default:
+ OSL_ENSURE( false, "PivotCacheItemList::importArray - unknown data type" );
+ nIdx = nCount;
+ }
+ }
+}
+
+// ============================================================================
+
+PCFieldModel::PCFieldModel() :
+ mnNumFmtId( 0 ),
+ mnSqlType( 0 ),
+ mnHierarchy( 0 ),
+ mnLevel( 0 ),
+ mnMappingCount( 0 ),
+ mbDatabaseField( true ),
+ mbServerField( false ),
+ mbUniqueList( true ),
+ mbMemberPropField( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PCSharedItemsModel::PCSharedItemsModel() :
+ mbHasSemiMixed( true ),
+ mbHasNonDate( true ),
+ mbHasDate( false ),
+ mbHasString( true ),
+ mbHasBlank( false ),
+ mbHasMixed( false ),
+ mbIsNumeric( false ),
+ mbIsInteger( false ),
+ mbHasLongText( false ),
+ mbHasLongIndexes( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PCFieldGroupModel::PCFieldGroupModel() :
+ mfStartValue( 0.0 ),
+ mfEndValue( 0.0 ),
+ mfInterval( 1.0 ),
+ mnParentField( -1 ),
+ mnBaseField( -1 ),
+ mnGroupBy( XML_range ),
+ mbRangeGroup( false ),
+ mbDateGroup( false ),
+ mbAutoStart( true ),
+ mbAutoEnd( true )
+{
+}
+
+void PCFieldGroupModel::setBinGroupBy( sal_uInt8 nGroupBy )
+{
+ static const sal_Int32 spnGroupBy[] = { XML_range,
+ XML_seconds, XML_minutes, XML_hours, XML_days, XML_months, XML_quarters, XML_years };
+ mnGroupBy = STATIC_ARRAY_SELECT( spnGroupBy, nGroupBy, XML_range );
+}
+
+// ----------------------------------------------------------------------------
+
+PivotCacheField::PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField ) :
+ WorkbookHelper( rHelper ),
+ maSharedItems( rHelper ),
+ maGroupItems( rHelper )
+{
+ maFieldModel.mbDatabaseField = bIsDatabaseField;
+}
+
+void PivotCacheField::importCacheField( const AttributeList& rAttribs )
+{
+ maFieldModel.maName = rAttribs.getXString( XML_name, OUString() );
+ maFieldModel.maCaption = rAttribs.getXString( XML_caption, OUString() );
+ maFieldModel.maPropertyName = rAttribs.getXString( XML_propertyName, OUString() );
+ maFieldModel.maFormula = rAttribs.getXString( XML_formula, OUString() );
+ maFieldModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
+ maFieldModel.mnSqlType = rAttribs.getInteger( XML_sqlType, 0 );
+ maFieldModel.mnHierarchy = rAttribs.getInteger( XML_hierarchy, 0 );
+ maFieldModel.mnLevel = rAttribs.getInteger( XML_level, 0 );
+ maFieldModel.mnMappingCount = rAttribs.getInteger( XML_mappingCount, 0 );
+ maFieldModel.mbDatabaseField = rAttribs.getBool( XML_databaseField, true );
+ maFieldModel.mbServerField = rAttribs.getBool( XML_serverField, false );
+ maFieldModel.mbUniqueList = rAttribs.getBool( XML_uniqueList, true );
+ maFieldModel.mbMemberPropField = rAttribs.getBool( XML_memberPropertyField, false );
+}
+
+void PivotCacheField::importSharedItems( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( maSharedItems.empty(), "PivotCacheField::importSharedItems - multiple shared items elements" );
+ maSharedItemsModel.mbHasSemiMixed = rAttribs.getBool( XML_containsSemiMixedTypes, true );
+ maSharedItemsModel.mbHasNonDate = rAttribs.getBool( XML_containsNonDate, true );
+ maSharedItemsModel.mbHasDate = rAttribs.getBool( XML_containsDate, false );
+ maSharedItemsModel.mbHasString = rAttribs.getBool( XML_containsString, true );
+ maSharedItemsModel.mbHasBlank = rAttribs.getBool( XML_containsBlank, false );
+ maSharedItemsModel.mbHasMixed = rAttribs.getBool( XML_containsMixedTypes, false );
+ maSharedItemsModel.mbIsNumeric = rAttribs.getBool( XML_containsNumber, false );
+ maSharedItemsModel.mbIsInteger = rAttribs.getBool( XML_containsInteger, false );
+ maSharedItemsModel.mbHasLongText = rAttribs.getBool( XML_longText, false );
+}
+
+void PivotCacheField::importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ maSharedItems.importItem( nElement, rAttribs );
+}
+
+void PivotCacheField::importFieldGroup( const AttributeList& rAttribs )
+{
+ maFieldGroupModel.mnParentField = rAttribs.getInteger( XML_par, -1 );
+ maFieldGroupModel.mnBaseField = rAttribs.getInteger( XML_base, -1 );
+}
+
+void PivotCacheField::importRangePr( const AttributeList& rAttribs )
+{
+ maFieldGroupModel.maStartDate = rAttribs.getDateTime( XML_startDate, DateTime() );
+ maFieldGroupModel.maEndDate = rAttribs.getDateTime( XML_endDate, DateTime() );
+ maFieldGroupModel.mfStartValue = rAttribs.getDouble( XML_startNum, 0.0 );
+ maFieldGroupModel.mfEndValue = rAttribs.getDouble( XML_endNum, 0.0 );
+ maFieldGroupModel.mfInterval = rAttribs.getDouble( XML_groupInterval, 1.0 );
+ maFieldGroupModel.mnGroupBy = rAttribs.getToken( XML_groupBy, XML_range );
+ maFieldGroupModel.mbRangeGroup = true;
+ maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range;
+ maFieldGroupModel.mbAutoStart = rAttribs.getBool( XML_autoStart, true );
+ maFieldGroupModel.mbAutoEnd = rAttribs.getBool( XML_autoEnd, true );
+}
+
+void PivotCacheField::importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ OSL_ENSURE( nElement == XLS_TOKEN( x ), "PivotCacheField::importDiscretePrItem - unexpected element" );
+ if( nElement == XLS_TOKEN( x ) )
+ maDiscreteItems.push_back( rAttribs.getInteger( XML_v, -1 ) );
+}
+
+void PivotCacheField::importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ maGroupItems.importItem( nElement, rAttribs );
+}
+
+void PivotCacheField::importPCDField( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags >> maFieldModel.mnNumFmtId;
+ maFieldModel.mnSqlType = rStrm.readInt16();
+ rStrm >> maFieldModel.mnHierarchy >> maFieldModel.mnLevel >> maFieldModel.mnMappingCount >> maFieldModel.maName;
+ if( getFlag( nFlags, OOBIN_PCDFIELD_HASCAPTION ) )
+ rStrm >> maFieldModel.maCaption;
+ if( getFlag( nFlags, OOBIN_PCDFIELD_HASFORMULA ) )
+ rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
+ if( maFieldModel.mnMappingCount > 0 )
+ rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
+ if( getFlag( nFlags, OOBIN_PCDFIELD_HASPROPERTYNAME ) )
+ rStrm >> maFieldModel.maPropertyName;
+
+ maFieldModel.mbDatabaseField = getFlag( nFlags, OOBIN_PCDFIELD_DATABASEFIELD );
+ maFieldModel.mbServerField = getFlag( nFlags, OOBIN_PCDFIELD_SERVERFIELD );
+ maFieldModel.mbUniqueList = !getFlag( nFlags, OOBIN_PCDFIELD_NOUNIQUEITEMS );
+ maFieldModel.mbMemberPropField = getFlag( nFlags, OOBIN_PCDFIELD_MEMBERPROPFIELD );
+}
+
+void PivotCacheField::importPCDFSharedItems( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, OOBIN_PCDFSITEMS_HASSEMIMIXED );
+ maSharedItemsModel.mbHasNonDate = getFlag( nFlags, OOBIN_PCDFSITEMS_HASNONDATE );
+ maSharedItemsModel.mbHasDate = getFlag( nFlags, OOBIN_PCDFSITEMS_HASDATE );
+ maSharedItemsModel.mbHasString = getFlag( nFlags, OOBIN_PCDFSITEMS_HASSTRING );
+ maSharedItemsModel.mbHasBlank = getFlag( nFlags, OOBIN_PCDFSITEMS_HASBLANK );
+ maSharedItemsModel.mbHasMixed = getFlag( nFlags, OOBIN_PCDFSITEMS_HASMIXED );
+ maSharedItemsModel.mbIsNumeric = getFlag( nFlags, OOBIN_PCDFSITEMS_ISNUMERIC );
+ maSharedItemsModel.mbIsInteger = getFlag( nFlags, OOBIN_PCDFSITEMS_ISINTEGER );
+ maSharedItemsModel.mbHasLongText = getFlag( nFlags, OOBIN_PCDFSITEMS_HASLONGTEXT );
+}
+
+void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ maSharedItems.importItem( nRecId, rStrm );
+}
+
+void PivotCacheField::importPCDFieldGroup( RecordInputStream& rStrm )
+{
+ rStrm >> maFieldGroupModel.mnParentField >> maFieldGroupModel.mnBaseField;
+}
+
+void PivotCacheField::importPCDFRangePr( RecordInputStream& rStrm )
+{
+ sal_uInt8 nGroupBy, nFlags;
+ rStrm >> nGroupBy >> nFlags >> maFieldGroupModel.mfStartValue >> maFieldGroupModel.mfEndValue >> maFieldGroupModel.mfInterval;
+
+ maFieldGroupModel.setBinGroupBy( nGroupBy );
+ maFieldGroupModel.mbRangeGroup = true;
+ maFieldGroupModel.mbDateGroup = getFlag( nFlags, OOBIN_PCDFRANGEPR_DATEGROUP );
+ maFieldGroupModel.mbAutoStart = getFlag( nFlags, OOBIN_PCDFRANGEPR_AUTOSTART );
+ maFieldGroupModel.mbAutoEnd = getFlag( nFlags, OOBIN_PCDFRANGEPR_AUTOEND );
+
+ OSL_ENSURE( maFieldGroupModel.mbDateGroup == (maFieldGroupModel.mnGroupBy != XML_range), "PivotCacheField::importPCDFRangePr - wrong date flag" );
+ if( maFieldGroupModel.mbDateGroup )
+ {
+ maFieldGroupModel.maStartDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfStartValue );
+ maFieldGroupModel.maEndDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfEndValue );
+ }
+}
+
+void PivotCacheField::importPCDFDiscretePrItem( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ OSL_ENSURE( nRecId == OOBIN_ID_PCITEM_INDEX, "PivotCacheField::importPCDFDiscretePrItem - unexpected record" );
+ if( nRecId == OOBIN_ID_PCITEM_INDEX )
+ maDiscreteItems.push_back( rStrm.readInt32() );
+}
+
+void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ maGroupItems.importItem( nRecId, rStrm );
+}
+
+void PivotCacheField::importPCDField( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFlags, nGroupItems, nBaseItems, nSharedItems;
+ rStrm >> nFlags;
+ maFieldGroupModel.mnParentField = rStrm.readuInt16();
+ maFieldGroupModel.mnBaseField = rStrm.readuInt16();
+ rStrm.skip( 2 ); // number of unique items (either shared or group)
+ rStrm >> nGroupItems >> nBaseItems >> nSharedItems;
+ maFieldModel.maName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, getTextEncoding() );
+
+ maFieldModel.mbServerField = getFlag( nFlags, BIFF_PCDFIELD_SERVERFIELD );
+ maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF_PCDFIELD_NOUNIQUEITEMS );
+ maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF_PCDFIELD_HASSEMIMIXED );
+ maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF_PCDFIELD_HASNONDATE );
+ maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF_PCDFIELD_HASDATE );
+ maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF_PCDFIELD_ISNUMERIC );
+ maSharedItemsModel.mbHasLongIndexes = getFlag( nFlags, BIFF_PCDFIELD_HASLONGINDEX );
+ maFieldGroupModel.mbRangeGroup = getFlag( nFlags, BIFF_PCDFIELD_RANGEGROUP );
+
+ // in BIFF, presence of parent group field is denoted by a flag
+ if( !getFlag( nFlags, BIFF_PCDFIELD_HASPARENT ) )
+ maFieldGroupModel.mnParentField = -1;
+
+ // following PCDFSQLTYPE record contains SQL type
+ if( (rStrm.getNextRecId() == BIFF_ID_PCDFSQLTYPE) && rStrm.startNextRecord() )
+ maFieldModel.mnSqlType = rStrm.readInt16();
+
+ // read group items, if any
+ if( nGroupItems > 0 )
+ {
+ OSL_ENSURE( getFlag( nFlags, BIFF_PCDFIELD_HASITEMS ), "PivotCacheField::importPCDField - missing items flag" );
+ maGroupItems.importItemList( rStrm, nGroupItems );
+
+ sal_uInt16 nNextRecId = rStrm.getNextRecId();
+ bool bHasRangePr = nNextRecId == BIFF_ID_PCDFRANGEPR;
+ bool bHasDiscretePr = nNextRecId == BIFF_ID_PCDFDISCRETEPR;
+
+ OSL_ENSURE( bHasRangePr || bHasDiscretePr, "PivotCacheField::importPCDField - missing group properties record" );
+ OSL_ENSURE( bHasRangePr == maFieldGroupModel.mbRangeGroup, "PivotCacheField::importPCDField - invalid range grouping flag" );
+ if( bHasRangePr && rStrm.startNextRecord() )
+ importPCDFRangePr( rStrm );
+ else if( bHasDiscretePr && rStrm.startNextRecord() )
+ importPCDFDiscretePr( rStrm );
+ }
+
+ // read the shared items, if any
+ if( nSharedItems > 0 )
+ {
+ OSL_ENSURE( getFlag( nFlags, BIFF_PCDFIELD_HASITEMS ), "PivotCacheField::importPCDField - missing items flag" );
+ maSharedItems.importItemList( rStrm, nSharedItems );
+ }
+}
+
+void PivotCacheField::importPCDFRangePr( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ maFieldGroupModel.setBinGroupBy( extractValue< sal_uInt8 >( nFlags, 2, 3 ) );
+ maFieldGroupModel.mbRangeGroup = true;
+ maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range;
+ maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOSTART );
+ maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOEND );
+
+ /* Start, end, and interval are stored in 3 separate item records. Type of
+ the items is dependent on numeric/date mode. Numeric groups expect
+ three PCITEM_DOUBLE records, date groups expect two PCITEM_DATE records
+ and one PCITEM_INT record. */
+ PivotCacheItemList aLimits( *this );
+ aLimits.importItemList( rStrm, 3 );
+ OSL_ENSURE( aLimits.size() == 3, "PivotCacheField::importPCDFRangePr - missing grouping records" );
+ const PivotCacheItem* pStartValue = aLimits.getCacheItem( 0 );
+ const PivotCacheItem* pEndValue = aLimits.getCacheItem( 1 );
+ const PivotCacheItem* pInterval = aLimits.getCacheItem( 2 );
+ if( pStartValue && pEndValue && pInterval )
+ {
+ if( maFieldGroupModel.mbDateGroup )
+ {
+ bool bHasTypes = (pStartValue->getType() == XML_d) && (pEndValue->getType() == XML_d) && (pInterval->getType() == XML_i);
+ OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" );
+ if( bHasTypes )
+ {
+ maFieldGroupModel.maStartDate = pStartValue->getValue().get< DateTime >();
+ maFieldGroupModel.maEndDate = pEndValue->getValue().get< DateTime >();
+ maFieldGroupModel.mfInterval = pInterval->getValue().get< sal_Int16 >();
+ }
+ }
+ else
+ {
+ bool bHasTypes = (pStartValue->getType() == XML_n) && (pEndValue->getType() == XML_n) && (pInterval->getType() == XML_n);
+ OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" );
+ if( bHasTypes )
+ {
+ maFieldGroupModel.mfStartValue = pStartValue->getValue().get< double >();
+ maFieldGroupModel.mfEndValue = pEndValue->getValue().get< double >();
+ maFieldGroupModel.mfInterval = pInterval->getValue().get< double >();
+ }
+ }
+ }
+}
+
+void PivotCacheField::importPCDFDiscretePr( BiffInputStream& rStrm )
+{
+ sal_Int32 nCount = static_cast< sal_Int32 >( rStrm.getLength() / 2 );
+ for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
+ maDiscreteItems.push_back( rStrm.readuInt16() );
+}
+
+const PivotCacheItem* PivotCacheField::getCacheItem( sal_Int32 nItemIdx ) const
+{
+ if( hasGroupItems() )
+ return maGroupItems.getCacheItem( nItemIdx );
+ if( hasSharedItems() )
+ return maSharedItems.getCacheItem( nItemIdx );
+ return 0;
+}
+
+void PivotCacheField::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
+{
+ if( hasGroupItems() )
+ maGroupItems.getCacheItemNames( orItemNames );
+ else if( hasSharedItems() )
+ maSharedItems.getCacheItemNames( orItemNames );
+}
+
+void PivotCacheField::convertNumericGrouping( const Reference< XDataPilotField >& rxDPField ) const
+{
+ OSL_ENSURE( hasGroupItems() && hasNumericGrouping(), "PivotCacheField::convertNumericGrouping - not a numeric group field" );
+ PropertySet aPropSet( rxDPField );
+ if( hasGroupItems() && hasNumericGrouping() && aPropSet.is() )
+ {
+ DataPilotFieldGroupInfo aGroupInfo;
+ aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
+ aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
+ aGroupInfo.HasDateValues = sal_False;
+ aGroupInfo.Start = maFieldGroupModel.mfStartValue;
+ aGroupInfo.End = maFieldGroupModel.mfEndValue;
+ aGroupInfo.Step = maFieldGroupModel.mfInterval;
+ aGroupInfo.GroupBy = 0;
+ aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
+ }
+}
+
+OUString PivotCacheField::createDateGroupField( const Reference< XDataPilotField >& rxBaseDPField ) const
+{
+ OSL_ENSURE( hasGroupItems() && hasDateGrouping(), "PivotCacheField::createDateGroupField - not a numeric group field" );
+ Reference< XDataPilotField > xDPGroupField;
+ PropertySet aPropSet( rxBaseDPField );
+ if( hasGroupItems() && hasDateGrouping() && aPropSet.is() )
+ {
+ bool bDayRanges = (maFieldGroupModel.mnGroupBy == XML_days) && (maFieldGroupModel.mfInterval >= 2.0);
+
+ DataPilotFieldGroupInfo aGroupInfo;
+ aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
+ aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
+ aGroupInfo.HasDateValues = sal_True;
+ aGroupInfo.Start = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maStartDate );
+ aGroupInfo.End = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maEndDate );
+ aGroupInfo.Step = bDayRanges ? maFieldGroupModel.mfInterval : 0.0;
+
+ using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
+ switch( maFieldGroupModel.mnGroupBy )
+ {
+ case XML_years: aGroupInfo.GroupBy = YEARS; break;
+ case XML_quarters: aGroupInfo.GroupBy = QUARTERS; break;
+ case XML_months: aGroupInfo.GroupBy = MONTHS; break;
+ case XML_days: aGroupInfo.GroupBy = DAYS; break;
+ case XML_hours: aGroupInfo.GroupBy = HOURS; break;
+ case XML_minutes: aGroupInfo.GroupBy = MINUTES; break;
+ case XML_seconds: aGroupInfo.GroupBy = SECONDS; break;
+ default: OSL_ENSURE( false, "PivotCacheField::convertRangeGrouping - unknown date/time interval" );
+ }
+
+ try
+ {
+ Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY_THROW );
+ xDPGroupField = xDPGrouping->createDateGroup( aGroupInfo );
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
+ return xFieldName.is() ? xFieldName->getName() : OUString();
+}
+
+OUString PivotCacheField::createParentGroupField( const Reference< XDataPilotField >& rxBaseDPField, PivotCacheGroupItemVector& orItemNames ) const
+{
+ OSL_ENSURE( hasGroupItems() && !maDiscreteItems.empty(), "PivotCacheField::createParentGroupField - not a group field" );
+ OSL_ENSURE( maDiscreteItems.size() == orItemNames.size(), "PivotCacheField::createParentGroupField - number of item names does not match grouping info" );
+ Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY );
+ if( !xDPGrouping.is() ) return OUString();
+
+ // map the group item indexes from maGroupItems to all item indexes from maDiscreteItems
+ typedef ::std::vector< sal_Int32 > GroupItemList;
+ typedef ::std::vector< GroupItemList > GroupItemMap;
+ GroupItemMap aItemMap( maGroupItems.size() );
+ for( IndexVector::const_iterator aBeg = maDiscreteItems.begin(), aIt = aBeg, aEnd = maDiscreteItems.end(); aIt != aEnd; ++aIt )
+ if( GroupItemList* pItems = ContainerHelper::getVectorElement( aItemMap, *aIt ) )
+ pItems->push_back( static_cast< sal_Int32 >( aIt - aBeg ) );
+
+ // process all groups
+ Reference< XDataPilotField > xDPGroupField;
+ for( GroupItemMap::iterator aBeg = aItemMap.begin(), aIt = aBeg, aEnd = aItemMap.end(); aIt != aEnd; ++aIt )
+ {
+ OSL_ENSURE( !aIt->empty(), "PivotCacheField::createParentGroupField - item/group should not be empty" );
+ // if the item count is greater than 1, the item is a group of items
+ if( aIt->size() > 1 )
+ {
+ /* Insert the names of the items that are part of this group. Calc
+ expects the names of the members of the field whose members are
+ grouped (which may be the names of groups too). Excel provides
+ the names of the base field items instead (no group names
+ involved). Therefore, the passed collection of current item
+ names as they are already grouped is used here to resolve the
+ item names. */
+ ::std::vector< OUString > aMembers;
+ for( GroupItemList::iterator aBeg2 = aIt->begin(), aIt2 = aBeg2, aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 )
+ if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, *aIt2 ) )
+ if( ::std::find( aMembers.begin(), aMembers.end(), pName->maGroupName ) == aMembers.end() )
+ aMembers.push_back( pName->maGroupName );
+
+ /* Check again, that this is not just a group that is not grouped
+ further with other items. */
+ if( aMembers.size() > 1 ) try
+ {
+ // only the first call of createNameGroup() returns the new field
+ Reference< XDataPilotField > xDPNewField = xDPGrouping->createNameGroup( ContainerHelper::vectorToSequence( aMembers ) );
+ OSL_ENSURE( xDPGroupField.is() != xDPNewField.is(), "PivotCacheField::createParentGroupField - missing group field" );
+ if( !xDPGroupField.is() )
+ xDPGroupField = xDPNewField;
+
+ // get current grouping info
+ DataPilotFieldGroupInfo aGroupInfo;
+ PropertySet aPropSet( xDPGroupField );
+ aPropSet.getProperty( aGroupInfo, PROP_GroupInfo );
+
+ /* Find the group object and the auto-generated group name.
+ The returned field contains all groups derived from the
+ previous field if that is grouped too. To find the correct
+ group, the first item used to create the group is serached.
+ Calc provides the original item names of the base field
+ when the group is querried for its members. Its does not
+ provide the names of members that are already groups in the
+ field used to create the new groups. (Is this a bug?)
+ Therefore, a name from the passed list of original item
+ names is used to find the correct group. */
+ OUString aFirstItem;
+ if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, aIt->front() ) )
+ aFirstItem = pName->maOrigName;
+ Reference< XNamed > xGroupName;
+ OUString aAutoName;
+ Reference< XIndexAccess > xGroupsIA( aGroupInfo.Groups, UNO_QUERY_THROW );
+ for( sal_Int32 nIdx = 0, nCount = xGroupsIA->getCount(); (nIdx < nCount) && (aAutoName.getLength() == 0); ++nIdx ) try
+ {
+ Reference< XNameAccess > xItemsNA( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
+ if( xItemsNA->hasByName( aFirstItem ) )
+ {
+ xGroupName.set( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
+ aAutoName = xGroupName->getName();
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( aAutoName.getLength() > 0, "PivotCacheField::createParentGroupField - cannot find auto-generated group name" );
+
+ // get the real group name from the list of group items
+ OUString aGroupName;
+ if( const PivotCacheItem* pGroupItem = maGroupItems.getCacheItem( static_cast< sal_Int32 >( aIt - aBeg ) ) )
+ aGroupName = pGroupItem->getName();
+ OSL_ENSURE( aGroupName.getLength() > 0, "PivotCacheField::createParentGroupField - cannot find group name" );
+ if( aGroupName.getLength() == 0 )
+ aGroupName = aAutoName;
+
+ if( xGroupName.is() && (aGroupName.getLength() > 0) )
+ {
+ // replace the auto-generated group name with the real name
+ if( aAutoName != aGroupName )
+ {
+ xGroupName->setName( aGroupName );
+ aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
+ }
+ // replace original item names in passed vector with group name
+ for( GroupItemList::iterator aIt2 = aIt->begin(), aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 )
+ if( PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, *aIt2 ) )
+ pName->maGroupName = aGroupName;
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ }
+
+ Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
+ return xFieldName.is() ? xFieldName->getName() : OUString();
+}
+
+void PivotCacheField::writeSourceHeaderCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ rSheetHelper.setStringCell( rSheetHelper.getCell( CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow ) ), maFieldModel.maName );
+}
+
+void PivotCacheField::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
+{
+ bool bHasIndex = rItem.getType() == XML_x;
+ OSL_ENSURE( bHasIndex != maSharedItems.empty(), "PivotCacheField::writeSourceDataCell - shared items missing or not expected" );
+ if( bHasIndex )
+ writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem.getValue().get< sal_Int32 >() );
+ else
+ writeItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem );
+}
+
+void PivotCacheField::importPCRecordItem( RecordInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ if( hasSharedItems() )
+ {
+ writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rStrm.readInt32() );
+ }
+ else
+ {
+ PivotCacheItem aItem;
+ if( maSharedItemsModel.mbIsNumeric )
+ aItem.readDouble( rStrm );
+ else if( maSharedItemsModel.mbHasDate && !maSharedItemsModel.mbHasString )
+ aItem.readDate( rStrm );
+ else
+ aItem.readString( rStrm );
+ writeItemToSourceDataCell( rSheetHelper, nCol, nRow, aItem );
+ }
+}
+
+void PivotCacheField::importPCItemIndex( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ OSL_ENSURE( hasSharedItems(), "PivotCacheField::importPCItemIndex - invalid call, no shared items found" );
+ sal_Int32 nIndex = maSharedItemsModel.mbHasLongIndexes ? rStrm.readuInt16() : rStrm.readuInt8();
+ writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, nIndex );
+}
+
+// private --------------------------------------------------------------------
+
+void PivotCacheField::writeItemToSourceDataCell( WorksheetHelper& rSheetHelper,
+ sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
+{
+ if( rItem.getType() != XML_m )
+ {
+ Reference< XCell > xCell = rSheetHelper.getCell( CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow ) );
+ if( xCell.is() ) switch( rItem.getType() )
+ {
+ case XML_s: rSheetHelper.setStringCell( xCell, rItem.getValue().get< OUString >() ); break;
+ case XML_n: xCell->setValue( rItem.getValue().get< double >() ); break;
+ case XML_i: xCell->setValue( rItem.getValue().get< sal_Int16 >() ); break;
+ case XML_d: rSheetHelper.setDateTimeCell( xCell, rItem.getValue().get< DateTime >() ); break;
+ case XML_b: rSheetHelper.setBooleanCell( xCell, rItem.getValue().get< bool >() ); break;
+ case XML_e: rSheetHelper.setErrorCell( xCell, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break;
+ default: OSL_ENSURE( false, "PivotCacheField::writeItemToSourceDataCell - unexpected item data type" );
+ }
+ }
+}
+
+void PivotCacheField::writeSharedItemToSourceDataCell(
+ WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const
+{
+ if( const PivotCacheItem* pCacheItem = maSharedItems.getCacheItem( nItemIdx ) )
+ writeItemToSourceDataCell( rSheetHelper, nCol, nRow, *pCacheItem );
+}
+
+// ============================================================================
+
+PCDefinitionModel::PCDefinitionModel() :
+ mfRefreshedDate( 0.0 ),
+ mnRecords( 0 ),
+ mnMissItemsLimit( 0 ),
+ mnDatabaseFields( 0 ),
+ mbInvalid( false ),
+ mbSaveData( true ),
+ mbRefreshOnLoad( false ),
+ mbOptimizeMemory( false ),
+ mbEnableRefresh( true ),
+ mbBackgroundQuery( false ),
+ mbUpgradeOnRefresh( false ),
+ mbTupleCache( false ),
+ mbSupportSubquery( false ),
+ mbSupportDrill( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PCSourceModel::PCSourceModel() :
+ mnSourceType( XML_TOKEN_INVALID ),
+ mnConnectionId( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PCWorksheetSourceModel::PCWorksheetSourceModel()
+{
+ maRange.StartColumn = maRange.StartRow = maRange.EndColumn = maRange.EndRow = -1;
+}
+
+// ----------------------------------------------------------------------------
+
+PivotCache::PivotCache( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mbValidSource( false ),
+ mbDummySheet( false )
+{
+}
+
+void PivotCache::importPivotCacheDefinition( const AttributeList& rAttribs )
+{
+ maDefModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
+ maDefModel.maRefreshedBy = rAttribs.getXString( XML_refreshedBy, OUString() );
+ maDefModel.mfRefreshedDate = rAttribs.getDouble( XML_refreshedDate, 0.0 );
+ maDefModel.mnRecords = rAttribs.getInteger( XML_recordCount, 0 );
+ maDefModel.mnMissItemsLimit = rAttribs.getInteger( XML_missingItemsLimit, 0 );
+ maDefModel.mbInvalid = rAttribs.getBool( XML_invalid, false );
+ maDefModel.mbSaveData = rAttribs.getBool( XML_saveData, true );
+ maDefModel.mbRefreshOnLoad = rAttribs.getBool( XML_refreshOnLoad, false );
+ maDefModel.mbOptimizeMemory = rAttribs.getBool( XML_optimizeMemory, false );
+ maDefModel.mbEnableRefresh = rAttribs.getBool( XML_enableRefresh, true );
+ maDefModel.mbBackgroundQuery = rAttribs.getBool( XML_backgroundQuery, false );
+ maDefModel.mbUpgradeOnRefresh = rAttribs.getBool( XML_upgradeOnRefresh, false );
+ maDefModel.mbTupleCache = rAttribs.getBool( XML_tupleCache, false );
+ maDefModel.mbSupportSubquery = rAttribs.getBool( XML_supportSubquery, false );
+ maDefModel.mbSupportDrill = rAttribs.getBool( XML_supportAdvancedDrill, false );
+}
+
+void PivotCache::importCacheSource( const AttributeList& rAttribs )
+{
+ maSourceModel.mnSourceType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
+ maSourceModel.mnConnectionId = rAttribs.getInteger( XML_connectionId, 0 );
+}
+
+void PivotCache::importWorksheetSource( const AttributeList& rAttribs, const Relations& rRelations )
+{
+ maSheetSrcModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
+ maSheetSrcModel.maSheet = rAttribs.getXString( XML_sheet, OUString() );
+ maSheetSrcModel.maDefName = rAttribs.getXString( XML_name, OUString() );
+
+ // resolve URL of external document
+ maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
+ // store range address unchecked with sheet index 0, will be resolved/checked later
+ getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, rAttribs.getString( XML_ref, OUString() ), 0 );
+}
+
+void PivotCache::importPCDefinition( RecordInputStream& rStrm )
+{
+ sal_uInt8 nFlags1, nFlags2;
+ rStrm.skip( 3 ); // create/refresh version id's
+ rStrm >> nFlags1 >> maDefModel.mnMissItemsLimit >> maDefModel.mfRefreshedDate >> nFlags2 >> maDefModel.mnRecords;
+ if( getFlag( nFlags2, OOBIN_PCDEFINITION_HASUSERNAME ) )
+ rStrm >> maDefModel.maRefreshedBy;
+ if( getFlag( nFlags2, OOBIN_PCDEFINITION_HASRELID ) )
+ rStrm >> maDefModel.maRelId;
+
+ maDefModel.mbInvalid = getFlag( nFlags1, OOBIN_PCDEFINITION_INVALID );
+ maDefModel.mbSaveData = getFlag( nFlags1, OOBIN_PCDEFINITION_SAVEDATA );
+ maDefModel.mbRefreshOnLoad = getFlag( nFlags1, OOBIN_PCDEFINITION_REFRESHONLOAD );
+ maDefModel.mbOptimizeMemory = getFlag( nFlags1, OOBIN_PCDEFINITION_OPTIMIZEMEMORY );
+ maDefModel.mbEnableRefresh = getFlag( nFlags1, OOBIN_PCDEFINITION_ENABLEREFRESH );
+ maDefModel.mbBackgroundQuery = getFlag( nFlags1, OOBIN_PCDEFINITION_BACKGROUNDQUERY );
+ maDefModel.mbUpgradeOnRefresh = getFlag( nFlags1, OOBIN_PCDEFINITION_UPGRADEONREFR );
+ maDefModel.mbTupleCache = getFlag( nFlags1, OOBIN_PCDEFINITION_TUPELCACHE );
+ maDefModel.mbSupportSubquery = getFlag( nFlags2, OOBIN_PCDEFINITION_SUPPORTSUBQUERY );
+ maDefModel.mbSupportDrill = getFlag( nFlags2, OOBIN_PCDEFINITION_SUPPORTDRILL );
+}
+
+void PivotCache::importPCDSource( RecordInputStream& rStrm )
+{
+ sal_Int32 nSourceType;
+ rStrm >> nSourceType >> maSourceModel.mnConnectionId;
+ static const sal_Int32 spnSourceTypes[] = { XML_worksheet, XML_external, XML_consolidation, XML_scenario };
+ maSourceModel.mnSourceType = STATIC_ARRAY_SELECT( spnSourceTypes, nSourceType, XML_TOKEN_INVALID );
+}
+
+void PivotCache::importPCDSheetSource( RecordInputStream& rStrm, const Relations& rRelations )
+{
+ sal_uInt8 nIsDefName, nIsBuiltinName, nFlags;
+ rStrm >> nIsDefName >> nIsBuiltinName >> nFlags;
+ if( getFlag( nFlags, OOBIN_PCDWBSOURCE_HASSHEET ) )
+ rStrm >> maSheetSrcModel.maSheet;
+ if( getFlag( nFlags, OOBIN_PCDWBSOURCE_HASRELID ) )
+ rStrm >> maSheetSrcModel.maRelId;
+
+ // read cell range or defined name
+ if( nIsDefName == 0 )
+ {
+ BinRange aBinRange;
+ rStrm >> aBinRange;
+ // store range address unchecked with sheet index 0, will be resolved/checked later
+ getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
+ }
+ else
+ {
+ rStrm >> maSheetSrcModel.maDefName;
+ if( nIsBuiltinName != 0 )
+ maSheetSrcModel.maDefName = CREATE_OUSTRING( "_xlnm." ) + maSheetSrcModel.maDefName;
+ }
+
+ // resolve URL of external document
+ maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
+}
+
+void PivotCache::importPCDSource( BiffInputStream& rStrm )
+{
+ switch( rStrm.readuInt16() )
+ {
+ case BIFF_PCDSOURCE_WORKSHEET:
+ {
+ maSourceModel.mnSourceType = XML_worksheet;
+ sal_uInt16 nNextRecId = rStrm.getNextRecId();
+ switch( nNextRecId )
+ {
+ case BIFF_ID_DCONREF: if( rStrm.startNextRecord() ) importDConRef( rStrm ); break;
+ case BIFF_ID_DCONNAME: if( rStrm.startNextRecord() ) importDConName( rStrm ); break;
+ case BIFF_ID_DCONBINAME: if( rStrm.startNextRecord() ) importDConBIName( rStrm ); break;
+ }
+ }
+ break;
+ case BIFF_PCDSOURCE_EXTERNAL:
+ maSourceModel.mnSourceType = XML_external;
+ break;
+ case BIFF_PCDSOURCE_CONSOLIDATION:
+ maSourceModel.mnSourceType = XML_consolidation;
+ break;
+ case BIFF_PCDSOURCE_SCENARIO:
+ maSourceModel.mnSourceType = XML_scenario;
+ break;
+ default:
+ maSourceModel.mnSourceType = XML_TOKEN_INVALID;
+ }
+}
+
+void PivotCache::importPCDefinition( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFlags, nUserNameLen;
+ rStrm >> maDefModel.mnRecords;
+ rStrm.skip( 2 ); // repeated cache ID
+ rStrm >> nFlags;
+ rStrm.skip( 2 ); // unused
+ rStrm >> maDefModel.mnDatabaseFields;
+ rStrm.skip( 6 ); // total field count, report record count, (repeated) cache type
+ rStrm >> nUserNameLen;
+ if( nUserNameLen != BIFF_PC_NOSTRING )
+ maDefModel.maRefreshedBy = (getBiff() == BIFF8) ?
+ rStrm.readUniString( nUserNameLen ) :
+ rStrm.readCharArrayUC( nUserNameLen, getTextEncoding() );
+
+ maDefModel.mbInvalid = getFlag( nFlags, BIFF_PCDEFINITION_INVALID );
+ maDefModel.mbSaveData = getFlag( nFlags, BIFF_PCDEFINITION_SAVEDATA );
+ maDefModel.mbRefreshOnLoad = getFlag( nFlags, BIFF_PCDEFINITION_REFRESHONLOAD );
+ maDefModel.mbOptimizeMemory = getFlag( nFlags, BIFF_PCDEFINITION_OPTIMIZEMEMORY );
+ maDefModel.mbEnableRefresh = getFlag( nFlags, BIFF_PCDEFINITION_ENABLEREFRESH );
+ maDefModel.mbBackgroundQuery = getFlag( nFlags, BIFF_PCDEFINITION_BACKGROUNDQUERY );
+
+ if( (rStrm.getNextRecId() == BIFF_ID_PCDEFINITION2) && rStrm.startNextRecord() )
+ rStrm >> maDefModel.mfRefreshedDate;
+}
+
+PivotCacheField& PivotCache::createCacheField( bool bInitDatabaseField )
+{
+ bool bIsDatabaseField = !bInitDatabaseField || (maFields.size() < maDefModel.mnDatabaseFields);
+ PivotCacheFieldVector::value_type xCacheField( new PivotCacheField( *this, bIsDatabaseField ) );
+ maFields.push_back( xCacheField );
+ return *xCacheField;
+}
+
+void PivotCache::finalizeImport()
+{
+ // collect all fields that are based on source data (needed to finalize source data below)
+ OSL_ENSURE( !maFields.empty(), "PivotCache::finalizeImport - no pivot cache fields found" );
+ for( PivotCacheFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt )
+ {
+ if( (*aIt)->isDatabaseField() )
+ {
+ OSL_ENSURE( (aIt == maFields.begin()) || (*(aIt - 1))->isDatabaseField(),
+ "PivotCache::finalizeImport - database field follows a calculated field" );
+ maDatabaseIndexes.push_back( static_cast< sal_Int32 >( maDatabaseFields.size() ) );
+ maDatabaseFields.push_back( *aIt );
+ }
+ else
+ {
+ maDatabaseIndexes.push_back( -1 );
+ }
+ }
+ OSL_ENSURE( !maDatabaseFields.empty(), "PivotCache::finalizeImport - no pivot cache source fields found" );
+
+ // finalize source data depending on source type
+ switch( maSourceModel.mnSourceType )
+ {
+ case XML_worksheet:
+ {
+ // decide whether an external document is used
+ bool bInternal = (maTargetUrl.getLength() == 0) && (maSheetSrcModel.maRelId.getLength() == 0);
+ bool bExternal = maTargetUrl.getLength() > 0; // relation ID may be empty, e.g. BIFF import
+ OSL_ENSURE( bInternal || bExternal, "PivotCache::finalizeImport - invalid external document URL" );
+ if( bInternal )
+ finalizeInternalSheetSource();
+ else if( bExternal )
+ finalizeExternalSheetSource();
+ }
+ break;
+
+ // currently, we only support worksheet data sources
+ case XML_external:
+ break;
+ case XML_consolidation:
+ break;
+ case XML_scenario:
+ break;
+ }
+}
+
+sal_Int32 PivotCache::getCacheFieldCount() const
+{
+ return static_cast< sal_Int32 >( maFields.size() );
+}
+
+const PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx ) const
+{
+ return maFields.get( nFieldIdx ).get();
+}
+
+sal_Int32 PivotCache::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const
+{
+ return ContainerHelper::getVectorElement< sal_Int32 >( maDatabaseIndexes, nFieldIdx, -1 );
+}
+
+void PivotCache::writeSourceHeaderCells( WorksheetHelper& rSheetHelper ) const
+{
+ OSL_ENSURE( static_cast< size_t >( maSheetSrcModel.maRange.EndColumn - maSheetSrcModel.maRange.StartColumn + 1 ) == maDatabaseFields.size(),
+ "PivotCache::writeSourceHeaderCells - source cell range width does not match number of source fields" );
+ sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
+ sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
+ sal_Int32 nRow = maSheetSrcModel.maRange.StartRow;
+ for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
+ (*aIt)->writeSourceHeaderCell( rSheetHelper, nCol, nRow );
+}
+
+void PivotCache::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
+{
+ OSL_ENSURE( (0 <= nCol) && (nCol <= maSheetSrcModel.maRange.EndColumn - maSheetSrcModel.maRange.StartColumn), "PivotCache::writeSourceDataCell - invalid column index" );
+ OSL_ENSURE( (0 < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow - maSheetSrcModel.maRange.StartRow), "PivotCache::writeSourceDataCell - invalid row index" );
+ if( const PivotCacheField* pCacheField = maDatabaseFields.get( nCol ).get() )
+ pCacheField->writeSourceDataCell( rSheetHelper, maSheetSrcModel.maRange.StartColumn + nCol, maSheetSrcModel.maRange.StartRow + nRow, rItem );
+}
+
+void PivotCache::importPCRecord( RecordInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const
+{
+ OSL_ENSURE( (0 < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow - maSheetSrcModel.maRange.StartRow), "PivotCache::importPCRecord - invalid row index" );
+ sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
+ sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
+ nRow += maSheetSrcModel.maRange.StartRow;
+ for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
+ (*aIt)->importPCRecordItem( rStrm, rSheetHelper, nCol, nRow );
+}
+
+void PivotCache::importPCItemIndexList( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const
+{
+ OSL_ENSURE( (0 < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow - maSheetSrcModel.maRange.StartRow), "PivotCache::importPCItemIndexList - invalid row index" );
+ sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
+ sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
+ nRow += maSheetSrcModel.maRange.StartRow;
+ for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
+ if( (*aIt)->hasSharedItems() )
+ (*aIt)->importPCItemIndex( rStrm, rSheetHelper, nCol, nRow );
+}
+
+// private --------------------------------------------------------------------
+
+void PivotCache::importDConRef( BiffInputStream& rStrm )
+{
+ BinRange aBinRange;
+ aBinRange.read( rStrm, false ); // always 8-bit column indexes
+ // store range address unchecked with sheet index 0, will be resolved/checked later
+ getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
+
+ // the URL with (required) sheet name and optional URL of an external document
+ importDConUrl( rStrm );
+ OSL_ENSURE( maSheetSrcModel.maSheet.getLength() > 0, "PivotCache::importDConRef - missing sheet name" );
+}
+
+void PivotCache::importDConName( BiffInputStream& rStrm )
+{
+ maSheetSrcModel.maDefName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
+ OSL_ENSURE( maSheetSrcModel.maDefName.getLength() > 0, "PivotCache::importDConName - missing defined name" );
+ importDConUrl( rStrm );
+}
+
+void PivotCache::importDConBIName( BiffInputStream& rStrm )
+{
+ sal_uInt8 nNameId = rStrm.readuInt8();
+ rStrm.skip( 3 );
+ maSheetSrcModel.maDefName = OUString( sal_Unicode( nNameId ) );
+ importDConUrl( rStrm );
+}
+
+void PivotCache::importDConUrl( BiffInputStream& rStrm )
+{
+ // the URL with sheet name and optional URL of an external document
+ OUString aEncodedUrl;
+ if( getBiff() == BIFF8 )
+ {
+ // empty string does not contain a flags byte, cannot use simple readUniString() here...
+ sal_uInt16 nChars = rStrm.readuInt16();
+ if( nChars > 0 )
+ aEncodedUrl = rStrm.readUniString( nChars );
+ }
+ else
+ {
+ aEncodedUrl = rStrm.readByteStringUC( false, getTextEncoding() );
+ }
+
+ if( aEncodedUrl.getLength() > 0 )
+ {
+ OUString aClassName;
+ getAddressConverter().parseBiffTargetUrl( aClassName, maTargetUrl, maSheetSrcModel.maSheet, aEncodedUrl, true );
+ }
+}
+
+void PivotCache::finalizeInternalSheetSource()
+{
+ // resolve sheet name to sheet index
+ sal_Int16 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet );
+
+ // if cache is based on a defined name or table, try to resolve to cell range
+ if( maSheetSrcModel.maDefName.getLength() > 0 )
+ {
+ // local or global defined name
+ if( const DefinedName* pDefName = getDefinedNames().getByModelName( maSheetSrcModel.maDefName, nSheet ).get() )
+ {
+ mbValidSource = pDefName->getAbsoluteRange( maSheetSrcModel.maRange );
+ }
+ // table
+ else if( const Table* pTable = getTables().getTable( maSheetSrcModel.maDefName ).get() )
+ {
+ // get original range from table, but exclude the totals row(s)
+ maSheetSrcModel.maRange = pTable->getOriginalRange();
+ mbValidSource = (pTable->getHeight() - pTable->getTotalsRows()) > 1;
+ if( mbValidSource )
+ maSheetSrcModel.maRange.EndRow -= pTable->getTotalsRows();
+ }
+ }
+ // else try the cell range (if the sheet exists)
+ else if( nSheet >= 0 )
+ {
+ // insert sheet index into the range, range address will be checked below
+ maSheetSrcModel.maRange.Sheet = nSheet;
+ mbValidSource = true;
+ }
+ // else sheet has been deleted, generate the source data from cache
+ else if( maSheetSrcModel.maSheet.getLength() > 0 )
+ {
+ prepareSourceDataSheet();
+ // return here to skip the source range check below
+ return;
+ }
+
+ // check range location, do not allow ranges that overflow the sheet partly
+ mbValidSource = mbValidSource &&
+ getAddressConverter().checkCellRange( maSheetSrcModel.maRange, false, true ) &&
+ (maSheetSrcModel.maRange.StartRow < maSheetSrcModel.maRange.EndRow);
+}
+
+void PivotCache::finalizeExternalSheetSource()
+{
+ /* If pivot cache is based on external sheet data, try to restore sheet
+ data from cache records. No support for external defined names or tables,
+ sheet name and path to cache records fragment (OOX only) are required. */
+ bool bHasRelation = (getFilterType() == FILTER_BIFF) || (maDefModel.maRelId.getLength() > 0);
+ if( bHasRelation && (maSheetSrcModel.maDefName.getLength() == 0) && (maSheetSrcModel.maSheet.getLength() > 0) )
+ prepareSourceDataSheet();
+}
+
+void PivotCache::prepareSourceDataSheet()
+{
+ // data will be inserted in top-left cell, sheet index is still set to 0 (will be set below)
+ maSheetSrcModel.maRange.EndColumn -= maSheetSrcModel.maRange.StartColumn;
+ maSheetSrcModel.maRange.StartColumn = 0;
+ maSheetSrcModel.maRange.EndRow -= maSheetSrcModel.maRange.StartRow;
+ maSheetSrcModel.maRange.StartRow = 0;
+ // check range location, do not allow ranges that overflow the sheet partly
+ if( getAddressConverter().checkCellRange( maSheetSrcModel.maRange, false, true ) )
+ {
+ OUString aSheetName = CREATE_OUSTRING( "DPCache_" ) + maSheetSrcModel.maSheet;
+ maSheetSrcModel.maRange.Sheet = getWorksheets().insertEmptySheet( aSheetName, false );
+ mbValidSource = mbDummySheet = maSheetSrcModel.maRange.Sheet >= 0;
+ }
+}
+
+// ============================================================================
+
+PivotCacheBuffer::PivotCacheBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void PivotCacheBuffer::registerPivotCacheFragment( sal_Int32 nCacheId, const OUString& rFragmentPath )
+{
+ OSL_ENSURE( nCacheId >= 0, "PivotCacheBuffer::registerPivotCacheFragment - invalid pivot cache identifier" );
+ OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::registerPivotCacheFragment - fragment path exists already" );
+ if( (nCacheId >= 0) && (rFragmentPath.getLength() > 0) )
+ maFragmentPaths[ nCacheId ] = rFragmentPath;
+}
+
+void PivotCacheBuffer::importPivotCacheRef( BiffInputStream& rStrm )
+{
+ // read the PIVOTCACHE record that contains the stream ID
+ sal_Int32 nCacheId = rStrm.readuInt16();
+ OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::importPivotCacheRef - cache stream exists already" );
+ OUStringBuffer aStrmName;
+ static const sal_Unicode spcHexChars[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
+ for( sal_uInt8 nBit = 0; nBit < 16; nBit += 4 )
+ aStrmName.insert( 0, spcHexChars[ extractValue< size_t >( nCacheId, nBit, 4 ) ] );
+ aStrmName.insert( 0, (getBiff() == BIFF8) ? CREATE_OUSTRING( "_SX_DB_CUR/" ) : CREATE_OUSTRING( "_SX_DB/" ) );
+ maFragmentPaths[ nCacheId ] = aStrmName.makeStringAndClear();
+
+ // try to read PCDSOURCE record (will read following data location records too)
+ sal_uInt16 nNextRecId = rStrm.getNextRecId();
+ OSL_ENSURE( nNextRecId == BIFF_ID_PCDSOURCE, "PivotCacheBuffer::importPivotCacheRef - PCDSOURCE record expected" );
+ if( (nNextRecId == BIFF_ID_PCDSOURCE) && rStrm.startNextRecord() )
+ createPivotCache( nCacheId ).importPCDSource( rStrm );
+}
+
+PivotCache* PivotCacheBuffer::importPivotCacheFragment( sal_Int32 nCacheId )
+{
+ switch( getFilterType() )
+ {
+ /* BIFF filter: Pivot table provides 0-based index into list of pivot
+ cache source links (PIVOTCACHE/PCDSOURCE/... record blocks in
+ workbook stream). First, this index has to be resolved to the cache
+ identifier that is used to manage the cache stream names (the
+ maFragmentPaths member). The cache object itself exists already
+ before the first call for the cache source index (see
+ PivotCacheBuffer::importPivotCacheRef() above), because source data
+ link is part of workbook data, not of the cache stream. To detect
+ subsequent calls with an already initialized cache, the entry in
+ maFragmentPaths will be removed after reading the cache stream. */
+ case FILTER_BIFF:
+ {
+ /* Resolve cache index to cache identifier and try to find pivot
+ cache. Cache must exist already for a valid cache index. */
+ nCacheId = ContainerHelper::getVectorElement< sal_Int32 >( maCacheIds, nCacheId, -1 );
+ PivotCache* pCache = maCaches.get( nCacheId ).get();
+ if( !pCache )
+ return 0;
+
+ /* Try to find fragment path entry (stream name). If missing, the
+ stream has been read already, and the cache can be returned. */
+ FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
+ if( aIt != maFragmentPaths.end() )
+ {
+ /* Import the cache stream. This may create a dummy data sheet
+ for external sheet sources. */
+ BiffPivotCacheFragment( *this, aIt->second, *pCache ).importFragment();
+ // remove the fragment entry to mark that the cache is initialized
+ maFragmentPaths.erase( aIt );
+ }
+ return pCache;
+ }
+
+ /* OOX/OOBIN filter: On first call for the cache ID, the pivot cache
+ object is created and inserted into maCaches. Then, the cache
+ definition fragment is read and the cache is returned. On
+ subsequent calls, the created cache will be found in maCaches and
+ returned immediately. */
+ case FILTER_OOX:
+ {
+ // try to find an imported pivot cache
+ if( PivotCache* pCache = maCaches.get( nCacheId ).get() )
+ return pCache;
+
+ // check if a fragment path exists for the passed cache identifier
+ FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
+ if( aIt == maFragmentPaths.end() )
+ return 0;
+
+ /* Import the cache fragment. This may create a dummy data sheet
+ for external sheet sources. */
+ PivotCache& rCache = createPivotCache( nCacheId );
+ importOoxFragment( new OoxPivotCacheDefinitionFragment( *this, aIt->second, rCache ) );
+ return &rCache;
+ }
+
+ case FILTER_UNKNOWN:
+ OSL_ENSURE( false, "PivotCacheBuffer::importPivotCacheFragment - unknown filter type" );
+ }
+ return 0;
+}
+
+PivotCache& PivotCacheBuffer::createPivotCache( sal_Int32 nCacheId )
+{
+ maCacheIds.push_back( nCacheId );
+ PivotCacheMap::mapped_type& rxCache = maCaches[ nCacheId ];
+ rxCache.reset( new PivotCache( *this ) );
+ return *rxCache;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/pivotcachefragment.cxx b/oox/source/xls/pivotcachefragment.cxx
new file mode 100644
index 000000000000..9800ebb6e567
--- /dev/null
+++ b/oox/source/xls/pivotcachefragment.cxx
@@ -0,0 +1,467 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/pivotcachefragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/pivotcachebuffer.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxPivotCacheFieldContext::OoxPivotCacheFieldContext( OoxWorkbookFragmentBase& rFragment, PivotCacheField& rCacheField ) :
+ OoxWorkbookContextBase( rFragment ),
+ mrCacheField( rCacheField )
+{
+}
+
+ContextHandlerRef OoxPivotCacheFieldContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( cacheField ):
+ if( nElement == XLS_TOKEN( sharedItems ) ) { mrCacheField.importSharedItems( rAttribs ); return this; }
+ if( nElement == XLS_TOKEN( fieldGroup ) ) { mrCacheField.importFieldGroup( rAttribs ); return this; }
+ break;
+
+ case XLS_TOKEN( fieldGroup ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( rangePr ): mrCacheField.importRangePr( rAttribs ); break;
+ case XLS_TOKEN( discretePr ): return this;
+ case XLS_TOKEN( groupItems ): return this;
+ }
+ break;
+
+ case XLS_TOKEN( sharedItems ): mrCacheField.importSharedItem( nElement, rAttribs ); break;
+ case XLS_TOKEN( discretePr ): mrCacheField.importDiscretePrItem( nElement, rAttribs ); break;
+ case XLS_TOKEN( groupItems ): mrCacheField.importGroupItem( nElement, rAttribs ); break;
+ }
+ return 0;
+}
+
+void OoxPivotCacheFieldContext::onStartElement( const AttributeList& rAttribs )
+{
+ if( isRootElement() )
+ mrCacheField.importCacheField( rAttribs );
+}
+
+ContextHandlerRef OoxPivotCacheFieldContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_PCDFIELD:
+ switch( nRecId )
+ {
+ case OOBIN_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItems( rStrm ); return this;
+ case OOBIN_ID_PCDFIELDGROUP: mrCacheField.importPCDFieldGroup( rStrm ); return this;
+ }
+ break;
+
+ case OOBIN_ID_PCDFIELDGROUP:
+ switch( nRecId )
+ {
+ case OOBIN_ID_PCDFRANGEPR: mrCacheField.importPCDFRangePr( rStrm ); break;
+ case OOBIN_ID_PCDFDISCRETEPR: return this;
+ case OOBIN_ID_PCDFGROUPITEMS: return this;
+ }
+ break;
+
+ case OOBIN_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItem( nRecId, rStrm ); break;
+ case OOBIN_ID_PCDFDISCRETEPR: mrCacheField.importPCDFDiscretePrItem( nRecId, rStrm ); break;
+ case OOBIN_ID_PCDFGROUPITEMS: mrCacheField.importPCDFGroupItem( nRecId, rStrm ); break;
+ }
+ return 0;
+}
+
+void OoxPivotCacheFieldContext::onStartRecord( RecordInputStream& rStrm )
+{
+ if( isRootElement() )
+ mrCacheField.importPCDField( rStrm );
+}
+
+// ============================================================================
+
+OoxPivotCacheDefinitionFragment::OoxPivotCacheDefinitionFragment(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath, PivotCache& rPivotCache ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath ),
+ mrPivotCache( rPivotCache )
+{
+}
+
+ContextHandlerRef OoxPivotCacheDefinitionFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( pivotCacheDefinition ) ) { mrPivotCache.importPivotCacheDefinition( rAttribs ); return this; }
+ break;
+
+ case XLS_TOKEN( pivotCacheDefinition ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( cacheSource ): mrPivotCache.importCacheSource( rAttribs ); return this;
+ case XLS_TOKEN( cacheFields ): return this;
+ }
+ break;
+
+ case XLS_TOKEN( cacheSource ):
+ if( nElement == XLS_TOKEN( worksheetSource ) ) mrPivotCache.importWorksheetSource( rAttribs, getRelations() );
+ break;
+
+ case XLS_TOKEN( cacheFields ):
+ if( nElement == XLS_TOKEN( cacheField ) ) return new OoxPivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
+ break;
+ }
+ return 0;
+}
+
+ContextHandlerRef OoxPivotCacheDefinitionFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_PCDEFINITION ) { mrPivotCache.importPCDefinition( rStrm ); return this; }
+ break;
+
+ case OOBIN_ID_PCDEFINITION:
+ switch( nRecId )
+ {
+ case OOBIN_ID_PCDSOURCE: mrPivotCache.importPCDSource( rStrm ); return this;
+ case OOBIN_ID_PCDFIELDS: return this;
+ }
+ break;
+
+ case OOBIN_ID_PCDSOURCE:
+ if( nRecId == OOBIN_ID_PCDSHEETSOURCE ) mrPivotCache.importPCDSheetSource( rStrm, getRelations() );
+ break;
+
+ case OOBIN_ID_PCDFIELDS:
+ if( nRecId == OOBIN_ID_PCDFIELD ) return new OoxPivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
+ break;
+ }
+ return 0;
+}
+
+const RecordInfo* OoxPivotCacheDefinitionFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_PCDEFINITION, OOBIN_ID_PCDEFINITION + 1 },
+ { OOBIN_ID_PCDFDISCRETEPR, OOBIN_ID_PCDFDISCRETEPR + 1 },
+ { OOBIN_ID_PCDFGROUPITEMS, OOBIN_ID_PCDFGROUPITEMS + 1 },
+ { OOBIN_ID_PCDFIELD, OOBIN_ID_PCDFIELD + 1 },
+ { OOBIN_ID_PCDFIELDGROUP, OOBIN_ID_PCDFIELDGROUP + 1 },
+ { OOBIN_ID_PCDFIELDS, OOBIN_ID_PCDFIELDS + 1 },
+ { OOBIN_ID_PCDFRANGEPR, OOBIN_ID_PCDFRANGEPR + 1 },
+ { OOBIN_ID_PCDFSHAREDITEMS, OOBIN_ID_PCDFSHAREDITEMS + 1 },
+ { OOBIN_ID_PCITEM_ARRAY, OOBIN_ID_PCITEM_ARRAY + 1 },
+ { OOBIN_ID_PCDSHEETSOURCE, OOBIN_ID_PCDSHEETSOURCE + 1 },
+ { OOBIN_ID_PCDSOURCE, OOBIN_ID_PCDSOURCE + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+void OoxPivotCacheDefinitionFragment::finalizeImport()
+{
+ // finalize the cache (check source range etc.)
+ mrPivotCache.finalizeImport();
+
+ // load the cache records, if the cache is based on a deleted or an external worksheet
+ if( mrPivotCache.isValidDataSource() && mrPivotCache.isBasedOnDummySheet() )
+ {
+ OUString aRecFragmentPath = getRelations().getFragmentPathFromRelId( mrPivotCache.getRecordsRelId() );
+ if( aRecFragmentPath.getLength() > 0 )
+ importOoxFragment( new OoxPivotCacheRecordsFragment( *this, aRecFragmentPath, mrPivotCache ) );
+ }
+}
+
+// ============================================================================
+
+OoxPivotCacheRecordsFragment::OoxPivotCacheRecordsFragment( const WorkbookHelper& rHelper,
+ const OUString& rFragmentPath, const PivotCache& rPivotCache ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath, ISegmentProgressBarRef(), SHEETTYPE_WORKSHEET, rPivotCache.getSourceRange().Sheet ),
+ mrPivotCache( rPivotCache ),
+ mnCol( 0 ),
+ mnRow( 0 ),
+ mbInRecord( false )
+{
+ // prepare sheet: insert column header names into top row
+ rPivotCache.writeSourceHeaderCells( *this );
+}
+
+ContextHandlerRef OoxPivotCacheRecordsFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( pivotCacheRecords ) ) return this;
+ break;
+
+ case XLS_TOKEN( pivotCacheRecords ):
+ if( nElement == XLS_TOKEN( r ) ) { startCacheRecord(); return this; }
+ break;
+
+ case XLS_TOKEN( r ):
+ {
+ PivotCacheItem aItem;
+ switch( nElement )
+ {
+ case XLS_TOKEN( m ): break;
+ case XLS_TOKEN( s ): aItem.readString( rAttribs ); break;
+ case XLS_TOKEN( n ): aItem.readNumeric( rAttribs ); break;
+ case XLS_TOKEN( d ): aItem.readDate( rAttribs ); break;
+ case XLS_TOKEN( b ): aItem.readBool( rAttribs ); break;
+ case XLS_TOKEN( e ): aItem.readError( rAttribs, getUnitConverter() ); break;
+ case XLS_TOKEN( x ): aItem.readIndex( rAttribs ); break;
+ default: OSL_ENSURE( false, "OoxPivotCacheRecordsFragment::onCreateContext - unexpected element" );
+ }
+ mrPivotCache.writeSourceDataCell( *this, mnCol, mnRow, aItem );
+ ++mnCol;
+ }
+ break;
+ }
+ return 0;
+}
+
+ContextHandlerRef OoxPivotCacheRecordsFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_PCRECORDS ) return this;
+ break;
+
+ case OOBIN_ID_PCRECORDS:
+ switch( nRecId )
+ {
+ case OOBIN_ID_PCRECORD: importPCRecord( rStrm ); break;
+ case OOBIN_ID_PCRECORDDT: startCacheRecord(); break;
+ default: importPCRecordItem( nRecId, rStrm ); break;
+ }
+ break;
+ }
+ return 0;
+}
+
+const RecordInfo* OoxPivotCacheRecordsFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_PCRECORDS, OOBIN_ID_PCRECORDS + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+// private --------------------------------------------------------------------
+
+void OoxPivotCacheRecordsFragment::startCacheRecord()
+{
+ mnCol = 0;
+ ++mnRow;
+ mbInRecord = true;
+}
+
+void OoxPivotCacheRecordsFragment::importPCRecord( RecordInputStream& rStrm )
+{
+ startCacheRecord();
+ mrPivotCache.importPCRecord( rStrm, *this, mnRow );
+ mbInRecord = false;
+}
+
+void OoxPivotCacheRecordsFragment::importPCRecordItem( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ if( mbInRecord )
+ {
+ PivotCacheItem aItem;
+ switch( nRecId )
+ {
+ case OOBIN_ID_PCITEM_MISSING: break;
+ case OOBIN_ID_PCITEM_STRING: aItem.readString( rStrm ); break;
+ case OOBIN_ID_PCITEM_DOUBLE: aItem.readDouble( rStrm ); break;
+ case OOBIN_ID_PCITEM_DATE: aItem.readDate( rStrm ); break;
+ case OOBIN_ID_PCITEM_BOOL: aItem.readBool( rStrm ); break;
+ case OOBIN_ID_PCITEM_ERROR: aItem.readError( rStrm ); break;
+ case OOBIN_ID_PCITEM_INDEX: aItem.readIndex( rStrm ); break;
+ default: OSL_ENSURE( false, "OoxPivotCacheRecordsFragment::importPCRecordItem - unexpected record" );
+ }
+ mrPivotCache.writeSourceDataCell( *this, mnCol, mnRow, aItem );
+ ++mnCol;
+ }
+}
+
+// ============================================================================
+// ============================================================================
+
+namespace {
+
+bool lclSeekToPCDField( BiffInputStream& rStrm )
+{
+ sal_Int64 nRecHandle = rStrm.getRecHandle();
+ while( rStrm.startNextRecord() )
+ if( rStrm.getRecId() == BIFF_ID_PCDFIELD )
+ return true;
+ rStrm.startRecordByHandle( nRecHandle );
+ return false;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+BiffPivotCacheFragment::BiffPivotCacheFragment(
+ const WorkbookHelper& rHelper, const ::rtl::OUString& rStrmName, PivotCache& rPivotCache ) :
+ BiffWorkbookFragmentBase( rHelper, rStrmName, true ),
+ mrPivotCache( rPivotCache )
+{
+}
+
+bool BiffPivotCacheFragment::importFragment()
+{
+ if( mrStrm.startNextRecord() && (mrStrm.getRecId() == BIFF_ID_PCDEFINITION) )
+ {
+ // read PCDEFINITION and optional PCDEFINITION2 records
+ mrPivotCache.importPCDefinition( mrStrm );
+
+ // read cache fields as long as another PCDFIELD record can be found
+ while( lclSeekToPCDField( mrStrm ) )
+ mrPivotCache.createCacheField( true ).importPCDField( mrStrm );
+
+ // finalize the cache (check source range etc.)
+ mrPivotCache.finalizeImport();
+
+ // load the cache records, if the cache is based on a deleted or an external worksheet
+ if( mrPivotCache.isValidDataSource() && mrPivotCache.isBasedOnDummySheet() )
+ {
+ /* Last call of lclSeekToPCDField() failed and kept stream position
+ unchanged. Stream should point to source data table now. */
+ BiffPivotCacheRecordsContext aContext( *this, mrPivotCache );
+ if( aContext.isValidSheet() )
+ while( mrStrm.startNextRecord() && (mrStrm.getRecId() != BIFF_ID_EOF) )
+ aContext.importRecord();
+ }
+ }
+
+ return mrStrm.getRecId() == BIFF_ID_EOF;
+}
+
+// ============================================================================
+
+BiffPivotCacheRecordsContext::BiffPivotCacheRecordsContext(
+ const BiffWorkbookFragmentBase& rFragment, const PivotCache& rPivotCache ) :
+ BiffWorksheetContextBase( rFragment, ISegmentProgressBarRef(), SHEETTYPE_WORKSHEET, rPivotCache.getSourceRange().Sheet ),
+ mrPivotCache( rPivotCache ),
+ mnColIdx( 0 ),
+ mnRow( 0 ),
+ mbHasShared( false ),
+ mbInRow( false )
+{
+ // prepare sheet: insert column header names into top row
+ mrPivotCache.writeSourceHeaderCells( *this );
+
+ // find all fields without shared items, remember column indexes in source data
+ for( sal_Int32 nFieldIdx = 0, nFieldCount = mrPivotCache.getCacheFieldCount(), nCol = 0; nFieldIdx < nFieldCount; ++nFieldIdx )
+ {
+ const PivotCacheField* pCacheField = mrPivotCache.getCacheField( nFieldIdx );
+ if( pCacheField && pCacheField->isDatabaseField() )
+ {
+ if( pCacheField->hasSharedItems() )
+ mbHasShared = true;
+ else
+ maUnsharedCols.push_back( nCol );
+ ++nCol;
+ }
+ }
+}
+
+void BiffPivotCacheRecordsContext::importRecord()
+{
+ if( mrStrm.getRecId() == BIFF_ID_PCITEM_INDEXLIST )
+ {
+ OSL_ENSURE( mbHasShared, "BiffPivotCacheRecordsContext::importRecord - unexpected PCITEM_INDEXLIST record" );
+ // PCITEM_INDEXLIST record always in front of a new data row
+ startNextRow();
+ mrPivotCache.importPCItemIndexList( mrStrm, *this, mnRow );
+ mbInRow = !maUnsharedCols.empty(); // mbInRow remains true, if unshared items are expected
+ return;
+ }
+
+ PivotCacheItem aItem;
+ switch( mrStrm.getRecId() )
+ {
+ case BIFF_ID_PCITEM_MISSING: break;
+ case BIFF_ID_PCITEM_STRING: aItem.readString( mrStrm, *this ); break;
+ case BIFF_ID_PCITEM_DOUBLE: aItem.readDouble( mrStrm ); break;
+ case BIFF_ID_PCITEM_INTEGER: aItem.readInteger( mrStrm ); break;
+ case BIFF_ID_PCITEM_DATE: aItem.readDate( mrStrm ); break;
+ case BIFF_ID_PCITEM_BOOL: aItem.readBool( mrStrm ); break;
+ case BIFF_ID_PCITEM_ERROR: aItem.readError( mrStrm ); break;
+ default: return; // unknown record, ignore
+ }
+
+ // find next column index, might start new row if no fields with shared items exist
+ if( mbInRow && (mnColIdx == maUnsharedCols.size()) )
+ {
+ OSL_ENSURE( !mbHasShared, "BiffPivotCacheRecordsContext::importRecord - PCITEM_INDEXLIST record missing" );
+ mbInRow = mbHasShared; // do not leave current row if PCITEM_INDEXLIST is expected
+ }
+ // start next row on first call, or on row wrap without shared items
+ if( !mbInRow )
+ startNextRow();
+
+ // write the item data to the sheet cell
+ OSL_ENSURE( mnColIdx < maUnsharedCols.size(), "BiffPivotCacheRecordsContext::importRecord - invalid column index" );
+ if( mnColIdx < maUnsharedCols.size() )
+ mrPivotCache.writeSourceDataCell( *this, maUnsharedCols[ mnColIdx ], mnRow, aItem );
+ ++mnColIdx;
+}
+
+void BiffPivotCacheRecordsContext::startNextRow()
+{
+ mnColIdx = 0;
+ ++mnRow;
+ mbInRow = true;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/pivottablebuffer.cxx b/oox/source/xls/pivottablebuffer.cxx
new file mode 100644
index 000000000000..2a6ce43a2484
--- /dev/null
+++ b/oox/source/xls/pivottablebuffer.cxx
@@ -0,0 +1,1555 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/pivottablebuffer.hxx"
+#include <set>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sheet/CellFlags.hpp>
+#include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldLayoutMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReference.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
+#include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
+#include <com/sun/star/sheet/GeneralFunction.hpp>
+#include <com/sun/star/sheet/XDataPilotDataLayoutFieldSupplier.hpp>
+#include <com/sun/star/sheet/XDataPilotField.hpp>
+#include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp>
+#include <com/sun/star/sheet/XSheetOperation.hpp>
+#include "properties.hxx"
+#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"
+
+using ::rtl::OUString;
+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 ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::sheet::DataPilotFieldOrientation;
+using ::com::sun::star::sheet::XDataPilotDataLayoutFieldSupplier;
+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::XSheetOperation;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 OOX_PT_DATALAYOUTFIELD = -2; /// Placeholder index of data layout field.
+
+const sal_Int32 OOX_PT_PREVIOUS_ITEM = 0x001000FC; /// Calculation of data item result is based on previous item.
+const sal_Int32 OOX_PT_NEXT_ITEM = 0x001000FD; /// Calculation of data item result is based on next item.
+
+// ----------------------------------------------------------------------------
+
+const sal_uInt32 OOBIN_PTFIELD_DATAFIELD = 0x00000008;
+const sal_uInt32 OOBIN_PTFIELD_DEFAULT = 0x00000100;
+const sal_uInt32 OOBIN_PTFIELD_SUM = 0x00000200;
+const sal_uInt32 OOBIN_PTFIELD_COUNTA = 0x00000400;
+const sal_uInt32 OOBIN_PTFIELD_AVERAGE = 0x00000800;
+const sal_uInt32 OOBIN_PTFIELD_MAX = 0x00001000;
+const sal_uInt32 OOBIN_PTFIELD_MIN = 0x00002000;
+const sal_uInt32 OOBIN_PTFIELD_PRODUCT = 0x00004000;
+const sal_uInt32 OOBIN_PTFIELD_COUNT = 0x00008000;
+const sal_uInt32 OOBIN_PTFIELD_STDDEV = 0x00010000;
+const sal_uInt32 OOBIN_PTFIELD_STDDEVP = 0x00020000;
+const sal_uInt32 OOBIN_PTFIELD_VAR = 0x00040000;
+const sal_uInt32 OOBIN_PTFIELD_VARP = 0x00080000;
+
+const sal_uInt32 OOBIN_PTFIELD_SHOWALL = 0x00000020;
+const sal_uInt32 OOBIN_PTFIELD_OUTLINE = 0x00000040;
+const sal_uInt32 OOBIN_PTFIELD_INSERTBLANKROW = 0x00000080;
+const sal_uInt32 OOBIN_PTFIELD_SUBTOTALTOP = 0x00000100;
+const sal_uInt32 OOBIN_PTFIELD_INSERTPAGEBREAK = 0x00000800;
+const sal_uInt32 OOBIN_PTFIELD_AUTOSORT = 0x00001000;
+const sal_uInt32 OOBIN_PTFIELD_SORTASCENDING = 0x00002000;
+const sal_uInt32 OOBIN_PTFIELD_AUTOSHOW = 0x00004000;
+const sal_uInt32 OOBIN_PTFIELD_AUTOSHOWTOP = 0x00008000;
+const sal_uInt32 OOBIN_PTFIELD_MULTIPAGEITEMS = 0x00080000;
+
+const sal_uInt16 OOBIN_PTFITEM_HIDDEN = 0x0001;
+const sal_uInt16 OOBIN_PTFITEM_HIDEDETAILS = 0x0002;
+
+const sal_uInt8 OOBIN_PTPAGEFIELD_HASNAME = 0x01;
+const sal_uInt8 OOBIN_PTPAGEFIELD_HASOLAPCAPTION = 0x02;
+const sal_Int32 OOBIN_PTPAGEFIELD_MULTIITEMS = 0x001000FE;
+
+const sal_uInt16 OOBIN_PTFILTER_HASNAME = 0x0001;
+const sal_uInt16 OOBIN_PTFILTER_HASDESCRIPTION = 0x0002;
+const sal_uInt16 OOBIN_PTFILTER_HASSTRVALUE1 = 0x0004;
+const sal_uInt16 OOBIN_PTFILTER_HASSTRVALUE2 = 0x0008;
+
+const sal_uInt8 OOBIN_TOP10FILTER_TOP = 0x01;
+const sal_uInt8 OOBIN_TOP10FILTER_PERCENT = 0x02;
+
+const sal_uInt32 OOBIN_PTDEF_SHOWITEMS = 0x00000100;
+const sal_uInt32 OOBIN_PTDEF_DISABLEFIELDLIST = 0x00000400;
+const sal_uInt32 OOBIN_PTDEF_HIDECALCMEMBERS = 0x00001000;
+const sal_uInt32 OOBIN_PTDEF_WITHHIDDENTOTALS = 0x00002000;
+const sal_uInt32 OOBIN_PTDEF_HIDEDRILL = 0x00100000;
+const sal_uInt32 OOBIN_PTDEF_PRINTDRILL = 0x00200000;
+const sal_uInt32 OOBIN_PTDEF_HIDEHEADERS = 0x80000000;
+
+const sal_uInt32 OOBIN_PTDEF_SHOWEMPTYROW = 0x00000004;
+const sal_uInt32 OOBIN_PTDEF_SHOWEMPTYCOL = 0x00000008;
+const sal_uInt32 OOBIN_PTDEF_ENABLEDRILL = 0x00000020;
+const sal_uInt32 OOBIN_PTDEF_PRESERVEFORMATTING = 0x00000080;
+const sal_uInt32 OOBIN_PTDEF_SHOWERROR = 0x00000200;
+const sal_uInt32 OOBIN_PTDEF_SHOWMISSING = 0x00000400;
+const sal_uInt32 OOBIN_PTDEF_PAGEOVERTHENDOWN = 0x00000800;
+const sal_uInt32 OOBIN_PTDEF_SUBTOTALHIDDENITEMS = 0x00001000;
+const sal_uInt32 OOBIN_PTDEF_ROWGRANDTOTALS = 0x00002000;
+const sal_uInt32 OOBIN_PTDEF_COLGRANDTOTALS = 0x00004000;
+const sal_uInt32 OOBIN_PTDEF_FIELDPRINTTITLES = 0x00008000;
+const sal_uInt32 OOBIN_PTDEF_ITEMPRINTTITLES = 0x00020000;
+const sal_uInt32 OOBIN_PTDEF_MERGEITEM = 0x00040000;
+const sal_uInt32 OOBIN_PTDEF_HASDATACAPTION = 0x00080000;
+const sal_uInt32 OOBIN_PTDEF_HASGRANDTOTALCAPTION = 0x00100000;
+const sal_uInt32 OOBIN_PTDEF_HASPAGESTYLE = 0x00200000;
+const sal_uInt32 OOBIN_PTDEF_HASPIVOTTABLESTYLE = 0x00400000;
+const sal_uInt32 OOBIN_PTDEF_HASVACATEDSTYLE = 0x00800000;
+const sal_uInt32 OOBIN_PTDEF_HASTAG = 0x40000000;
+
+const sal_uInt32 OOBIN_PTDEF_NOERRORCAPTION = 0x00000040;
+const sal_uInt32 OOBIN_PTDEF_NOMISSINGCAPTION = 0x00000080;
+const sal_uInt32 OOBIN_PTDEF_HASROWHEADERCAPTION = 0x00000400;
+const sal_uInt32 OOBIN_PTDEF_HASCOLHEADERCAPTION = 0x00000800;
+const sal_uInt32 OOBIN_PTDEF_FIELDLISTSORTASC = 0x00001000;
+const sal_uInt32 OOBIN_PTDEF_NOCUSTOMLISTSORT = 0x00004000;
+
+const sal_uInt8 OOBIN_PTDEF_ROWAXIS = 1;
+const sal_uInt8 OOBIN_PTDEF_COLAXIS = 2;
+
+// ----------------------------------------------------------------------------
+
+const sal_uInt16 BIFF_PT_NOSTRING = 0xFFFF;
+
+const sal_uInt16 BIFF_PTFIELD_DATAFIELD = 0x0008;
+const sal_uInt16 BIFF_PTFIELD_DEFAULT = 0x0001;
+const sal_uInt16 BIFF_PTFIELD_SUM = 0x0002;
+const sal_uInt16 BIFF_PTFIELD_COUNTA = 0x0004;
+const sal_uInt16 BIFF_PTFIELD_AVERAGE = 0x0008;
+const sal_uInt16 BIFF_PTFIELD_MAX = 0x0010;
+const sal_uInt16 BIFF_PTFIELD_MIN = 0x0020;
+const sal_uInt16 BIFF_PTFIELD_PRODUCT = 0x0040;
+const sal_uInt16 BIFF_PTFIELD_COUNT = 0x0080;
+const sal_uInt16 BIFF_PTFIELD_STDDEV = 0x0100;
+const sal_uInt16 BIFF_PTFIELD_STDDEVP = 0x0200;
+const sal_uInt16 BIFF_PTFIELD_VAR = 0x0400;
+const sal_uInt16 BIFF_PTFIELD_VARP = 0x0800;
+
+const sal_uInt32 BIFF_PTFIELD2_SHOWALL = 0x00000001;
+const sal_uInt32 BIFF_PTFIELD2_AUTOSORT = 0x00000200;
+const sal_uInt32 BIFF_PTFIELD2_SORTASCENDING = 0x00000400;
+const sal_uInt32 BIFF_PTFIELD2_AUTOSHOW = 0x00000800;
+const sal_uInt32 BIFF_PTFIELD2_AUTOSHOWTOP = 0x00001000;
+const sal_uInt32 BIFF_PTFIELD2_OUTLINE = 0x00200000;
+const sal_uInt32 BIFF_PTFIELD2_INSERTBLANKROW = 0x00400000;
+const sal_uInt32 BIFF_PTFIELD2_SUBTOTALTOP = 0x00800000;
+
+const sal_uInt16 BIFF_PTFITEM_HIDDEN = 0x0001;
+const sal_uInt16 BIFF_PTFITEM_HIDEDETAILS = 0x0002;
+
+const sal_uInt16 BIFF_PTDEF_ROWGRANDTOTALS = 0x0001;
+const sal_uInt16 BIFF_PTDEF_COLGRANDTOTALS = 0x0002;
+
+const sal_uInt8 BIFF_PTDEF_ROWAXIS = 1;
+const sal_uInt8 BIFF_PTDEF_COLAXIS = 2;
+
+const sal_uInt32 BIFF_PTDEF2_PAGEOVERTHENDOWN = 0x00000001;
+const sal_uInt32 BIFF_PTDE2F_ENABLEDRILL = 0x00020000;
+const sal_uInt32 BIFF_PTDEF2_PRESERVEFORMATTING = 0x00080000;
+const sal_uInt32 BIFF_PTDEF2_MERGEITEM = 0x00100000;
+const sal_uInt32 BIFF_PTDEF2_SHOWERROR = 0x00200000;
+const sal_uInt32 BIFF_PTDEF2_SHOWMISSING = 0x00400000;
+const sal_uInt32 BIFF_PTDEF2_SUBTOTALHIDDENITEMS = 0x00800000;
+
+const sal_Int16 BIFF_PTPAGEFIELDS_ALLITEMS = 0x7FFD;
+
+const sal_Int16 BIFF_PTDATAFIELD_PREVIOUS = 0x7FFB;
+const sal_Int16 BIFF_PTDATAFIELD_NEXT = 0x7FFC;
+
+// ----------------------------------------------------------------------------
+
+OUString lclReadPivotString( const WorkbookHelper& rHelper, BiffInputStream& rStrm, sal_uInt16 nLen )
+{
+ if( nLen == BIFF_PT_NOSTRING )
+ return OUString();
+ return (rHelper.getBiff() == BIFF8) ? rStrm.readUniStringBody( nLen ) : rStrm.readCharArrayUC( nLen, rHelper.getTextEncoding() );
+}
+
+} // namespace
+
+// ============================================================================
+
+PTFieldItemModel::PTFieldItemModel() :
+ mnCacheItem( -1 ),
+ mnType( XML_data ),
+ mbShowDetails( true ),
+ mbHidden( false )
+{
+}
+
+void PTFieldItemModel::setBinType( sal_uInt16 nType )
+{
+ static const sal_Int32 spnTypes[] = { XML_data, XML_default,
+ XML_sum, XML_countA, XML_avg, XML_max, XML_min, XML_product, XML_count,
+ XML_stdDev, XML_stdDevP, XML_var, XML_varP, XML_grand, XML_blank };
+ mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_data );
+}
+
+// ----------------------------------------------------------------------------
+
+PTFieldModel::PTFieldModel() :
+ mnAxis( XML_TOKEN_INVALID ),
+ mnNumFmtId( 0 ),
+ mnAutoShowItems( 10 ),
+ mnAutoShowRankBy( -1 ),
+ mnSortType( XML_manual ),
+ mnSortRefField( -1 ),
+ mnSortRefItem( -1 ),
+ mbDataField( false ),
+ mbDefaultSubtotal( true ),
+ mbSumSubtotal( false ),
+ mbCountASubtotal( false ),
+ mbAverageSubtotal( false ),
+ mbMaxSubtotal( false ),
+ mbMinSubtotal( false ),
+ mbProductSubtotal( false ),
+ mbCountSubtotal( false ),
+ mbStdDevSubtotal( false ),
+ mbStdDevPSubtotal( false ),
+ mbVarSubtotal( false ),
+ mbVarPSubtotal( false ),
+ mbShowAll( true ),
+ mbOutline( true ),
+ mbSubtotalTop( true ),
+ mbInsertBlankRow( false ),
+ mbInsertPageBreak( false ),
+ mbAutoShow( false ),
+ mbTopAutoShow( true ),
+ mbMultiPageItems( false )
+{
+}
+
+void PTFieldModel::setBinAxis( sal_uInt8 nAxis )
+{
+ /* Weird. The axis field is organized as bit field, but only one of the
+ row/col/page flags are allowed at the same time and refer to the values
+ 'axisRow', 'axisCol', and 'axisPage' of the XML attribute
+ 'pivotField@axis'. Additionally, the fourth bit determines if the field
+ is a data field, which may appear combined with the row/col/page flags.
+ Therefore, this bit is unrelated to the 'axisValues' value of the
+ 'pivotField@axis' attribute, but refers to the 'pivotField@dataField'
+ boolean attribute. */
+ static const sal_Int32 spnAxisIds[] = { XML_TOKEN_INVALID, XML_axisRow, XML_axisCol, XML_TOKEN_INVALID, XML_axisPage };
+ mnAxis = STATIC_ARRAY_SELECT( spnAxisIds, nAxis, XML_TOKEN_INVALID );
+}
+
+// ----------------------------------------------------------------------------
+
+PTPageFieldModel::PTPageFieldModel() :
+ mnField( -1 ),
+ mnItem( OOBIN_PTPAGEFIELD_MULTIITEMS )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PTDataFieldModel::PTDataFieldModel() :
+ mnField( -1 ),
+ mnSubtotal( XML_sum ),
+ mnShowDataAs( XML_normal ),
+ mnBaseField( -1 ),
+ mnBaseItem( -1 ),
+ mnNumFmtId( 0 )
+{
+}
+
+void PTDataFieldModel::setBinSubtotal( sal_Int32 nSubtotal )
+{
+ static sal_Int32 spnSubtotals[] = { XML_sum, XML_count, XML_average, XML_max, XML_min, XML_product, XML_countNums, XML_stdDev, XML_stdDevp, XML_var, XML_varp };
+ mnSubtotal = STATIC_ARRAY_SELECT( spnSubtotals, nSubtotal, XML_TOKEN_INVALID );
+}
+
+void PTDataFieldModel::setBinShowDataAs( sal_Int32 nShowDataAs )
+{
+ static sal_Int32 spnShowDataAs[] = { XML_normal, XML_difference, XML_percent, XML_percentDiff, XML_runTotal, XML_percentOfRow, XML_percentOfCol, XML_percentOfTotal, XML_index };
+ mnShowDataAs = STATIC_ARRAY_SELECT( spnShowDataAs, nShowDataAs, XML_TOKEN_INVALID );
+}
+
+// ----------------------------------------------------------------------------
+
+PivotTableField::PivotTableField( PivotTable& rPivotTable, sal_Int32 nFieldIndex ) :
+ WorkbookHelper( rPivotTable ),
+ mrPivotTable( rPivotTable ),
+ mnFieldIndex( nFieldIndex )
+{
+}
+
+void PivotTableField::importPivotField( const AttributeList& rAttribs )
+{
+ /* The documentation mentions a value 'axisValues' for the attribute
+ 'pivotField@axis'. But this value is not used to mark a data field, as
+ data fields may be inserted in one of the row/column/page dimensions at
+ the same time. Therefore, the boolean attribute 'pivotField@dataField'
+ is really used to mark data fields. */
+ maModel.mnAxis = rAttribs.getToken( XML_axis, XML_TOKEN_INVALID );
+ maModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
+ maModel.mnAutoShowItems = rAttribs.getInteger( XML_itemPageCount, 10 );
+ maModel.mnAutoShowRankBy = rAttribs.getInteger( XML_rankBy, -1 );
+ maModel.mnSortType = rAttribs.getToken( XML_sortType, XML_manual );
+ maModel.mbDataField = rAttribs.getBool( XML_dataField, false );
+ maModel.mbDefaultSubtotal = rAttribs.getBool( XML_defaultSubtotal, true );
+ maModel.mbSumSubtotal = rAttribs.getBool( XML_sumSubtotal, false );
+ maModel.mbCountASubtotal = rAttribs.getBool( XML_countASubtotal, false );
+ maModel.mbAverageSubtotal = rAttribs.getBool( XML_avgSubtotal, false );
+ maModel.mbMaxSubtotal = rAttribs.getBool( XML_maxSubtotal, false );
+ maModel.mbMinSubtotal = rAttribs.getBool( XML_minSubtotal, false );
+ maModel.mbProductSubtotal = rAttribs.getBool( XML_productSubtotal, false );
+ maModel.mbCountSubtotal = rAttribs.getBool( XML_countSubtotal, false );
+ maModel.mbStdDevSubtotal = rAttribs.getBool( XML_stdDevSubtotal, false );
+ maModel.mbStdDevPSubtotal = rAttribs.getBool( XML_stdDevPSubtotal, false );
+ maModel.mbVarSubtotal = rAttribs.getBool( XML_varSubtotal, false );
+ maModel.mbVarPSubtotal = rAttribs.getBool( XML_varPSubtotal, false );
+ maModel.mbShowAll = rAttribs.getBool( XML_showAll, true );
+ maModel.mbOutline = rAttribs.getBool( XML_outline, true );
+ maModel.mbSubtotalTop = rAttribs.getBool( XML_subtotalTop, true );
+ maModel.mbInsertBlankRow = rAttribs.getBool( XML_insertBlankRow, false );
+ maModel.mbInsertPageBreak = rAttribs.getBool( XML_insertPageBreak, false );
+ maModel.mbAutoShow = rAttribs.getBool( XML_autoShow, false );
+ maModel.mbTopAutoShow = rAttribs.getBool( XML_topAutoShow, true );
+ maModel.mbMultiPageItems = rAttribs.getBool( XML_multipleItemSelectionAllowed, false );
+}
+
+void PivotTableField::importItem( const AttributeList& rAttribs )
+{
+ PTFieldItemModel aModel;
+ aModel.mnCacheItem = rAttribs.getInteger( XML_x, -1 );
+ aModel.mnType = rAttribs.getToken( XML_t, XML_data );
+ aModel.mbShowDetails = rAttribs.getBool( XML_sd, true );
+ aModel.mbHidden = rAttribs.getBool( XML_h, false );
+ maItems.push_back( aModel );
+}
+
+void PivotTableField::importReference( const AttributeList& rAttribs )
+{
+ // field index is stored as unsigned integer
+ maModel.mnSortRefField = static_cast< sal_Int32 >( rAttribs.getUnsigned( XML_field, SAL_MAX_UINT32 ) );
+}
+
+void PivotTableField::importReferenceItem( const AttributeList& rAttribs )
+{
+ maModel.mnSortRefItem = rAttribs.getInteger( XML_v, -1 );
+}
+
+void PivotTableField::importPTField( RecordInputStream& rStrm )
+{
+ sal_uInt32 nFlags1, nFlags2;
+ rStrm >> nFlags1 >> maModel.mnNumFmtId >> nFlags2 >> maModel.mnAutoShowItems >> maModel.mnAutoShowRankBy;
+
+ maModel.setBinAxis( extractValue< sal_uInt8 >( nFlags1, 0, 3 ) );
+ maModel.mbDataField = getFlag( nFlags1, OOBIN_PTFIELD_DATAFIELD );
+ maModel.mbDefaultSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_DEFAULT );
+ maModel.mbSumSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_SUM );
+ maModel.mbCountASubtotal = getFlag( nFlags1, OOBIN_PTFIELD_COUNTA );
+ maModel.mbAverageSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_AVERAGE );
+ maModel.mbMaxSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_MAX );
+ maModel.mbMinSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_MIN );
+ maModel.mbProductSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_PRODUCT );
+ maModel.mbCountSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_COUNT );
+ maModel.mbStdDevSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_STDDEV );
+ maModel.mbStdDevPSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_STDDEVP );
+ maModel.mbVarSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_VAR );
+ maModel.mbVarPSubtotal = getFlag( nFlags1, OOBIN_PTFIELD_VARP );
+
+ maModel.mbShowAll = getFlag( nFlags2, OOBIN_PTFIELD_SHOWALL );
+ maModel.mbOutline = getFlag( nFlags2, OOBIN_PTFIELD_OUTLINE );
+ maModel.mbSubtotalTop = getFlag( nFlags2, OOBIN_PTFIELD_SUBTOTALTOP );
+ maModel.mbInsertBlankRow = getFlag( nFlags2, OOBIN_PTFIELD_INSERTBLANKROW );
+ maModel.mbInsertPageBreak = getFlag( nFlags2, OOBIN_PTFIELD_INSERTPAGEBREAK );
+ maModel.mbAutoShow = getFlag( nFlags2, OOBIN_PTFIELD_AUTOSHOW );
+ maModel.mbTopAutoShow = getFlag( nFlags2, OOBIN_PTFIELD_AUTOSHOWTOP );
+ maModel.mbMultiPageItems = getFlag( nFlags2, OOBIN_PTFIELD_MULTIPAGEITEMS );
+
+ bool bAutoSort = getFlag( nFlags2, OOBIN_PTFIELD_AUTOSORT );
+ bool bAscending = getFlag( nFlags2, OOBIN_PTFIELD_SORTASCENDING );
+ maModel.mnSortType = bAutoSort ? (bAscending ? XML_ascending : XML_descending) : XML_manual;
+}
+
+void PivotTableField::importPTFItem( RecordInputStream& rStrm )
+{
+ PTFieldItemModel aModel;
+ sal_uInt8 nType;
+ sal_uInt16 nFlags;
+ rStrm >> nType >> nFlags >> aModel.mnCacheItem;
+
+ aModel.setBinType( nType );
+ aModel.mbShowDetails = !getFlag( nFlags, OOBIN_PTFITEM_HIDEDETAILS );
+ aModel.mbHidden = getFlag( nFlags, OOBIN_PTFITEM_HIDDEN );
+
+ maItems.push_back( aModel );
+}
+
+void PivotTableField::importPTReference( RecordInputStream& rStrm )
+{
+ rStrm >> maModel.mnSortRefField;
+}
+
+void PivotTableField::importPTReferenceItem( RecordInputStream& rStrm )
+{
+ rStrm >> maModel.mnSortRefItem;
+}
+
+void PivotTableField::importPTField( BiffInputStream& rStrm )
+{
+ sal_uInt16 nAxis, nSubtCount, nSubtotals;
+ rStrm >> nAxis >> nSubtCount >> nSubtotals;
+ rStrm.skip( 2 ); // item count
+
+ maModel.setBinAxis( extractValue< sal_uInt8 >( nAxis, 0, 3 ) );
+ maModel.mbDataField = getFlag( nAxis, BIFF_PTFIELD_DATAFIELD );
+
+ maModel.mbDefaultSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_DEFAULT );
+ maModel.mbSumSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_SUM );
+ maModel.mbCountASubtotal = getFlag( nSubtotals, BIFF_PTFIELD_COUNTA );
+ maModel.mbAverageSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_AVERAGE );
+ maModel.mbMaxSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_MAX );
+ maModel.mbMinSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_MIN );
+ maModel.mbProductSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_PRODUCT );
+ maModel.mbCountSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_COUNT );
+ maModel.mbStdDevSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_STDDEV );
+ maModel.mbStdDevPSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_STDDEVP );
+ maModel.mbVarSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_VAR );
+ maModel.mbVarPSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_VARP );
+
+ // set different defaults for BIFF
+ maModel.mbShowAll = maModel.mbOutline = maModel.mbSubtotalTop = false;
+
+ // read following items
+ while( (rStrm.getNextRecId() == BIFF_ID_PTFITEM) && rStrm.startNextRecord() )
+ importPTFItem( rStrm );
+
+ // read following PTFIELD2 record with additional field settings
+ if( (getBiff() == BIFF8) && (rStrm.getNextRecId() == BIFF_ID_PTFIELD2) && rStrm.startNextRecord() )
+ importPTField2( rStrm );
+}
+
+void PivotTableField::importPTField2( BiffInputStream& rStrm )
+{
+ sal_uInt32 nFlags;
+ rStrm >> nFlags;
+ maModel.mnSortRefItem = rStrm.readInt16();
+ maModel.mnAutoShowRankBy = rStrm.readInt16();
+ maModel.mnNumFmtId = rStrm.readuInt16();
+
+ maModel.mnAutoShowItems = extractValue< sal_Int32 >( nFlags, 24, 8 );
+ maModel.mbShowAll = getFlag( nFlags, BIFF_PTFIELD2_SHOWALL );
+ maModel.mbOutline = getFlag( nFlags, BIFF_PTFIELD2_OUTLINE );
+ maModel.mbSubtotalTop = getFlag( nFlags, BIFF_PTFIELD2_SUBTOTALTOP );
+ maModel.mbInsertBlankRow = getFlag( nFlags, BIFF_PTFIELD2_INSERTBLANKROW );
+ maModel.mbAutoShow = getFlag( nFlags, BIFF_PTFIELD2_AUTOSHOW );
+ maModel.mbTopAutoShow = getFlag( nFlags, BIFF_PTFIELD2_AUTOSHOWTOP );
+
+ bool bAutoSort = getFlag( nFlags, BIFF_PTFIELD2_AUTOSORT );
+ bool bAscending = getFlag( nFlags, BIFF_PTFIELD2_SORTASCENDING );
+ maModel.mnSortType = bAutoSort ? (bAscending ? XML_ascending : XML_descending) : XML_manual;
+ // mnSortRefField == OOX_PT_DATALAYOUTFIELD will indicate sorting by data field
+ if( maModel.mnSortRefItem >= 0 )
+ maModel.mnSortRefField = OOX_PT_DATALAYOUTFIELD;
+}
+
+void PivotTableField::importPTFItem( BiffInputStream& rStrm )
+{
+ PTFieldItemModel aModel;
+ sal_uInt16 nType, nFlags;
+ sal_Int16 nCacheItem;
+ rStrm >> nType >> nFlags >> nCacheItem;
+
+ aModel.setBinType( nType );
+ aModel.mnCacheItem = nCacheItem;
+ aModel.mbShowDetails = !getFlag( nFlags, BIFF_PTFITEM_HIDEDETAILS );
+ aModel.mbHidden = getFlag( nFlags, BIFF_PTFITEM_HIDDEN );
+
+ maItems.push_back( aModel );
+}
+
+void PivotTableField::finalizeImport( const Reference< XDataPilotDescriptor >& rxDPDesc )
+{
+ /* Process all fields based on source data, other fields (e.g. group
+ fields) are processed from here. PivotCacahe::getDatabaseIndex()
+ returns -1 for all fields not based on source data. */
+ Reference< XDataPilotField > xDPField;
+ sal_Int32 nDatabaseIdx = mrPivotTable.getCacheDatabaseIndex( mnFieldIndex );
+ if( (nDatabaseIdx >= 0) && rxDPDesc.is() ) try
+ {
+ // try to get the source field and its name from passed DataPilot descriptor
+ Reference< XIndexAccess > xDPFieldsIA( rxDPDesc->getDataPilotFields(), UNO_SET_THROW );
+ xDPField.set( xDPFieldsIA->getByIndex( nDatabaseIdx ), UNO_QUERY_THROW );
+ Reference< XNamed > xDPFieldName( xDPField, UNO_QUERY_THROW );
+ maDPFieldName = xDPFieldName->getName();
+ OSL_ENSURE( maDPFieldName.getLength() > 0, "PivotTableField::finalizeImport - no field name in source data found" );
+
+ // try to convert grouping settings
+ if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
+ {
+ // numeric grouping is done inplace, no nested group fields will appear
+ if( pCacheField->hasNumericGrouping() )
+ {
+ pCacheField->convertNumericGrouping( xDPField );
+ }
+ else if( pCacheField->hasDateGrouping() )
+ {
+ // first date group settings are inplace
+ pCacheField->createDateGroupField( xDPField );
+ // create all nested group fields (if any)
+ mrPivotTable.finalizeDateGroupingImport( xDPField, mnFieldIndex );
+ }
+ else if( pCacheField->hasParentGrouping() )
+ {
+ // create a list of all item names, needed to map between original and group items
+ ::std::vector< OUString > aItems;
+ pCacheField->getCacheItemNames( aItems );
+ PivotCacheGroupItemVector aItemNames;
+ for( ::std::vector< OUString >::iterator aIt = aItems.begin(), aEnd = aItems.end(); aIt != aEnd; ++aIt )
+ aItemNames.push_back( PivotCacheGroupItem( *aIt ) );
+ // create all nested group fields (if any)
+ mrPivotTable.finalizeParentGroupingImport( xDPField, *pCacheField, aItemNames );
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void PivotTableField::finalizeDateGroupingImport( const Reference< XDataPilotField >& rxBaseDPField, sal_Int32 nBaseFieldIdx )
+{
+ if( maDPFieldName.getLength() == 0 ) // prevent endless loops if file format is broken
+ {
+ if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
+ {
+ if( !pCacheField->isDatabaseField() && pCacheField->hasDateGrouping() && (pCacheField->getGroupBaseField() == nBaseFieldIdx) )
+ {
+ maDPFieldName = pCacheField->createDateGroupField( rxBaseDPField );
+ OSL_ENSURE( maDPFieldName.getLength() > 0, "PivotTableField::finalizeDateGroupingImport - cannot create date group field" );
+ }
+ }
+ }
+}
+
+void PivotTableField::finalizeParentGroupingImport( const Reference< XDataPilotField >& rxBaseDPField, PivotCacheGroupItemVector& orItemNames )
+{
+ if( maDPFieldName.getLength() == 0 ) // prevent endless loops if file format is broken
+ {
+ if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
+ {
+ maDPFieldName = pCacheField->createParentGroupField( rxBaseDPField, orItemNames );
+ // on success, try to create nested group fields
+ Reference< XDataPilotField > xDPField = mrPivotTable.getDataPilotField( maDPFieldName );
+ if( xDPField.is() )
+ mrPivotTable.finalizeParentGroupingImport( xDPField, *pCacheField, orItemNames );
+ }
+ }
+}
+
+void PivotTableField::convertRowField()
+{
+ convertRowColPageField( XML_axisRow );
+}
+
+void PivotTableField::convertColField()
+{
+ convertRowColPageField( XML_axisCol );
+}
+
+void PivotTableField::convertHiddenField()
+{
+ convertRowColPageField( XML_TOKEN_INVALID );
+}
+
+void PivotTableField::convertPageField( const PTPageFieldModel& rPageField )
+{
+ OSL_ENSURE( rPageField.mnField == mnFieldIndex, "PivotTableField::convertPageField - wrong field index" );
+ // convert all settings common for row/column/page fields
+ Reference< XDataPilotField > xDPField = convertRowColPageField( XML_axisPage );
+
+ if( xDPField.is() )
+ {
+ PropertySet aPropSet( xDPField );
+ using namespace ::com::sun::star::sheet;
+
+ // find cache item used as 'selected page'
+ sal_Int32 nCacheItem = -1;
+ if( maModel.mbMultiPageItems )
+ {
+ // multiple items may be selected
+ OSL_ENSURE( rPageField.mnItem == OOBIN_PTPAGEFIELD_MULTIITEMS, "PivotTableField::convertPageField - unexpected cache item index" );
+ // try to find a single visible item
+ bool bHasMultiItems = false;
+ for( ItemModelVector::iterator aIt = maItems.begin(), aEnd = maItems.end(); (aIt != aEnd) && !bHasMultiItems; ++aIt )
+ {
+ if( (aIt->mnType == XML_data) && !aIt->mbHidden )
+ {
+ bHasMultiItems = nCacheItem >= 0;
+ nCacheItem = bHasMultiItems ? -1 : aIt->mnCacheItem;
+ }
+ }
+ }
+ else
+ {
+ // single item may be selected
+ if( (0 <= rPageField.mnItem) && (rPageField.mnItem < static_cast< sal_Int32 >( maItems.size() )) )
+ nCacheItem = maItems[ rPageField.mnItem ].mnCacheItem;
+ }
+
+ if( nCacheItem >= 0 )
+ {
+ if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
+ {
+ if( const PivotCacheItem* pSharedItem = pCacheField->getCacheItem( nCacheItem ) )
+ {
+ OUString aSelectedPage = pSharedItem->getName();
+ if( aSelectedPage.getLength() > 0 )
+ aPropSet.setProperty( PROP_SelectedPage, aSelectedPage );
+ }
+ }
+ }
+ }
+}
+
+void PivotTableField::convertDataField( const PTDataFieldModel& rDataField )
+{
+ OSL_ENSURE( rDataField.mnField == mnFieldIndex, "PivotTableField::convertDataField - wrong field index" );
+ OSL_ENSURE( maModel.mbDataField, "PivotTableField::convertDataField - not a data field" );
+ Reference< XDataPilotField > xDPField = mrPivotTable.getDataPilotField( maDPFieldName );
+ if( xDPField.is() )
+ {
+ PropertySet aPropSet( xDPField );
+ using namespace ::com::sun::star::sheet;
+
+ // field orientation
+ aPropSet.setProperty( PROP_Orientation, DataPilotFieldOrientation_DATA );
+
+ /* Field aggregation function. Documentation is a little bit confused
+ about which names to use for the count functions. The name 'count'
+ means 'count all', and 'countNum' means 'count numbers'. On the
+ other hand, for subtotals, 'countA' means 'count all', and 'count'
+ means 'count numbers' (see above). */
+ GeneralFunction eAggFunc = GeneralFunction_SUM;
+ switch( rDataField.mnSubtotal )
+ {
+ case XML_sum: eAggFunc = GeneralFunction_SUM; break;
+ case XML_count: eAggFunc = GeneralFunction_COUNT; break;
+ case XML_average: eAggFunc = GeneralFunction_AVERAGE; break;
+ case XML_max: eAggFunc = GeneralFunction_MAX; break;
+ case XML_min: eAggFunc = GeneralFunction_MIN; break;
+ case XML_product: eAggFunc = GeneralFunction_PRODUCT; break;
+ case XML_countNums: eAggFunc = GeneralFunction_COUNTNUMS; break;
+ case XML_stdDev: eAggFunc = GeneralFunction_STDEV; break;
+ case XML_stdDevp: eAggFunc = GeneralFunction_STDEVP; break;
+ case XML_var: eAggFunc = GeneralFunction_VAR; break;
+ case XML_varp: eAggFunc = GeneralFunction_VARP; break;
+ default: OSL_ENSURE( false, "PivotTableField::convertDataField - unknown aggregation function" );
+ }
+ aPropSet.setProperty( PROP_Function, eAggFunc );
+
+ // field reference ('show data as')
+ DataPilotFieldReference aReference;
+ aReference.ReferenceType = DataPilotFieldReferenceType::NONE;
+ switch( rDataField.mnShowDataAs )
+ {
+ case XML_difference: aReference.ReferenceType = DataPilotFieldReferenceType::ITEM_DIFFERENCE; break;
+ case XML_percent: aReference.ReferenceType = DataPilotFieldReferenceType::ITEM_PERCENTAGE; break;
+ case XML_percentDiff: aReference.ReferenceType = DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE; break;
+ case XML_runTotal: aReference.ReferenceType = DataPilotFieldReferenceType::RUNNING_TOTAL; break;
+ case XML_percentOfRow: aReference.ReferenceType = DataPilotFieldReferenceType::ROW_PERCENTAGE; break;
+ case XML_percentOfCol: aReference.ReferenceType = DataPilotFieldReferenceType::COLUMN_PERCENTAGE; break;
+ case XML_percentOfTotal: aReference.ReferenceType = DataPilotFieldReferenceType::TOTAL_PERCENTAGE; break;
+ case XML_index: aReference.ReferenceType = DataPilotFieldReferenceType::INDEX; break;
+ }
+ if( aReference.ReferenceType != DataPilotFieldReferenceType::NONE )
+ {
+ if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( rDataField.mnBaseField ) )
+ {
+ aReference.ReferenceField = pCacheField->getName();
+ switch( rDataField.mnBaseItem )
+ {
+ case OOX_PT_PREVIOUS_ITEM:
+ aReference.ReferenceItemType = DataPilotFieldReferenceItemType::PREVIOUS;
+ break;
+ case OOX_PT_NEXT_ITEM:
+ aReference.ReferenceItemType = DataPilotFieldReferenceItemType::NEXT;
+ break;
+ default:
+ aReference.ReferenceItemType = DataPilotFieldReferenceItemType::NAMED;
+ if( const PivotCacheItem* pCacheItem = pCacheField->getCacheItem( rDataField.mnBaseItem ) )
+ aReference.ReferenceItemName = pCacheItem->getName();
+ }
+ aPropSet.setProperty( PROP_Reference, aReference );
+ }
+ }
+ }
+}
+
+// private --------------------------------------------------------------------
+
+Reference< XDataPilotField > PivotTableField::convertRowColPageField( sal_Int32 nAxis )
+{
+ bool bDataLayout = mnFieldIndex == OOX_PT_DATALAYOUTFIELD;
+ Reference< XDataPilotField > xDPField = bDataLayout ? mrPivotTable.getDataLayoutField() : mrPivotTable.getDataPilotField( maDPFieldName );
+ OSL_ENSURE( bDataLayout || (nAxis == maModel.mnAxis), "PivotTableField::convertRowColPageField - field axis mismatch" );
+
+ if( xDPField.is() )
+ {
+ PropertySet aPropSet( xDPField );
+ using namespace ::com::sun::star::sheet;
+
+ // field orientation
+ DataPilotFieldOrientation eFieldOrient = DataPilotFieldOrientation_HIDDEN;
+ switch( nAxis )
+ {
+ case XML_axisRow: eFieldOrient = DataPilotFieldOrientation_ROW; break;
+ case XML_axisCol: eFieldOrient = DataPilotFieldOrientation_COLUMN; break;
+ case XML_axisPage: eFieldOrient = DataPilotFieldOrientation_PAGE; break;
+ }
+ if( eFieldOrient != DataPilotFieldOrientation_HIDDEN )
+ aPropSet.setProperty( PROP_Orientation, eFieldOrient );
+
+ // all other settings not for the data layout field
+ if( !bDataLayout )
+ {
+ /* Field subtotal functions. Ignore the 'defaultSubtotal' flag, if
+ explicit functions are set. This is different behaviour between
+ XML (where 'defaultSubtotal' is set regardless of other
+ functions) and binary formats (where 'defaultSubtotal' is not
+ set if other functions are set). */
+ ::std::vector< GeneralFunction > aSubtotals;
+ /* Order of subtotals is fixed in Excel. Documentation is a little
+ bit confused about which names to use for the count functions.
+ For subtotals, 'countA' means 'count all', and 'count' means
+ 'count numbers'. On the other hand, for the data field
+ aggregation function, 'count' means 'count all', and 'countNum'
+ means 'count numbers' (see below). */
+ if( maModel.mbSumSubtotal ) aSubtotals.push_back( GeneralFunction_SUM );
+ if( maModel.mbCountASubtotal ) aSubtotals.push_back( GeneralFunction_COUNT );
+ if( maModel.mbAverageSubtotal ) aSubtotals.push_back( GeneralFunction_AVERAGE );
+ if( maModel.mbMaxSubtotal ) aSubtotals.push_back( GeneralFunction_MAX );
+ if( maModel.mbMinSubtotal ) aSubtotals.push_back( GeneralFunction_MIN );
+ if( maModel.mbProductSubtotal ) aSubtotals.push_back( GeneralFunction_PRODUCT );
+ if( maModel.mbCountSubtotal ) aSubtotals.push_back( GeneralFunction_COUNTNUMS );
+ if( maModel.mbStdDevSubtotal ) aSubtotals.push_back( GeneralFunction_STDEV );
+ if( maModel.mbStdDevPSubtotal ) aSubtotals.push_back( GeneralFunction_STDEVP );
+ if( maModel.mbVarSubtotal ) aSubtotals.push_back( GeneralFunction_VAR );
+ if( maModel.mbVarPSubtotal ) aSubtotals.push_back( GeneralFunction_VARP );
+ // if no function is set manually, check the 'defaultSubtotal' flag
+ if( aSubtotals.empty() && maModel.mbDefaultSubtotal )
+ aSubtotals.push_back( GeneralFunction_AUTO );
+ aPropSet.setProperty( PROP_Subtotals, ContainerHelper::vectorToSequence( aSubtotals ) );
+
+ // layout settings
+ DataPilotFieldLayoutInfo aLayoutInfo;
+ aLayoutInfo.LayoutMode = maModel.mbOutline ?
+ (maModel.mbSubtotalTop ? DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_TOP : DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_BOTTOM) :
+ DataPilotFieldLayoutMode::TABULAR_LAYOUT;
+ aLayoutInfo.AddEmptyLines = maModel.mbInsertBlankRow;
+ aPropSet.setProperty( PROP_LayoutInfo, aLayoutInfo );
+ aPropSet.setProperty( PROP_ShowEmpty, maModel.mbShowAll );
+
+ // auto show (OOXML3/OOBIN3 only)
+ if( maModel.mbAutoShow )
+ {
+ DataPilotFieldAutoShowInfo aAutoShowInfo;
+ aAutoShowInfo.IsEnabled = sal_True;
+ aAutoShowInfo.ShowItemsMode = maModel.mbTopAutoShow ? DataPilotFieldShowItemsMode::FROM_TOP : DataPilotFieldShowItemsMode::FROM_BOTTOM;
+ aAutoShowInfo.ItemCount = maModel.mnAutoShowItems;
+ if( const PivotCacheField* pCacheField = mrPivotTable.getCacheFieldOfDataField( maModel.mnAutoShowRankBy ) )
+ aAutoShowInfo.DataField = pCacheField->getName();
+ aPropSet.setProperty( PROP_AutoShowInfo, aAutoShowInfo );
+ }
+
+ // auto sort
+ DataPilotFieldSortInfo aSortInfo;
+ aSortInfo.IsAscending = maModel.mnSortType == XML_ascending;
+ if( (maModel.mnSortType != XML_ascending) && (maModel.mnSortType != XML_descending) )
+ {
+ aSortInfo.Mode = DataPilotFieldSortMode::MANUAL;
+ }
+ else
+ {
+ const PivotCacheField* pCacheField = (maModel.mnSortRefField == OOX_PT_DATALAYOUTFIELD) ?
+ mrPivotTable.getCacheFieldOfDataField( maModel.mnSortRefItem ) : 0;
+ if( pCacheField )
+ {
+ aSortInfo.Mode = DataPilotFieldSortMode::DATA;
+ aSortInfo.Field = pCacheField->getName();
+ }
+ else
+ {
+ aSortInfo.Mode = DataPilotFieldSortMode::NAME;
+ }
+ }
+ aPropSet.setProperty( PROP_SortInfo, aSortInfo );
+
+ // item settings
+ if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) ) try
+ {
+ Reference< XNameAccess > xDPItemsNA( xDPField->getItems(), UNO_QUERY_THROW );
+ for( ItemModelVector::iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
+ {
+ if( aIt->mnType == XML_data )
+ {
+ if( const PivotCacheItem* pSharedItem = pCacheField->getCacheItem( aIt->mnCacheItem ) ) try
+ {
+ PropertySet aItemProp( xDPItemsNA->getByName( pSharedItem->getName() ) );
+ aItemProp.setProperty( PROP_ShowDetail, aIt->mbShowDetails );
+ aItemProp.setProperty( PROP_IsHidden, aIt->mbHidden );
+ }
+ catch( Exception& )
+ {
+ // catch every failed container access to be able to process following items
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ }
+ return xDPField;
+}
+
+// ============================================================================
+
+PTFilterModel::PTFilterModel() :
+ mfValue( 0.0 ),
+ mnField( -1 ),
+ mnMemPropField( -1 ),
+ mnType( XML_TOKEN_INVALID ),
+ mnEvalOrder( 0 ),
+ mnId( -1 ),
+ mnMeasureField( -1 ),
+ mnMeasureHier( -1 ),
+ mbTopFilter( true )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PivotTableFilter::PivotTableFilter( const PivotTable& rPivotTable ) :
+ WorkbookHelper( rPivotTable ),
+ mrPivotTable( rPivotTable )
+{
+}
+
+void PivotTableFilter::importFilter( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ maModel.maDescription = rAttribs.getXString( XML_description, OUString() );
+ maModel.maStrValue1 = rAttribs.getXString( XML_stringValue1, OUString() );
+ maModel.maStrValue2 = rAttribs.getXString( XML_stringValue2, OUString() );
+ maModel.mnField = rAttribs.getInteger( XML_fld, -1 );
+ maModel.mnMemPropField = rAttribs.getInteger( XML_mpFld, -1 );
+ maModel.mnType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
+ maModel.mnEvalOrder = rAttribs.getInteger( XML_evalOrder, 0 );
+ maModel.mnId = rAttribs.getInteger( XML_id, -1 );
+ maModel.mnMeasureField = rAttribs.getInteger( XML_iMeasureFld, -1 );
+ maModel.mnMeasureHier = rAttribs.getInteger( XML_iMeasureHier, -1 );
+}
+
+void PivotTableFilter::importTop10( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( rAttribs.getBool( XML_percent, false ) == (maModel.mnType == XML_percent),
+ "PivotTableFilter::importTop10 - unexpected value of percent attribute" );
+ maModel.mfValue = rAttribs.getDouble( XML_val, 0.0 );
+ maModel.mbTopFilter = rAttribs.getBool( XML_top, true );
+}
+
+void PivotTableFilter::importPTFilter( RecordInputStream& rStrm )
+{
+ sal_Int32 nType;
+ sal_uInt16 nFlags;
+ rStrm >> maModel.mnField >> maModel.mnMemPropField >> nType;
+ rStrm.skip( 4 ); // unused
+ rStrm >> maModel.mnId >> maModel.mnMeasureField >> maModel.mnMeasureHier >> nFlags;
+ if( getFlag( nFlags, OOBIN_PTFILTER_HASNAME ) )
+ rStrm >> maModel.maName;
+ if( getFlag( nFlags, OOBIN_PTFILTER_HASDESCRIPTION ) )
+ rStrm >> maModel.maDescription;
+ if( getFlag( nFlags, OOBIN_PTFILTER_HASSTRVALUE1 ) )
+ rStrm >> maModel.maStrValue1;
+ if( getFlag( nFlags, OOBIN_PTFILTER_HASSTRVALUE2 ) )
+ rStrm >> maModel.maStrValue2;
+
+ static sal_Int32 spnTypes[] =
+ {
+ XML_unknown,
+ // data field top10 filter (1-3)
+ XML_count, XML_percent, XML_sum,
+ // caption filter (4-17)
+ XML_captionEqual, XML_captionNotEqual,
+ XML_captionBeginsWith, XML_captionNotBeginsWith, XML_captionEndsWith, XML_captionNotEndsWith,
+ XML_captionContains, XML_captionNotContains, XML_captionGreaterThan, XML_captionGreaterThanOrEqual,
+ XML_captionLessThan, XML_captionLessThanOrEqual, XML_captionBetween, XML_captionNotBetween,
+ // value filter (18-25)
+ XML_valueEqual, XML_valueNotEqual, XML_valueGreaterThan, XML_valueGreaterThanOrEqual,
+ XML_valueLessThan, XML_valueLessThanOrEqual, XML_valueBetween, XML_valueNotBetween,
+ // date filter (26-65)
+ XML_dateEqual, XML_dateOlderThan, XML_dateNewerThan, XML_dateBetween,
+ XML_tomorrow, XML_today, XML_yesterday, XML_nextWeek, XML_thisWeek, XML_lastWeek,
+ XML_nextMonth, XML_thisMonth, XML_lastMonth, XML_nextQuarter, XML_thisQuarter, XML_lastQuarter,
+ XML_nextYear, XML_thisYear, XML_lastYear, XML_yearToDate, XML_Q1, XML_Q2, XML_Q3, XML_Q4,
+ XML_M1, XML_M2, XML_M3, XML_M4, XML_M5, XML_M6, XML_M7, XML_M8, XML_M9, XML_M10, XML_M11, XML_M12,
+ XML_dateNotEqual, XML_dateOlderThanOrEqual, XML_dateNewerThanOrEqual, XML_dateNotBetween
+ };
+ maModel.mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_TOKEN_INVALID );
+}
+
+void PivotTableFilter::importTop10Filter( RecordInputStream& rStrm )
+{
+ sal_uInt8 nFlags;
+ rStrm >> nFlags >> maModel.mfValue;
+
+ OSL_ENSURE( getFlag( nFlags, OOBIN_TOP10FILTER_PERCENT ) == (maModel.mnType == XML_percent),
+ "PivotTableFilter::importTop10 - unexpected value of percent attribute" );
+ maModel.mbTopFilter = getFlag( nFlags, OOBIN_TOP10FILTER_TOP );
+}
+
+void PivotTableFilter::finalizeImport()
+{
+ // only simple top10 filter supported
+ if( maModel.mnType == XML_count )
+ {
+ PropertySet aPropSet( mrPivotTable.getDataPilotField( maModel.mnField ) );
+ if( aPropSet.is() )
+ {
+ using namespace ::com::sun::star::sheet;
+ DataPilotFieldAutoShowInfo aAutoShowInfo;
+ aAutoShowInfo.IsEnabled = sal_True;
+ aAutoShowInfo.ShowItemsMode = maModel.mbTopFilter ? DataPilotFieldShowItemsMode::FROM_TOP : DataPilotFieldShowItemsMode::FROM_BOTTOM;
+ aAutoShowInfo.ItemCount = getLimitedValue< sal_Int32, double >( maModel.mfValue, 0, SAL_MAX_INT32 );
+ if( const PivotCacheField* pCacheField = mrPivotTable.getCacheFieldOfDataField( maModel.mnMeasureField ) )
+ aAutoShowInfo.DataField = pCacheField->getName();
+ aPropSet.setProperty( PROP_AutoShowInfo, aAutoShowInfo );
+ }
+ }
+}
+
+// ============================================================================
+
+PTDefinitionModel::PTDefinitionModel() :
+ mnCacheId( -1 ),
+ mnDataPosition( 0 ),
+ mnPageWrap( 0 ),
+ mnIndent( 1 ),
+ mnChartFormat( 0 ),
+ mnRowFields( 0 ),
+ mnColFields( 0 ),
+ mbDataOnRows( false ),
+ mbShowError( false ),
+ mbShowMissing( true ),
+ mbShowItems( true ),
+ mbDisableFieldList( false ),
+ mbShowCalcMembers( true ),
+ mbVisualTotals( true ),
+ mbShowDrill( true ),
+ mbPrintDrill( false ),
+ mbEnableDrill( true ),
+ mbPreserveFormatting( true ),
+ mbPageOverThenDown( false ),
+ mbSubtotalHiddenItems( false ),
+ mbRowGrandTotals( true ),
+ mbColGrandTotals( true ),
+ mbFieldPrintTitles( false ),
+ mbItemPrintTitles( false ),
+ mbMergeItem( false ),
+ mbShowEmptyRow( false ),
+ mbShowEmptyCol( false ),
+ mbShowHeaders( true ),
+ mbFieldListSortAsc( false ),
+ mbCustomListSort( true )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PTLocationModel::PTLocationModel() :
+ mnFirstHeaderRow( 0 ),
+ mnFirstDataRow( 0 ),
+ mnFirstDataCol( 0 ),
+ mnRowPageCount( 0 ),
+ mnColPageCount( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PivotTable::PivotTable( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maDataField( *this, OOX_PT_DATALAYOUTFIELD ),
+ mpPivotCache( 0 )
+{
+}
+
+void PivotTable::importPivotTableDefinition( const AttributeList& rAttribs )
+{
+ maDefModel.maName = rAttribs.getXString( XML_name, OUString() );
+ maDefModel.maDataCaption = rAttribs.getXString( XML_dataCaption , OUString() );
+ maDefModel.maGrandTotalCaption = rAttribs.getXString( XML_grandTotalCaption, OUString() );
+ maDefModel.maRowHeaderCaption = rAttribs.getXString( XML_rowHeaderCaption, OUString() );
+ maDefModel.maColHeaderCaption = rAttribs.getXString( XML_colHeaderCaption, OUString() );
+ maDefModel.maErrorCaption = rAttribs.getXString( XML_errorCaption, OUString() );
+ maDefModel.maMissingCaption = rAttribs.getXString( XML_missingCaption, OUString() );
+ maDefModel.maPageStyle = rAttribs.getXString( XML_pageStyle, OUString() );
+ maDefModel.maPivotTableStyle = rAttribs.getXString( XML_pivotTableStyle, OUString() );
+ maDefModel.maVacatedStyle = rAttribs.getXString( XML_vacatedStyle, OUString() );
+ maDefModel.maTag = rAttribs.getXString( XML_tag, OUString() );
+ maDefModel.mnCacheId = rAttribs.getInteger( XML_cacheId, -1 );
+ maDefModel.mnDataPosition = rAttribs.getInteger( XML_dataPosition, 0 );
+ maDefModel.mnPageWrap = rAttribs.getInteger( XML_pageWrap, 0 );
+ maDefModel.mnIndent = rAttribs.getInteger( XML_indent, 1 );
+ maDefModel.mnChartFormat = rAttribs.getInteger( XML_chartFormat, 0 );
+ maDefModel.mbDataOnRows = rAttribs.getBool( XML_dataOnRows, false );
+ maDefModel.mbShowError = rAttribs.getBool( XML_showError, false );
+ maDefModel.mbShowMissing = rAttribs.getBool( XML_showMissing, true );
+ maDefModel.mbShowItems = rAttribs.getBool( XML_showItems, true );
+ maDefModel.mbDisableFieldList = rAttribs.getBool( XML_disableFieldList, false );
+ maDefModel.mbShowCalcMembers = rAttribs.getBool( XML_showCalcMbrs, true );
+ maDefModel.mbVisualTotals = rAttribs.getBool( XML_visualTotals, true );
+ maDefModel.mbShowDrill = rAttribs.getBool( XML_showDrill, true );
+ maDefModel.mbPrintDrill = rAttribs.getBool( XML_printDrill, false );
+ maDefModel.mbEnableDrill = rAttribs.getBool( XML_enableDrill, true );
+ maDefModel.mbPreserveFormatting = rAttribs.getBool( XML_preserveFormatting, true );
+ maDefModel.mbPageOverThenDown = rAttribs.getBool( XML_pageOverThenDown, false );
+ maDefModel.mbSubtotalHiddenItems = rAttribs.getBool( XML_subtotalHiddenItems, false );
+ maDefModel.mbRowGrandTotals = rAttribs.getBool( XML_rowGrandTotals, true );
+ maDefModel.mbColGrandTotals = rAttribs.getBool( XML_colGrandTotals, true );
+ maDefModel.mbFieldPrintTitles = rAttribs.getBool( XML_fieldPrintTitles, false );
+ maDefModel.mbItemPrintTitles = rAttribs.getBool( XML_itemPrintTitles, false );
+ maDefModel.mbMergeItem = rAttribs.getBool( XML_mergeItem, false );
+ maDefModel.mbShowEmptyRow = rAttribs.getBool( XML_showEmptyRow, false );
+ maDefModel.mbShowEmptyCol = rAttribs.getBool( XML_showEmptyCol, false );
+ maDefModel.mbShowHeaders = rAttribs.getBool( XML_showHeaders, true );
+ maDefModel.mbFieldListSortAsc = rAttribs.getBool( XML_fieldListSortAscending, false );
+ maDefModel.mbCustomListSort = rAttribs.getBool( XML_customListSort, true );
+}
+
+void PivotTable::importLocation( const AttributeList& rAttribs, sal_Int16 nSheet )
+{
+ getAddressConverter().convertToCellRangeUnchecked( maLocationModel.maRange, rAttribs.getString( XML_ref, OUString() ), nSheet );
+ maLocationModel.mnFirstHeaderRow = rAttribs.getInteger( XML_firstHeaderRow, 0 );
+ maLocationModel.mnFirstDataRow = rAttribs.getInteger( XML_firstDataRow, 0 );
+ maLocationModel.mnFirstDataCol = rAttribs.getInteger( XML_firstDataCol, 0 );
+ maLocationModel.mnRowPageCount = rAttribs.getInteger( XML_rowPageCount, 0 );
+ maLocationModel.mnColPageCount = rAttribs.getInteger( XML_colPageCount, 0 );
+}
+
+void PivotTable::importRowField( const AttributeList& rAttribs )
+{
+ importField( maRowFields, rAttribs );
+}
+
+void PivotTable::importColField( const AttributeList& rAttribs )
+{
+ importField( maColFields, rAttribs );
+}
+
+void PivotTable::importPageField( const AttributeList& rAttribs )
+{
+ PTPageFieldModel aModel;
+ aModel.maName = rAttribs.getXString( XML_name, OUString() );
+ aModel.mnField = rAttribs.getInteger( XML_fld, -1 );
+ // specification is wrong, XML_item is not the cache item, but the field item
+ aModel.mnItem = rAttribs.getInteger( XML_item, OOBIN_PTPAGEFIELD_MULTIITEMS );
+ maPageFields.push_back( aModel );
+}
+
+void PivotTable::importDataField( const AttributeList& rAttribs )
+{
+ PTDataFieldModel aModel;
+ aModel.maName = rAttribs.getXString( XML_name, OUString() );
+ aModel.mnField = rAttribs.getInteger( XML_fld, -1 );
+ aModel.mnSubtotal = rAttribs.getToken( XML_subtotal, XML_sum );
+ aModel.mnShowDataAs = rAttribs.getToken( XML_showDataAs, XML_normal );
+ aModel.mnBaseField = rAttribs.getInteger( XML_baseField, -1 );
+ aModel.mnBaseItem = rAttribs.getInteger( XML_baseItem, -1 );
+ aModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
+ maDataFields.push_back( aModel );
+}
+
+void PivotTable::importPTDefinition( RecordInputStream& rStrm )
+{
+ sal_uInt32 nFlags1, nFlags2, nFlags3;
+ sal_uInt8 nDataAxis;
+ rStrm >> nFlags1 >> nFlags2 >> nFlags3 >> nDataAxis;
+ maDefModel.mnPageWrap = rStrm.readuInt8();
+ rStrm.skip( 2 ); // refresh versions
+ rStrm >> maDefModel.mnDataPosition;
+ rStrm.skip( 4 ); // 2 bytes autoformat id, 2 bytes unused
+ rStrm >> maDefModel.mnChartFormat >> maDefModel.mnCacheId >> maDefModel.maName;
+ if( getFlag( nFlags2, OOBIN_PTDEF_HASDATACAPTION ) )
+ rStrm >> maDefModel.maDataCaption;
+ if( getFlag( nFlags2, OOBIN_PTDEF_HASGRANDTOTALCAPTION ) )
+ rStrm >> maDefModel.maGrandTotalCaption;
+ if( !getFlag( nFlags3, OOBIN_PTDEF_NOERRORCAPTION ) ) // missing flag indicates existing string
+ rStrm >> maDefModel.maErrorCaption;
+ if( !getFlag( nFlags3, OOBIN_PTDEF_NOMISSINGCAPTION ) ) // missing flag indicates existing string
+ rStrm >> maDefModel.maMissingCaption;
+ if( getFlag( nFlags2, OOBIN_PTDEF_HASPAGESTYLE ) )
+ rStrm >> maDefModel.maPageStyle;
+ if( getFlag( nFlags2, OOBIN_PTDEF_HASPIVOTTABLESTYLE ) )
+ rStrm >> maDefModel.maPivotTableStyle;
+ if( getFlag( nFlags2, OOBIN_PTDEF_HASVACATEDSTYLE ) )
+ rStrm >> maDefModel.maVacatedStyle;
+ if( getFlag( nFlags2, OOBIN_PTDEF_HASTAG ) )
+ rStrm >> maDefModel.maTag;
+ if( getFlag( nFlags3, OOBIN_PTDEF_HASCOLHEADERCAPTION ) ) // TODO: right order (col/row)? spec is unclear
+ rStrm >> maDefModel.maColHeaderCaption;
+ if( getFlag( nFlags3, OOBIN_PTDEF_HASROWHEADERCAPTION ) )
+ rStrm >> maDefModel.maRowHeaderCaption;
+
+ OSL_ENSURE( (nDataAxis == OOBIN_PTDEF_ROWAXIS) || (nDataAxis == OOBIN_PTDEF_COLAXIS),
+ "PivotTable::importPTDefinition - unexpected axis position for data field" );
+
+ maDefModel.mnIndent = extractValue< sal_uInt8 >( nFlags1, 24, 7 );
+ maDefModel.mbDataOnRows = nDataAxis == OOBIN_PTDEF_ROWAXIS;
+ maDefModel.mbShowError = getFlag( nFlags2, OOBIN_PTDEF_SHOWERROR );
+ maDefModel.mbShowMissing = getFlag( nFlags2, OOBIN_PTDEF_SHOWMISSING );
+ maDefModel.mbShowItems = getFlag( nFlags1, OOBIN_PTDEF_SHOWITEMS );
+ maDefModel.mbDisableFieldList = getFlag( nFlags1, OOBIN_PTDEF_DISABLEFIELDLIST );
+ maDefModel.mbShowCalcMembers = !getFlag( nFlags1, OOBIN_PTDEF_HIDECALCMEMBERS );
+ maDefModel.mbVisualTotals = !getFlag( nFlags1, OOBIN_PTDEF_WITHHIDDENTOTALS );
+ maDefModel.mbShowDrill = !getFlag( nFlags1, OOBIN_PTDEF_HIDEDRILL );
+ maDefModel.mbPrintDrill = getFlag( nFlags1, OOBIN_PTDEF_PRINTDRILL );
+ maDefModel.mbEnableDrill = getFlag( nFlags2, OOBIN_PTDEF_ENABLEDRILL );
+ maDefModel.mbPreserveFormatting = getFlag( nFlags2, OOBIN_PTDEF_PRESERVEFORMATTING );
+ maDefModel.mbPageOverThenDown = getFlag( nFlags2, OOBIN_PTDEF_PAGEOVERTHENDOWN );
+ maDefModel.mbSubtotalHiddenItems = getFlag( nFlags2, OOBIN_PTDEF_SUBTOTALHIDDENITEMS );
+ maDefModel.mbRowGrandTotals = getFlag( nFlags2, OOBIN_PTDEF_ROWGRANDTOTALS );
+ maDefModel.mbColGrandTotals = getFlag( nFlags2, OOBIN_PTDEF_COLGRANDTOTALS );
+ maDefModel.mbFieldPrintTitles = getFlag( nFlags2, OOBIN_PTDEF_FIELDPRINTTITLES );
+ maDefModel.mbItemPrintTitles = getFlag( nFlags2, OOBIN_PTDEF_ITEMPRINTTITLES );
+ maDefModel.mbMergeItem = getFlag( nFlags2, OOBIN_PTDEF_MERGEITEM );
+ maDefModel.mbShowEmptyRow = getFlag( nFlags2, OOBIN_PTDEF_SHOWEMPTYROW );
+ maDefModel.mbShowEmptyCol = getFlag( nFlags2, OOBIN_PTDEF_SHOWEMPTYCOL );
+ maDefModel.mbShowHeaders = !getFlag( nFlags1, OOBIN_PTDEF_HIDEHEADERS );
+ maDefModel.mbFieldListSortAsc = getFlag( nFlags3, OOBIN_PTDEF_FIELDLISTSORTASC );
+ maDefModel.mbCustomListSort = !getFlag( nFlags3, OOBIN_PTDEF_NOCUSTOMLISTSORT );
+}
+
+void PivotTable::importPTLocation( RecordInputStream& rStrm, sal_Int16 nSheet )
+{
+ BinRange aBinRange;
+ rStrm >> aBinRange >> maLocationModel.mnFirstHeaderRow
+ >> maLocationModel.mnFirstDataRow >> maLocationModel.mnFirstDataCol
+ >> maLocationModel.mnRowPageCount >> maLocationModel.mnColPageCount;
+ getAddressConverter().convertToCellRangeUnchecked( maLocationModel.maRange, aBinRange, nSheet );
+}
+
+void PivotTable::importPTRowFields( RecordInputStream& rStrm )
+{
+ importFields( maRowFields, rStrm );
+}
+
+void PivotTable::importPTColFields( RecordInputStream& rStrm )
+{
+ importFields( maColFields, rStrm );
+}
+
+void PivotTable::importPTPageField( RecordInputStream& rStrm )
+{
+ PTPageFieldModel aModel;
+ sal_uInt8 nFlags;
+ rStrm >> aModel.mnField >> aModel.mnItem;
+ rStrm.skip( 4 ); // hierarchy
+ rStrm >> nFlags;
+ if( getFlag( nFlags, OOBIN_PTPAGEFIELD_HASNAME ) )
+ rStrm >> aModel.maName;
+ maPageFields.push_back( aModel );
+}
+
+void PivotTable::importPTDataField( RecordInputStream& rStrm )
+{
+ PTDataFieldModel aModel;
+ sal_Int32 nSubtotal, nShowDataAs;
+ sal_uInt8 nHasName;
+ rStrm >> aModel.mnField >> nSubtotal >> nShowDataAs >> aModel.mnBaseField >> aModel.mnBaseItem >> aModel.mnNumFmtId >> nHasName;
+ if( nHasName == 1 )
+ rStrm >> aModel.maName;
+ aModel.setBinSubtotal( nSubtotal );
+ aModel.setBinShowDataAs( nShowDataAs );
+ maDataFields.push_back( aModel );
+}
+
+void PivotTable::importPTDefinition( BiffInputStream& rStrm, sal_Int16 nSheet )
+{
+ BinRange aBinRange;
+ sal_uInt16 nFlags, nTabNameLen, nDataNameLen;
+ rStrm >> aBinRange;
+ maLocationModel.mnFirstHeaderRow = rStrm.readuInt16();
+ maLocationModel.mnFirstDataRow = rStrm.readuInt16();
+ maLocationModel.mnFirstDataCol = rStrm.readuInt16();
+ maDefModel.mnCacheId = rStrm.readuInt16();
+ rStrm.skip( 2 ); // unused
+ maDefModel.mbDataOnRows = rStrm.readuInt16() == BIFF_PTDEF_ROWAXIS;
+ maDefModel.mnDataPosition = rStrm.readInt16();
+ rStrm.skip( 2 ); // number of fields
+ rStrm >> maDefModel.mnRowFields >> maDefModel.mnColFields;
+ rStrm.skip( 8 ); // number of page fields, data fields, data rows, data columns
+ rStrm >> nFlags;
+ maDefModel.mnChartFormat = rStrm.readuInt16();
+ rStrm >> nTabNameLen >> nDataNameLen;
+ maDefModel.maName = lclReadPivotString( *this, rStrm, nTabNameLen );
+ maDefModel.maDataCaption = lclReadPivotString( *this, rStrm, nDataNameLen );
+
+ maDefModel.mbRowGrandTotals = getFlag( nFlags, BIFF_PTDEF_ROWGRANDTOTALS );
+ maDefModel.mbColGrandTotals = getFlag( nFlags, BIFF_PTDEF_COLGRANDTOTALS );
+
+ getAddressConverter().convertToCellRangeUnchecked( maLocationModel.maRange, aBinRange, nSheet );
+}
+
+void PivotTable::importPTDefinition2( BiffInputStream& rStrm )
+{
+ if( getBiff() == BIFF8 )
+ {
+ sal_uInt16 nErrCaptLen, nMissCaptLen, nTagLen, nPageStyleLen, nTabStyleLen, nVacStyleLen;
+ sal_uInt32 nFlags;
+ rStrm.skip( 2 ); // number of formatting records
+ rStrm >> nErrCaptLen >> nMissCaptLen >> nTagLen;
+ rStrm.skip( 6 ); // number of selection records, page rows, page columns
+ rStrm >> nFlags >> nPageStyleLen >> nTabStyleLen >> nVacStyleLen;
+ maDefModel.maErrorCaption = lclReadPivotString( *this, rStrm, nErrCaptLen );
+ maDefModel.maMissingCaption = lclReadPivotString( *this, rStrm, nMissCaptLen );
+ maDefModel.maTag = lclReadPivotString( *this, rStrm, nTagLen );
+ maDefModel.maPageStyle = lclReadPivotString( *this, rStrm, nPageStyleLen );
+ maDefModel.maPivotTableStyle = lclReadPivotString( *this, rStrm, nTabStyleLen );
+ maDefModel.maVacatedStyle = lclReadPivotString( *this, rStrm, nVacStyleLen );
+
+ maDefModel.mbShowError = getFlag( nFlags, BIFF_PTDEF2_SHOWERROR );
+ maDefModel.mbShowMissing = getFlag( nFlags, BIFF_PTDEF2_SHOWMISSING );
+ maDefModel.mbEnableDrill = getFlag( nFlags, BIFF_PTDE2F_ENABLEDRILL );
+ maDefModel.mbPreserveFormatting = getFlag( nFlags, BIFF_PTDEF2_PRESERVEFORMATTING );
+ maDefModel.mbPageOverThenDown = getFlag( nFlags, BIFF_PTDEF2_PAGEOVERTHENDOWN );
+ maDefModel.mbSubtotalHiddenItems = getFlag( nFlags, BIFF_PTDEF2_SUBTOTALHIDDENITEMS );
+ maDefModel.mbMergeItem = getFlag( nFlags, BIFF_PTDEF2_MERGEITEM );
+ }
+}
+
+void PivotTable::importPTRowColFields( BiffInputStream& rStrm )
+{
+ // first PTROWCOLFIELDS record contains row fields unless there are no row fields
+ if( (maDefModel.mnRowFields > 0) && maRowFields.empty() )
+ importFields( maRowFields, rStrm, maDefModel.mnRowFields );
+ else if( (maDefModel.mnColFields > 0) && maColFields.empty() )
+ importFields( maColFields, rStrm, maDefModel.mnColFields );
+}
+
+void PivotTable::importPTPageFields( BiffInputStream& rStrm )
+{
+ while( rStrm.getRemaining() >= 6 )
+ {
+ PTPageFieldModel aModel;
+ sal_Int16 nField, nItem;
+ rStrm >> nField >> nItem;
+ rStrm.skip( 2 ); // dropdown object ID
+ aModel.mnField = nField;
+ aModel.mnItem = (nItem == BIFF_PTPAGEFIELDS_ALLITEMS) ? OOBIN_PTPAGEFIELD_MULTIITEMS : nItem;
+ maPageFields.push_back( aModel );
+ }
+}
+
+void PivotTable::importPTDataField( BiffInputStream& rStrm )
+{
+ PTDataFieldModel aModel;
+ sal_Int16 nField, nBaseField, nBaseItem;
+ sal_uInt16 nSubtotal, nShowDataAs, nNumFmt, nNameLen;
+ rStrm >> nField >> nSubtotal >> nShowDataAs >> nBaseField >> nBaseItem >> nNumFmt >> nNameLen;
+ aModel.maName = lclReadPivotString( *this, rStrm, nNameLen );
+
+ aModel.mnField = nField;
+ aModel.setBinSubtotal( nSubtotal );
+ aModel.setBinShowDataAs( nShowDataAs );
+ aModel.mnBaseField = nBaseField;
+ switch( nBaseItem )
+ {
+ case BIFF_PTDATAFIELD_PREVIOUS: aModel.mnBaseItem = OOX_PT_PREVIOUS_ITEM; break;
+ case BIFF_PTDATAFIELD_NEXT: aModel.mnBaseItem = OOX_PT_NEXT_ITEM; break;
+ default: aModel.mnBaseItem = nBaseItem;
+ }
+ aModel.mnNumFmtId = nNumFmt;
+
+ maDataFields.push_back( aModel );
+}
+
+PivotTableField& PivotTable::createTableField()
+{
+ sal_Int32 nFieldIndex = static_cast< sal_Int32 >( maFields.size() );
+ PivotTableFieldVector::value_type xTableField( new PivotTableField( *this, nFieldIndex ) );
+ maFields.push_back( xTableField );
+ return *xTableField;
+}
+
+PivotTableFilter& PivotTable::createTableFilter()
+{
+ PivotTableFilterVector::value_type xTableFilter( new PivotTableFilter( *this ) );
+ maFilters.push_back( xTableFilter );
+ return *xTableFilter;
+}
+
+void PivotTable::finalizeImport()
+{
+ if( getAddressConverter().validateCellRange( maLocationModel.maRange, true, true ) )
+ {
+ mpPivotCache = getPivotCaches().importPivotCacheFragment( maDefModel.mnCacheId );
+ if( mpPivotCache && mpPivotCache->isValidDataSource() && (maDefModel.maName.getLength() > 0) )
+ {
+ // clear destination area of the original pivot table
+ try
+ {
+ Reference< XSheetOperation > xSheetOp( getCellRangeFromDoc( maLocationModel.maRange ), UNO_QUERY_THROW );
+ using namespace ::com::sun::star::sheet::CellFlags;
+ xSheetOp->clearContents( VALUE | DATETIME | STRING | FORMULA | HARDATTR | STYLES | EDITATTR | FORMATTED );
+ }
+ catch( Exception& )
+ {
+ }
+
+ try
+ {
+ // create a new data pilot descriptor based on the source data
+ Reference< XDataPilotTablesSupplier > xDPTablesSupp( getSheetFromDoc( maLocationModel.maRange.Sheet ), UNO_QUERY_THROW );
+ Reference< XDataPilotTables > xDPTables( xDPTablesSupp->getDataPilotTables(), UNO_SET_THROW );
+ mxDPDescriptor.set( xDPTables->createDataPilotDescriptor(), UNO_SET_THROW );
+ mxDPDescriptor->setSourceRange( mpPivotCache->getSourceRange() );
+ mxDPDescriptor->setTag( maDefModel.maTag );
+
+ // global data pilot properties
+ PropertySet aDescProp( mxDPDescriptor );
+ aDescProp.setProperty( PROP_ColumnGrand, maDefModel.mbColGrandTotals );
+ aDescProp.setProperty( PROP_RowGrand, maDefModel.mbRowGrandTotals );
+ aDescProp.setProperty( PROP_ShowFilterButton, false );
+ aDescProp.setProperty( PROP_DrillDownOnDoubleClick, maDefModel.mbEnableDrill );
+
+ // finalize all fields, this finds field names and creates grouping fields
+ maFields.forEachMem( &PivotTableField::finalizeImport, ::boost::cref( mxDPDescriptor ) );
+
+ // all row fields
+ for( IndexVector::iterator aIt = maRowFields.begin(), aEnd = maRowFields.end(); aIt != aEnd; ++aIt )
+ if( PivotTableField* pField = getTableField( *aIt ) )
+ pField->convertRowField();
+
+ // all column fields
+ for( IndexVector::iterator aIt = maColFields.begin(), aEnd = maColFields.end(); aIt != aEnd; ++aIt )
+ if( PivotTableField* pField = getTableField( *aIt ) )
+ pField->convertColField();
+
+ // all page fields
+ for( PageFieldVector::iterator aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
+ if( PivotTableField* pField = getTableField( aIt->mnField ) )
+ pField->convertPageField( *aIt );
+
+ // all hidden fields
+ ::std::set< sal_Int32 > aVisFields;
+ aVisFields.insert( maRowFields.begin(), maRowFields.end() );
+ aVisFields.insert( maColFields.begin(), maColFields.end() );
+ for( PageFieldVector::iterator aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
+ aVisFields.insert( aIt->mnField );
+ for( PivotTableFieldVector::iterator aBeg = maFields.begin(), aIt = aBeg, aEnd = maFields.end(); aIt != aEnd; ++aIt )
+ if( aVisFields.count( static_cast< sal_Int32 >( aIt - aBeg ) ) == 0 )
+ (*aIt)->convertHiddenField();
+
+ // all data fields
+ for( DataFieldVector::iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
+ if( PivotTableField* pField = getTableField( aIt->mnField ) )
+ pField->convertDataField( *aIt );
+
+ // filters
+ maFilters.forEachMem( &PivotTableFilter::finalizeImport );
+
+ // calculate base position of table
+ CellAddress aPos( maLocationModel.maRange.Sheet, maLocationModel.maRange.StartColumn, maLocationModel.maRange.StartRow );
+ /* If page fields exist, include them into the destination
+ area (they are excluded in Excel). Add an extra blank row. */
+ if( !maPageFields.empty() )
+ aPos.Row = ::std::max< sal_Int32 >( static_cast< sal_Int32 >( aPos.Row - maPageFields.size() - 1 ), 0 );
+
+ // insert the DataPilot table into the sheet
+ xDPTables->insertNewByName( maDefModel.maName, aPos, mxDPDescriptor );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "PivotTable::finalizeImport - exception while creating the DataPilot table" );
+ }
+ }
+ }
+}
+
+void PivotTable::finalizeDateGroupingImport( const Reference< XDataPilotField >& rxBaseDPField, sal_Int32 nBaseFieldIdx )
+{
+ // process all fields, there is no chaining information in the cache fields
+ maFields.forEachMem( &PivotTableField::finalizeDateGroupingImport, ::boost::cref( rxBaseDPField ), nBaseFieldIdx );
+}
+
+void PivotTable::finalizeParentGroupingImport( const Reference< XDataPilotField >& rxBaseDPField,
+ const PivotCacheField& rBaseCacheField, PivotCacheGroupItemVector& orItemNames )
+{
+ // try to create parent group fields that group the items of the passed base field
+ if( PivotTableField* pParentTableField = maFields.get( rBaseCacheField.getParentGroupField() ).get() )
+ pParentTableField->finalizeParentGroupingImport( rxBaseDPField, orItemNames );
+}
+
+Reference< XDataPilotField > PivotTable::getDataPilotField( const OUString& rFieldName ) const
+{
+ Reference< XDataPilotField > xDPField;
+ if( (rFieldName.getLength() > 0) && mxDPDescriptor.is() ) try
+ {
+ Reference< XNameAccess > xDPFieldsNA( mxDPDescriptor->getDataPilotFields(), UNO_QUERY_THROW );
+ xDPField.set( xDPFieldsNA->getByName( rFieldName ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ return xDPField;
+}
+
+Reference< XDataPilotField > PivotTable::getDataPilotField( sal_Int32 nFieldIdx ) const
+{
+ Reference< XDataPilotField > xDPField;
+ if( const PivotTableField* pTableField = maFields.get( nFieldIdx ).get() )
+ xDPField = getDataPilotField( pTableField->getDPFieldName() );
+ return xDPField;
+}
+
+Reference< XDataPilotField > PivotTable::getDataLayoutField() const
+{
+ Reference< XDataPilotField > xDPField;
+ try
+ {
+ Reference< XDataPilotDataLayoutFieldSupplier > xDPDataFieldSupp( mxDPDescriptor, UNO_QUERY_THROW );
+ xDPField = xDPDataFieldSupp->getDataLayoutField();
+ }
+ catch( Exception& )
+ {
+ }
+ return xDPField;
+}
+
+const PivotCacheField* PivotTable::getCacheField( sal_Int32 nFieldIdx ) const
+{
+ return mpPivotCache ? mpPivotCache->getCacheField( nFieldIdx ) : 0;
+}
+
+const PivotCacheField* PivotTable::getCacheFieldOfDataField( sal_Int32 nDataItemIdx ) const
+{
+ const PTDataFieldModel* pDataField = ContainerHelper::getVectorElement( maDataFields, nDataItemIdx );
+ return pDataField ? getCacheField( pDataField->mnField ) : 0;
+}
+
+sal_Int32 PivotTable::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const
+{
+ return mpPivotCache ? mpPivotCache->getCacheDatabaseIndex( nFieldIdx ) : -1;
+}
+
+// private --------------------------------------------------------------------
+
+PivotTableField* PivotTable::getTableField( sal_Int32 nFieldIdx )
+{
+ return (nFieldIdx == OOX_PT_DATALAYOUTFIELD) ? &maDataField : maFields.get( nFieldIdx ).get();
+}
+
+void PivotTable::importField( IndexVector& orFields, const AttributeList& rAttribs )
+{
+ orFields.push_back( rAttribs.getInteger( XML_x, -1 ) );
+}
+
+void PivotTable::importFields( IndexVector& orFields, RecordInputStream& rStrm )
+{
+ OSL_ENSURE( orFields.empty(), "PivotTable::importFields - multiple record instances" );
+ orFields.clear();
+ sal_Int32 nCount = rStrm.readInt32();
+ OSL_ENSURE( 4 * nCount == rStrm.getRemaining(), "PivotTable::importFields - invalid field count" );
+ nCount = static_cast< sal_Int32 >( rStrm.getRemaining() / 4 );
+ for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
+ orFields.push_back( rStrm.readInt32() );
+}
+
+void PivotTable::importFields( IndexVector& orFields, BiffInputStream& rStrm, sal_Int32 nCount )
+{
+ OSL_ENSURE( orFields.empty(), "PivotTable::importFields - multiple record instances" );
+ orFields.clear();
+ OSL_ENSURE( 2 * nCount == rStrm.getRemaining(), "PivotTable::importFields - invalid field count" );
+ nCount = static_cast< sal_Int32 >( rStrm.getRemaining() / 2 );
+ for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
+ orFields.push_back( rStrm.readInt16() );
+}
+
+// ============================================================================
+
+PivotTableBuffer::PivotTableBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+PivotTable& PivotTableBuffer::createPivotTable()
+{
+ PivotTableVector::value_type xTable( new PivotTable( *this ) );
+ maTables.push_back( xTable );
+ return *xTable;
+}
+
+void PivotTableBuffer::finalizeImport()
+{
+ maTables.forEachMem( &PivotTable::finalizeImport );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/pivottablefragment.cxx b/oox/source/xls/pivottablefragment.cxx
new file mode 100644
index 000000000000..9c34994d482d
--- /dev/null
+++ b/oox/source/xls/pivottablefragment.cxx
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/pivottablefragment.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/pivottablebuffer.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxPivotTableFieldContext::OoxPivotTableFieldContext( OoxWorksheetFragmentBase& rFragment, PivotTableField& rTableField ) :
+ OoxWorksheetContextBase( rFragment ),
+ mrTableField( rTableField )
+{
+}
+
+ContextHandlerRef OoxPivotTableFieldContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( pivotField ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( items ): return this;
+ case XLS_TOKEN( autoSortScope ): return this;
+ }
+ break;
+ case XLS_TOKEN( items ):
+ if( nElement == XLS_TOKEN( item ) ) mrTableField.importItem( rAttribs );
+ break;
+ case XLS_TOKEN( autoSortScope ):
+ if( nElement == XLS_TOKEN( pivotArea ) ) return this;
+ break;
+ case XLS_TOKEN( pivotArea ):
+ if( nElement == XLS_TOKEN( references ) ) return this;
+ break;
+ case XLS_TOKEN( references ):
+ if( nElement == XLS_TOKEN( reference ) ) { mrTableField.importReference( rAttribs ); return this; }
+ break;
+ case XLS_TOKEN( reference ):
+ if( nElement == XLS_TOKEN( x ) ) mrTableField.importReferenceItem( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+void OoxPivotTableFieldContext::onStartElement( const AttributeList& rAttribs )
+{
+ if( isRootElement() )
+ mrTableField.importPivotField( rAttribs );
+}
+
+ContextHandlerRef OoxPivotTableFieldContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_PTFIELD:
+ switch( nRecId )
+ {
+ case OOBIN_ID_PTFITEMS: return this;
+ case OOBIN_ID_AUTOSORTSCOPE: return this;
+ }
+ break;
+ case OOBIN_ID_PTFITEMS:
+ if( nRecId == OOBIN_ID_PTFITEM ) mrTableField.importPTFItem( rStrm );
+ break;
+ case OOBIN_ID_AUTOSORTSCOPE:
+ if( nRecId == OOBIN_ID_PIVOTAREA ) return this;
+ break;
+ case OOBIN_ID_PIVOTAREA:
+ if( nRecId == OOBIN_ID_PTREFERENCES ) return this;
+ break;
+ case OOBIN_ID_PTREFERENCES:
+ if( nRecId == OOBIN_ID_PTREFERENCE ) { mrTableField.importPTReference( rStrm ); return this; }
+ break;
+ case OOBIN_ID_PTREFERENCE:
+ if( nRecId == OOBIN_ID_PTREFERENCEITEM ) mrTableField.importPTReferenceItem( rStrm );
+ break;
+ }
+ return 0;
+}
+
+void OoxPivotTableFieldContext::onStartRecord( RecordInputStream& rStrm )
+{
+ if( isRootElement() )
+ mrTableField.importPTField( rStrm );
+}
+
+// ============================================================================
+
+OoxPivotTableFilterContext::OoxPivotTableFilterContext( OoxWorksheetFragmentBase& rFragment, PivotTableFilter& rTableFilter ) :
+ OoxWorksheetContextBase( rFragment ),
+ mrTableFilter( rTableFilter )
+{
+}
+
+ContextHandlerRef OoxPivotTableFilterContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( filter ):
+ if( nElement == XLS_TOKEN( autoFilter ) ) return this;
+ break;
+ case XLS_TOKEN( autoFilter ):
+ if( nElement == XLS_TOKEN( filterColumn ) ) return this;
+ break;
+ case XLS_TOKEN( filterColumn ):
+ if( nElement == XLS_TOKEN( top10 ) ) mrTableFilter.importTop10( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+void OoxPivotTableFilterContext::onStartElement( const AttributeList& rAttribs )
+{
+ if( isRootElement() )
+ mrTableFilter.importFilter( rAttribs );
+}
+
+ContextHandlerRef OoxPivotTableFilterContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_PTFILTER:
+ if( nRecId == OOBIN_ID_AUTOFILTER ) return this;
+ break;
+ case OOBIN_ID_AUTOFILTER:
+ if( nRecId == OOBIN_ID_FILTERCOLUMN ) return this;
+ break;
+ case OOBIN_ID_FILTERCOLUMN:
+ if( nRecId == OOBIN_ID_TOP10FILTER ) mrTableFilter.importTop10Filter( rStrm );
+ break;
+ }
+ return 0;
+}
+
+void OoxPivotTableFilterContext::onStartRecord( RecordInputStream& rStrm )
+{
+ if( isRootElement() )
+ mrTableFilter.importPTFilter( rStrm );
+}
+
+// ============================================================================
+
+OoxPivotTableFragment::OoxPivotTableFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath ),
+ mrPivotTable( rHelper.getPivotTables().createPivotTable() )
+{
+}
+
+ContextHandlerRef OoxPivotTableFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( pivotTableDefinition ) ) { mrPivotTable.importPivotTableDefinition( rAttribs ); return this; }
+ break;
+
+ case XLS_TOKEN( pivotTableDefinition ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( location ): mrPivotTable.importLocation( rAttribs, getSheetIndex() ); break;
+ case XLS_TOKEN( pivotFields ): return this;
+ case XLS_TOKEN( rowFields ): return this;
+ case XLS_TOKEN( colFields ): return this;
+ case XLS_TOKEN( pageFields ): return this;
+ case XLS_TOKEN( dataFields ): return this;
+ case XLS_TOKEN( filters ): return this;
+ }
+ break;
+
+ case XLS_TOKEN( pivotFields ):
+ if( nElement == XLS_TOKEN( pivotField ) ) return new OoxPivotTableFieldContext( *this, mrPivotTable.createTableField() );
+ break;
+ case XLS_TOKEN( rowFields ):
+ if( nElement == XLS_TOKEN( field ) ) mrPivotTable.importRowField( rAttribs );
+ break;
+ case XLS_TOKEN( colFields ):
+ if( nElement == XLS_TOKEN( field ) ) mrPivotTable.importColField( rAttribs );
+ break;
+ case XLS_TOKEN( pageFields ):
+ if( nElement == XLS_TOKEN( pageField ) ) mrPivotTable.importPageField( rAttribs );
+ break;
+ case XLS_TOKEN( dataFields ):
+ if( nElement == XLS_TOKEN( dataField ) ) mrPivotTable.importDataField( rAttribs );
+ break;
+ case XLS_TOKEN( filters ):
+ if( nElement == XLS_TOKEN( filter ) ) return new OoxPivotTableFilterContext( *this, mrPivotTable.createTableFilter() );
+ break;
+ }
+ return 0;
+}
+
+ContextHandlerRef OoxPivotTableFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_PTDEFINITION ) { mrPivotTable.importPTDefinition( rStrm ); return this; }
+ break;
+
+ case OOBIN_ID_PTDEFINITION:
+ switch( nRecId )
+ {
+ case OOBIN_ID_PTLOCATION: mrPivotTable.importPTLocation( rStrm, getSheetIndex() ); break;
+ case OOBIN_ID_PTFIELDS: return this;
+ case OOBIN_ID_PTROWFIELDS: mrPivotTable.importPTRowFields( rStrm ); break;
+ case OOBIN_ID_PTCOLFIELDS: mrPivotTable.importPTColFields( rStrm ); break;
+ case OOBIN_ID_PTPAGEFIELDS: return this;
+ case OOBIN_ID_PTDATAFIELDS: return this;
+ case OOBIN_ID_PTFILTERS: return this;
+ }
+ break;
+
+ case OOBIN_ID_PTFIELDS:
+ if( nRecId == OOBIN_ID_PTFIELD ) return new OoxPivotTableFieldContext( *this, mrPivotTable.createTableField() );
+ break;
+ case OOBIN_ID_PTPAGEFIELDS:
+ if( nRecId == OOBIN_ID_PTPAGEFIELD ) mrPivotTable.importPTPageField( rStrm );
+ break;
+ case OOBIN_ID_PTDATAFIELDS:
+ if( nRecId == OOBIN_ID_PTDATAFIELD ) mrPivotTable.importPTDataField( rStrm );
+ break;
+ case OOBIN_ID_PTFILTERS:
+ if( nRecId == OOBIN_ID_PTFILTER ) return new OoxPivotTableFilterContext( *this, mrPivotTable.createTableFilter() );
+ break;
+ }
+ return 0;
+}
+
+const RecordInfo* OoxPivotTableFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_AUTOFILTER, OOBIN_ID_AUTOFILTER + 1 },
+ { OOBIN_ID_AUTOSORTSCOPE, OOBIN_ID_AUTOSORTSCOPE + 1 },
+ { OOBIN_ID_FILTERCOLUMN, OOBIN_ID_FILTERCOLUMN + 1 },
+ { OOBIN_ID_PIVOTAREA, OOBIN_ID_PIVOTAREA + 1 },
+ { OOBIN_ID_PTCOLFIELDS, OOBIN_ID_PTCOLFIELDS + 1 },
+ { OOBIN_ID_PTDATAFIELD, OOBIN_ID_PTDATAFIELD + 1 },
+ { OOBIN_ID_PTDATAFIELDS, OOBIN_ID_PTDATAFIELDS + 1 },
+ { OOBIN_ID_PTDEFINITION, OOBIN_ID_PTDEFINITION + 35 },
+ { OOBIN_ID_PTFIELD, OOBIN_ID_PTFIELD + 1 },
+ { OOBIN_ID_PTFIELDS, OOBIN_ID_PTFIELDS + 1 },
+ { OOBIN_ID_PTFILTER, OOBIN_ID_PTFILTER + 1 },
+ { OOBIN_ID_PTFILTERS, OOBIN_ID_PTFILTERS + 1 },
+ { OOBIN_ID_PTFITEM, OOBIN_ID_PTFITEM - 1 },
+ { OOBIN_ID_PTFITEMS, OOBIN_ID_PTFITEMS + 1 },
+ { OOBIN_ID_PTLOCATION, OOBIN_ID_PTLOCATION - 1 },
+ { OOBIN_ID_PTPAGEFIELD, OOBIN_ID_PTPAGEFIELD + 1 },
+ { OOBIN_ID_PTPAGEFIELDS, OOBIN_ID_PTPAGEFIELDS + 1 },
+ { OOBIN_ID_PTREFERENCE, OOBIN_ID_PTREFERENCE + 1 },
+ { OOBIN_ID_PTREFERENCEITEM, OOBIN_ID_PTREFERENCEITEM + 1 },
+ { OOBIN_ID_PTREFERENCES, OOBIN_ID_PTREFERENCES + 1 },
+ { OOBIN_ID_PTROWFIELDS, OOBIN_ID_PTROWFIELDS + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+// ============================================================================
+// ============================================================================
+
+BiffPivotTableContext::BiffPivotTableContext( const BiffWorksheetFragmentBase& rFragment, PivotTable& rPivotTable ) :
+ BiffWorksheetContextBase( rFragment ),
+ mrPivotTable( rPivotTable )
+{
+}
+
+void BiffPivotTableContext::importRecord()
+{
+ switch( mrStrm.getRecId() )
+ {
+ case BIFF_ID_PTDEFINITION: mrPivotTable.importPTDefinition( mrStrm, getSheetIndex() ); break;
+ case BIFF_ID_PTDEFINITION2: mrPivotTable.importPTDefinition2( mrStrm ); break;
+ case BIFF_ID_PTFIELD: mrPivotTable.createTableField().importPTField( mrStrm ); break;
+ case BIFF_ID_PTROWCOLFIELDS: mrPivotTable.importPTRowColFields( mrStrm ); break;
+ case BIFF_ID_PTPAGEFIELDS: mrPivotTable.importPTPageFields( mrStrm ); break;
+ case BIFF_ID_PTDATAFIELD: mrPivotTable.importPTDataField( mrStrm ); break;
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/querytablefragment.cxx b/oox/source/xls/querytablefragment.cxx
new file mode 100644
index 000000000000..73251419711e
--- /dev/null
+++ b/oox/source/xls/querytablefragment.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/querytablefragment.hxx"
+#include "oox/xls/webquerybuffer.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+
+namespace oox {
+namespace xls {
+
+OoxQueryTableFragment::OoxQueryTableFragment(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+ContextHandlerRef OoxQueryTableFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( queryTable ) ) getWebQueries().importQueryTable( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/richstring.cxx b/oox/source/xls/richstring.cxx
new file mode 100644
index 000000000000..0e2b067105c6
--- /dev/null
+++ b/oox/source/xls/richstring.cxx
@@ -0,0 +1,639 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/richstring.hxx"
+#include <rtl/ustrbuf.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 ::rtl::OUStringBuffer;
+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::createFont()
+{
+ 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_TEXT );
+ }
+ if( const Font* pFont = getStyles().getFontFromCellXf( nXfId ).get() )
+ {
+ if( pFont->needsRichTextFormat() )
+ {
+ PropertySet aPropSet( xRange );
+ pFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
+ }
+ }
+}
+
+void RichStringPortion::writeFontProperties( const Reference<XText>& rxText, sal_Int32 nXfId ) const
+{
+ PropertySet aPropSet(rxText);
+
+ if (mxFont.get())
+ mxFont->writeToPropertySet(aPropSet, FONT_PROPTYPE_TEXT);
+
+ if (const Font* pFont = getStyles().getFontFromCellXf(nXfId).get())
+ {
+ if (pFont->needsRichTextFormat())
+ pFont->writeToPropertySet(aPropSet, FONT_PROPTYPE_TEXT);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void FontPortionModel::read( RecordInputStream& rStrm )
+{
+ mnPos = rStrm.readuInt16();
+ mnFontId = rStrm.readuInt16();
+}
+
+void FontPortionModel::read( BiffInputStream& rStrm, BiffFontPortionMode eMode )
+{
+ switch( eMode )
+ {
+ case BIFF_FONTPORTION_8BIT:
+ mnPos = rStrm.readuInt8();
+ mnFontId = rStrm.readuInt8();
+ break;
+ case BIFF_FONTPORTION_16BIT:
+ mnPos = rStrm.readuInt16();
+ mnFontId = rStrm.readuInt16();
+ break;
+ case BIFF_FONTPORTION_OBJ:
+ mnPos = rStrm.readuInt16();
+ mnFontId = rStrm.readuInt16();
+ rStrm.skip( 4 );
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void FontPortionModelList::appendPortion( const FontPortionModel& rPortion )
+{
+ // #i33341# real life -- same character index may occur several times
+ OSL_ENSURE( empty() || (back().mnPos <= rPortion.mnPos), "FontPortionModelList::appendPortion - wrong char order" );
+ if( empty() || (back().mnPos < rPortion.mnPos) )
+ push_back( rPortion );
+ else
+ back().mnFontId = rPortion.mnFontId;
+}
+
+void FontPortionModelList::importPortions( RecordInputStream& rStrm )
+{
+ sal_Int32 nCount = rStrm.readInt32();
+ clear();
+ if( nCount > 0 )
+ {
+ reserve( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 4 ) );
+ /* #i33341# real life -- same character index may occur several times
+ -> use appendPortion() to validate string position. */
+ FontPortionModel aPortion;
+ for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
+ {
+ aPortion.read( rStrm );
+ appendPortion( aPortion );
+ }
+ }
+}
+
+void FontPortionModelList::importPortions( BiffInputStream& rStrm, sal_uInt16 nCount, BiffFontPortionMode eMode )
+{
+ clear();
+ reserve( nCount );
+ /* #i33341# real life -- same character index may occur several times
+ -> use appendPortion() to validate string position. */
+ FontPortionModel aPortion;
+ for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
+ {
+ aPortion.read( rStrm, eMode );
+ appendPortion( aPortion );
+ }
+}
+
+void FontPortionModelList::importPortions( BiffInputStream& rStrm, bool b16Bit )
+{
+ sal_uInt16 nCount = b16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
+ importPortions( rStrm, nCount, b16Bit ? BIFF_FONTPORTION_16BIT : BIFF_FONTPORTION_8BIT );
+}
+
+// ============================================================================
+
+PhoneticDataModel::PhoneticDataModel() :
+ mnFontId( -1 ),
+ mnType( XML_fullwidthKatakana ),
+ mnAlignment( XML_left )
+{
+}
+
+void PhoneticDataModel::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 )
+{
+ maModel.mnFontId = rAttribs.getInteger( XML_fontId, -1 );
+ maModel.mnType = rAttribs.getToken( XML_type, XML_fullwidthKatakana );
+ maModel.mnAlignment = rAttribs.getToken( XML_alignment, XML_left );
+}
+
+void PhoneticSettings::importPhoneticPr( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFontId;
+ sal_Int32 nType, nAlignment;
+ rStrm >> nFontId >> nType >> nAlignment;
+ maModel.mnFontId = nFontId;
+ maModel.setBinData( nType, nAlignment );
+}
+
+void PhoneticSettings::importPhoneticPr( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFontId, nFlags;
+ rStrm >> nFontId >> nFlags;
+ maModel.mnFontId = nFontId;
+ maModel.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;
+ maModel.mnFontId = nFontId;
+ maModel.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;
+ maModel.mnFontId = nFontId;
+ maModel.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 PhoneticPortionModel::read( RecordInputStream& rStrm )
+{
+ mnPos = rStrm.readuInt16();
+ mnBasePos = rStrm.readuInt16();
+ mnBaseLen = rStrm.readuInt16();
+}
+
+void PhoneticPortionModel::read( BiffInputStream& rStrm )
+{
+ mnPos = rStrm.readuInt16();
+ mnBasePos = rStrm.readuInt16();
+ mnBaseLen = rStrm.readuInt16();
+}
+
+// ----------------------------------------------------------------------------
+
+void PhoneticPortionModelList::appendPortion( const PhoneticPortionModel& rPortion )
+{
+ // same character index may occur several times
+ OSL_ENSURE( empty() || ((back().mnPos <= rPortion.mnPos) &&
+ (back().mnBasePos + back().mnBaseLen <= rPortion.mnBasePos)),
+ "PhoneticPortionModelList::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 PhoneticPortionModelList::importPortions( RecordInputStream& rStrm )
+{
+ sal_Int32 nCount = rStrm.readInt32();
+ clear();
+ if( nCount > 0 )
+ {
+ reserve( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 6 ) );
+ PhoneticPortionModel aPortion;
+ for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
+ {
+ aPortion.read( rStrm );
+ appendPortion( aPortion );
+ }
+ }
+}
+
+OUString PhoneticPortionModelList::importPortions( BiffInputStream& rStrm, sal_Int32 nPhoneticSize )
+{
+ OUString aPhoneticText;
+ sal_uInt16 nPortionCount, nTextLen1, nTextLen2;
+ rStrm >> nPortionCount >> nTextLen1 >> nTextLen2;
+ OSL_ENSURE( nTextLen1 == nTextLen2, "PhoneticPortionModelList::importPortions - wrong phonetic text length" );
+ if( (nTextLen1 == nTextLen2) && (nTextLen1 > 0) )
+ {
+ sal_Int32 nMinSize = 2 * nTextLen1 + 6 * nPortionCount + 14;
+ OSL_ENSURE( nMinSize <= nPhoneticSize, "PhoneticPortionModelList::importPortions - wrong size of phonetic data" );
+ if( nMinSize <= nPhoneticSize )
+ {
+ aPhoneticText = rStrm.readUnicodeArray( nTextLen1 );
+ clear();
+ reserve( nPortionCount );
+ PhoneticPortionModel 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.isEof() && getFlag( nFlags, OOBIN_STRINGFLAG_FONTS ) )
+ {
+ FontPortionModelList aPortions;
+ aPortions.importPortions( rStrm );
+ createFontPortions( aBaseText, aPortions );
+ }
+ else
+ {
+ createPortion()->setText( aBaseText );
+ }
+
+ if( !rStrm.isEof() && getFlag( nFlags, OOBIN_STRINGFLAG_PHONETICS ) )
+ {
+ OUString aPhoneticText = rStrm.readString();
+ PhoneticPortionModelList 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.isEof() && getFlag( nFlags, BIFF_STR_EXTRAFONTS ) )
+ {
+ FontPortionModelList 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 = getFlag( nFlagField, BIFF_STRF_16BIT );
+ bool bFonts = getFlag( nFlagField, BIFF_STRF_RICH );
+ bool bPhonetic = getFlag( nFlagField, BIFF_STRF_PHONETIC );
+ sal_uInt16 nFontCount = bFonts ? rStrm.readuInt16() : 0;
+ sal_Int32 nPhoneticSize = bPhonetic ? rStrm.readInt32() : 0;
+
+ // --- character array ---
+ OUString aBaseText = rStrm.readUniStringChars( nChars, b16Bit );
+
+ // --- formatting ---
+ // #122185# bRich flag may be set, but format runs may be missing
+ if( !rStrm.isEof() && (nFontCount > 0) )
+ {
+ FontPortionModelList aPortions;
+ aPortions.importPortions( rStrm, nFontCount, BIFF_FONTPORTION_16BIT );
+ createFontPortions( aBaseText, aPortions );
+ }
+ else
+ {
+ createPortion()->setText( aBaseText );
+ }
+
+ // --- Asian phonetic information ---
+ // #122185# bPhonetic flag may be set, but phonetic info may be missing
+ if( !rStrm.isEof() && (nPhoneticSize > 0) )
+ {
+ sal_Int64 nPhoneticEnd = rStrm.tell() + 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_Int32 nMinSize = nSize + 4;
+ OSL_ENSURE( nMinSize <= nPhoneticSize, "RichString::importUniString - wrong size of phonetic data" );
+ if( (nId == 1) && (nMinSize <= nPhoneticSize) )
+ {
+ maPhonSettings.importStringData( rStrm );
+ PhoneticPortionModelList aPortions;
+ OUString aPhoneticText = aPortions.importPortions( rStrm, nPhoneticSize );
+ createPhoneticPortions( aPhoneticText, aPortions, aBaseText.getLength() );
+ }
+ }
+ rStrm.seek( nPhoneticEnd );
+ }
+}
+
+void RichString::finalizeImport()
+{
+ maFontPortions.forEachMem( &RichStringPortion::finalizeImport );
+}
+
+OUString RichString::getPlainText() const
+{
+ OUStringBuffer aBuffer;
+ for( PortionVec::const_iterator aIt = maFontPortions.begin(), aEnd = maFontPortions.end(); aIt != aEnd; ++aIt )
+ aBuffer.append( (*aIt)->getText() );
+ return aBuffer.makeStringAndClear();
+}
+
+void RichString::convert( const Reference< XText >& rxText, sal_Int32 nXfId ) const
+{
+ if (maFontPortions.size() == 1)
+ {
+ // Set text directly to the cell when the string has only one portion.
+ // It's much faster this way.
+ RichStringPortion& rPtn = *maFontPortions.front();
+ rxText->setString(rPtn.getText());
+ rPtn.writeFontProperties(rxText, nXfId);
+ return;
+ }
+
+ for( PortionVec::const_iterator aIt = maFontPortions.begin(), aEnd = maFontPortions.end(); aIt != aEnd; ++aIt )
+ {
+ (*aIt)->convert( rxText, nXfId );
+ nXfId = -1; // use passed XF identifier for first portion only
+ }
+}
+
+// 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, FontPortionModelList& 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(), FontPortionModel( 0, -1 ) );
+ if( rPortions.back().mnPos < nStrLen )
+ rPortions.push_back( FontPortionModel( nStrLen, -1 ) );
+
+ // create all string portions according to the font id vector
+ for( FontPortionModelList::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, FontPortionModelList& 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(), FontPortionModel( 0, -1 ) );
+ if( rPortions.back().mnPos < nStrLen )
+ rPortions.push_back( FontPortionModel( nStrLen, -1 ) );
+
+ // create all string portions according to the font id vector
+ for( FontPortionModelList::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, PhoneticPortionModelList& 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( PhoneticPortionModel( 0, 0, nBaseLen ) );
+ // add trailing string position to ease the following loop
+ if( rPortions.back().mnPos < nStrLen )
+ rPortions.push_back( PhoneticPortionModel( nStrLen, nBaseLen, 0 ) );
+
+ // create all phonetic portions according to the portions vector
+ for( PhoneticPortionModelList::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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/richstringcontext.cxx b/oox/source/xls/richstringcontext.cxx
new file mode 100644
index 000000000000..015d01b72684
--- /dev/null
+++ b/oox/source/xls/richstringcontext.cxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/richstringcontext.hxx"
+#include "oox/xls/stylesfragment.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxRichStringContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( isRootElement() )
+ {
+ switch( nElement )
+ {
+ case XLS_TOKEN( t ): mxPortion = mxString->importText( rAttribs ); return this; // collect text in onEndElement()
+ case XLS_TOKEN( r ): mxPortion = mxString->importRun( rAttribs ); return this;
+ case XLS_TOKEN( rPh ): mxPhonetic = mxString->importPhoneticRun( rAttribs ); return this;
+ case XLS_TOKEN( phoneticPr ): mxString->importPhoneticPr( rAttribs ); break;
+ }
+ }
+ else switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( r ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( rPr ):
+ if( mxPortion.get() )
+ return new OoxFontContext( *this, mxPortion->createFont() );
+ break;
+
+ case XLS_TOKEN( t ):
+ return this; // collect portion text in onEndElement()
+ }
+ break;
+
+ case XLS_TOKEN( rPh ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( t ):
+ return this; // collect phonetic text in onEndElement()
+ }
+ break;
+ }
+ return 0;
+}
+
+void OoxRichStringContext::onEndElement( const OUString& rChars )
+{
+ if( getCurrentElement() == XLS_TOKEN( t ) )
+ {
+ switch( getPreviousElement() )
+ {
+ case XLS_TOKEN( rPh ): if( mxPhonetic.get() ) mxPhonetic->setText( rChars ); break;
+ default: if( mxPortion.get() ) mxPortion->setText( rChars ); break;
+ }
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/scenariobuffer.cxx b/oox/source/xls/scenariobuffer.cxx
new file mode 100644
index 000000000000..0cdd54f5c9cf
--- /dev/null
+++ b/oox/source/xls/scenariobuffer.cxx
@@ -0,0 +1,308 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/scenariobuffer.hxx"
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sheet/XScenario.hpp>
+#include <com/sun/star/sheet/XScenarios.hpp>
+#include <com/sun/star/sheet/XScenariosSupplier.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include "properties.hxx"
+#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"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::table::XCell;
+using ::com::sun::star::sheet::XScenario;
+using ::com::sun::star::sheet::XScenarios;
+using ::com::sun::star::sheet::XScenariosSupplier;
+using ::com::sun::star::sheet::XSpreadsheet;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 BIFF_SCENARIO_DELETED = 0x4000;
+
+} // namespace
+
+// ============================================================================
+
+ScenarioCellModel::ScenarioCellModel() :
+ mnNumFmtId( 0 ),
+ mbDeleted( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ScenarioModel::ScenarioModel() :
+ mbLocked( false ),
+ mbHidden( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+Scenario::Scenario( const WorkbookHelper& rHelper, sal_Int16 nSheet ) :
+ WorkbookHelper( rHelper ),
+ mnSheet( nSheet )
+{
+}
+
+void Scenario::importScenario( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ maModel.maComment = rAttribs.getXString( XML_comment, OUString() );
+ maModel.maUser = rAttribs.getXString( XML_user, OUString() );
+ maModel.mbLocked = rAttribs.getBool( XML_locked, false );
+ maModel.mbHidden = rAttribs.getBool( XML_hidden, false );
+}
+
+void Scenario::importInputCells( const AttributeList& rAttribs )
+{
+ ScenarioCellModel aModel;
+ getAddressConverter().convertToCellAddressUnchecked( aModel.maPos, rAttribs.getString( XML_r, OUString() ), mnSheet );
+ aModel.maValue = rAttribs.getXString( XML_val, OUString() );
+ aModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
+ aModel.mbDeleted = rAttribs.getBool( XML_deleted, false );
+ maCells.push_back( aModel );
+}
+
+void Scenario::importScenario( RecordInputStream& rStrm )
+{
+ rStrm.skip( 2 ); // cell count
+ // two longs instead of flag field
+ maModel.mbLocked = rStrm.readInt32() != 0;
+ maModel.mbHidden = rStrm.readInt32() != 0;
+ rStrm >> maModel.maName >> maModel.maComment >> maModel.maUser;
+}
+
+void Scenario::importInputCells( RecordInputStream& rStrm )
+{
+ // TODO: where is the deleted flag?
+ ScenarioCellModel aModel;
+ BinAddress aPos;
+ rStrm >> aPos;
+ rStrm.skip( 8 );
+ aModel.mnNumFmtId = rStrm.readuInt16();
+ rStrm >> aModel.maValue;
+ getAddressConverter().convertToCellAddressUnchecked( aModel.maPos, aPos, mnSheet );
+ maCells.push_back( aModel );
+}
+
+void Scenario::importScenario( BiffInputStream& rStrm )
+{
+ sal_uInt16 nCellCount;
+ sal_uInt8 nNameLen, nCommentLen, nUserLen;
+ rStrm >> nCellCount;
+ // two bytes instead of flag field
+ maModel.mbLocked = rStrm.readuInt8() != 0;
+ maModel.mbHidden = rStrm.readuInt8() != 0;
+ rStrm >> nNameLen >> nCommentLen >> nUserLen;
+ maModel.maName = rStrm.readUniStringBody( nNameLen );
+ // user name: before comment (in difference to leading length field), repeated length
+ if( nUserLen > 0 )
+ maModel.maUser = rStrm.readUniString();
+ // comment: repeated length
+ if( nCommentLen > 0 )
+ maModel.maComment = rStrm.readUniString();
+
+ // list of cell addresses
+ for( sal_uInt16 nCell = 0; !rStrm.isEof() && (nCell < nCellCount); ++nCell )
+ {
+ ScenarioCellModel aModel;
+ BinAddress aPos;
+ rStrm >> aPos;
+ // deleted flag is encoded in column index
+ aModel.mbDeleted = getFlag( aPos.mnCol, BIFF_SCENARIO_DELETED );
+ setFlag( aPos.mnCol, BIFF_SCENARIO_DELETED, false );
+ getAddressConverter().convertToCellAddressUnchecked( aModel.maPos, aPos, mnSheet );
+ maCells.push_back( aModel );
+ }
+
+ // list of cell values
+ for( ScenarioCellVector::iterator aIt = maCells.begin(), aEnd = maCells.end(); !rStrm.isEof() && (aIt != aEnd); ++aIt )
+ aIt->maValue = rStrm.readUniString();
+}
+
+void Scenario::finalizeImport()
+{
+ AddressConverter& rAddrConv = getAddressConverter();
+ ::std::vector< CellRangeAddress > aRanges;
+ for( ScenarioCellVector::iterator aIt = maCells.begin(), aEnd = maCells.end(); aIt != aEnd; ++aIt )
+ if( !aIt->mbDeleted && rAddrConv.checkCellAddress( aIt->maPos, true ) )
+ aRanges.push_back( CellRangeAddress( aIt->maPos.Sheet, aIt->maPos.Column, aIt->maPos.Row, aIt->maPos.Column, aIt->maPos.Row ) );
+
+ if( !aRanges.empty() && (maModel.maName.getLength() > 0) ) try
+ {
+ /* Find an unused name for the scenario (Calc stores scenario data in
+ hidden sheets named after the scenario following the base sheet). */
+ Reference< XNameAccess > xSheetsNA( getDocument()->getSheets(), UNO_QUERY_THROW );
+ OUString aScenName = ContainerHelper::getUnusedName( xSheetsNA, maModel.maName, '_' );
+
+ // create the new scenario sheet
+ Reference< XScenariosSupplier > xScenariosSupp( getSheetFromDoc( mnSheet ), UNO_QUERY_THROW );
+ Reference< XScenarios > xScenarios( xScenariosSupp->getScenarios(), UNO_SET_THROW );
+ xScenarios->addNewByName( aScenName, ContainerHelper::vectorToSequence( aRanges ), maModel.maComment );
+
+ // write scenario cell values
+ Reference< XSpreadsheet > xSheet( getSheetFromDoc( aScenName ), UNO_SET_THROW );
+ for( ScenarioCellVector::iterator aIt = maCells.begin(), aEnd = maCells.end(); aIt != aEnd; ++aIt )
+ {
+ if( !aIt->mbDeleted ) try
+ {
+ // use XCell::setFormula to auto-detect values and strings
+ Reference< XCell > xCell( xSheet->getCellByPosition( aIt->maPos.Column, aIt->maPos.Row ), UNO_SET_THROW );
+ xCell->setFormula( aIt->maValue );
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ // scenario properties
+ PropertySet aPropSet( xScenarios->getByName( aScenName ) );
+ aPropSet.setProperty( PROP_IsActive, false );
+ aPropSet.setProperty( PROP_CopyBack, false );
+ aPropSet.setProperty( PROP_CopyStyles, false );
+ aPropSet.setProperty( PROP_CopyFormulas, false );
+ aPropSet.setProperty( PROP_Protected, maModel.mbLocked );
+ // #112621# do not show/print scenario border
+ aPropSet.setProperty( PROP_ShowBorder, false );
+ aPropSet.setProperty( PROP_PrintBorder, false );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+
+SheetScenariosModel::SheetScenariosModel() :
+ mnCurrent( 0 ),
+ mnShown( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+SheetScenarios::SheetScenarios( const WorkbookHelper& rHelper, sal_Int16 nSheet ) :
+ WorkbookHelper( rHelper ),
+ mnSheet( nSheet )
+{
+}
+
+void SheetScenarios::importScenarios( const AttributeList& rAttribs )
+{
+ maModel.mnCurrent = rAttribs.getInteger( XML_current, 0 );
+ maModel.mnShown = rAttribs.getInteger( XML_show, 0 );
+}
+
+void SheetScenarios::importScenarios( RecordInputStream& rStrm )
+{
+ maModel.mnCurrent = rStrm.readuInt16();
+ maModel.mnShown = rStrm.readuInt16();
+}
+
+void SheetScenarios::importScenarios( BiffInputStream& rStrm )
+{
+ rStrm.skip( 2 ); // scenario count
+ maModel.mnCurrent = rStrm.readuInt16();
+ maModel.mnShown = rStrm.readuInt16();
+
+ // read following SCENARIO records
+ while( (rStrm.getNextRecId() == BIFF_ID_SCENARIO) && rStrm.startNextRecord() )
+ createScenario().importScenario( rStrm );
+}
+
+Scenario& SheetScenarios::createScenario()
+{
+ ScenarioVector::value_type xScenario( new Scenario( *this, mnSheet ) );
+ maScenarios.push_back( xScenario );
+ return *xScenario;
+}
+
+void SheetScenarios::finalizeImport()
+{
+ maScenarios.forEachMem( &Scenario::finalizeImport );
+
+ // activate a scenario
+ try
+ {
+ Reference< XScenariosSupplier > xScenariosSupp( getSheetFromDoc( mnSheet ), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xScenariosIA( xScenariosSupp->getScenarios(), UNO_QUERY_THROW );
+ Reference< XScenario > xScenario( xScenariosIA->getByIndex( maModel.mnShown ), UNO_QUERY_THROW );
+ xScenario->apply();
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+
+ScenarioBuffer::ScenarioBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+SheetScenarios& ScenarioBuffer::createSheetScenarios( sal_Int16 nSheet )
+{
+ SheetScenariosMap::mapped_type& rxSheetScens = maSheetScenarios[ nSheet ];
+ if( !rxSheetScens )
+ rxSheetScens.reset( new SheetScenarios( *this, nSheet ) );
+ return *rxSheetScens;
+}
+
+void ScenarioBuffer::finalizeImport()
+{
+ maSheetScenarios.forEachMem( &SheetScenarios::finalizeImport );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/scenariocontext.cxx b/oox/source/xls/scenariocontext.cxx
new file mode 100644
index 000000000000..c244065aa876
--- /dev/null
+++ b/oox/source/xls/scenariocontext.cxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/scenariocontext.hxx"
+#include "oox/xls/scenariobuffer.hxx"
+
+using ::oox::core::ContextHandlerRef;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxScenarioContext::OoxScenarioContext( OoxWorksheetContextBase& rParent, SheetScenarios& rSheetScenarios ) :
+ OoxWorksheetContextBase( rParent ),
+ mrScenario( rSheetScenarios.createScenario() )
+{
+}
+
+ContextHandlerRef OoxScenarioContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( scenario ):
+ if( nElement == XLS_TOKEN( inputCells ) ) mrScenario.importInputCells( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+void OoxScenarioContext::onStartElement( const AttributeList& rAttribs )
+{
+ if( isRootElement() )
+ mrScenario.importScenario( rAttribs );
+}
+
+ContextHandlerRef OoxScenarioContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_SCENARIO:
+ if( nRecId == OOBIN_ID_INPUTCELLS ) mrScenario.importInputCells( rStrm );
+ break;
+ }
+ return 0;
+}
+
+void OoxScenarioContext::onStartRecord( RecordInputStream& rStrm )
+{
+ if( isRootElement() )
+ mrScenario.importScenario( rStrm );
+}
+
+// ============================================================================
+
+OoxScenariosContext::OoxScenariosContext( OoxWorksheetFragmentBase& rFragment ) :
+ OoxWorksheetContextBase( rFragment ),
+ mrSheetScenarios( getScenarios().createSheetScenarios( getSheetIndex() ) )
+{
+}
+
+ContextHandlerRef OoxScenariosContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( scenarios ):
+ if( nElement == XLS_TOKEN( scenario ) ) return new OoxScenarioContext( *this, mrSheetScenarios );
+ break;
+ }
+ return 0;
+}
+
+void OoxScenariosContext::onStartElement( const AttributeList& rAttribs )
+{
+ if( isRootElement() )
+ mrSheetScenarios.importScenarios( rAttribs );
+}
+
+ContextHandlerRef OoxScenariosContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_SCENARIOS:
+ if( nRecId == OOBIN_ID_SCENARIO ) return new OoxScenarioContext( *this, mrSheetScenarios );
+ break;
+ }
+ return 0;
+}
+
+void OoxScenariosContext::onStartRecord( RecordInputStream& rStrm )
+{
+ if( isRootElement() )
+ mrSheetScenarios.importScenarios( rStrm );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/sharedformulabuffer.cxx b/oox/source/xls/sharedformulabuffer.cxx
new file mode 100644
index 000000000000..46f0712b22ec
--- /dev/null
+++ b/oox/source/xls/sharedformulabuffer.cxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/sharedformulabuffer.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include "properties.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"
+
+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, 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, 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, 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 = createNamedRangeObject( aName );
+ PropertySet aNameProps( xNamedRange );
+ aNameProps.setProperty( PROP_IsSharedFormula, true );
+ sal_Int32 nTokenIndex = -1;
+ if( aNameProps.getProperty( nTokenIndex, PROP_TokenIndex ) && (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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/sharedstringsbuffer.cxx b/oox/source/xls/sharedstringsbuffer.cxx
new file mode 100644
index 000000000000..c11b7c225be9
--- /dev/null
+++ b/oox/source/xls/sharedstringsbuffer.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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 )
+{
+ rStrm.skip( 4 );
+ sal_Int32 nStringCount = rStrm.readInt32();
+ if( nStringCount > 0 )
+ {
+ maStrings.clear();
+ maStrings.reserve( static_cast< size_t >( nStringCount ) );
+ for( ; !rStrm.isEof() && (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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/sharedstringsfragment.cxx b/oox/source/xls/sharedstringsfragment.cxx
new file mode 100644
index 000000000000..0dc8ab221ab3
--- /dev/null
+++ b/oox/source/xls/sharedstringsfragment.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/sharedstringsfragment.hxx"
+#include "oox/xls/sharedstringsbuffer.hxx"
+#include "oox/xls/richstringcontext.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxSharedStringsFragment::OoxSharedStringsFragment(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxSharedStringsFragment::onCreateContext( sal_Int32 nElement, const AttributeList& )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( sst ) )
+ return this;
+ break;
+
+ case XLS_TOKEN( sst ):
+ if( nElement == XLS_TOKEN( si ) )
+ return new OoxRichStringContext( *this, getSharedStrings().createRichString() );
+ break;
+ }
+ return 0;
+}
+
+ContextHandlerRef OoxSharedStringsFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_SST )
+ return this;
+ break;
+
+ case OOBIN_ID_SST:
+ if( nRecId == OOBIN_ID_SI )
+ getSharedStrings().createRichString()->importString( rStrm, true );
+ break;
+ }
+ return 0;
+}
+
+// oox.core.FragmentHandler2 interface ----------------------------------------
+
+const RecordInfo* OoxSharedStringsFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_SST, OOBIN_ID_SST + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+void OoxSharedStringsFragment::finalizeImport()
+{
+ getSharedStrings().finalizeImport();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/sheetdatacontext.cxx b/oox/source/xls/sheetdatacontext.cxx
new file mode 100644
index 000000000000..a7aa5d303122
--- /dev/null
+++ b/oox/source/xls/sheetdatacontext.cxx
@@ -0,0 +1,994 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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/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 ::oox::core::ContextHandlerRef;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+// record constants -----------------------------------------------------------
+
+const sal_uInt32 OOBIN_CELL_SHOWPHONETIC = 0x01000000;
+
+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 OOBIN_ROW_SHOWPHONETIC = 0x01;
+
+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 BIFF2_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( OoxWorksheetFragmentBase& rFragment ) :
+ OoxWorksheetContextBase( rFragment )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxSheetDataContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( sheetData ):
+ if( nElement == XLS_TOKEN( row ) ) { importRow( rAttribs ); return this; }
+ break;
+
+ case XLS_TOKEN( row ):
+ if( nElement == XLS_TOKEN( c ) ) { importCell( rAttribs ); return this; }
+ break;
+
+ case XLS_TOKEN( c ):
+ if( maCurrCell.mxCell.is() ) switch( nElement )
+ {
+ case XLS_TOKEN( is ):
+ mxInlineStr.reset( new RichString( *this ) );
+ return new OoxRichStringContext( *this, mxInlineStr );
+ case XLS_TOKEN( v ):
+ return this;
+ case XLS_TOKEN( f ):
+ importFormula( rAttribs );
+ return this;
+ }
+ break;
+ }
+ return 0;
+}
+
+void OoxSheetDataContext::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentElement() )
+ {
+ 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, 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
+ setCell( 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;
+ }
+}
+
+ContextHandlerRef OoxSheetDataContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_SHEETDATA:
+ switch( nRecId )
+ {
+ case OOBIN_ID_ROW: importRow( rStrm ); return this;
+ }
+ break;
+
+ case OOBIN_ID_ROW:
+ switch( nRecId )
+ {
+ case OOBIN_ID_ARRAY: importArray( rStrm ); break;
+ case OOBIN_ID_CELL_BOOL: importCellBool( rStrm, CELLTYPE_VALUE ); break;
+ case OOBIN_ID_CELL_BLANK: importCellBlank( rStrm, CELLTYPE_VALUE ); break;
+ case OOBIN_ID_CELL_DOUBLE: importCellDouble( rStrm, CELLTYPE_VALUE ); break;
+ case OOBIN_ID_CELL_ERROR: importCellError( rStrm, CELLTYPE_VALUE ); break;
+ case OOBIN_ID_CELL_RK: importCellRk( rStrm, CELLTYPE_VALUE ); break;
+ case OOBIN_ID_CELL_RSTRING: importCellRString( rStrm, CELLTYPE_VALUE ); break;
+ case OOBIN_ID_CELL_SI: importCellSi( rStrm, CELLTYPE_VALUE ); break;
+ case OOBIN_ID_CELL_STRING: importCellString( rStrm, CELLTYPE_VALUE ); break;
+ case OOBIN_ID_DATATABLE: importDataTable( rStrm ); break;
+ case OOBIN_ID_FORMULA_BOOL: importCellBool( rStrm, CELLTYPE_FORMULA ); break;
+ case OOBIN_ID_FORMULA_DOUBLE: importCellDouble( rStrm, CELLTYPE_FORMULA ); break;
+ case OOBIN_ID_FORMULA_ERROR: importCellError( rStrm, CELLTYPE_FORMULA ); break;
+ case OOBIN_ID_FORMULA_STRING: importCellString( rStrm, CELLTYPE_FORMULA ); break;
+ case OOBIN_ID_MULTCELL_BOOL: importCellBool( rStrm, CELLTYPE_MULTI ); break;
+ case OOBIN_ID_MULTCELL_BLANK: importCellBlank( rStrm, CELLTYPE_MULTI ); break;
+ case OOBIN_ID_MULTCELL_DOUBLE: importCellDouble( rStrm, CELLTYPE_MULTI ); break;
+ case OOBIN_ID_MULTCELL_ERROR: importCellError( rStrm, CELLTYPE_MULTI ); break;
+ case OOBIN_ID_MULTCELL_RK: importCellRk( rStrm, CELLTYPE_MULTI ); break;
+ case OOBIN_ID_MULTCELL_RSTRING: importCellRString( rStrm, CELLTYPE_MULTI ); break;
+ case OOBIN_ID_MULTCELL_SI: importCellSi( rStrm, CELLTYPE_MULTI ); break;
+ case OOBIN_ID_MULTCELL_STRING: importCellString( rStrm, CELLTYPE_MULTI ); break;
+ case OOBIN_ID_SHAREDFMLA: importSharedFmla( rStrm ); break;
+ }
+ break;
+ }
+ return 0;
+}
+
+// private --------------------------------------------------------------------
+
+void OoxSheetDataContext::importRow( const AttributeList& rAttribs )
+{
+ RowModel aModel;
+ aModel.mnFirstRow = aModel.mnLastRow = rAttribs.getInteger( XML_r, -1 );
+ aModel.mfHeight = rAttribs.getDouble( XML_ht, -1.0 );
+ aModel.mnXfId = rAttribs.getInteger( XML_s, -1 );
+ aModel.mnLevel = rAttribs.getInteger( XML_outlineLevel, 0 );
+ aModel.mbCustomHeight = rAttribs.getBool( XML_customHeight, false );
+ aModel.mbCustomFormat = rAttribs.getBool( XML_customFormat, false );
+ aModel.mbShowPhonetic = rAttribs.getBool( XML_ph, false );
+ aModel.mbHidden = rAttribs.getBool( XML_hidden, false );
+ aModel.mbCollapsed = rAttribs.getBool( XML_collapsed, false );
+ aModel.mbThickTop = rAttribs.getBool( XML_thickTop, false );
+ aModel.mbThickBottom = rAttribs.getBool( XML_thickBot, false );
+ // set row properties in the current sheet
+ setRowModel( aModel );
+}
+
+void OoxSheetDataContext::importCell( const AttributeList& rAttribs )
+{
+ maCurrCell.reset();
+ maCurrCell.mxCell = getCell( rAttribs.getString( XML_r, OUString() ), &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();
+
+ // update used area of the sheet
+ if( maCurrCell.mxCell.is() )
+ extendUsedArea( maCurrCell.maAddress );
+}
+
+void OoxSheetDataContext::importFormula( const AttributeList& rAttribs )
+{
+ maCurrCell.maFormulaRef = rAttribs.getString( XML_ref, OUString() );
+ maCurrCell.mnFormulaType = rAttribs.getToken( XML_t, XML_normal );
+ maCurrCell.mnSharedId = rAttribs.getInteger( XML_si, -1 );
+ maTableData.maRef1 = rAttribs.getString( XML_r1, OUString() );
+ maTableData.maRef2 = rAttribs.getString( XML_r2, OUString() );
+ 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, CellType eCellType )
+{
+ maCurrCell.reset();
+
+ switch( eCellType )
+ {
+ case CELLTYPE_VALUE:
+ case CELLTYPE_FORMULA: rStrm >> maCurrPos.mnCol; break;
+ case CELLTYPE_MULTI: ++maCurrPos.mnCol; break;
+ }
+
+ sal_uInt32 nXfId;
+ rStrm >> nXfId;
+
+ maCurrCell.mxCell = getCell( maCurrPos, &maCurrCell.maAddress );
+ maCurrCell.mnXfId = extractValue< sal_Int32 >( nXfId, 0, 24 );
+ maCurrCell.mbShowPhonetic = getFlag( nXfId, OOBIN_CELL_SHOWPHONETIC );
+
+ // update used area of the sheet
+ if( maCurrCell.mxCell.is() )
+ extendUsedArea( maCurrCell.maAddress );
+}
+
+void OoxSheetDataContext::importCellBool( RecordInputStream& rStrm, CellType eCellType )
+{
+ importCellHeader( rStrm, eCellType );
+ maCurrCell.mnCellType = XML_b;
+ if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ {
+ bool bValue = rStrm.readuInt8() != 0;
+ if( eCellType == CELLTYPE_FORMULA )
+ {
+ 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, CellType eCellType )
+{
+ OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "OoxSheetDataContext::importCellBlank - no formula cells supported" );
+ importCellHeader( rStrm, eCellType );
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellDouble( RecordInputStream& rStrm, CellType eCellType )
+{
+ importCellHeader( rStrm, eCellType );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ {
+ double fValue = rStrm.readDouble();
+ if( eCellType == CELLTYPE_FORMULA )
+ importCellFormula( rStrm );
+ else
+ maCurrCell.mxCell->setValue( fValue );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellError( RecordInputStream& rStrm, CellType eCellType )
+{
+ importCellHeader( rStrm, eCellType );
+ maCurrCell.mnCellType = XML_e;
+ if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) )
+ {
+ sal_uInt8 nErrorCode = rStrm.readuInt8();
+ if( eCellType == CELLTYPE_FORMULA )
+ importCellFormula( rStrm );
+ else
+ setErrorCell( maCurrCell.mxCell, nErrorCode );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void OoxSheetDataContext::importCellRk( RecordInputStream& rStrm, CellType eCellType )
+{
+ OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "OoxSheetDataContext::importCellRk - no formula cells supported" );
+ importCellHeader( rStrm, eCellType );
+ 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, CellType eCellType )
+{
+ OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "OoxSheetDataContext::importCellRString - no formula cells supported" );
+ importCellHeader( rStrm, eCellType );
+ 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, CellType eCellType )
+{
+ OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "OoxSheetDataContext::importCellSi - no formula cells supported" );
+ importCellHeader( rStrm, eCellType );
+ 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, CellType eCellType )
+{
+ importCellHeader( rStrm, eCellType );
+ 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( eCellType == CELLTYPE_FORMULA )
+ 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 )
+{
+ RowModel aModel;
+
+ sal_uInt16 nHeight, nFlags1;
+ sal_uInt8 nFlags2;
+ rStrm >> maCurrPos.mnRow >> aModel.mnXfId >> nHeight >> nFlags1 >> nFlags2;
+
+ // row index is 0-based in OOBIN, but RowModel expects 1-based
+ aModel.mnFirstRow = aModel.mnLastRow = maCurrPos.mnRow + 1;
+ // row height is in twips in OOBIN, convert to points
+ aModel.mfHeight = nHeight / 20.0;
+ aModel.mnLevel = extractValue< sal_Int32 >( nFlags1, 8, 3 );
+ aModel.mbCustomHeight = getFlag( nFlags1, OOBIN_ROW_CUSTOMHEIGHT );
+ aModel.mbCustomFormat = getFlag( nFlags1, OOBIN_ROW_CUSTOMFORMAT );
+ aModel.mbShowPhonetic = getFlag( nFlags2, OOBIN_ROW_SHOWPHONETIC );
+ aModel.mbHidden = getFlag( nFlags1, OOBIN_ROW_HIDDEN );
+ aModel.mbCollapsed = getFlag( nFlags1, OOBIN_ROW_COLLAPSED );
+ aModel.mbThickTop = getFlag( nFlags1, OOBIN_ROW_THICKTOP );
+ aModel.mbThickBottom = getFlag( nFlags1, OOBIN_ROW_THICKBOTTOM );
+ // set row properties in the current sheet
+ setRowModel( aModel );
+}
+
+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, true ) )
+ {
+ DataTableModel aModel;
+ BinAddress aRef1, aRef2;
+ sal_uInt8 nFlags;
+ rStrm >> aRef1 >> aRef2 >> nFlags;
+ aModel.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false );
+ aModel.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false );
+ aModel.mbRowTable = getFlag( nFlags, OOBIN_DATATABLE_ROW );
+ aModel.mb2dTable = getFlag( nFlags, OOBIN_DATATABLE_2D );
+ aModel.mbRef1Deleted = getFlag( nFlags, OOBIN_DATATABLE_REF1DEL );
+ aModel.mbRef2Deleted = getFlag( nFlags, OOBIN_DATATABLE_REF2DEL );
+ setTableOperation( aTableRange, aModel );
+ }
+}
+
+// ============================================================================
+
+BiffSheetDataContext::BiffSheetDataContext( const BiffWorksheetFragmentBase& rParent ) :
+ BiffWorksheetContextBase( rParent ),
+ 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()
+{
+ sal_uInt16 nRecId = mrStrm.getRecId();
+ switch( nRecId )
+ {
+ // records in all BIFF versions
+ case BIFF2_ID_ARRAY: // #i72713#
+ case BIFF3_ID_ARRAY: importArray(); break;
+ case BIFF2_ID_BLANK:
+ case BIFF3_ID_BLANK: importBlank(); break;
+ case BIFF2_ID_BOOLERR:
+ case BIFF3_ID_BOOLERR: importBoolErr(); break;
+ case BIFF2_ID_INTEGER: importInteger(); break;
+ case BIFF_ID_IXFE: mrStrm >> mnBiff2XfId; break;
+ case BIFF2_ID_LABEL:
+ case BIFF3_ID_LABEL: importLabel(); break;
+ case BIFF2_ID_NUMBER:
+ case BIFF3_ID_NUMBER: importNumber(); break;
+ case BIFF_ID_RK: importRk(); break;
+
+ // BIFF specific records
+ default: switch( getBiff() )
+ {
+ case BIFF2: switch( nRecId )
+ {
+ case BIFF2_ID_DATATABLE: importDataTable(); break;
+ case BIFF2_ID_DATATABLE2: importDataTable(); break;
+ case BIFF2_ID_FORMULA: importFormula(); break;
+ case BIFF2_ID_ROW: importRow(); break;
+ }
+ break;
+
+ case BIFF3: switch( nRecId )
+ {
+ case BIFF3_ID_DATATABLE: importDataTable(); break;
+ case BIFF3_ID_FORMULA: importFormula(); break;
+ case BIFF3_ID_ROW: importRow(); break;
+ }
+ break;
+
+ case BIFF4: switch( nRecId )
+ {
+ case BIFF3_ID_DATATABLE: importDataTable(); break;
+ case BIFF4_ID_FORMULA: importFormula(); break;
+ case BIFF3_ID_ROW: importRow(); break;
+ }
+ break;
+
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF3_ID_DATATABLE: importDataTable(); break;
+ case BIFF3_ID_FORMULA:
+ case BIFF4_ID_FORMULA:
+ case BIFF5_ID_FORMULA: importFormula(); break;
+ case BIFF_ID_MULTBLANK: importMultBlank(); break;
+ case BIFF_ID_MULTRK: importMultRk(); break;
+ case BIFF3_ID_ROW: importRow(); break;
+ case BIFF_ID_RSTRING: importLabel(); break;
+ case BIFF_ID_SHAREDFMLA: importSharedFmla(); break;
+ }
+ break;
+
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF3_ID_DATATABLE: importDataTable(); break;
+ case BIFF3_ID_FORMULA:
+ case BIFF4_ID_FORMULA:
+ case BIFF5_ID_FORMULA: importFormula(); break;
+ case BIFF_ID_LABELSST: importLabelSst(); break;
+ case BIFF_ID_MULTBLANK: importMultBlank(); break;
+ case BIFF_ID_MULTRK: importMultRk(); break;
+ case BIFF3_ID_ROW: importRow(); break;
+ case BIFF_ID_RSTRING: importLabel(); break;
+ case BIFF_ID_SHAREDFMLA: importSharedFmla(); break;
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void BiffSheetDataContext::setCurrCell( const BinAddress& rAddr )
+{
+ maCurrCell.reset();
+ maCurrCell.mxCell = getCell( rAddr, &maCurrCell.maAddress );
+ // update used area of the sheet
+ if( maCurrCell.mxCell.is() )
+ extendUsedArea( maCurrCell.maAddress );
+}
+
+void BiffSheetDataContext::importXfId( bool bBiff2 )
+{
+ if( bBiff2 )
+ {
+ sal_uInt8 nBiff2XfId;
+ mrStrm >> nBiff2XfId;
+ mrStrm.skip( 2 );
+ maCurrCell.mnXfId = nBiff2XfId & BIFF2_XF_MASK;
+ if( maCurrCell.mnXfId == BIFF2_XF_EXTENDED_IDS )
+ maCurrCell.mnXfId = mnBiff2XfId;
+ }
+ else
+ {
+ maCurrCell.mnXfId = mrStrm.readuInt16();
+ }
+}
+
+void BiffSheetDataContext::importCellHeader( bool bBiff2 )
+{
+ BinAddress aAddr;
+ mrStrm >> aAddr;
+ setCurrCell( aAddr );
+ importXfId( bBiff2 );
+}
+
+void BiffSheetDataContext::importBlank()
+{
+ importCellHeader( mrStrm.getRecId() == BIFF2_ID_BLANK );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importBoolErr()
+{
+ importCellHeader( mrStrm.getRecId() == BIFF2_ID_BOOLERR );
+ if( maCurrCell.mxCell.is() )
+ {
+ sal_uInt8 nValue, nType;
+ mrStrm >> 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()
+{
+ importCellHeader( getBiff() == BIFF2 );
+ maCurrCell.mnCellType = XML_n;
+ Reference< XFormulaTokens > xTokens( maCurrCell.mxCell, UNO_QUERY );
+ if( xTokens.is() )
+ {
+ mrStrm.skip( mnFormulaIgnoreSize );
+ ExtCellFormulaContext aContext( *this, xTokens, maCurrCell.maAddress );
+ getFormulaParser().importFormula( aContext, mrStrm );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importInteger()
+{
+ importCellHeader( true );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( mrStrm.readuInt16() );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importLabel()
+{
+ bool bBiff2Xf = mrStrm.getRecId() == BIFF2_ID_LABEL;
+ importCellHeader( 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( mrStrm );
+ }
+ 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, mrStrm.getRecId() == BIFF_ID_RSTRING );
+ aString.importByteString( mrStrm, eTextEnc, nFlags );
+ }
+ aString.finalizeImport();
+ aString.convert( xText, maCurrCell.mnXfId );
+ }
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importLabelSst()
+{
+ importCellHeader( false );
+ maCurrCell.mnCellType = XML_s;
+ if( maCurrCell.mxCell.is() )
+ setSharedStringCell( maCurrCell.mxCell, mrStrm.readInt32(), maCurrCell.mnXfId );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importMultBlank()
+{
+ BinAddress aAddr;
+ for( mrStrm >> aAddr; mrStrm.getRemaining() > 2; ++aAddr.mnCol )
+ {
+ setCurrCell( aAddr );
+ importXfId( false );
+ setCellFormat( maCurrCell );
+ }
+}
+
+void BiffSheetDataContext::importMultRk()
+{
+ BinAddress aAddr;
+ for( mrStrm >> aAddr; mrStrm.getRemaining() > 2; ++aAddr.mnCol )
+ {
+ setCurrCell( aAddr );
+ maCurrCell.mnCellType = XML_n;
+ importXfId( false );
+ sal_Int32 nRkValue = mrStrm.readInt32();
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( BiffHelper::calcDoubleFromRk( nRkValue ) );
+ setCellFormat( maCurrCell );
+ }
+}
+
+void BiffSheetDataContext::importNumber()
+{
+ importCellHeader( mrStrm.getRecId() == BIFF2_ID_NUMBER );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( mrStrm.readDouble() );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importRk()
+{
+ importCellHeader( false );
+ maCurrCell.mnCellType = XML_n;
+ if( maCurrCell.mxCell.is() )
+ maCurrCell.mxCell->setValue( BiffHelper::calcDoubleFromRk( mrStrm.readInt32() ) );
+ setCellFormat( maCurrCell );
+}
+
+void BiffSheetDataContext::importRow()
+{
+ RowModel aModel;
+
+ sal_uInt16 nRow, nHeight;
+ mrStrm >> nRow;
+ mrStrm.skip( 4 );
+ mrStrm >> nHeight;
+ if( getBiff() == BIFF2 )
+ {
+ mrStrm.skip( 2 );
+ aModel.mbCustomFormat = mrStrm.readuInt8() == BIFF2_ROW_CUSTOMFORMAT;
+ if( aModel.mbCustomFormat )
+ {
+ mrStrm.skip( 5 );
+ aModel.mnXfId = mrStrm.readuInt16();
+ }
+ }
+ else
+ {
+ mrStrm.skip( 4 );
+ sal_uInt32 nFlags = mrStrm.readuInt32();
+ aModel.mnXfId = extractValue< sal_Int32 >( nFlags, 16, 12 );
+ aModel.mnLevel = extractValue< sal_Int32 >( nFlags, 0, 3 );
+ aModel.mbCustomFormat = getFlag( nFlags, BIFF_ROW_CUSTOMFORMAT );
+ aModel.mbCustomHeight = getFlag( nFlags, BIFF_ROW_CUSTOMHEIGHT );
+ aModel.mbShowPhonetic = getFlag( nFlags, BIFF_ROW_SHOWPHONETIC );
+ aModel.mbHidden = getFlag( nFlags, BIFF_ROW_HIDDEN );
+ aModel.mbCollapsed = getFlag( nFlags, BIFF_ROW_COLLAPSED );
+ aModel.mbThickTop = getFlag( nFlags, BIFF_ROW_THICKTOP );
+ aModel.mbThickBottom = getFlag( nFlags, BIFF_ROW_THICKBOTTOM );
+ }
+
+ // row index is 0-based in BIFF, but RowModel expects 1-based
+ aModel.mnFirstRow = aModel.mnLastRow = nRow + 1;
+ // row height is in twips in BIFF, convert to points
+ aModel.mfHeight = (nHeight & BIFF_ROW_HEIGHTMASK) / 20.0;
+ // set row properties in the current sheet
+ setRowModel( aModel );
+}
+
+void BiffSheetDataContext::importArray()
+{
+ BinRange aRange;
+ aRange.read( mrStrm, false ); // columns always 8-bit
+ CellRangeAddress aArrayRange;
+ Reference< XCellRange > xRange = getCellRange( aRange, &aArrayRange );
+ Reference< XArrayFormulaTokens > xTokens( xRange, UNO_QUERY );
+ if( xRange.is() && xTokens.is() )
+ {
+ mrStrm.skip( mnArrayIgnoreSize );
+ ArrayFormulaContext aContext( xTokens, aArrayRange );
+ getFormulaParser().importFormula( aContext, mrStrm );
+ }
+}
+
+void BiffSheetDataContext::importSharedFmla()
+{
+ getSharedFormulas().importSharedFmla( mrStrm, maCurrCell.maAddress );
+}
+
+void BiffSheetDataContext::importDataTable()
+{
+ BinRange aRange;
+ aRange.read( mrStrm, false ); // columns always 8-bit
+ CellRangeAddress aTableRange;
+ if( getAddressConverter().convertToCellRange( aTableRange, aRange, getSheetIndex(), true, true ) )
+ {
+ DataTableModel aModel;
+ BinAddress aRef1, aRef2;
+ switch( mrStrm.getRecId() )
+ {
+ case BIFF2_ID_DATATABLE:
+ mrStrm.skip( 1 );
+ aModel.mbRowTable = mrStrm.readuInt8() != 0;
+ aModel.mb2dTable = false;
+ mrStrm >> aRef1;
+ break;
+ case BIFF2_ID_DATATABLE2:
+ mrStrm.skip( 2 );
+ aModel.mb2dTable = true;
+ mrStrm >> aRef1 >> aRef2;
+ break;
+ case BIFF3_ID_DATATABLE:
+ {
+ sal_uInt16 nFlags;
+ mrStrm >> nFlags >> aRef1 >> aRef2;
+ aModel.mbRowTable = getFlag( nFlags, BIFF_DATATABLE_ROW );
+ aModel.mb2dTable = getFlag( nFlags, BIFF_DATATABLE_2D );
+ aModel.mbRef1Deleted = getFlag( nFlags, BIFF_DATATABLE_REF1DEL );
+ aModel.mbRef2Deleted = getFlag( nFlags, BIFF_DATATABLE_REF2DEL );
+ }
+ break;
+ default:
+ OSL_ENSURE( false, "BiffSheetDataContext::importDataTable - unknown record id" );
+ }
+ aModel.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false );
+ aModel.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false );
+ setTableOperation( aTableRange, aModel );
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/stylesbuffer.cxx b/oox/source/xls/stylesbuffer.cxx
new file mode 100644
index 000000000000..6c06b6a37dfe
--- /dev/null
+++ b/oox/source/xls/stylesbuffer.cxx
@@ -0,0 +1,3522 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/stylesbuffer.hxx"
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontPitch.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontType.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontUnderline.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 <com/sun/star/table/CellVertJustify2.hpp>
+#include <com/sun/star/table/CellJustifyMethod.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <rtl/tencinfo.h>
+#include <rtl/ustrbuf.hxx>
+#include "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertymap.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/condformatbuffer.hxx"
+#include "oox/xls/excelhandlers.hxx"
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+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 ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+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::table::BorderLine2;
+using ::com::sun::star::table::TableBorder;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::style::XStyle;
+using ::oox::core::FilterBase;
+
+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 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 = 0;
+const sal_uInt8 OOBIN_COLOR_INDEXED = 1;
+const sal_uInt8 OOBIN_COLOR_RGB = 2;
+const sal_uInt8 OOBIN_COLOR_THEME = 3;
+
+// 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_CHARSET = 34;
+const sal_uInt16 OOBIN_DXF_FONT_FAMILY = 35;
+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 STYLEEXT flags
+const sal_uInt8 BIFF_STYLEEXT_BUILTIN = 0x01;
+const sal_uInt8 BIFF_STYLEEXT_HIDDEN = 0x02;
+const sal_uInt8 BIFF_STYLEEXT_CUSTOM = 0x04;
+
+// 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 lclReadRgbColor( BinaryInputStream& rStrm )
+{
+ sal_uInt8 nR, nG, nB, nA;
+ rStrm >> nR >> nG >> nB >> nA;
+ sal_Int32 nValue = nA;
+ nValue <<= 8;
+ nValue |= nR;
+ nValue <<= 8;
+ nValue |= nG;
+ nValue <<= 8;
+ nValue |= nB;
+ return nValue;
+}
+
+} // namespace
+
+// ============================================================================
+
+ExcelGraphicHelper::ExcelGraphicHelper( const WorkbookHelper& rHelper ) :
+ GraphicHelper( rHelper.getGlobalFactory(), rHelper.getBaseFilter().getTargetFrame(), rHelper.getBaseFilter().getStorage() ),
+ WorkbookHelper( rHelper )
+{
+}
+
+sal_Int32 ExcelGraphicHelper::getSchemeColor( sal_Int32 nToken ) const
+{
+ if( getFilterType() == FILTER_OOX )
+ return getTheme().getColorByToken( nToken );
+ return GraphicHelper::getSchemeColor( nToken );
+}
+
+sal_Int32 ExcelGraphicHelper::getPaletteColor( sal_Int32 nPaletteIdx ) const
+{
+ return getStyles().getPaletteColor( nPaletteIdx );
+}
+
+// ============================================================================
+
+void Color::setAuto()
+{
+ clearTransformations();
+ setSchemeClr( XML_phClr );
+}
+
+void Color::setRgb( sal_Int32 nRgbValue, double fTint )
+{
+ clearTransformations();
+ setSrgbClr( nRgbValue & 0xFFFFFF );
+ if( fTint != 0.0 ) addExcelTintTransformation( fTint );
+}
+
+void Color::setTheme( sal_Int32 nThemeIdx, double fTint )
+{
+ clearTransformations();
+ 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 };
+ setSchemeClr( STATIC_ARRAY_SELECT( spnColorTokens, nThemeIdx, XML_TOKEN_INVALID ) );
+ if( fTint != 0.0 ) addExcelTintTransformation( fTint );
+}
+
+void Color::setIndexed( sal_Int32 nPaletteIdx, double fTint )
+{
+ clearTransformations();
+ setPaletteClr( nPaletteIdx );
+ if( fTint != 0.0 ) addExcelTintTransformation( fTint );
+}
+
+void Color::importColor( const AttributeList& rAttribs )
+{
+ if( rAttribs.getBool( XML_auto, false ) )
+ setAuto();
+ else if( rAttribs.hasAttribute( XML_rgb ) )
+ setRgb( rAttribs.getIntegerHex( XML_rgb, API_RGB_TRANSPARENT ), rAttribs.getDouble( XML_tint, 0.0 ) );
+ else if( rAttribs.hasAttribute( XML_theme ) )
+ setTheme( rAttribs.getInteger( XML_theme, -1 ), rAttribs.getDouble( XML_tint, 0.0 ) );
+ else if( rAttribs.hasAttribute( XML_indexed ) )
+ setIndexed( rAttribs.getInteger( XML_indexed, -1 ), rAttribs.getDouble( XML_tint, 0.0 ) );
+ else
+ {
+ OSL_ENSURE( false, "Color::importColor - unknown color type" );
+ setAuto();
+ }
+}
+
+void Color::importColor( RecordInputStream& rStrm )
+{
+ sal_uInt8 nFlags, nIndex;
+ sal_Int16 nTint;
+ rStrm >> nFlags >> nIndex >> nTint;
+
+ // scale tint from signed 16-bit to double range -1.0 ... 1.0
+ double fTint = nTint;
+ if( nTint < 0 )
+ fTint /= -SAL_MIN_INT16;
+ else if( nTint > 0 )
+ fTint /= SAL_MAX_INT16;
+
+ switch( extractValue< sal_uInt8 >( nFlags, 1, 7 ) )
+ {
+ case OOBIN_COLOR_AUTO:
+ setAuto();
+ rStrm.skip( 4 );
+ break;
+ case OOBIN_COLOR_INDEXED:
+ setIndexed( nIndex, fTint );
+ rStrm.skip( 4 );
+ break;
+ case OOBIN_COLOR_RGB:
+ setRgb( lclReadRgbColor( rStrm ), fTint );
+ break;
+ case OOBIN_COLOR_THEME:
+ setTheme( nIndex, fTint );
+ rStrm.skip( 4 );
+ break;
+ default:
+ OSL_ENSURE( false, "Color::importColor - unknown color type" );
+ setAuto();
+ rStrm.skip( 4 );
+ }
+}
+
+void Color::importColorId( RecordInputStream& rStrm )
+{
+ setIndexed( rStrm.readInt32() );
+}
+
+void Color::importColorRgb( RecordInputStream& rStrm )
+{
+ setRgb( lclReadRgbColor( rStrm ) );
+}
+
+void Color::importColorId( BiffInputStream& rStrm, bool b16Bit )
+{
+ setIndexed( b16Bit ? rStrm.readuInt16() : rStrm.readuInt8() );
+}
+
+void Color::importColorRgb( BiffInputStream& rStrm )
+{
+ setRgb( lclReadRgbColor( rStrm ) );
+}
+
+RecordInputStream& operator>>( RecordInputStream& rStrm, Color& 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 )
+{
+ // 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.getIntegerHex( XML_rgb, API_RGB_WHITE ) );
+}
+
+void ColorPalette::importPaletteColor( RecordInputStream& rStrm )
+{
+ sal_Int32 nRgb = lclReadRgbColor( rStrm );
+ appendColor( nRgb & 0xFFFFFF );
+}
+
+void ColorPalette::importPalette( BiffInputStream& rStrm )
+{
+ sal_uInt16 nCount;
+ rStrm >> nCount;
+ OSL_ENSURE( rStrm.getRemaining() == 4 * nCount, "ColorPalette::importPalette - wrong palette size" );
+
+ // fill palette from BIFF_COLOR_USEROFFSET
+ mnAppendIndex = BIFF_COLOR_USEROFFSET;
+ for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
+ {
+ sal_Int32 nRgb = lclReadRgbColor( rStrm );
+ appendColor( nRgb & 0xFFFFFF );
+ }
+}
+
+sal_Int32 ColorPalette::getColor( sal_Int32 nPaletteIdx ) const
+{
+ sal_Int32 nColor = API_RGB_TRANSPARENT;
+ if( const sal_Int32* pnPaletteColor = ContainerHelper::getVectorElement( maColors, nPaletteIdx ) )
+ {
+ nColor = *pnPaletteColor;
+ }
+ else switch( nPaletteIdx )
+ {
+ case OOX_COLOR_WINDOWTEXT3:
+ case OOX_COLOR_WINDOWTEXT:
+ case OOX_COLOR_CHWINDOWTEXT: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_windowText ); break;
+ case OOX_COLOR_WINDOWBACK3:
+ case OOX_COLOR_WINDOWBACK:
+ case OOX_COLOR_CHWINDOWBACK: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_window ); break;
+ case OOX_COLOR_BUTTONBACK: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_btnFace ); break;
+ case OOX_COLOR_CHBORDERAUTO: nColor = API_RGB_BLACK; /* really always black? */ break;
+ case OOX_COLOR_NOTEBACK: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_infoBk ); break;
+ case OOX_COLOR_NOTETEXT: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_infoText ); break;
+ 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;
+}
+
+// ============================================================================
+
+namespace {
+
+void lclSetFontName( ApiScriptFontName& rFontName, const FontDescriptor& rFontDesc, bool bHasGlyphs )
+{
+ if( bHasGlyphs )
+ {
+ rFontName.maName = rFontDesc.Name;
+ rFontName.mnFamily = rFontDesc.Family;
+ // API font descriptor contains rtl_TextEncoding constants
+ rFontName.mnTextEnc = rFontDesc.CharSet;
+ }
+ else
+ {
+ rFontName = ApiScriptFontName();
+ }
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+FontModel::FontModel() :
+ mnScheme( XML_none ),
+ mnFamily( OOX_FONTFAMILY_NONE ),
+ mnCharSet( WINDOWS_CHARSET_DEFAULT ),
+ mfHeight( 0.0 ),
+ mnUnderline( XML_none ),
+ mnEscapement( XML_baseline ),
+ mbBold( false ),
+ mbItalic( false ),
+ mbStrikeout( false ),
+ mbOutline( false ),
+ mbShadow( false )
+{
+}
+
+void FontModel::setBinScheme( sal_uInt8 nScheme )
+{
+ static const sal_Int32 spnSchemes[] = { XML_none, XML_major, XML_minor };
+ mnScheme = STATIC_ARRAY_SELECT( spnSchemes, nScheme, XML_none );
+}
+
+void FontModel::setBiffHeight( sal_uInt16 nHeight )
+{
+ mfHeight = nHeight / 20.0; // convert twips to points
+}
+
+void FontModel::setBiffWeight( sal_uInt16 nWeight )
+{
+ mbBold = nWeight >= BIFF_FONTWEIGHT_BOLD;
+}
+
+void FontModel::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 FontModel::setBiffEscapement( sal_uInt16 nEscapement )
+{
+ static const sal_Int32 spnEscapes[] = { XML_baseline, XML_superscript, XML_subscript };
+ mnEscapement = STATIC_ARRAY_SELECT( spnEscapes, nEscapement, XML_baseline );
+}
+
+// ----------------------------------------------------------------------------
+
+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 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ApiScriptFontName::ApiScriptFontName() :
+ mnFamily( ::com::sun::star::awt::FontFamily::DONTKNOW ),
+ mnTextEnc( RTL_TEXTENCODING_DONTKNOW )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+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 )
+{
+ maLatinFont.maName = maDesc.Name;
+}
+
+// ============================================================================
+
+Font::Font( const WorkbookHelper& rHelper, bool bDxf ) :
+ WorkbookHelper( rHelper ),
+ maModel( rHelper.getTheme().getDefaultFontModel() ),
+ maUsedFlags( !bDxf ),
+ mbDxf( bDxf )
+{
+}
+
+Font::Font( const WorkbookHelper& rHelper, const FontModel& rModel ) :
+ WorkbookHelper( rHelper ),
+ maModel( rModel ),
+ maUsedFlags( true ),
+ mbDxf( false )
+{
+}
+
+void Font::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ const FontModel& rDefModel = getTheme().getDefaultFontModel();
+ switch( nElement )
+ {
+ case XLS_TOKEN( name ): // when in <font> element
+ case XLS_TOKEN( rFont ): // when in <rPr> element
+ if( rAttribs.hasAttribute( XML_val ) )
+ {
+ maModel.maName = rAttribs.getXString( XML_val, OUString() );
+ maUsedFlags.mbNameUsed = true;
+ }
+ break;
+ case XLS_TOKEN( scheme ):
+ maModel.mnScheme = rAttribs.getToken( XML_val, rDefModel.mnScheme );
+ break;
+ case XLS_TOKEN( family ):
+ maModel.mnFamily = rAttribs.getInteger( XML_val, rDefModel.mnFamily );
+ break;
+ case XLS_TOKEN( charset ):
+ maModel.mnCharSet = rAttribs.getInteger( XML_val, rDefModel.mnCharSet );
+ break;
+ case XLS_TOKEN( sz ):
+ maModel.mfHeight = rAttribs.getDouble( XML_val, rDefModel.mfHeight );
+ maUsedFlags.mbHeightUsed = true;
+ break;
+ case XLS_TOKEN( color ):
+ maModel.maColor.importColor( rAttribs );
+ maUsedFlags.mbColorUsed = true;
+ break;
+ case XLS_TOKEN( u ):
+ maModel.mnUnderline = rAttribs.getToken( XML_val, XML_single );
+ maUsedFlags.mbUnderlineUsed = true;
+ break;
+ case XLS_TOKEN( vertAlign ):
+ maModel.mnEscapement = rAttribs.getToken( XML_val, XML_baseline );
+ maUsedFlags.mbEscapementUsed = true;
+ break;
+ case XLS_TOKEN( b ):
+ maModel.mbBold = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbWeightUsed = true;
+ break;
+ case XLS_TOKEN( i ):
+ maModel.mbItalic = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbPostureUsed = true;
+ break;
+ case XLS_TOKEN( strike ):
+ maModel.mbStrikeout = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbStrikeoutUsed = true;
+ break;
+ case XLS_TOKEN( outline ):
+ maModel.mbOutline = rAttribs.getBool( XML_val, true );
+ maUsedFlags.mbOutlineUsed = true;
+ break;
+ case XLS_TOKEN( shadow ):
+ maModel.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 >> maModel.maColor >> nScheme >> maModel.maName;
+
+ // equal constants in BIFF and OOBIN for weight, underline, and escapement
+ maModel.setBinScheme( nScheme );
+ maModel.setBiffHeight( nHeight );
+ maModel.setBiffWeight( nWeight );
+ maModel.setBiffUnderline( nUnderline );
+ maModel.setBiffEscapement( nEscapement );
+ maModel.mnFamily = nFamily;
+ maModel.mnCharSet = nCharSet;
+ // equal flags in BIFF and OOBIN
+ maModel.mbItalic = getFlag( nFlags, BIFF_FONTFLAG_ITALIC );
+ maModel.mbStrikeout = getFlag( nFlags, BIFF_FONTFLAG_STRIKEOUT );
+ maModel.mbOutline = getFlag( nFlags, BIFF_FONTFLAG_OUTLINE );
+ maModel.mbShadow = getFlag( nFlags, BIFF_FONTFLAG_SHADOW );
+}
+
+void Font::importDxfName( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfName - missing conditional formatting flag" );
+ maModel.maName = rStrm.readString( false );
+ maUsedFlags.mbColorUsed = true;
+}
+
+void Font::importDxfColor( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfColor - missing conditional formatting flag" );
+ rStrm >> maModel.maColor;
+ maUsedFlags.mbColorUsed = true;
+}
+
+void Font::importDxfScheme( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfScheme - missing conditional formatting flag" );
+ maModel.setBinScheme( rStrm.readuInt8() );
+ maUsedFlags.mbSchemeUsed = true;
+}
+
+void Font::importDxfHeight( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfHeight - missing conditional formatting flag" );
+ maModel.setBiffHeight( rStrm.readuInt16() );
+ maUsedFlags.mbHeightUsed = true;
+}
+
+void Font::importDxfWeight( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfWeight - missing conditional formatting flag" );
+ maModel.setBiffWeight( rStrm.readuInt16() );
+ maUsedFlags.mbWeightUsed = true;
+}
+
+void Font::importDxfUnderline( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfUnderline - missing conditional formatting flag" );
+ maModel.setBiffUnderline( rStrm.readuInt16() );
+ maUsedFlags.mbUnderlineUsed = true;
+}
+
+void Font::importDxfEscapement( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Font::importDxfEscapement - missing conditional formatting flag" );
+ maModel.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:
+ maModel.mbItalic = bFlag;
+ maUsedFlags.mbPostureUsed = true;
+ break;
+ case XML_strike:
+ maModel.mbStrikeout = bFlag;
+ maUsedFlags.mbStrikeoutUsed = true;
+ break;
+ case XML_outline:
+ maModel.mbOutline = bFlag;
+ maUsedFlags.mbOutlineUsed = true;
+ break;
+ case XML_shadow:
+ maModel.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" );
+ maModel.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.getRemaining() >= 118, "Font::importCfRule - missing record data" );
+ sal_Int64 nRecPos = rStrm.tell();
+ maModel.maName = rStrm.readUniStringBody( rStrm.readuInt8() );
+ maUsedFlags.mbNameUsed = maModel.maName.getLength() > 0;
+ OSL_ENSURE( !rStrm.isEof() && (rStrm.tell() <= 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 )
+ maModel.maColor.setIndexed( nColor );
+ if( (maUsedFlags.mbHeightUsed = (0 < nHeight) && (nHeight <= 0x7FFF)) == true )
+ maModel.setBiffHeight( static_cast< sal_uInt16 >( nHeight ) );
+ if( (maUsedFlags.mbUnderlineUsed = !getFlag( nFontFlags3, BIFF_CFRULE_FONT_UNDERL )) == true )
+ maModel.setBiffUnderline( nUnderline );
+ if( (maUsedFlags.mbEscapementUsed = !getFlag( nFontFlags2, BIFF_CFRULE_FONT_ESCAPEM )) == true )
+ maModel.setBiffEscapement( nEscapement );
+ if( (maUsedFlags.mbWeightUsed = maUsedFlags.mbPostureUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_STYLE )) == true )
+ {
+ maModel.setBiffWeight( nWeight );
+ maModel.mbItalic = getFlag( nStyle, BIFF_CFRULE_FONT_STYLE );
+ }
+ if( (maUsedFlags.mbStrikeoutUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_STRIKEOUT )) == true )
+ maModel.mbStrikeout = getFlag( nStyle, BIFF_CFRULE_FONT_STRIKEOUT );
+ if( (maUsedFlags.mbOutlineUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_OUTLINE )) == true )
+ maModel.mbOutline = getFlag( nStyle, BIFF_CFRULE_FONT_OUTLINE );
+ if( (maUsedFlags.mbShadowUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_SHADOW )) == true )
+ maModel.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 <= maModel.mnCharSet) && (maModel.mnCharSet <= SAL_MAX_UINT8) )
+ eFontEnc = rtl_getTextEncodingFromWindowsCharset( static_cast< sal_uInt8 >( maModel.mnCharSet ) );
+ return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? getTextEncoding() : eFontEnc;
+}
+
+void Font::finalizeImport()
+{
+ namespace cssawt = ::com::sun::star::awt;
+
+ // font name
+ maApiData.maDesc.Name = maModel.maName;
+
+ // font family
+ switch( maModel.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 (API font descriptor uses rtl_TextEncoding in member CharSet!)
+ if( (0 <= maModel.mnCharSet) && (maModel.mnCharSet <= SAL_MAX_UINT8) )
+ maApiData.maDesc.CharSet = static_cast< sal_Int16 >(
+ rtl_getTextEncodingFromWindowsCharset( static_cast< sal_uInt8 >( maModel.mnCharSet ) ) );
+
+ // color, height, weight, slant, strikeout, outline, shadow
+ maApiData.mnColor = maModel.maColor.getColor( getBaseFilter().getGraphicHelper() );
+ maApiData.maDesc.Height = static_cast< sal_Int16 >( maModel.mfHeight * 20.0 );
+ maApiData.maDesc.Weight = maModel.mbBold ? cssawt::FontWeight::BOLD : cssawt::FontWeight::NORMAL;
+ maApiData.maDesc.Slant = maModel.mbItalic ? cssawt::FontSlant_ITALIC : cssawt::FontSlant_NONE;
+ maApiData.maDesc.Strikeout = maModel.mbStrikeout ? cssawt::FontStrikeout::SINGLE : cssawt::FontStrikeout::NONE;
+ maApiData.mbOutline = maModel.mbOutline;
+ maApiData.mbShadow = maModel.mbShadow;
+
+ // underline
+ switch( maModel.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( maModel.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
+ bool bHasAsian =
+ 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
+ bool bHasCmplx =
+ 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
+ bool bHasLatin =
+ (!bHasAsian && !bHasCmplx) ||
+ xFont->hasGlyphs( OUString( sal_Unicode( 'A' ) ) );
+
+ lclSetFontName( maApiData.maLatinFont, maApiData.maDesc, bHasLatin );
+ lclSetFontName( maApiData.maAsianFont, maApiData.maDesc, bHasAsian );
+ lclSetFontName( maApiData.maCmplxFont, maApiData.maDesc, bHasCmplx );
+ }
+ }
+ }
+}
+
+const FontDescriptor& Font::getFontDescriptor() const
+{
+ return maApiData.maDesc;
+}
+
+bool Font::needsRichTextFormat() const
+{
+ return maApiData.mnEscapement != API_ESCAPE_NONE;
+}
+
+void Font::writeToPropertyMap( PropertyMap& rPropMap, FontPropertyType ePropType ) const
+{
+ // font name properties
+ if( maUsedFlags.mbNameUsed )
+ {
+ if( maApiData.maLatinFont.maName.getLength() > 0 )
+ {
+ rPropMap[ PROP_CharFontName ] <<= maApiData.maLatinFont.maName;
+ rPropMap[ PROP_CharFontFamily ] <<= maApiData.maLatinFont.mnFamily;
+ rPropMap[ PROP_CharFontCharSet ] <<= maApiData.maLatinFont.mnTextEnc;
+ }
+ if( maApiData.maAsianFont.maName.getLength() > 0 )
+ {
+ rPropMap[ PROP_CharFontNameAsian ] <<= maApiData.maAsianFont.maName;
+ rPropMap[ PROP_CharFontFamilyAsian ] <<= maApiData.maAsianFont.mnFamily;
+ rPropMap[ PROP_CharFontCharSetAsian ] <<= maApiData.maAsianFont.mnTextEnc;
+ }
+ if( maApiData.maCmplxFont.maName.getLength() > 0 )
+ {
+ rPropMap[ PROP_CharFontNameComplex ] <<= maApiData.maCmplxFont.maName;
+ rPropMap[ PROP_CharFontFamilyComplex ] <<= maApiData.maCmplxFont.mnFamily;
+ rPropMap[ PROP_CharFontCharSetComplex ] <<= maApiData.maCmplxFont.mnTextEnc;
+ }
+ }
+ // font height
+ if( maUsedFlags.mbHeightUsed )
+ {
+ float fHeight = static_cast< float >( maApiData.maDesc.Height / 20.0 ); // twips to points
+ rPropMap[ PROP_CharHeight ] <<= fHeight;
+ rPropMap[ PROP_CharHeightAsian ] <<= fHeight;
+ rPropMap[ PROP_CharHeightComplex ] <<= fHeight;
+ }
+ // font weight
+ if( maUsedFlags.mbWeightUsed )
+ {
+ float fWeight = maApiData.maDesc.Weight;
+ rPropMap[ PROP_CharWeight ] <<= fWeight;
+ rPropMap[ PROP_CharWeightAsian ] <<= fWeight;
+ rPropMap[ PROP_CharWeightComplex ] <<= fWeight;
+ }
+ // font posture
+ if( maUsedFlags.mbPostureUsed )
+ {
+ rPropMap[ PROP_CharPosture ] <<= maApiData.maDesc.Slant;
+ rPropMap[ PROP_CharPostureAsian ] <<= maApiData.maDesc.Slant;
+ rPropMap[ PROP_CharPostureComplex ] <<= maApiData.maDesc.Slant;
+ }
+ // character color
+ if( maUsedFlags.mbColorUsed )
+ rPropMap[ PROP_CharColor ] <<= maApiData.mnColor;
+ // underline style
+ if( maUsedFlags.mbUnderlineUsed )
+ rPropMap[ PROP_CharUnderline ] <<= maApiData.maDesc.Underline;
+ // strike out style
+ if( maUsedFlags.mbStrikeoutUsed )
+ rPropMap[ PROP_CharStrikeout ] <<= maApiData.maDesc.Strikeout;
+ // outline style
+ if( maUsedFlags.mbOutlineUsed )
+ rPropMap[ PROP_CharContoured ] <<= maApiData.mbOutline;
+ // shadow style
+ if( maUsedFlags.mbShadowUsed )
+ rPropMap[ PROP_CharShadowed ] <<= maApiData.mbShadow;
+ // escapement
+ if( maUsedFlags.mbEscapementUsed && (ePropType == FONT_PROPTYPE_TEXT) )
+ {
+ rPropMap[ PROP_CharEscapement ] <<= maApiData.mnEscapement;
+ rPropMap[ PROP_CharEscapementHeight ] <<= maApiData.mnEscapeHeight;
+ }
+}
+
+void Font::writeToPropertySet( PropertySet& rPropSet, FontPropertyType ePropType ) const
+{
+ PropertyMap aPropMap;
+ writeToPropertyMap( aPropMap, ePropType );
+ rPropSet.setProperties( aPropMap );
+}
+
+void Font::importFontData2( BiffInputStream& rStrm )
+{
+ sal_uInt16 nHeight, nFlags;
+ rStrm >> nHeight >> nFlags;
+
+ maModel.setBiffHeight( nHeight );
+ maModel.mnFamily = OOX_FONTFAMILY_NONE;
+ maModel.mnCharSet = -1; // ensure to not use font charset in byte string import
+ maModel.mnUnderline = getFlagValue( nFlags, BIFF_FONTFLAG_UNDERLINE, XML_single, XML_none );
+ maModel.mnEscapement = XML_none;
+ maModel.mbBold = getFlag( nFlags, BIFF_FONTFLAG_BOLD );
+ maModel.mbItalic = getFlag( nFlags, BIFF_FONTFLAG_ITALIC );
+ maModel.mbStrikeout = getFlag( nFlags, BIFF_FONTFLAG_STRIKEOUT );
+ maModel.mbOutline = getFlag( nFlags, BIFF_FONTFLAG_OUTLINE );
+ maModel.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 );
+
+ maModel.setBiffWeight( nWeight );
+ maModel.setBiffUnderline( nUnderline );
+ maModel.setBiffEscapement( nEscapement );
+ // equal constants in XML and BIFF for family and charset
+ maModel.mnFamily = nFamily;
+ maModel.mnCharSet = nCharSet;
+}
+
+void Font::importFontName2( BiffInputStream& rStrm )
+{
+ maModel.maName = rStrm.readByteStringUC( false, getTextEncoding() );
+}
+
+void Font::importFontName8( BiffInputStream& rStrm )
+{
+ maModel.maName = rStrm.readUniStringBody( rStrm.readuInt8() );
+}
+
+// ============================================================================
+
+AlignmentModel::AlignmentModel() :
+ 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 AlignmentModel::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 AlignmentModel::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 AlignmentModel::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 );
+}
+
+// ----------------------------------------------------------------------------
+
+ApiAlignmentData::ApiAlignmentData() :
+ meHorJustify( ::com::sun::star::table::CellHoriJustify_STANDARD ),
+ mnHorJustifyMethod( ::com::sun::star::table::CellJustifyMethod::AUTO ),
+ mnVerJustify( ::com::sun::star::table::CellVertJustify2::STANDARD ),
+ mnVerJustifyMethod( ::com::sun::star::table::CellJustifyMethod::AUTO ),
+ 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.mnHorJustifyMethod == rRight.mnHorJustifyMethod) &&
+ (rLeft.mnVerJustify == rRight.mnVerJustify) &&
+ (rLeft.mnVerJustifyMethod == rRight.mnVerJustifyMethod) &&
+ (rLeft.meOrientation == rRight.meOrientation) &&
+ (rLeft.mnRotation == rRight.mnRotation) &&
+ (rLeft.mnWritingMode == rRight.mnWritingMode) &&
+ (rLeft.mnIndent == rRight.mnIndent) &&
+ (rLeft.mbWrapText == rRight.mbWrapText) &&
+ (rLeft.mbShrink == rRight.mbShrink);
+}
+
+// ============================================================================
+
+Alignment::Alignment( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void Alignment::importAlignment( const AttributeList& rAttribs )
+{
+ maModel.mnHorAlign = rAttribs.getToken( XML_horizontal, XML_general );
+ maModel.mnVerAlign = rAttribs.getToken( XML_vertical, XML_bottom );
+ maModel.mnTextDir = rAttribs.getInteger( XML_readingOrder, OOX_XF_TEXTDIR_CONTEXT );
+ maModel.mnRotation = rAttribs.getInteger( XML_textRotation, OOX_XF_ROTATION_NONE );
+ maModel.mnIndent = rAttribs.getInteger( XML_indent, OOX_XF_INDENT_NONE );
+ maModel.mbWrapText = rAttribs.getBool( XML_wrapText, false );
+ maModel.mbShrink = rAttribs.getBool( XML_shrinkToFit, false );
+ maModel.mbJustLastLine = rAttribs.getBool( XML_justifyLastLine, false );
+}
+
+void Alignment::setBinData( sal_uInt32 nFlags )
+{
+ maModel.setBinHorAlign( extractValue< sal_uInt8 >( nFlags, 16, 3 ) );
+ maModel.setBinVerAlign( extractValue< sal_uInt8 >( nFlags, 19, 3 ) );
+ maModel.mnTextDir = extractValue< sal_Int32 >( nFlags, 26, 2 );
+ maModel.mnRotation = extractValue< sal_Int32 >( nFlags, 0, 8 );
+ maModel.mnIndent = extractValue< sal_uInt8 >( nFlags, 8, 8 );
+ maModel.mbWrapText = getFlag( nFlags, OOBIN_XF_WRAPTEXT );
+ maModel.mbShrink = getFlag( nFlags, OOBIN_XF_SHRINK );
+ maModel.mbJustLastLine = getFlag( nFlags, OOBIN_XF_JUSTLASTLINE );
+}
+
+void Alignment::setBiff2Data( sal_uInt8 nFlags )
+{
+ maModel.setBinHorAlign( extractValue< sal_uInt8 >( nFlags, 0, 3 ) );
+}
+
+void Alignment::setBiff3Data( sal_uInt16 nAlign )
+{
+ maModel.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+ maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT ); // new in BIFF3
+}
+
+void Alignment::setBiff4Data( sal_uInt16 nAlign )
+{
+ maModel.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+ maModel.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 2 ) ); // new in BIFF4
+ maModel.setBinTextOrient( extractValue< sal_uInt8 >( nAlign, 6, 2 ) ); // new in BIFF4
+ maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT );
+}
+
+void Alignment::setBiff5Data( sal_uInt16 nAlign )
+{
+ maModel.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+ maModel.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 3 ) );
+ maModel.setBinTextOrient( extractValue< sal_uInt8 >( nAlign, 8, 2 ) );
+ maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT );
+}
+
+void Alignment::setBiff8Data( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
+{
+ maModel.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+ maModel.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 3 ) );
+ maModel.mnTextDir = extractValue< sal_Int32 >( nMiscAttrib, 6, 2 ); // new in BIFF8
+ maModel.mnRotation = extractValue< sal_Int32 >( nAlign, 8, 8 ); // new in BIFF8
+ maModel.mnIndent = extractValue< sal_uInt8 >( nMiscAttrib, 0, 4 ); // new in BIFF8
+ maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT );
+ maModel.mbShrink = getFlag( nMiscAttrib, BIFF_XF_SHRINK ); // new in BIFF8
+ maModel.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( maModel.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;
+ }
+
+ if (maModel.mnHorAlign == XML_distributed)
+ maApiData.mnHorJustifyMethod = csstab::CellJustifyMethod::DISTRIBUTE;
+
+ // vertical alignment
+ switch( maModel.mnVerAlign )
+ {
+ case XML_bottom: maApiData.mnVerJustify = csstab::CellVertJustify2::BOTTOM; break;
+ case XML_center: maApiData.mnVerJustify = csstab::CellVertJustify2::CENTER; break;
+ case XML_distributed: maApiData.mnVerJustify = csstab::CellVertJustify2::BLOCK; break;
+ case XML_justify: maApiData.mnVerJustify = csstab::CellVertJustify2::BLOCK; break;
+ case XML_top: maApiData.mnVerJustify = csstab::CellVertJustify2::TOP; break;
+ }
+
+ if (maModel.mnVerAlign == XML_distributed)
+ maApiData.mnVerJustifyMethod = csstab::CellJustifyMethod::DISTRIBUTE;
+
+ /* 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().scaleToMm100( 3.0 * maModel.mnIndent, UNIT_SPACE ); break;
+ case FILTER_BIFF: nIndent = getUnitConverter().scaleToMm100( 10.0 * maModel.mnIndent, UNIT_POINT ); break;
+ case FILTER_UNKNOWN: break;
+ }
+ if( (0 <= nIndent) && (nIndent <= SAL_MAX_INT16) )
+ maApiData.mnIndent = static_cast< sal_Int16 >( nIndent );
+
+ // complex text direction
+ switch( maModel.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 = maModel.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 (#i84960 automatic line break, if vertically justified/distributed)
+ maApiData.mbWrapText = maModel.mbWrapText || (maModel.mnVerAlign == XML_distributed) || (maModel.mnVerAlign == XML_justify);
+ maApiData.mbShrink = maModel.mbShrink;
+
+}
+
+void Alignment::writeToPropertyMap( PropertyMap& rPropMap ) const
+{
+ rPropMap[ PROP_HoriJustify ] <<= maApiData.meHorJustify;
+ rPropMap[ PROP_HoriJustifyMethod ] <<= maApiData.mnHorJustifyMethod;
+ rPropMap[ PROP_VertJustify ] <<= maApiData.mnVerJustify;
+ rPropMap[ PROP_VertJustifyMethod ] <<= maApiData.mnVerJustifyMethod;
+ rPropMap[ PROP_WritingMode ] <<= maApiData.mnWritingMode;
+ rPropMap[ PROP_RotateAngle ] <<= maApiData.mnRotation;
+ rPropMap[ PROP_Orientation ] <<= maApiData.meOrientation;
+ rPropMap[ PROP_ParaIndent ] <<= maApiData.mnIndent;
+ rPropMap[ PROP_IsTextWrapped ] <<= maApiData.mbWrapText;
+ rPropMap[ PROP_ShrinkToFit ] <<= maApiData.mbShrink;
+}
+
+// ============================================================================
+
+ProtectionModel::ProtectionModel() :
+ mbLocked( true ), // default in Excel and Calc
+ mbHidden( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+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);
+}
+
+// ============================================================================
+
+Protection::Protection( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+void Protection::importProtection( const AttributeList& rAttribs )
+{
+ maModel.mbLocked = rAttribs.getBool( XML_locked, true );
+ maModel.mbHidden = rAttribs.getBool( XML_hidden, false );
+}
+
+void Protection::setBinData( sal_uInt32 nFlags )
+{
+ maModel.mbLocked = getFlag( nFlags, OOBIN_XF_LOCKED );
+ maModel.mbHidden = getFlag( nFlags, OOBIN_XF_HIDDEN );
+}
+
+void Protection::setBiff2Data( sal_uInt8 nNumFmt )
+{
+ maModel.mbLocked = getFlag( nNumFmt, BIFF2_XF_LOCKED );
+ maModel.mbHidden = getFlag( nNumFmt, BIFF2_XF_HIDDEN );
+}
+
+void Protection::setBiff3Data( sal_uInt16 nProt )
+{
+ maModel.mbLocked = getFlag( nProt, BIFF_XF_LOCKED );
+ maModel.mbHidden = getFlag( nProt, BIFF_XF_HIDDEN );
+}
+
+void Protection::finalizeImport()
+{
+ maApiData.maCellProt.IsLocked = maModel.mbLocked;
+ maApiData.maCellProt.IsFormulaHidden = maModel.mbHidden;
+}
+
+void Protection::writeToPropertyMap( PropertyMap& rPropMap ) const
+{
+ rPropMap[ PROP_CellProtection ] <<= maApiData.maCellProt;
+}
+
+// ============================================================================
+
+namespace {
+
+bool lcl_isBorder(const ::com::sun::star::table::BorderLine& rBorder)
+{
+ return (rBorder.InnerLineWidth > 0) || (rBorder.OuterLineWidth > 0);
+}
+
+}
+
+BorderLineModel::BorderLineModel( bool bDxf ) :
+ mnStyle( XML_none ),
+ mbUsed( !bDxf )
+{
+ maColor.setIndexed( OOX_COLOR_WINDOWTEXT );
+}
+
+void BorderLineModel::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 BorderLineModel::setBiffData( sal_uInt8 nLineStyle, sal_uInt16 nLineColor )
+{
+ maColor.setIndexed( nLineColor );
+ setBiffStyle( nLineStyle );
+}
+
+// ----------------------------------------------------------------------------
+
+BorderModel::BorderModel( bool bDxf ) :
+ maLeft( bDxf ),
+ maRight( bDxf ),
+ maTop( bDxf ),
+ maBottom( bDxf ),
+ maDiagonal( bDxf ),
+ mbDiagTLtoBR( false ),
+ mbDiagBLtoTR( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ApiBorderData::ApiBorderData() :
+ mbBorderUsed( false ),
+ mbDiagUsed( false )
+{
+}
+
+bool ApiBorderData::hasAnyOuterBorder() const
+{
+ return
+ ( ( lcl_isBorder( maTop ) && maTop.OuterLineWidth > 0 ) ) ||
+ ( ( lcl_isBorder( maBottom ) && maBottom.OuterLineWidth > 0 ) ) ||
+ ( ( lcl_isBorder( maLeft ) && maLeft.OuterLineWidth > 0 ) ) ||
+ ( ( lcl_isBorder( maRight ) && maRight.OuterLineWidth > 0 ) );
+}
+
+namespace {
+
+bool operator==( const BorderLine& rLeft, const BorderLine& rRight )
+{
+ return
+ (rLeft.Color == rRight.Color) &&
+ (rLeft.InnerLineWidth == rRight.InnerLineWidth) &&
+ (rLeft.OuterLineWidth == rRight.OuterLineWidth) &&
+ (rLeft.LineDistance == rRight.LineDistance);
+}
+
+bool operator==( const TableBorder& rLeft, const TableBorder& rRight )
+{
+ return
+ (rLeft.TopLine == rRight.TopLine) &&
+ (rLeft.IsTopLineValid == rRight.IsTopLineValid) &&
+ (rLeft.BottomLine == rRight.BottomLine) &&
+ (rLeft.IsBottomLineValid == rRight.IsBottomLineValid) &&
+ (rLeft.LeftLine == rRight.LeftLine) &&
+ (rLeft.IsLeftLineValid == rRight.IsLeftLineValid) &&
+ (rLeft.RightLine == rRight.RightLine) &&
+ (rLeft.IsRightLineValid == rRight.IsRightLineValid) &&
+ (rLeft.HorizontalLine == rRight.HorizontalLine) &&
+ (rLeft.IsHorizontalLineValid == rRight.IsHorizontalLineValid) &&
+ (rLeft.VerticalLine == rRight.VerticalLine) &&
+ (rLeft.IsVerticalLineValid == rRight.IsVerticalLineValid) &&
+ (rLeft.Distance == rRight.Distance) &&
+ (rLeft.IsDistanceValid == rRight.IsDistanceValid);
+}
+
+} // namespace
+
+bool operator==( const ApiBorderData& rLeft, const ApiBorderData& rRight )
+{
+ return
+ (rLeft.maLeft == rRight.maLeft) &&
+ (rLeft.maRight == rRight.maRight) &&
+ (rLeft.maTop == rRight.maTop) &&
+ (rLeft.maBottom == rRight.maBottom) &&
+ (rLeft.maTLtoBR == rRight.maTLtoBR) &&
+ (rLeft.maBLtoTR == rRight.maBLtoTR) &&
+ (rLeft.mbBorderUsed == rRight.mbBorderUsed) &&
+ (rLeft.mbDiagUsed == rRight.mbDiagUsed);
+}
+
+// ============================================================================
+
+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 BorderLine2* lclGetThickerLine( const BorderLine2& rBorderLine1, sal_Bool bValid1, const BorderLine2& 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 ),
+ maModel( bDxf ),
+ mbDxf( bDxf )
+{
+}
+
+void Border::importBorder( const AttributeList& rAttribs )
+{
+ maModel.mbDiagTLtoBR = rAttribs.getBool( XML_diagonalDown, false );
+ maModel.mbDiagBLtoTR = rAttribs.getBool( XML_diagonalUp, false );
+}
+
+void Border::importStyle( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( BorderLineModel* pBorderLine = getBorderLine( nElement ) )
+ {
+ pBorderLine->mnStyle = rAttribs.getToken( XML_style, XML_none );
+ pBorderLine->mbUsed = true;
+ }
+}
+
+void Border::importColor( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( BorderLineModel* pBorderLine = getBorderLine( nElement ) )
+ pBorderLine->maColor.importColor( rAttribs );
+}
+
+void Border::importBorder( RecordInputStream& rStrm )
+{
+ sal_uInt8 nFlags = rStrm.readuInt8();
+ maModel.mbDiagTLtoBR = getFlag( nFlags, OOBIN_BORDER_DIAG_TLBR );
+ maModel.mbDiagBLtoTR = getFlag( nFlags, OOBIN_BORDER_DIAG_BLTR );
+ maModel.maTop.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maModel.maTop.maColor;
+ maModel.maBottom.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maModel.maBottom.maColor;
+ maModel.maLeft.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maModel.maLeft.maColor;
+ maModel.maRight.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maModel.maRight.maColor;
+ maModel.maDiagonal.setBiffStyle( rStrm.readuInt16() );
+ rStrm >> maModel.maDiagonal.maColor;
+}
+
+void Border::importDxfBorder( sal_Int32 nElement, RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Border::importDxfBorder - missing conditional formatting flag" );
+ if( BorderLineModel* 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" );
+ maModel.maLeft.setBiffData( getFlagValue( nFlags, BIFF2_XF_LEFTLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK );
+ maModel.maRight.setBiffData( getFlagValue( nFlags, BIFF2_XF_RIGHTLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK );
+ maModel.maTop.setBiffData( getFlagValue( nFlags, BIFF2_XF_TOPLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK );
+ maModel.maBottom.setBiffData( getFlagValue( nFlags, BIFF2_XF_BOTTOMLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK );
+ maModel.maDiagonal.mbUsed = false;
+}
+
+void Border::setBiff3Data( sal_uInt32 nBorder )
+{
+ OSL_ENSURE( !mbDxf, "Border::setBiff3Data - unexpected conditional formatting flag" );
+ maModel.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder, 8, 3 ), extractValue< sal_uInt16 >( nBorder, 11, 5 ) );
+ maModel.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder, 24, 3 ), extractValue< sal_uInt16 >( nBorder, 27, 5 ) );
+ maModel.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder, 0, 3 ), extractValue< sal_uInt16 >( nBorder, 3, 5 ) );
+ maModel.maBottom.setBiffData( extractValue< sal_uInt8 >( nBorder, 16, 3 ), extractValue< sal_uInt16 >( nBorder, 19, 5 ) );
+ maModel.maDiagonal.mbUsed = false;
+}
+
+void Border::setBiff5Data( sal_uInt32 nBorder, sal_uInt32 nArea )
+{
+ OSL_ENSURE( !mbDxf, "Border::setBiff5Data - unexpected conditional formatting flag" );
+ maModel.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder, 3, 3 ), extractValue< sal_uInt16 >( nBorder, 16, 7 ) );
+ maModel.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder, 6, 3 ), extractValue< sal_uInt16 >( nBorder, 23, 7 ) );
+ maModel.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder, 0, 3 ), extractValue< sal_uInt16 >( nBorder, 9, 7 ) );
+ maModel.maBottom.setBiffData( extractValue< sal_uInt8 >( nArea, 22, 3 ), extractValue< sal_uInt16 >( nArea, 25, 7 ) );
+ maModel.maDiagonal.mbUsed = false;
+}
+
+void Border::setBiff8Data( sal_uInt32 nBorder1, sal_uInt32 nBorder2 )
+{
+ OSL_ENSURE( !mbDxf, "Border::setBiff8Data - unexpected conditional formatting flag" );
+ maModel.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder1, 0, 4 ), extractValue< sal_uInt16 >( nBorder1, 16, 7 ) );
+ maModel.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder1, 4, 4 ), extractValue< sal_uInt16 >( nBorder1, 23, 7 ) );
+ maModel.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder1, 8, 4 ), extractValue< sal_uInt16 >( nBorder2, 0, 7 ) );
+ maModel.maBottom.setBiffData( extractValue< sal_uInt8 >( nBorder1, 12, 4 ), extractValue< sal_uInt16 >( nBorder2, 7, 7 ) );
+ maModel.mbDiagTLtoBR = getFlag( nBorder1, BIFF_XF_DIAG_TLBR );
+ maModel.mbDiagBLtoTR = getFlag( nBorder1, BIFF_XF_DIAG_BLTR );
+ if( maModel.mbDiagTLtoBR || maModel.mbDiagBLtoTR )
+ maModel.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 );
+ maModel.maLeft.setBiffData( extractValue< sal_uInt8 >( nStyle, 0, 4 ), extractValue< sal_uInt16 >( nColor, 0, 7 ) );
+ maModel.maRight.setBiffData( extractValue< sal_uInt8 >( nStyle, 4, 4 ), extractValue< sal_uInt16 >( nColor, 7, 7 ) );
+ maModel.maTop.setBiffData( extractValue< sal_uInt8 >( nStyle, 8, 4 ), extractValue< sal_uInt16 >( nColor, 16, 7 ) );
+ maModel.maBottom.setBiffData( extractValue< sal_uInt8 >( nStyle, 12, 4 ), extractValue< sal_uInt16 >( nColor, 23, 7 ) );
+ maModel.maLeft.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_LEFT );
+ maModel.maRight.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_RIGHT );
+ maModel.maTop.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_TOP );
+ maModel.maBottom.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_BOTTOM );
+}
+
+void Border::finalizeImport()
+{
+ maApiData.mbBorderUsed = maModel.maLeft.mbUsed || maModel.maRight.mbUsed || maModel.maTop.mbUsed || maModel.maBottom.mbUsed;
+ maApiData.mbDiagUsed = maModel.maDiagonal.mbUsed;
+
+ convertBorderLine( maApiData.maLeft, maModel.maLeft );
+ convertBorderLine( maApiData.maRight, maModel.maRight );
+ convertBorderLine( maApiData.maTop, maModel.maTop );
+ convertBorderLine( maApiData.maBottom, maModel.maBottom );
+
+ if( maModel.mbDiagTLtoBR )
+ convertBorderLine( maApiData.maTLtoBR, maModel.maDiagonal );
+ if( maModel.mbDiagBLtoTR )
+ convertBorderLine( maApiData.maBLtoTR, maModel.maDiagonal );
+}
+
+void Border::writeToPropertyMap( PropertyMap& rPropMap ) const
+{
+ if( maApiData.mbBorderUsed )
+ {
+ rPropMap[ PROP_LeftBorder ] <<= maApiData.maLeft;
+ rPropMap[ PROP_RightBorder ] <<= maApiData.maRight;
+ rPropMap[ PROP_TopBorder ] <<= maApiData.maTop;
+ rPropMap[ PROP_BottomBorder ] <<= maApiData.maBottom;
+ }
+ if( maApiData.mbDiagUsed )
+ {
+ rPropMap[ PROP_DiagonalTLBR ] <<= maApiData.maTLtoBR;
+ rPropMap[ PROP_DiagonalBLTR ] <<= maApiData.maBLtoTR;
+ }
+}
+
+bool Border::hasBorder() const
+{
+ if (lcl_isBorder(maApiData.maBottom))
+ return true;
+
+ if (lcl_isBorder(maApiData.maTop))
+ return true;
+
+ if (lcl_isBorder(maApiData.maLeft))
+ return true;
+
+ if (lcl_isBorder(maApiData.maRight))
+ return true;
+
+ return false;
+}
+
+BorderLineModel* Border::getBorderLine( sal_Int32 nElement )
+{
+ switch( nElement )
+ {
+ case XLS_TOKEN( left ): return &maModel.maLeft;
+ case XLS_TOKEN( right ): return &maModel.maRight;
+ case XLS_TOKEN( top ): return &maModel.maTop;
+ case XLS_TOKEN( bottom ): return &maModel.maBottom;
+ case XLS_TOKEN( diagonal ): return &maModel.maDiagonal;
+ }
+ return 0;
+}
+
+bool Border::convertBorderLine( BorderLine2& rBorderLine, const BorderLineModel& rModel )
+{
+ rBorderLine.Color = rModel.maColor.getColor( getBaseFilter().getGraphicHelper(), API_RGB_BLACK );
+ switch( rModel.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 );
+ rBorderLine.LineStyle = API_LINE_DASHED;
+ break;
+ }
+ case XML_dotted:
+ {
+ lclSetBorderLineWidth( rBorderLine, API_LINE_THIN );
+ rBorderLine.LineStyle = API_LINE_DOTTED;
+ 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 rModel.mbUsed;
+}
+
+
+// ============================================================================
+
+PatternFillModel::PatternFillModel( bool bDxf ) :
+ mnPattern( XML_none ),
+ mbPattColorUsed( !bDxf ),
+ mbFillColorUsed( !bDxf ),
+ mbPatternUsed( !bDxf )
+{
+ maPatternColor.setIndexed( OOX_COLOR_WINDOWTEXT );
+ maFillColor.setIndexed( OOX_COLOR_WINDOWBACK );
+}
+
+void PatternFillModel::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 PatternFillModel::setBiffData( sal_uInt16 nPatternColor, sal_uInt16 nFillColor, sal_uInt8 nPattern )
+{
+ maPatternColor.setIndexed( nPatternColor );
+ maFillColor.setIndexed( nFillColor );
+ // patterns equal in BIFF and OOBIN
+ setBinPattern( nPattern );
+}
+
+// ----------------------------------------------------------------------------
+
+GradientFillModel::GradientFillModel() :
+ mnType( XML_linear ),
+ mfAngle( 0.0 ),
+ mfLeft( 0.0 ),
+ mfRight( 0.0 ),
+ mfTop( 0.0 ),
+ mfBottom( 0.0 )
+{
+}
+
+void GradientFillModel::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 GradientFillModel::readGradientStop( RecordInputStream& rStrm, bool bDxf )
+{
+ Color aColor;
+ double fPosition;
+ if( bDxf )
+ {
+ rStrm.skip( 2 );
+ rStrm >> fPosition >> aColor;
+ }
+ else
+ {
+ rStrm >> aColor >> fPosition;
+ }
+ if( !rStrm.isEof() && (fPosition >= 0.0) )
+ maColors[ fPosition ] = aColor;
+}
+
+// ----------------------------------------------------------------------------
+
+ApiSolidFillData::ApiSolidFillData() :
+ mnColor( API_RGB_TRANSPARENT ),
+ mbTransparent( true ),
+ mbUsed( false )
+{
+}
+
+bool operator==( const ApiSolidFillData& rLeft, const ApiSolidFillData& rRight )
+{
+ return
+ (rLeft.mnColor == rRight.mnColor) &&
+ (rLeft.mbTransparent == rRight.mbTransparent) &&
+ (rLeft.mbUsed == rRight.mbUsed);
+}
+
+// ============================================================================
+
+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 )
+{
+}
+
+void Fill::importPatternFill( const AttributeList& rAttribs )
+{
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->mnPattern = rAttribs.getToken( XML_patternType, XML_none );
+ if( mbDxf )
+ mxPatternModel->mbPatternUsed = rAttribs.hasAttribute( XML_patternType );
+}
+
+void Fill::importFgColor( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( mxPatternModel.get(), "Fill::importFgColor - missing pattern data" );
+ if( mxPatternModel.get() )
+ {
+ mxPatternModel->maPatternColor.importColor( rAttribs );
+ mxPatternModel->mbPattColorUsed = true;
+ }
+}
+
+void Fill::importBgColor( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( mxPatternModel.get(), "Fill::importBgColor - missing pattern data" );
+ if( mxPatternModel.get() )
+ {
+ mxPatternModel->maFillColor.importColor( rAttribs );
+ mxPatternModel->mbFillColorUsed = true;
+ }
+}
+
+void Fill::importGradientFill( const AttributeList& rAttribs )
+{
+ mxGradientModel.reset( new GradientFillModel );
+ mxGradientModel->mnType = rAttribs.getToken( XML_type, XML_linear );
+ mxGradientModel->mfAngle = rAttribs.getDouble( XML_degree, 0.0 );
+ mxGradientModel->mfLeft = rAttribs.getDouble( XML_left, 0.0 );
+ mxGradientModel->mfRight = rAttribs.getDouble( XML_right, 0.0 );
+ mxGradientModel->mfTop = rAttribs.getDouble( XML_top, 0.0 );
+ mxGradientModel->mfBottom = rAttribs.getDouble( XML_bottom, 0.0 );
+}
+
+void Fill::importColor( const AttributeList& rAttribs, double fPosition )
+{
+ OSL_ENSURE( mxGradientModel.get(), "Fill::importColor - missing gradient data" );
+ if( mxGradientModel.get() && (fPosition >= 0.0) )
+ mxGradientModel->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 )
+ {
+ mxGradientModel.reset( new GradientFillModel );
+ sal_Int32 nStopCount;
+ rStrm.skip( 16 );
+ mxGradientModel->readGradient( rStrm );
+ rStrm >> nStopCount;
+ for( sal_Int32 nStop = 0; (nStop < nStopCount) && !rStrm.isEof(); ++nStop )
+ mxGradientModel->readGradientStop( rStrm, false );
+ }
+ else
+ {
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->setBinPattern( nPattern );
+ rStrm >> mxPatternModel->maPatternColor >> mxPatternModel->maFillColor;
+ }
+}
+
+void Fill::importDxfPattern( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfPattern - missing conditional formatting flag" );
+ if( !mxPatternModel )
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->setBinPattern( rStrm.readuInt8() );
+ mxPatternModel->mbPatternUsed = true;
+}
+
+void Fill::importDxfFgColor( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfFgColor - missing conditional formatting flag" );
+ if( !mxPatternModel )
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->maPatternColor.importColor( rStrm );
+ mxPatternModel->mbPattColorUsed = true;
+}
+
+void Fill::importDxfBgColor( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfBgColor - missing conditional formatting flag" );
+ if( !mxPatternModel )
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->maFillColor.importColor( rStrm );
+ mxPatternModel->mbFillColorUsed = true;
+}
+
+void Fill::importDxfGradient( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfGradient - missing conditional formatting flag" );
+ if( !mxGradientModel )
+ mxGradientModel.reset( new GradientFillModel );
+ mxGradientModel->readGradient( rStrm );
+}
+
+void Fill::importDxfStop( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( mbDxf, "Fill::importDxfStop - missing conditional formatting flag" );
+ if( !mxGradientModel )
+ mxGradientModel.reset( new GradientFillModel );
+ mxGradientModel->readGradientStop( rStrm, true );
+}
+
+void Fill::setBiff2Data( sal_uInt8 nFlags )
+{
+ OSL_ENSURE( !mbDxf, "Fill::setBiff2Data - unexpected conditional formatting flag" );
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->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" );
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->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" );
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->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" );
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ mxPatternModel->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" );
+ mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+ sal_uInt32 nFillData;
+ rStrm >> nFillData;
+ mxPatternModel->setBiffData(
+ extractValue< sal_uInt16 >( nFillData, 16, 7 ),
+ extractValue< sal_uInt16 >( nFillData, 23, 7 ),
+ extractValue< sal_uInt8 >( nFillData, 10, 6 ) );
+ mxPatternModel->mbPattColorUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_PATTCOLOR );
+ mxPatternModel->mbFillColorUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_FILLCOLOR );
+ mxPatternModel->mbPatternUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_PATTERN );
+}
+
+void Fill::finalizeImport()
+{
+ const GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
+
+ if( mxPatternModel.get() )
+ {
+ // finalize the OOX data struct
+ PatternFillModel& rModel = *mxPatternModel;
+ if( mbDxf )
+ {
+ if( rModel.mbFillColorUsed && (!rModel.mbPatternUsed || (rModel.mnPattern == XML_solid)) )
+ {
+ rModel.maPatternColor = rModel.maFillColor;
+ rModel.mnPattern = XML_solid;
+ rModel.mbPattColorUsed = rModel.mbPatternUsed = true;
+ }
+ else if( !rModel.mbFillColorUsed && rModel.mbPatternUsed && (rModel.mnPattern == XML_solid) )
+ {
+ rModel.mbPatternUsed = false;
+ }
+ }
+
+ // convert to API fill settings
+ maApiData.mbUsed = rModel.mbPatternUsed;
+ if( rModel.mnPattern == XML_none )
+ {
+ maApiData.mnColor = API_RGB_TRANSPARENT;
+ maApiData.mbTransparent = true;
+ }
+ else
+ {
+ sal_Int32 nAlpha = 0x80;
+ switch( rModel.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;
+ }
+
+ sal_Int32 nWinTextColor = rGraphicHelper.getSystemColor( XML_windowText );
+ sal_Int32 nWinColor = rGraphicHelper.getSystemColor( XML_window );
+
+ if( !rModel.mbPattColorUsed )
+ rModel.maPatternColor.setAuto();
+ sal_Int32 nPattColor = rModel.maPatternColor.getColor( rGraphicHelper, nWinTextColor );
+
+ if( !rModel.mbFillColorUsed )
+ rModel.maFillColor.setAuto();
+ sal_Int32 nFillColor = rModel.maFillColor.getColor( rGraphicHelper, nWinColor );
+
+ maApiData.mnColor = lclGetMixedColor( nPattColor, nFillColor, nAlpha );
+ maApiData.mbTransparent = false;
+ }
+ }
+ else if( mxGradientModel.get() && !mxGradientModel->maColors.empty() )
+ {
+ GradientFillModel& rModel = *mxGradientModel;
+ maApiData.mbUsed = true; // no support for differential attributes
+ GradientFillModel::ColorMap::const_iterator aIt = rModel.maColors.begin();
+ OSL_ENSURE( !aIt->second.isAuto(), "Fill::finalizeImport - automatic gradient color" );
+ maApiData.mnColor = aIt->second.getColor( rGraphicHelper, API_RGB_WHITE );
+ if( ++aIt != rModel.maColors.end() )
+ {
+ OSL_ENSURE( !aIt->second.isAuto(), "Fill::finalizeImport - automatic gradient color" );
+ sal_Int32 nEndColor = aIt->second.getColor( rGraphicHelper, API_RGB_WHITE );
+ maApiData.mnColor = lclGetMixedColor( maApiData.mnColor, nEndColor, 0x40 );
+ maApiData.mbTransparent = false;
+ }
+ }
+}
+
+void Fill::writeToPropertyMap( PropertyMap& rPropMap ) const
+{
+ if( maApiData.mbUsed )
+ {
+ rPropMap[ PROP_CellBackColor ] <<= maApiData.mnColor;
+ rPropMap[ PROP_IsCellBackgroundTransparent ] <<= maApiData.mbTransparent;
+ }
+}
+
+// ============================================================================
+
+XfModel::XfModel() :
+ 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 ),
+ meRotationRef( ::com::sun::star::table::CellVertJustify_STANDARD )
+{
+}
+
+void Xf::setAllUsedFlags( bool bUsed )
+{
+ maModel.mbAlignUsed = maModel.mbProtUsed = maModel.mbFontUsed =
+ maModel.mbNumFmtUsed = maModel.mbBorderUsed = maModel.mbAreaUsed = bUsed;
+}
+
+void Xf::importXf( const AttributeList& rAttribs, bool bCellXf )
+{
+ maModel.mbCellXf = bCellXf;
+ maModel.mnStyleXfId = rAttribs.getInteger( XML_xfId, -1 );
+ maModel.mnFontId = rAttribs.getInteger( XML_fontId, -1 );
+ maModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, -1 );
+ maModel.mnBorderId = rAttribs.getInteger( XML_borderId, -1 );
+ maModel.mnFillId = rAttribs.getInteger( XML_fillId, -1 );
+
+ /* Default value of the apply*** attributes is dependent on context:
+ true in cellStyleXfs element, false in cellXfs element... */
+ maModel.mbAlignUsed = rAttribs.getBool( XML_applyAlignment, !maModel.mbCellXf );
+ maModel.mbProtUsed = rAttribs.getBool( XML_applyProtection, !maModel.mbCellXf );
+ maModel.mbFontUsed = rAttribs.getBool( XML_applyFont, !maModel.mbCellXf );
+ maModel.mbNumFmtUsed = rAttribs.getBool( XML_applyNumberFormat, !maModel.mbCellXf );
+ maModel.mbBorderUsed = rAttribs.getBool( XML_applyBorder, !maModel.mbCellXf );
+ maModel.mbAreaUsed = rAttribs.getBool( XML_applyFill, !maModel.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 )
+{
+ maModel.mbCellXf = bCellXf;
+ maModel.mnStyleXfId = rStrm.readuInt16();
+ maModel.mnNumFmtId = rStrm.readuInt16();
+ maModel.mnFontId = rStrm.readuInt16();
+ maModel.mnFillId = rStrm.readuInt16();
+ maModel.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();
+ maModel.mbFontUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_FONT_USED );
+ maModel.mbNumFmtUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_NUMFMT_USED );
+ maModel.mbAlignUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_ALIGN_USED );
+ maModel.mbProtUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_PROT_USED );
+ maModel.mbBorderUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_BORDER_USED );
+ maModel.mbAreaUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_AREA_USED );
+}
+
+void Xf::importXf( BiffInputStream& rStrm )
+{
+ BorderRef xBorder = getStyles().createBorder( &maModel.mnBorderId );
+ FillRef xFill = getStyles().createFill( &maModel.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 );
+ maModel.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maModel.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
+ maModel.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE ); // new in BIFF3
+ maModel.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 );
+ maModel.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maModel.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
+ maModel.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE );
+ maModel.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 );
+ maModel.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maModel.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
+ maModel.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE );
+ maModel.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 );
+ maModel.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maModel.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
+ maModel.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE );
+ maModel.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 );
+ maModel.mnFontId = static_cast< sal_Int32 >( nFontId );
+ maModel.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId );
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+}
+
+void Xf::finalizeImport()
+{
+ StylesBuffer& rStyles = getStyles();
+
+ // alignment and protection
+ maAlignment.finalizeImport();
+ maProtection.finalizeImport();
+
+ /* Enables the used flags, if the formatting attributes differ from the
+ style XF. In cell XFs Excel uses the cell attributes, if they differ
+ from the parent style XF (even if the used flag is switched off).
+ #109899# ...or if the respective flag is not set in parent style XF.
+ */
+ const Xf* pStyleXf = isCellXf() ? rStyles.getStyleXf( maModel.mnStyleXfId ).get() : 0;
+ if( pStyleXf )
+ {
+ const XfModel& rStyleData = pStyleXf->maModel;
+ if( !maModel.mbFontUsed )
+ maModel.mbFontUsed = !rStyleData.mbFontUsed || (maModel.mnFontId != rStyleData.mnFontId);
+ if( !maModel.mbNumFmtUsed )
+ maModel.mbNumFmtUsed = !rStyleData.mbNumFmtUsed || (maModel.mnNumFmtId != rStyleData.mnNumFmtId);
+ if( !maModel.mbAlignUsed )
+ maModel.mbAlignUsed = !rStyleData.mbAlignUsed || !(maAlignment.getApiData() == pStyleXf->maAlignment.getApiData());
+ if( !maModel.mbProtUsed )
+ maModel.mbProtUsed = !rStyleData.mbProtUsed || !(maProtection.getApiData() == pStyleXf->maProtection.getApiData());
+ if( !maModel.mbBorderUsed )
+ maModel.mbBorderUsed = !rStyleData.mbBorderUsed || !rStyles.equalBorders( maModel.mnBorderId, rStyleData.mnBorderId );
+ if( !maModel.mbAreaUsed )
+ maModel.mbAreaUsed = !rStyleData.mbAreaUsed || !rStyles.equalFills( maModel.mnFillId, rStyleData.mnFillId );
+ }
+
+ /* #i38709# Decide which rotation reference mode to use. If any outer
+ border line of the cell is set (either explicitly or via cell style),
+ and the cell contents are rotated, set rotation reference to bottom of
+ cell. This causes the borders to be painted rotated with the text. */
+ if( const Alignment* pAlignment = maModel.mbAlignUsed ? &maAlignment : (pStyleXf ? &pStyleXf->maAlignment : 0) )
+ {
+ sal_Int32 nBorderId = maModel.mbBorderUsed ? maModel.mnBorderId : (pStyleXf ? pStyleXf->maModel.mnBorderId : -1);
+ if( const Border* pBorder = rStyles.getBorder( nBorderId ).get() )
+ if( (pAlignment->getApiData().mnRotation != 0) && pBorder->getApiData().hasAnyOuterBorder() )
+ meRotationRef = ::com::sun::star::table::CellVertJustify_BOTTOM;
+ }
+}
+
+FontRef Xf::getFont() const
+{
+ return getStyles().getFont( maModel.mnFontId );
+}
+
+bool Xf::hasAnyUsedFlags() const
+{
+ return
+ maModel.mbAlignUsed || maModel.mbProtUsed || maModel.mbFontUsed ||
+ maModel.mbNumFmtUsed || maModel.mbBorderUsed || maModel.mbAreaUsed;
+}
+
+void Xf::writeToPropertyMap( PropertyMap& rPropMap ) const
+{
+ StylesBuffer& rStyles = getStyles();
+
+ // create and set cell style
+ if( isCellXf() )
+ rPropMap[ PROP_CellStyle ] <<= rStyles.createCellStyle( maModel.mnStyleXfId );
+
+ if( maModel.mbFontUsed )
+ rStyles.writeFontToPropertyMap( rPropMap, maModel.mnFontId );
+ if( maModel.mbNumFmtUsed )
+ rStyles.writeNumFmtToPropertyMap( rPropMap, maModel.mnNumFmtId );
+ if( maModel.mbAlignUsed )
+ maAlignment.writeToPropertyMap( rPropMap );
+ if( maModel.mbProtUsed )
+ maProtection.writeToPropertyMap( rPropMap );
+ if( maModel.mbBorderUsed )
+ rStyles.writeBorderToPropertyMap( rPropMap, maModel.mnBorderId );
+ if( maModel.mbAreaUsed )
+ rStyles.writeFillToPropertyMap( rPropMap, maModel.mnFillId );
+ if( maModel.mbAlignUsed || maModel.mbBorderUsed )
+ rPropMap[ PROP_RotateReference ] <<= meRotationRef;
+
+ ::com::sun::star::table::CellVertJustify eRotRef = ::com::sun::star::table::CellVertJustify_STANDARD;
+ if (maModel.mbBorderUsed && rStyles.hasBorder(maModel.mnBorderId) && maAlignment.getApiData().mnRotation)
+ eRotRef = ::com::sun::star::table::CellVertJustify_BOTTOM;
+ rPropMap[ PROP_RotateReference ] <<= eRotRef;
+}
+
+void Xf::writeToPropertySet( PropertySet& rPropSet ) const
+{
+ PropertyMap aPropMap;
+ writeToPropertyMap( aPropMap );
+ rPropSet.setProperties( aPropMap );
+}
+
+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 "isCellXf() == getFlag(...)" construct evaluates to true in both
+ mentioned cases: cell XF and set bit; or style XF and cleared bit.
+ */
+ maModel.mbFontUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_FONT_USED );
+ maModel.mbNumFmtUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_NUMFMT_USED );
+ maModel.mbAlignUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_ALIGN_USED );
+ maModel.mbProtUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_PROT_USED );
+ maModel.mbBorderUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_BORDER_USED );
+ maModel.mbAreaUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_AREA_USED );
+}
+
+// ============================================================================
+
+Dxf::Dxf( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+FontRef Dxf::createFont( bool bAlwaysNew )
+{
+ if( bAlwaysNew || !mxFont )
+ mxFont.reset( new Font( *this, true ) );
+ return mxFont;
+}
+
+BorderRef Dxf::createBorder( bool bAlwaysNew )
+{
+ if( bAlwaysNew || !mxBorder )
+ mxBorder.reset( new Border( *this, true ) );
+ return mxBorder;
+}
+
+FillRef Dxf::createFill( bool bAlwaysNew )
+{
+ if( bAlwaysNew || !mxFill )
+ mxFill.reset( new Fill( *this, true ) );
+ return mxFill;
+}
+
+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 );
+}
+
+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.isEof() && (nRec < nRecCount); ++nRec )
+ {
+ sal_uInt16 nSubRecId, nSubRecSize;
+ sal_Int64 nRecEnd = rStrm.tell();
+ rStrm >> nSubRecId >> nSubRecSize;
+ nRecEnd += nSubRecSize;
+ switch( nSubRecId )
+ {
+ case OOBIN_DXF_FILL_PATTERN: createFill( false )->importDxfPattern( rStrm ); break;
+ case OOBIN_DXF_FILL_FGCOLOR: createFill( false )->importDxfFgColor( rStrm ); break;
+ case OOBIN_DXF_FILL_BGCOLOR: createFill( false )->importDxfBgColor( rStrm ); break;
+ case OOBIN_DXF_FILL_GRADIENT: createFill( false )->importDxfGradient( rStrm ); break;
+ case OOBIN_DXF_FILL_STOP: createFill( false )->importDxfStop( rStrm ); break;
+ case OOBIN_DXF_FONT_COLOR: createFont( false )->importDxfColor( rStrm ); break;
+ case OOBIN_DXF_BORDER_TOP: createBorder( false )->importDxfBorder( XLS_TOKEN( top ), rStrm ); break;
+ case OOBIN_DXF_BORDER_BOTTOM: createBorder( false )->importDxfBorder( XLS_TOKEN( bottom ), rStrm ); break;
+ case OOBIN_DXF_BORDER_LEFT: createBorder( false )->importDxfBorder( XLS_TOKEN( left ), rStrm ); break;
+ case OOBIN_DXF_BORDER_RIGHT: createBorder( false )->importDxfBorder( XLS_TOKEN( right ), rStrm ); break;
+ case OOBIN_DXF_FONT_NAME: createFont( false )->importDxfName( rStrm ); break;
+ case OOBIN_DXF_FONT_WEIGHT: createFont( false )->importDxfWeight( rStrm ); break;
+ case OOBIN_DXF_FONT_UNDERLINE: createFont( false )->importDxfUnderline( rStrm ); break;
+ case OOBIN_DXF_FONT_ESCAPEMENT: createFont( false )->importDxfEscapement( rStrm ); break;
+ case OOBIN_DXF_FONT_ITALIC: createFont( false )->importDxfFlag( XML_i, rStrm ); break;
+ case OOBIN_DXF_FONT_STRIKE: createFont( false )->importDxfFlag( XML_strike, rStrm ); break;
+ case OOBIN_DXF_FONT_OUTLINE: createFont( false )->importDxfFlag( XML_outline, rStrm ); break;
+ case OOBIN_DXF_FONT_SHADOW: createFont( false )->importDxfFlag( XML_shadow, rStrm ); break;
+ case OOBIN_DXF_FONT_HEIGHT: createFont( false )->importDxfHeight( rStrm ); break;
+ case OOBIN_DXF_FONT_SCHEME: createFont( false )->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.isEof() && (rStrm.getRemaining() == 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()->importCfRule( rStrm );
+ if( getFlag( nFlags, BIFF_CFRULE_ALIGNBLOCK ) )
+ rStrm.skip( 8 );
+ if( getFlag( nFlags, BIFF_CFRULE_BORDERBLOCK ) )
+ createBorder()->importCfRule( rStrm, nFlags );
+ if( getFlag( nFlags, BIFF_CFRULE_FILLBLOCK ) )
+ createFill()->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();
+}
+
+void Dxf::writeToPropertyMap( PropertyMap& rPropMap ) const
+{
+ if( mxFont.get() )
+ mxFont->writeToPropertyMap( rPropMap, FONT_PROPTYPE_CELL );
+ if( mxNumFmt.get() )
+ mxNumFmt->writeToPropertyMap( rPropMap );
+ if( mxAlignment.get() )
+ mxAlignment->writeToPropertyMap( rPropMap );
+ if( mxProtection.get() )
+ mxProtection->writeToPropertyMap( rPropMap );
+ if( mxBorder.get() )
+ mxBorder->writeToPropertyMap( rPropMap );
+ if( mxFill.get() )
+ mxFill->writeToPropertyMap( rPropMap );
+}
+
+void Dxf::writeToPropertySet( PropertySet& rPropSet ) const
+{
+ PropertyMap aPropMap;
+ writeToPropertyMap( aPropMap );
+ rPropSet.setProperties( aPropMap );
+}
+
+// ============================================================================
+
+namespace {
+
+const sal_Char* const spcLegacyStyleNamePrefix = "Excel_BuiltIn_";
+const sal_Char* const sppcLegacyStyleNames[] =
+{
+ "Normal",
+ "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[] =
+{
+ "Normal",
+ "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 ) );
+
+OUString lclGetBuiltinStyleName( sal_Int32 nBuiltinId, const OUString& rName, sal_Int32 nLevel = 0 )
+{
+ OSL_ENSURE( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount), "lclGetBuiltinStyleName - unknown built-in style" );
+ OUStringBuffer aStyleName;
+ 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 );
+ return aStyleName.makeStringAndClear();
+}
+
+OUString lclGetBuiltInStyleName( const OUString& rName )
+{
+ OUStringBuffer aStyleName;
+ aStyleName.appendAscii( spcStyleNamePrefix ).append( rName );
+ return aStyleName.makeStringAndClear();
+}
+
+bool lclIsBuiltinStyleName( const OUString& rStyleName, sal_Int32* pnBuiltinId, sal_Int32* pnNextChar )
+{
+ // try the other built-in 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 )
+ {
+ aShortName = OUString::createFromAscii( sppcStyleNames[ nId ] );
+ if( rStyleName.matchIgnoreAsciiCase( aShortName, nPrefixLen ) &&
+ (nNextChar < nPrefixLen + aShortName.getLength()) )
+ {
+ nFoundId = nId;
+ nNextChar = nPrefixLen + aShortName.getLength();
+ }
+ }
+ }
+
+ 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
+
+// ----------------------------------------------------------------------------
+
+CellStyleModel::CellStyleModel() :
+ mnXfId( -1 ),
+ mnBuiltinId( -1 ),
+ mnLevel( 0 ),
+ mbBuiltin( false ),
+ mbCustom( false ),
+ mbHidden( false )
+{
+}
+
+bool CellStyleModel::isBuiltin() const
+{
+ return mbBuiltin && (mnBuiltinId >= 0);
+}
+
+bool CellStyleModel::isDefaultStyle() const
+{
+ return mbBuiltin && (mnBuiltinId == OOX_STYLE_NORMAL);
+}
+
+// ============================================================================
+
+CellStyle::CellStyle( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mbCreated( false )
+{
+}
+
+void CellStyle::importCellStyle( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ maModel.mnXfId = rAttribs.getInteger( XML_xfId, -1 );
+ maModel.mnBuiltinId = rAttribs.getInteger( XML_builtinId, -1 );
+ maModel.mnLevel = rAttribs.getInteger( XML_iLevel, 0 );
+ maModel.mbBuiltin = rAttribs.hasAttribute( XML_builtinId );
+ maModel.mbCustom = rAttribs.getBool( XML_customBuiltin, false );
+ maModel.mbHidden = rAttribs.getBool( XML_hidden, false );
+}
+
+void CellStyle::importCellStyle( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> maModel.mnXfId >> nFlags;
+ maModel.mnBuiltinId = rStrm.readInt8();
+ maModel.mnLevel = rStrm.readInt8();
+ rStrm >> maModel.maName;
+ maModel.mbBuiltin = getFlag( nFlags, OOBIN_CELLSTYLE_BUILTIN );
+ maModel.mbCustom = getFlag( nFlags, OOBIN_CELLSTYLE_CUSTOM );
+ maModel.mbHidden = getFlag( nFlags, OOBIN_CELLSTYLE_HIDDEN );
+}
+
+void CellStyle::importStyle( BiffInputStream& rStrm )
+{
+ sal_uInt16 nStyleXf;
+ rStrm >> nStyleXf;
+ maModel.mnXfId = static_cast< sal_Int32 >( nStyleXf & BIFF_STYLE_XFMASK );
+ maModel.mbBuiltin = getFlag( nStyleXf, BIFF_STYLE_BUILTIN );
+ if( maModel.mbBuiltin )
+ {
+ maModel.mnBuiltinId = rStrm.readInt8();
+ maModel.mnLevel = rStrm.readInt8();
+ }
+ else
+ {
+ maModel.maName = (getBiff() == BIFF8) ?
+ rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
+ // #i103281# check if this is a new built-in style introduced in XL2007
+ if( (getBiff() == BIFF8) && (rStrm.getNextRecId() == BIFF_ID_STYLEEXT) && rStrm.startNextRecord() )
+ {
+ sal_uInt8 nExtFlags;
+ rStrm.skip( 12 );
+ rStrm >> nExtFlags;
+ maModel.mbBuiltin = getFlag( nExtFlags, BIFF_STYLEEXT_BUILTIN );
+ maModel.mbCustom = getFlag( nExtFlags, BIFF_STYLEEXT_CUSTOM );
+ maModel.mbHidden = getFlag( nExtFlags, BIFF_STYLEEXT_HIDDEN );
+ if( maModel.mbBuiltin )
+ {
+ maModel.mnBuiltinId = rStrm.readInt8();
+ maModel.mnLevel = rStrm.readInt8();
+ }
+ }
+ }
+}
+
+void CellStyle::createCellStyle()
+{
+ // #i1624# #i1768# ignore unnamed user styles
+ if( !mbCreated )
+ mbCreated = maFinalName.getLength() == 0;
+
+ /* #i103281# do not create another style of the same name, if it exists
+ already. This is needed to prevent that styles pasted from clipboard
+ get duplicated over and over. */
+ if( !mbCreated ) try
+ {
+ Reference< XNameAccess > xCellStylesNA( getStyleFamily( false ), UNO_QUERY_THROW );
+ mbCreated = xCellStylesNA->hasByName( maFinalName );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // create the style object in the document
+ if( !mbCreated ) try
+ {
+ mbCreated = true;
+ Reference< XStyle > xStyle( createStyleObject( maFinalName, false ), UNO_SET_THROW );
+ // write style formatting properties
+ PropertySet aPropSet( xStyle );
+ getStyles().writeStyleXfToPropertySet( aPropSet, maModel.mnXfId );
+ if( !maModel.isDefaultStyle() )
+ xStyle->setParentStyle( getStyles().getDefaultStyleName() );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void CellStyle::finalizeImport( const OUString& rFinalName )
+{
+ maFinalName = rFinalName;
+ if( !maModel.isBuiltin() || maModel.mbCustom )
+ createCellStyle();
+}
+
+// ============================================================================
+
+CellStyleBuffer::CellStyleBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+CellStyleRef CellStyleBuffer::importCellStyle( const AttributeList& rAttribs )
+{
+ CellStyleRef xCellStyle( new CellStyle( *this ) );
+ xCellStyle->importCellStyle( rAttribs );
+ insertCellStyle( xCellStyle );
+ return xCellStyle;
+}
+
+CellStyleRef CellStyleBuffer::importCellStyle( RecordInputStream& rStrm )
+{
+ CellStyleRef xCellStyle( new CellStyle( *this ) );
+ xCellStyle->importCellStyle( rStrm );
+ insertCellStyle( xCellStyle );
+ return xCellStyle;
+}
+
+CellStyleRef CellStyleBuffer::importStyle( BiffInputStream& rStrm )
+{
+ CellStyleRef xCellStyle( new CellStyle( *this ) );
+ xCellStyle->importStyle( rStrm );
+ insertCellStyle( xCellStyle );
+ return xCellStyle;
+}
+
+void CellStyleBuffer::finalizeImport()
+{
+ // calculate final names of all styles
+ typedef RefMap< OUString, CellStyle, IgnoreCaseCompare > CellStyleNameMap;
+ CellStyleNameMap aCellStyles;
+ CellStyleVector aConflictNameStyles;
+
+ /* First, reserve style names that are built-in in Calc. This causes that
+ imported cell styles get different unused names and thus do not try to
+ overwrite these built-in styles. For BIFF4 workbooks (which contain a
+ separate list of cell styles per sheet), reserve all existing styles if
+ current sheet is not the first sheet (this styles buffer will be
+ constructed again for every new sheet). This will create unique names
+ for styles in different sheets with the same name. Assuming that the
+ BIFF4W import filter is never used to import from clipboard... */
+ bool bReserveAll = (getFilterType() == FILTER_BIFF) && (getBiff() == BIFF4) && isWorkbookFile() && (getCurrentSheetIndex() > 0);
+ try
+ {
+ // unfortunately, com.sun.star.style.StyleFamily does not implement XEnumerationAccess...
+ Reference< XIndexAccess > xStyleFamilyIA( getStyleFamily( false ), UNO_QUERY_THROW );
+ for( sal_Int32 nIndex = 0, nCount = xStyleFamilyIA->getCount(); nIndex < nCount; ++nIndex )
+ {
+ Reference< XStyle > xStyle( xStyleFamilyIA->getByIndex( nIndex ), UNO_QUERY_THROW );
+ if( bReserveAll || !xStyle->isUserDefined() )
+ {
+ Reference< XNamed > xStyleName( xStyle, UNO_QUERY_THROW );
+ // create an empty entry by using ::std::map<>::operator[]
+ aCellStyles[ xStyleName->getName() ];
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ /* Calculate names of built-in styles. Store styles with reserved names
+ in the aConflictNameStyles list. */
+ for( CellStyleVector::iterator aIt = maBuiltinStyles.begin(), aEnd = maBuiltinStyles.end(); aIt != aEnd; ++aIt )
+ {
+ const CellStyleModel& rModel = (*aIt)->getModel();
+ if (rModel.isDefaultStyle())
+ continue;
+
+ OUString aStyleName = lclGetBuiltinStyleName( rModel.mnBuiltinId, rModel.maName, rModel.mnLevel );
+ OSL_ENSURE( bReserveAll || (aCellStyles.count( aStyleName ) == 0),
+ "CellStyleBuffer::finalizeImport - multiple styles with equal built-in identifier" );
+ if( aCellStyles.count( aStyleName ) > 0 )
+ aConflictNameStyles.push_back( *aIt );
+ else
+ aCellStyles[ aStyleName ] = *aIt;
+ }
+
+ /* Calculate names of user defined styles. Store styles with reserved
+ names in the aConflictNameStyles list. */
+ for( CellStyleVector::iterator aIt = maUserStyles.begin(), aEnd = maUserStyles.end(); aIt != aEnd; ++aIt )
+ {
+ const CellStyleModel& rModel = (*aIt)->getModel();
+ // #i1624# #i1768# ignore unnamed user styles
+ if( rModel.maName.getLength() > 0 )
+ {
+ if( aCellStyles.count( rModel.maName ) > 0 )
+ aConflictNameStyles.push_back( *aIt );
+ else
+ aCellStyles[ rModel.maName ] = *aIt;
+ }
+ }
+
+ // find unused names for all styles with conflicting names
+ for( CellStyleVector::iterator aIt = aConflictNameStyles.begin(), aEnd = aConflictNameStyles.end(); aIt != aEnd; ++aIt )
+ {
+ const CellStyleModel& rModel = (*aIt)->getModel();
+ OUString aUnusedName;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aUnusedName = OUStringBuffer( rModel.maName ).append( sal_Unicode( ' ' ) ).append( ++nIndex ).makeStringAndClear();
+ }
+ while( aCellStyles.count( aUnusedName ) > 0 );
+ aCellStyles[ aUnusedName ] = *aIt;
+ }
+
+ // set final names and create user-defined and modified built-in cell styles
+ aCellStyles.forEachMemWithKey( &CellStyle::finalizeImport );
+
+ if (mxDefStyle)
+ {
+ Reference<XNameAccess> xNA(getStyleFamily(false), UNO_QUERY_THROW);
+ if (xNA->hasByName(CREATE_OUSTRING("Default")))
+ {
+ PropertySet aPropSet(xNA->getByName(CREATE_OUSTRING("Default")));
+ getStyles().writeStyleXfToPropertySet(aPropSet, mxDefStyle->getModel().mnXfId);
+ }
+ }
+}
+
+sal_Int32 CellStyleBuffer::getDefaultXfId() const
+{
+ return mxDefStyle.get() ? mxDefStyle->getModel().mnXfId : -1;
+}
+
+OUString CellStyleBuffer::getDefaultStyleName() const
+{
+ return createCellStyle( mxDefStyle );
+}
+
+OUString CellStyleBuffer::createCellStyle( sal_Int32 nXfId ) const
+{
+ return createCellStyle( maStylesByXf.get( nXfId ) );
+}
+
+// private --------------------------------------------------------------------
+
+void CellStyleBuffer::insertCellStyle( CellStyleRef xCellStyle )
+{
+ const CellStyleModel& rModel = xCellStyle->getModel();
+ if( rModel.mnXfId >= 0 )
+ {
+ // insert into the built-in map or user defined map
+ (rModel.isBuiltin() ? maBuiltinStyles : maUserStyles).push_back( xCellStyle );
+
+ // insert into the XF identifier map
+ OSL_ENSURE( maStylesByXf.count( rModel.mnXfId ) == 0, "CellStyleBuffer::insertCellStyle - multiple styles with equal XF identifier" );
+ maStylesByXf[ rModel.mnXfId ] = xCellStyle;
+
+ // remember default cell style
+ if( rModel.isDefaultStyle() )
+ mxDefStyle = xCellStyle;
+ }
+}
+
+OUString CellStyleBuffer::createCellStyle( const CellStyleRef& rxCellStyle ) const
+{
+ if( rxCellStyle.get() )
+ {
+ rxCellStyle->createCellStyle();
+ const OUString& rStyleName = rxCellStyle->getFinalStyleName();
+ if( rStyleName.getLength() > 0 )
+ return rStyleName;
+ }
+ // on error: fallback to default style
+ return lclGetBuiltinStyleName( OOX_STYLE_NORMAL, OUString() );
+}
+
+// ============================================================================
+
+StylesBuffer::StylesBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maPalette( rHelper ),
+ maNumFmts( rHelper ),
+ maCellStyles( rHelper )
+{
+}
+
+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 );
+}
+
+NumberFormatRef StylesBuffer::importNumFmt( const AttributeList& rAttribs )
+{
+ return maNumFmts.importNumFmt( rAttribs );
+}
+
+CellStyleRef StylesBuffer::importCellStyle( const AttributeList& rAttribs )
+{
+ return maCellStyles.importCellStyle( rAttribs );
+}
+
+void StylesBuffer::importPaletteColor( RecordInputStream& rStrm )
+{
+ maPalette.importPaletteColor( rStrm );
+}
+
+void StylesBuffer::importNumFmt( RecordInputStream& rStrm )
+{
+ maNumFmts.importNumFmt( rStrm );
+}
+
+void StylesBuffer::importCellStyle( RecordInputStream& rStrm )
+{
+ maCellStyles.importCellStyle( rStrm );
+}
+
+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 ) );
+ xXf->importXf( rStrm );
+
+ XfRef xCellXf, xStyleXf;
+ (xXf->isCellXf() ? xCellXf : xStyleXf) = xXf;
+ maCellXfs.push_back( xCellXf );
+ maStyleXfs.push_back( xStyleXf );
+}
+
+void StylesBuffer::importStyle( BiffInputStream& rStrm )
+{
+ maCellStyles.importStyle( rStrm );
+}
+
+void StylesBuffer::finalizeImport()
+{
+ // fonts first, are needed to finalize unit converter and XFs below
+ maFonts.forEachMem( &Font::finalizeImport );
+ // finalize unit coefficients 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
+ maStyleXfs.forEachMem( &Xf::finalizeImport );
+ maCellXfs.forEachMem( &Xf::finalizeImport );
+ // built-in and user defined cell styles
+ maCellStyles.finalizeImport();
+ // differential formatting (for conditional formatting)
+ maDxfs.forEachMem( &Dxf::finalizeImport );
+}
+
+sal_Int32 StylesBuffer::getPaletteColor( sal_Int32 nPaletteIdx ) const
+{
+ return maPalette.getColor( nPaletteIdx );
+}
+
+FontRef StylesBuffer::getFont( sal_Int32 nFontId ) const
+{
+ return maFonts.get( nFontId );
+}
+
+BorderRef StylesBuffer::getBorder( sal_Int32 nBorderId ) const
+{
+ return maBorders.get( nBorderId );
+}
+
+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( maCellStyles.getDefaultXfId() ).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 FontModel& StylesBuffer::getDefaultFontModel() const
+{
+ FontRef xDefFont = getDefaultFont();
+ return xDefFont.get() ? xDefFont->getModel() : getTheme().getDefaultFontModel();
+}
+
+bool StylesBuffer::equalBorders( sal_Int32 nBorderId1, sal_Int32 nBorderId2 ) const
+{
+ if( nBorderId1 == nBorderId2 )
+ return true;
+
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ // in OOXML, borders are assumed to be unique
+ return false;
+
+ case FILTER_BIFF:
+ {
+ // in BIFF, a new border entry has been created for every XF
+ const Border* pBorder1 = maBorders.get( nBorderId1 ).get();
+ const Border* pBorder2 = maBorders.get( nBorderId2 ).get();
+ return pBorder1 && pBorder2 && (pBorder1->getApiData() == pBorder2->getApiData());
+ }
+
+ case FILTER_UNKNOWN:
+ break;
+ }
+ return false;
+}
+
+bool StylesBuffer::equalFills( sal_Int32 nFillId1, sal_Int32 nFillId2 ) const
+{
+ if( nFillId1 == nFillId2 )
+ return true;
+
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ // in OOXML, fills are assumed to be unique
+ return false;
+
+ case FILTER_BIFF:
+ {
+ // in BIFF, a new fill entry has been created for every XF
+ const Fill* pFill1 = maFills.get( nFillId1 ).get();
+ const Fill* pFill2 = maFills.get( nFillId2 ).get();
+ return pFill1 && pFill2 && (pFill1->getApiData() == pFill2->getApiData());
+ }
+
+ case FILTER_UNKNOWN:
+ break;
+ }
+ return false;
+}
+
+OUString StylesBuffer::getDefaultStyleName() const
+{
+ return maCellStyles.getDefaultStyleName();
+}
+
+OUString StylesBuffer::createCellStyle( sal_Int32 nXfId ) const
+{
+ return maCellStyles.createCellStyle( nXfId );
+}
+
+OUString StylesBuffer::createDxfStyle( sal_Int32 nDxfId ) const
+{
+ OUString& rStyleName = maDxfStyles[ nDxfId ];
+ if( rStyleName.getLength() == 0 )
+ {
+ if( Dxf* pDxf = maDxfs.get( nDxfId ).get() )
+ {
+ rStyleName = OUStringBuffer( CREATE_OUSTRING( "ConditionalStyle_" ) ).append( nDxfId + 1 ).makeStringAndClear();
+ // create the style sheet (this may change rStyleName if such a style already exists)
+ Reference< XStyle > xStyle = createStyleObject( rStyleName, false );
+ // write style formatting properties
+ PropertySet aPropSet( xStyle );
+ pDxf->writeToPropertySet( aPropSet );
+ }
+ // on error: fallback to default style
+ if( rStyleName.getLength() == 0 )
+ rStyleName = maCellStyles.getDefaultStyleName();
+ }
+ return rStyleName;
+}
+
+void StylesBuffer::writeFontToPropertyMap( PropertyMap& rPropMap, sal_Int32 nFontId ) const
+{
+ if( Font* pFont = maFonts.get( nFontId ).get() )
+ pFont->writeToPropertyMap( rPropMap, FONT_PROPTYPE_CELL );
+}
+
+void StylesBuffer::writeNumFmtToPropertyMap( PropertyMap& rPropMap, sal_Int32 nNumFmtId ) const
+{
+ maNumFmts.writeToPropertyMap( rPropMap, nNumFmtId );
+}
+
+void StylesBuffer::writeBorderToPropertyMap( PropertyMap& rPropMap, sal_Int32 nBorderId ) const
+{
+ if( Border* pBorder = maBorders.get( nBorderId ).get() )
+ pBorder->writeToPropertyMap( rPropMap );
+}
+
+void StylesBuffer::writeFillToPropertyMap( PropertyMap& rPropMap, sal_Int32 nFillId ) const
+{
+ if( Fill* pFill = maFills.get( nFillId ).get() )
+ pFill->writeToPropertyMap( rPropMap );
+}
+
+void StylesBuffer::writeCellXfToPropertyMap( PropertyMap& rPropMap, sal_Int32 nXfId ) const
+{
+ if( Xf* pXf = maCellXfs.get( nXfId ).get() )
+ pXf->writeToPropertyMap( rPropMap );
+}
+
+void StylesBuffer::writeStyleXfToPropertyMap( PropertyMap& rPropMap, sal_Int32 nXfId ) const
+{
+ if( Xf* pXf = maStyleXfs.get( nXfId ).get() )
+ pXf->writeToPropertyMap( rPropMap );
+}
+
+void StylesBuffer::writeCellXfToPropertySet( PropertySet& rPropSet, sal_Int32 nXfId ) const
+{
+ if( Xf* pXf = maCellXfs.get( nXfId ).get() )
+ pXf->writeToPropertySet( rPropSet );
+}
+
+bool StylesBuffer::hasBorder( sal_Int32 nBorderId ) const
+{
+ Border* pBorder = maBorders.get( nBorderId ).get();
+ return pBorder && pBorder->hasBorder();
+}
+
+void StylesBuffer::writeStyleXfToPropertySet( PropertySet& rPropSet, sal_Int32 nXfId ) const
+{
+ if( Xf* pXf = maStyleXfs.get( nXfId ).get() )
+ pXf->writeToPropertySet( rPropSet );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/stylesfragment.cxx b/oox/source/xls/stylesfragment.cxx
new file mode 100644
index 000000000000..c3b15f872077
--- /dev/null
+++ b/oox/source/xls/stylesfragment.cxx
@@ -0,0 +1,333 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/stylesfragment.hxx"
+#include "oox/helper/attributelist.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxIndexedColorsContext::OoxIndexedColorsContext( OoxWorkbookFragmentBase& rFragment ) :
+ OoxWorkbookContextBase( rFragment )
+{
+}
+
+ContextHandlerRef OoxIndexedColorsContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( indexedColors ):
+ if( nElement == XLS_TOKEN( rgbColor ) ) getStyles().importPaletteColor( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+ContextHandlerRef OoxIndexedColorsContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case OOBIN_ID_INDEXEDCOLORS:
+ if( nRecId == OOBIN_ID_RGBCOLOR ) getStyles().importPaletteColor( rStrm );
+ break;
+ }
+ return 0;
+}
+
+// ============================================================================
+
+ContextHandlerRef OoxFontContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( mxFont.get() )
+ mxFont->importAttribs( nElement, rAttribs );
+ return 0;
+}
+
+// ============================================================================
+
+void OoxBorderContext::onStartElement( const AttributeList& rAttribs )
+{
+ if( mxBorder.get() && (getCurrentElement() == XLS_TOKEN( border )) )
+ mxBorder->importBorder( rAttribs );
+}
+
+ContextHandlerRef OoxBorderContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( mxBorder.get() ) switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( border ):
+ mxBorder->importStyle( nElement, rAttribs );
+ return this;
+
+ default:
+ if( nElement == XLS_TOKEN( color ) )
+ mxBorder->importColor( getCurrentElement(), rAttribs );
+ }
+ return 0;
+}
+
+// ============================================================================
+
+ContextHandlerRef OoxFillContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( mxFill.get() ) switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( fill ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( patternFill ): mxFill->importPatternFill( rAttribs ); return this;
+ case XLS_TOKEN( gradientFill ): mxFill->importGradientFill( rAttribs ); return this;
+ }
+ break;
+ case XLS_TOKEN( patternFill ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( fgColor ): mxFill->importFgColor( rAttribs ); break;
+ case XLS_TOKEN( bgColor ): mxFill->importBgColor( rAttribs ); break;
+ }
+ break;
+ case XLS_TOKEN( gradientFill ):
+ if( nElement == XLS_TOKEN( stop ) )
+ {
+ mfGradPos = rAttribs.getDouble( XML_position, -1.0 );
+ return this;
+ }
+ break;
+ case XLS_TOKEN( stop ):
+ if( nElement == XLS_TOKEN( color ) )
+ mxFill->importColor( rAttribs, mfGradPos );
+ break;
+ }
+ return 0;
+}
+
+// ============================================================================
+
+void OoxXfContext::onStartElement( const AttributeList& rAttribs )
+{
+ if( mxXf.get() && (getCurrentElement() == XLS_TOKEN( xf )) )
+ mxXf->importXf( rAttribs, mbCellXf );
+}
+
+ContextHandlerRef OoxXfContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( mxXf.get() ) switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( xf ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( alignment ): mxXf->importAlignment( rAttribs ); break;
+ case XLS_TOKEN( protection ): mxXf->importProtection( rAttribs ); break;
+ }
+ break;
+ }
+ return 0;
+}
+
+// ============================================================================
+
+ContextHandlerRef OoxDxfContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ if( mxDxf.get() ) switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( dxf ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( font ): return new OoxFontContext( *this, mxDxf->createFont() );
+ case XLS_TOKEN( border ): return new OoxBorderContext( *this, mxDxf->createBorder() );
+ case XLS_TOKEN( fill ): return new OoxFillContext( *this, mxDxf->createFill() );
+
+ case XLS_TOKEN( numFmt ): mxDxf->importNumFmt( rAttribs ); break;
+#if 0
+ case XLS_TOKEN( alignment ): mxDxf->importAlignment( rAttribs ); break;
+ case XLS_TOKEN( protection ): mxDxf->importProtection( rAttribs ); break;
+#endif
+ }
+ break;
+ }
+ return 0;
+}
+
+// ============================================================================
+
+OoxStylesFragment::OoxStylesFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxStylesFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( styleSheet ) ) return this;
+ break;
+
+ case XLS_TOKEN( styleSheet ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( colors ):
+ case XLS_TOKEN( numFmts ):
+ case XLS_TOKEN( fonts ):
+ case XLS_TOKEN( borders ):
+ case XLS_TOKEN( fills ):
+ case XLS_TOKEN( cellXfs ):
+ case XLS_TOKEN( cellStyleXfs ):
+ case XLS_TOKEN( dxfs ):
+ case XLS_TOKEN( cellStyles ): return this;
+ }
+ break;
+
+ case XLS_TOKEN( colors ):
+ if( nElement == XLS_TOKEN( indexedColors ) ) return new OoxIndexedColorsContext( *this );
+ break;
+ case XLS_TOKEN( numFmts ):
+ if( nElement == XLS_TOKEN( numFmt ) ) getStyles().importNumFmt( rAttribs );
+ break;
+ case XLS_TOKEN( fonts ):
+ if( nElement == XLS_TOKEN( font ) ) return new OoxFontContext( *this, getStyles().createFont() );
+ break;
+ case XLS_TOKEN( borders ):
+ if( nElement == XLS_TOKEN( border ) ) return new OoxBorderContext( *this, getStyles().createBorder() );
+ break;
+ case XLS_TOKEN( fills ):
+ if( nElement == XLS_TOKEN( fill ) ) return new OoxFillContext( *this, getStyles().createFill() );
+ break;
+ case XLS_TOKEN( cellXfs ):
+ if( nElement == XLS_TOKEN( xf ) ) return new OoxXfContext( *this, getStyles().createCellXf(), true );
+ break;
+ case XLS_TOKEN( cellStyleXfs ):
+ if( nElement == XLS_TOKEN( xf ) ) return new OoxXfContext( *this, getStyles().createStyleXf(), false );
+ break;
+ case XLS_TOKEN( dxfs ):
+ if( nElement == XLS_TOKEN( dxf ) ) return new OoxDxfContext( *this, getStyles().createDxf() );
+ break;
+ case XLS_TOKEN( cellStyles ):
+ if( nElement == XLS_TOKEN( cellStyle ) ) getStyles().importCellStyle( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+ContextHandlerRef OoxStylesFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_STYLESHEET ) return this;
+ break;
+
+ case OOBIN_ID_STYLESHEET:
+ switch( nRecId )
+ {
+ case OOBIN_ID_COLORS:
+ case OOBIN_ID_NUMFMTS:
+ case OOBIN_ID_FONTS:
+ case OOBIN_ID_BORDERS:
+ case OOBIN_ID_FILLS:
+ case OOBIN_ID_CELLXFS:
+ case OOBIN_ID_CELLSTYLEXFS:
+ case OOBIN_ID_DXFS:
+ case OOBIN_ID_CELLSTYLES: return this;
+ }
+ break;
+
+ case OOBIN_ID_COLORS:
+ if( nRecId == OOBIN_ID_INDEXEDCOLORS ) return new OoxIndexedColorsContext( *this );
+ break;
+ case OOBIN_ID_NUMFMTS:
+ if( nRecId == OOBIN_ID_NUMFMT ) getStyles().importNumFmt( rStrm );
+ break;
+ case OOBIN_ID_FONTS:
+ if( nRecId == OOBIN_ID_FONT ) getStyles().createFont()->importFont( rStrm );
+ break;
+ case OOBIN_ID_BORDERS:
+ if( nRecId == OOBIN_ID_BORDER ) getStyles().createBorder()->importBorder( rStrm );
+ break;
+ case OOBIN_ID_FILLS:
+ if( nRecId == OOBIN_ID_FILL ) getStyles().createFill()->importFill( rStrm );
+ break;
+ case OOBIN_ID_CELLXFS:
+ if( nRecId == OOBIN_ID_XF ) getStyles().createCellXf()->importXf( rStrm, true );
+ break;
+ case OOBIN_ID_CELLSTYLEXFS:
+ if( nRecId == OOBIN_ID_XF ) getStyles().createStyleXf()->importXf( rStrm, false );
+ break;
+ case OOBIN_ID_DXFS:
+ if( nRecId == OOBIN_ID_DXF ) getStyles().createDxf()->importDxf( rStrm );
+ break;
+ case OOBIN_ID_CELLSTYLES:
+ if( nRecId == OOBIN_ID_CELLSTYLE ) getStyles().importCellStyle( rStrm );
+ break;
+ }
+ return 0;
+}
+
+// oox.core.FragmentHandler2 interface ----------------------------------------
+
+const RecordInfo* OoxStylesFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { 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_COLORS, OOBIN_ID_COLORS + 1 },
+ { OOBIN_ID_DXFS, OOBIN_ID_DXFS + 1 },
+ { OOBIN_ID_FILLS, OOBIN_ID_FILLS + 1 },
+ { OOBIN_ID_FONTS, OOBIN_ID_FONTS + 1 },
+ { OOBIN_ID_INDEXEDCOLORS, OOBIN_ID_INDEXEDCOLORS + 1 },
+ { OOBIN_ID_MRUCOLORS, OOBIN_ID_MRUCOLORS + 1 },
+ { OOBIN_ID_NUMFMTS, OOBIN_ID_NUMFMTS + 1 },
+ { OOBIN_ID_STYLESHEET, OOBIN_ID_STYLESHEET + 1 },
+ { OOBIN_ID_TABLESTYLES, OOBIN_ID_TABLESTYLES + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+void OoxStylesFragment::finalizeImport()
+{
+ getStyles().finalizeImport();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/tablebuffer.cxx b/oox/source/xls/tablebuffer.cxx
new file mode 100644
index 000000000000..f9b68b6f74f5
--- /dev/null
+++ b/oox/source/xls/tablebuffer.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/tablebuffer.hxx"
+#include <com/sun/star/sheet/XDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XDatabaseRange.hpp>
+#include "properties.hxx"
+#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 {
+
+// ============================================================================
+
+TableModel::TableModel() :
+ 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 )
+{
+ getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, rAttribs.getString( XML_ref, OUString() ), nSheet );
+ maModel.maProgName = rAttribs.getXString( XML_name, OUString() );
+ maModel.maDisplayName = rAttribs.getXString( XML_displayName, OUString() );
+ maModel.mnId = rAttribs.getInteger( XML_id, -1 );
+ maModel.mnType = rAttribs.getToken( XML_tableType, XML_worksheet );
+ maModel.mnHeaderRows = rAttribs.getInteger( XML_headerRowCount, 1 );
+ maModel.mnTotalsRows = rAttribs.getInteger( XML_totalsRowCount, 0 );
+}
+
+void Table::importTable( RecordInputStream& rStrm, sal_Int16 nSheet )
+{
+ BinRange aBinRange;
+ sal_Int32 nType;
+ rStrm >> aBinRange >> nType >> maModel.mnId >> maModel.mnHeaderRows >> maModel.mnTotalsRows;
+ rStrm.skip( 32 );
+ rStrm >> maModel.maProgName >> maModel.maDisplayName;
+
+ getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, aBinRange, nSheet );
+ static const sal_Int32 spnTypes[] = { XML_worksheet, XML_TOKEN_INVALID, XML_TOKEN_INVALID, XML_queryTable };
+ maModel.mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_TOKEN_INVALID );
+}
+
+void Table::finalizeImport()
+{
+ // validate cell range
+ maDestRange = maModel.maRange;
+ bool bValidRange = getAddressConverter().validateCellRange( maDestRange, true, true );
+
+ // create database range
+ if( bValidRange && (maModel.mnId > 0) && (maModel.maDisplayName.getLength() > 0) ) try
+ {
+ // find an unused name
+ Reference< XDatabaseRanges > xDatabaseRanges = getDatabaseRanges();
+ Reference< XNameAccess > xNameAccess( xDatabaseRanges, UNO_QUERY_THROW );
+ OUString aName = ContainerHelper::getUnusedName( xNameAccess, maModel.maDisplayName, '_' );
+ xDatabaseRanges->addNewByName( aName, maModel.maRange );
+ Reference< XDatabaseRange > xDatabaseRange( xDatabaseRanges->getByName( aName ), UNO_QUERY_THROW );
+ PropertySet aPropSet( xDatabaseRange );
+ if( !aPropSet.getProperty( mnTokenIndex, PROP_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()
+{
+ maIdTables.forEachMem( &Table::finalizeImport );
+}
+
+TableRef TableBuffer::getTable( sal_Int32 nTableId ) const
+{
+ return maIdTables.get( nTableId );
+}
+
+TableRef TableBuffer::getTable( const OUString& rDispName ) const
+{
+ return maNameTables.get( rDispName );
+}
+
+// private --------------------------------------------------------------------
+
+void TableBuffer::insertTable( TableRef xTable )
+{
+ sal_Int32 nTableId = xTable->getTableId();
+ const OUString& rDispName = xTable->getDisplayName();
+ if( (nTableId > 0) && (rDispName.getLength() > 0) )
+ {
+ OSL_ENSURE( maIdTables.find( nTableId ) == maIdTables.end(), "TableBuffer::insertTable - multiple table identifier" );
+ maIdTables[ nTableId ] = xTable;
+ OSL_ENSURE( maNameTables.find( rDispName ) == maNameTables.end(), "TableBuffer::insertTable - multiple table name" );
+ maNameTables[ rDispName ] = xTable;
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/tablefragment.cxx b/oox/source/xls/tablefragment.cxx
new file mode 100644
index 000000000000..096a8ca25cce
--- /dev/null
+++ b/oox/source/xls/tablefragment.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/tablefragment.hxx"
+
+using ::rtl::OUString;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+OoxTableFragment::OoxTableFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxTableFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( table ) )
+ mxTable = getTables().importTable( rAttribs, getSheetIndex() );
+ break;
+ }
+ return 0;
+}
+
+ContextHandlerRef OoxTableFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_TABLE )
+ mxTable = getTables().importTable( rStrm, getSheetIndex() );
+ break;
+ }
+ return 0;
+}
+
+// oox.core.FragmentHandler2 interface ----------------------------------------
+
+const RecordInfo* OoxTableFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_TABLE, OOBIN_ID_TABLE + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/themebuffer.cxx b/oox/source/xls/themebuffer.cxx
new file mode 100644
index 000000000000..fc1ec6ce987e
--- /dev/null
+++ b/oox/source/xls/themebuffer.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "tokens.hxx"
+
+using ::oox::drawingml::ClrScheme;
+
+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 ),
+ mxDefFontModel( new FontModel )
+{
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ //! TODO: locale dependent font name
+ mxDefFontModel->maName = CREATE_OUSTRING( "Cambria" );
+ mxDefFontModel->mfHeight = 11.0;
+ break;
+ case FILTER_BIFF:
+ //! TODO: BIFF dependent font name
+ mxDefFontModel->maName = CREATE_OUSTRING( "Arial" );
+ mxDefFontModel->mfHeight = 10.0;
+ break;
+ case FILTER_UNKNOWN: break;
+ }
+}
+
+ThemeBuffer::~ThemeBuffer()
+{
+}
+
+sal_Int32 ThemeBuffer::getColorByToken( sal_Int32 nToken ) const
+{
+ sal_Int32 nColor = 0;
+ return getClrScheme().getColor( nToken, nColor ) ? nColor : API_RGB_TRANSPARENT;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/unitconverter.cxx b/oox/source/xls/unitconverter.cxx
new file mode 100644
index 000000000000..2cf7fae8f0cb
--- /dev/null
+++ b/oox/source/xls/unitconverter.cxx
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/unitconverter.hxx"
+#include <rtl/math.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 <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include "oox/core/filterbase.hxx"
+#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;
+using ::com::sun::star::util::Date;
+using ::com::sun::star::util::DateTime;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const double MM100_PER_INCH = 2540.0;
+const double MM100_PER_POINT = MM100_PER_INCH / 72.0;
+const double MM100_PER_TWIP = MM100_PER_POINT / 20.0;
+const double MM100_PER_EMU = 1.0 / 360.0;
+
+// ----------------------------------------------------------------------------
+
+/** Returns true, if the passed year is a leap year. */
+inline sal_Int32 lclIsLeapYear( sal_Int32 nYear )
+{
+ return ((nYear % 4) == 0) && (((nYear % 100) != 0) || ((nYear % 400) == 0));
+}
+
+void lclSkipYearBlock( sal_Int32& ornDays, sal_uInt16& ornYear, sal_Int32 nDaysInBlock, sal_Int32 nYearsPerBlock, sal_Int32 nMaxBlocks )
+{
+ sal_Int32 nBlocks = ::std::min< sal_Int32 >( ornDays / nDaysInBlock, nMaxBlocks );
+ ornYear = static_cast< sal_uInt16 >( ornYear + nYearsPerBlock * nBlocks );
+ ornDays -= nBlocks * nDaysInBlock;
+}
+
+/** Returns the number of days before the passed date, starting from the null
+ date 0000-Jan-01, using standard leap year conventions. */
+sal_Int32 lclGetDays( const Date& rDate )
+{
+ // number of days in all full years before passed date including all leap days
+ sal_Int32 nDays = rDate.Year * 365 + ((rDate.Year + 3) / 4) - ((rDate.Year + 99) / 100) + ((rDate.Year + 399) / 400);
+ OSL_ENSURE( (1 <= rDate.Month) && (rDate.Month <= 12), "lclGetDays - invalid month" );
+ OSL_ENSURE( (1 <= rDate.Day) && (rDate.Day <= 31), "lclGetDays - invalid day" ); // yes, this is weak...
+ if( (1 <= rDate.Month) && (rDate.Month <= 12) )
+ {
+ // number of days at start of month jan feb mar apr may jun jul aug sep oct nov dec
+ static const sal_Int32 spnCumDays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ // add number of days in full months before passed date
+ nDays += spnCumDays[ rDate.Month - 1 ];
+ // add number of days from passed date (this adds one day too much)
+ nDays += rDate.Day;
+ /* Remove the one day added too much if there is no leap day before
+ the passed day in the passed year. This means: remove the day, if
+ we are in january or february (leap day not reached if existing),
+ or if the passed year is not a leap year. */
+ if( (rDate.Month < 3) || !lclIsLeapYear( rDate.Year ) )
+ --nDays;
+ }
+ return nDays;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+UnitConverter::UnitConverter( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maCoeffs( UNIT_ENUM_SIZE, 1.0 ),
+ mnNullDate( lclGetDays( Date( 30, 12, 1899 ) ) )
+{
+ // initialize constant and default coefficients
+ const DeviceInfo& rDeviceInfo = getBaseFilter().getGraphicHelper().getDeviceInfo();
+ maCoeffs[ UNIT_INCH ] = MM100_PER_INCH;
+ maCoeffs[ UNIT_POINT ] = MM100_PER_POINT;
+ maCoeffs[ UNIT_TWIP ] = MM100_PER_TWIP;
+ maCoeffs[ UNIT_EMU ] = MM100_PER_EMU;
+ maCoeffs[ UNIT_SCREENX ] = (rDeviceInfo.PixelPerMeterX > 0) ? (100000.0 / rDeviceInfo.PixelPerMeterX) : 50.0;
+ maCoeffs[ UNIT_SCREENY ] = (rDeviceInfo.PixelPerMeterY > 0) ? (100000.0 / rDeviceInfo.PixelPerMeterY) : 50.0;
+ maCoeffs[ UNIT_REFDEVX ] = 12.5; // default: 1 px = 0.125 mm
+ maCoeffs[ UNIT_REFDEVY ] = 12.5; // default: 1 px = 0.125 mm
+ maCoeffs[ UNIT_DIGIT ] = 200.0; // default: 1 digit = 2 mm
+ maCoeffs[ UNIT_SPACE ] = 100.0; // default 1 space = 1 mm
+
+ // error code maps
+ addErrorCode( BIFF_ERR_NULL, CREATE_OUSTRING( "#NULL!" ) );
+ addErrorCode( BIFF_ERR_DIV0, CREATE_OUSTRING( "#DIV/0!" ) );
+ addErrorCode( BIFF_ERR_VALUE, CREATE_OUSTRING( "#VALUE!" ) );
+ addErrorCode( BIFF_ERR_REF, CREATE_OUSTRING( "#REF!" ) );
+ addErrorCode( BIFF_ERR_NAME, CREATE_OUSTRING( "#NAME?" ) );
+ addErrorCode( BIFF_ERR_NUM, CREATE_OUSTRING( "#NUM!" ) );
+ addErrorCode( BIFF_ERR_NA, CREATE_OUSTRING( "#NA" ) );
+}
+
+void UnitConverter::finalizeImport()
+{
+ Reference< XDevice > xDevice = getReferenceDevice();
+ if( xDevice.is() )
+ {
+ // get reference device metric first, needed to get character widths below
+ DeviceInfo aInfo = xDevice->getInfo();
+ maCoeffs[ UNIT_REFDEVX ] = 100000.0 / aInfo.PixelPerMeterX;
+ maCoeffs[ UNIT_REFDEVY ] = 100000.0 / aInfo.PixelPerMeterY;
+
+ // 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 >( scaleValue( aDesc.Height, UNIT_TWIP, UNIT_REFDEVX ) + 0.5 );
+ 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, scaleToMm100( xFont->getCharWidth( cChar ), UNIT_REFDEVX ) );
+ if( nDigitWidth > 0 )
+ maCoeffs[ UNIT_DIGIT ] = nDigitWidth;
+ // get width of space character
+ sal_Int32 nSpaceWidth = scaleToMm100( xFont->getCharWidth( ' ' ), UNIT_REFDEVX );
+ if( nSpaceWidth > 0 )
+ maCoeffs[ UNIT_SPACE ] = nSpaceWidth;
+ }
+ }
+ }
+}
+
+void UnitConverter::finalizeNullDate( const Date& rNullDate )
+{
+ // convert the nulldate to number of days since 0000-Jan-01
+ mnNullDate = lclGetDays( rNullDate );
+}
+
+// conversion -----------------------------------------------------------------
+
+double UnitConverter::scaleValue( double fValue, Unit eFromUnit, Unit eToUnit ) const
+{
+ return (eFromUnit == eToUnit) ? fValue : (fValue * getCoefficient( eFromUnit ) / getCoefficient( eToUnit ));
+}
+
+sal_Int32 UnitConverter::scaleToMm100( double fValue, Unit eUnit ) const
+{
+ return static_cast< sal_Int32 >( fValue * getCoefficient( eUnit ) + 0.5 );
+}
+
+double UnitConverter::scaleFromMm100( sal_Int32 nMm100, Unit eUnit ) const
+{
+ return static_cast< double >( nMm100 ) / getCoefficient( eUnit );
+}
+
+double UnitConverter::calcSerialFromDateTime( const DateTime& rDateTime ) const
+{
+ sal_Int32 nDays = lclGetDays( Date( rDateTime.Day, rDateTime.Month, rDateTime.Year ) ) - mnNullDate;
+ OSL_ENSURE( nDays >= 0, "UnitConverter::calcDateTimeSerial - invalid date" );
+ OSL_ENSURE( (rDateTime.Hours <= 23) && (rDateTime.Minutes <= 59) && (rDateTime.Seconds <= 59), "UnitConverter::calcDateTimeSerial - invalid time" );
+ return nDays + rDateTime.Hours / 24.0 + rDateTime.Minutes / 1440.0 + rDateTime.Seconds / 86400.0;
+}
+
+DateTime UnitConverter::calcDateTimeFromSerial( double fSerial ) const
+{
+ DateTime aDateTime( 0, 0, 0, 0, 1, 1, 0 );
+ double fDays = 0.0;
+ double fTime = modf( fSerial, &fDays );
+
+ // calculate date from number of days with O(1) complexity
+ sal_Int32 nDays = getLimitedValue< sal_Int32, double >( fDays + mnNullDate, 0, 3652424 );
+ // skip year 0, assumed to be a leap year. By starting at year 1, leap years can be handled easily
+ if( nDays >= 366 ) { ++aDateTime.Year; nDays -= 366; }
+ // skip full blocks of 400, 100, 4 years, and remaining full years
+ lclSkipYearBlock( nDays, aDateTime.Year, 400 * 365 + 97, 400, 24 );
+ lclSkipYearBlock( nDays, aDateTime.Year, 100 * 365 + 24, 100, 3 );
+ lclSkipYearBlock( nDays, aDateTime.Year, 4 * 365 + 1, 4, 24 );
+ lclSkipYearBlock( nDays, aDateTime.Year, 365, 1, 3 );
+ // skip full months of current year
+ static const sal_Int32 spnDaysInMonth[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ if( (nDays >= 59) && !lclIsLeapYear( aDateTime.Year ) ) ++nDays;
+ const sal_Int32* pnDaysInMonth = spnDaysInMonth;
+ while( *pnDaysInMonth >= nDays ) { ++aDateTime.Month; nDays -= *pnDaysInMonth; ++pnDaysInMonth; }
+ aDateTime.Day = static_cast< sal_uInt16 >( nDays + 1 );
+
+ // calculate time from fractional part of serial
+ sal_Int32 nTime = getLimitedValue< sal_Int32, double >( fTime * 86400, 0, 86399 );
+ aDateTime.Seconds = static_cast< sal_uInt16 >( nTime % 60 );
+ nTime /= 60;
+ aDateTime.Minutes = static_cast< sal_uInt16 >( nTime % 60 );
+ aDateTime.Hours = static_cast< sal_uInt16 >( nTime / 60 );
+
+ return aDateTime;
+}
+
+OUString UnitConverter::calcOoxErrorCode( sal_uInt8 nErrorCode ) const
+{
+ BiffErrorCodeMap::const_iterator aIt = maBiffErrCodes.find( nErrorCode );
+ return (aIt == maBiffErrCodes.end()) ? CREATE_OUSTRING( "#N/A" ) : aIt->second;
+}
+
+sal_uInt8 UnitConverter::calcBiffErrorCode( const OUString& rErrorCode ) const
+{
+ OoxErrorCodeMap::const_iterator aIt = maOoxErrCodes.find( rErrorCode );
+ return (aIt == maOoxErrCodes.end()) ? BIFF_ERR_NA : aIt->second;
+}
+
+void UnitConverter::addErrorCode( sal_uInt8 nErrorCode, const OUString& rErrorCode )
+{
+ maOoxErrCodes[ rErrorCode ] = nErrorCode;
+ maBiffErrCodes[ nErrorCode ] = rErrorCode;
+}
+
+double UnitConverter::getCoefficient( Unit eUnit ) const
+{
+ OSL_ENSURE( static_cast< size_t >( eUnit ) < UNIT_ENUM_SIZE, "UnitConverter::getCoefficient - invalid unit" );
+ return maCoeffs[ static_cast< size_t >( eUnit ) ];
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/viewsettings.cxx b/oox/source/xls/viewsettings.cxx
new file mode 100644
index 000000000000..9f04cf3d8007
--- /dev/null
+++ b/oox/source/xls/viewsettings.cxx
@@ -0,0 +1,835 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/viewsettings.hxx"
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#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 <comphelper/mediadescriptor.hxx>
+#include "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertymap.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/unitconverter.hxx"
+#include "oox/xls/workbooksettings.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::awt::Point;
+using ::com::sun::star::awt::Size;
+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;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::oox::core::FilterBase;
+
+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_uInt16 OOBIN_CHARTSHEETVIEW_SELECTED = 0x0001;
+const sal_uInt16 OOBIN_CHARTSHEETVIEW_ZOOMTOFIT = 0x0002;
+
+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.
+
+// ----------------------------------------------------------------------------
+
+/** 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
+
+// ============================================================================
+
+PaneSelectionModel::PaneSelectionModel() :
+ mnActiveCellId( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+SheetViewModel::SheetViewModel() :
+ 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 ),
+ mbZoomToFit( false )
+{
+ maGridColor.setIndexed( OOX_COLOR_WINDOWTEXT );
+}
+
+bool SheetViewModel::isPageBreakPreview() const
+{
+ return mnViewType == XML_pageBreakPreview;
+}
+
+sal_Int32 SheetViewModel::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 SheetViewModel::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 );
+}
+
+sal_Int32 SheetViewModel::getGridColor( const FilterBase& rFilter ) const
+{
+ return mbDefGridColor ? API_RGB_TRANSPARENT : maGridColor.getColor( rFilter.getGraphicHelper() );
+}
+
+const PaneSelectionModel* SheetViewModel::getPaneSelection( sal_Int32 nPaneId ) const
+{
+ return maPaneSelMap.get( nPaneId ).get();
+}
+
+const PaneSelectionModel* SheetViewModel::getActiveSelection() const
+{
+ return getPaneSelection( mnActivePaneId );
+}
+
+PaneSelectionModel& SheetViewModel::createPaneSelection( sal_Int32 nPaneId )
+{
+ PaneSelectionModelMap::mapped_type& rxPaneSel = maPaneSelMap[ nPaneId ];
+ if( !rxPaneSel )
+ rxPaneSel.reset( new PaneSelectionModel );
+ return *rxPaneSel;
+}
+
+// ----------------------------------------------------------------------------
+
+SheetViewSettings::SheetViewSettings( const WorksheetHelper& rHelper ) :
+ WorksheetHelper( rHelper )
+{
+}
+
+void SheetViewSettings::importSheetView( const AttributeList& rAttribs )
+{
+ SheetViewModel& rModel = *createSheetView();
+ rModel.maGridColor.setIndexed( rAttribs.getInteger( XML_colorId, OOX_COLOR_WINDOWTEXT ) );
+ rModel.maFirstPos = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_topLeftCell, OUString() ), getSheetIndex(), false );
+ rModel.mnWorkbookViewId = rAttribs.getToken( XML_workbookViewId, 0 );
+ rModel.mnViewType = rAttribs.getToken( XML_view, XML_normal );
+ rModel.mnCurrentZoom = rAttribs.getInteger( XML_zoomScale, 100 );
+ rModel.mnNormalZoom = rAttribs.getInteger( XML_zoomScaleNormal, 0 );
+ rModel.mnSheetLayoutZoom = rAttribs.getInteger( XML_zoomScaleSheetLayoutView, 0 );
+ rModel.mnPageLayoutZoom = rAttribs.getInteger( XML_zoomScalePageLayoutView, 0 );
+ rModel.mbSelected = rAttribs.getBool( XML_tabSelected, false );
+ rModel.mbRightToLeft = rAttribs.getBool( XML_rightToLeft, false );
+ rModel.mbDefGridColor = rAttribs.getBool( XML_defaultGridColor, true );
+ rModel.mbShowFormulas = rAttribs.getBool( XML_showFormulas, false );
+ rModel.mbShowGrid = rAttribs.getBool( XML_showGridLines, true );
+ rModel.mbShowHeadings = rAttribs.getBool( XML_showRowColHeaders, true );
+ rModel.mbShowZeros = rAttribs.getBool( XML_showZeros, true );
+ rModel.mbShowOutline = rAttribs.getBool( XML_showOutlineSymbols, true );
+}
+
+void SheetViewSettings::importPane( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importPane - missing sheet view model" );
+ if( !maSheetViews.empty() )
+ {
+ SheetViewModel& rModel = *maSheetViews.back();
+ rModel.maSecondPos = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_topLeftCell, OUString() ), getSheetIndex(), false );
+ rModel.mnActivePaneId = rAttribs.getToken( XML_activePane, XML_topLeft );
+ rModel.mnPaneState = rAttribs.getToken( XML_state, XML_split );
+ rModel.mfSplitX = rAttribs.getDouble( XML_xSplit, 0.0 );
+ rModel.mfSplitY = rAttribs.getDouble( XML_ySplit, 0.0 );
+ }
+}
+
+void SheetViewSettings::importSelection( const AttributeList& rAttribs )
+{
+ OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importSelection - missing sheet view model" );
+ if( !maSheetViews.empty() )
+ {
+ // pane this selection belongs to
+ sal_Int32 nPaneId = rAttribs.getToken( XML_pane, XML_topLeft );
+ PaneSelectionModel& rSelData = maSheetViews.back()->createPaneSelection( nPaneId );
+ // cursor position
+ rSelData.maActiveCell = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_activeCell, OUString() ), getSheetIndex(), false );
+ rSelData.mnActiveCellId = rAttribs.getInteger( XML_activeCellId, 0 );
+ // selection
+ rSelData.maSelection.clear();
+ getAddressConverter().convertToCellRangeList( rSelData.maSelection, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), false );
+ }
+}
+
+void SheetViewSettings::importChartSheetView( const AttributeList& rAttribs )
+{
+ SheetViewModel& rModel = *createSheetView();
+ rModel.mnWorkbookViewId = rAttribs.getToken( XML_workbookViewId, 0 );
+ rModel.mnCurrentZoom = rAttribs.getInteger( XML_zoomScale, 100 );
+ rModel.mbSelected = rAttribs.getBool( XML_tabSelected, false );
+ rModel.mbZoomToFit = rAttribs.getBool( XML_zoomToFit, false );
+}
+
+void SheetViewSettings::importSheetView( RecordInputStream& rStrm )
+{
+ SheetViewModel& rModel = *createSheetView();
+ sal_uInt16 nFlags;
+ sal_Int32 nViewType;
+ BinAddress aFirstPos;
+ rStrm >> nFlags >> nViewType >> aFirstPos;
+ rModel.maGridColor.importColorId( rStrm );
+ rModel.mnCurrentZoom = rStrm.readuInt16();
+ rModel.mnNormalZoom = rStrm.readuInt16();
+ rModel.mnSheetLayoutZoom = rStrm.readuInt16();
+ rModel.mnPageLayoutZoom = rStrm.readuInt16();
+ rStrm >> rModel.mnWorkbookViewId;
+
+ rModel.maFirstPos = getAddressConverter().createValidCellAddress( aFirstPos, getSheetIndex(), false );
+ static const sal_Int32 spnViewTypes[] = { XML_normal, XML_pageBreakPreview, XML_pageLayout };
+ rModel.mnViewType = STATIC_ARRAY_SELECT( spnViewTypes, nViewType, XML_normal );
+ rModel.mbSelected = getFlag( nFlags, OOBIN_SHEETVIEW_SELECTED );
+ rModel.mbRightToLeft = getFlag( nFlags, OOBIN_SHEETVIEW_RIGHTTOLEFT );
+ rModel.mbDefGridColor = getFlag( nFlags, OOBIN_SHEETVIEW_DEFGRIDCOLOR );
+ rModel.mbShowFormulas = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWFORMULAS );
+ rModel.mbShowGrid = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWGRID );
+ rModel.mbShowHeadings = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWHEADINGS );
+ rModel.mbShowZeros = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWZEROS );
+ rModel.mbShowOutline = getFlag( nFlags, OOBIN_SHEETVIEW_SHOWOUTLINE );
+}
+
+void SheetViewSettings::importPane( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importPane - missing sheet view model" );
+ if( !maSheetViews.empty() )
+ {
+ SheetViewModel& rModel = *maSheetViews.back();
+
+ BinAddress aSecondPos;
+ sal_Int32 nActivePaneId;
+ sal_uInt8 nFlags;
+ rStrm >> rModel.mfSplitX >> rModel.mfSplitY >> aSecondPos >> nActivePaneId >> nFlags;
+
+ rModel.maSecondPos = getAddressConverter().createValidCellAddress( aSecondPos, getSheetIndex(), false );
+ rModel.mnActivePaneId = lclGetOoxPaneId( nActivePaneId, XML_topLeft );
+ rModel.mnPaneState = getFlagValue( nFlags, OOBIN_PANE_FROZEN, getFlagValue( nFlags, OOBIN_PANE_FROZENNOSPLIT, XML_frozen, XML_frozenSplit ), XML_split );
+ }
+}
+
+void SheetViewSettings::importSelection( RecordInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importSelection - missing sheet view model" );
+ if( !maSheetViews.empty() )
+ {
+ // pane this selection belongs to
+ sal_Int32 nPaneId = rStrm.readInt32();
+ PaneSelectionModel& rPaneSel = maSheetViews.back()->createPaneSelection( lclGetOoxPaneId( nPaneId, -1 ) );
+ // cursor position
+ BinAddress aActiveCell;
+ rStrm >> aActiveCell >> rPaneSel.mnActiveCellId;
+ rPaneSel.maActiveCell = getAddressConverter().createValidCellAddress( aActiveCell, getSheetIndex(), false );
+ // selection
+ BinRangeList aSelection;
+ rStrm >> aSelection;
+ rPaneSel.maSelection.clear();
+ getAddressConverter().convertToCellRangeList( rPaneSel.maSelection, aSelection, getSheetIndex(), false );
+ }
+}
+
+void SheetViewSettings::importChartSheetView( RecordInputStream& rStrm )
+{
+ SheetViewModel& rModel = *createSheetView();
+ sal_uInt16 nFlags;
+ rStrm >> nFlags >> rModel.mnCurrentZoom >> rModel.mnWorkbookViewId;
+
+ rModel.mbSelected = getFlag( nFlags, OOBIN_CHARTSHEETVIEW_SELECTED );
+ rModel.mbZoomToFit = getFlag( nFlags, OOBIN_CHARTSHEETVIEW_ZOOMTOFIT );
+}
+
+void SheetViewSettings::importWindow2( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( maSheetViews.empty(), "SheetViewSettings::importWindow2 - multiple WINDOW2 records" );
+ SheetViewModel& rModel = *createSheetView();
+ if( getBiff() == BIFF2 )
+ {
+ rModel.mbShowFormulas = rStrm.readuInt8() != 0;
+ rModel.mbShowGrid = rStrm.readuInt8() != 0;
+ rModel.mbShowHeadings = rStrm.readuInt8() != 0;
+ rModel.mnPaneState = (rStrm.readuInt8() == 0) ? XML_split : XML_frozen;
+ rModel.mbShowZeros = rStrm.readuInt8() != 0;
+ BinAddress aFirstPos;
+ rStrm >> aFirstPos;
+ rModel.maFirstPos = getAddressConverter().createValidCellAddress( aFirstPos, getSheetIndex(), false );
+ rModel.mbDefGridColor = rStrm.readuInt8() != 0;
+ rModel.maGridColor.importColorRgb( rStrm );
+ }
+ else
+ {
+ sal_uInt16 nFlags;
+ BinAddress aFirstPos;
+ rStrm >> nFlags >> aFirstPos;
+
+ rModel.maFirstPos = getAddressConverter().createValidCellAddress( aFirstPos, getSheetIndex(), false );
+ rModel.mnPaneState = getFlagValue( nFlags, BIFF_WINDOW2_FROZEN, getFlagValue( nFlags, BIFF_WINDOW2_FROZENNOSPLIT, XML_frozen, XML_frozenSplit ), XML_split );
+ rModel.mbSelected = getFlag( nFlags, BIFF_WINDOW2_SELECTED );
+ rModel.mbRightToLeft = getFlag( nFlags, BIFF_WINDOW2_RIGHTTOLEFT );
+ rModel.mbDefGridColor = getFlag( nFlags, BIFF_WINDOW2_DEFGRIDCOLOR );
+ rModel.mbShowFormulas = getFlag( nFlags, BIFF_WINDOW2_SHOWFORMULAS );
+ rModel.mbShowGrid = getFlag( nFlags, BIFF_WINDOW2_SHOWGRID );
+ rModel.mbShowHeadings = getFlag( nFlags, BIFF_WINDOW2_SHOWHEADINGS );
+ rModel.mbShowZeros = getFlag( nFlags, BIFF_WINDOW2_SHOWZEROS );
+ rModel.mbShowOutline = getFlag( nFlags, BIFF_WINDOW2_SHOWOUTLINE );
+
+ if( getBiff() == BIFF8 )
+ {
+ rModel.mnViewType = getFlagValue( nFlags, BIFF_WINDOW2_PAGEBREAKMODE, XML_pageBreakPreview, XML_normal );
+
+ rModel.maGridColor.importColorId( rStrm );
+ // zoom data not included in chart sheets
+ if( (getSheetType() != SHEETTYPE_CHARTSHEET) && (rStrm.getRemaining() >= 6) )
+ {
+ rStrm.skip( 2 );
+ sal_uInt16 nPageZoom, nNormalZoom;
+ rStrm >> nPageZoom >> nNormalZoom;
+ rModel.mnSheetLayoutZoom = nPageZoom;
+ rModel.mnNormalZoom = nNormalZoom;
+ }
+ }
+ else
+ {
+ rModel.maGridColor.importColorRgb( rStrm );
+ }
+ }
+}
+
+void SheetViewSettings::importPane( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importPane - missing leading WINDOW2 record" );
+ if( !maSheetViews.empty() )
+ {
+ sal_uInt8 nActivePaneId;
+ sal_uInt16 nSplitX, nSplitY;
+ BinAddress aSecondPos;
+ rStrm >> nSplitX >> nSplitY >> aSecondPos >> nActivePaneId;
+
+ SheetViewModel& rModel = *maSheetViews.back();
+ rModel.mfSplitX = nSplitX;
+ rModel.mfSplitY = nSplitY;
+ rModel.maSecondPos = getAddressConverter().createValidCellAddress( aSecondPos, getSheetIndex(), false );
+ rModel.mnActivePaneId = lclGetOoxPaneId( nActivePaneId, XML_topLeft );
+ }
+}
+
+void SheetViewSettings::importScl( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importScl - missing leading WINDOW2 record" );
+ if( !maSheetViews.empty() )
+ {
+ sal_uInt16 nNum, nDenom;
+ rStrm >> nNum >> nDenom;
+ OSL_ENSURE( nDenom > 0, "SheetViewSettings::importScl - invalid denominator" );
+ if( nDenom > 0 )
+ maSheetViews.back()->mnCurrentZoom = getLimitedValue< sal_Int32, sal_uInt16 >( (nNum * 100) / nDenom, 10, 400 );
+ }
+}
+
+void SheetViewSettings::importSelection( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importPane - missing leading WINDOW2 record" );
+ if( !maSheetViews.empty() )
+ {
+ // pane this selection belongs to
+ sal_uInt8 nPaneId = rStrm.readuInt8();
+ PaneSelectionModel& rPaneSel = maSheetViews.back()->createPaneSelection( lclGetOoxPaneId( nPaneId, -1 ) );
+ // cursor position
+ BinAddress aActiveCell;
+ sal_uInt16 nActiveCellId;
+ rStrm >> aActiveCell >> nActiveCellId;
+ rPaneSel.maActiveCell = getAddressConverter().createValidCellAddress( aActiveCell, getSheetIndex(), false );
+ rPaneSel.mnActiveCellId = nActiveCellId;
+ // selection
+ rPaneSel.maSelection.clear();
+ BinRangeList aSelection;
+ aSelection.read( rStrm, false );
+ getAddressConverter().convertToCellRangeList( rPaneSel.maSelection, aSelection, getSheetIndex(), false );
+ }
+}
+
+void SheetViewSettings::finalizeImport()
+{
+ // force creation of sheet view model to get the Excel defaults
+ SheetViewModelRef xModel = maSheetViews.empty() ? createSheetView() : maSheetViews.front();
+
+ // #i59590# #158194# special handling for chart sheets (Excel ignores some settings in chart sheets)
+ if( getSheetType() == SHEETTYPE_CHARTSHEET )
+ {
+ xModel->maPaneSelMap.clear();
+ xModel->maFirstPos = xModel->maSecondPos = CellAddress( getSheetIndex(), 0, 0 );
+ xModel->mnViewType = XML_normal;
+ xModel->mnActivePaneId = XML_topLeft;
+ xModel->mnPaneState = XML_split;
+ xModel->mfSplitX = xModel->mfSplitY = 0.0;
+ xModel->mbRightToLeft = false;
+ xModel->mbDefGridColor = true;
+ xModel->mbShowFormulas = false;
+ xModel->mbShowGrid = true;
+ xModel->mbShowHeadings = true;
+ xModel->mbShowZeros = true;
+ xModel->mbShowOutline = true;
+ }
+
+ // mirrored sheet (this is not a view setting in Calc)
+ if( xModel->mbRightToLeft )
+ {
+ PropertySet aPropSet( getSheet() );
+ aPropSet.setProperty( PROP_TableLayout, ::com::sun::star::text::WritingMode2::RL_TB );
+ }
+
+ // sheet selected (active sheet must be selected)
+ bool bSelected = xModel->mbSelected || (getSheetIndex() == getViewSettings().getActiveCalcSheet());
+
+ // visible area and current cursor position (selection not supported via API)
+ CellAddress aFirstPos = xModel->maFirstPos;
+ const PaneSelectionModel* pPaneSel = xModel->getActiveSelection();
+ CellAddress aCursor = pPaneSel ? pPaneSel->maActiveCell : aFirstPos;
+
+ // freeze/split position default
+ sal_Int16 nHSplitMode = API_SPLITMODE_NONE;
+ sal_Int16 nVSplitMode = API_SPLITMODE_NONE;
+ sal_Int32 nHSplitPos = 0;
+ sal_Int32 nVSplitPos = 0;
+ // active pane default
+ sal_Int16 nActivePane = API_SPLITPANE_BOTTOMLEFT;
+
+ // freeze/split position
+ if( (xModel->mnPaneState == XML_frozen) || (xModel->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( (xModel->mfSplitX >= 1.0) && (xModel->maFirstPos.Column + xModel->mfSplitX <= rMaxApiPos.Column) )
+ nHSplitPos = static_cast< sal_Int32 >( xModel->maFirstPos.Column + xModel->mfSplitX );
+ nHSplitMode = (nHSplitPos > 0) ? API_SPLITMODE_FREEZE : API_SPLITMODE_NONE;
+ if( (xModel->mfSplitY >= 1.0) && (xModel->maFirstPos.Row + xModel->mfSplitY <= rMaxApiPos.Row) )
+ nVSplitPos = static_cast< sal_Int32 >( xModel->maFirstPos.Row + xModel->mfSplitY );
+ nVSplitMode = (nVSplitPos > 0) ? API_SPLITMODE_FREEZE : API_SPLITMODE_NONE;
+ }
+ else if( xModel->mnPaneState == XML_split )
+ {
+ // split window: view settings API uses twips...
+ nHSplitPos = getLimitedValue< sal_Int32, double >( xModel->mfSplitX + 0.5, 0, SAL_MAX_INT32 );
+ nHSplitMode = (nHSplitPos > 0) ? API_SPLITMODE_SPLIT : API_SPLITMODE_NONE;
+ nVSplitPos = getLimitedValue< sal_Int32, double >( xModel->mfSplitY + 0.5, 0, SAL_MAX_INT32 );
+ nVSplitMode = (nVSplitPos > 0) ? API_SPLITMODE_SPLIT : API_SPLITMODE_NONE;
+ }
+
+ // active pane
+ switch( xModel->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;
+ }
+
+ // write the sheet view settings into the property sequence
+ PropertyMap aPropMap;
+ aPropMap[ PROP_TableSelected ] <<= bSelected;
+ aPropMap[ PROP_CursorPositionX ] <<= aCursor.Column;
+ aPropMap[ PROP_CursorPositionY ] <<= aCursor.Row;
+ aPropMap[ PROP_HorizontalSplitMode ] <<= nHSplitMode;
+ aPropMap[ PROP_VerticalSplitMode ] <<= nVSplitMode;
+ aPropMap[ PROP_HorizontalSplitPositionTwips ] <<= nHSplitPos;
+ aPropMap[ PROP_VerticalSplitPositionTwips ] <<= nVSplitPos;
+ aPropMap[ PROP_ActiveSplitRange ] <<= nActivePane;
+ aPropMap[ PROP_PositionLeft ] <<= aFirstPos.Column;
+ aPropMap[ PROP_PositionTop ] <<= aFirstPos.Row;
+ aPropMap[ PROP_PositionRight ] <<= xModel->maSecondPos.Column;
+ aPropMap[ PROP_PositionBottom ] <<= ((nVSplitPos > 0) ? xModel->maSecondPos.Row : xModel->maFirstPos.Row);
+ aPropMap[ PROP_ZoomType ] <<= API_ZOOMTYPE_PERCENT;
+ aPropMap[ PROP_ZoomValue ] <<= static_cast< sal_Int16 >( xModel->getNormalZoom() );
+ aPropMap[ PROP_PageViewZoomValue ] <<= static_cast< sal_Int16 >( xModel->getPageBreakZoom() );
+ aPropMap[ PROP_GridColor ] <<= xModel->getGridColor( getBaseFilter() );
+ aPropMap[ PROP_ShowPageBreakPreview ] <<= xModel->isPageBreakPreview();
+ aPropMap[ PROP_ShowFormulas ] <<= xModel->mbShowFormulas;
+ aPropMap[ PROP_ShowGrid ] <<= xModel->mbShowGrid;
+ aPropMap[ PROP_HasColumnRowHeaders ] <<= xModel->mbShowHeadings;
+ aPropMap[ PROP_ShowZeroValues ] <<= xModel->mbShowZeros;
+ aPropMap[ PROP_IsOutlineSymbolsSet ] <<= xModel->mbShowOutline;
+
+ // store sheet view settings in global view settings object
+ getViewSettings().setSheetViewSettings( getSheetIndex(), xModel, Any( aPropMap.makePropertyValueSequence() ) );
+}
+
+// private --------------------------------------------------------------------
+
+SheetViewModelRef SheetViewSettings::createSheetView()
+{
+ SheetViewModelRef xModel( new SheetViewModel );
+ maSheetViews.push_back( xModel );
+ return xModel;
+}
+
+// ============================================================================
+
+WorkbookViewModel::WorkbookViewModel() :
+ 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 ),
+ mbValidOleSize( false )
+{
+}
+
+void ViewSettings::importWorkbookView( const AttributeList& rAttribs )
+{
+ WorkbookViewModel& rModel = createWorkbookView();
+ rModel.mnWinX = rAttribs.getInteger( XML_xWindow, 0 );
+ rModel.mnWinY = rAttribs.getInteger( XML_yWindow, 0 );
+ rModel.mnWinWidth = rAttribs.getInteger( XML_windowWidth, 0 );
+ rModel.mnWinHeight = rAttribs.getInteger( XML_windowHeight, 0 );
+ rModel.mnActiveSheet = rAttribs.getInteger( XML_activeTab, 0 );
+ rModel.mnFirstVisSheet = rAttribs.getInteger( XML_firstSheet, 0 );
+ rModel.mnTabBarWidth = rAttribs.getInteger( XML_tabRatio, 600 );
+ rModel.mnVisibility = rAttribs.getToken( XML_visibility, XML_visible );
+ rModel.mbShowTabBar = rAttribs.getBool( XML_showSheetTabs, true );
+ rModel.mbShowHorScroll = rAttribs.getBool( XML_showHorizontalScroll, true );
+ rModel.mbShowVerScroll = rAttribs.getBool( XML_showVerticalScroll, true );
+ rModel.mbMinimized = rAttribs.getBool( XML_minimized, false );
+}
+
+void ViewSettings::importOleSize( const AttributeList& rAttribs )
+{
+ OUString aRange = rAttribs.getString( XML_ref, OUString() );
+ mbValidOleSize = getAddressConverter().convertToCellRange( maOleSize, aRange, 0, true, false );
+}
+
+void ViewSettings::importWorkbookView( RecordInputStream& rStrm )
+{
+ WorkbookViewModel& rModel = createWorkbookView();
+ sal_uInt8 nFlags;
+ rStrm >> rModel.mnWinX >> rModel.mnWinY >> rModel.mnWinWidth >> rModel.mnWinHeight >> rModel.mnTabBarWidth >> rModel.mnFirstVisSheet >> rModel.mnActiveSheet >> nFlags;
+ rModel.mnVisibility = getFlagValue( nFlags, OOBIN_WBVIEW_HIDDEN, XML_hidden, XML_visible );
+ rModel.mbShowTabBar = getFlag( nFlags, OOBIN_WBVIEW_SHOWTABBAR );
+ rModel.mbShowHorScroll = getFlag( nFlags, OOBIN_WBVIEW_SHOWHORSCROLL );
+ rModel.mbShowVerScroll = getFlag( nFlags, OOBIN_WBVIEW_SHOWVERSCROLL );
+ rModel.mbMinimized = getFlag( nFlags, OOBIN_WBVIEW_MINIMIZED );
+}
+
+void ViewSettings::importOleSize( RecordInputStream& rStrm )
+{
+ BinRange aBinRange;
+ rStrm >> aBinRange;
+ mbValidOleSize = getAddressConverter().convertToCellRange( maOleSize, aBinRange, 0, true, false );
+}
+
+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( maBookViews.empty() || ((getBiff() == BIFF4) && isWorkbookFile()),
+ "ViewSettings::importWindow1 - multiple WINDOW1 records" );
+ WorkbookViewModel& rModel = createWorkbookView();
+ rModel.mnWinX = nWinX;
+ rModel.mnWinY = nWinY;
+ rModel.mnWinWidth = nWinWidth;
+ rModel.mnWinHeight = nWinHeight;
+
+ if( getBiff() <= BIFF4 )
+ {
+ sal_uInt8 nHidden;
+ rStrm >> nHidden;
+ rModel.mnVisibility = (nHidden == 0) ? XML_visible : XML_hidden;
+ }
+ else
+ {
+ sal_uInt16 nFlags, nActiveTab, nFirstVisTab, nSelectCnt, nTabBarWidth;
+ rStrm >> nFlags >> nActiveTab >> nFirstVisTab >> nSelectCnt >> nTabBarWidth;
+
+ rModel.mnActiveSheet = nActiveTab;
+ rModel.mnFirstVisSheet = nFirstVisTab;
+ rModel.mnTabBarWidth = nTabBarWidth;
+ rModel.mnVisibility = getFlagValue( nFlags, BIFF_WINDOW1_HIDDEN, XML_hidden, XML_visible );
+ rModel.mbMinimized = getFlag( nFlags, BIFF_WINDOW1_MINIMIZED );
+ rModel.mbShowHorScroll = getFlag( nFlags, BIFF_WINDOW1_SHOWHORSCROLL );
+ rModel.mbShowVerScroll = getFlag( nFlags, BIFF_WINDOW1_SHOWVERSCROLL );
+ rModel.mbShowTabBar = getFlag( nFlags, BIFF_WINDOW1_SHOWTABBAR );
+ }
+}
+
+void ViewSettings::importOleSize( BiffInputStream& rStrm )
+{
+ rStrm.skip( 2 );
+ BinRange aBinRange;
+ aBinRange.read( rStrm, false );
+ mbValidOleSize = getAddressConverter().convertToCellRange( maOleSize, aBinRange, 0, true, false );
+}
+
+void ViewSettings::setSheetViewSettings( sal_Int16 nSheet, const SheetViewModelRef& rxSheetView, const Any& rProperties )
+{
+ maSheetViews[ nSheet ] = rxSheetView;
+ maSheetProps[ nSheet ] = rProperties;
+}
+
+void ViewSettings::setSheetUsedArea( const CellRangeAddress& rUsedArea )
+{
+ maSheetUsedAreas[ rUsedArea.Sheet ] = rUsedArea;
+}
+
+void ViewSettings::finalizeImport()
+{
+ const WorksheetBuffer& rWorksheets = getWorksheets();
+ if( rWorksheets.getWorksheetCount() <= 0 ) return;
+
+ // force creation of workbook view model to get the Excel defaults
+ const WorkbookViewModel& rModel = maBookViews.empty() ? createWorkbookView() : *maBookViews.front();
+
+ // show object mode is part of workbook settings
+ sal_Int16 nShowMode = getWorkbookSettings().getApiShowObjectMode();
+
+ // view settings for all sheets
+ Reference< XNameContainer > xSheetsNC = ContainerHelper::createNameContainer( getGlobalFactory() );
+ if( !xSheetsNC.is() ) return;
+ for( SheetPropertiesMap::const_iterator aIt = maSheetProps.begin(), aEnd = maSheetProps.end(); aIt != aEnd; ++aIt )
+ ContainerHelper::insertByName( xSheetsNC, rWorksheets.getCalcSheetName( aIt->first ), aIt->second );
+
+ // use active sheet to set sheet properties that are document-global in Calc
+ sal_Int16 nActiveSheet = getActiveCalcSheet();
+ SheetViewModelRef& rxActiveSheetView = maSheetViews[ nActiveSheet ];
+ OSL_ENSURE( rxActiveSheetView.get(), "ViewSettings::finalizeImport - missing active sheet view settings" );
+ if( !rxActiveSheetView )
+ rxActiveSheetView.reset( new SheetViewModel );
+
+ Reference< XIndexContainer > xContainer = ContainerHelper::createIndexContainer( getGlobalFactory() );
+ if( xContainer.is() ) try
+ {
+ PropertyMap aPropMap;
+ aPropMap[ PROP_Tables ] <<= xSheetsNC;
+ aPropMap[ PROP_ActiveTable ] <<= rWorksheets.getCalcSheetName( nActiveSheet );
+ aPropMap[ PROP_HasHorizontalScrollBar ] <<= rModel.mbShowHorScroll;
+ aPropMap[ PROP_HasVerticalScrollBar ] <<= rModel.mbShowVerScroll;
+ aPropMap[ PROP_HasSheetTabs ] <<= rModel.mbShowTabBar;
+ aPropMap[ PROP_RelativeHorizontalTabbarWidth ] <<= double( rModel.mnTabBarWidth / 1000.0 );
+ aPropMap[ PROP_ShowObjects ] <<= nShowMode;
+ aPropMap[ PROP_ShowCharts ] <<= nShowMode;
+ aPropMap[ PROP_ShowDrawing ] <<= nShowMode;
+ aPropMap[ PROP_GridColor ] <<= rxActiveSheetView->getGridColor( getBaseFilter() );
+ aPropMap[ PROP_ShowPageBreakPreview ] <<= rxActiveSheetView->isPageBreakPreview();
+ aPropMap[ PROP_ShowFormulas ] <<= rxActiveSheetView->mbShowFormulas;
+ aPropMap[ PROP_ShowGrid ] <<= rxActiveSheetView->mbShowGrid;
+ aPropMap[ PROP_HasColumnRowHeaders ] <<= rxActiveSheetView->mbShowHeadings;
+ aPropMap[ PROP_ShowZeroValues ] <<= rxActiveSheetView->mbShowZeros;
+ aPropMap[ PROP_IsOutlineSymbolsSet ] <<= rxActiveSheetView->mbShowOutline;
+
+ xContainer->insertByIndex( 0, Any( aPropMap.makePropertyValueSequence() ) );
+ 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" );
+ }
+
+ /* Set visible area to be used if this document is an embedded OLE object.
+ #i44077# If a new OLE object is inserted from file, there is no OLESIZE
+ record in the Excel file. In this case, use the used area calculated
+ from file contents (used cells and drawing objects). */
+ maOleSize.Sheet = nActiveSheet;
+ const CellRangeAddress* pVisibleArea = mbValidOleSize ?
+ &maOleSize : ContainerHelper::getMapElement( maSheetUsedAreas, nActiveSheet );
+ if( pVisibleArea )
+ {
+ // calculate the visible area in units of 1/100 mm
+ PropertySet aRangeProp( getCellRangeFromDoc( *pVisibleArea ) );
+ Point aPos;
+ Size aSize;
+ if( aRangeProp.getProperty( aPos, PROP_Position ) && aRangeProp.getProperty( aSize, PROP_Size ) )
+ {
+ // set the visible area as sequence of long at the media descriptor
+ Sequence< sal_Int32 > aWinExtent( 4 );
+ aWinExtent[ 0 ] = aPos.X;
+ aWinExtent[ 1 ] = aPos.Y;
+ aWinExtent[ 2 ] = aPos.X + aSize.Width;
+ aWinExtent[ 3 ] = aPos.Y + aSize.Height;
+ getBaseFilter().getMediaDescriptor()[ CREATE_OUSTRING( "WinExtent" ) ] <<= aWinExtent;
+ }
+ }
+}
+
+sal_Int16 ViewSettings::getActiveCalcSheet() const
+{
+ return maBookViews.empty() ? 0 : ::std::max< sal_Int16 >( getWorksheets().getCalcSheetIndex( maBookViews.front()->mnActiveSheet ), 0 );
+}
+
+// private --------------------------------------------------------------------
+
+WorkbookViewModel& ViewSettings::createWorkbookView()
+{
+ WorkbookViewModelRef xModel( new WorkbookViewModel );
+ maBookViews.push_back( xModel );
+ return *xModel;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/webquerybuffer.cxx b/oox/source/xls/webquerybuffer.cxx
new file mode 100644
index 000000000000..8bedc8c66d6a
--- /dev/null
+++ b/oox/source/xls/webquerybuffer.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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, OUString() );
+ 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.getUnsigned( XML_id, 0 );
+ if ( maConnections.size() < (nId + 1) )
+ maConnections.resize(nId + 1);
+
+ Connection aConn;
+ aConn.maName = rAttribs.getString( XML_name, OUString() );
+ 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, OUString() );
+
+ // 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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/workbookfragment.cxx b/oox/source/xls/workbookfragment.cxx
new file mode 100644
index 000000000000..bb84b49e7cc5
--- /dev/null
+++ b/oox/source/xls/workbookfragment.cxx
@@ -0,0 +1,740 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#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/ole/olestorage.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/drawingml/themefragmenthandler.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/chartsheetfragment.hxx"
+#include "oox/xls/connectionsfragment.hxx"
+#include "oox/xls/externallinkbuffer.hxx"
+#include "oox/xls/externallinkfragment.hxx"
+#include "oox/xls/pivotcachebuffer.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::uno::UNO_SET_THROW;
+using ::com::sun::star::io::XInputStream;
+using ::com::sun::star::table::CellAddress;
+using ::oox::core::ContextHandlerRef;
+using ::oox::core::FragmentHandlerRef;
+using ::oox::core::RecordInfo;
+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.
+
+} // namespace
+
+// ============================================================================
+
+OoxWorkbookFragment::OoxWorkbookFragment(
+ const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+ OoxWorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxWorkbookFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nElement == XLS_TOKEN( workbook ) ) return this;
+ break;
+
+ case XLS_TOKEN( workbook ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( sheets ):
+ case XLS_TOKEN( bookViews ):
+ case XLS_TOKEN( externalReferences ):
+ case XLS_TOKEN( definedNames ):
+ case XLS_TOKEN( pivotCaches ): return this;
+
+ case XLS_TOKEN( fileSharing ): getWorkbookSettings().importFileSharing( rAttribs ); break;
+ case XLS_TOKEN( workbookPr ): getWorkbookSettings().importWorkbookPr( rAttribs ); break;
+ case XLS_TOKEN( calcPr ): getWorkbookSettings().importCalcPr( rAttribs ); break;
+ case XLS_TOKEN( oleSize ): getViewSettings().importOleSize( rAttribs ); break;
+ }
+ break;
+
+ case XLS_TOKEN( sheets ):
+ if( nElement == XLS_TOKEN( sheet ) ) getWorksheets().importSheet( rAttribs );
+ break;
+ case XLS_TOKEN( bookViews ):
+ if( nElement == XLS_TOKEN( workbookView ) ) getViewSettings().importWorkbookView( rAttribs );
+ break;
+ case XLS_TOKEN( externalReferences ):
+ if( nElement == XLS_TOKEN( externalReference ) ) importExternalReference( rAttribs );
+ break;
+ case XLS_TOKEN( definedNames ):
+ if( nElement == XLS_TOKEN( definedName ) ) { importDefinedName( rAttribs ); return this; } // collect formula
+ break;
+ case XLS_TOKEN( pivotCaches ):
+ if( nElement == XLS_TOKEN( pivotCache ) ) importPivotCache( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+void OoxWorkbookFragment::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( definedName ):
+ if( mxCurrName.get() ) mxCurrName->setFormula( rChars );
+ break;
+ }
+}
+
+ContextHandlerRef OoxWorkbookFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_WORKBOOK ) return this;
+ break;
+
+ case OOBIN_ID_WORKBOOK:
+ switch( nRecId )
+ {
+ case OOBIN_ID_SHEETS:
+ case OOBIN_ID_BOOKVIEWS:
+ case OOBIN_ID_EXTERNALREFS:
+ case OOBIN_ID_PIVOTCACHES: return this;
+
+ case OOBIN_ID_FILESHARING: getWorkbookSettings().importFileSharing( rStrm ); break;
+ case OOBIN_ID_WORKBOOKPR: getWorkbookSettings().importWorkbookPr( rStrm ); break;
+ case OOBIN_ID_CALCPR: getWorkbookSettings().importCalcPr( rStrm ); break;
+ case OOBIN_ID_OLESIZE: getViewSettings().importOleSize( rStrm ); break;
+ case OOBIN_ID_DEFINEDNAME: getDefinedNames().importDefinedName( rStrm ); break;
+ }
+ break;
+
+ case OOBIN_ID_SHEETS:
+ if( nRecId == OOBIN_ID_SHEET ) getWorksheets().importSheet( rStrm );
+ break;
+ case OOBIN_ID_BOOKVIEWS:
+ if( nRecId == OOBIN_ID_WORKBOOKVIEW ) getViewSettings().importWorkbookView( rStrm );
+ break;
+
+ case OOBIN_ID_EXTERNALREFS:
+ switch( nRecId )
+ {
+ case OOBIN_ID_EXTERNALREF: importExternalRef( rStrm ); break;
+ case OOBIN_ID_EXTERNALSELF: getExternalLinks().importExternalSelf( rStrm ); break;
+ case OOBIN_ID_EXTERNALSAME: getExternalLinks().importExternalSame( rStrm ); break;
+ case OOBIN_ID_EXTERNALADDIN: getExternalLinks().importExternalAddin( rStrm ); break;
+ case OOBIN_ID_EXTERNALSHEETS: getExternalLinks().importExternalSheets( rStrm ); break;
+ }
+ break;
+
+ case OOBIN_ID_PIVOTCACHES:
+ if( nRecId == OOBIN_ID_PIVOTCACHE ) importPivotCache( rStrm );
+ }
+ return 0;
+}
+
+// oox.core.FragmentHandler2 interface ----------------------------------------
+
+const RecordInfo* OoxWorkbookFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_BOOKVIEWS, OOBIN_ID_BOOKVIEWS + 1 },
+ { OOBIN_ID_EXTERNALREFS, OOBIN_ID_EXTERNALREFS + 1 },
+ { OOBIN_ID_FUNCTIONGROUPS, OOBIN_ID_FUNCTIONGROUPS + 2 },
+ { OOBIN_ID_PIVOTCACHE, OOBIN_ID_PIVOTCACHE + 1 },
+ { OOBIN_ID_PIVOTCACHES, OOBIN_ID_PIVOTCACHES + 1 },
+ { OOBIN_ID_SHEETS, OOBIN_ID_SHEETS + 1 },
+ { OOBIN_ID_WORKBOOK, OOBIN_ID_WORKBOOK + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+void OoxWorkbookFragment::finalizeImport()
+{
+ ISegmentProgressBarRef xGlobalSegment = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
+
+ // read the theme substream
+ OUString aThemeFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATIONSTYPE( "theme" ) );
+ if( aThemeFragmentPath.getLength() > 0 )
+ importOoxFragment( new ThemeFragmentHandler( getFilter(), aThemeFragmentPath, getTheme() ) );
+ xGlobalSegment->setPosition( 0.25 );
+
+ // read the styles substream (requires finalized theme buffer)
+ OUString aStylesFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATIONSTYPE( "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 = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATIONSTYPE( "sharedStrings" ) );
+ if( aSstFragmentPath.getLength() > 0 )
+ importOoxFragment( new OoxSharedStringsFragment( *this, aSstFragmentPath ) );
+ xGlobalSegment->setPosition( 0.75 );
+
+ // read the connections substream
+ OUString aConnFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATIONSTYPE( "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::vector< FragmentHandlerRef > SheetFragmentVector;
+ SheetFragmentVector aSheetFragments;
+ WorksheetBuffer& rWorksheets = getWorksheets();
+ sal_Int32 nWorksheetCount = rWorksheets.getWorksheetCount();
+ for( sal_Int32 nWorksheet = 0; nWorksheet < nWorksheetCount; ++nWorksheet )
+ {
+ sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet );
+ const Relation* pRelation = getRelations().getRelationFromRelId( rWorksheets.getWorksheetRelId( nWorksheet ) );
+ if( (nCalcSheet >= 0) && pRelation )
+ {
+ // get fragment path of the sheet
+ OUString aFragmentPath = getFragmentPathFromRelation( *pRelation );
+ OSL_ENSURE( aFragmentPath.getLength() > 0, "OoxWorkbookFragment::finalizeImport - cannot access sheet fragment" );
+ if( aFragmentPath.getLength() > 0 )
+ {
+ ::rtl::Reference< OoxWorksheetFragmentBase > xFragment;
+ double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
+ ISegmentProgressBarRef xSheetSegment = getProgressBar().createSegment( fSegmentLength );
+
+ // create the fragment according to the sheet type
+ if( pRelation->maType == CREATE_OFFICEDOC_RELATIONSTYPE( "worksheet" ) )
+ {
+ xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_WORKSHEET, nCalcSheet ) );
+ }
+ else if( pRelation->maType == CREATE_OFFICEDOC_RELATIONSTYPE( "chartsheet" ) )
+ {
+ xFragment.set( new OoxChartsheetFragment( *this, aFragmentPath, xSheetSegment, nCalcSheet ) );
+ }
+ else if( (pRelation->maType == CREATE_MSOFFICE_RELATIONSTYPE( "xlMacrosheet" )) ||
+ (pRelation->maType == CREATE_MSOFFICE_RELATIONSTYPE( "xlIntlMacrosheet" )) )
+ {
+ xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_MACROSHEET, nCalcSheet ) );
+ }
+ else if( pRelation->maType == CREATE_OFFICEDOC_RELATIONSTYPE( "dialogsheet" ) )
+ {
+ xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_DIALOGSHEET, nCalcSheet ) );
+ }
+
+ // 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.push_back( xFragment.get() );
+ }
+ }
+ }
+
+ // create all defined names and database ranges
+ getDefinedNames().finalizeImport();
+ getTables().finalizeImport();
+
+ // load all worksheets
+ for( SheetFragmentVector::iterator aIt = aSheetFragments.begin(), aEnd = aSheetFragments.end(); aIt != aEnd; ++aIt )
+ {
+ // import the sheet fragment
+ importOoxFragment( *aIt );
+ // delete fragment object, will free all allocated sheet buffers
+ aIt->clear();
+ }
+
+ // open the VBA project storage
+ OUString aVbaFragmentPath = getFragmentPathFromFirstType( CREATE_MSOFFICE_RELATIONSTYPE( "vbaProject" ) );
+ if( aVbaFragmentPath.getLength() > 0 )
+ {
+ Reference< XInputStream > xInStrm = getBaseFilter().openInputStream( aVbaFragmentPath );
+ if( xInStrm.is() )
+ setVbaProjectStorage( StorageRef( new ::oox::ole::OleStorage( getGlobalFactory(), xInStrm, false ) ) );
+ }
+
+ // final conversions, e.g. calculation settings and view settings
+ finalizeWorkbookImport();
+}
+
+// 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 )
+{
+ sal_Int32 nCacheId = rAttribs.getInteger( XML_cacheId, -1 );
+ OUString aRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
+ importPivotCacheDefFragment( aRelId, nCacheId );
+}
+
+void OoxWorkbookFragment::importExternalRef( RecordInputStream& rStrm )
+{
+ if( ExternalLink* pExtLink = getExternalLinks().importExternalRef( rStrm ).get() )
+ importExternalLinkFragment( *pExtLink );
+}
+
+void OoxWorkbookFragment::importPivotCache( RecordInputStream& rStrm )
+{
+ sal_Int32 nCacheId = rStrm.readInt32();
+ OUString aRelId = rStrm.readString();
+ importPivotCacheDefFragment( aRelId, nCacheId );
+}
+
+void OoxWorkbookFragment::importExternalLinkFragment( ExternalLink& rExtLink )
+{
+ OUString aFragmentPath = getFragmentPathFromRelId( rExtLink.getRelId() );
+ if( aFragmentPath.getLength() > 0 )
+ importOoxFragment( new OoxExternalLinkFragment( *this, aFragmentPath, rExtLink ) );
+}
+
+void OoxWorkbookFragment::importPivotCacheDefFragment( const OUString& rRelId, sal_Int32 nCacheId )
+{
+ // pivot caches will be imported on demand, here we just store the fragment path in the buffer
+ getPivotCaches().registerPivotCacheFragment( nCacheId, getFragmentPathFromRelId( rRelId ) );
+}
+
+// ============================================================================
+
+BiffWorkbookFragment::BiffWorkbookFragment( const WorkbookHelper& rHelper, const OUString& rStrmName ) :
+ BiffWorkbookFragmentBase( rHelper, rStrmName )
+{
+}
+
+bool BiffWorkbookFragment::importFragment()
+{
+ bool bRet = false;
+
+ BiffFragmentType eFragment = startFragment( 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( *xGlobalsProgress );
+ // load sheet fragments (do not return false in bRet on missing/broken sheets)
+ WorksheetBuffer& rWorksheets = getWorksheets();
+ bool bNextSheet = bRet;
+ for( sal_Int32 nWorksheet = 0, nWorksheetCount = rWorksheets.getWorksheetCount(); bNextSheet && (nWorksheet < nWorksheetCount); ++nWorksheet )
+ {
+ // try to start a new sheet fragment
+ double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
+ ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength );
+ BiffFragmentType eSheetFragment = startFragment( getBiff(), rWorksheets.getBiffRecordHandle( nWorksheet ) );
+ sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet );
+ bNextSheet = importSheetFragment( *xSheetProgress, eSheetFragment, nCalcSheet );
+ }
+ }
+ break;
+
+ case BIFF_FRAGMENT_WORKSPACE:
+ {
+ bRet = importWorkspaceFragment();
+ // sheets are embedded in workspace fragment, nothing to do here
+ }
+ break;
+
+ case BIFF_FRAGMENT_WORKSHEET:
+ case BIFF_FRAGMENT_CHARTSHEET:
+ case BIFF_FRAGMENT_MACROSHEET:
+ {
+ /* Single sheet without globals
+ - #i62752# possible in all BIFF versions
+ - do not return false in bRet on missing/broken sheets. */
+ getWorksheets().initializeSingleSheet();
+ importSheetFragment( getProgressBar(), eFragment, 0 );
+ // success, even if stream is broken
+ bRet = true;
+ }
+ break;
+
+ default:;
+ }
+
+ // final conversions, e.g. calculation settings and view settings
+ if( bRet )
+ finalizeWorkbookImport();
+
+ return bRet;
+}
+
+bool BiffWorkbookFragment::importWorkspaceFragment()
+{
+ // 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 && mrStrm.startNextRecord() && (mrStrm.getRecId() != BIFF_ID_EOF) )
+ {
+ switch( mrStrm.getRecId() )
+ {
+ case BIFF_ID_SHEET: rWorksheets.importSheet( mrStrm ); break;
+ case BIFF_ID_CODEPAGE: setCodePage( mrStrm.readuInt16() ); break;
+ case BIFF_ID_FILEPASS: bRet = getCodecHelper().importFilePass( mrStrm ); break;
+ case BIFF_ID_SHEETHEADER: mrStrm.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 nWorksheet = 0, nWorksheetCount = rWorksheets.getWorksheetCount(); bNextSheet && (nWorksheet < nWorksheetCount); ++nWorksheet )
+ {
+ // try to start a new sheet fragment (with leading SHEETHEADER record)
+ bNextSheet = mrStrm.startNextRecord() && (mrStrm.getRecId() == BIFF_ID_SHEETHEADER);
+ if( bNextSheet )
+ {
+ double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
+ ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength );
+ /* Read current sheet name (sheet substreams may not be in the
+ same order as SHEET records are). */
+ mrStrm.skip( 4 );
+ OUString aSheetName = mrStrm.readByteStringUC( false, getTextEncoding() );
+ sal_Int16 nCurrSheet = rWorksheets.getCalcSheetIndex( aSheetName );
+ // load the sheet fragment records
+ BiffFragmentType eSheetFragment = startFragment( getBiff() );
+ bNextSheet = importSheetFragment( *xSheetProgress, eSheetFragment, nCurrSheet );
+ // do not return false in bRet on missing/broken sheets
+ }
+ }
+
+ return bRet;
+}
+
+bool BiffWorkbookFragment::importGlobalsFragment( ISegmentProgressBar& rProgressBar )
+{
+ WorkbookSettings& rWorkbookSett = getWorkbookSettings();
+ ViewSettings& rViewSett = getViewSettings();
+ SharedStringsBuffer& rSharedStrings = getSharedStrings();
+ StylesBuffer& rStyles = getStyles();
+ WorksheetBuffer& rWorksheets = getWorksheets();
+ PivotCacheBuffer& rPivotCaches = getPivotCaches();
+ bool bHasVbaProject = false;
+ bool bEmptyVbaProject = false;
+
+ // 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 && mrStrm.startNextRecord() )
+ {
+ sal_uInt16 nRecId = mrStrm.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 == BIFF_ID_EOF) )
+ {
+ bLoop = false;
+ }
+ else switch( nRecId )
+ {
+ // records in all BIFF versions
+ case BIFF_ID_CODEPAGE: setCodePage( mrStrm.readuInt16() ); break;
+ case BIFF_ID_DATEMODE: rWorkbookSett.importDateMode( mrStrm ); break;
+ case BIFF_ID_FILEPASS: bRet = getCodecHelper().importFilePass( mrStrm ); break;
+ case BIFF_ID_PRECISION: rWorkbookSett.importPrecision( mrStrm ); break;
+ case BIFF_ID_WINDOW1: rViewSett.importWindow1( mrStrm ); 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( mrStrm ); break;
+ case BIFF_ID_FONTCOLOR: rStyles.importFontColor( mrStrm ); break;
+ case BIFF2_ID_FORMAT: rStyles.importFormat( mrStrm ); break;
+ case BIFF2_ID_XF: rStyles.importXf( mrStrm ); 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 BIFF_ID_FILESHARING: rWorkbookSett.importFileSharing( mrStrm ); break;
+ case BIFF3_ID_FONT: rStyles.importFont( mrStrm ); break;
+ case BIFF2_ID_FORMAT: rStyles.importFormat( mrStrm ); break;
+ case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( mrStrm ); break;
+ case BIFF_ID_PALETTE: rStyles.importPalette( mrStrm ); break;
+ case BIFF_ID_STYLE: rStyles.importStyle( mrStrm ); break;
+ case BIFF_ID_XCT: bExtLinkRec = true; break;
+ case BIFF3_ID_XF: rStyles.importXf( mrStrm ); 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 BIFF_ID_FILESHARING: rWorkbookSett.importFileSharing( mrStrm ); break;
+ case BIFF3_ID_FONT: rStyles.importFont( mrStrm ); break;
+ case BIFF4_ID_FORMAT: rStyles.importFormat( mrStrm ); break;
+ case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( mrStrm ); break;
+ case BIFF_ID_PALETTE: rStyles.importPalette( mrStrm ); break;
+ case BIFF_ID_STYLE: rStyles.importStyle( mrStrm ); break;
+ case BIFF_ID_XCT: bExtLinkRec = true; break;
+ case BIFF4_ID_XF: rStyles.importXf( mrStrm ); break;
+ }
+ break;
+
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF_ID_BOOKBOOL: rWorkbookSett.importBookBool( mrStrm ); 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 BIFF_ID_FILESHARING: rWorkbookSett.importFileSharing( mrStrm ); break;
+ case BIFF5_ID_FONT: rStyles.importFont( mrStrm ); break;
+ case BIFF4_ID_FORMAT: rStyles.importFormat( mrStrm ); break;
+ case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( mrStrm ); break;
+ case BIFF_ID_OLESIZE: rViewSett.importOleSize( mrStrm ); break;
+ case BIFF_ID_PALETTE: rStyles.importPalette( mrStrm ); break;
+ case BIFF_ID_PIVOTCACHE: rPivotCaches.importPivotCacheRef( mrStrm ); break;
+ case BIFF_ID_SHEET: rWorksheets.importSheet( mrStrm ); break;
+ case BIFF_ID_STYLE: rStyles.importStyle( mrStrm ); break;
+ case BIFF_ID_XCT: bExtLinkRec = true; break;
+ case BIFF5_ID_XF: rStyles.importXf( mrStrm ); break;
+ }
+ break;
+
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF_ID_BOOKBOOL: rWorkbookSett.importBookBool( mrStrm ); break;
+ case BIFF_ID_CODENAME: rWorkbookSett.importCodeName( mrStrm ); 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 BIFF_ID_FILESHARING: rWorkbookSett.importFileSharing( mrStrm ); break;
+ case BIFF5_ID_FONT: rStyles.importFont( mrStrm ); break;
+ case BIFF4_ID_FORMAT: rStyles.importFormat( mrStrm ); break;
+ case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( mrStrm ); break;
+ case BIFF_ID_OLESIZE: rViewSett.importOleSize( mrStrm ); break;
+ case BIFF_ID_PALETTE: rStyles.importPalette( mrStrm ); break;
+ case BIFF_ID_PIVOTCACHE: rPivotCaches.importPivotCacheRef( mrStrm ); break;
+ case BIFF_ID_SHEET: rWorksheets.importSheet( mrStrm ); break;
+ case BIFF_ID_SST: rSharedStrings.importSst( mrStrm ); break;
+ case BIFF_ID_STYLE: rStyles.importStyle( mrStrm ); break;
+ case BIFF_ID_USESELFS: rWorkbookSett.importUsesElfs( mrStrm ); break;
+ case BIFF_ID_VBAPROJECT: bHasVbaProject = true; break;
+ case BIFF_ID_VBAPROJECTEMPTY: bEmptyVbaProject = true; break;
+ case BIFF_ID_XCT: bExtLinkRec = true; break;
+ case BIFF5_ID_XF: rStyles.importXf( mrStrm ); break;
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+ }
+
+ if( bExtLinkRec )
+ aExtLinkRecs.push_back( mrStrm.getRecHandle() );
+ }
+
+ // finalize global buffers
+ rProgressBar.setPosition( 0.5 );
+ if( bRet )
+ {
+ 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 = mrStrm.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) && mrStrm.startRecordByHandle( *aIt ); ++aIt )
+ aLinkFragment.importRecord();
+ // finalize global buffers
+ aLinkFragment.finalizeImport();
+ // seek back to the EOF record of the workbook globals fragment
+ bRet = mrStrm.startRecordByHandle( nEofHandle );
+ }
+
+ // open the VBA project storage
+ if( bHasVbaProject && !bEmptyVbaProject )
+ setVbaProjectStorage( getBaseFilter().openSubStorage( CREATE_OUSTRING( "_VBA_PROJECT_CUR" ), false ) );
+
+ // #i56376# missing EOF - rewind before worksheet BOF record (see above)
+ if( bRet && isBofRecord() )
+ mrStrm.rewindRecord();
+
+ rProgressBar.setPosition( 1.0 );
+ return bRet;
+}
+
+bool BiffWorkbookFragment::importSheetFragment( ISegmentProgressBar& rProgressBar, BiffFragmentType eFragment, sal_Int16 nCalcSheet )
+{
+ // no Calc sheet - skip the fragment
+ if( nCalcSheet < 0 )
+ return skipFragment();
+
+ // find the sheet type for this fragment
+ WorksheetType eSheetType = SHEETTYPE_EMPTYSHEET;
+ switch( eFragment )
+ {
+ case BIFF_FRAGMENT_WORKSHEET: eSheetType = SHEETTYPE_WORKSHEET; break;
+ case BIFF_FRAGMENT_CHARTSHEET: eSheetType = SHEETTYPE_CHARTSHEET; break;
+ case BIFF_FRAGMENT_MACROSHEET: eSheetType = SHEETTYPE_MACROSHEET; break;
+ case BIFF_FRAGMENT_MODULESHEET: eSheetType = SHEETTYPE_MODULESHEET; break;
+ case BIFF_FRAGMENT_EMPTYSHEET: eSheetType = SHEETTYPE_EMPTYSHEET; break;
+ default: return false;
+ }
+
+ /* #i11183# Clear buffers that are used per-sheet, e.g. external links in
+ BIFF4W and BIFF5 files, or defined names in BIFF4W files. */
+ createBuffersPerSheet( nCalcSheet );
+
+ // preprocess some records
+ switch( getBiff() )
+ {
+ // load the workbook globals fragment records in BIFF2-BIFF4
+ case BIFF2:
+ case BIFF3:
+ case BIFF4:
+ {
+ // remember current record to seek back below
+ sal_Int64 nRecHandle = mrStrm.getRecHandle();
+ // import the global records
+ ISegmentProgressBarRef xGlobalsProgress = rProgressBar.createSegment( PROGRESS_LENGTH_GLOBALS );
+ importGlobalsFragment( *xGlobalsProgress );
+ // rewind stream to fragment BOF record
+ mrStrm.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 = mrStrm.getRecHandle();
+ // fragment implementing import of external link records
+ BiffExternalLinkFragment( *this, false ).importFragment();
+ // rewind stream to fragment BOF record
+ mrStrm.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_MACROSHEET:
+ case SHEETTYPE_DIALOGSHEET:
+ xFragment.reset( new BiffWorksheetFragment( *this, xSheetProgress, eSheetType, nCalcSheet ) );
+ break;
+ case SHEETTYPE_CHARTSHEET:
+ xFragment.reset( new BiffChartsheetFragment( *this, xSheetProgress, nCalcSheet ) );
+ break;
+ case SHEETTYPE_MODULESHEET:
+ case SHEETTYPE_EMPTYSHEET:
+ xFragment.reset( new BiffSkipWorksheetFragment( *this, xSheetProgress, nCalcSheet ) );
+ break;
+ }
+ // load the sheet fragment records
+ return xFragment->isValidSheet() && xFragment->importFragment();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/workbookhelper.cxx b/oox/source/xls/workbookhelper.cxx
new file mode 100644
index 000000000000..f8a49c435244
--- /dev/null
+++ b/oox/source/xls/workbookhelper.cxx
@@ -0,0 +1,1007 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/workbookhelper.hxx"
+#include <osl/thread.h>
+#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/table/CellAddress.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XNamedRange.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/sheet/XDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XExternalDocLinks.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include "properties.hxx"
+#include "oox/helper/progressbar.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/ole/vbaproject.hxx"
+#include "oox/drawingml/theme.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/biffcodec.hxx"
+#include "oox/xls/defnamesbuffer.hxx"
+#include "oox/xls/excelchartconverter.hxx"
+#include "oox/xls/excelfilter.hxx"
+#include "oox/xls/externallinkbuffer.hxx"
+#include "oox/xls/formulaparser.hxx"
+#include "oox/xls/pagesettings.hxx"
+#include "oox/xls/pivotcachebuffer.hxx"
+#include "oox/xls/pivottablebuffer.hxx"
+#include "oox/xls/scenariobuffer.hxx"
+#include "oox/xls/sharedstringsbuffer.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/tablebuffer.hxx"
+#include "oox/xls/themebuffer.hxx"
+#include "oox/xls/unitconverter.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::uno::UNO_SET_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::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::table::XCell;
+using ::com::sun::star::table::XCellRange;
+using ::com::sun::star::sheet::XSpreadsheetDocument;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::sheet::XNamedRange;
+using ::com::sun::star::sheet::XNamedRanges;
+using ::com::sun::star::sheet::XDatabaseRanges;
+using ::com::sun::star::sheet::XExternalDocLinks;
+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;
+using ::oox::drawingml::Theme;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+bool IgnoreCaseCompare::operator()( const OUString& rName1, const OUString& rName2 ) const
+{
+ // there is no wrapper in rtl::OUString, TODO: compare with collator
+ return ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
+ rName1.getStr(), rName1.getLength(), rName2.getStr(), rName2.getLength() ) < 0;
+}
+
+// ============================================================================
+
+class WorkbookData
+{
+public:
+ explicit WorkbookData( ExcelFilter& rFilter );
+ explicit WorkbookData( ExcelBiffFilter& 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; }
+ /** Returns the index of the current sheet in the Calc document. */
+ inline sal_Int16 getCurrentSheetIndex() const { return mnCurrSheet; }
+ /** Sets the index of the current sheet in the Calc document. */
+ inline void setCurrentSheetIndex( sal_Int16 nSheet ) { mnCurrSheet = nSheet; }
+ /** Returns the VBA project storage. */
+ inline StorageRef getVbaProjectStorage() const { return mxVbaPrjStrg; }
+ /** Sets the VBA project storage. */
+ inline void setVbaProjectStorage( const StorageRef& rxVbaPrjStrg ) { mxVbaPrjStrg = rxVbaPrjStrg; }
+
+ // document model ---------------------------------------------------------
+
+ /** Returns a reference to the source/target spreadsheet document model. */
+ inline Reference< XSpreadsheetDocument > getDocument() const { return mxDoc; }
+ /** 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 external documents from the Calc document. */
+ Reference< XExternalDocLinks > getExternalDocLinks() 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 and returns a defined name on-the-fly in the Calc document. */
+ Reference< XNamedRange > createNamedRangeObject( OUString& orName, sal_Int32 nNameFlags ) const;
+ /** Creates and returns a com.sun.star.style.Style object for cells or pages. */
+ Reference< XStyle > createStyleObject( OUString& orStyleName, bool bPageStyle ) const;
+
+ // 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 scenarios collection. */
+ inline ScenarioBuffer& getScenarios() const { return *mxScenarios; }
+ /** Returns the web queries. */
+ inline WebQueryBuffer& getWebQueries() const { return *mxWebQueries; }
+ /** Returns the collection of pivot caches. */
+ inline PivotCacheBuffer& getPivotCaches() const { return *mxPivotCaches; }
+ /** Returns the collection of pivot tables. */
+ inline PivotTableBuffer& getPivotTables() { 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 chart object converter. */
+ inline ExcelChartConverter& getChartConverter() const { return *mxChartConverter; }
+ /** Returns the page/print settings converter. */
+ inline PageSettingsConverter& getPageSettingsConverter() const { return *mxPageSettConverter; }
+
+ // 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( sal_Int16 nSheet );
+ /** Returns the codec helper that stores the encoder/decoder object. */
+ inline BiffCodecHelper& getCodecHelper() { return *mxCodecHelper; }
+
+private:
+ /** Initializes some basic members and sets needed document properties. */
+ void initialize( bool bWorkbookFile );
+ /** 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 ::boost::shared_ptr< ThemeBuffer > ThemeBfrRef;
+ 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< ScenarioBuffer > ScenarioBfrPtr;
+ typedef ::std::auto_ptr< WebQueryBuffer > WebQueryBfrPtr;
+ typedef ::std::auto_ptr< PivotCacheBuffer > PivotCacheBfrPtr;
+ typedef ::std::auto_ptr< PivotTableBuffer > PivotTableBfrPtr;
+ typedef ::std::auto_ptr< FormulaParser > FormulaParserPtr;
+ typedef ::std::auto_ptr< UnitConverter > UnitConvPtr;
+ typedef ::std::auto_ptr< AddressConverter > AddressConvPtr;
+ typedef ::std::auto_ptr< ExcelChartConverter > ExcelChartConvPtr;
+ typedef ::std::auto_ptr< PageSettingsConverter > PageSettConvPtr;
+ typedef ::std::auto_ptr< BiffCodecHelper > BiffCodecHelperPtr;
+
+ OUString maCellStyles; /// Style family name for cell styles.
+ OUString maPageStyles; /// Style family 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.
+ ExcelFilterBase& mrExcelBase; /// Base object for registration of this structure.
+ FilterType meFilterType; /// File type of the filter.
+ ProgressBarPtr mxProgressBar; /// The progress bar.
+ StorageRef mxVbaPrjStrg; /// Storage containing the VBA project.
+ sal_Int16 mnCurrSheet; /// Current sheet index in Calc dcument.
+ bool mbWorkbook; /// True = multi-sheet file.
+
+ // buffers
+ WorkbookSettPtr mxWorkbookSettings; /// Global workbook settings.
+ ViewSettingsPtr mxViewSettings; /// Workbook and sheet view settings.
+ WorksheetBfrPtr mxWorksheets; /// Sheet info buffer.
+ ThemeBfrRef 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).
+ ScenarioBfrPtr mxScenarios; /// All scenarios.
+ WebQueryBfrPtr mxWebQueries; /// Web queries buffer.
+ PivotCacheBfrPtr mxPivotCaches; /// All pivot caches in the document.
+ PivotTableBfrPtr mxPivotTables; /// All pivot tables in the document.
+
+ // converters
+ FormulaParserPtr mxFmlaParser; /// Import formula parser.
+ UnitConvPtr mxUnitConverter; /// General unit converter.
+ AddressConvPtr mxAddrConverter; /// Cell address and cell range address converter.
+ ExcelChartConvPtr mxChartConverter; /// Chart object converter.
+ PageSettConvPtr mxPageSettConverter; /// Page/print settings converter.
+
+ // OOX specific
+ XmlFilterBase* mpOoxFilter; /// Base OOX filter object.
+
+ // BIFF specific
+ BinaryFilterBase* mpBiffFilter; /// Base BIFF filter object.
+ BiffCodecHelperPtr mxCodecHelper; /// Encoder/decoder helper.
+ 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.
+};
+
+// ----------------------------------------------------------------------------
+
+WorkbookData::WorkbookData( ExcelFilter& rFilter ) :
+ mrBaseFilter( rFilter ),
+ mrExcelBase( rFilter ),
+ meFilterType( FILTER_OOX ),
+ mpOoxFilter( &rFilter ),
+ mpBiffFilter( 0 ),
+ meBiff( BIFF_UNKNOWN )
+{
+ // register at the filter, needed for virtual callbacks (even during construction)
+ mrExcelBase.registerWorkbookData( *this );
+ initialize( true );
+}
+
+WorkbookData::WorkbookData( ExcelBiffFilter& rFilter, BiffType eBiff ) :
+ mrBaseFilter( rFilter ),
+ mrExcelBase( rFilter ),
+ meFilterType( FILTER_BIFF ),
+ mpOoxFilter( 0 ),
+ mpBiffFilter( &rFilter ),
+ meBiff( eBiff )
+{
+ // register at the filter, needed for virtual callbacks (even during construction)
+ mrExcelBase.registerWorkbookData( *this );
+ initialize( eBiff >= BIFF5 );
+}
+
+WorkbookData::~WorkbookData()
+{
+ finalize();
+ mrExcelBase.unregisterWorkbookData();
+}
+
+// document model -------------------------------------------------------------
+
+Reference< XDevice > WorkbookData::getReferenceDevice() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XDevice > xDevice;
+ aPropSet.getProperty( xDevice, PROP_ReferenceDevice );
+ return xDevice;
+}
+
+Reference< XNamedRanges > WorkbookData::getNamedRanges() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XNamedRanges > xNamedRanges;
+ aPropSet.getProperty( xNamedRanges, PROP_NamedRanges );
+ return xNamedRanges;
+}
+
+Reference< XDatabaseRanges > WorkbookData::getDatabaseRanges() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XDatabaseRanges > xDatabaseRanges;
+ aPropSet.getProperty( xDatabaseRanges, PROP_DatabaseRanges );
+ return xDatabaseRanges;
+}
+
+Reference< XExternalDocLinks > WorkbookData::getExternalDocLinks() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XExternalDocLinks > xDocLinks;
+ aPropSet.getProperty( xDocLinks, PROP_ExternalDocLinks );
+ return xDocLinks;
+}
+
+Reference< XNameAccess > WorkbookData::getDdeLinks() const
+{
+ PropertySet aPropSet( mxDoc );
+ Reference< XNameAccess > xDdeLinks;
+ aPropSet.getProperty( xDdeLinks, PROP_DDELinks );
+ 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 ? maPageStyles : maCellStyles ), UNO_QUERY );
+ }
+ 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;
+ try
+ {
+ Reference< XNameContainer > xStylesNC( getStyleFamily( bPageStyle ), UNO_SET_THROW );
+ xStyle.set( xStylesNC->getByName( rStyleName ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( xStyle.is(), "WorkbookData::getStyleObject - cannot access style object" );
+ return xStyle;
+}
+
+Reference< XNamedRange > WorkbookData::createNamedRangeObject( 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( xNamedRange.is(), "WorkbookData::createNamedRangeObject - cannot create defined name" );
+ return xNamedRange;
+}
+
+Reference< XStyle > WorkbookData::createStyleObject( OUString& orStyleName, bool bPageStyle ) const
+{
+ Reference< XStyle > xStyle;
+ try
+ {
+ Reference< XNameContainer > xStylesNC( getStyleFamily( bPageStyle ), UNO_SET_THROW );
+ xStyle.set( mrBaseFilter.getModelFactory()->createInstance( bPageStyle ? maPageStyleServ : maCellStyleServ ), UNO_QUERY_THROW );
+ orStyleName = ContainerHelper::insertByUnusedName( xStylesNC, orStyleName, ' ', Any( xStyle ), false );
+ }
+ 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( sal_Int16 nSheet )
+{
+ // set mnCurrSheet to enable usage of WorkbookHelper::getCurrentSheetIndex()
+ mnCurrSheet = nSheet;
+ switch( meBiff )
+ {
+ case BIFF2:
+ case BIFF3:
+ OSL_ENSURE( mnCurrSheet == 0, "WorkbookData::createBuffersPerSheet - unexpected sheet index" );
+ mxDefNames->setLocalCalcSheet( mnCurrSheet );
+ break;
+
+ case BIFF4:
+ OSL_ENSURE( mbWorkbook || (mnCurrSheet == 0), "WorkbookData::createBuffersPerSheet - unexpected sheet index" );
+ // #i11183# sheets in BIFF4W files have own styles and names
+ if( mbWorkbook && (mnCurrSheet > 0) )
+ {
+ mxStyles.reset( new StylesBuffer( *this ) );
+ mxDefNames.reset( new DefinedNamesBuffer( *this ) );
+ mxExtLinks.reset( new ExternalLinkBuffer( *this ) );
+ }
+ mxDefNames->setLocalCalcSheet( mnCurrSheet );
+ break;
+
+ case BIFF5:
+ // BIFF5 stores external references per sheet
+ mxExtLinks.reset( new ExternalLinkBuffer( *this ) );
+ break;
+
+ case BIFF8:
+ break;
+
+ case BIFF_UNKNOWN:
+ break;
+ }
+ mnCurrSheet = -1;
+}
+
+// private --------------------------------------------------------------------
+
+void WorkbookData::initialize( bool bWorkbookFile )
+{
+ maCellStyles = CREATE_OUSTRING( "CellStyles" );
+ maPageStyles = CREATE_OUSTRING( "PageStyles" );
+ maCellStyleServ = CREATE_OUSTRING( "com.sun.star.style.CellStyle" );
+ maPageStyleServ = CREATE_OUSTRING( "com.sun.star.style.PageStyle" );
+ mnCurrSheet = -1;
+ mbWorkbook = bWorkbookFile;
+ meTextEnc = osl_getThreadTextEncoding();
+ mbHasCodePage = false;
+
+ // the spreadsheet document
+ mxDoc.set( mrBaseFilter.getModel(), UNO_QUERY );
+ OSL_ENSURE( mxDoc.is(), "WorkbookData::initialize - no spreadsheet document" );
+
+ mxWorkbookSettings.reset( new WorkbookSettings( *this ) );
+ mxViewSettings.reset( new ViewSettings( *this ) );
+ mxWorksheets.reset( new WorksheetBuffer( *this ) );
+ mxTheme.reset( new ThemeBuffer( *this ) );
+ mxStyles.reset( new StylesBuffer( *this ) );
+ mxSharedStrings.reset( new SharedStringsBuffer( *this ) );
+ mxExtLinks.reset( new ExternalLinkBuffer( *this ) );
+ mxDefNames.reset( new DefinedNamesBuffer( *this ) );
+ mxTables.reset( new TableBuffer( *this ) );
+ mxScenarios.reset( new ScenarioBuffer( *this ) );
+ mxWebQueries.reset( new WebQueryBuffer( *this ) );
+ mxPivotCaches.reset( new PivotCacheBuffer( *this ) );
+ mxPivotTables.reset( new PivotTableBuffer( *this ) );
+
+ mxUnitConverter.reset( new UnitConverter( *this ) );
+ mxAddrConverter.reset( new AddressConverter( *this ) );
+ mxChartConverter.reset( new ExcelChartConverter( *this ) );
+ mxPageSettConverter.reset( new PageSettingsConverter( *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( PROP_IsChangeReadOnlyEnabled, true );
+ // #i76026# disable Undo while loading the document
+ aPropSet.setProperty( PROP_IsUndoEnabled, false );
+ // #i79826# disable calculating automatic row height while loading the document
+ aPropSet.setProperty( PROP_IsAdjustHeightEnabled, false );
+ // disable automatic update of linked sheets and DDE links
+ aPropSet.setProperty( PROP_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( *this ) );
+ }
+ else if( mrBaseFilter.isExportFilter() )
+ {
+ //! TODO: localize progress bar text
+ mxProgressBar.reset( new SegmentProgressBar( mrBaseFilter.getStatusIndicator(), CREATE_OUSTRING( "Saving..." ) ) );
+ }
+
+ // filter specific
+ switch( getFilterType() )
+ {
+ case FILTER_BIFF:
+ mxCodecHelper.reset( new BiffCodecHelper( *this ) );
+ break;
+
+ case FILTER_OOX:
+ break;
+
+ case FILTER_UNKNOWN:
+ break;
+ }
+}
+
+void WorkbookData::finalize()
+{
+ // set some document properties needed after import
+ if( mrBaseFilter.isImportFilter() )
+ {
+ PropertySet aPropSet( mxDoc );
+ // #i74668# do not insert default sheets
+ aPropSet.setProperty( PROP_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( PROP_IsExecuteLinkEnabled, true );
+ // #i79826# enable updating automatic row height after loading the document
+ aPropSet.setProperty( PROP_IsAdjustHeightEnabled, true );
+ // #i76026# enable Undo after loading the document
+ aPropSet.setProperty( PROP_IsUndoEnabled, true );
+ // disable editing read-only documents (e.g. from read-only files)
+ aPropSet.setProperty( PROP_IsChangeReadOnlyEnabled, false );
+ }
+}
+
+// ============================================================================
+
+WorkbookHelper::~WorkbookHelper()
+{
+}
+
+// filter ---------------------------------------------------------------------
+
+FilterBase& WorkbookHelper::getBaseFilter() const
+{
+ return mrBookData.getBaseFilter();
+}
+
+Reference< XMultiServiceFactory > WorkbookHelper::getGlobalFactory() const
+{
+ return mrBookData.getBaseFilter().getGlobalFactory();
+}
+
+FilterType WorkbookHelper::getFilterType() const
+{
+ return mrBookData.getFilterType();
+}
+
+SegmentProgressBar& WorkbookHelper::getProgressBar() const
+{
+ return mrBookData.getProgressBar();
+}
+
+bool WorkbookHelper::isWorkbookFile() const
+{
+ return mrBookData.isWorkbookFile();
+}
+
+sal_Int16 WorkbookHelper::getCurrentSheetIndex() const
+{
+ return mrBookData.getCurrentSheetIndex();
+}
+
+void WorkbookHelper::setCurrentSheetIndex( sal_Int16 nSheet )
+{
+ mrBookData.setCurrentSheetIndex( nSheet );
+}
+
+void WorkbookHelper::setVbaProjectStorage( const StorageRef& rxVbaPrjStrg )
+{
+ mrBookData.setVbaProjectStorage( rxVbaPrjStrg );
+}
+
+void WorkbookHelper::finalizeWorkbookImport()
+{
+ // workbook settings, document and sheet view settings
+ mrBookData.getWorkbookSettings().finalizeImport();
+ mrBookData.getViewSettings().finalizeImport();
+
+ /* Insert all pivot tables. Must be done after loading all sheets, because
+ data pilots expect existing source data on creation. */
+ mrBookData.getPivotTables().finalizeImport();
+
+ /* Insert scenarios after all sheet processing is done, because new hidden
+ sheets are created for scenarios which would confuse code that relies
+ on certain sheet indexes. Must be done after pivot tables too. */
+ mrBookData.getScenarios().finalizeImport();
+
+ /* Set 'Default' page style to automatic page numbering (default is manual
+ number 1). Otherwise hidden sheets (e.g. for scenarios) which have
+ 'Default' page style will break automatic page numbering for following
+ sheets. Automatic numbering is set by passing the value 0. */
+ PropertySet aDefPageStyle( getStyleObject( CREATE_OUSTRING( "Default" ), true ) );
+ aDefPageStyle.setProperty< sal_Int16 >( PROP_FirstPageNumber, 0 );
+
+ /* Import the VBA project (after finalizing workbook settings which
+ contains the workbook code name). */
+ StorageRef xVbaPrjStrg = mrBookData.getVbaProjectStorage();
+ if( xVbaPrjStrg.get() && xVbaPrjStrg->isStorage() )
+ {
+ ::oox::ole::VbaProject aVbaProject( getGlobalFactory(), getBaseFilter().getModel(), CREATE_OUSTRING( "Calc" ) );
+ aVbaProject.importVbaProject( *xVbaPrjStrg, getBaseFilter().getGraphicHelper() );
+ }
+}
+
+// document model -------------------------------------------------------------
+
+Reference< XSpreadsheetDocument > WorkbookHelper::getDocument() const
+{
+ return mrBookData.getDocument();
+}
+
+Reference< XMultiServiceFactory > WorkbookHelper::getDocumentFactory() const
+{
+ return mrBookData.getBaseFilter().getModelFactory();
+}
+
+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< XExternalDocLinks > WorkbookHelper::getExternalDocLinks() const
+{
+ return mrBookData.getExternalDocLinks();
+}
+
+Reference< XNameAccess > WorkbookHelper::getDdeLinks() const
+{
+ return mrBookData.getDdeLinks();
+}
+
+Reference< XSpreadsheet > WorkbookHelper::getSheetFromDoc( sal_Int16 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< XSpreadsheet > WorkbookHelper::getSheetFromDoc( const OUString& rSheet ) const
+{
+ Reference< XSpreadsheet > xSheet;
+ try
+ {
+ Reference< XNameAccess > xSheetsNA( getDocument()->getSheets(), UNO_QUERY_THROW );
+ xSheet.set( xSheetsNA->getByName( rSheet ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ return xSheet;
+}
+
+Reference< XCell > WorkbookHelper::getCellFromDoc( const CellAddress& rAddress ) const
+{
+ Reference< XCell > xCell;
+ try
+ {
+ Reference< XSpreadsheet > xSheet( getSheetFromDoc( rAddress.Sheet ), UNO_SET_THROW );
+ xCell = xSheet->getCellByPosition( rAddress.Column, rAddress.Row );
+ }
+ catch( Exception& )
+ {
+ }
+ return xCell;
+}
+
+Reference< XCellRange > WorkbookHelper::getCellRangeFromDoc( const CellRangeAddress& rRange ) const
+{
+ Reference< XCellRange > xRange;
+ try
+ {
+ Reference< XSpreadsheet > xSheet( getSheetFromDoc( rRange.Sheet ), UNO_SET_THROW );
+ xRange = xSheet->getCellRangeByPosition( rRange.StartColumn, rRange.StartRow, rRange.EndColumn, rRange.EndRow );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRange;
+}
+
+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< XNamedRange > WorkbookHelper::createNamedRangeObject( OUString& orName, sal_Int32 nNameFlags ) const
+{
+ return mrBookData.createNamedRangeObject( orName, nNameFlags );
+}
+
+Reference< XStyle > WorkbookHelper::createStyleObject( OUString& orStyleName, bool bPageStyle ) const
+{
+ return mrBookData.createStyleObject( orStyleName, bPageStyle );
+}
+
+// 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();
+}
+
+ScenarioBuffer& WorkbookHelper::getScenarios() const
+{
+ return mrBookData.getScenarios();
+}
+
+WebQueryBuffer& WorkbookHelper::getWebQueries() const
+{
+ return mrBookData.getWebQueries();
+}
+
+PivotCacheBuffer& WorkbookHelper::getPivotCaches() const
+{
+ return mrBookData.getPivotCaches();
+}
+
+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();
+}
+
+ExcelChartConverter& WorkbookHelper::getChartConverter() const
+{
+ return mrBookData.getChartConverter();
+}
+
+PageSettingsConverter& WorkbookHelper::getPageSettingsConverter() const
+{
+ return mrBookData.getPageSettingsConverter();
+}
+
+// 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( sal_Int16 nSheet )
+{
+ mrBookData.createBuffersPerSheet( nSheet );
+}
+
+BiffCodecHelper& WorkbookHelper::getCodecHelper() const
+{
+ return mrBookData.getCodecHelper();
+}
+
+// ============================================================================
+
+namespace prv {
+
+WorkbookDataOwner::WorkbookDataOwner( WorkbookDataRef xBookData ) :
+ mxBookData( xBookData )
+{
+}
+
+WorkbookDataOwner::~WorkbookDataOwner()
+{
+}
+
+} // namespace prv
+
+// ----------------------------------------------------------------------------
+
+WorkbookHelperRoot::WorkbookHelperRoot( ExcelFilter& rFilter ) :
+ prv::WorkbookDataOwner( prv::WorkbookDataRef( new WorkbookData( rFilter ) ) ),
+ WorkbookHelper( *mxBookData )
+{
+}
+
+WorkbookHelperRoot::WorkbookHelperRoot( ExcelBiffFilter& rFilter, BiffType eBiff ) :
+ prv::WorkbookDataOwner( prv::WorkbookDataRef( new WorkbookData( rFilter, eBiff ) ) ),
+ WorkbookHelper( *mxBookData )
+{
+}
+
+bool WorkbookHelperRoot::isValid() const
+{
+ return mxBookData->isValid();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/workbooksettings.cxx b/oox/source/xls/workbooksettings.cxx
new file mode 100644
index 000000000000..711cc9ac8e0d
--- /dev/null
+++ b/oox/source/xls/workbooksettings.cxx
@@ -0,0 +1,387 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/workbooksettings.hxx"
+#include <com/sun/star/sheet/XCalculatable.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <comphelper/mediadescriptor.hxx>
+#include "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/core/xmlfilterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/unitconverter.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::sheet::XCalculatable;
+using ::com::sun::star::uno::Any;
+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 ::com::sun::star::util::Date;
+using ::com::sun::star::util::XNumberFormatsSupplier;
+using ::comphelper::MediaDescriptor;
+using ::oox::core::CodecHelper;
+
+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
+
+// ============================================================================
+
+FileSharingModel::FileSharingModel() :
+ mnPasswordHash( 0 ),
+ mbRecommendReadOnly( false )
+{
+}
+
+// ============================================================================
+
+WorkbookSettingsModel::WorkbookSettingsModel() :
+ mnShowObjectMode( XML_all ),
+ mnUpdateLinksMode( XML_userSet ),
+ mnDefaultThemeVer( -1 ),
+ mbDateMode1904( false ),
+ mbSaveExtLinkValues( true )
+{
+}
+
+void WorkbookSettingsModel::setBinObjectMode( sal_uInt16 nObjMode )
+{
+ static const sal_Int32 spnObjModes[] = { XML_all, XML_placeholders, XML_none };
+ mnShowObjectMode = STATIC_ARRAY_SELECT( spnObjModes, nObjMode, XML_all );
+}
+
+// ============================================================================
+
+CalcSettingsModel::CalcSettingsModel() :
+ 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::importFileSharing( const AttributeList& rAttribs )
+{
+ maFileSharing.maUserName = rAttribs.getXString( XML_userName, OUString() );
+ maFileSharing.mnPasswordHash = CodecHelper::getPasswordHash( rAttribs, XML_reservationPassword );
+ maFileSharing.mbRecommendReadOnly = rAttribs.getBool( XML_readOnlyRecommended, false );
+}
+
+void WorkbookSettings::importWorkbookPr( const AttributeList& rAttribs )
+{
+ maBookSettings.maCodeName = rAttribs.getString( XML_codeName, OUString() );
+ maBookSettings.mnShowObjectMode = rAttribs.getToken( XML_showObjects, XML_all );
+ maBookSettings.mnUpdateLinksMode = rAttribs.getToken( XML_updateLinks, XML_userSet );
+ maBookSettings.mnDefaultThemeVer = rAttribs.getInteger( XML_defaultThemeVersion, -1 );
+ maBookSettings.mbSaveExtLinkValues = rAttribs.getBool( XML_saveExternalLinkValues, true );
+ setDateMode( rAttribs.getBool( XML_date1904, false ), rAttribs.getBool( XML_dateCompatibility, true ) );
+}
+
+void WorkbookSettings::importCalcPr( const AttributeList& rAttribs )
+{
+ maCalcSettings.mfIterateDelta = rAttribs.getDouble( XML_iterateDelta, 0.0001 );
+ maCalcSettings.mnCalcId = rAttribs.getInteger( XML_calcId, -1 );
+ maCalcSettings.mnRefMode = rAttribs.getToken( XML_refMode, XML_A1 );
+ maCalcSettings.mnCalcMode = rAttribs.getToken( XML_calcMode, XML_auto );
+ maCalcSettings.mnIterateCount = rAttribs.getInteger( XML_iterateCount, 100 );
+ maCalcSettings.mnProcCount = rAttribs.getInteger( XML_concurrentManualCount, -1 );
+ maCalcSettings.mbCalcOnSave = rAttribs.getBool( XML_calcOnSave, true );
+ maCalcSettings.mbCalcCompleted = rAttribs.getBool( XML_calcCompleted, true );
+ maCalcSettings.mbFullPrecision = rAttribs.getBool( XML_fullPrecision, true );
+ maCalcSettings.mbIterate = rAttribs.getBool( XML_iterate, false );
+ maCalcSettings.mbConcurrent = rAttribs.getBool( XML_concurrentCalc, true );
+}
+
+void WorkbookSettings::importFileSharing( RecordInputStream& rStrm )
+{
+ maFileSharing.mbRecommendReadOnly = rStrm.readuInt16() != 0;
+ rStrm >> maFileSharing.mnPasswordHash >> maFileSharing.maUserName;
+}
+
+void WorkbookSettings::importWorkbookPr( RecordInputStream& rStrm )
+{
+ sal_uInt32 nFlags;
+ rStrm >> nFlags >> maBookSettings.mnDefaultThemeVer >> maBookSettings.maCodeName;
+ maBookSettings.setBinObjectMode( extractValue< sal_uInt16 >( nFlags, 13, 2 ) );
+ // set flag means: strip external link values
+ maBookSettings.mbSaveExtLinkValues = !getFlag( nFlags, OOBIN_WORKBOOKPR_STRIPEXT );
+ setDateMode( getFlag( nFlags, OOBIN_WORKBOOKPR_DATE1904 ) );
+}
+
+void WorkbookSettings::importCalcPr( RecordInputStream& rStrm )
+{
+ sal_Int32 nCalcMode, nProcCount;
+ sal_uInt16 nFlags;
+ rStrm >> maCalcSettings.mnCalcId >> nCalcMode >> maCalcSettings.mnIterateCount >> maCalcSettings.mfIterateDelta >> nProcCount >> nFlags;
+
+ static const sal_Int32 spnCalcModes[] = { XML_manual, XML_auto, XML_autoNoTable };
+ maCalcSettings.mnRefMode = getFlagValue( nFlags, OOBIN_CALCPR_A1, XML_A1, XML_R1C1 );
+ maCalcSettings.mnCalcMode = STATIC_ARRAY_SELECT( spnCalcModes, nCalcMode, XML_auto );
+ maCalcSettings.mnProcCount = getFlagValue< sal_Int32 >( nFlags, OOBIN_CALCPR_MANUALPROC, nProcCount, -1 );
+ maCalcSettings.mbCalcOnSave = getFlag( nFlags, OOBIN_CALCPR_CALCONSAVE );
+ maCalcSettings.mbCalcCompleted = getFlag( nFlags, OOBIN_CALCPR_CALCCOMPLETED );
+ maCalcSettings.mbFullPrecision = getFlag( nFlags, OOBIN_CALCPR_FULLPRECISION );
+ maCalcSettings.mbIterate = getFlag( nFlags, OOBIN_CALCPR_ITERATE );
+ maCalcSettings.mbConcurrent = getFlag( nFlags, OOBIN_CALCPR_CONCURRENT );
+}
+
+void WorkbookSettings::setSaveExtLinkValues( bool bSaveExtLinks )
+{
+ maBookSettings.mbSaveExtLinkValues = bSaveExtLinks;
+}
+
+void WorkbookSettings::importBookBool( BiffInputStream& rStrm )
+{
+ // value of 0 means save external values, value of 1 means strip external values
+ maBookSettings.mbSaveExtLinkValues = rStrm.readuInt16() == 0;
+}
+
+void WorkbookSettings::importCalcCount( BiffInputStream& rStrm )
+{
+ maCalcSettings.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 };
+ maCalcSettings.mnCalcMode = STATIC_ARRAY_SELECT( spnCalcModes, nCalcMode, XML_auto );
+}
+
+void WorkbookSettings::importCodeName( BiffInputStream& rStrm )
+{
+ maBookSettings.maCodeName = rStrm.readUniString();
+}
+
+void WorkbookSettings::importDateMode( BiffInputStream& rStrm )
+{
+ setDateMode( rStrm.readuInt16() != 0 );
+}
+
+void WorkbookSettings::importDelta( BiffInputStream& rStrm )
+{
+ rStrm >> maCalcSettings.mfIterateDelta;
+}
+
+void WorkbookSettings::importFileSharing( BiffInputStream& rStrm )
+{
+ maFileSharing.mbRecommendReadOnly = rStrm.readuInt16() != 0;
+ rStrm >> maFileSharing.mnPasswordHash;
+ if( getBiff() == BIFF8 )
+ {
+ sal_uInt16 nStrLen = rStrm.readuInt16();
+ // there is no string flags field if string is empty
+ if( nStrLen > 0 )
+ maFileSharing.maUserName = rStrm.readUniStringBody( nStrLen );
+ }
+ else
+ {
+ maFileSharing.maUserName = rStrm.readByteStringUC( false, getTextEncoding() );
+ }
+}
+
+void WorkbookSettings::importHideObj( BiffInputStream& rStrm )
+{
+ maBookSettings.setBinObjectMode( rStrm.readuInt16() );
+}
+
+void WorkbookSettings::importIteration( BiffInputStream& rStrm )
+{
+ maCalcSettings.mbIterate = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::importPrecision( BiffInputStream& rStrm )
+{
+ maCalcSettings.mbFullPrecision = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::importRefMode( BiffInputStream& rStrm )
+{
+ maCalcSettings.mnRefMode = (rStrm.readuInt16() == 0) ? XML_R1C1 : XML_A1;
+}
+
+void WorkbookSettings::importSaveRecalc( BiffInputStream& rStrm )
+{
+ maCalcSettings.mbCalcOnSave = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::importUncalced( BiffInputStream& )
+{
+ // existence of this record indicates incomplete recalc
+ maCalcSettings.mbCalcCompleted = false;
+}
+
+void WorkbookSettings::importUsesElfs( BiffInputStream& rStrm )
+{
+ maCalcSettings.mbUseNlr = rStrm.readuInt16() != 0;
+}
+
+void WorkbookSettings::finalizeImport()
+{
+ // default settings
+ PropertySet aPropSet( getDocument() );
+ switch( getFilterType() )
+ {
+ case FILTER_OOX:
+ case FILTER_BIFF:
+ aPropSet.setProperty( PROP_IgnoreCase, true ); // always in Excel
+ aPropSet.setProperty( PROP_RegularExpressions, false ); // not supported in Excel
+ break;
+ case FILTER_UNKNOWN:
+ break;
+ }
+
+ // write protection
+ if( maFileSharing.mbRecommendReadOnly || (maFileSharing.mnPasswordHash != 0) ) try
+ {
+ getBaseFilter().getMediaDescriptor()[ CREATE_OUSTRING( "ReadOnly" ) ] <<= true;
+
+ Reference< XPropertySet > xDocumentSettings( getDocumentFactory()->createInstance(
+ CREATE_OUSTRING( "com.sun.star.document.Settings" ) ), UNO_QUERY_THROW );
+ PropertySet aSettingsProp( xDocumentSettings );
+ if( maFileSharing.mbRecommendReadOnly )
+ aSettingsProp.setProperty( PROP_LoadReadonly, true );
+// if( maFileSharing.mnPasswordHash != 0 )
+// aSettingsProp.setProperty( PROP_ModifyPasswordHash, static_cast< sal_Int32 >( maFileSharing.mnPasswordHash ) );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // calculation settings
+ Date aNullDate = getNullDate();
+
+ aPropSet.setProperty( PROP_NullDate, aNullDate );
+ aPropSet.setProperty( PROP_IsIterationEnabled, maCalcSettings.mbIterate );
+ aPropSet.setProperty( PROP_IterationCount, maCalcSettings.mnIterateCount );
+ aPropSet.setProperty( PROP_IterationEpsilon, maCalcSettings.mfIterateDelta );
+ aPropSet.setProperty( PROP_CalcAsShown, !maCalcSettings.mbFullPrecision );
+ aPropSet.setProperty( PROP_LookUpLabels, maCalcSettings.mbUseNlr );
+
+ Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY );
+ if( xNumFmtsSupp.is() )
+ {
+ PropertySet aNumFmtProp( xNumFmtsSupp->getNumberFormatSettings() );
+ aNumFmtProp.setProperty( PROP_NullDate, aNullDate );
+ }
+
+ Reference< XCalculatable > xCalculatable( getDocument(), UNO_QUERY );
+ if( xCalculatable.is() )
+ xCalculatable->enableAutomaticCalculation( (maCalcSettings.mnCalcMode == XML_auto) || (maCalcSettings.mnCalcMode == XML_autoNoTable) );
+
+ // VBA code name
+ aPropSet.setProperty( PROP_CodeName, maBookSettings.maCodeName );
+}
+
+sal_Int16 WorkbookSettings::getApiShowObjectMode() const
+{
+ switch( maBookSettings.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;
+}
+
+Date WorkbookSettings::getNullDate() const
+{
+ static const Date saDate1900 ( 30, 12, 1899 );
+ static const Date saDate1904 ( 1, 1, 1904 );
+ static const Date saDateBackCompatibility1900( 31, 12, 1899 );
+
+ if( getOoxFilter().getVersion() == oox::core::ISOIEC_29500_2008 )
+ {
+ if( !maBookSettings.mbDateCompatibility )
+ return saDate1900;
+
+ return maBookSettings.mbDateMode1904 ? saDate1904 :
+ saDateBackCompatibility1900;
+ }
+
+ return maBookSettings.mbDateMode1904 ? saDate1904 : saDate1900;
+}
+
+void WorkbookSettings::setDateMode( bool bDateMode1904, bool bDateCompatibility )
+{
+ maBookSettings.mbDateMode1904 = bDateMode1904;
+ maBookSettings.mbDateCompatibility = bDateCompatibility;
+
+ getUnitConverter().finalizeNullDate( getNullDate() );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/worksheetbuffer.cxx b/oox/source/xls/worksheetbuffer.cxx
new file mode 100644
index 000000000000..3d0d882325c7
--- /dev/null
+++ b/oox/source/xls/worksheetbuffer.cxx
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheetbuffer.hxx"
+#include <rtl/ustrbuf.hxx>
+#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/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XExternalSheetName.hpp>
+#include <com/sun/star/sheet/XSheetLinkable.hpp>
+#include "properties.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/excelhandlers.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_THROW;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::sheet::XSpreadsheetDocument;
+using ::com::sun::star::sheet::XSpreadsheets;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+SheetInfoModel::SheetInfoModel() :
+ mnBiffHandle( -1 ),
+ mnSheetId( -1 ),
+ mnState( XML_visible )
+{
+}
+
+// ============================================================================
+
+WorksheetBuffer::WorksheetBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+/*static*/ OUString WorksheetBuffer::getBaseFileName( 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 );
+}
+
+void WorksheetBuffer::initializeSingleSheet()
+{
+ OSL_ENSURE( maSheetInfos.empty(), "WorksheetBuffer::initializeSingleSheet - invalid call" );
+ SheetInfoModel aModel;
+ aModel.maName = getBaseFileName( getBaseFilter().getFileUrl() );
+ insertSheet( aModel );
+}
+
+void WorksheetBuffer::importSheet( const AttributeList& rAttribs )
+{
+ SheetInfoModel aModel;
+ aModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
+ aModel.maName = rAttribs.getXString( XML_name, OUString() );
+ aModel.mnSheetId = rAttribs.getInteger( XML_sheetId, -1 );
+ aModel.mnState = rAttribs.getToken( XML_state, XML_visible );
+ insertSheet( aModel );
+}
+
+void WorksheetBuffer::importSheet( RecordInputStream& rStrm )
+{
+ sal_Int32 nState;
+ SheetInfoModel aModel;
+ rStrm >> nState >> aModel.mnSheetId >> aModel.maRelId >> aModel.maName;
+ static const sal_Int32 spnStates[] = { XML_visible, XML_hidden, XML_veryHidden };
+ aModel.mnState = STATIC_ARRAY_SELECT( spnStates, nState, XML_visible );
+ insertSheet( aModel );
+}
+
+void WorksheetBuffer::importSheet( BiffInputStream& rStrm )
+{
+ SheetInfoModel aModel;
+ if( getBiff() >= BIFF5 )
+ {
+ rStrm.enableDecoder( false );
+ aModel.mnBiffHandle = rStrm.readuInt32();
+ rStrm.enableDecoder( true );
+ sal_uInt16 nState = rStrm.readuInt16();
+ static const sal_Int32 spnStates[] = { XML_visible, XML_hidden, XML_veryHidden };
+ aModel.mnState = STATIC_ARRAY_SELECT( spnStates, nState, XML_visible );
+ }
+ aModel.maName = (getBiff() == BIFF8) ?
+ rStrm.readUniStringBody( rStrm.readuInt8() ) :
+ rStrm.readByteStringUC( false, getTextEncoding() );
+ insertSheet( aModel );
+}
+
+sal_Int16 WorksheetBuffer::insertEmptySheet( const OUString& rPreferredName, bool bVisible )
+{
+ return createSheet( rPreferredName, SAL_MAX_INT32, bVisible ).first;
+}
+
+sal_Int32 WorksheetBuffer::getWorksheetCount() const
+{
+ return static_cast< sal_Int32 >( maSheetInfos.size() );
+}
+
+OUString WorksheetBuffer::getWorksheetRelId( sal_Int32 nWorksheet ) const
+{
+ const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
+ return pSheetInfo ? pSheetInfo->maRelId : OUString();
+}
+
+sal_Int64 WorksheetBuffer::getBiffRecordHandle( sal_Int32 nWorksheet ) const
+{
+ const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
+ return pSheetInfo ? pSheetInfo->mnBiffHandle : -1;
+}
+
+sal_Int16 WorksheetBuffer::getCalcSheetIndex( sal_Int32 nWorksheet ) const
+{
+ const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
+ return pSheetInfo ? pSheetInfo->mnCalcSheet : -1;
+}
+
+OUString WorksheetBuffer::getCalcSheetName( sal_Int32 nWorksheet ) const
+{
+ const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
+ return pSheetInfo ? pSheetInfo->maCalcName : OUString();
+}
+
+sal_Int16 WorksheetBuffer::getCalcSheetIndex( const OUString& rWorksheetName ) const
+{
+ const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get();
+ return pSheetInfo ? pSheetInfo->mnCalcSheet : -1;
+}
+
+OUString WorksheetBuffer::getCalcSheetName( const OUString& rWorksheetName ) const
+{
+ if( const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get() )
+ {
+ bool bIsQuoted = pSheetInfo->maName != rWorksheetName;
+ return bIsQuoted ? pSheetInfo->maCalcQuotedName : pSheetInfo->maCalcName;
+ }
+ return OUString();
+}
+
+// private --------------------------------------------------------------------
+
+namespace {
+
+OUString lclQuoteName( const OUString& rName )
+{
+ OUStringBuffer aBuffer( rName );
+ // duplicate all quote characters
+ for( sal_Int32 nPos = aBuffer.getLength() - 1; nPos >= 0; --nPos )
+ if( aBuffer.charAt( nPos ) == '\'' )
+ aBuffer.insert( nPos, sal_Unicode( '\'' ) );
+ // add outer quotes and return
+ return aBuffer.insert( 0, sal_Unicode( '\'' ) ).append( sal_Unicode( '\'' ) ).makeStringAndClear();
+}
+
+} // namespace
+
+WorksheetBuffer::SheetInfo::SheetInfo( const SheetInfoModel& rModel, sal_Int16 nCalcSheet, const OUString& rCalcName ) :
+ SheetInfoModel( rModel ),
+ maCalcName( rCalcName ),
+ maCalcQuotedName( lclQuoteName( rCalcName ) ),
+ mnCalcSheet( nCalcSheet )
+{
+}
+
+WorksheetBuffer::IndexNamePair WorksheetBuffer::createSheet( const OUString& rPreferredName, sal_Int32 nSheetPos, bool bVisible )
+{
+ try
+ {
+ Reference< XSpreadsheets > xSheets( getDocument()->getSheets(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSheetsIA( xSheets, UNO_QUERY_THROW );
+ Reference< XNameAccess > xSheetsNA( xSheets, UNO_QUERY_THROW );
+ sal_Int16 nCalcSheet = -1;
+ OUString aSheetName = (rPreferredName.getLength() == 0) ? CREATE_OUSTRING( "Sheet" ) : rPreferredName;
+ PropertySet aPropSet;
+ if( nSheetPos < xSheetsIA->getCount() )
+ {
+ nCalcSheet = static_cast< sal_Int16 >( nSheetPos );
+ // existing sheet - try to rename
+ Reference< XNamed > xSheetName( xSheetsIA->getByIndex( nSheetPos ), UNO_QUERY_THROW );
+ if( xSheetName->getName() != aSheetName )
+ {
+ aSheetName = ContainerHelper::getUnusedName( xSheetsNA, aSheetName, ' ' );
+ xSheetName->setName( aSheetName );
+ }
+ aPropSet.set( xSheetName );
+ }
+ else
+ {
+ nCalcSheet = static_cast< sal_Int16 >( xSheetsIA->getCount() );
+ // new sheet - insert with unused name
+ aSheetName = ContainerHelper::getUnusedName( xSheetsNA, aSheetName, ' ' );
+ xSheets->insertNewByName( aSheetName, nCalcSheet );
+ aPropSet.set( xSheetsIA->getByIndex( nCalcSheet ) );
+ }
+
+ // sheet properties
+ aPropSet.setProperty( PROP_IsVisible, bVisible );
+
+ // return final sheet index if sheet exists
+ return IndexNamePair( nCalcSheet, aSheetName );
+ }
+ catch( Exception& )
+ {
+ OSL_ENSURE( false, "WorksheetBuffer::createSheet - cannot insert or rename worksheet" );
+ }
+ return IndexNamePair( -1, OUString() );
+}
+
+void WorksheetBuffer::insertSheet( const SheetInfoModel& rModel )
+{
+ sal_Int32 nWorksheet = static_cast< sal_Int32 >( maSheetInfos.size() );
+ IndexNamePair aIndexName = createSheet( rModel.maName, nWorksheet, rModel.mnState == XML_visible );
+ ::boost::shared_ptr< SheetInfo > xSheetInfo( new SheetInfo( rModel, aIndexName.first, aIndexName.second ) );
+ maSheetInfos.push_back( xSheetInfo );
+ maSheetInfosByName[ rModel.maName ] = xSheetInfo;
+ maSheetInfosByName[ lclQuoteName( rModel.maName ) ] = xSheetInfo;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/worksheetfragment.cxx b/oox/source/xls/worksheetfragment.cxx
new file mode 100644
index 000000000000..a0f32ce86104
--- /dev/null
+++ b/oox/source/xls/worksheetfragment.cxx
@@ -0,0 +1,1204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheetfragment.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/recordinputstream.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/core/relations.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/autofiltercontext.hxx"
+#include "oox/xls/biffinputstream.hxx"
+#include "oox/xls/commentsfragment.hxx"
+#include "oox/xls/condformatcontext.hxx"
+#include "oox/xls/drawingfragment.hxx"
+#include "oox/xls/externallinkbuffer.hxx"
+#include "oox/xls/pagesettings.hxx"
+#include "oox/xls/pivottablebuffer.hxx"
+#include "oox/xls/pivottablefragment.hxx"
+#include "oox/xls/querytablefragment.hxx"
+#include "oox/xls/scenariobuffer.hxx"
+#include "oox/xls/scenariocontext.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 ::oox::core::ContextHandlerRef;
+using ::oox::core::RecordInfo;
+using ::oox::core::Relations;
+using ::oox::core::RelationsRef;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF_COLINFO_HIDDEN = 0x0001;
+const sal_uInt16 BIFF_COLINFO_SHOWPHONETIC = 0x0008;
+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_SHRFEATHEAD_SHEETPROT = 2;
+
+const sal_Int32 OOBIN_OLEOBJECT_CONTENT = 1;
+const sal_Int32 OOBIN_OLEOBJECT_ICON = 4;
+const sal_Int32 OOBIN_OLEOBJECT_ALWAYS = 1;
+const sal_Int32 OOBIN_OLEOBJECT_ONCALL = 3;
+const sal_uInt16 OOBIN_OLEOBJECT_LINKED = 0x0001;
+const sal_uInt16 OOBIN_OLEOBJECT_AUTOLOAD = 0x0002;
+
+} // namespace
+
+// ============================================================================
+
+OoxDataValidationsContext::OoxDataValidationsContext( OoxWorksheetFragmentBase& rFragment ) :
+ OoxWorksheetContextBase( rFragment )
+{
+}
+
+ContextHandlerRef OoxDataValidationsContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( dataValidations ):
+ if( nElement == XLS_TOKEN( dataValidation ) )
+ {
+ importDataValidation( rAttribs );
+ return this;
+ }
+ break;
+ case XLS_TOKEN( dataValidation ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( formula1 ):
+ case XLS_TOKEN( formula2 ):
+ return this; // collect formulas in onEndElement()
+ }
+ break;
+ }
+ return 0;
+}
+
+namespace {
+
+ApiTokenSequence lclImportDataValFormula( FormulaParser& rParser, const OUString& rFormula, const CellAddress& rBaseAddress )
+{
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( rBaseAddress );
+ rParser.importFormula( aContext, rFormula );
+ return aContext.getTokens();
+}
+
+} // namespace
+
+void OoxDataValidationsContext::onEndElement( const OUString& rChars )
+{
+ if( mxValModel.get() ) switch( getCurrentElement() )
+ {
+ case XLS_TOKEN( formula1 ):
+ mxValModel->maTokens1 = lclImportDataValFormula(
+ getFormulaParser(), rChars, mxValModel->maRanges.getBaseAddress() );
+ // process string list of a list validation (convert to list of string tokens)
+ if( mxValModel->mnType == XML_list )
+ getFormulaParser().convertStringToStringList( mxValModel->maTokens1, ',', true );
+ break;
+ case XLS_TOKEN( formula2 ):
+ mxValModel->maTokens2 = lclImportDataValFormula(
+ getFormulaParser(), rChars, mxValModel->maRanges.getBaseAddress() );
+ break;
+ case XLS_TOKEN( dataValidation ):
+ setValidation( *mxValModel );
+ mxValModel.reset();
+ break;
+ }
+}
+
+
+ContextHandlerRef OoxDataValidationsContext::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ if( nRecId == OOBIN_ID_DATAVALIDATION )
+ importDataValidation( rStrm );
+ return 0;
+}
+
+void OoxDataValidationsContext::importDataValidation( const AttributeList& rAttribs )
+{
+ mxValModel.reset( new ValidationModel );
+ getAddressConverter().convertToCellRangeList( mxValModel->maRanges, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), true );
+ mxValModel->maInputTitle = rAttribs.getXString( XML_promptTitle, OUString() );
+ mxValModel->maInputMessage = rAttribs.getXString( XML_prompt, OUString() );
+ mxValModel->maErrorTitle = rAttribs.getXString( XML_errorTitle, OUString() );
+ mxValModel->maErrorMessage = rAttribs.getXString( XML_error, OUString() );
+ mxValModel->mnType = rAttribs.getToken( XML_type, XML_none );
+ mxValModel->mnOperator = rAttribs.getToken( XML_operator, XML_between );
+ mxValModel->mnErrorStyle = rAttribs.getToken( XML_errorStyle, XML_stop );
+ mxValModel->mbShowInputMsg = rAttribs.getBool( XML_showInputMessage, false );
+ mxValModel->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! */
+ mxValModel->mbNoDropDown = rAttribs.getBool( XML_showDropDown, false );
+ mxValModel->mbAllowBlank = rAttribs.getBool( XML_allowBlank, false );
+}
+
+void OoxDataValidationsContext::importDataValidation( RecordInputStream& rStrm )
+{
+ ValidationModel aModel;
+
+ sal_uInt32 nFlags;
+ BinRangeList aRanges;
+ rStrm >> nFlags >> aRanges >> aModel.maErrorTitle >> aModel.maErrorMessage >> aModel.maInputTitle >> aModel.maInputMessage;
+
+ // equal flags in BIFF and OOBIN
+ aModel.setBinType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
+ aModel.setBinOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
+ aModel.setBinErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
+ aModel.mbAllowBlank = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
+ aModel.mbNoDropDown = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
+ aModel.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
+ aModel.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
+
+ // cell range list
+ getAddressConverter().convertToCellRangeList( aModel.maRanges, aRanges, getSheetIndex(), true );
+
+ // condition formula(s)
+ FormulaParser& rParser = getFormulaParser();
+ TokensFormulaContext aContext( true, false );
+ aContext.setBaseAddress( aModel.maRanges.getBaseAddress() );
+ rParser.importFormula( aContext, rStrm );
+ aModel.maTokens1 = aContext.getTokens();
+ rParser.importFormula( aContext, rStrm );
+ aModel.maTokens2 = aContext.getTokens();
+ // process string list of a list validation (convert to list of string tokens)
+ if( (aModel.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
+ rParser.convertStringToStringList( aModel.maTokens1, ',', true );
+
+ // set validation data
+ setValidation( aModel );
+}
+
+// ============================================================================
+
+OoxWorksheetFragment::OoxWorksheetFragment( const WorkbookHelper& rHelper,
+ const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
+ OoxWorksheetFragmentBase( rHelper, rFragmentPath, xProgressBar, eSheetType, nSheet )
+{
+ // import data tables related to this worksheet
+ RelationsRef xTableRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATIONSTYPE( "table" ) );
+ for( Relations::const_iterator aIt = xTableRels->begin(), aEnd = xTableRels->end(); aIt != aEnd; ++aIt )
+ importOoxFragment( new OoxTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
+
+ // import comments related to this worksheet
+ OUString aCommentsFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATIONSTYPE( "comments" ) );
+ if( aCommentsFragmentPath.getLength() > 0 )
+ importOoxFragment( new OoxCommentsFragment( *this, aCommentsFragmentPath ) );
+}
+
+// oox.core.ContextHandler2Helper interface -----------------------------------
+
+ContextHandlerRef OoxWorksheetFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT: switch( getSheetType() )
+ {
+ case SHEETTYPE_WORKSHEET: return (nElement == XLS_TOKEN( worksheet )) ? this : 0;
+ case SHEETTYPE_CHARTSHEET: return 0;
+ case SHEETTYPE_MACROSHEET: return (nElement == XM_TOKEN( macrosheet )) ? this : 0;
+ case SHEETTYPE_DIALOGSHEET: return (nElement == XM_TOKEN( dialogsheet )) ? this : 0;
+ case SHEETTYPE_MODULESHEET: return 0;
+ case SHEETTYPE_EMPTYSHEET: return 0;
+ }
+ break;
+
+ case XLS_TOKEN( worksheet ):
+ case XM_TOKEN( macrosheet ):
+ 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 );
+ case XLS_TOKEN( dataValidations ): return new OoxDataValidationsContext( *this );
+
+ case XLS_TOKEN( sheetViews ):
+ case XLS_TOKEN( cols ):
+ case XLS_TOKEN( mergeCells ):
+ case XLS_TOKEN( hyperlinks ):
+ case XLS_TOKEN( rowBreaks ):
+ case XLS_TOKEN( colBreaks ):
+ case XLS_TOKEN( oleObjects ):
+ case XLS_TOKEN( controls ): return this;
+
+ case XLS_TOKEN( sheetPr ): getWorksheetSettings().importSheetPr( rAttribs ); return this;
+ case XLS_TOKEN( dimension ): importDimension( rAttribs ); break;
+ case XLS_TOKEN( sheetFormatPr ): importSheetFormatPr( rAttribs ); break;
+ case XLS_TOKEN( sheetProtection ): getWorksheetSettings().importSheetProtection( rAttribs ); break;
+ case XLS_TOKEN( phoneticPr ): getWorksheetSettings().importPhoneticPr( rAttribs ); break;
+ case XLS_TOKEN( printOptions ): getPageSettings().importPrintOptions( rAttribs ); break;
+ case XLS_TOKEN( pageMargins ): getPageSettings().importPageMargins( rAttribs ); break;
+ case XLS_TOKEN( pageSetup ): getPageSettings().importPageSetup( getRelations(), rAttribs ); break;
+ case XLS_TOKEN( headerFooter ): getPageSettings().importHeaderFooter( rAttribs ); return this;
+ case XLS_TOKEN( picture ): getPageSettings().importPicture( getRelations(), rAttribs ); break;
+ case XLS_TOKEN( drawing ): importDrawing( rAttribs ); break;
+ case XLS_TOKEN( legacyDrawing ): importLegacyDrawing( rAttribs ); break;
+ case XLS_TOKEN( scenarios ):
+ return new OoxScenariosContext( *this );
+ }
+ break;
+
+ case XLS_TOKEN( sheetPr ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( tabColor ): getWorksheetSettings().importTabColor( rAttribs ); break;
+ case XLS_TOKEN( outlinePr ): getWorksheetSettings().importOutlinePr( rAttribs ); break;
+ case XLS_TOKEN( pageSetUpPr ): importPageSetUpPr( rAttribs ); break;
+ }
+ break;
+
+ case XLS_TOKEN( sheetViews ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( sheetView ): getSheetViewSettings().importSheetView( rAttribs ); return this;
+ }
+ break;
+ case XLS_TOKEN( sheetView ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( pane ): getSheetViewSettings().importPane( rAttribs ); break;
+ case XLS_TOKEN( selection ): getSheetViewSettings().importSelection( rAttribs ); break;
+ }
+ break;
+
+ case XLS_TOKEN( cols ):
+ if( nElement == XLS_TOKEN( col ) ) importCol( rAttribs );
+ break;
+ case XLS_TOKEN( mergeCells ):
+ if( nElement == XLS_TOKEN( mergeCell ) ) importMergeCell( rAttribs );
+ break;
+ case XLS_TOKEN( hyperlinks ):
+ if( nElement == XLS_TOKEN( hyperlink ) ) importHyperlink( rAttribs );
+ break;
+ case XLS_TOKEN( rowBreaks ):
+ if( nElement == XLS_TOKEN( brk ) ) importBrk( rAttribs, true );
+ break;
+ case XLS_TOKEN( colBreaks ):
+ if( nElement == XLS_TOKEN( brk ) ) importBrk( rAttribs, false );
+ break;
+
+ case XLS_TOKEN( headerFooter ):
+ switch( nElement )
+ {
+ case XLS_TOKEN( firstHeader ):
+ case XLS_TOKEN( firstFooter ):
+ case XLS_TOKEN( oddHeader ):
+ case XLS_TOKEN( oddFooter ):
+ case XLS_TOKEN( evenHeader ):
+ case XLS_TOKEN( evenFooter ): return this; // collect h/f contents in onEndElement()
+ }
+ break;
+
+ case XLS_TOKEN( oleObjects ):
+ if( nElement == XLS_TOKEN( oleObject ) ) importOleObject( rAttribs );
+ break;
+ case XLS_TOKEN( controls ):
+ if( nElement == XLS_TOKEN( control ) ) importControl( rAttribs );
+ break;
+ }
+ return 0;
+}
+
+void OoxWorksheetFragment::onEndElement( const OUString& rChars )
+{
+ switch( getCurrentElement() )
+ {
+ 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, getCurrentElement() );
+ break;
+ }
+}
+
+ContextHandlerRef OoxWorksheetFragment::onCreateRecordContext( sal_Int32 nRecId, RecordInputStream& rStrm )
+{
+ switch( getCurrentElement() )
+ {
+ case XML_ROOT_CONTEXT:
+ if( nRecId == OOBIN_ID_WORKSHEET ) return this;
+ break;
+
+ case OOBIN_ID_WORKSHEET:
+ switch( nRecId )
+ {
+ case OOBIN_ID_SHEETDATA: return new OoxSheetDataContext( *this );
+ case OOBIN_ID_CONDFORMATTING: return new OoxCondFormatContext( *this );
+ case OOBIN_ID_DATAVALIDATIONS: return new OoxDataValidationsContext( *this );
+
+ case OOBIN_ID_SHEETVIEWS:
+ case OOBIN_ID_COLS:
+ case OOBIN_ID_MERGECELLS:
+ case OOBIN_ID_ROWBREAKS:
+ case OOBIN_ID_COLBREAKS:
+ case OOBIN_ID_OLEOBJECTS:
+ case OOBIN_ID_CONTROLS: return this;
+
+ case OOBIN_ID_SHEETPR: getWorksheetSettings().importSheetPr( rStrm ); break;
+ case OOBIN_ID_DIMENSION: importDimension( rStrm ); break;
+ case OOBIN_ID_SHEETFORMATPR: importSheetFormatPr( rStrm ); break;
+ case OOBIN_ID_HYPERLINK: importHyperlink( rStrm ); break;
+ case OOBIN_ID_PAGEMARGINS: getPageSettings().importPageMargins( rStrm ); break;
+ case OOBIN_ID_PAGESETUP: getPageSettings().importPageSetup( getRelations(), rStrm ); break;
+ case OOBIN_ID_PRINTOPTIONS: getPageSettings().importPrintOptions( rStrm ); break;
+ case OOBIN_ID_HEADERFOOTER: getPageSettings().importHeaderFooter( rStrm ); break;
+ case OOBIN_ID_PICTURE: getPageSettings().importPicture( getRelations(), rStrm ); break;
+ case OOBIN_ID_SHEETPROTECTION: getWorksheetSettings().importSheetProtection( rStrm ); break;
+ case OOBIN_ID_PHONETICPR: getWorksheetSettings().importPhoneticPr( rStrm ); break;
+ case OOBIN_ID_DRAWING: importDrawing( rStrm ); break;
+ case OOBIN_ID_LEGACYDRAWING: importLegacyDrawing( rStrm ); break;
+ case OOBIN_ID_SCENARIOS:
+ return new OoxScenariosContext( *this );
+ }
+ break;
+
+ case OOBIN_ID_SHEETVIEWS:
+ switch( nRecId )
+ {
+ case OOBIN_ID_SHEETVIEW: getSheetViewSettings().importSheetView( rStrm ); return this;
+ }
+ break;
+ case OOBIN_ID_SHEETVIEW:
+ switch( nRecId )
+ {
+ case OOBIN_ID_PANE: getSheetViewSettings().importPane( rStrm ); break;
+ case OOBIN_ID_SELECTION: getSheetViewSettings().importSelection( rStrm ); break;
+ }
+ break;
+
+ case OOBIN_ID_COLS:
+ if( nRecId == OOBIN_ID_COL ) importCol( rStrm );
+ break;
+ case OOBIN_ID_MERGECELLS:
+ if( nRecId == OOBIN_ID_MERGECELL ) importMergeCell( rStrm );
+ break;
+ case OOBIN_ID_ROWBREAKS:
+ if( nRecId == OOBIN_ID_BRK ) importBrk( rStrm, true );
+ break;
+ case OOBIN_ID_COLBREAKS:
+ if( nRecId == OOBIN_ID_BRK ) importBrk( rStrm, false );
+ break;
+ case OOBIN_ID_OLEOBJECTS:
+ if( nRecId == OOBIN_ID_OLEOBJECT ) importOleObject( rStrm );
+ break;
+ case OOBIN_ID_CONTROLS:
+ if( nRecId == OOBIN_ID_CONTROL ) importControl( rStrm );
+ break;
+ }
+ return 0;
+}
+
+// oox.core.FragmentHandler2 interface ----------------------------------------
+
+const RecordInfo* OoxWorksheetFragment::getRecordInfos() const
+{
+ static const RecordInfo spRecInfos[] =
+ {
+ { OOBIN_ID_CFRULE, OOBIN_ID_CFRULE + 1 },
+ { OOBIN_ID_COLBREAKS, OOBIN_ID_COLBREAKS + 1 },
+ { OOBIN_ID_COLORSCALE, OOBIN_ID_COLORSCALE + 1 },
+ { OOBIN_ID_COLS, OOBIN_ID_COLS + 1 },
+ { OOBIN_ID_CONDFORMATTING, OOBIN_ID_CONDFORMATTING + 1 },
+ { OOBIN_ID_CONTROLS, OOBIN_ID_CONTROLS + 2 },
+ { OOBIN_ID_CUSTOMSHEETVIEW, OOBIN_ID_CUSTOMSHEETVIEW + 1 },
+ { OOBIN_ID_CUSTOMSHEETVIEWS, OOBIN_ID_CUSTOMSHEETVIEWS + 3 },
+ { OOBIN_ID_DATABAR, OOBIN_ID_DATABAR + 1 },
+ { OOBIN_ID_DATAVALIDATIONS, OOBIN_ID_DATAVALIDATIONS + 1 },
+ { OOBIN_ID_HEADERFOOTER, OOBIN_ID_HEADERFOOTER + 1 },
+ { OOBIN_ID_ICONSET, OOBIN_ID_ICONSET + 1 },
+ { OOBIN_ID_MERGECELLS, OOBIN_ID_MERGECELLS + 1 },
+ { OOBIN_ID_OLEOBJECTS, OOBIN_ID_OLEOBJECTS + 2 },
+ { OOBIN_ID_ROW, -1 },
+ { OOBIN_ID_ROWBREAKS, OOBIN_ID_ROWBREAKS + 1 },
+ { OOBIN_ID_SCENARIO, OOBIN_ID_SCENARIO + 1 },
+ { OOBIN_ID_SCENARIOS, OOBIN_ID_SCENARIOS + 1 },
+ { OOBIN_ID_SHEETDATA, OOBIN_ID_SHEETDATA + 1 },
+ { OOBIN_ID_SHEETVIEW, OOBIN_ID_SHEETVIEW + 1 },
+ { OOBIN_ID_SHEETVIEWS, OOBIN_ID_SHEETVIEWS + 1 },
+ { OOBIN_ID_TABLEPARTS, OOBIN_ID_TABLEPARTS + 2 },
+ { OOBIN_ID_WORKSHEET, OOBIN_ID_WORKSHEET + 1 },
+ { -1, -1 }
+ };
+ return spRecInfos;
+}
+
+void OoxWorksheetFragment::initializeImport()
+{
+ // initial processing in base class WorksheetHelper
+ initializeWorksheetImport();
+
+ // import query table fragments related to this worksheet
+ RelationsRef xQueryRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATIONSTYPE( "queryTable" ) );
+ for( Relations::const_iterator aIt = xQueryRels->begin(), aEnd = xQueryRels->end(); aIt != aEnd; ++aIt )
+ importOoxFragment( new OoxQueryTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
+
+ // import pivot table fragments related to this worksheet
+ RelationsRef xPivotRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATIONSTYPE( "pivotTable" ) );
+ for( Relations::const_iterator aIt = xPivotRels->begin(), aEnd = xPivotRels->end(); aIt != aEnd; ++aIt )
+ importOoxFragment( new OoxPivotTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
+}
+
+void OoxWorksheetFragment::finalizeImport()
+{
+ // final processing in base class WorksheetHelper
+ finalizeWorksheetImport();
+}
+
+// private --------------------------------------------------------------------
+
+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::importDimension( const AttributeList& rAttribs )
+{
+ CellRangeAddress aRange;
+ getAddressConverter().convertToCellRangeUnchecked( aRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex() );
+ /* OOXML stores the used area, if existing, or "A1" if the sheet is empty.
+ In case of "A1", the dimension at the WorksheetHelper object will not
+ be set. If the cell A1 exists, the used area will be updated while
+ importing the cell. */
+ if( (aRange.EndColumn > 0) || (aRange.EndRow > 0) )
+ extendUsedArea( 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 )
+{
+ ColumnModel aModel;
+ aModel.mnFirstCol = rAttribs.getInteger( XML_min, -1 );
+ aModel.mnLastCol = rAttribs.getInteger( XML_max, -1 );
+ aModel.mfWidth = rAttribs.getDouble( XML_width, 0.0 );
+ aModel.mnXfId = rAttribs.getInteger( XML_style, -1 );
+ aModel.mnLevel = rAttribs.getInteger( XML_outlineLevel, 0 );
+ aModel.mbShowPhonetic = rAttribs.getBool( XML_phonetic, false );
+ aModel.mbHidden = rAttribs.getBool( XML_hidden, false );
+ aModel.mbCollapsed = rAttribs.getBool( XML_collapsed, false );
+ // set column properties in the current sheet
+ setColumnModel( aModel );
+}
+
+void OoxWorksheetFragment::importMergeCell( const AttributeList& rAttribs )
+{
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex(), true, true ) )
+ setMergedRange( aRange );
+}
+
+void OoxWorksheetFragment::importHyperlink( const AttributeList& rAttribs )
+{
+ HyperlinkModel aModel;
+ if( getAddressConverter().convertToCellRange( aModel.maRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex(), true, true ) )
+ {
+ aModel.maTarget = getRelations().getExternalTargetFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ aModel.maLocation = rAttribs.getXString( XML_location, OUString() );
+ aModel.maDisplay = rAttribs.getXString( XML_display, OUString() );
+ aModel.maTooltip = rAttribs.getXString( XML_tooltip, OUString() );
+ setHyperlink( aModel );
+ }
+}
+
+void OoxWorksheetFragment::importBrk( const AttributeList& rAttribs, bool bRowBreak )
+{
+ PageBreakModel aModel;
+ aModel.mnColRow = rAttribs.getInteger( XML_id, 0 );
+ aModel.mnMin = rAttribs.getInteger( XML_min, aModel.mnColRow );
+ aModel.mnMax = rAttribs.getInteger( XML_max, aModel.mnColRow );
+ aModel.mbManual = rAttribs.getBool( XML_man, false );
+ setPageBreak( aModel, bRowBreak );
+}
+
+void OoxWorksheetFragment::importDrawing( const AttributeList& rAttribs )
+{
+ setDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
+}
+
+void OoxWorksheetFragment::importLegacyDrawing( const AttributeList& rAttribs )
+{
+ setVmlDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
+}
+
+void OoxWorksheetFragment::importOleObject( const AttributeList& rAttribs )
+{
+ ::oox::vml::OleObjectInfo aInfo;
+ aInfo.setShapeId( rAttribs.getInteger( XML_shapeId, 0 ) );
+ OSL_ENSURE( rAttribs.hasAttribute( XML_link ) != rAttribs.hasAttribute( R_TOKEN( id ) ),
+ "OoxWorksheetFragment::importOleObject - OLE object must be either linked or embedded" );
+ aInfo.mbLinked = rAttribs.hasAttribute( XML_link );
+ if( aInfo.mbLinked )
+ aInfo.maTargetLink = getFormulaParser().importOleTargetLink( rAttribs.getString( XML_link, OUString() ) );
+ else if( rAttribs.hasAttribute( R_TOKEN( id ) ) )
+ importEmbeddedOleData( aInfo.maEmbeddedData, rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ aInfo.maProgId = rAttribs.getString( XML_progId, OUString() );
+ aInfo.mbShowAsIcon = rAttribs.getToken( XML_dvAspect, XML_DVASPECT_CONTENT ) == XML_DVASPECT_ICON;
+ aInfo.mbAutoUpdate = rAttribs.getToken( XML_oleUpdate, XML_OLEUPDATE_ONCALL ) == XML_OLEUPDATE_ALWAYS;
+ aInfo.mbAutoLoad = rAttribs.getBool( XML_autoLoad, false );
+ getVmlDrawing().registerOleObject( aInfo );
+}
+
+void OoxWorksheetFragment::importControl( const AttributeList& rAttribs )
+{
+ ::oox::vml::ControlInfo aInfo;
+ aInfo.setShapeId( rAttribs.getInteger( XML_shapeId, 0 ) );
+ aInfo.maFragmentPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ aInfo.maName = rAttribs.getString( XML_name, OUString() );
+ getVmlDrawing().registerControl( aInfo );
+}
+
+void OoxWorksheetFragment::importDimension( RecordInputStream& rStrm )
+{
+ BinRange aBinRange;
+ aBinRange.read( rStrm );
+ CellRangeAddress aRange;
+ getAddressConverter().convertToCellRangeUnchecked( aRange, aBinRange, getSheetIndex() );
+ /* BIFF12 stores the used area, if existing, or "A1" if the sheet is
+ empty. In case of "A1", the dimension at the WorksheetHelper object
+ will not be set. If the cell A1 exists, the used area will be updated
+ while importing the cell. */
+ if( (aRange.EndColumn > 0) || (aRange.EndRow > 0) )
+ extendUsedArea( 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 )
+{
+ ColumnModel aModel;
+
+ sal_Int32 nWidth;
+ sal_uInt16 nFlags;
+ rStrm >> aModel.mnFirstCol >> aModel.mnLastCol >> nWidth >> aModel.mnXfId >> nFlags;
+
+ // column indexes are 0-based in OOBIN, but ColumnModel expects 1-based
+ ++aModel.mnFirstCol;
+ ++aModel.mnLastCol;
+ // width is stored as 1/256th of a character in OOBIN, convert to entire character
+ aModel.mfWidth = static_cast< double >( nWidth ) / 256.0;
+ // equal flags in BIFF and OOBIN
+ aModel.mnLevel = extractValue< sal_Int32 >( nFlags, 8, 3 );
+ aModel.mbShowPhonetic = getFlag( nFlags, BIFF_COLINFO_SHOWPHONETIC );
+ aModel.mbHidden = getFlag( nFlags, BIFF_COLINFO_HIDDEN );
+ aModel.mbCollapsed = getFlag( nFlags, BIFF_COLINFO_COLLAPSED );
+ // set column properties in the current sheet
+ setColumnModel( aModel );
+}
+
+void OoxWorksheetFragment::importMergeCell( RecordInputStream& rStrm )
+{
+ BinRange aBinRange;
+ rStrm >> aBinRange;
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, aBinRange, getSheetIndex(), true, true ) )
+ setMergedRange( aRange );
+}
+
+void OoxWorksheetFragment::importHyperlink( RecordInputStream& rStrm )
+{
+ BinRange aBinRange;
+ rStrm >> aBinRange;
+ HyperlinkModel aModel;
+ if( getAddressConverter().convertToCellRange( aModel.maRange, aBinRange, getSheetIndex(), true, true ) )
+ {
+ aModel.maTarget = getRelations().getExternalTargetFromRelId( rStrm.readString() );
+ rStrm >> aModel.maLocation >> aModel.maTooltip >> aModel.maDisplay;
+ setHyperlink( aModel );
+ }
+}
+
+void OoxWorksheetFragment::importBrk( RecordInputStream& rStrm, bool bRowBreak )
+{
+ PageBreakModel aModel;
+ sal_Int32 nManual;
+ rStrm >> aModel.mnColRow >> aModel.mnMin >> aModel.mnMax >> nManual;
+ aModel.mbManual = nManual != 0;
+ setPageBreak( aModel, bRowBreak );
+}
+
+void OoxWorksheetFragment::importDrawing( RecordInputStream& rStrm )
+{
+ setDrawingPath( getFragmentPathFromRelId( rStrm.readString() ) );
+}
+
+void OoxWorksheetFragment::importLegacyDrawing( RecordInputStream& rStrm )
+{
+ setVmlDrawingPath( getFragmentPathFromRelId( rStrm.readString() ) );
+}
+
+void OoxWorksheetFragment::importOleObject( RecordInputStream& rStrm )
+{
+ ::oox::vml::OleObjectInfo aInfo;
+ sal_Int32 nAspect, nUpdateMode, nShapeId;
+ sal_uInt16 nFlags;
+ rStrm >> nAspect >> nUpdateMode >> nShapeId >> nFlags >> aInfo.maProgId;
+ aInfo.mbLinked = getFlag( nFlags, OOBIN_OLEOBJECT_LINKED );
+ if( aInfo.mbLinked )
+ aInfo.maTargetLink = getFormulaParser().importOleTargetLink( rStrm );
+ else
+ importEmbeddedOleData( aInfo.maEmbeddedData, rStrm.readString() );
+ aInfo.setShapeId( nShapeId );
+ aInfo.mbShowAsIcon = nAspect == OOBIN_OLEOBJECT_ICON;
+ aInfo.mbAutoUpdate = nUpdateMode == OOBIN_OLEOBJECT_ALWAYS;
+ aInfo.mbAutoLoad = getFlag( nFlags, OOBIN_OLEOBJECT_AUTOLOAD );
+ getVmlDrawing().registerOleObject( aInfo );
+}
+
+void OoxWorksheetFragment::importControl( RecordInputStream& rStrm )
+{
+ ::oox::vml::ControlInfo aInfo;
+ aInfo.setShapeId( rStrm.readInt32() );
+ aInfo.maFragmentPath = getFragmentPathFromRelId( rStrm.readString() );
+ rStrm >> aInfo.maName;
+ getVmlDrawing().registerControl( aInfo );
+}
+
+void OoxWorksheetFragment::importEmbeddedOleData( StreamDataSequence& orEmbeddedData, const OUString& rRelId )
+{
+ OUString aFragmentPath = getFragmentPathFromRelId( rRelId );
+ if( aFragmentPath.getLength() > 0 )
+ getBaseFilter().importBinaryData( orEmbeddedData, aFragmentPath );
+}
+
+// ============================================================================
+
+BiffWorksheetFragment::BiffWorksheetFragment( const BiffWorkbookFragmentBase& rParent, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
+ BiffWorksheetFragmentBase( rParent, xProgressBar, eSheetType, nSheet )
+{
+}
+
+BiffWorksheetFragment::~BiffWorksheetFragment()
+{
+}
+
+bool BiffWorksheetFragment::importFragment()
+{
+ // 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( mrStrm.startNextRecord() && (mrStrm.getRecId() != BIFF_ID_EOF) )
+ {
+ if( isBofRecord() )
+ {
+ // skip unknown embedded fragments (BOF/EOF blocks)
+ skipFragment();
+ }
+ else
+ {
+ // cache base stream position to detect if record is already processed
+ sal_Int64 nStrmPos = mrStrm.tellBase();
+ sal_uInt16 nRecId = mrStrm.getRecId();
+
+ switch( nRecId )
+ {
+ // records in all BIFF versions
+ case BIFF_ID_BOTTOMMARGIN: rPageSett.importBottomMargin( mrStrm ); break;
+ case BIFF_ID_CALCCOUNT: rWorkbookSett.importCalcCount( mrStrm ); break;
+ case BIFF_ID_CALCMODE: rWorkbookSett.importCalcMode( mrStrm ); break;
+ case BIFF_ID_DEFCOLWIDTH: importDefColWidth(); break;
+ case BIFF_ID_DELTA: rWorkbookSett.importDelta( mrStrm ); break;
+ case BIFF2_ID_DIMENSION: importDimension(); break;
+ case BIFF3_ID_DIMENSION: importDimension(); break;
+ case BIFF_ID_FOOTER: rPageSett.importFooter( mrStrm ); break;
+ case BIFF_ID_HEADER: rPageSett.importHeader( mrStrm ); break;
+ case BIFF_ID_HORPAGEBREAKS: importPageBreaks( true ); break;
+ case BIFF_ID_ITERATION: rWorkbookSett.importIteration( mrStrm ); break;
+ case BIFF_ID_LEFTMARGIN: rPageSett.importLeftMargin( mrStrm ); break;
+ case BIFF_ID_PANE: rSheetViewSett.importPane( mrStrm ); break;
+ case BIFF_ID_PASSWORD: rWorksheetSett.importPassword( mrStrm ); break;
+ case BIFF_ID_PRINTGRIDLINES: rPageSett.importPrintGridLines( mrStrm ); break;
+ case BIFF_ID_PRINTHEADERS: rPageSett.importPrintHeaders( mrStrm ); break;
+ case BIFF_ID_PROTECT: rWorksheetSett.importProtect( mrStrm ); break;
+ case BIFF_ID_REFMODE: rWorkbookSett.importRefMode( mrStrm ); break;
+ case BIFF_ID_RIGHTMARGIN: rPageSett.importRightMargin( mrStrm ); break;
+ case BIFF_ID_SELECTION: rSheetViewSett.importSelection( mrStrm ); break;
+ case BIFF_ID_TOPMARGIN: rPageSett.importTopMargin( mrStrm ); break;
+ case BIFF_ID_VERPAGEBREAKS: importPageBreaks( false ); break;
+
+ // BIFF specific records
+ default: switch( getBiff() )
+ {
+ case BIFF2: switch( nRecId )
+ {
+ case BIFF_ID_COLUMNDEFAULT: importColumnDefault(); break;
+ case BIFF_ID_COLWIDTH: importColWidth(); break;
+ case BIFF2_ID_DEFROWHEIGHT: importDefRowHeight(); break;
+ case BIFF2_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+ }
+ break;
+
+ case BIFF3: switch( nRecId )
+ {
+ case BIFF_ID_COLINFO: importColInfo(); break;
+ case BIFF_ID_DEFCOLWIDTH: importDefColWidth(); break;
+ case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight(); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
+ case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( mrStrm ); break;
+ case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( mrStrm ); break;
+ case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( mrStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( mrStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+
+ }
+ break;
+
+ case BIFF4: switch( nRecId )
+ {
+ case BIFF_ID_COLINFO: importColInfo(); break;
+ case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight(); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( mrStrm ); break;
+ case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( mrStrm ); break;
+ case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( mrStrm ); break;
+ case BIFF_ID_STANDARDWIDTH: importStandardWidth(); break;
+ case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( mrStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( mrStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+ }
+ break;
+
+ case BIFF5: switch( nRecId )
+ {
+ case BIFF_ID_COLINFO: importColInfo(); break;
+ case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight(); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
+ case BIFF_ID_MERGEDCELLS: importMergedCells(); break; // #i62300# also in BIFF5
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( mrStrm ); break;
+ case BIFF_ID_PTDEFINITION: importPTDefinition(); break;
+ case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( mrStrm ); break;
+ case BIFF_ID_SCENPROTECT: rWorksheetSett.importScenProtect( mrStrm ); break;
+ case BIFF_ID_SCL: rSheetViewSett.importScl( mrStrm ); break;
+ case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( mrStrm ); break;
+ case BIFF_ID_STANDARDWIDTH: importStandardWidth(); break;
+ case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( mrStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( mrStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+ }
+ break;
+
+ case BIFF8: switch( nRecId )
+ {
+ case BIFF_ID_CFHEADER: rCondFormats.importCfHeader( mrStrm ); break;
+ case BIFF_ID_CODENAME: rWorksheetSett.importCodeName( mrStrm ); break;
+ case BIFF_ID_COLINFO: importColInfo(); break;
+ case BIFF_ID_DATAVALIDATION: importDataValidation(); break;
+ case BIFF_ID_DATAVALIDATIONS: importDataValidations(); break;
+ case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight(); break;
+ case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
+ case BIFF_ID_HYPERLINK: importHyperlink(); break;
+ case BIFF_ID_LABELRANGES: importLabelRanges(); break;
+ case BIFF_ID_MERGEDCELLS: importMergedCells(); break;
+ case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
+ case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( mrStrm ); break;
+ case BIFF_ID_PHONETICPR: rWorksheetSett.importPhoneticPr( mrStrm ); break;
+ case BIFF_ID_PICTURE: rPageSett.importPicture( mrStrm ); break;
+ case BIFF_ID_PTDEFINITION: importPTDefinition(); break;
+ case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( mrStrm ); break;
+ case BIFF_ID_SCENARIOS: importScenarios(); break;
+ case BIFF_ID_SCENPROTECT: rWorksheetSett.importScenProtect( mrStrm ); break;
+ case BIFF_ID_SCL: rSheetViewSett.importScl( mrStrm ); break;
+ case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( mrStrm ); break;
+ case BIFF_ID_SHAREDFEATHEAD: importSharedFeatHead(); break;
+ case BIFF_ID_STANDARDWIDTH: importStandardWidth(); break;
+ case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( mrStrm ); break;
+ case BIFF_ID_VCENTER: rPageSett.importVerCenter( mrStrm ); break;
+ case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
+ }
+ break;
+
+ case BIFF_UNKNOWN: break;
+ }
+ }
+
+ // record not processed, try cell records
+ if( mrStrm.tellBase() == nStrmPos )
+ aSheetData.importRecord();
+ // record still not processed, try pivot table records
+ if( mxPTContext.get() && (mrStrm.tellBase() == nStrmPos) )
+ mxPTContext->importRecord();
+ }
+ }
+
+ // final processing in base class WorksheetHelper
+ finalizeWorksheetImport();
+ return mrStrm.getRecId() == BIFF_ID_EOF;
+}
+
+// private --------------------------------------------------------------------
+
+void BiffWorksheetFragment::importColInfo()
+{
+ sal_uInt16 nFirstCol, nLastCol, nWidth, nXfId, nFlags;
+ mrStrm >> nFirstCol >> nLastCol >> nWidth >> nXfId >> nFlags;
+
+ ColumnModel aModel;
+ // column indexes are 0-based in BIFF, but ColumnModel expects 1-based
+ aModel.mnFirstCol = static_cast< sal_Int32 >( nFirstCol ) + 1;
+ aModel.mnLastCol = static_cast< sal_Int32 >( nLastCol ) + 1;
+ // width is stored as 1/256th of a character in BIFF, convert to entire character
+ aModel.mfWidth = static_cast< double >( nWidth ) / 256.0;
+ aModel.mnXfId = nXfId;
+ aModel.mnLevel = extractValue< sal_Int32 >( nFlags, 8, 3 );
+ aModel.mbShowPhonetic = getFlag( nFlags, BIFF_COLINFO_SHOWPHONETIC );
+ aModel.mbHidden = getFlag( nFlags, BIFF_COLINFO_HIDDEN );
+ aModel.mbCollapsed = getFlag( nFlags, BIFF_COLINFO_COLLAPSED );
+ // set column properties in the current sheet
+ setColumnModel( aModel );
+}
+
+void BiffWorksheetFragment::importColumnDefault()
+{
+ sal_uInt16 nFirstCol, nLastCol, nXfId;
+ mrStrm >> nFirstCol >> nLastCol >> nXfId;
+ setDefaultColumnFormat( nFirstCol, nLastCol, nXfId );
+}
+
+void BiffWorksheetFragment::importColWidth()
+{
+ sal_uInt8 nFirstCol, nLastCol;
+ sal_uInt16 nWidth;
+ mrStrm >> nFirstCol >> nLastCol >> nWidth;
+
+ ColumnModel aModel;
+ // column indexes are 0-based in BIFF, but ColumnModel expects 1-based
+ aModel.mnFirstCol = static_cast< sal_Int32 >( nFirstCol ) + 1;
+ aModel.mnLastCol = static_cast< sal_Int32 >( nLastCol ) + 1;
+ // width is stored as 1/256th of a character in BIFF, convert to entire character
+ aModel.mfWidth = static_cast< double >( nWidth ) / 256.0;
+ // set column properties in the current sheet
+ setColumnModel( aModel );
+}
+
+void BiffWorksheetFragment::importDefColWidth()
+{
+ /* 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( mrStrm.readuInt16() );
+}
+
+void BiffWorksheetFragment::importDefRowHeight()
+{
+ sal_uInt16 nFlags = BIFF_DEFROW_CUSTOMHEIGHT, nHeight;
+ if( getBiff() != BIFF2 )
+ mrStrm >> nFlags;
+ mrStrm >> 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()
+{
+ sal_Int32 nObjId;
+ mrStrm.skip( 10 );
+ mrStrm >> nObjId;
+ //! TODO: invalidate object id in drawing object manager
+}
+
+namespace {
+
+OUString lclReadDataValMessage( BiffInputStream& rStrm )
+{
+ // empty strings are single NUL characters (string length is 1)
+ OUString aMessage = rStrm.readUniString( true );
+ if( (aMessage.getLength() == 1) && (aMessage[ 0 ] == 0) )
+ aMessage = OUString();
+ return aMessage;
+}
+
+ApiTokenSequence lclReadDataValFormula( BiffInputStream& rStrm, FormulaParser& rParser )
+{
+ sal_uInt16 nFmlaSize = rStrm.readuInt16();
+ rStrm.skip( 2 );
+ // enable NUL characters, string list is single tStr token with NUL separators
+ TokensFormulaContext aContext( true, false, true );
+ rParser.importFormula( aContext, rStrm, &nFmlaSize );
+ return aContext.getTokens();
+}
+
+} // namespace
+
+void BiffWorksheetFragment::importDataValidation()
+{
+ ValidationModel aModel;
+
+ // flags
+ sal_uInt32 nFlags;
+ mrStrm >> nFlags;
+ aModel.setBinType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
+ aModel.setBinOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
+ aModel.setBinErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
+ aModel.mbAllowBlank = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
+ aModel.mbNoDropDown = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
+ aModel.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
+ aModel.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
+
+ // message strings
+ aModel.maInputTitle = lclReadDataValMessage( mrStrm );
+ aModel.maErrorTitle = lclReadDataValMessage( mrStrm );
+ aModel.maInputMessage = lclReadDataValMessage( mrStrm );
+ aModel.maErrorMessage = lclReadDataValMessage( mrStrm );
+
+ // condition formula(s)
+ FormulaParser& rParser = getFormulaParser();
+ aModel.maTokens1 = lclReadDataValFormula( mrStrm, rParser );
+ aModel.maTokens2 = lclReadDataValFormula( mrStrm, rParser );
+ // process string list of a list validation (convert to list of string tokens)
+ if( (aModel.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
+ rParser.convertStringToStringList( aModel.maTokens1, '\0', true );
+
+ // cell range list
+ BinRangeList aRanges;
+ mrStrm >> aRanges;
+ getAddressConverter().convertToCellRangeList( aModel.maRanges, aRanges, getSheetIndex(), true );
+
+ // set validation data
+ setValidation( aModel );
+}
+
+void BiffWorksheetFragment::importDimension()
+{
+ // 32-bit row indexes in BIFF8
+ bool bInt32Rows = (mrStrm.getRecId() == BIFF3_ID_DIMENSION) && (getBiff() == BIFF8);
+ BinRange aBinRange;
+ aBinRange.read( mrStrm, true, bInt32Rows );
+ /* BIFF stores the used area with end column and end row increased by 1
+ (first unused column and row). */
+ if( (aBinRange.maFirst.mnCol < aBinRange.maLast.mnCol) && (aBinRange.maFirst.mnRow < aBinRange.maLast.mnRow) )
+ {
+ // reduce range to used area
+ --aBinRange.maLast.mnCol;
+ --aBinRange.maLast.mnRow;
+ CellRangeAddress aRange;
+ getAddressConverter().convertToCellRangeUnchecked( aRange, aBinRange, getSheetIndex() );
+ extendUsedArea( aRange );
+ }
+}
+
+void BiffWorksheetFragment::importHyperlink()
+{
+ HyperlinkModel aModel;
+
+ // read cell range for the hyperlink
+ BinRange aBiffRange;
+ mrStrm >> aBiffRange;
+ // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
+ aBiffRange.maFirst.mnCol &= 0xFF;
+ aBiffRange.maLast.mnCol &= 0xFF;
+ if( !getAddressConverter().convertToCellRange( aModel.maRange, aBiffRange, getSheetIndex(), true, true ) )
+ return;
+
+ // try to read the StdHlink data
+ if( !::oox::ole::OleHelper::importStdHlink( aModel, mrStrm, true ) )
+ return;
+
+ // try to read the optional following SCREENTIP record
+ if( (mrStrm.getNextRecId() == BIFF_ID_SCREENTIP) && mrStrm.startNextRecord() )
+ {
+ mrStrm.skip( 2 ); // repeated record id
+ // the cell range, again
+ mrStrm >> aBiffRange;
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, aBiffRange, getSheetIndex(), true, true ) &&
+ (aRange.StartColumn == aModel.maRange.StartColumn) &&
+ (aRange.StartRow == aModel.maRange.StartRow) &&
+ (aRange.EndColumn == aModel.maRange.EndColumn) &&
+ (aRange.EndRow == aModel.maRange.EndRow) )
+ {
+ /* This time, we have no string length, no flag field, and a
+ null-terminated 16-bit character array. */
+ aModel.maTooltip = mrStrm.readNulUnicodeArray();
+ }
+ }
+
+ // store the hyperlink settings
+ setHyperlink( aModel );
+}
+
+void BiffWorksheetFragment::importLabelRanges()
+{
+ BinRangeList aBiffRowRanges, aBiffColRanges;
+ mrStrm >> aBiffRowRanges >> aBiffColRanges;
+ ApiCellRangeList aColRanges, aRowRanges;
+ getAddressConverter().convertToCellRangeList( aColRanges, aBiffColRanges, getSheetIndex(), true );
+ getAddressConverter().convertToCellRangeList( aRowRanges, aBiffRowRanges, getSheetIndex(), true );
+ setLabelRanges( aColRanges, aRowRanges );
+}
+
+void BiffWorksheetFragment::importMergedCells()
+{
+ BinRangeList aBiffRanges;
+ mrStrm >> 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( bool bRowBreak )
+{
+ PageBreakModel aModel;
+ aModel.mbManual = true; // only manual breaks stored in BIFF
+ bool bBiff8 = getBiff() == BIFF8; // skip start/end columns or rows in BIFF8
+
+ sal_uInt16 nCount;
+ mrStrm >> nCount;
+ for( sal_uInt16 nIndex = 0; !mrStrm.isEof() && (nIndex < nCount); ++nIndex )
+ {
+ aModel.mnColRow = mrStrm.readuInt16();
+ setPageBreak( aModel, bRowBreak );
+ if( bBiff8 )
+ mrStrm.skip( 4 );
+ }
+}
+
+void BiffWorksheetFragment::importPTDefinition()
+{
+ mxPTContext.reset( new BiffPivotTableContext( *this, getPivotTables().createPivotTable() ) );
+ mxPTContext->importRecord();
+}
+
+void BiffWorksheetFragment::importScenarios()
+{
+ getScenarios().createSheetScenarios( getSheetIndex() ).importScenarios( mrStrm );
+}
+
+void BiffWorksheetFragment::importSharedFeatHead()
+{
+ mrStrm.skip( 12 );
+ sal_uInt16 nType = mrStrm.readuInt16();
+ mrStrm.skip( 5 );
+ switch( nType )
+ {
+ case BIFF_SHRFEATHEAD_SHEETPROT:
+ if( mrStrm.getRemaining() >= 4 )
+ getWorksheetSettings().importSheetProtection( mrStrm );
+ break;
+ }
+}
+
+void BiffWorksheetFragment::importStandardWidth()
+{
+ sal_uInt16 nWidth;
+ mrStrm >> 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 );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/worksheethelper.cxx b/oox/source/xls/worksheethelper.cxx
new file mode 100644
index 000000000000..57e283a745a7
--- /dev/null
+++ b/oox/source/xls/worksheethelper.cxx
@@ -0,0 +1,2297 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheethelper.hxx"
+#include <algorithm>
+#include <utility>
+#include <list>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/TableValidationVisibility.hpp>
+#include <com/sun/star/sheet/ValidationType.hpp>
+#include <com/sun/star/sheet/ValidationAlertStyle.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
+#include <com/sun/star/sheet/XSheetCondition.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/XMultiFormulaTokens.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/table/XColumnRowRange.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XMergeable.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include "properties.hxx"
+#include "tokens.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/commentsbuffer.hxx"
+#include "oox/xls/condformatbuffer.hxx"
+#include "oox/xls/drawingfragment.hxx"
+#include "oox/xls/formulaparser.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/viewsettings.hxx"
+#include "oox/xls/workbooksettings.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+#include "oox/xls/worksheetsettings.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::awt::Point;
+using ::com::sun::star::awt::Rectangle;
+using ::com::sun::star::awt::Size;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::drawing::XDrawPage;
+using ::com::sun::star::drawing::XDrawPageSupplier;
+using ::com::sun::star::lang::Locale;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::sheet::ConditionOperator;
+using ::com::sun::star::sheet::ValidationType;
+using ::com::sun::star::sheet::ValidationAlertStyle;
+using ::com::sun::star::sheet::XCellAddressable;
+using ::com::sun::star::sheet::XCellRangeAddressable;
+using ::com::sun::star::sheet::XFormulaTokens;
+using ::com::sun::star::sheet::XLabelRanges;
+using ::com::sun::star::sheet::XMultiFormulaTokens;
+using ::com::sun::star::sheet::XMultipleOperation;
+using ::com::sun::star::sheet::XSheetCellRangeContainer;
+using ::com::sun::star::sheet::XSheetCellRanges;
+using ::com::sun::star::sheet::XSheetCondition;
+using ::com::sun::star::sheet::XSheetOutline;
+using ::com::sun::star::sheet::XSpreadsheet;
+using ::com::sun::star::table::BorderLine;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::table::XCell;
+using ::com::sun::star::table::XCellRange;
+using ::com::sun::star::table::XColumnRowRange;
+using ::com::sun::star::table::XTableColumns;
+using ::com::sun::star::table::XTableRows;
+using ::com::sun::star::text::XText;
+using ::com::sun::star::text::XTextContent;
+using ::com::sun::star::text::XTextRange;
+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 ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::util::DateTime;
+using ::com::sun::star::util::XMergeable;
+using ::com::sun::star::util::XNumberFormatsSupplier;
+using ::com::sun::star::util::XNumberFormatTypes;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+void lclUpdateProgressBar( ISegmentProgressBarRef xProgressBar, const CellRangeAddress& rUsedArea, sal_Int32 nRow )
+{
+ if( xProgressBar.get() && (rUsedArea.StartRow <= nRow) && (nRow <= rUsedArea.EndRow) )
+ {
+ double fPosition = static_cast< double >( nRow - rUsedArea.StartRow + 1 ) / (rUsedArea.EndRow - rUsedArea.StartRow + 1);
+ if( xProgressBar->getPosition() < fPosition )
+ xProgressBar->setPosition( fPosition );
+ }
+}
+
+void lclUpdateProgressBar( ISegmentProgressBarRef xProgressBar, double fPosition )
+{
+ if( xProgressBar.get() )
+ xProgressBar->setPosition( fPosition );
+}
+
+// ----------------------------------------------------------------------------
+
+struct ValueRange
+{
+ sal_Int32 mnFirst;
+ sal_Int32 mnLast;
+
+ inline explicit ValueRange( sal_Int32 nValue ) : mnFirst( nValue ), mnLast( nValue ) {}
+ inline explicit ValueRange( sal_Int32 nFirst, sal_Int32 nLast ) : mnFirst( nFirst ), mnLast( nLast ) {}
+};
+
+typedef ::std::vector< ValueRange > ValueRangeVector;
+
+// ----------------------------------------------------------------------------
+
+struct ValueRangeComp
+{
+ inline bool operator()( const ValueRange& rRange, sal_Int32 nValue ) const { return rRange.mnLast < nValue; }
+};
+
+typedef ::std::vector< ValueRange > ValueRangeVector;
+
+// ----------------------------------------------------------------------------
+
+class ValueRangeSet
+{
+public:
+ inline explicit ValueRangeSet() {}
+
+ void insert( sal_Int32 nValue );
+ void intersect( ValueRangeVector& orRanges, sal_Int32 nFirst, sal_Int32 nLast ) const;
+
+private:
+ ValueRangeVector maData;
+};
+
+void ValueRangeSet::insert( sal_Int32 nValue )
+{
+ // find the first range that contains nValue or that follows nValue
+ ValueRangeVector::iterator aBeg = maData.begin();
+ ValueRangeVector::iterator aEnd = maData.end();
+ ValueRangeVector::iterator aNext = ::std::lower_bound( aBeg, aEnd, nValue, ValueRangeComp() );
+
+ // nothing to do if found range contains nValue
+ if( (aNext == aEnd) || (nValue < aNext->mnFirst) )
+ {
+ ValueRangeVector::iterator aPrev = (aNext == aBeg) ? aEnd : (aNext - 1);
+ bool bJoinPrev = (aPrev != aEnd) && (aPrev->mnLast + 1 == nValue);
+ bool bJoinNext = (aNext != aEnd) && (aNext->mnFirst - 1 == nValue);
+ if( bJoinPrev && bJoinNext )
+ {
+ aPrev->mnLast = aNext->mnLast;
+ maData.erase( aNext );
+ }
+ else if( bJoinPrev )
+ ++aPrev->mnLast;
+ else if( bJoinNext )
+ --aNext->mnFirst;
+ else
+ maData.insert( aNext, ValueRange( nValue ) );
+ }
+}
+
+void ValueRangeSet::intersect( ValueRangeVector& orRanges, sal_Int32 nFirst, sal_Int32 nLast ) const
+{
+ orRanges.clear();
+ // find the range that contains nFirst or the first range that follows nFirst
+ ValueRangeVector::const_iterator aIt = ::std::lower_bound( maData.begin(), maData.end(), nFirst, ValueRangeComp() );
+ for( ValueRangeVector::const_iterator aEnd = maData.end(); (aIt != aEnd) && (aIt->mnFirst <= nLast); ++aIt )
+ orRanges.push_back( ValueRange( ::std::max( aIt->mnFirst, nFirst ), ::std::min( aIt->mnLast, nLast ) ) );
+}
+
+} // namespace
+
+// ============================================================================
+// ============================================================================
+
+void CellModel::reset()
+{
+ mxCell.clear();
+ maValueStr = maFormulaRef = OUString();
+ mnCellType = mnFormulaType = XML_TOKEN_INVALID;
+ mnSharedId = mnXfId = mnNumFmtId = -1;
+ mbHasValueStr = mbShowPhonetic = false;
+}
+
+// ----------------------------------------------------------------------------
+
+DataTableModel::DataTableModel() :
+ mb2dTable( false ),
+ mbRowTable( false ),
+ mbRef1Deleted( false ),
+ mbRef2Deleted( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ColumnModel::ColumnModel() :
+ mnFirstCol( -1 ),
+ mnLastCol( -1 ),
+ mfWidth( 0.0 ),
+ mnXfId( -1 ),
+ mnLevel( 0 ),
+ mbShowPhonetic( false ),
+ mbHidden( false ),
+ mbCollapsed( false )
+{
+}
+
+bool ColumnModel::tryExpand( const ColumnModel& rModel )
+{
+ bool bExpandable =
+ (mnFirstCol <= rModel.mnFirstCol) &&
+ (rModel.mnFirstCol <= mnLastCol + 1) &&
+ (mfWidth == rModel.mfWidth) &&
+ // ignore mnXfId, cell formatting is always set directly
+ (mnLevel == rModel.mnLevel) &&
+ (mbHidden == rModel.mbHidden) &&
+ (mbCollapsed == rModel.mbCollapsed);
+
+ if( bExpandable )
+ mnLastCol = rModel.mnLastCol;
+ return bExpandable;
+}
+
+// ----------------------------------------------------------------------------
+
+RowModel::RowModel() :
+ 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 RowModel::tryExpand( const RowModel& rModel )
+{
+ bool bExpandable =
+ (mnFirstRow <= rModel.mnFirstRow) &&
+ (rModel.mnFirstRow <= mnLastRow + 1) &&
+ (mfHeight == rModel.mfHeight) &&
+ // ignore mnXfId, mbCustomFormat, mbShowPhonetic - cell formatting is always set directly
+ (mnLevel == rModel.mnLevel) &&
+ (mbCustomHeight == rModel.mbCustomHeight) &&
+ (mbHidden == rModel.mbHidden) &&
+ (mbCollapsed == rModel.mbCollapsed);
+
+ if( bExpandable )
+ mnLastRow = rModel.mnLastRow;
+ return bExpandable;
+}
+
+// ----------------------------------------------------------------------------
+
+PageBreakModel::PageBreakModel() :
+ mnColRow( 0 ),
+ mbManual( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+HyperlinkModel::HyperlinkModel()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ValidationModel::ValidationModel() :
+ mnType( XML_none ),
+ mnOperator( XML_between ),
+ mnErrorStyle( XML_stop ),
+ mbShowInputMsg( false ),
+ mbShowErrorMsg( false ),
+ mbNoDropDown( false ),
+ mbAllowBlank( false )
+{
+}
+
+void ValidationModel::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 ValidationModel::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 ValidationModel::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_Int16 nSheet );
+
+ /** Returns true, if this helper refers to an existing Calc sheet. */
+ inline bool isValidSheet() const { return mxSheet.is(); }
+
+ /** 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 maUsedArea.Sheet; }
+ /** Returns the XSpreadsheet interface of the current sheet. */
+ inline const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheet >&
+ getSheet() 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 XDrawPage interface of the draw page of the current sheet. */
+ Reference< XDrawPage > getDrawPage() const;
+ /** Returns the size of the entire drawing page in 1/100 mm. */
+ Size getDrawPageSize() const;
+
+ /** Returns the absolute position of the top-left corner of the cell in 1/100 mm. */
+ Point getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const;
+ /** Returns the size of the cell in 1/100 mm. */
+ Size getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ /** Returns the address of the cell that contains the passed point in 1/100 mm. */
+ CellAddress getCellAddressFromPosition( const Point& rPosition, const Size& rDrawPageSize ) const;
+ /** Returns the cell range address that contains the passed rectangle in 1/100 mm. */
+ CellRangeAddress getCellRangeFromRectangle( const Rectangle& rRect ) 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 buffer for all cell comments in this sheet. */
+ inline CommentsBuffer& getComments() { return maComments; }
+ /** 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; }
+ /** Returns the VML drawing page for this sheet (OOX only!). */
+ inline VmlDrawing& getVmlDrawing() { return *mxVmlDrawing; }
+
+ /** Changes the current sheet type. */
+ inline void setSheetType( WorksheetType eSheetType ) { meSheetType = eSheetType; }
+ /** Stores the cell format at the passed address. */
+ void setCellFormat( const CellModel& rModel );
+ /** 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 PageBreakModel& rModel, bool bRowBreak );
+ /** Inserts the hyperlink URL into the spreadsheet. */
+ void setHyperlink( const HyperlinkModel& rModel );
+ /** Inserts the data validation settings into the spreadsheet. */
+ void setValidation( const ValidationModel& rModel );
+ /** Sets the path to the DrawingML fragment of this sheet. */
+ void setDrawingPath( const OUString& rDrawingPath );
+ /** Sets the path to the legacy VML drawing fragment of this sheet. */
+ void setVmlDrawingPath( const OUString& rVmlDrawingPath );
+
+ /** Extends the used area of this sheet by the passed cell position. */
+ void extendUsedArea( const CellAddress& rAddress );
+ /** Extends the used area of this sheet by the passed cell range. */
+ void extendUsedArea( const CellRangeAddress& rRange );
+ /** Extends the shape bounding box by the position and size of the passed rectangle. */
+ void extendShapeBoundingBox( const Rectangle& rShapeRect );
+
+ /** 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 setColumnModel( const ColumnModel& rModel );
+
+ /** 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 setRowModel( const RowModel& rModel );
+
+ /** Converts column default cell formatting. */
+ void convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ) const;
+ /** Converts row default cell formatting. */
+ void convertRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId ) const;
+
+ /** 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, ColumnModel > ColumnModelMap;
+ typedef ::std::map< sal_Int32, RowModel > RowModelMap;
+ typedef ::std::list< HyperlinkModel > HyperlinkModelList;
+ typedef ::std::list< ValidationModel > ValidationModelList;
+
+ struct XfIdRowRange
+ {
+ sal_Int32 mnFirstRow; /// Index of first row.
+ sal_Int32 mnLastRow; /// Index of last row.
+ sal_Int32 mnXfId; /// XF identifier for the row range.
+
+ explicit XfIdRowRange();
+ bool intersects( const CellRangeAddress& rRange ) const;
+ void set( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId );
+ bool tryExpand( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId );
+ };
+
+ 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 CellModel& rModel );
+ bool tryExpand( const CellModel& rModel );
+ 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& rRange );
+ 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 row range. */
+ void writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowRange ) const;
+ /** 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;
+ /** Generates the final URL for the passed hyperlink. */
+ OUString getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const;
+ /** Inserts a hyperlinks into the specified cell. */
+ void insertHyperlink( 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();
+ /** Merges the passed merged range and updates right/bottom cell borders. */
+ void finalizeMergedRange( const CellRangeAddress& rRange );
+
+ /** Imports the drawing layer of the sheet (DrawingML part). */
+ void finalizeDrawing();
+ /** Imports the drawing layer of the sheet (VML part). */
+ void finalizeVmlDrawing();
+ /** Extends the used cell area with the area used by drawing objects. */
+ void finalizeUsedArea();
+
+ /** 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 ColumnModel& rModel );
+
+ /** 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 RowModel& rModel, 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:
+ typedef ::std::auto_ptr< VmlDrawing > VmlDrawingPtr;
+
+ 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 maUrlTextField; /// Service name for a URL text field.
+ const CellAddress& mrMaxApiPos; /// Reference to maximum Calc cell address from address converter.
+ CellRangeAddress maUsedArea; /// Used area of the sheet, and sheet index of the sheet.
+ ColumnModel maDefColModel; /// Default column formatting.
+ ColumnModelMap maColModels; /// Columns sorted by first column index.
+ RowModel maDefRowModel; /// Default row formatting.
+ RowModelMap maRowModels; /// Rows sorted by row index.
+ HyperlinkModelList maHyperlinks; /// Cell ranges containing hyperlinks.
+ ValidationModelList maValidations; /// Cell ranges containing data validation settings.
+ XfIdRowRange maXfIdRowRange; /// Cached XF identifier for a range of rows.
+ XfIdRangeMap maXfIdRanges; /// Collected XF identifiers for cell ranges.
+ MergedRangeList maMergedRanges; /// Merged cell ranges.
+ MergedRangeList maCenterFillRanges; /// Merged cell ranges from 'center across' or 'fill' alignment.
+ ValueRangeSet maManualRowHeights; /// Rows that need manual height independent from own settings.
+ WorksheetSettings maSheetSett; /// Global settings for this sheet.
+ SharedFormulaBuffer maSharedFmlas; /// Buffer for shared formulas in this sheet.
+ CondFormatBuffer maCondFormats; /// Buffer for conditional formattings.
+ CommentsBuffer maComments; /// Buffer for all cell comments in this sheet.
+ PageSettings maPageSett; /// Page/print settings for this sheet.
+ SheetViewSettings maSheetViewSett; /// View settings for this sheet.
+ VmlDrawingPtr mxVmlDrawing; /// Collection of all VML shapes.
+ OUString maDrawingPath; /// Path to DrawingML fragment.
+ OUString maVmlDrawingPath; /// Path to legacy VML drawing fragment.
+ Rectangle maShapeBoundingBox; /// Bounding box for all shapes from all drawings.
+ ISegmentProgressBarRef mxProgressBar; /// Sheet progress bar.
+ ISegmentProgressBarRef mxRowProgress; /// Progress bar for row/cell processing.
+ ISegmentProgressBarRef mxFinalProgress; /// Progress bar for finalization.
+ WorksheetType meSheetType; /// Type of this sheet.
+ Reference< XSpreadsheet > mxSheet; /// Reference to the current sheet.
+ bool mbHasDefWidth; /// True = default column width is set from defaultColWidth attribute.
+};
+
+// ----------------------------------------------------------------------------
+
+WorksheetData::WorksheetData( const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
+ WorkbookHelper( rHelper ),
+ maTrueFormula( CREATE_OUSTRING( "=TRUE()" ) ),
+ maFalseFormula( CREATE_OUSTRING( "=FALSE()" ) ),
+ maSheetCellRanges( CREATE_OUSTRING( "com.sun.star.sheet.SheetCellRanges" ) ),
+ maUrlTextField( CREATE_OUSTRING( "com.sun.star.text.TextField.URL" ) ),
+ mrMaxApiPos( rHelper.getAddressConverter().getMaxApiAddress() ),
+ maUsedArea( nSheet, SAL_MAX_INT32, SAL_MAX_INT32, -1, -1 ),
+ maSheetSett( *this ),
+ maSharedFmlas( *this ),
+ maCondFormats( *this ),
+ maComments( *this ),
+ maPageSett( *this ),
+ maSheetViewSett( *this ),
+ mxProgressBar( xProgressBar ),
+ meSheetType( eSheetType ),
+ mbHasDefWidth( false )
+{
+ mxSheet = getSheetFromDoc( nSheet );
+ if( !mxSheet.is() )
+ maUsedArea.Sheet = -1;
+
+ // default column settings (width and hidden state may be updated later)
+ maDefColModel.mfWidth = 8.5;
+ maDefColModel.mnXfId = -1;
+ maDefColModel.mnLevel = 0;
+ maDefColModel.mbHidden = false;
+ maDefColModel.mbCollapsed = false;
+
+ // default row settings (height and hidden state may be updated later)
+ maDefRowModel.mfHeight = 0.0;
+ maDefRowModel.mnXfId = -1;
+ maDefRowModel.mnLevel = 0;
+ maDefRowModel.mbCustomHeight = false;
+ maDefRowModel.mbCustomFormat = false;
+ maDefRowModel.mbShowPhonetic = false;
+ maDefRowModel.mbHidden = false;
+ maDefRowModel.mbCollapsed = false;
+
+ // buffers
+ if( getFilterType() == FILTER_OOX )
+ mxVmlDrawing.reset( new VmlDrawing( *this ) );
+
+ // prepare progress bars
+ 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
+ {
+ xRanges.set( getDocumentFactory()->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(), UNO_SET_THROW );
+ 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(), UNO_SET_THROW );
+ 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( getSheetIndex(), 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( getSheetIndex(), 0, nFirstRow, 0, nLastRow ) ), UNO_QUERY );
+ if( xRange.is() )
+ xRows = xRange->getRows();
+ }
+ return xRows;
+}
+
+Reference< XDrawPage > WorksheetData::getDrawPage() const
+{
+ Reference< XDrawPage > xDrawPage;
+ try
+ {
+ xDrawPage = Reference< XDrawPageSupplier >( mxSheet, UNO_QUERY_THROW )->getDrawPage();
+ }
+ catch( Exception& )
+ {
+ }
+ return xDrawPage;
+}
+
+Size WorksheetData::getDrawPageSize() const
+{
+ Size aSize;
+ PropertySet aRangeProp( getCellRange( CellRangeAddress( getSheetIndex(), 0, 0, mrMaxApiPos.Column, mrMaxApiPos.Row ) ) );
+ aRangeProp.getProperty( aSize, PROP_Size );
+ return aSize;
+}
+
+Point WorksheetData::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ Point aPoint;
+ PropertySet aCellProp( getCell( CellAddress( getSheetIndex(), nCol, nRow ) ) );
+ aCellProp.getProperty( aPoint, PROP_Position );
+ return aPoint;
+}
+
+Size WorksheetData::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ Size aSize;
+ PropertySet aCellProp( getCell( CellAddress( getSheetIndex(), nCol, nRow ) ) );
+ aCellProp.getProperty( aSize, PROP_Size );
+ return aSize;
+}
+
+namespace {
+
+inline sal_Int32 lclGetMidAddr( sal_Int32 nBegAddr, sal_Int32 nEndAddr, sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos )
+{
+ // use sal_Int64 to prevent integer overflow
+ return nBegAddr + 1 + static_cast< sal_Int32 >( static_cast< sal_Int64 >( nEndAddr - nBegAddr - 2 ) * (nSearchPos - nBegPos) / (nEndPos - nBegPos) );
+}
+
+bool lclPrepareInterval( sal_Int32 nBegAddr, sal_Int32& rnMidAddr, sal_Int32 nEndAddr,
+ sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos )
+{
+ // searched position before nBegPos -> use nBegAddr
+ if( nSearchPos <= nBegPos )
+ {
+ rnMidAddr = nBegAddr;
+ return false;
+ }
+
+ // searched position after nEndPos, or begin next to end -> use nEndAddr
+ if( (nSearchPos >= nEndPos) || (nBegAddr + 1 >= nEndAddr) )
+ {
+ rnMidAddr = nEndAddr;
+ return false;
+ }
+
+ /* Otherwise find mid address according to position. lclGetMidAddr() will
+ return an address between nBegAddr and nEndAddr. */
+ rnMidAddr = lclGetMidAddr( nBegAddr, nEndAddr, nBegPos, nEndPos, nSearchPos );
+ return true;
+}
+
+bool lclUpdateInterval( sal_Int32& rnBegAddr, sal_Int32& rnMidAddr, sal_Int32& rnEndAddr,
+ sal_Int32& rnBegPos, sal_Int32 nMidPos, sal_Int32& rnEndPos, sal_Int32 nSearchPos )
+{
+ // nSearchPos < nMidPos: use the interval [begin,mid] in the next iteration
+ if( nSearchPos < nMidPos )
+ {
+ // if rnBegAddr is next to rnMidAddr, the latter is the column/row in question
+ if( rnBegAddr + 1 >= rnMidAddr )
+ return false;
+ // otherwise, set interval end to mid
+ rnEndPos = nMidPos;
+ rnEndAddr = rnMidAddr;
+ rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos );
+ return true;
+ }
+
+ // nSearchPos > nMidPos: use the interval [mid,end] in the next iteration
+ if( nSearchPos > nMidPos )
+ {
+ // if rnMidAddr is next to rnEndAddr, the latter is the column/row in question
+ if( rnMidAddr + 1 >= rnEndAddr )
+ {
+ rnMidAddr = rnEndAddr;
+ return false;
+ }
+ // otherwise, set interval start to mid
+ rnBegPos = nMidPos;
+ rnBegAddr = rnMidAddr;
+ rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos );
+ return true;
+ }
+
+ // nSearchPos == nMidPos: rnMidAddr is the column/row in question, do not loop anymore
+ return false;
+}
+
+} // namespace
+
+CellAddress WorksheetData::getCellAddressFromPosition( const Point& rPosition, const Size& rDrawPageSize ) const
+{
+ // starting cell address and its position in drawing layer (top-left edge)
+ sal_Int32 nBegCol = 0;
+ sal_Int32 nBegRow = 0;
+ Point aBegPos( 0, 0 );
+
+ // end cell address and its position in drawing layer (bottom-right edge)
+ sal_Int32 nEndCol = mrMaxApiPos.Column + 1;
+ sal_Int32 nEndRow = mrMaxApiPos.Row + 1;
+ Point aEndPos( rDrawPageSize.Width, rDrawPageSize.Height );
+
+ // starting point for interval search
+ sal_Int32 nMidCol, nMidRow;
+ bool bLoopCols = lclPrepareInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aEndPos.X, rPosition.X );
+ bool bLoopRows = lclPrepareInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aEndPos.Y, rPosition.Y );
+ Point aMidPos = getCellPosition( nMidCol, nMidRow );
+
+ /* The loop will find the column/row index of the cell right of/below
+ the cell containing the passed point, unless the point is located at
+ the top or left border of the containing cell. */
+ while( bLoopCols || bLoopRows )
+ {
+ bLoopCols = bLoopCols && lclUpdateInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aMidPos.X, aEndPos.X, rPosition.X );
+ bLoopRows = bLoopRows && lclUpdateInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aMidPos.Y, aEndPos.Y, rPosition.Y );
+ aMidPos = getCellPosition( nMidCol, nMidRow );
+ }
+
+ /* The cell left of/above the current search position contains the passed
+ point, unless the point is located on the top/left border of the cell,
+ or the last column/row of the sheet has been reached. */
+ if( aMidPos.X > rPosition.X ) --nMidCol;
+ if( aMidPos.Y > rPosition.Y ) --nMidRow;
+ return CellAddress( getSheetIndex(), nMidCol, nMidRow );
+}
+
+CellRangeAddress WorksheetData::getCellRangeFromRectangle( const Rectangle& rRect ) const
+{
+ Size aPageSize = getDrawPageSize();
+ CellAddress aStartAddr = getCellAddressFromPosition( Point( rRect.X, rRect.Y ), aPageSize );
+ Point aBotRight( rRect.X + rRect.Width, rRect.Y + rRect.Height );
+ CellAddress aEndAddr = getCellAddressFromPosition( aBotRight, aPageSize );
+ bool bMultiCols = aStartAddr.Column < aEndAddr.Column;
+ bool bMultiRows = aStartAddr.Row < aEndAddr.Row;
+ if( bMultiCols || bMultiRows )
+ {
+ /* Reduce end position of the cell range to previous column or row, if
+ the rectangle ends exactly between two columns or rows. */
+ Point aEndPos = getCellPosition( aEndAddr.Column, aEndAddr.Row );
+ if( bMultiCols && (aBotRight.X <= aEndPos.X) )
+ --aEndAddr.Column;
+ if( bMultiRows && (aBotRight.Y <= aEndPos.Y) )
+ --aEndAddr.Row;
+ }
+ return CellRangeAddress( getSheetIndex(), aStartAddr.Column, aStartAddr.Row, aEndAddr.Column, aEndAddr.Row );
+}
+
+void WorksheetData::setCellFormat( const CellModel& rModel )
+{
+ if( rModel.mxCell.is() && ((rModel.mnXfId >= 0) || (rModel.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( rModel.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 )
+ {
+ // check that range cannot be merged with current row, and that range is not in cached row range
+ if( (aIt->second.maRange.EndRow < nLastRow) && !maXfIdRowRange.intersects( aIt->second.maRange ) )
+ {
+ 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( rModel ) )
+ maXfIdRanges[ RowColKey( rModel.maAddress.Row, rModel.maAddress.Column ) ].set( rModel );
+
+ // update merged ranges for 'center across selection' and 'fill'
+ if( const Xf* pXf = getStyles().getCellXf( rModel.mnXfId ).get() )
+ {
+ sal_Int32 nHorAlign = pXf->getAlignment().getModel().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( rModel.mnCellType != XML_TOKEN_INVALID )
+ maCenterFillRanges.push_back( MergedRange( rModel.maAddress, nHorAlign ) );
+ else if( !maCenterFillRanges.empty() )
+ maCenterFillRanges.rbegin()->tryExpand( rModel.maAddress, nHorAlign );
+ }
+ }
+ }
+}
+
+void WorksheetData::setMergedRange( const CellRangeAddress& rRange )
+{
+ maMergedRanges.push_back( MergedRange( rRange ) );
+}
+
+void WorksheetData::setPageBreak( const PageBreakModel& rModel, bool bRowBreak )
+{
+ if( rModel.mbManual && (rModel.mnColRow > 0) )
+ {
+ PropertySet aPropSet( bRowBreak ? getRow( rModel.mnColRow ) : getColumn( rModel.mnColRow ) );
+ aPropSet.setProperty( PROP_IsStartOfNewPage, true );
+ }
+}
+
+void WorksheetData::setHyperlink( const HyperlinkModel& rModel )
+{
+ maHyperlinks.push_back( rModel );
+}
+
+void WorksheetData::setValidation( const ValidationModel& rModel )
+{
+ maValidations.push_back( rModel );
+}
+
+void WorksheetData::setDrawingPath( const OUString& rDrawingPath )
+{
+ maDrawingPath = rDrawingPath;
+}
+
+void WorksheetData::setVmlDrawingPath( const OUString& rVmlDrawingPath )
+{
+ maVmlDrawingPath = rVmlDrawingPath;
+}
+
+void WorksheetData::extendUsedArea( const CellAddress& rAddress )
+{
+ maUsedArea.StartColumn = ::std::min( maUsedArea.StartColumn, rAddress.Column );
+ maUsedArea.StartRow = ::std::min( maUsedArea.StartRow, rAddress.Row );
+ maUsedArea.EndColumn = ::std::max( maUsedArea.EndColumn, rAddress.Column );
+ maUsedArea.EndRow = ::std::max( maUsedArea.EndRow, rAddress.Row );
+}
+
+void WorksheetData::extendUsedArea( const CellRangeAddress& rRange )
+{
+ extendUsedArea( CellAddress( rRange.Sheet, rRange.StartColumn, rRange.StartRow ) );
+ extendUsedArea( CellAddress( rRange.Sheet, rRange.EndColumn, rRange.EndRow ) );
+}
+
+void WorksheetData::extendShapeBoundingBox( const Rectangle& rShapeRect )
+{
+ // scale EMUs to 1/100 mm
+ const UnitConverter& rUnitConv = getUnitConverter();
+ Rectangle aShapeRectHmm(
+ rUnitConv.scaleToMm100( rShapeRect.X, UNIT_EMU ),
+ rUnitConv.scaleToMm100( rShapeRect.Y, UNIT_EMU ),
+ rUnitConv.scaleToMm100( rShapeRect.Width, UNIT_EMU ),
+ rUnitConv.scaleToMm100( rShapeRect.Height, UNIT_EMU ) );
+
+ if( (maShapeBoundingBox.Width == 0) && (maShapeBoundingBox.Height == 0) )
+ {
+ // width and height of maShapeBoundingBox are assumed to be zero on first cell
+ maShapeBoundingBox = aShapeRectHmm;
+ }
+ else
+ {
+ sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, aShapeRectHmm.X + aShapeRectHmm.Width );
+ sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, aShapeRectHmm.Y + aShapeRectHmm.Height );
+ maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, aShapeRectHmm.X );
+ maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, aShapeRectHmm.Y );
+ maShapeBoundingBox.Width = nEndX - maShapeBoundingBox.X;
+ maShapeBoundingBox.Height = nEndY - maShapeBoundingBox.Y;
+ }
+}
+
+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
+ const UnitConverter& rUnitConv = getUnitConverter();
+ maDefColModel.mfWidth = rUnitConv.scaleFromMm100(
+ rUnitConv.scaleToMm100( nWidth, UNIT_DIGIT ) + rUnitConv.scaleToMm100( 5, UNIT_SCREENX ), UNIT_DIGIT );
+ }
+}
+
+void WorksheetData::setDefaultColumnWidth( double fWidth )
+{
+ // overrides a width set with setBaseColumnWidth()
+ if( fWidth > 0.0 )
+ {
+ maDefColModel.mfWidth = fWidth;
+ mbHasDefWidth = true;
+ }
+}
+
+void WorksheetData::setColumnModel( const ColumnModel& rModel )
+{
+ // convert 1-based OOX column indexes to 0-based API column indexes
+ sal_Int32 nFirstCol = rModel.mnFirstCol - 1;
+ sal_Int32 nLastCol = rModel.mnLastCol - 1;
+ if( (0 <= nFirstCol) && (nFirstCol <= mrMaxApiPos.Column) )
+ {
+ // set column formatting directly, nLastCol is checked inside the function
+ convertColumnFormat( nFirstCol, nLastCol, rModel.mnXfId );
+ // expand last entry or add new entry
+ if( maColModels.empty() || !maColModels.rbegin()->second.tryExpand( rModel ) )
+ maColModels[ nFirstCol ] = rModel;
+ }
+}
+
+void WorksheetData::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
+{
+ maDefRowModel.mfHeight = fHeight;
+ maDefRowModel.mbCustomHeight = bCustomHeight;
+ maDefRowModel.mbHidden = bHidden;
+ maDefRowModel.mbThickTop = bThickTop;
+ maDefRowModel.mbThickBottom = bThickBottom;
+}
+
+void WorksheetData::setRowModel( const RowModel& rModel )
+{
+ // convert 1-based OOX row indexes to 0-based API row indexes
+ sal_Int32 nFirstRow = rModel.mnFirstRow - 1;
+ sal_Int32 nLastRow = rModel.mnLastRow - 1;
+ if( (0 <= nFirstRow) && (nFirstRow <= mrMaxApiPos.Row) )
+ {
+ // set row formatting
+ if( rModel.mbCustomFormat )
+ {
+ // try to expand cached row range, if formatting is equal
+ if( (maXfIdRowRange.mnLastRow < 0) || !maXfIdRowRange.tryExpand( nFirstRow, nLastRow, rModel.mnXfId ) )
+ {
+ writeXfIdRowRangeProperties( maXfIdRowRange );
+ maXfIdRowRange.set( nFirstRow, nLastRow, rModel.mnXfId );
+ }
+ }
+ else if( maXfIdRowRange.mnLastRow >= 0 )
+ {
+ // finish last cached row range
+ writeXfIdRowRangeProperties( maXfIdRowRange );
+ maXfIdRowRange.set( -1, -1, -1 );
+ }
+
+ // expand last entry or add new entry
+ if( maRowModels.empty() || !maRowModels.rbegin()->second.tryExpand( rModel ) )
+ maRowModels[ nFirstRow ] = rModel;
+ }
+ lclUpdateProgressBar( mxRowProgress, maUsedArea, nLastRow );
+}
+
+void WorksheetData::convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ) const
+{
+ CellRangeAddress aRange( getSheetIndex(), nFirstCol, 0, nLastCol, mrMaxApiPos.Row );
+ if( getAddressConverter().validateCellRange( aRange, true, false ) )
+ {
+ PropertySet aPropSet( getCellRange( aRange ) );
+ getStyles().writeCellXfToPropertySet( aPropSet, nXfId );
+ }
+}
+
+void WorksheetData::convertRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId ) const
+{
+ CellRangeAddress aRange( getSheetIndex(), 0, nFirstRow, mrMaxApiPos.Column, nLastRow );
+ if( getAddressConverter().validateCellRange( aRange, true, false ) )
+ {
+ PropertySet aPropSet( getCellRange( aRange ) );
+ getStyles().writeCellXfToPropertySet( aPropSet, nXfId );
+ }
+}
+
+void WorksheetData::initializeWorksheetImport()
+{
+ // set default cell style for unused cells
+ PropertySet aPropSet( mxSheet );
+ aPropSet.setProperty( PROP_CellStyle, getStyles().getDefaultStyleName() );
+
+ /* Remember current sheet index in global data, needed by some global
+ objects, e.g. the chart converter. */
+ setCurrentSheetIndex( getSheetIndex() );
+}
+
+void WorksheetData::finalizeWorksheetImport()
+{
+ lclUpdateProgressBar( mxRowProgress, 1.0 );
+ finalizeXfIdRanges();
+ lclUpdateProgressBar( mxFinalProgress, 0.25 );
+ finalizeHyperlinkRanges();
+ finalizeValidationRanges();
+ finalizeMergedRanges();
+ maSheetSett.finalizeImport();
+ maCondFormats.finalizeImport();
+ maPageSett.finalizeImport();
+ maSheetViewSett.finalizeImport();
+ maSheetSett.finalizeImport();
+
+ lclUpdateProgressBar( mxFinalProgress, 0.5 );
+ convertColumns();
+ convertRows();
+ lclUpdateProgressBar( mxFinalProgress, 0.75 );
+ finalizeDrawing();
+ finalizeVmlDrawing();
+ maComments.finalizeImport(); // after VML drawing
+ finalizeUsedArea(); // after DML and VML drawing
+ lclUpdateProgressBar( mxFinalProgress, 1.0 );
+
+ // reset current sheet index in global data
+ setCurrentSheetIndex( -1 );
+}
+
+// private --------------------------------------------------------------------
+
+WorksheetData::XfIdRowRange::XfIdRowRange() :
+ mnFirstRow( -1 ),
+ mnLastRow( -1 ),
+ mnXfId( -1 )
+{
+}
+
+bool WorksheetData::XfIdRowRange::intersects( const CellRangeAddress& rRange ) const
+{
+ return (rRange.StartRow <= mnLastRow) && (mnFirstRow <= rRange.EndRow);
+}
+
+void WorksheetData::XfIdRowRange::set( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId )
+{
+ mnFirstRow = nFirstRow;
+ mnLastRow = nLastRow;
+ mnXfId = nXfId;
+}
+
+bool WorksheetData::XfIdRowRange::tryExpand( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId )
+{
+ if( mnXfId == nXfId )
+ {
+ if( mnLastRow + 1 == nFirstRow )
+ {
+ mnLastRow = nLastRow;
+ return true;
+ }
+ if( mnFirstRow == nLastRow + 1 )
+ {
+ mnFirstRow = nFirstRow;
+ return true;
+ }
+ }
+ return false;
+}
+
+void WorksheetData::XfIdRange::set( const CellModel& rModel )
+{
+ maRange.Sheet = rModel.maAddress.Sheet;
+ maRange.StartColumn = maRange.EndColumn = rModel.maAddress.Column;
+ maRange.StartRow = maRange.EndRow = rModel.maAddress.Row;
+ mnXfId = rModel.mnXfId;
+ mnNumFmtId = rModel.mnNumFmtId;
+}
+
+bool WorksheetData::XfIdRange::tryExpand( const CellModel& rModel )
+{
+ if( (mnXfId == rModel.mnXfId) && (mnNumFmtId == rModel.mnNumFmtId) &&
+ (maRange.StartRow == rModel.maAddress.Row) &&
+ (maRange.EndRow == rModel.maAddress.Row) &&
+ (maRange.EndColumn + 1 == rModel.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::writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowRange ) const
+{
+ if( (rXfIdRowRange.mnLastRow >= 0) && (rXfIdRowRange.mnXfId >= 0) )
+ convertRowFormat( rXfIdRowRange.mnFirstRow, rXfIdRowRange.mnLastRow, rXfIdRowRange.mnXfId );
+}
+
+void WorksheetData::writeXfIdRangeProperties( const XfIdRange& rXfIdRange ) const
+{
+ StylesBuffer& rStyles = getStyles();
+ PropertyMap aPropMap;
+ if( rXfIdRange.mnXfId >= 0 )
+ rStyles.writeCellXfToPropertyMap( aPropMap, rXfIdRange.mnXfId );
+ if( rXfIdRange.mnNumFmtId >= 0 )
+ rStyles.writeNumFmtToPropertyMap( aPropMap, rXfIdRange.mnNumFmtId );
+ PropertySet aPropSet( getCellRange( rXfIdRange.maRange ) );
+ aPropSet.setProperties( aPropMap );
+}
+
+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()
+{
+ // write default formatting of remaining row range
+ writeXfIdRowRangeProperties( maXfIdRowRange );
+ // try to merge remaining inserted ranges
+ mergeXfIdRanges();
+ // write all formatting
+ for( XfIdRangeMap::const_iterator aIt = maXfIdRanges.begin(), aEnd = maXfIdRanges.end(); aIt != aEnd; ++aIt )
+ writeXfIdRangeProperties( aIt->second );
+}
+
+void WorksheetData::finalizeHyperlinkRanges() const
+{
+ for( HyperlinkModelList::const_iterator aIt = maHyperlinks.begin(), aEnd = maHyperlinks.end(); aIt != aEnd; ++aIt )
+ {
+ OUString aUrl = getHyperlinkUrl( *aIt );
+ // try to insert URL into each cell of the range
+ if( aUrl.getLength() > 0 )
+ for( CellAddress aAddress( getSheetIndex(), 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 )
+ insertHyperlink( aAddress, aUrl );
+ }
+}
+
+OUString WorksheetData::getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const
+{
+ OUStringBuffer aUrlBuffer;
+ if( rHyperlink.maTarget.getLength() > 0 )
+ aUrlBuffer.append( getBaseFilter().getAbsoluteUrl( rHyperlink.maTarget ) );
+ if( rHyperlink.maLocation.getLength() > 0 )
+ aUrlBuffer.append( sal_Unicode( '#' ) ).append( rHyperlink.maLocation );
+ OUString aUrl = aUrlBuffer.makeStringAndClear();
+
+ // convert '#SheetName!A1' to '#SheetName.A1'
+ if( (aUrl.getLength() > 0) && (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 sheet names that have been renamed on import
+ OUString aSheetName = aUrl.copy( 1, nSepPos - 1 );
+ OUString aCalcName = getWorksheets().getCalcSheetName( aSheetName );
+ if( aCalcName.getLength() > 0 )
+ aUrl = aUrl.replaceAt( 1, nSepPos - 1, aCalcName );
+ }
+ }
+
+ return aUrl;
+}
+
+void WorksheetData::insertHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const
+{
+ Reference< XCell > xCell = getCell( rAddress );
+ if( xCell.is() ) switch( xCell->getType() )
+ {
+ // #i54261# restrict creation of URL field to text cells
+ case ::com::sun::star::table::CellContentType_TEXT:
+ {
+ Reference< XText > xText( xCell, UNO_QUERY );
+ if( xText.is() )
+ {
+ // create a URL field object and set its properties
+ Reference< XTextContent > xUrlField( getDocumentFactory()->createInstance( maUrlTextField ), UNO_QUERY );
+ OSL_ENSURE( xUrlField.is(), "WorksheetData::insertHyperlink - cannot create text field" );
+ if( xUrlField.is() )
+ {
+ // properties of the URL field
+ PropertySet aPropSet( xUrlField );
+ aPropSet.setProperty( PROP_URL, rUrl );
+ aPropSet.setProperty( PROP_Representation, 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::insertHyperlink - cannot insert text field" );
+ }
+ }
+ }
+ }
+ break;
+
+ // fix for #i31050# disabled, HYPERLINK is not able to return numeric value (#i91351#)
+#if 0
+ // #i31050# replace number with HYPERLINK function
+ case ::com::sun::star::table::CellContentType_VALUE:
+ {
+ Reference< XFormulaTokens > xTokens( xCell, UNO_QUERY );
+ OSL_ENSURE( xTokens.is(), "WorksheetHelper::insertHyperlink - missing formula interface" );
+ if( xTokens.is() )
+ {
+ SimpleFormulaContext aContext( xTokens, false, false );
+ getFormulaParser().convertNumberToHyperlink( aContext, rUrl, xCell->getValue() );
+ }
+ }
+ break;
+#endif
+
+ default:;
+ }
+}
+
+void WorksheetData::finalizeValidationRanges() const
+{
+ for( ValidationModelList::const_iterator aIt = maValidations.begin(), aEnd = maValidations.end(); aIt != aEnd; ++aIt )
+ {
+ PropertySet aPropSet( getCellRangeList( aIt->maRanges ) );
+
+ Reference< XPropertySet > xValidation;
+ if( aPropSet.getProperty( xValidation, PROP_Validation ) && xValidation.is() )
+ {
+ PropertySet aValProps( xValidation );
+ namespace csss = ::com::sun::star::sheet;
+
+ // convert validation type to API enum
+ ValidationType eType = csss::ValidationType_ANY;
+ switch( aIt->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, "WorksheetData::finalizeValidationRanges - unknown validation type" );
+ }
+ aValProps.setProperty( PROP_Type, eType );
+
+ // convert error alert style to API enum
+ ValidationAlertStyle eAlertStyle = csss::ValidationAlertStyle_STOP;
+ switch( aIt->mnErrorStyle )
+ {
+ case XML_information: eAlertStyle = csss::ValidationAlertStyle_INFO; break;
+ case XML_stop: eAlertStyle = csss::ValidationAlertStyle_STOP; break;
+ case XML_warning: eAlertStyle = csss::ValidationAlertStyle_WARNING; break;
+ default: OSL_ENSURE( false, "WorksheetData::finalizeValidationRanges - unknown error style" );
+ }
+ aValProps.setProperty( PROP_ErrorAlertStyle, eAlertStyle );
+
+ // convert dropdown style to API visibility constants
+ sal_Int16 nVisibility = aIt->mbNoDropDown ? csss::TableValidationVisibility::INVISIBLE : csss::TableValidationVisibility::UNSORTED;
+ aValProps.setProperty( PROP_ShowList, nVisibility );
+
+ // messages
+ aValProps.setProperty( PROP_ShowInputMessage, aIt->mbShowInputMsg );
+ aValProps.setProperty( PROP_InputTitle, aIt->maInputTitle );
+ aValProps.setProperty( PROP_InputMessage, aIt->maInputMessage );
+ aValProps.setProperty( PROP_ShowErrorMessage, aIt->mbShowErrorMsg );
+ aValProps.setProperty( PROP_ErrorTitle, aIt->maErrorTitle );
+ aValProps.setProperty( PROP_ErrorMessage, aIt->maErrorMessage );
+
+ // allow blank cells
+ aValProps.setProperty( PROP_IgnoreBlankCells, aIt->mbAllowBlank );
+
+ try
+ {
+ // condition operator
+ Reference< XSheetCondition > xSheetCond( xValidation, UNO_QUERY_THROW );
+ xSheetCond->setOperator( CondFormatBuffer::convertToApiOperator( aIt->mnOperator ) );
+
+ // condition formulas
+ Reference< XMultiFormulaTokens > xTokens( xValidation, UNO_QUERY_THROW );
+ xTokens->setTokens( 0, aIt->maTokens1 );
+ xTokens->setTokens( 1, aIt->maTokens2 );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // write back validation settings to cell range(s)
+ aPropSet.setProperty( PROP_Validation, xValidation );
+ }
+ }
+}
+
+void WorksheetData::finalizeMergedRanges()
+{
+ 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 )
+{
+ 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
+ Reference< XCell > xTopLeft( getCell( CellAddress( getSheetIndex(), rRange.StartColumn, rRange.StartRow ) ), UNO_SET_THROW );
+ PropertySet aTopLeftProp( xTopLeft );
+
+ // copy right border of top-right cell to right border of top-left cell
+ if( bMultiCol )
+ {
+ PropertySet aTopRightProp( getCell( CellAddress( getSheetIndex(), rRange.EndColumn, rRange.StartRow ) ) );
+ BorderLine aLine;
+ if( aTopRightProp.getProperty( aLine, PROP_RightBorder ) )
+ aTopLeftProp.setProperty( PROP_RightBorder, aLine );
+ }
+
+ // copy bottom border of bottom-left cell to bottom border of top-left cell
+ if( bMultiRow )
+ {
+ PropertySet aBottomLeftProp( getCell( CellAddress( getSheetIndex(), rRange.StartColumn, rRange.EndRow ) ) );
+ BorderLine aLine;
+ if( aBottomLeftProp.getProperty( aLine, PROP_BottomBorder ) )
+ aTopLeftProp.setProperty( PROP_BottomBorder, aLine );
+ }
+
+ // #i93609# merged range in a single row: test if manual row height is needed
+ if( !bMultiRow )
+ {
+ bool bTextWrap = aTopLeftProp.getBoolProperty( PROP_IsTextWrapped );
+ if( !bTextWrap && (xTopLeft->getType() == ::com::sun::star::table::CellContentType_TEXT) )
+ {
+ Reference< XText > xText( xTopLeft, UNO_QUERY );
+ bTextWrap = xText.is() && (xText->getString().indexOf( '\x0A' ) >= 0);
+ }
+ if( bTextWrap )
+ maManualRowHeights.insert( rRange.StartRow );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void WorksheetData::finalizeDrawing()
+{
+ OSL_ENSURE( (getFilterType() == FILTER_OOX) || (maDrawingPath.getLength() == 0),
+ "WorksheetData::finalizeDrawing - unexpected DrawingML path" );
+ if( (getFilterType() == FILTER_OOX) && (maDrawingPath.getLength() > 0) )
+ importOoxFragment( new OoxDrawingFragment( *this, maDrawingPath ) );
+}
+
+void WorksheetData::finalizeVmlDrawing()
+{
+ OSL_ENSURE( (getFilterType() == FILTER_OOX) || (maVmlDrawingPath.getLength() == 0),
+ "WorksheetData::finalizeVmlDrawing - unexpected VML path" );
+ if( (getFilterType() == FILTER_OOX) && (maVmlDrawingPath.getLength() > 0) )
+ importOoxFragment( new OoxVmlDrawingFragment( *this, maVmlDrawingPath ) );
+}
+
+void WorksheetData::finalizeUsedArea()
+{
+ /* Extend used area of the sheet by cells covered with drawing objects.
+ Needed if the imported document is inserted as "OLE object from file"
+ and thus does not provide an OLE size property by itself. */
+ if( (maShapeBoundingBox.Width > 0) || (maShapeBoundingBox.Height > 0) )
+ extendUsedArea( getCellRangeFromRectangle( maShapeBoundingBox ) );
+
+ // if no used area is set, default to A1
+ if( maUsedArea.StartColumn > maUsedArea.EndColumn )
+ maUsedArea.StartColumn = maUsedArea.EndColumn = 0;
+ if( maUsedArea.StartRow > maUsedArea.EndRow )
+ maUsedArea.StartRow = maUsedArea.EndRow = 0;
+
+ /* Register the used area of this sheet in global view settings. The
+ global view settings will set the visible area if this document is an
+ embedded OLE object. */
+ getViewSettings().setSheetUsedArea( maUsedArea );
+}
+
+void WorksheetData::convertColumns()
+{
+ sal_Int32 nNextCol = 0;
+ sal_Int32 nMaxCol = mrMaxApiPos.Column;
+ // stores first grouped column index for each level
+ OutlineLevelVec aColLevels;
+
+ for( ColumnModelMap::const_iterator aIt = maColModels.begin(), aEnd = maColModels.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 models, use default column model
+ if( nNextCol < nFirstCol )
+ convertColumns( aColLevels, nNextCol, nFirstCol - 1, maDefColModel );
+ // process the column model
+ 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, maDefColModel );
+ // 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 ColumnModel& rModel )
+{
+ PropertySet aPropSet( getColumns( nFirstCol, nLastCol ) );
+
+ // column width: convert 'number of characters' to column width in 1/100 mm
+ sal_Int32 nWidth = getUnitConverter().scaleToMm100( rModel.mfWidth, UNIT_DIGIT );
+ // macro sheets have double width
+ if( meSheetType == SHEETTYPE_MACROSHEET )
+ nWidth *= 2;
+ if( nWidth > 0 )
+ aPropSet.setProperty( PROP_Width, nWidth );
+
+ // hidden columns: TODO: #108683# hide columns later?
+ if( rModel.mbHidden )
+ aPropSet.setProperty( PROP_IsVisible, false );
+
+ // outline settings for this column range
+ convertOutlines( orColLevels, nFirstCol, rModel.mnLevel, rModel.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( RowModelMap::const_iterator aIt = maRowModels.begin(), aEnd = maRowModels.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 models, use default row model
+ if( nNextRow < nFirstRow )
+ convertRows( aRowLevels, nNextRow, nFirstRow - 1, maDefRowModel );
+ // process the row model
+ convertRows( aRowLevels, nFirstRow, nLastRow, aIt->second, maDefRowModel.mfHeight );
+
+ // cache next row to be processed
+ nNextRow = nLastRow + 1;
+ }
+
+ // remaining default rows to end of sheet
+ convertRows( aRowLevels, nNextRow, nMaxRow, maDefRowModel );
+ // 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 RowModel& rModel, double fDefHeight )
+{
+ // row height: convert points to row height in 1/100 mm
+ double fHeight = (rModel.mfHeight >= 0.0) ? rModel.mfHeight : fDefHeight;
+ sal_Int32 nHeight = getUnitConverter().scaleToMm100( fHeight, UNIT_POINT );
+ if( nHeight > 0 )
+ {
+ ValueRangeVector aManualRows;
+ if( rModel.mbCustomHeight )
+ aManualRows.push_back( ValueRange( nFirstRow, nLastRow ) );
+ else
+ maManualRowHeights.intersect( aManualRows, nFirstRow, nLastRow );
+ for( ValueRangeVector::const_iterator aIt = aManualRows.begin(), aEnd = aManualRows.end(); aIt != aEnd; ++aIt )
+ {
+ PropertySet aPropSet( getRows( aIt->mnFirst, aIt->mnLast ) );
+ aPropSet.setProperty( PROP_Height, nHeight );
+ }
+ }
+
+ // hidden rows: TODO: #108683# hide rows later?
+ if( rModel.mbHidden )
+ {
+ PropertySet aPropSet( getRows( nFirstRow, nLastRow ) );
+ aPropSet.setProperty( PROP_IsVisible, false );
+ }
+
+ // outline settings for this row range
+ convertOutlines( orRowLevels, nFirstRow, rModel.mnLevel, rModel.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( getSheetIndex(), 0, nFirstColRow, 0, nLastColRow );
+ xOutline->group( aRange, ::com::sun::star::table::TableOrientation_ROWS );
+ if( bCollapse )
+ xOutline->hideDetail( aRange );
+ }
+ else
+ {
+ CellRangeAddress aRange( getSheetIndex(), 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::getSheet() const
+{
+ return mrSheetData.getSheet();
+}
+
+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, 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, 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 );
+}
+
+Reference< XDrawPage > WorksheetHelper::getDrawPage() const
+{
+ return mrSheetData.getDrawPage();
+}
+
+Point WorksheetHelper::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return mrSheetData.getCellPosition( nCol, nRow );
+}
+
+Size WorksheetHelper::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return mrSheetData.getCellSize( nCol, nRow );
+}
+
+Size WorksheetHelper::getDrawPageSize() const
+{
+ return mrSheetData.getDrawPageSize();
+}
+
+WorksheetSettings& WorksheetHelper::getWorksheetSettings() const
+{
+ return mrSheetData.getWorksheetSettings();
+}
+
+SharedFormulaBuffer& WorksheetHelper::getSharedFormulas() const
+{
+ return mrSheetData.getSharedFormulas();
+}
+
+CondFormatBuffer& WorksheetHelper::getCondFormats() const
+{
+ return mrSheetData.getCondFormats();
+}
+
+CommentsBuffer& WorksheetHelper::getComments() const
+{
+ return mrSheetData.getComments();
+}
+
+PageSettings& WorksheetHelper::getPageSettings() const
+{
+ return mrSheetData.getPageSettings();
+}
+
+SheetViewSettings& WorksheetHelper::getSheetViewSettings() const
+{
+ return mrSheetData.getSheetViewSettings();
+}
+
+VmlDrawing& WorksheetHelper::getVmlDrawing() const
+{
+ return mrSheetData.getVmlDrawing();
+}
+
+void WorksheetHelper::setStringCell( const Reference< XCell >& rxCell, const OUString& rText ) const
+{
+ 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::setDateTimeCell( const Reference< XCell >& rxCell, const DateTime& rDateTime ) const
+{
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setDateTimeCell - missing cell interface" );
+ // write serial date/time value into the cell
+ double fSerial = getUnitConverter().calcSerialFromDateTime( rDateTime );
+ rxCell->setValue( fSerial );
+ // set appropriate number format
+ using namespace ::com::sun::star::util::NumberFormat;
+ sal_Int16 nStdFmt = (fSerial < 1.0) ? TIME : (((rDateTime.Hours > 0) || (rDateTime.Minutes > 0) || (rDateTime.Seconds > 0)) ? DATETIME : DATE);
+ setStandardNumFmt( rxCell, nStdFmt );
+}
+
+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 formula interface" );
+ if( xTokens.is() )
+ {
+ SimpleFormulaContext aContext( xTokens, false, false );
+ getFormulaParser().convertErrorToFormula( aContext, nErrorCode );
+ }
+}
+
+void WorksheetHelper::setCell( CellModel& orModel ) const
+{
+ OSL_ENSURE( orModel.mxCell.is(), "WorksheetHelper::setCell - missing cell interface" );
+ if( orModel.mbHasValueStr ) switch( orModel.mnCellType )
+ {
+ case XML_b:
+ setBooleanCell( orModel.mxCell, orModel.maValueStr.toDouble() != 0.0 );
+ // #108770# set 'Standard' number format for all Boolean cells
+ orModel.mnNumFmtId = 0;
+ break;
+ case XML_n:
+ orModel.mxCell->setValue( orModel.maValueStr.toDouble() );
+ break;
+ case XML_e:
+ setErrorCell( orModel.mxCell, orModel.maValueStr );
+ break;
+ case XML_str:
+ setStringCell( orModel.mxCell, orModel.maValueStr );
+ break;
+ case XML_s:
+ setSharedStringCell( orModel.mxCell, orModel.maValueStr.toInt32(), orModel.mnXfId );
+ break;
+ }
+}
+
+void WorksheetHelper::setStandardNumFmt( const Reference< XCell >& rxCell, sal_Int16 nStdNumFmt ) const
+{
+ try
+ {
+ Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY_THROW );
+ Reference< XNumberFormatTypes > xNumFmtTypes( xNumFmtsSupp->getNumberFormats(), UNO_QUERY_THROW );
+ sal_Int32 nIndex = xNumFmtTypes->getStandardFormat( nStdNumFmt, Locale() );
+ PropertySet aPropSet( rxCell );
+ aPropSet.setProperty( PROP_NumberFormat, nIndex );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void WorksheetHelper::setSheetType( WorksheetType eSheetType )
+{
+ mrSheetData.setSheetType( eSheetType );
+}
+
+void WorksheetHelper::setCellFormat( const CellModel& rModel )
+{
+ mrSheetData.setCellFormat( rModel );
+}
+
+void WorksheetHelper::setMergedRange( const CellRangeAddress& rRange )
+{
+ mrSheetData.setMergedRange( rRange );
+}
+
+void WorksheetHelper::setPageBreak( const PageBreakModel& rModel, bool bRowBreak )
+{
+ mrSheetData.setPageBreak( rModel, bRowBreak );
+}
+
+void WorksheetHelper::setHyperlink( const HyperlinkModel& rModel )
+{
+ mrSheetData.setHyperlink( rModel );
+}
+
+void WorksheetHelper::setValidation( const ValidationModel& rModel )
+{
+ mrSheetData.setValidation( rModel );
+}
+
+void WorksheetHelper::setTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) const
+{
+ OSL_ENSURE( getAddressConverter().checkCellRange( rRange, true, false ), "WorksheetHelper::setTableOperation - invalid range" );
+ bool bOk = false;
+ if( !rModel.mbRef1Deleted && (rModel.maRef1.getLength() > 0) && (rRange.StartColumn > 0) && (rRange.StartRow > 0) )
+ {
+ CellRangeAddress aOpRange = rRange;
+ CellAddress aRef1, aRef2;
+ if( getAddressConverter().convertToCellAddress( aRef1, rModel.maRef1, mrSheetData.getSheetIndex(), true ) ) try
+ {
+ if( rModel.mb2dTable )
+ {
+ if( !rModel.mbRef2Deleted && getAddressConverter().convertToCellAddress( aRef2, rModel.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( rModel.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( getSheet() );
+
+ if( !rColRanges.empty() && aPropSet.getProperty( xLabelRanges, PROP_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, PROP_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::setDrawingPath( const OUString& rDrawingPath )
+{
+ mrSheetData.setDrawingPath( rDrawingPath );
+}
+
+void WorksheetHelper::setVmlDrawingPath( const OUString& rVmlDrawingPath )
+{
+ mrSheetData.setVmlDrawingPath( rVmlDrawingPath );
+}
+
+void WorksheetHelper::extendUsedArea( const CellAddress& rAddress )
+{
+ mrSheetData.extendUsedArea( rAddress );
+}
+
+void WorksheetHelper::extendUsedArea( const CellRangeAddress& rRange )
+{
+ mrSheetData.extendUsedArea( rRange );
+}
+
+void WorksheetHelper::extendShapeBoundingBox( const Rectangle& rShapeRect )
+{
+ mrSheetData.extendShapeBoundingBox( rShapeRect );
+}
+
+void WorksheetHelper::setBaseColumnWidth( sal_Int32 nWidth )
+{
+ mrSheetData.setBaseColumnWidth( nWidth );
+}
+
+void WorksheetHelper::setDefaultColumnWidth( double fWidth )
+{
+ mrSheetData.setDefaultColumnWidth( fWidth );
+}
+
+void WorksheetHelper::setDefaultColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId )
+{
+ mrSheetData.convertColumnFormat( nFirstCol, nLastCol, nXfId );
+}
+
+void WorksheetHelper::setColumnModel( const ColumnModel& rModel )
+{
+ mrSheetData.setColumnModel( rModel );
+}
+
+void WorksheetHelper::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
+{
+ mrSheetData.setDefaultRowSettings( fHeight, bCustomHeight, bHidden, bThickTop, bThickBottom );
+}
+
+void WorksheetHelper::setRowModel( const RowModel& rModel )
+{
+ mrSheetData.setRowModel( rModel );
+}
+
+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_Int16 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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/xls/worksheetsettings.cxx b/oox/source/xls/worksheetsettings.cxx
new file mode 100644
index 000000000000..9743f2b74f0f
--- /dev/null
+++ b/oox/source/xls/worksheetsettings.cxx
@@ -0,0 +1,340 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheetsettings.hxx"
+#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"
+#include "oox/core/filterbase.hxx"
+#include "properties.hxx"
+
+#include <com/sun/star/util/XProtectable.hpp>
+
+using ::rtl::OUString;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::util::XProtectable;
+using ::oox::core::CodecHelper;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt8 OOBIN_SHEETPR_FILTERMODE = 0x01;
+const sal_uInt8 OOBIN_SHEETPR_EVAL_CF = 0x02;
+
+const sal_uInt16 BIFF_SHEETPR_DIALOGSHEET = 0x0010;
+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_uInt32 BIFF_SHEETPROT_OBJECTS = 0x00000001;
+const sal_uInt32 BIFF_SHEETPROT_SCENARIOS = 0x00000002;
+const sal_uInt32 BIFF_SHEETPROT_FORMAT_CELLS = 0x00000004;
+const sal_uInt32 BIFF_SHEETPROT_FORMAT_COLUMNS = 0x00000008;
+const sal_uInt32 BIFF_SHEETPROT_FORMAT_ROWS = 0x00000010;
+const sal_uInt32 BIFF_SHEETPROT_INSERT_COLUMNS = 0x00000020;
+const sal_uInt32 BIFF_SHEETPROT_INSERT_ROWS = 0x00000040;
+const sal_uInt32 BIFF_SHEETPROT_INSERT_HLINKS = 0x00000080;
+const sal_uInt32 BIFF_SHEETPROT_DELETE_COLUMNS = 0x00000100;
+const sal_uInt32 BIFF_SHEETPROT_DELETE_ROWS = 0x00000200;
+const sal_uInt32 BIFF_SHEETPROT_SELECT_LOCKED = 0x00000400;
+const sal_uInt32 BIFF_SHEETPROT_SORT = 0x00000800;
+const sal_uInt32 BIFF_SHEETPROT_AUTOFILTER = 0x00001000;
+const sal_uInt32 BIFF_SHEETPROT_PIVOTTABLES = 0x00002000;
+const sal_uInt32 BIFF_SHEETPROT_SELECT_UNLOCKED = 0x00004000;
+
+} // namespace
+
+// ============================================================================
+
+SheetSettingsModel::SheetSettingsModel() :
+ mbFilterMode( false ),
+ mbApplyStyles( false ),
+ mbSummaryBelow( true ),
+ mbSummaryRight( true )
+{
+}
+
+// ============================================================================
+
+SheetProtectionModel::SheetProtectionModel() :
+ 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::importSheetPr( const AttributeList& rAttribs )
+{
+ maSheetSettings.maCodeName = rAttribs.getString( XML_codeName, OUString() );
+ maSheetSettings.mbFilterMode = rAttribs.getBool( XML_filterMode, false );
+}
+
+void WorksheetSettings::importChartSheetPr( const AttributeList& rAttribs )
+{
+ maSheetSettings.maCodeName = rAttribs.getString( XML_codeName, OUString() );
+}
+
+void WorksheetSettings::importTabColor( const AttributeList& rAttribs )
+{
+ maSheetSettings.maTabColor.importColor( rAttribs );
+}
+
+void WorksheetSettings::importOutlinePr( const AttributeList& rAttribs )
+{
+ maSheetSettings.mbApplyStyles = rAttribs.getBool( XML_applyStyles, false );
+ maSheetSettings.mbSummaryBelow = rAttribs.getBool( XML_summaryBelow, true );
+ maSheetSettings.mbSummaryRight = rAttribs.getBool( XML_summaryRight, true );
+}
+
+void WorksheetSettings::importSheetProtection( const AttributeList& rAttribs )
+{
+ maSheetProt.mnPasswordHash = CodecHelper::getPasswordHash( rAttribs, XML_password );
+ maSheetProt.mbSheet = rAttribs.getBool( XML_sheet, false );
+ maSheetProt.mbObjects = rAttribs.getBool( XML_objects, false );
+ maSheetProt.mbScenarios = rAttribs.getBool( XML_scenarios, false );
+ maSheetProt.mbFormatCells = rAttribs.getBool( XML_formatCells, true );
+ maSheetProt.mbFormatColumns = rAttribs.getBool( XML_formatColumns, true );
+ maSheetProt.mbFormatRows = rAttribs.getBool( XML_formatRows, true );
+ maSheetProt.mbInsertColumns = rAttribs.getBool( XML_insertColumns, true );
+ maSheetProt.mbInsertRows = rAttribs.getBool( XML_insertRows, true );
+ maSheetProt.mbInsertHyperlinks = rAttribs.getBool( XML_insertHyperlinks, true );
+ maSheetProt.mbDeleteColumns = rAttribs.getBool( XML_deleteColumns, true );
+ maSheetProt.mbDeleteRows = rAttribs.getBool( XML_deleteRows, true );
+ maSheetProt.mbSelectLocked = rAttribs.getBool( XML_selectLockedCells, false );
+ maSheetProt.mbSort = rAttribs.getBool( XML_sort, true );
+ maSheetProt.mbAutoFilter = rAttribs.getBool( XML_autoFilter, true );
+ maSheetProt.mbPivotTables = rAttribs.getBool( XML_pivotTables, true );
+ maSheetProt.mbSelectUnlocked = rAttribs.getBool( XML_selectUnlockedCells, false );
+}
+
+void WorksheetSettings::importChartProtection( const AttributeList& rAttribs )
+{
+ maSheetProt.mnPasswordHash = CodecHelper::getPasswordHash( rAttribs, XML_password );
+ maSheetProt.mbSheet = rAttribs.getBool( XML_content, false );
+ maSheetProt.mbObjects = rAttribs.getBool( XML_objects, false );
+}
+
+void WorksheetSettings::importPhoneticPr( const AttributeList& rAttribs )
+{
+ maPhoneticSett.importPhoneticPr( rAttribs );
+}
+
+void WorksheetSettings::importSheetPr( RecordInputStream& rStrm )
+{
+ sal_uInt16 nFlags1;
+ sal_uInt8 nFlags2;
+ rStrm >> nFlags1 >> nFlags2 >> maSheetSettings.maTabColor;
+ rStrm.skip( 8 ); // sync anchor cell
+ rStrm >> maSheetSettings.maCodeName;
+ // sheet settings
+ maSheetSettings.mbFilterMode = getFlag( nFlags2, OOBIN_SHEETPR_FILTERMODE );
+ // outline settings, equal flags in BIFF and OOBIN
+ maSheetSettings.mbApplyStyles = getFlag( nFlags1, BIFF_SHEETPR_APPLYSTYLES );
+ maSheetSettings.mbSummaryRight = getFlag( nFlags1, BIFF_SHEETPR_SYMBOLSRIGHT );
+ maSheetSettings.mbSummaryBelow = getFlag( nFlags1, BIFF_SHEETPR_SYMBOLSBELOW );
+ /* Fit printout to width/height - for whatever reason, this flag is still
+ stored separated from the page settings */
+ getPageSettings().setFitToPagesMode( getFlag( nFlags1, BIFF_SHEETPR_FITTOPAGES ) );
+}
+
+void WorksheetSettings::importChartSheetPr( RecordInputStream& rStrm )
+{
+ rStrm.skip( 2 ); // flags, contains only the 'published' flag
+ rStrm >> maSheetSettings.maTabColor >> maSheetSettings.maCodeName;
+}
+
+void WorksheetSettings::importSheetProtection( RecordInputStream& rStrm )
+{
+ rStrm >> maSheetProt.mnPasswordHash;
+ // no flags field for all these boolean flags?!?
+ maSheetProt.mbSheet = rStrm.readInt32() != 0;
+ maSheetProt.mbObjects = rStrm.readInt32() != 0;
+ maSheetProt.mbScenarios = rStrm.readInt32() != 0;
+ maSheetProt.mbFormatCells = rStrm.readInt32() != 0;
+ maSheetProt.mbFormatColumns = rStrm.readInt32() != 0;
+ maSheetProt.mbFormatRows = rStrm.readInt32() != 0;
+ maSheetProt.mbInsertColumns = rStrm.readInt32() != 0;
+ maSheetProt.mbInsertRows = rStrm.readInt32() != 0;
+ maSheetProt.mbInsertHyperlinks = rStrm.readInt32() != 0;
+ maSheetProt.mbDeleteColumns = rStrm.readInt32() != 0;
+ maSheetProt.mbDeleteRows = rStrm.readInt32() != 0;
+ maSheetProt.mbSelectLocked = rStrm.readInt32() != 0;
+ maSheetProt.mbSort = rStrm.readInt32() != 0;
+ maSheetProt.mbAutoFilter = rStrm.readInt32() != 0;
+ maSheetProt.mbPivotTables = rStrm.readInt32() != 0;
+ maSheetProt.mbSelectUnlocked = rStrm.readInt32() != 0;
+}
+
+void WorksheetSettings::importChartProtection( RecordInputStream& rStrm )
+{
+ rStrm >> maSheetProt.mnPasswordHash;
+ // no flags field for all these boolean flags?!?
+ maSheetProt.mbSheet = rStrm.readInt32() != 0;
+ maSheetProt.mbObjects = rStrm.readInt32() != 0;
+}
+
+void WorksheetSettings::importPhoneticPr( RecordInputStream& rStrm )
+{
+ maPhoneticSett.importPhoneticPr( rStrm );
+}
+
+void WorksheetSettings::importSheetPr( BiffInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ // worksheet vs. dialogsheet
+ if( getFlag( nFlags, BIFF_SHEETPR_DIALOGSHEET ) )
+ {
+ OSL_ENSURE( getSheetType() == SHEETTYPE_WORKSHEET, "WorksheetSettings::importSheetPr - unexpected sheet type" );
+ setSheetType( SHEETTYPE_DIALOGSHEET );
+ }
+ // outline settings
+ maSheetSettings.mbApplyStyles = getFlag( nFlags, BIFF_SHEETPR_APPLYSTYLES );
+ maSheetSettings.mbSummaryRight = getFlag( nFlags, BIFF_SHEETPR_SYMBOLSRIGHT );
+ maSheetSettings.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 )
+{
+ maSheetProt.mbSheet = rStrm.readuInt16() != 0;
+}
+
+void WorksheetSettings::importObjectProtect( BiffInputStream& rStrm )
+{
+ maSheetProt.mbObjects = rStrm.readuInt16() != 0;
+}
+
+void WorksheetSettings::importScenProtect( BiffInputStream& rStrm )
+{
+ maSheetProt.mbScenarios = rStrm.readuInt16() != 0;
+}
+
+void WorksheetSettings::importPassword( BiffInputStream& rStrm )
+{
+ rStrm >> maSheetProt.mnPasswordHash;
+}
+
+void WorksheetSettings::importSheetProtection( BiffInputStream& rStrm )
+{
+ sal_uInt32 nFlags = rStrm.readuInt32();
+ // set flag means protection is disabled
+ maSheetProt.mbObjects = !getFlag( nFlags, BIFF_SHEETPROT_OBJECTS );
+ maSheetProt.mbScenarios = !getFlag( nFlags, BIFF_SHEETPROT_SCENARIOS );
+ maSheetProt.mbFormatCells = !getFlag( nFlags, BIFF_SHEETPROT_FORMAT_CELLS );
+ maSheetProt.mbFormatColumns = !getFlag( nFlags, BIFF_SHEETPROT_FORMAT_COLUMNS );
+ maSheetProt.mbFormatRows = !getFlag( nFlags, BIFF_SHEETPROT_FORMAT_ROWS );
+ maSheetProt.mbInsertColumns = !getFlag( nFlags, BIFF_SHEETPROT_INSERT_COLUMNS );
+ maSheetProt.mbInsertRows = !getFlag( nFlags, BIFF_SHEETPROT_INSERT_ROWS );
+ maSheetProt.mbInsertHyperlinks = !getFlag( nFlags, BIFF_SHEETPROT_INSERT_HLINKS );
+ maSheetProt.mbDeleteColumns = !getFlag( nFlags, BIFF_SHEETPROT_DELETE_COLUMNS );
+ maSheetProt.mbDeleteRows = !getFlag( nFlags, BIFF_SHEETPROT_DELETE_ROWS );
+ maSheetProt.mbSelectLocked = !getFlag( nFlags, BIFF_SHEETPROT_SELECT_LOCKED );
+ maSheetProt.mbSort = !getFlag( nFlags, BIFF_SHEETPROT_SORT );
+ maSheetProt.mbAutoFilter = !getFlag( nFlags, BIFF_SHEETPROT_AUTOFILTER );
+ maSheetProt.mbPivotTables = !getFlag( nFlags, BIFF_SHEETPROT_PIVOTTABLES );
+ maSheetProt.mbSelectUnlocked = !getFlag( nFlags, BIFF_SHEETPROT_SELECT_UNLOCKED );
+}
+
+void WorksheetSettings::importCodeName( BiffInputStream& rStrm )
+{
+ maSheetSettings.maCodeName = rStrm.readUniString();
+}
+
+void WorksheetSettings::importPhoneticPr( BiffInputStream& rStrm )
+{
+ maPhoneticSett.importPhoneticPr( rStrm );
+}
+
+void WorksheetSettings::finalizeImport()
+{
+ // sheet protection
+ if( maSheetProt.mbSheet ) try
+ {
+ Reference< XProtectable > xProtectable( getSheet(), UNO_QUERY_THROW );
+ xProtectable->protect( OUString() );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // VBA code name
+ PropertySet aPropSet( getSheet() );
+ aPropSet.setProperty( PROP_CodeName, maSheetSettings.maCodeName );
+
+ if (!maSheetSettings.maTabColor.isAuto())
+ {
+ sal_Int32 nColor = maSheetSettings.maTabColor.getColor(getBaseFilter().getGraphicHelper());
+ aPropSet.setProperty(PROP_TabColor, nColor);
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */