From 8ada1cd2846e5e60ad63250c68ddea3a9356546f Mon Sep 17 00:00:00 2001 From: Noel Power Date: Fri, 16 Mar 2012 12:28:31 +0000 Subject: move excel related oox bits to sc --- sc/Library_scfilt.mk | 59 + sc/source/filter/excel/xestream.cxx | 14 +- sc/source/filter/inc/addressconverter.hxx | 672 +++++ sc/source/filter/inc/autofilterbuffer.hxx | 285 ++ sc/source/filter/inc/autofiltercontext.hxx | 117 + sc/source/filter/inc/biffcodec.hxx | 190 ++ sc/source/filter/inc/biffdetector.hxx | 100 + sc/source/filter/inc/biffhelper.hxx | 672 +++++ sc/source/filter/inc/biffinputstream.hxx | 411 +++ sc/source/filter/inc/biffoutputstream.hxx | 161 ++ sc/source/filter/inc/chartsheetfragment.hxx | 83 + sc/source/filter/inc/commentsbuffer.hxx | 129 + sc/source/filter/inc/commentsfragment.hxx | 73 + sc/source/filter/inc/condformatbuffer.hxx | 195 ++ sc/source/filter/inc/condformatcontext.hxx | 65 + sc/source/filter/inc/connectionsbuffer.hxx | 189 ++ sc/source/filter/inc/connectionsfragment.hxx | 81 + sc/source/filter/inc/defnamesbuffer.hxx | 235 ++ sc/source/filter/inc/drawingbase.hxx | 157 ++ sc/source/filter/inc/drawingfragment.hxx | 238 ++ sc/source/filter/inc/drawingmanager.hxx | 491 ++++ sc/source/filter/inc/excelchartconverter.hxx | 64 + sc/source/filter/inc/excelfilter.hxx | 125 + sc/source/filter/inc/excelhandlers.hxx | 252 ++ sc/source/filter/inc/excelvbaproject.hxx | 67 + sc/source/filter/inc/externallinkbuffer.hxx | 405 +++ sc/source/filter/inc/externallinkfragment.hxx | 164 ++ sc/source/filter/inc/formulabase.hxx | 845 ++++++ sc/source/filter/inc/formulaparser.hxx | 166 ++ sc/source/filter/inc/numberformatsbuffer.hxx | 141 + sc/source/filter/inc/ooxformulaparser.hxx | 111 + sc/source/filter/inc/pagesettings.hxx | 224 ++ sc/source/filter/inc/pivotcachebuffer.hxx | 532 ++++ sc/source/filter/inc/pivotcachefragment.hxx | 158 ++ sc/source/filter/inc/pivottablebuffer.hxx | 453 ++++ sc/source/filter/inc/pivottablefragment.hxx | 120 + sc/source/filter/inc/querytablebuffer.hxx | 112 + sc/source/filter/inc/querytablefragment.hxx | 79 + sc/source/filter/inc/richstring.hxx | 313 +++ sc/source/filter/inc/richstringcontext.hxx | 74 + sc/source/filter/inc/scenariobuffer.hxx | 158 ++ sc/source/filter/inc/scenariocontext.hxx | 83 + sc/source/filter/inc/sharedstringsbuffer.hxx | 68 + sc/source/filter/inc/sharedstringsfragment.hxx | 61 + sc/source/filter/inc/sheetdatabuffer.hxx | 343 +++ sc/source/filter/inc/sheetdatacontext.hxx | 196 ++ sc/source/filter/inc/stylesbuffer.hxx | 1099 ++++++++ sc/source/filter/inc/stylesfragment.hxx | 158 ++ sc/source/filter/inc/tablebuffer.hxx | 142 + sc/source/filter/inc/tablefragment.hxx | 65 + sc/source/filter/inc/themebuffer.hxx | 66 + sc/source/filter/inc/unitconverter.hxx | 123 + sc/source/filter/inc/viewsettings.hxx | 235 ++ sc/source/filter/inc/workbookfragment.hxx | 101 + sc/source/filter/inc/workbookhelper.hxx | 302 +++ sc/source/filter/inc/workbooksettings.hxx | 168 ++ sc/source/filter/inc/worksheetbuffer.hxx | 136 + sc/source/filter/inc/worksheetfragment.hxx | 193 ++ sc/source/filter/inc/worksheethelper.hxx | 339 +++ sc/source/filter/inc/worksheetsettings.hxx | 147 + sc/source/filter/oox/addressconverter.cxx | 760 ++++++ sc/source/filter/oox/autofilterbuffer.cxx | 871 ++++++ sc/source/filter/oox/autofiltercontext.cxx | 186 ++ sc/source/filter/oox/biffcodec.cxx | 382 +++ sc/source/filter/oox/biffdetector.cxx | 232 ++ sc/source/filter/oox/biffhelper.cxx | 334 +++ sc/source/filter/oox/biffinputstream.cxx | 555 ++++ sc/source/filter/oox/biffoutputstream.cxx | 212 ++ sc/source/filter/oox/chartsheetfragment.cxx | 292 ++ sc/source/filter/oox/commentsbuffer.cxx | 325 +++ sc/source/filter/oox/commentsfragment.cxx | 161 ++ sc/source/filter/oox/condformatbuffer.cxx | 779 ++++++ sc/source/filter/oox/condformatcontext.cxx | 105 + sc/source/filter/oox/connectionsbuffer.cxx | 504 ++++ sc/source/filter/oox/connectionsfragment.cxx | 182 ++ sc/source/filter/oox/defnamesbuffer.cxx | 696 +++++ sc/source/filter/oox/drawingbase.cxx | 355 +++ sc/source/filter/oox/drawingfragment.cxx | 772 ++++++ sc/source/filter/oox/drawingmanager.cxx | 1359 ++++++++++ sc/source/filter/oox/excelchartconverter.cxx | 139 + sc/source/filter/oox/excelfilter.cxx | 360 +++ sc/source/filter/oox/excelhandlers.cxx | 217 ++ sc/source/filter/oox/excelvbaproject.cxx | 150 ++ sc/source/filter/oox/externallinkbuffer.cxx | 1136 ++++++++ sc/source/filter/oox/externallinkfragment.cxx | 551 ++++ sc/source/filter/oox/formulabase.cxx | 1639 +++++++++++ sc/source/filter/oox/formulaparser.cxx | 2930 ++++++++++++++++++++ sc/source/filter/oox/numberformatsbuffer.cxx | 2117 +++++++++++++++ sc/source/filter/oox/ooxformulaparser.cxx | 205 ++ sc/source/filter/oox/pagesettings.cxx | 1285 +++++++++ sc/source/filter/oox/pivotcachebuffer.cxx | 1607 +++++++++++ sc/source/filter/oox/pivotcachefragment.cxx | 478 ++++ sc/source/filter/oox/pivottablebuffer.cxx | 1590 +++++++++++ sc/source/filter/oox/pivottablefragment.cxx | 322 +++ sc/source/filter/oox/querytablebuffer.cxx | 393 +++ sc/source/filter/oox/querytablefragment.cxx | 109 + sc/source/filter/oox/richstring.cxx | 668 +++++ sc/source/filter/oox/richstringcontext.cxx | 108 + sc/source/filter/oox/scenariobuffer.cxx | 302 +++ sc/source/filter/oox/scenariocontext.cxx | 129 + sc/source/filter/oox/sharedformulabuffer.cxx | 213 ++ sc/source/filter/oox/sharedstringsbuffer.cxx | 87 + sc/source/filter/oox/sharedstringsfragment.cxx | 105 + sc/source/filter/oox/sheetdatabuffer.cxx | 897 ++++++ sc/source/filter/oox/sheetdatacontext.cxx | 1009 +++++++ sc/source/filter/oox/stylesbuffer.cxx | 3443 ++++++++++++++++++++++++ sc/source/filter/oox/stylesfragment.cxx | 332 +++ sc/source/filter/oox/tablebuffer.cxx | 171 ++ sc/source/filter/oox/tablefragment.cxx | 109 + sc/source/filter/oox/themebuffer.cxx | 126 + sc/source/filter/oox/unitconverter.cxx | 255 ++ sc/source/filter/oox/viewsettings.cxx | 832 ++++++ sc/source/filter/oox/workbookfragment.cxx | 777 ++++++ sc/source/filter/oox/workbookhelper.cxx | 960 +++++++ sc/source/filter/oox/workbooksettings.cxx | 384 +++ sc/source/filter/oox/worksheetbuffer.cxx | 261 ++ sc/source/filter/oox/worksheetfragment.cxx | 1223 +++++++++ sc/source/filter/oox/worksheethelper.cxx | 1667 ++++++++++++ sc/source/filter/oox/worksheetsettings.cxx | 351 +++ sc/util/scfilt.component | 7 + 120 files changed, 51910 insertions(+), 1 deletion(-) create mode 100644 sc/source/filter/inc/addressconverter.hxx create mode 100644 sc/source/filter/inc/autofilterbuffer.hxx create mode 100644 sc/source/filter/inc/autofiltercontext.hxx create mode 100644 sc/source/filter/inc/biffcodec.hxx create mode 100644 sc/source/filter/inc/biffdetector.hxx create mode 100644 sc/source/filter/inc/biffhelper.hxx create mode 100644 sc/source/filter/inc/biffinputstream.hxx create mode 100644 sc/source/filter/inc/biffoutputstream.hxx create mode 100644 sc/source/filter/inc/chartsheetfragment.hxx create mode 100644 sc/source/filter/inc/commentsbuffer.hxx create mode 100644 sc/source/filter/inc/commentsfragment.hxx create mode 100644 sc/source/filter/inc/condformatbuffer.hxx create mode 100644 sc/source/filter/inc/condformatcontext.hxx create mode 100644 sc/source/filter/inc/connectionsbuffer.hxx create mode 100644 sc/source/filter/inc/connectionsfragment.hxx create mode 100644 sc/source/filter/inc/defnamesbuffer.hxx create mode 100644 sc/source/filter/inc/drawingbase.hxx create mode 100644 sc/source/filter/inc/drawingfragment.hxx create mode 100644 sc/source/filter/inc/drawingmanager.hxx create mode 100644 sc/source/filter/inc/excelchartconverter.hxx create mode 100644 sc/source/filter/inc/excelfilter.hxx create mode 100644 sc/source/filter/inc/excelhandlers.hxx create mode 100644 sc/source/filter/inc/excelvbaproject.hxx create mode 100644 sc/source/filter/inc/externallinkbuffer.hxx create mode 100644 sc/source/filter/inc/externallinkfragment.hxx create mode 100644 sc/source/filter/inc/formulabase.hxx create mode 100644 sc/source/filter/inc/formulaparser.hxx create mode 100644 sc/source/filter/inc/numberformatsbuffer.hxx create mode 100644 sc/source/filter/inc/ooxformulaparser.hxx create mode 100644 sc/source/filter/inc/pagesettings.hxx create mode 100644 sc/source/filter/inc/pivotcachebuffer.hxx create mode 100644 sc/source/filter/inc/pivotcachefragment.hxx create mode 100644 sc/source/filter/inc/pivottablebuffer.hxx create mode 100644 sc/source/filter/inc/pivottablefragment.hxx create mode 100644 sc/source/filter/inc/querytablebuffer.hxx create mode 100644 sc/source/filter/inc/querytablefragment.hxx create mode 100644 sc/source/filter/inc/richstring.hxx create mode 100644 sc/source/filter/inc/richstringcontext.hxx create mode 100644 sc/source/filter/inc/scenariobuffer.hxx create mode 100644 sc/source/filter/inc/scenariocontext.hxx create mode 100644 sc/source/filter/inc/sharedstringsbuffer.hxx create mode 100644 sc/source/filter/inc/sharedstringsfragment.hxx create mode 100644 sc/source/filter/inc/sheetdatabuffer.hxx create mode 100644 sc/source/filter/inc/sheetdatacontext.hxx create mode 100644 sc/source/filter/inc/stylesbuffer.hxx create mode 100644 sc/source/filter/inc/stylesfragment.hxx create mode 100644 sc/source/filter/inc/tablebuffer.hxx create mode 100644 sc/source/filter/inc/tablefragment.hxx create mode 100644 sc/source/filter/inc/themebuffer.hxx create mode 100644 sc/source/filter/inc/unitconverter.hxx create mode 100644 sc/source/filter/inc/viewsettings.hxx create mode 100644 sc/source/filter/inc/workbookfragment.hxx create mode 100644 sc/source/filter/inc/workbookhelper.hxx create mode 100644 sc/source/filter/inc/workbooksettings.hxx create mode 100644 sc/source/filter/inc/worksheetbuffer.hxx create mode 100644 sc/source/filter/inc/worksheetfragment.hxx create mode 100644 sc/source/filter/inc/worksheethelper.hxx create mode 100644 sc/source/filter/inc/worksheetsettings.hxx create mode 100644 sc/source/filter/oox/addressconverter.cxx create mode 100644 sc/source/filter/oox/autofilterbuffer.cxx create mode 100644 sc/source/filter/oox/autofiltercontext.cxx create mode 100644 sc/source/filter/oox/biffcodec.cxx create mode 100644 sc/source/filter/oox/biffdetector.cxx create mode 100644 sc/source/filter/oox/biffhelper.cxx create mode 100644 sc/source/filter/oox/biffinputstream.cxx create mode 100644 sc/source/filter/oox/biffoutputstream.cxx create mode 100644 sc/source/filter/oox/chartsheetfragment.cxx create mode 100644 sc/source/filter/oox/commentsbuffer.cxx create mode 100644 sc/source/filter/oox/commentsfragment.cxx create mode 100644 sc/source/filter/oox/condformatbuffer.cxx create mode 100644 sc/source/filter/oox/condformatcontext.cxx create mode 100644 sc/source/filter/oox/connectionsbuffer.cxx create mode 100644 sc/source/filter/oox/connectionsfragment.cxx create mode 100644 sc/source/filter/oox/defnamesbuffer.cxx create mode 100644 sc/source/filter/oox/drawingbase.cxx create mode 100644 sc/source/filter/oox/drawingfragment.cxx create mode 100644 sc/source/filter/oox/drawingmanager.cxx create mode 100644 sc/source/filter/oox/excelchartconverter.cxx create mode 100644 sc/source/filter/oox/excelfilter.cxx create mode 100644 sc/source/filter/oox/excelhandlers.cxx create mode 100644 sc/source/filter/oox/excelvbaproject.cxx create mode 100644 sc/source/filter/oox/externallinkbuffer.cxx create mode 100644 sc/source/filter/oox/externallinkfragment.cxx create mode 100644 sc/source/filter/oox/formulabase.cxx create mode 100644 sc/source/filter/oox/formulaparser.cxx create mode 100644 sc/source/filter/oox/numberformatsbuffer.cxx create mode 100644 sc/source/filter/oox/ooxformulaparser.cxx create mode 100644 sc/source/filter/oox/pagesettings.cxx create mode 100644 sc/source/filter/oox/pivotcachebuffer.cxx create mode 100644 sc/source/filter/oox/pivotcachefragment.cxx create mode 100644 sc/source/filter/oox/pivottablebuffer.cxx create mode 100644 sc/source/filter/oox/pivottablefragment.cxx create mode 100644 sc/source/filter/oox/querytablebuffer.cxx create mode 100644 sc/source/filter/oox/querytablefragment.cxx create mode 100644 sc/source/filter/oox/richstring.cxx create mode 100644 sc/source/filter/oox/richstringcontext.cxx create mode 100644 sc/source/filter/oox/scenariobuffer.cxx create mode 100644 sc/source/filter/oox/scenariocontext.cxx create mode 100644 sc/source/filter/oox/sharedformulabuffer.cxx create mode 100644 sc/source/filter/oox/sharedstringsbuffer.cxx create mode 100644 sc/source/filter/oox/sharedstringsfragment.cxx create mode 100644 sc/source/filter/oox/sheetdatabuffer.cxx create mode 100644 sc/source/filter/oox/sheetdatacontext.cxx create mode 100644 sc/source/filter/oox/stylesbuffer.cxx create mode 100644 sc/source/filter/oox/stylesfragment.cxx create mode 100644 sc/source/filter/oox/tablebuffer.cxx create mode 100644 sc/source/filter/oox/tablefragment.cxx create mode 100644 sc/source/filter/oox/themebuffer.cxx create mode 100644 sc/source/filter/oox/unitconverter.cxx create mode 100644 sc/source/filter/oox/viewsettings.cxx create mode 100644 sc/source/filter/oox/workbookfragment.cxx create mode 100644 sc/source/filter/oox/workbookhelper.cxx create mode 100644 sc/source/filter/oox/workbooksettings.cxx create mode 100644 sc/source/filter/oox/worksheetbuffer.cxx create mode 100644 sc/source/filter/oox/worksheetfragment.cxx create mode 100644 sc/source/filter/oox/worksheethelper.cxx create mode 100644 sc/source/filter/oox/worksheetsettings.cxx (limited to 'sc') diff --git a/sc/Library_scfilt.mk b/sc/Library_scfilt.mk index fb168e303095..2a997efdba44 100644 --- a/sc/Library_scfilt.mk +++ b/sc/Library_scfilt.mk @@ -29,6 +29,7 @@ $(eval $(call gb_Library_set_include,scfilt,\ -I$(SRCDIR)/sc/source/filter/inc \ -I$(SRCDIR)/sc/source/ui/inc \ -I$(SRCDIR)/sc/inc \ + -I$(WORKDIR)/oox/inc \ $$(INCLUDE) \ )) @@ -158,6 +159,64 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\ sc/source/filter/xcl97/XclImpChangeTrack \ sc/source/filter/xcl97/xcl97esc \ sc/source/filter/xcl97/xcl97rec \ + sc/source/filter/oox/excelfilter \ + sc/source/filter/oox/addressconverter \ + sc/source/filter/oox/autofilterbuffer \ + sc/source/filter/oox/autofiltercontext \ + sc/source/filter/oox/biffcodec \ + sc/source/filter/oox/biffdetector \ + sc/source/filter/oox/biffhelper \ + sc/source/filter/oox/biffinputstream \ + sc/source/filter/oox/biffoutputstream \ + sc/source/filter/oox/chartsheetfragment \ + sc/source/filter/oox/commentsbuffer \ + sc/source/filter/oox/commentsfragment \ + sc/source/filter/oox/condformatbuffer \ + sc/source/filter/oox/condformatcontext \ + sc/source/filter/oox/connectionsbuffer \ + sc/source/filter/oox/connectionsfragment \ + sc/source/filter/oox/defnamesbuffer \ + sc/source/filter/oox/drawingbase \ + sc/source/filter/oox/drawingfragment \ + sc/source/filter/oox/drawingmanager \ + sc/source/filter/oox/excelchartconverter \ + sc/source/filter/oox/excelhandlers \ + sc/source/filter/oox/excelvbaproject \ + sc/source/filter/oox/externallinkbuffer \ + sc/source/filter/oox/externallinkfragment \ + sc/source/filter/oox/formulabase \ + sc/source/filter/oox/formulaparser \ + sc/source/filter/oox/numberformatsbuffer \ + sc/source/filter/oox/ooxformulaparser \ + sc/source/filter/oox/pagesettings \ + sc/source/filter/oox/pivotcachebuffer \ + sc/source/filter/oox/pivotcachefragment \ + sc/source/filter/oox/pivottablebuffer \ + sc/source/filter/oox/pivottablefragment \ + sc/source/filter/oox/querytablebuffer \ + sc/source/filter/oox/querytablefragment \ + sc/source/filter/oox/richstringcontext \ + sc/source/filter/oox/richstring \ + sc/source/filter/oox/scenariobuffer \ + sc/source/filter/oox/scenariocontext \ + sc/source/filter/oox/sharedstringsbuffer \ + sc/source/filter/oox/sharedstringsfragment \ + sc/source/filter/oox/sheetdatabuffer \ + sc/source/filter/oox/sheetdatacontext \ + sc/source/filter/oox/stylesbuffer \ + sc/source/filter/oox/stylesfragment \ + sc/source/filter/oox/tablebuffer \ + sc/source/filter/oox/tablefragment \ + sc/source/filter/oox/themebuffer \ + sc/source/filter/oox/unitconverter \ + sc/source/filter/oox/viewsettings \ + sc/source/filter/oox/workbookfragment \ + sc/source/filter/oox/workbookhelper \ + sc/source/filter/oox/workbooksettings \ + sc/source/filter/oox/worksheetbuffer \ + sc/source/filter/oox/worksheetfragment \ + sc/source/filter/oox/worksheethelper \ + sc/source/filter/oox/worksheetsettings \ )) $(eval $(call gb_Library_add_noexception_objects,scfilt,\ diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index 5230ab895c98..67df56f12c91 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include @@ -1182,6 +1182,13 @@ Reference< XInterface > SAL_CALL XlsxExport_createInstance(const Reference< XCom return (cppu::OWeakObject*) new XclExpXmlStream( rCC ); } +namespace oox { namespace xls { + OUString SAL_CALL ExcelFilter_getImplementationName() throw(); + Sequence< OUString > SAL_CALL ExcelFilter_getSupportedServiceNames() throw(); + Reference< XInterface > SAL_CALL ExcelFilter_createInstance( + const Reference< XComponentContext >& rxContext ) throw( Exception ); +} } + #ifdef __cplusplus extern "C" { @@ -1197,6 +1204,11 @@ extern "C" XlsxExport_getSupportedServiceNames, ::cppu::createSingleComponentFactory, 0, 0 }, + { + oox::xls::ExcelFilter_createInstance, oox::xls::ExcelFilter_getImplementationName, + oox::xls::ExcelFilter_getSupportedServiceNames, ::cppu::createSingleComponentFactory, + 0, 0 + }, { 0, 0, 0, 0, 0, 0 } }; diff --git a/sc/source/filter/inc/addressconverter.hxx b/sc/source/filter/inc/addressconverter.hxx new file mode 100644 index 000000000000..e8108c76b375 --- /dev/null +++ b/sc/source/filter/inc/addressconverter.hxx @@ -0,0 +1,672 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_ADDRESSCONVERTER_HXX +#define OOX_XLS_ADDRESSCONVERTER_HXX + +#include +#include +#include +#include "workbookhelper.hxx" + +namespace oox { +namespace xls { + +class BiffInputStream; +class BiffOutputStream; + +// ============================================================================ +// ============================================================================ + +/** A vector of com.sun.star.table.CellRangeAddress elements and additional + functionality. */ +class ApiCellRangeList : public ::std::vector< ::com::sun::star::table::CellRangeAddress > +{ +public: + inline explicit ApiCellRangeList() {} + + /** Returns the base address of this range list (top-left cell of first range). */ + ::com::sun::star::table::CellAddress + getBaseAddress() const; +}; + +// ============================================================================ + +/** A 2D cell address struct for binary filters. */ +struct BinAddress +{ + sal_Int32 mnCol; + sal_Int32 mnRow; + + inline explicit BinAddress() : mnCol( 0 ), mnRow( 0 ) {} + inline explicit BinAddress( sal_Int32 nCol, sal_Int32 nRow ) : mnCol( nCol ), mnRow( nRow ) {} + inline explicit BinAddress( const ::com::sun::star::table::CellAddress& rAddr ) : mnCol( rAddr.Column ), mnRow( rAddr.Row ) {} + + inline void set( sal_Int32 nCol, sal_Int32 nRow ) { mnCol = nCol; mnRow = nRow; } + inline void set( const ::com::sun::star::table::CellAddress& rAddr ) { mnCol = rAddr.Column; mnRow = rAddr.Row; } + + void read( SequenceInputStream& rStrm ); + void read( BiffInputStream& rStrm, bool bCol16Bit = true, bool bRow32Bit = false ); + void write( BiffOutputStream& rStrm, bool bCol16Bit = true, bool bRow32Bit = false ) const; +}; + +// ---------------------------------------------------------------------------- + +inline bool operator==( const BinAddress& rL, const BinAddress& rR ) +{ + return (rL.mnCol == rR.mnCol) && (rL.mnRow == rR.mnRow); +} + +inline bool operator<( const BinAddress& rL, const BinAddress& rR ) +{ + return (rL.mnCol < rR.mnCol) || ((rL.mnCol == rR.mnCol) && (rL.mnRow < rR.mnRow)); +} + +inline SequenceInputStream& operator>>( SequenceInputStream& rStrm, BinAddress& orPos ) +{ + orPos.read( rStrm ); + return rStrm; +} + +inline BiffInputStream& operator>>( BiffInputStream& rStrm, BinAddress& orPos ) +{ + orPos.read( rStrm ); + return rStrm; +} + +inline BiffOutputStream& operator<<( BiffOutputStream& rStrm, const BinAddress& rPos ) +{ + rPos.write( rStrm ); + return rStrm; +} + +// ============================================================================ + +/** A 2D cell range address struct for binary filters. */ +struct BinRange +{ + BinAddress maFirst; + BinAddress maLast; + + inline explicit BinRange() {} + inline explicit BinRange( const BinAddress& rAddr ) : maFirst( rAddr ), maLast( rAddr ) {} + inline explicit BinRange( const BinAddress& rFirst, const BinAddress& rLast ) : maFirst( rFirst ), maLast( rLast ) {} + inline explicit BinRange( sal_Int32 nCol1, sal_Int32 nRow1, sal_Int32 nCol2, sal_Int32 nRow2 ) : + maFirst( nCol1, nRow1 ), maLast( nCol2, nRow2 ) {} + inline explicit BinRange( const ::com::sun::star::table::CellAddress& rAddr ) : maFirst( rAddr ), maLast( rAddr ) {} + inline explicit BinRange( const ::com::sun::star::table::CellAddress& rFirst, const ::com::sun::star::table::CellAddress& rLast ) : maFirst( rFirst ), maLast( rLast ) {} + inline explicit BinRange( const ::com::sun::star::table::CellRangeAddress& rRange ) : maFirst( rRange.StartColumn, rRange.StartRow ), maLast( rRange.EndColumn, rRange.EndRow ) {} + + inline void set( const BinAddress& rFirst, const BinAddress& rLast ) + { maFirst = rFirst; maLast = rLast; } + inline void set( sal_Int32 nCol1, sal_Int32 nRow1, sal_Int32 nCol2, sal_Int32 nRow2 ) + { maFirst.set( nCol1, nRow1 ); maLast.set( nCol2, nRow2 ); } + inline void set( const ::com::sun::star::table::CellAddress& rFirst, const ::com::sun::star::table::CellAddress& rLast ) + { maFirst.set( rFirst ); maLast.set( rLast ); } + inline void set( const ::com::sun::star::table::CellRangeAddress& rRange ) + { maFirst.set( rRange.StartColumn, rRange.StartRow ); maLast.set( rRange.EndColumn, rRange.EndRow ); } + + inline sal_Int32 getColCount() const { return maLast.mnCol - maFirst.mnCol + 1; } + inline sal_Int32 getRowCount() const { return maLast.mnRow - maFirst.mnRow + 1; } + bool contains( const BinAddress& rAddr ) const; + + void read( SequenceInputStream& rStrm ); + void read( BiffInputStream& rStrm, bool bCol16Bit = true, bool bRow32Bit = false ); + void write( BiffOutputStream& rStrm, bool bCol16Bit = true, bool bRow32Bit = false ) const; +}; + +// ---------------------------------------------------------------------------- + +inline bool operator==( const BinRange& rL, const BinRange& rR ) +{ + return (rL.maFirst == rR.maFirst) && (rL.maLast == rR.maLast); +} + +inline bool operator<( const BinRange& rL, const BinRange& rR ) +{ + return (rL.maFirst < rR.maFirst) || ((rL.maFirst == rR.maFirst) && (rL.maLast < rR.maLast)); +} + +inline SequenceInputStream& operator>>( SequenceInputStream& rStrm, BinRange& orRange ) +{ + orRange.read( rStrm ); + return rStrm; +} + +inline BiffInputStream& operator>>( BiffInputStream& rStrm, BinRange& orRange ) +{ + orRange.read( rStrm ); + return rStrm; +} + +inline BiffOutputStream& operator<<( BiffOutputStream& rStrm, const BinRange& rRange ) +{ + rRange.write( rStrm ); + return rStrm; +} + +// ============================================================================ + +/** A 2D cell range address list for binary filters. */ +class BinRangeList : public ::std::vector< BinRange > +{ +public: + inline explicit BinRangeList() {} + + void read( SequenceInputStream& rStrm ); + void read( BiffInputStream& rStrm, bool bCol16Bit = true, bool bRow32Bit = false ); + void write( BiffOutputStream& rStrm, bool bCol16Bit = true, bool bRow32Bit = false ) const; + void writeSubList( BiffOutputStream& rStrm, + size_t nBegin, size_t nCount, bool bCol16Bit = true, bool bRow32Bit = false ) const; +}; + +// ---------------------------------------------------------------------------- + +inline SequenceInputStream& operator>>( SequenceInputStream& rStrm, BinRangeList& orRanges ) +{ + orRanges.read( rStrm ); + return rStrm; +} + +inline BiffInputStream& operator>>( BiffInputStream& rStrm, BinRangeList& orRanges ) +{ + orRanges.read( rStrm ); + return rStrm; +} + +inline BiffOutputStream& operator<<( BiffOutputStream& rStrm, const BinRangeList& rRanges ) +{ + rRanges.write( rStrm ); + return rStrm; +} + +// ============================================================================ + +/** Different target types that can be encoded in a BIFF URL. */ +enum BiffTargetType +{ + BIFF_TARGETTYPE_URL, /// URL, URL with sheet name, or sheet name. + BIFF_TARGETTYPE_SAMESHEET, /// Target for special '!A1' syntax to refer to current sheet. + BIFF_TARGETTYPE_LIBRARY, /// Library directory in application installation. + BIFF_TARGETTYPE_DDE_OLE, /// DDE server/topic or OLE class/target. + BIFF_TARGETTYPE_UNKNOWN /// Unknown/unsupported target type. +}; + +// ============================================================================ +// ============================================================================ + +/** Converter for cell addresses and cell ranges for OOXML and BIFF filters. + */ +class AddressConverter : public WorkbookHelper +{ +public: + explicit AddressConverter( const WorkbookHelper& rHelper ); + + // ------------------------------------------------------------------------ + + /** Tries to parse the passed string for a 2d cell address in A1 notation. + + This function accepts all strings that match the regular expression + "[a-zA-Z]{1,6}0*[1-9][0-9]{0,8}" (without quotes), i.e. 1 to 6 letters + for the column index (translated to 0-based column indexes from 0 to + 321,272,405), and 1 to 9 digits for the 1-based row index (translated + to 0-based row indexes from 0 to 999,999,998). The row number part may + contain leading zeros, they will be ignored. It is up to the caller to + handle cell addresses outside of a specific valid range (e.g. the + entire spreadsheet). + + @param ornColumn (out-parameter) Returns the converted column index. + @param ornRow (out-parameter) returns the converted row index. + @param rString The string containing the cell address. + @param nStart Start index of string part in rString to be parsed. + @param nLength Length of string part in rString to be parsed. + + @return true = Parsed string was valid, returned values can be used. + */ + static bool parseOoxAddress2d( + sal_Int32& ornColumn, sal_Int32& ornRow, + const ::rtl::OUString& rString, + sal_Int32 nStart = 0, + sal_Int32 nLength = SAL_MAX_INT32 ); + + /** Tries to parse the passed string for a 2d cell range in A1 notation. + + This function accepts all strings that match the regular expression + "ADDR(:ADDR)?" (without quotes), where ADDR is a cell address accepted + by the parseOoxAddress2d() function of this class. It is up to the + caller to handle cell ranges outside of a specific valid range (e.g. + the entire spreadsheet). + + @param ornStartColumn (out-parameter) Returns the converted start column index. + @param ornStartRow (out-parameter) returns the converted start row index. + @param ornEndColumn (out-parameter) Returns the converted end column index. + @param ornEndRow (out-parameter) returns the converted end row index. + @param rString The string containing the cell address. + @param nStart Start index of string part in rString to be parsed. + @param nLength Length of string part in rString to be parsed. + + @return true = Parsed string was valid, returned values can be used. + */ + static bool parseOoxRange2d( + sal_Int32& ornStartColumn, sal_Int32& ornStartRow, + sal_Int32& ornEndColumn, sal_Int32& ornEndRow, + const ::rtl::OUString& rString, + sal_Int32 nStart = 0, + sal_Int32 nLength = SAL_MAX_INT32 ); + + /** Tries to parse an encoded name of an external link target in BIFF + documents, e.g. from EXTERNSHEET or SUPBOOK records. + + @param orClassName (out-parameter) DDE server name or OLE class name. + @param orTargetUrl (out-parameter) Target URL, DDE topic or OLE object name. + @param orSheetName (out-parameter) Sheet name in target document. + @param rBiffEncoded Encoded name of the external link target. + @param bFromDConRec True = path from DCONREF/DCONNAME/DCONBINAME records, false = other records. + + @return Type of the decoded target. + */ + BiffTargetType parseBiffTargetUrl( + ::rtl::OUString& orClassName, + ::rtl::OUString& orTargetUrl, + ::rtl::OUString& orSheetName, + const ::rtl::OUString& rBiffTargetUrl, + bool bFromDConRec = false ); + + // ------------------------------------------------------------------------ + + /** Returns the biggest valid cell address in the own Calc document. */ + inline const ::com::sun::star::table::CellAddress& + getMaxApiAddress() const { return maMaxApiPos; } + + /** Returns the biggest valid cell address in the imported/exported + Excel document. */ + inline const ::com::sun::star::table::CellAddress& + getMaxXlsAddress() const { return maMaxXlsPos; } + + /** Returns the biggest valid cell address in both Calc and the + imported/exported Excel document. */ + inline const ::com::sun::star::table::CellAddress& + getMaxAddress() const { return maMaxPos; } + + /** Returns the column overflow status. */ + inline bool isColOverflow() const { return mbColOverflow; } + /** Returns the row overflow status. */ + inline bool isRowOverflow() const { return mbRowOverflow; } + /** Returns the sheet overflow status. */ + inline bool isTabOverflow() const { return mbTabOverflow; } + + // ------------------------------------------------------------------------ + + /** Checks if the passed column index is valid. + + @param nCol The column index to check. + @param bTrackOverflow true = Update the internal overflow flag, if the + column index is outside of the supported limits. + @return true = Passed column index is valid (no index overflow). + */ + bool checkCol( sal_Int32 nCol, bool bTrackOverflow ); + + /** Checks if the passed row index is valid. + + @param nRow The row index to check. + @param bTrackOverflow true = Update the internal overflow flag, if the + row index is outside of the supported limits. + @return true = Passed row index is valid (no index overflow). + */ + bool checkRow( sal_Int32 nRow, bool bTrackOverflow ); + + /** Checks if the passed sheet index is valid. + + @param nSheet The sheet index to check. + @param bTrackOverflow true = Update the internal overflow flag, if the + sheet index is outside of the supported limits. + @return true = Passed sheet index is valid (no index overflow). + */ + bool checkTab( sal_Int16 nSheet, bool bTrackOverflow ); + + // ------------------------------------------------------------------------ + + /** Checks the passed cell address if it fits into the spreadsheet limits. + + @param rAddress The cell address to be checked. + @param bTrackOverflow true = Update the internal overflow flags, if + the address is outside of the supported sheet limits. + @return true = Passed address is valid (no index overflow). + */ + bool checkCellAddress( + const ::com::sun::star::table::CellAddress& rAddress, + bool bTrackOverflow ); + + /** Converts the passed string to a single cell address, without checking + any sheet limits. + + @param orAddress (out-parameter) Returns the converted cell address. + @param rString Cell address string in A1 notation. + @param nSheet Sheet index to be inserted into orAddress. + @return true = Cell address could be parsed from the passed string. + */ + bool convertToCellAddressUnchecked( + ::com::sun::star::table::CellAddress& orAddress, + const ::rtl::OUString& rString, + sal_Int16 nSheet ); + + /** Tries to convert the passed string to a single cell address. + + @param orAddress (out-parameter) Returns the converted cell address. + @param rString Cell address string in A1 notation. + @param nSheet Sheet index to be inserted into orAddress (will be checked). + @param bTrackOverflow true = Update the internal overflow flags, if + the address is outside of the supported sheet limits. + @return true = Converted address is valid (no index overflow). + */ + bool convertToCellAddress( + ::com::sun::star::table::CellAddress& orAddress, + const ::rtl::OUString& rString, + sal_Int16 nSheet, + bool bTrackOverflow ); + + /** Returns a valid cell address by moving it into allowed dimensions. + + @param rString Cell address string in A1 notation. + @param nSheet Sheet index for the returned address (will be checked). + @param bTrackOverflow true = Update the internal overflow flags, if + the address is outside of the supported sheet limits. + @return A valid API cell address struct. */ + ::com::sun::star::table::CellAddress + createValidCellAddress( + const ::rtl::OUString& rString, + sal_Int16 nSheet, + bool bTrackOverflow ); + + /** Converts the passed address to a single cell address, without checking + any sheet limits. + + @param orAddress (out-parameter) Returns the converted cell address. + @param rBinAddress Binary cell address struct. + @param nSheet Sheet index to be inserted into orAddress. + */ + void convertToCellAddressUnchecked( + ::com::sun::star::table::CellAddress& orAddress, + const BinAddress& rBinAddress, + sal_Int16 nSheet ); + + /** Tries to convert the passed address to a single cell address. + + @param orAddress (out-parameter) Returns the converted cell address. + @param rBinAddress Binary cell address struct. + @param nSheet Sheet index to be inserted into orAddress (will be checked). + @param bTrackOverflow true = Update the internal overflow flags, if + the address is outside of the supported sheet limits. + @return true = Converted address is valid (no index overflow). + */ + bool convertToCellAddress( + ::com::sun::star::table::CellAddress& orAddress, + const BinAddress& rBinAddress, + sal_Int16 nSheet, + bool bTrackOverflow ); + + /** Returns a valid cell address by moving it into allowed dimensions. + + @param rBinAddress Binary cell address struct. + @param nSheet Sheet index for the returned address (will be checked). + @param bTrackOverflow true = Update the internal overflow flags, if + the address is outside of the supported sheet limits. + @return A valid API cell address struct. */ + ::com::sun::star::table::CellAddress + createValidCellAddress( + const BinAddress& rBinAddress, + sal_Int16 nSheet, + bool bTrackOverflow ); + + // ------------------------------------------------------------------------ + + /** Checks the passed cell range if it fits into the spreadsheet limits. + + @param rRange The cell range address to be checked. + @param bAllowOverflow true = Allow ranges that start inside the + supported sheet limits but may end outside of these limits. + false = Do not allow ranges that overflow the supported limits. + @param bTrackOverflow true = Update the internal overflow flags, if + the passed range contains cells outside of the supported sheet + limits. + @return true = Cell range is valid. This function returns also true, + if only parts of the range are outside the current sheet limits and + such an overflow is allowed via parameter bAllowOverflow. Returns + false, if the entire range is outside the sheet limits, or if + overflow is not allowed via parameter bAllowOverflow. + */ + bool checkCellRange( + const ::com::sun::star::table::CellRangeAddress& rRange, + bool bAllowOverflow, bool bTrackOverflow ); + + /** Checks the passed cell range, may try to fit it to current sheet limits. + + First, this function reorders the column and row indexes so that the + starting indexes are less than or equal to the end indexes. Then, + depending on the parameter bAllowOverflow, the range is just checked or + cropped to the current sheet limits. + + @param orRange (in-out-parameter) Converts the passed cell range + into a valid cell range address. If the passed range contains cells + outside the currently supported spreadsheet limits, it will be + cropped to these limits. + @param bAllowOverflow true = Allow ranges that start inside the + supported sheet limits but may end outside of these limits. The + cell range returned in orRange will be cropped to these limits. + false = Do not allow ranges that overflow the supported limits. The + function will return false when the range overflows the sheet limits. + @param bTrackOverflow true = Update the internal overflow flags, if + the original range contains cells outside of the supported sheet + limits. + @return true = Converted range address is valid. This function + returns also true, if overflowing ranges are allowed via parameter + bAllowOverflow and the range has been cropped, but still contains + cells inside the current sheet limits. Returns false, if the entire + range is outside the sheet limits or overflowing ranges are not + allowed via parameter bAllowOverflow. + */ + bool validateCellRange( + ::com::sun::star::table::CellRangeAddress& orRange, + bool bAllowOverflow, bool bTrackOverflow ); + + /** Converts the passed string to a cell range address, without checking + any sheet limits. + + @param orRange (out-parameter) Returns the converted range address. + @param rString Cell range string in A1 notation. + @param nSheet Sheet index to be inserted into orRange. + @return true = Range address could be parsed from the passed string. + */ + bool convertToCellRangeUnchecked( + ::com::sun::star::table::CellRangeAddress& orRange, + const ::rtl::OUString& rString, + sal_Int16 nSheet ); + + /** Tries to convert the passed string to a cell range address. + + @param orRange (out-parameter) Returns the converted cell range + address. If the original range in the passed string contains cells + outside the currently supported spreadsheet limits, and parameter + bAllowOverflow is set to true, the range will be cropped to these + limits. Example: the range string "A1:ZZ100000" may be converted to + the range A1:IV65536. + @param rString Cell range string in A1 notation. + @param nSheet Sheet index to be inserted into orRange (will be checked). + @param bAllowOverflow true = Allow ranges that start inside the + supported sheet limits but may end outside of these limits. The + cell range returned in orRange will be cropped to these limits. + false = Do not allow ranges that overflow the supported limits. + @param bTrackOverflow true = Update the internal overflow flags, if + the original range contains cells outside of the supported sheet + limits. + @return true = Converted and returned range is valid. This function + returns also true, if overflowing ranges are allowed via parameter + bAllowOverflow and the range has been cropped, but still contains + cells inside the current sheet limits. Returns false, if the entire + range is outside the sheet limits or overflowing ranges are not + allowed via parameter bAllowOverflow. + */ + bool convertToCellRange( + ::com::sun::star::table::CellRangeAddress& orRange, + const ::rtl::OUString& rString, + sal_Int16 nSheet, + bool bAllowOverflow, bool bTrackOverflow ); + + /** Converts the passed range to a cell range address, without checking any + sheet limits. + + @param orRange (out-parameter) Returns the converted range address. + @param rBinRange Binary cell range struct. + @param nSheet Sheet index to be inserted into orRange. + */ + void convertToCellRangeUnchecked( + ::com::sun::star::table::CellRangeAddress& orRange, + const BinRange& rBinRange, + sal_Int16 nSheet ); + + /** Tries to convert the passed range to a cell range address. + + @param orRange (out-parameter) Returns the converted cell range + address. If the passed original range contains cells outside the + currently supported spreadsheet limits, and parameter bAllowOverflow + is set to true, the range will be cropped to these limits. + @param rBinRange Binary cell range struct. + @param nSheet Sheet index to be inserted into orRange (will be checked). + @param bAllowOverflow true = Allow ranges that start inside the + supported sheet limits but may end outside of these limits. The + cell range returned in orRange will be cropped to these limits. + false = Do not allow ranges that overflow the supported limits. + @param bTrackOverflow true = Update the internal overflow flags, if + the original range contains cells outside of the supported sheet + limits. + @return true = Converted and returned range is valid. This function + returns also true, if overflowing ranges are allowed via parameter + bAllowOverflow and the range has been cropped, but still contains + cells inside the current sheet limits. Returns false, if the entire + range is outside the sheet limits or if overflowing ranges are not + allowed via parameter bAllowOverflow. + */ + bool convertToCellRange( + ::com::sun::star::table::CellRangeAddress& orRange, + const BinRange& rBinRange, + sal_Int16 nSheet, + bool bAllowOverflow, bool bTrackOverflow ); + + // ------------------------------------------------------------------------ + + /** Tries to restrict the passed cell range list to current sheet limits. + + @param orRanges (in-out-parameter) Restricts the cell range addresses + in the passed list to the current sheet limits and removes invalid + ranges from the list. + @param bTrackOverflow true = Update the internal overflow flags, if + the original ranges contain cells outside of the supported sheet + limits. + */ + void validateCellRangeList( + ApiCellRangeList& orRanges, + bool bTrackOverflow ); + + /** Tries to convert the passed string to a cell range list. + + @param orRanges (out-parameter) Returns the converted cell range + addresses. If a range in the passed string contains cells outside + the currently supported spreadsheet limits, it will be cropped to + these limits. Example: the range string "A1:ZZ100000" may be + converted to the range A1:IV65536. If a range is completely outside + the limits, it will be omitted. + @param rString Cell range list string in A1 notation, space separated. + @param nSheet Sheet index to be inserted into orRanges (will be checked). + @param bTrackOverflow true = Update the internal overflow flags, if + the original ranges contain cells outside of the supported sheet + limits. + */ + void convertToCellRangeList( + ApiCellRangeList& orRanges, + const ::rtl::OUString& rString, + sal_Int16 nSheet, + bool bTrackOverflow ); + + /** Tries to convert the passed range list to a cell range list. + + @param orRanges (out-parameter) Returns the converted cell range + addresses. If a range in the passed string contains cells outside + the currently supported spreadsheet limits, it will be cropped to + these limits. Example: the range string "A1:ZZ100000" may be + converted to the range A1:IV65536. If a range is completely outside + the limits, it will be omitted. + @param rBinRanges List of binary cell range objects. + @param nSheet Sheet index to be inserted into orRanges (will be checked). + @param bTrackOverflow true = Update the internal overflow flags, if + the original ranges contain cells outside of the supported sheet + limits. + */ + void convertToCellRangeList( + ApiCellRangeList& orRanges, + const BinRangeList& rBinRanges, + sal_Int16 nSheet, + bool bTrackOverflow ); + + // ------------------------------------------------------------------------ +private: + void initializeMaxPos( + sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow ); + +private: + struct ControlCharacters + { + sal_Unicode mcThisWorkbook; /// Control character: Link to current workbook. + sal_Unicode mcExternal; /// Control character: Link to external workbook/sheet. + sal_Unicode mcThisSheet; /// Control character: Link to current sheet. + sal_Unicode mcInternal; /// Control character: Link to internal sheet. + sal_Unicode mcSameSheet; /// Control character: Link to same sheet (special '!A1' syntax). + + void set( + sal_Unicode cThisWorkbook, sal_Unicode cExternal, + sal_Unicode cThisSheet, sal_Unicode cInternal, + sal_Unicode cSameSheet ); + }; + + ::com::sun::star::table::CellAddress maMaxApiPos; /// Maximum valid cell address in Calc. + ::com::sun::star::table::CellAddress maMaxXlsPos; /// Maximum valid cell address in Excel. + ::com::sun::star::table::CellAddress maMaxPos; /// Maximum valid cell address in Calc/Excel. + ControlCharacters maLinkChars; /// Control characters for external link import (BIFF). + ControlCharacters maDConChars; /// Control characters for DCON* record import (BIFF). + bool mbColOverflow; /// Flag for "columns overflow". + bool mbRowOverflow; /// Flag for "rows overflow". + bool mbTabOverflow; /// Flag for "tables overflow". +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/autofilterbuffer.hxx b/sc/source/filter/inc/autofilterbuffer.hxx new file mode 100644 index 000000000000..711986186d01 --- /dev/null +++ b/sc/source/filter/inc/autofilterbuffer.hxx @@ -0,0 +1,285 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_AUTOFILTERBUFFER_HXX +#define OOX_XLS_AUTOFILTERBUFFER_HXX + +#include +#include "oox/helper/refvector.hxx" +#include "workbookhelper.hxx" + +namespace com { namespace sun { namespace star { + namespace sheet { struct TableFilterField3; } + namespace sheet { class XDatabaseRange; } + namespace sheet { class XSheetFilterDescriptor3; } +} } } + +namespace oox { +namespace xls { + +// ============================================================================ + +/** Contains UNO API filter settings for a column in a filtered range. */ +struct ApiFilterSettings +{ + typedef ::std::vector FilterFieldVector; + + FilterFieldVector maFilterFields; /// List of UNO API filter settings. + OptValue< bool > mobNeedsRegExp; /// If set, requires regular expressions to be enabled/disabled. + + explicit ApiFilterSettings(); + + void appendField( bool bAnd, sal_Int32 nOperator, double fValue ); + void appendField( bool bAnd, sal_Int32 nOperator, const ::rtl::OUString& rValue ); + void appendField( bool bAnd, const std::vector& rValues ); +}; + +// ============================================================================ + +/** Base class for specific filter settings for a column in a filtered range. + */ +class FilterSettingsBase : public WorkbookHelper +{ +public: + explicit FilterSettingsBase( const WorkbookHelper& rHelper ); + + /** Derived classes import filter settings from the passed attribute list. */ + virtual void importAttribs( sal_Int32 nElement, const AttributeList& rAttribs ); + /** Derived classes import filter settings from the passed record. */ + virtual void importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm ); + /** Derived classes import filter settings from the FILTERCOLUMN record. */ + virtual void importBiffRecord( BiffInputStream& rStrm, sal_uInt16 nFlags ); + + /** Derived classes return converted UNO API filter settings representing all filter settings. */ + virtual ApiFilterSettings finalizeImport( sal_Int32 nMaxCount ); +}; + +typedef ::boost::shared_ptr< FilterSettingsBase > FilterSettingsRef; + +// ============================================================================ + +/** Settings for a discrete filter, specifying a list of values to be shown in + the filtered range. + */ +class DiscreteFilter : public FilterSettingsBase +{ +public: + explicit DiscreteFilter( const WorkbookHelper& rHelper ); + + /** Imports filter settings from the filters and filter elements. */ + virtual void importAttribs( sal_Int32 nElement, const AttributeList& rAttribs ); + /** Imports filter settings from the FILTERS and FILTER records. */ + virtual void importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm ); + + /** Returns converted UNO API filter settings representing all filter settings. */ + virtual ApiFilterSettings finalizeImport( sal_Int32 nMaxCount ); + +private: + typedef ::std::vector< ::rtl::OUString > FilterValueVector; + + FilterValueVector maValues; + sal_Int32 mnCalendarType; + bool mbShowBlank; +}; + +// ============================================================================ + +/** Settings for a top-10 filter. */ +class Top10Filter : public FilterSettingsBase +{ +public: + explicit Top10Filter( const WorkbookHelper& rHelper ); + + /** Imports filter settings from the filters and filter elements. */ + virtual void importAttribs( sal_Int32 nElement, const AttributeList& rAttribs ); + /** Imports filter settings from the FILTERS and FILTER records. */ + virtual void importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm ); + /** Imports filter settings from the FILTERCOLUMN record. */ + virtual void importBiffRecord( BiffInputStream& rStrm, sal_uInt16 nFlags ); + + /** Returns converted UNO API filter settings representing all filter settings. */ + virtual ApiFilterSettings finalizeImport( sal_Int32 nMaxCount ); + +private: + double mfValue; /// Number of items or percentage. + bool mbTop; /// True = show top (greatest) items/percentage. + bool mbPercent; /// True = percentage, false = number of items. +}; + +// ============================================================================ + +/** A filter criterion for a custom filter. */ +struct FilterCriterionModel +{ + ::com::sun::star::uno::Any maValue; /// Comparison operand. + sal_Int32 mnOperator; /// Comparison operator. + sal_uInt8 mnDataType; /// Operand data type (BIFF only). + sal_uInt8 mnStrLen; /// Length of string operand (BIFF5-BIFF8 only). + + explicit FilterCriterionModel(); + + /** Sets the passed BIFF operator constant. */ + void setBiffOperator( sal_uInt8 nOperator ); + + /** Imports the criterion model from the passed BIFF12 stream. */ + void readBiffData( SequenceInputStream& rStrm ); + /** Imports the initial criterion data from the passed BIFF5/BIFF8 stream. */ + void readBiffData( BiffInputStream& rStrm ); + /** Imports the trailing string data from the passed BIFF5/BIFF8 stream. */ + void readString( BiffInputStream& rStrm, BiffType eBiff, rtl_TextEncoding eTextEnc ); +}; + +// ---------------------------------------------------------------------------- + +/** Settings for a custom filter, specifying one or two comparison operators + associated with some values. + */ +class CustomFilter : public FilterSettingsBase +{ +public: + explicit CustomFilter( const WorkbookHelper& rHelper ); + + /** Imports filter settings from the filters and filter elements. */ + virtual void importAttribs( sal_Int32 nElement, const AttributeList& rAttribs ); + /** Imports filter settings from the FILTERS and FILTER records. */ + virtual void importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm ); + /** Imports filter settings from the FILTERCOLUMN record. */ + virtual void importBiffRecord( BiffInputStream& rStrm, sal_uInt16 nFlags ); + + /** Returns converted UNO API filter settings representing all filter settings. */ + virtual ApiFilterSettings finalizeImport( sal_Int32 nMaxCount ); + +private: + /** Apeends the passed filter criteriom, if it contains valid settings. */ + void appendCriterion( const FilterCriterionModel& rCriterion ); + +private: + typedef ::std::vector< FilterCriterionModel > FilterCriterionVector; + + FilterCriterionVector maCriteria; + bool mbAnd; +}; + +// ============================================================================ + +/** A column in a filtered range. Contains an object with specific filter + settings for the cells in the column. + */ +class FilterColumn : public WorkbookHelper +{ +public: + explicit FilterColumn( const WorkbookHelper& rHelper ); + + /** Imports auto filter column settings from the filterColumn element. */ + void importFilterColumn( const AttributeList& rAttribs ); + /** Imports auto filter column settings from the FILTERCOLUMN record. */ + void importFilterColumn( SequenceInputStream& rStrm ); + /** Imports auto filter column settings from the FILTERCOLUMN record. */ + void importFilterColumn( BiffInputStream& rStrm ); + + /** Creates and returns the specified filter settings object. */ + template< typename FilterSettingsType > + inline FilterSettingsBase& createFilterSettings() + { mxSettings.reset( new FilterSettingsType( *this ) ); return *mxSettings; } + + /** Returns the index of the column in the filtered range this object is related to. */ + inline sal_Int32 getColumnId() const { return mnColId; } + + /** Returns converted UNO API filter settings representing all filter + settings of this column. */ + ApiFilterSettings finalizeImport( sal_Int32 nMaxCount ); + +private: + FilterSettingsRef mxSettings; + sal_Int32 mnColId; + bool mbHiddenButton; + bool mbShowButton; +}; + +// ============================================================================ + +class AutoFilter : public WorkbookHelper +{ +public: + explicit AutoFilter( const WorkbookHelper& rHelper ); + + /** Imports auto filter settings from the autoFilter element. */ + void importAutoFilter( const AttributeList& rAttribs, sal_Int16 nSheet ); + /** Imports auto filter settings from the AUTOFILTER record. */ + void importAutoFilter( SequenceInputStream& rStrm, sal_Int16 nSheet ); + + /** Creates a new auto filter column and stores it internally. */ + FilterColumn& createFilterColumn(); + + /** Applies the filter to the passed filter descriptor. */ + void finalizeImport( + const ::com::sun::star::uno::Reference< + ::com::sun::star::sheet::XSheetFilterDescriptor3>& rxFilterDesc ); + +private: + typedef RefVector< FilterColumn > FilterColumnVector; + + FilterColumnVector maFilterColumns; + ::com::sun::star::table::CellRangeAddress maRange; +}; + +// ============================================================================ + +class AutoFilterBuffer : public WorkbookHelper +{ +public: + explicit AutoFilterBuffer( const WorkbookHelper& rHelper ); + + /** Creates a new auto filter and stores it internally. */ + AutoFilter& createAutoFilter(); + + /** Applies filter settings to a new database range object (used for sheet + autofilter or advanced filter as specified by built-in defined names). */ + void finalizeImport( sal_Int16 nSheet ); + + /** Applies the filters to the passed database range object. + @return True = this buffer contains valid auto filter settings. */ + bool finalizeImport( const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDatabaseRange >& rxDatabaseRange ); + +private: + /** Returns the auto filter object used to perform auto filtering. */ + AutoFilter* getActiveAutoFilter(); + +private: + typedef RefVector< AutoFilter > AutoFilterVector; + AutoFilterVector maAutoFilters; +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/autofiltercontext.hxx b/sc/source/filter/inc/autofiltercontext.hxx new file mode 100644 index 000000000000..6583fd36d509 --- /dev/null +++ b/sc/source/filter/inc/autofiltercontext.hxx @@ -0,0 +1,117 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_AUTOFILTERCONTEXT_HXX +#define OOX_XLS_AUTOFILTERCONTEXT_HXX + +#include "excelhandlers.hxx" + +namespace oox { +namespace xls { + +class AutoFilter; +class FilterColumn; +class FilterSettingsBase; + +// ============================================================================ + +class FilterSettingsContext : public WorksheetContextBase +{ +public: + explicit FilterSettingsContext( WorksheetContextBase& rParent, FilterSettingsBase& rFilterSettings ); + +protected: + virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ); + virtual void onStartElement( const AttributeList& rAttribs ); + + virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ); + virtual void onStartRecord( SequenceInputStream& rStrm ); + +private: + FilterSettingsBase& mrFilterSettings; +}; + +// ============================================================================ + +class FilterColumnContext : public WorksheetContextBase +{ +public: + explicit FilterColumnContext( WorksheetContextBase& rParent, FilterColumn& rFilterColumn ); + +protected: + virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ); + virtual void onStartElement( const AttributeList& rAttribs ); + + virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ); + virtual void onStartRecord( SequenceInputStream& rStrm ); + +private: + FilterColumn& mrFilterColumn; +}; + +// ============================================================================ + +class AutoFilterContext : public WorksheetContextBase +{ +public: + explicit AutoFilterContext( WorksheetFragmentBase& rFragment, AutoFilter& rAutoFilter ); + +protected: + virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ); + virtual void onStartElement( const AttributeList& rAttribs ); + + virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ); + virtual void onStartRecord( SequenceInputStream& rStrm ); + +private: + AutoFilter& mrAutoFilter; +}; + +// ============================================================================ + +class BiffAutoFilterContext : public BiffWorksheetContextBase +{ +public: + explicit BiffAutoFilterContext( const WorksheetHelper& rHelper, AutoFilter& rAutoFilter ); + +protected: + /** Imports all records related to the current auto filter. */ + virtual void importRecord( BiffInputStream& rStrm ); + +private: + AutoFilter& mrAutoFilter; +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/biffcodec.hxx b/sc/source/filter/inc/biffcodec.hxx new file mode 100644 index 000000000000..2c3aeabb4a53 --- /dev/null +++ b/sc/source/filter/inc/biffcodec.hxx @@ -0,0 +1,190 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_BIFFCODEC_HXX +#define OOX_XLS_BIFFCODEC_HXX + +#include +#include +#include "oox/core/binarycodec.hxx" +#include "workbookhelper.hxx" + +namespace oox { +namespace xls { + +// ============================================================================ + +const sal_Int64 BIFF_RCF_BLOCKSIZE = 1024; + +// ============================================================================ + +/** Base class for BIFF stream decoders. */ +class BiffDecoderBase : public ::comphelper::IDocPasswordVerifier +{ +public: + explicit BiffDecoderBase(); + virtual ~BiffDecoderBase(); + + /** Derived classes return a clone of the decoder for usage in new streams. */ + inline BiffDecoderBase* clone() { return implClone(); } + + /** Implementation of the ::comphelper::IDocPasswordVerifier interface. */ + virtual ::comphelper::DocPasswordVerifierResult verifyPassword( const ::rtl::OUString& rPassword, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& o_rEncryptionData ); + virtual ::comphelper::DocPasswordVerifierResult verifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& o_rEncryptionData ); + + /** Returns true, if the decoder has been initialized correctly. */ + inline bool isValid() const { return mbValid; } + + /** Decodes nBytes bytes and writes encrypted data into the buffer pnDestData. */ + void decode( + sal_uInt8* pnDestData, + const sal_uInt8* pnSrcData, + sal_Int64 nStreamPos, + sal_uInt16 nBytes ); + +private: + /** Derived classes return a clone of the decoder for usage in new streams. */ + virtual BiffDecoderBase* implClone() = 0; + + /** Derived classes implement password verification and initialization of + the decoder. */ + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > implVerifyPassword( const ::rtl::OUString& rPassword ) = 0; + virtual bool implVerifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rEncryptionData ) = 0; + + /** Implementation of decryption of a memory block. */ + virtual void implDecode( + sal_uInt8* pnDestData, + const sal_uInt8* pnSrcData, + sal_Int64 nStreamPos, + sal_uInt16 nBytes ) = 0; + +private: + bool mbValid; /// True = decoder is correctly initialized. +}; + +typedef ::boost::shared_ptr< BiffDecoderBase > BiffDecoderRef; + +// ============================================================================ + +/** Decodes BIFF stream contents that are encoded using the old XOR algorithm. */ +class BiffDecoder_XOR : public BiffDecoderBase +{ +public: + explicit BiffDecoder_XOR( sal_uInt16 nKey, sal_uInt16 nHash ); + +private: + /** Copy constructor for cloning. */ + BiffDecoder_XOR( const BiffDecoder_XOR& rDecoder ); + + /** Returns a clone of the decoder for usage in new streams. */ + virtual BiffDecoder_XOR* implClone(); + + /** Implements password verification and initialization of the decoder. */ + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > implVerifyPassword( const ::rtl::OUString& rPassword ); + virtual bool implVerifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rEncryptionData ); + + + /** Implementation of decryption of a memory block. */ + virtual void implDecode( + sal_uInt8* pnDestData, + const sal_uInt8* pnSrcData, + sal_Int64 nStreamPos, + sal_uInt16 nBytes ); + +private: + ::oox::core::BinaryCodec_XOR maCodec; /// Cipher algorithm implementation. + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > maEncryptionData; + sal_uInt16 mnKey; + sal_uInt16 mnHash; +}; + +// ============================================================================ + +/** Decodes BIFF stream contents that are encoded using the RC4 algorithm. */ +class BiffDecoder_RCF : public BiffDecoderBase +{ +public: + explicit BiffDecoder_RCF( + sal_uInt8 pnSalt[ 16 ], + sal_uInt8 pnVerifier[ 16 ], + sal_uInt8 pnVerifierHash[ 16 ] ); + +private: + /** Copy constructor for cloning. */ + BiffDecoder_RCF( const BiffDecoder_RCF& rDecoder ); + + /** Returns a clone of the decoder for usage in new streams. */ + virtual BiffDecoder_RCF* implClone(); + + /** Implements password verification and initialization of the decoder. */ + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > implVerifyPassword( const ::rtl::OUString& rPassword ); + virtual bool implVerifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rEncryptionData ); + + /** Implementation of decryption of a memory block. */ + virtual void implDecode( + sal_uInt8* pnDestData, + const sal_uInt8* pnSrcData, + sal_Int64 nStreamPos, + sal_uInt16 nBytes ); + +private: + ::oox::core::BinaryCodec_RCF maCodec; /// Cipher algorithm implementation. + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > maEncryptionData; + ::std::vector< sal_uInt8 > maSalt; + ::std::vector< sal_uInt8 > maVerifier; + ::std::vector< sal_uInt8 > maVerifierHash; +}; + +// ============================================================================ + +/** Helper for BIFF stream codecs. Holds the used codec object. */ +class BiffCodecHelper : public WorkbookHelper +{ +public: + explicit BiffCodecHelper( const WorkbookHelper& rHelper ); + + /** Implementation helper, reads the FILEPASS and returns a decoder object. */ + static BiffDecoderRef implReadFilePass( BiffInputStream& rStrm, BiffType eBiff ); + + /** Imports the FILEPASS record, asks for a password and sets a decoder at the stream. */ + bool importFilePass( BiffInputStream& rStrm ); + /** Clones the contained decoder object if existing and sets it at the passed stream. */ + void cloneDecoder( BiffInputStream& rStrm ); + +private: + BiffDecoderRef mxDecoder; /// The decoder for import filter. +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/biffdetector.hxx b/sc/source/filter/inc/biffdetector.hxx new file mode 100644 index 000000000000..5a7c330b5733 --- /dev/null +++ b/sc/source/filter/inc/biffdetector.hxx @@ -0,0 +1,100 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_BIFFDETECTOR_HXX +#define OOX_XLS_BIFFDETECTOR_HXX + +#include +#include +#include +#include "oox/helper/storagebase.hxx" +#include "biffhelper.hxx" + +namespace com { namespace sun { namespace star { + namespace beans { struct PropertyValue; } + namespace uno { class XComponentContext; } +} } } + +namespace oox { class BinaryInputStream; } + +namespace oox { +namespace xls { + +// ============================================================================ + +/** Detection service for BIFF streams or storages. */ +class BiffDetector : public ::cppu::WeakImplHelper2< + ::com::sun::star::lang::XServiceInfo, + ::com::sun::star::document::XExtendedFilterDetection > +{ +public: + explicit BiffDetector( + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext ) + throw( ::com::sun::star::uno::RuntimeException ); + + virtual ~BiffDetector(); + + /** Detects the BIFF version of the passed stream. */ + static BiffType detectStreamBiffVersion( BinaryInputStream& rInStream ); + + /** Detects the BIFF version and workbook stream name of the passed storage. */ + static BiffType detectStorageBiffVersion( + ::rtl::OUString& orWorkbookStreamName, + const StorageRef& rxStorage ); + + // com.sun.star.lang.XServiceInfo interface ------------------------------- + + virtual ::rtl::OUString SAL_CALL + getImplementationName() throw( ::com::sun::star::uno::RuntimeException ); + + virtual sal_Bool SAL_CALL + supportsService( const ::rtl::OUString& rService ) + throw( ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL + getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ); + + // com.sun.star.document.XExtendedFilterDetect interface ------------------ + + virtual ::rtl::OUString SAL_CALL + detect( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& orDescriptor ) + throw( ::com::sun::star::uno::RuntimeException ); + +private: + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > + mxContext; +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/biffhelper.hxx b/sc/source/filter/inc/biffhelper.hxx new file mode 100644 index 000000000000..be8303feac54 --- /dev/null +++ b/sc/source/filter/inc/biffhelper.hxx @@ -0,0 +1,672 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_BIFFHELPER_HXX +#define OOX_XLS_BIFFHELPER_HXX + +#include "oox/helper/binarystreambase.hxx" + +namespace oox { class SequenceInputStream; } + +namespace oox { +namespace xls { + +class BiffInputStream; + +// BIFF12 record identifiers ================================================== + +const sal_Int32 BIFF12_ID_ARRAY = 0x01AA; +const sal_Int32 BIFF12_ID_AUTOFILTER = 0x00A1; +const sal_Int32 BIFF12_ID_AUTOSORTSCOPE = 0x01CB; +const sal_Int32 BIFF12_ID_BINARYINDEXBLOCK = 0x002A; +const sal_Int32 BIFF12_ID_BINARYINDEXROWS = 0x0028; +const sal_Int32 BIFF12_ID_BOOKVIEWS = 0x0087; +const sal_Int32 BIFF12_ID_BORDER = 0x002E; +const sal_Int32 BIFF12_ID_BORDERS = 0x0265; +const sal_Int32 BIFF12_ID_BRK = 0x018C; +const sal_Int32 BIFF12_ID_CALCPR = 0x009D; +const sal_Int32 BIFF12_ID_CELL_BLANK = 0x0001; +const sal_Int32 BIFF12_ID_CELL_BOOL = 0x0004; +const sal_Int32 BIFF12_ID_CELL_DOUBLE = 0x0005; +const sal_Int32 BIFF12_ID_CELL_ERROR = 0x0003; +const sal_Int32 BIFF12_ID_CELL_RK = 0x0002; +const sal_Int32 BIFF12_ID_CELL_RSTRING = 0x003E; +const sal_Int32 BIFF12_ID_CELL_SI = 0x0007; +const sal_Int32 BIFF12_ID_CELL_STRING = 0x0006; +const sal_Int32 BIFF12_ID_CELLSTYLE = 0x0030; +const sal_Int32 BIFF12_ID_CELLSTYLES = 0x026B; +const sal_Int32 BIFF12_ID_CELLSTYLEXFS = 0x0272; +const sal_Int32 BIFF12_ID_CELLXFS = 0x0269; +const sal_Int32 BIFF12_ID_CFCOLOR = 0x0234; +const sal_Int32 BIFF12_ID_CFRULE = 0x01CF; +const sal_Int32 BIFF12_ID_CHARTPAGESETUP = 0x028C; +const sal_Int32 BIFF12_ID_CHARTPROTECTION = 0x029D; +const sal_Int32 BIFF12_ID_CHARTSHEETPR = 0x028B; +const sal_Int32 BIFF12_ID_CHARTSHEETVIEW = 0x008D; +const sal_Int32 BIFF12_ID_CHARTSHEETVIEWS = 0x008B; +const sal_Int32 BIFF12_ID_COL = 0x003C; +const sal_Int32 BIFF12_ID_COLBREAKS = 0x018A; +const sal_Int32 BIFF12_ID_COLOR = 0x023C; +const sal_Int32 BIFF12_ID_COLORS = 0x01D9; +const sal_Int32 BIFF12_ID_COLORSCALE = 0x01D5; +const sal_Int32 BIFF12_ID_COLS = 0x0186; +const sal_Int32 BIFF12_ID_COMMENT = 0x027B; +const sal_Int32 BIFF12_ID_COMMENTAUTHOR = 0x0278; +const sal_Int32 BIFF12_ID_COMMENTAUTHORS = 0x0276; +const sal_Int32 BIFF12_ID_COMMENTLIST = 0x0279; +const sal_Int32 BIFF12_ID_COMMENTS = 0x0274; +const sal_Int32 BIFF12_ID_COMMENTTEXT = 0x027D; +const sal_Int32 BIFF12_ID_CONDFORMATTING = 0x01CD; +const sal_Int32 BIFF12_ID_CONNECTION = 0x00C9; +const sal_Int32 BIFF12_ID_CONNECTIONS = 0x01AD; +const sal_Int32 BIFF12_ID_CONTROL = 0x0284; +const sal_Int32 BIFF12_ID_CONTROLS = 0x0283; +const sal_Int32 BIFF12_ID_CUSTOMCHARTVIEW = 0x028F; +const sal_Int32 BIFF12_ID_CUSTOMCHARTVIEWS = 0x028D; +const sal_Int32 BIFF12_ID_CUSTOMFILTER = 0x00AE; +const sal_Int32 BIFF12_ID_CUSTOMFILTERS = 0x00AC; +const sal_Int32 BIFF12_ID_CUSTOMSHEETVIEW = 0x01A7; +const sal_Int32 BIFF12_ID_CUSTOMSHEETVIEWS = 0x01A6; +const sal_Int32 BIFF12_ID_CUSTOMWORKBOOKVIEW= 0x018D; +const sal_Int32 BIFF12_ID_DATABAR = 0x01D3; +const sal_Int32 BIFF12_ID_DATATABLE = 0x01AC; +const sal_Int32 BIFF12_ID_DATAVALIDATION = 0x0040; +const sal_Int32 BIFF12_ID_DATAVALIDATIONS = 0x023D; +const sal_Int32 BIFF12_ID_DDEITEMVALUES = 0x0242; +const sal_Int32 BIFF12_ID_DDEITEM_BOOL = 0x0248; +const sal_Int32 BIFF12_ID_DDEITEM_DOUBLE = 0x0244; +const sal_Int32 BIFF12_ID_DDEITEM_ERROR = 0x0245; +const sal_Int32 BIFF12_ID_DDEITEM_STRING = 0x0246; +const sal_Int32 BIFF12_ID_DEFINEDNAME = 0x0027; +const sal_Int32 BIFF12_ID_DIMENSION = 0x0094; +const sal_Int32 BIFF12_ID_DISCRETEFILTER = 0x00A7; +const sal_Int32 BIFF12_ID_DISCRETEFILTERS = 0x00A5; +const sal_Int32 BIFF12_ID_DRAWING = 0x0226; +const sal_Int32 BIFF12_ID_DXF = 0x01FB; +const sal_Int32 BIFF12_ID_DXFS = 0x01F9; +const sal_Int32 BIFF12_ID_EXTCELL_BLANK = 0x016F; +const sal_Int32 BIFF12_ID_EXTCELL_BOOL = 0x0171; +const sal_Int32 BIFF12_ID_EXTCELL_DOUBLE = 0x0170; +const sal_Int32 BIFF12_ID_EXTCELL_ERROR = 0x0172; +const sal_Int32 BIFF12_ID_EXTCELL_STRING = 0x0173; +const sal_Int32 BIFF12_ID_EXTERNALADDIN = 0x029B; +const sal_Int32 BIFF12_ID_EXTERNALBOOK = 0x0168; +const sal_Int32 BIFF12_ID_EXTERNALNAME = 0x0241; +const sal_Int32 BIFF12_ID_EXTERNALREF = 0x0163; +const sal_Int32 BIFF12_ID_EXTERNALREFS = 0x0161; +const sal_Int32 BIFF12_ID_EXTERNALSELF = 0x0165; +const sal_Int32 BIFF12_ID_EXTERNALSAME = 0x0166; +const sal_Int32 BIFF12_ID_EXTERNALSHEETS = 0x016A; +const sal_Int32 BIFF12_ID_EXTROW = 0x016E; +const sal_Int32 BIFF12_ID_EXTSHEETDATA = 0x016B; +const sal_Int32 BIFF12_ID_EXTERNALNAMEFLAGS = 0x024A; +const sal_Int32 BIFF12_ID_EXTSHEETNAMES = 0x0167; +const sal_Int32 BIFF12_ID_FILESHARING = 0x0224; +const sal_Int32 BIFF12_ID_FILEVERSION = 0x0080; +const sal_Int32 BIFF12_ID_FILL = 0x002D; +const sal_Int32 BIFF12_ID_FILLS = 0x025B; +const sal_Int32 BIFF12_ID_FILTERCOLUMN = 0x00A3; +const sal_Int32 BIFF12_ID_FONT = 0x002B; +const sal_Int32 BIFF12_ID_FONTS = 0x0263; +const sal_Int32 BIFF12_ID_FORMULA_STRING = 0x0008; +const sal_Int32 BIFF12_ID_FORMULA_DOUBLE = 0x0009; +const sal_Int32 BIFF12_ID_FORMULA_BOOL = 0x000A; +const sal_Int32 BIFF12_ID_FORMULA_ERROR = 0x000B; +const sal_Int32 BIFF12_ID_FUNCTIONGROUP = 0x0299; +const sal_Int32 BIFF12_ID_FUNCTIONGROUPS = 0x0298; +const sal_Int32 BIFF12_ID_HEADERFOOTER = 0x01DF; +const sal_Int32 BIFF12_ID_HYPERLINK = 0x01EE; +const sal_Int32 BIFF12_ID_ICONSET = 0x01D1; +const sal_Int32 BIFF12_ID_INDEXEDCOLORS = 0x0235; +const sal_Int32 BIFF12_ID_INPUTCELLS = 0x01F8; +const sal_Int32 BIFF12_ID_LEGACYDRAWING = 0x0227; +const sal_Int32 BIFF12_ID_MERGECELL = 0x00B0; +const sal_Int32 BIFF12_ID_MERGECELLS = 0x00B1; +const sal_Int32 BIFF12_ID_MRUCOLORS = 0x0239; +const sal_Int32 BIFF12_ID_MULTCELL_BLANK = 0x000C; +const sal_Int32 BIFF12_ID_MULTCELL_BOOL = 0x000F; +const sal_Int32 BIFF12_ID_MULTCELL_DOUBLE = 0x0010; +const sal_Int32 BIFF12_ID_MULTCELL_ERROR = 0x000E; +const sal_Int32 BIFF12_ID_MULTCELL_RK = 0x000D; +const sal_Int32 BIFF12_ID_MULTCELL_RSTRING = 0x003D; +const sal_Int32 BIFF12_ID_MULTCELL_SI = 0x0012; +const sal_Int32 BIFF12_ID_MULTCELL_STRING = 0x0011; +const sal_Int32 BIFF12_ID_NUMFMT = 0x002C; +const sal_Int32 BIFF12_ID_NUMFMTS = 0x0267; +const sal_Int32 BIFF12_ID_OLEOBJECT = 0x027F; +const sal_Int32 BIFF12_ID_OLEOBJECTS = 0x027E; +const sal_Int32 BIFF12_ID_OLESIZE = 0x0225; +const sal_Int32 BIFF12_ID_PAGEMARGINS = 0x01DC; +const sal_Int32 BIFF12_ID_PAGESETUP = 0x01DE; +const sal_Int32 BIFF12_ID_PANE = 0x0097; +const sal_Int32 BIFF12_ID_PCDEFINITION = 0x00B3; +const sal_Int32 BIFF12_ID_PCDFDISCRETEPR = 0x00E1; +const sal_Int32 BIFF12_ID_PCDFGROUPITEMS = 0x00DD; +const sal_Int32 BIFF12_ID_PCDFIELD = 0x00B7; +const sal_Int32 BIFF12_ID_PCDFIELDGROUP = 0x00DB; +const sal_Int32 BIFF12_ID_PCDFIELDS = 0x00B5; +const sal_Int32 BIFF12_ID_PCDFRANGEPR = 0x00DF; +const sal_Int32 BIFF12_ID_PCDFSHAREDITEMS = 0x00BD; +const sal_Int32 BIFF12_ID_PCDSHEETSOURCE = 0x00BB; +const sal_Int32 BIFF12_ID_PCDSOURCE = 0x00B9; +const sal_Int32 BIFF12_ID_PCITEM_ARRAY = 0x00BF; +const sal_Int32 BIFF12_ID_PCITEM_BOOL = 0x0016; +const sal_Int32 BIFF12_ID_PCITEM_DATE = 0x0019; +const sal_Int32 BIFF12_ID_PCITEM_DOUBLE = 0x0015; +const sal_Int32 BIFF12_ID_PCITEM_ERROR = 0x0017; +const sal_Int32 BIFF12_ID_PCITEM_INDEX = 0x001A; +const sal_Int32 BIFF12_ID_PCITEM_MISSING = 0x0014; +const sal_Int32 BIFF12_ID_PCITEM_STRING = 0x0018; +const sal_Int32 BIFF12_ID_PCITEMA_BOOL = 0x001D; +const sal_Int32 BIFF12_ID_PCITEMA_DATE = 0x0020; +const sal_Int32 BIFF12_ID_PCITEMA_DOUBLE = 0x001C; +const sal_Int32 BIFF12_ID_PCITEMA_ERROR = 0x001E; +const sal_Int32 BIFF12_ID_PCITEMA_MISSING = 0x001B; +const sal_Int32 BIFF12_ID_PCITEMA_STRING = 0x001F; +const sal_Int32 BIFF12_ID_PCRECORD = 0x0021; +const sal_Int32 BIFF12_ID_PCRECORDDT = 0x0022; +const sal_Int32 BIFF12_ID_PCRECORDS = 0x00C1; +const sal_Int32 BIFF12_ID_PHONETICPR = 0x0219; +const sal_Int32 BIFF12_ID_PICTURE = 0x0232; +const sal_Int32 BIFF12_ID_PIVOTAREA = 0x00F7; +const sal_Int32 BIFF12_ID_PIVOTCACHE = 0x0182; +const sal_Int32 BIFF12_ID_PIVOTCACHES = 0x0180; +const sal_Int32 BIFF12_ID_PRINTOPTIONS = 0x01DD; +const sal_Int32 BIFF12_ID_PTCOLFIELDS = 0x0137; +const sal_Int32 BIFF12_ID_PTDATAFIELD = 0x0125; +const sal_Int32 BIFF12_ID_PTDATAFIELDS = 0x0127; +const sal_Int32 BIFF12_ID_PTDEFINITION = 0x0118; +const sal_Int32 BIFF12_ID_PTFIELD = 0x011D; +const sal_Int32 BIFF12_ID_PTFIELDS = 0x011F; +const sal_Int32 BIFF12_ID_PTFILTER = 0x0259; +const sal_Int32 BIFF12_ID_PTFILTERS = 0x0257; +const sal_Int32 BIFF12_ID_PTFITEM = 0x011A; +const sal_Int32 BIFF12_ID_PTFITEMS = 0x011B; +const sal_Int32 BIFF12_ID_PTLOCATION = 0x013A; +const sal_Int32 BIFF12_ID_PTPAGEFIELD = 0x0121; +const sal_Int32 BIFF12_ID_PTPAGEFIELDS = 0x0123; +const sal_Int32 BIFF12_ID_PTREFERENCE = 0x00FB; +const sal_Int32 BIFF12_ID_PTREFERENCEITEM = 0x017E; +const sal_Int32 BIFF12_ID_PTREFERENCES = 0x00F9; +const sal_Int32 BIFF12_ID_PTROWFIELDS = 0x0135; +const sal_Int32 BIFF12_ID_QUERYTABLE = 0x01BF; +const sal_Int32 BIFF12_ID_QUERYTABLEREFRESH = 0x01C1; +const sal_Int32 BIFF12_ID_RGBCOLOR = 0x01DB; +const sal_Int32 BIFF12_ID_ROW = 0x0000; +const sal_Int32 BIFF12_ID_ROWBREAKS = 0x0188; +const sal_Int32 BIFF12_ID_SCENARIO = 0x01F6; +const sal_Int32 BIFF12_ID_SCENARIOS = 0x01F4; +const sal_Int32 BIFF12_ID_SELECTION = 0x0098; +const sal_Int32 BIFF12_ID_SHAREDFMLA = 0x01AB; +const sal_Int32 BIFF12_ID_SHEET = 0x009C; +const sal_Int32 BIFF12_ID_SHEETDATA = 0x0091; +const sal_Int32 BIFF12_ID_SHEETFORMATPR = 0x01E5; +const sal_Int32 BIFF12_ID_SHEETPR = 0x0093; +const sal_Int32 BIFF12_ID_SHEETPROTECTION = 0x0217; +const sal_Int32 BIFF12_ID_SHEETS = 0x008F; +const sal_Int32 BIFF12_ID_SHEETVIEW = 0x0089; +const sal_Int32 BIFF12_ID_SHEETVIEWS = 0x0085; +const sal_Int32 BIFF12_ID_SI = 0x0013; +const sal_Int32 BIFF12_ID_SST = 0x009F; +const sal_Int32 BIFF12_ID_STYLESHEET = 0x0116; +const sal_Int32 BIFF12_ID_TABLE = 0x0157; +const sal_Int32 BIFF12_ID_TABLEPART = 0x0295; +const sal_Int32 BIFF12_ID_TABLEPARTS = 0x0294; +const sal_Int32 BIFF12_ID_TABLESTYLEINFO = 0x0201; +const sal_Int32 BIFF12_ID_TABLESTYLES = 0x01FC; +const sal_Int32 BIFF12_ID_TOP10FILTER = 0x00AA; +const sal_Int32 BIFF12_ID_VOLTYPE = 0x0204; +const sal_Int32 BIFF12_ID_VOLTYPEMAIN = 0x0206; +const sal_Int32 BIFF12_ID_VOLTYPES = 0x0202; +const sal_Int32 BIFF12_ID_VOLTYPESTP = 0x020A; +const sal_Int32 BIFF12_ID_VOLTYPETR = 0x020B; +const sal_Int32 BIFF12_ID_WEBPR = 0x0105; +const sal_Int32 BIFF12_ID_WEBPRTABLES = 0x0107; +const sal_Int32 BIFF12_ID_WORKBOOK = 0x0083; +const sal_Int32 BIFF12_ID_WORKBOOKPR = 0x0099; +const sal_Int32 BIFF12_ID_WORKBOOKVIEW = 0x009E; +const sal_Int32 BIFF12_ID_WORKSHEET = 0x0081; +const sal_Int32 BIFF12_ID_XF = 0x002F; + +// BIFF2-BIFF8 record identifiers ============================================= + +/** An enumeration for all binary Excel file format types (BIFF types). */ +enum BiffType +{ + BIFF2 = 0, /// MS Excel 2.1. + BIFF3, /// MS Excel 3.0. + BIFF4, /// MS Excel 4.0. + BIFF5, /// MS Excel 5.0, MS Excel 7.0 (95). + BIFF8, /// MS Excel 8.0 (97), 9.0 (2000), 10.0 (XP), 11.0 (2003). + BIFF_UNKNOWN /// Unknown BIFF version. +}; + +const sal_uInt16 BIFF2_MAXRECSIZE = 2080; +const sal_uInt16 BIFF8_MAXRECSIZE = 8224; + +// record identifiers --------------------------------------------------------- + +const sal_uInt16 BIFF2_ID_ARRAY = 0x0021; +const sal_uInt16 BIFF3_ID_ARRAY = 0x0221; +const sal_uInt16 BIFF_ID_AUTOFILTER = 0x009D; +const sal_uInt16 BIFF2_ID_BLANK = 0x0001; +const sal_uInt16 BIFF3_ID_BLANK = 0x0201; +const sal_uInt16 BIFF2_ID_BOF = 0x0009; +const sal_uInt16 BIFF3_ID_BOF = 0x0209; +const sal_uInt16 BIFF4_ID_BOF = 0x0409; +const sal_uInt16 BIFF5_ID_BOF = 0x0809; +const sal_uInt16 BIFF_ID_BOOKBOOL = 0x00DA; +const sal_uInt16 BIFF_ID_BOOKEXT = 0x0863; +const sal_uInt16 BIFF2_ID_BOOLERR = 0x0005; +const sal_uInt16 BIFF3_ID_BOOLERR = 0x0205; +const sal_uInt16 BIFF_ID_BOTTOMMARGIN = 0x0029; +const sal_uInt16 BIFF_ID_CALCCOUNT = 0x000C; +const sal_uInt16 BIFF_ID_CALCMODE = 0x000D; +const sal_uInt16 BIFF_ID_CFHEADER = 0x01B0; +const sal_uInt16 BIFF_ID_CFRULE = 0x01B1; +const sal_uInt16 BIFF_ID_CFRULE12 = 0x087A; +const sal_uInt16 BIFF_ID_CFRULEEXT = 0x087B; +const sal_uInt16 BIFF_ID_CH3DDATAFORMAT = 0x105F; +const sal_uInt16 BIFF_ID_CHAREA = 0x101A; +const sal_uInt16 BIFF_ID_CHAREAFORMAT = 0x100A; +const sal_uInt16 BIFF_ID_CHATTACHEDLABEL = 0x100C; +const sal_uInt16 BIFF_ID_CHAXESSET = 0x1041; +const sal_uInt16 BIFF_ID_CHAXIS = 0x101D; +const sal_uInt16 BIFF_ID_CHAXISLINE = 0x1021; +const sal_uInt16 BIFF_ID_CHBAR = 0x1017; +const sal_uInt16 BIFF_ID_CHBEGIN = 0x1033; +const sal_uInt16 BIFF_ID_CHCHART = 0x1002; +const sal_uInt16 BIFF_ID_CHCHART3D = 0x103A; +const sal_uInt16 BIFF_ID_CHCHARTLINE = 0x101C; +const sal_uInt16 BIFF_ID_CHDATAFORMAT = 0x1006; +const sal_uInt16 BIFF_ID_CHDATERANGE = 0x1062; +const sal_uInt16 BIFF_ID_CHDEFAULTTEXT = 0x1024; +const sal_uInt16 BIFF_ID_CHDROPBAR = 0x103D; +const sal_uInt16 BIFF_ID_CHECKCOMPAT = 0x088C; +const sal_uInt16 BIFF_ID_CHEND = 0x1034; +const sal_uInt16 BIFF_ID_CHESCHERFORMAT = 0x1066; +const sal_uInt16 BIFF_ID_CHFONT = 0x1026; +const sal_uInt16 BIFF_ID_CHFORMAT = 0x104E; +const sal_uInt16 BIFF_ID_CHFORMATRUNS = 0x1050; +const sal_uInt16 BIFF_ID_CHFRAME = 0x1032; +const sal_uInt16 BIFF_ID_CHFRAMEPOS = 0x104F; +const sal_uInt16 BIFF_ID_CHFRBLOCKBEGIN = 0x0852; +const sal_uInt16 BIFF_ID_CHFRBLOCKEND = 0x0853; +const sal_uInt16 BIFF_ID_CHFRCATEGORYPROPS = 0x0856; +const sal_uInt16 BIFF_ID_CHFREXTPROPS = 0x089E; +const sal_uInt16 BIFF_ID_CHFREXTPROPSCONT = 0x089F; +const sal_uInt16 BIFF_ID_CHFRINFO = 0x0850; +const sal_uInt16 BIFF_ID_CHFRLABELPROPS = 0x086B; +const sal_uInt16 BIFF_ID_CHFRLAYOUT = 0x089D; +const sal_uInt16 BIFF_ID_CHFRPLOTAREALAYOUT = 0x08A7; +const sal_uInt16 BIFF_ID_CHFRSHAPEPROPS = 0x08A4; +const sal_uInt16 BIFF_ID_CHFRTEXTPROPS = 0x08A5; +const sal_uInt16 BIFF_ID_CHFRUNITPROPS = 0x0857; +const sal_uInt16 BIFF_ID_CHFRWRAPPER = 0x0851; +const sal_uInt16 BIFF_ID_CHLABELRANGE = 0x1020; +const sal_uInt16 BIFF_ID_CHLEGEND = 0x1015; +const sal_uInt16 BIFF_ID_CHLINE = 0x1018; +const sal_uInt16 BIFF_ID_CHLINEFORMAT = 0x1007; +const sal_uInt16 BIFF_ID_CHMARKERFORMAT = 0x1009; +const sal_uInt16 BIFF_ID_CHOBJECTLINK = 0x1027; +const sal_uInt16 BIFF_ID_CHPICFORMAT = 0x103C; +const sal_uInt16 BIFF_ID_CHPIE = 0x1019; +const sal_uInt16 BIFF_ID_CHPIEEXT = 0x1061; +const sal_uInt16 BIFF_ID_CHPIEFORMAT = 0x100B; +const sal_uInt16 BIFF_ID_CHPIVOTFLAGS = 0x0859; +const sal_uInt16 BIFF5_ID_CHPIVOTREF = 0x1048; +const sal_uInt16 BIFF8_ID_CHPIVOTREF = 0x0858; +const sal_uInt16 BIFF_ID_CHPLOTFRAME = 0x1035; +const sal_uInt16 BIFF_ID_CHPLOTGROWTH = 0x1064; +const sal_uInt16 BIFF_ID_CHPROPERTIES = 0x1044; +const sal_uInt16 BIFF_ID_CHRADARLINE = 0x103E; +const sal_uInt16 BIFF_ID_CHRADARAREA = 0x1040; +const sal_uInt16 BIFF_ID_CHSCATTER = 0x101B; +const sal_uInt16 BIFF_ID_CHSERERRORBAR = 0x105B; +const sal_uInt16 BIFF_ID_CHSERGROUP = 0x1045; +const sal_uInt16 BIFF_ID_CHSERIES = 0x1003; +const sal_uInt16 BIFF_ID_CHSERIESFORMAT = 0x105D; +const sal_uInt16 BIFF_ID_CHSERPARENT = 0x104A; +const sal_uInt16 BIFF_ID_CHSERTRENDLINE = 0x104B; +const sal_uInt16 BIFF_ID_CHSOURCELINK = 0x1051; +const sal_uInt16 BIFF_ID_CHSTRING = 0x100D; +const sal_uInt16 BIFF_ID_CHSURFACE = 0x103F; +const sal_uInt16 BIFF_ID_CHTEXT = 0x1025; +const sal_uInt16 BIFF_ID_CHTICK = 0x101E; +const sal_uInt16 BIFF_ID_CHTYPEGROUP = 0x1014; +const sal_uInt16 BIFF_ID_CHVALUERANGE = 0x101F; +const sal_uInt16 BIFF_ID_CODENAME = 0x01BA; +const sal_uInt16 BIFF_ID_CODEPAGE = 0x0042; +const sal_uInt16 BIFF_ID_COLINFO = 0x007D; +const sal_uInt16 BIFF_ID_COLUMNDEFAULT = 0x0020; +const sal_uInt16 BIFF_ID_COLWIDTH = 0x0024; +const sal_uInt16 BIFF_ID_COMPRESSPICS = 0x089B; +const sal_uInt16 BIFF_ID_CONNECTION = 0x0876; +const sal_uInt16 BIFF_ID_CONT = 0x003C; +const sal_uInt16 BIFF_ID_COORDLIST = 0x00A9; +const sal_uInt16 BIFF_ID_COUNTRY = 0x008C; +const sal_uInt16 BIFF_ID_CRN = 0x005A; +const sal_uInt16 BIFF2_ID_DATATABLE = 0x0036; +const sal_uInt16 BIFF3_ID_DATATABLE = 0x0236; +const sal_uInt16 BIFF2_ID_DATATABLE2 = 0x0037; +const sal_uInt16 BIFF_ID_DATAVALIDATION = 0x01BE; +const sal_uInt16 BIFF_ID_DATAVALIDATIONS = 0x01B2; +const sal_uInt16 BIFF_ID_DATEMODE = 0x0022; +const sal_uInt16 BIFF_ID_DBCELL = 0x00D7; +const sal_uInt16 BIFF_ID_DBQUERY = 0x00DC; +const sal_uInt16 BIFF_ID_DCONBINAME = 0x01B5; +const sal_uInt16 BIFF_ID_DCONNAME = 0x0052; +const sal_uInt16 BIFF_ID_DCONREF = 0x0051; +const sal_uInt16 BIFF_ID_DEFCOLWIDTH = 0x0055; +const sal_uInt16 BIFF2_ID_DEFINEDNAME = 0x0018; +const sal_uInt16 BIFF3_ID_DEFINEDNAME = 0x0218; +const sal_uInt16 BIFF5_ID_DEFINEDNAME = 0x0018; +const sal_uInt16 BIFF2_ID_DEFROWHEIGHT = 0x0025; +const sal_uInt16 BIFF3_ID_DEFROWHEIGHT = 0x0225; +const sal_uInt16 BIFF_ID_DELTA = 0x0010; +const sal_uInt16 BIFF2_ID_DIMENSION = 0x0000; +const sal_uInt16 BIFF3_ID_DIMENSION = 0x0200; +const sal_uInt16 BIFF_ID_DXF = 0x088D; +const sal_uInt16 BIFF_ID_EOF = 0x000A; +const sal_uInt16 BIFF_ID_EXTERNALBOOK = 0x01AE; +const sal_uInt16 BIFF2_ID_EXTERNALNAME = 0x0023; +const sal_uInt16 BIFF3_ID_EXTERNALNAME = 0x0223; +const sal_uInt16 BIFF5_ID_EXTERNALNAME = 0x0023; +const sal_uInt16 BIFF_ID_EXTERNSHEET = 0x0017; +const sal_uInt16 BIFF_ID_EXTSST = 0x00FF; +const sal_uInt16 BIFF_ID_FILEPASS = 0x002F; +const sal_uInt16 BIFF_ID_FILESHARING = 0x005B; +const sal_uInt16 BIFF_ID_FILTERCOLUMN = 0x009E; +const sal_uInt16 BIFF_ID_FILTERMODE = 0x009B; +const sal_uInt16 BIFF2_ID_FONT = 0x0031; +const sal_uInt16 BIFF3_ID_FONT = 0x0231; +const sal_uInt16 BIFF5_ID_FONT = 0x0031; +const sal_uInt16 BIFF_ID_FONTCOLOR = 0x0045; +const sal_uInt16 BIFF_ID_FOOTER = 0x0015; +const sal_uInt16 BIFF_ID_FORCEFULLCALC = 0x08A3; +const sal_uInt16 BIFF2_ID_FORMAT = 0x001E; +const sal_uInt16 BIFF4_ID_FORMAT = 0x041E; +const sal_uInt16 BIFF2_ID_FORMULA = 0x0006; +const sal_uInt16 BIFF3_ID_FORMULA = 0x0206; +const sal_uInt16 BIFF4_ID_FORMULA = 0x0406; +const sal_uInt16 BIFF5_ID_FORMULA = 0x0006; +const sal_uInt16 BIFF_ID_GUTS = 0x0080; +const sal_uInt16 BIFF_ID_HCENTER = 0x0083; +const sal_uInt16 BIFF_ID_HEADER = 0x0014; +const sal_uInt16 BIFF_ID_HEADERFOOTER = 0x089C; +const sal_uInt16 BIFF_ID_HIDEOBJ = 0x008D; +const sal_uInt16 BIFF_ID_HORPAGEBREAKS = 0x001B; +const sal_uInt16 BIFF_ID_HYPERLINK = 0x01B8; +const sal_uInt16 BIFF3_ID_IMGDATA = 0x007F; +const sal_uInt16 BIFF8_ID_IMGDATA = 0x00E9; +const sal_uInt16 BIFF2_ID_INDEX = 0x000B; +const sal_uInt16 BIFF3_ID_INDEX = 0x020B; +const sal_uInt16 BIFF2_ID_INTEGER = 0x0002; +const sal_uInt16 BIFF_ID_INTERFACEHDR = 0x00E1; +const sal_uInt16 BIFF_ID_ITERATION = 0x0011; +const sal_uInt16 BIFF_ID_IXFE = 0x0044; +const sal_uInt16 BIFF2_ID_LABEL = 0x0004; +const sal_uInt16 BIFF3_ID_LABEL = 0x0204; +const sal_uInt16 BIFF_ID_LABELRANGES = 0x015F; +const sal_uInt16 BIFF_ID_LABELSST = 0x00FD; +const sal_uInt16 BIFF_ID_LEFTMARGIN = 0x0026; +const sal_uInt16 BIFF_ID_MERGEDCELLS = 0x00E5; +const sal_uInt16 BIFF_ID_MSODRAWING = 0x00EC; +const sal_uInt16 BIFF_ID_MSODRAWINGGROUP = 0x00EB; +const sal_uInt16 BIFF_ID_MSODRAWINGSEL = 0x00ED; +const sal_uInt16 BIFF_ID_MTHREADSETTINGS = 0x089A; +const sal_uInt16 BIFF_ID_MULTBLANK = 0x00BE; +const sal_uInt16 BIFF_ID_MULTRK = 0x00BD; +const sal_uInt16 BIFF_ID_NOTE = 0x001C; +const sal_uInt16 BIFF_ID_NOTESOUND = 0x0096; +const sal_uInt16 BIFF2_ID_NUMBER = 0x0003; +const sal_uInt16 BIFF3_ID_NUMBER = 0x0203; +const sal_uInt16 BIFF_ID_OBJ = 0x005D; +const sal_uInt16 BIFF_ID_OBJECTPROTECT = 0x0063; +const sal_uInt16 BIFF_ID_OLESIZE = 0x00DE; +const sal_uInt16 BIFF_ID_PAGELAYOUTVIEW = 0x088B; +const sal_uInt16 BIFF_ID_PAGESETUP = 0x00A1; +const sal_uInt16 BIFF_ID_PALETTE = 0x0092; +const sal_uInt16 BIFF_ID_PANE = 0x0041; +const sal_uInt16 BIFF_ID_PARAMQUERY = 0x00DC; +const sal_uInt16 BIFF_ID_PASSWORD = 0x0013; +const sal_uInt16 BIFF_ID_PCDEFINITION = 0x00C6; +const sal_uInt16 BIFF_ID_PCDEFINITION2 = 0x0122; +const sal_uInt16 BIFF_ID_PCDFDISCRETEPR = 0x00D9; +const sal_uInt16 BIFF_ID_PCDFIELD = 0x00C7; +const sal_uInt16 BIFF_ID_PCDFIELDINDEX = 0x0103; +const sal_uInt16 BIFF_ID_PCDFORMULAFIELD = 0x00F9; +const sal_uInt16 BIFF_ID_PCDFRANGEPR = 0x00D8; +const sal_uInt16 BIFF_ID_PCDFSQLTYPE = 0x01BB; +const sal_uInt16 BIFF_ID_PCDSOURCE = 0x00E3; +const sal_uInt16 BIFF_ID_PCITEM_BOOL = 0x00CA; +const sal_uInt16 BIFF_ID_PCITEM_DATE = 0x00CE; +const sal_uInt16 BIFF_ID_PCITEM_DOUBLE = 0x00C9; +const sal_uInt16 BIFF_ID_PCITEM_ERROR = 0x00CB; +const sal_uInt16 BIFF_ID_PCITEM_INDEXLIST = 0x00C8; +const sal_uInt16 BIFF_ID_PCITEM_INTEGER = 0x00CC; +const sal_uInt16 BIFF_ID_PCITEM_MISSING = 0x00CF; +const sal_uInt16 BIFF_ID_PCITEM_STRING = 0x00CD; +const sal_uInt16 BIFF_ID_PHONETICPR = 0x00EF; +const sal_uInt16 BIFF_ID_PICTURE = 0x00E9; +const sal_uInt16 BIFF_ID_PIVOTCACHE = 0x00D5; +const sal_uInt16 BIFF_ID_PRECISION = 0x000E; +const sal_uInt16 BIFF_ID_PRINTGRIDLINES = 0x002B; +const sal_uInt16 BIFF_ID_PRINTHEADERS = 0x002A; +const sal_uInt16 BIFF_ID_PROJEXTSHEET = 0x00A3; +const sal_uInt16 BIFF_ID_PROTECT = 0x0012; +const sal_uInt16 BIFF_ID_PTDATAFIELD = 0x00C5; +const sal_uInt16 BIFF_ID_PTDEFINITION = 0x00B0; +const sal_uInt16 BIFF_ID_PTDEFINITION2 = 0x00F1; +const sal_uInt16 BIFF_ID_PTFIELD = 0x00B1; +const sal_uInt16 BIFF_ID_PTFIELD2 = 0x0100; +const sal_uInt16 BIFF_ID_PTFITEM = 0x00B2; +const sal_uInt16 BIFF_ID_PTPAGEFIELDS = 0x00B6; +const sal_uInt16 BIFF_ID_PTROWCOLFIELDS = 0x00B4; +const sal_uInt16 BIFF_ID_PTROWCOLITEMS = 0x00B5; +const sal_uInt16 BIFF_ID_QUERYTABLE = 0x01AD; +const sal_uInt16 BIFF_ID_QUERYTABLEREFRESH = 0x0802; +const sal_uInt16 BIFF_ID_QUERYTABLESETTINGS = 0x0803; +const sal_uInt16 BIFF_ID_QUERYTABLESTRING = 0x0804; +const sal_uInt16 BIFF_ID_RECALCID = 0x01C1; +const sal_uInt16 BIFF_ID_REFMODE = 0x000F; +const sal_uInt16 BIFF_ID_RIGHTMARGIN = 0x0027; +const sal_uInt16 BIFF_ID_RK = 0x027E; +const sal_uInt16 BIFF2_ID_ROW = 0x0008; +const sal_uInt16 BIFF3_ID_ROW = 0x0208; +const sal_uInt16 BIFF_ID_RSTRING = 0x00D6; +const sal_uInt16 BIFF_ID_SAVERECALC = 0x005F; +const sal_uInt16 BIFF_ID_SCENARIO = 0x00AF; +const sal_uInt16 BIFF_ID_SCENARIOS = 0x00AE; +const sal_uInt16 BIFF_ID_SCL = 0x00A0; +const sal_uInt16 BIFF_ID_SCENPROTECT = 0x00DD; +const sal_uInt16 BIFF_ID_SCREENTIP = 0x0800; +const sal_uInt16 BIFF_ID_SELECTION = 0x001D; +const sal_uInt16 BIFF_ID_SHAREDFEATHEAD = 0x0867; +const sal_uInt16 BIFF_ID_SHAREDFMLA = 0x04BC; +const sal_uInt16 BIFF_ID_SHEET = 0x0085; +const sal_uInt16 BIFF_ID_SHEETEXT = 0x0862; +const sal_uInt16 BIFF_ID_SHEETHEADER = 0x008F; +const sal_uInt16 BIFF_ID_SHEETPR = 0x0081; +const sal_uInt16 BIFF_ID_SST = 0x00FC; +const sal_uInt16 BIFF_ID_STANDARDWIDTH = 0x0099; +const sal_uInt16 BIFF2_ID_STRING = 0x0007; +const sal_uInt16 BIFF3_ID_STRING = 0x0207; +const sal_uInt16 BIFF_ID_STYLE = 0x0293; +const sal_uInt16 BIFF_ID_STYLEEXT = 0x0892; +const sal_uInt16 BIFF_ID_TABLESTYLES = 0x088E; +const sal_uInt16 BIFF_ID_THEME = 0x0896; +const sal_uInt16 BIFF_ID_TOPMARGIN = 0x0028; +const sal_uInt16 BIFF_ID_TXO = 0x01B6; +const sal_uInt16 BIFF_ID_UNCALCED = 0x005E; +const sal_uInt16 BIFF_ID_USESELFS = 0x0160; +const sal_uInt16 BIFF_ID_VBAPROJECT = 0x00D3; +const sal_uInt16 BIFF_ID_VBAPROJECTEMPTY = 0x01BD; +const sal_uInt16 BIFF_ID_VCENTER = 0x0084; +const sal_uInt16 BIFF_ID_VERPAGEBREAKS = 0x001A; +const sal_uInt16 BIFF_ID_WINDOW1 = 0x003D; +const sal_uInt16 BIFF2_ID_WINDOW2 = 0x003E; +const sal_uInt16 BIFF3_ID_WINDOW2 = 0x023E; +const sal_uInt16 BIFF_ID_WRITEACCESS = 0x005C; +const sal_uInt16 BIFF_ID_XCT = 0x0059; +const sal_uInt16 BIFF2_ID_XF = 0x0043; +const sal_uInt16 BIFF3_ID_XF = 0x0243; +const sal_uInt16 BIFF4_ID_XF = 0x0443; +const sal_uInt16 BIFF5_ID_XF = 0x00E0; +const sal_uInt16 BIFF_ID_XFCRC = 0x087C; +const sal_uInt16 BIFF_ID_XFEXT = 0x087D; + +const sal_uInt16 BIFF_ID_UNKNOWN = SAL_MAX_UINT16; + +// OBJ subrecord identifiers -------------------------------------------------- + +const sal_uInt16 BIFF_ID_OBJEND = 0x0000; /// End of OBJ. +const sal_uInt16 BIFF_ID_OBJMACRO = 0x0004; /// Macro link. +const sal_uInt16 BIFF_ID_OBJBUTTON = 0x0005; /// Button data. +const sal_uInt16 BIFF_ID_OBJGMO = 0x0006; /// Group marker. +const sal_uInt16 BIFF_ID_OBJCF = 0x0007; /// Clipboard format. +const sal_uInt16 BIFF_ID_OBJFLAGS = 0x0008; /// Option flags. +const sal_uInt16 BIFF_ID_OBJPICTFMLA = 0x0009; /// OLE link formula. +const sal_uInt16 BIFF_ID_OBJCBLS = 0x000A; /// Check box/radio button data. +const sal_uInt16 BIFF_ID_OBJRBO = 0x000B; /// Radio button group data. +const sal_uInt16 BIFF_ID_OBJSBS = 0x000C; /// Scroll bar data. +const sal_uInt16 BIFF_ID_OBJNTS = 0x000C; /// Note data. +const sal_uInt16 BIFF_ID_OBJSBSFMLA = 0x000E; /// Scroll bar/list box/combo box cell link. +const sal_uInt16 BIFF_ID_OBJGBODATA = 0x000F; /// Group box data. +const sal_uInt16 BIFF_ID_OBJEDODATA = 0x0010; /// Edit box data. +const sal_uInt16 BIFF_ID_OBJRBODATA = 0x0011; /// Radio button group data. +const sal_uInt16 BIFF_ID_OBJCBLSDATA = 0x0012; /// Check box/radio button data. +const sal_uInt16 BIFF_ID_OBJLBSDATA = 0x0013; /// List box/combo box data. +const sal_uInt16 BIFF_ID_OBJCBLSFMLA = 0x0014; /// Check box/radio button cell link. +const sal_uInt16 BIFF_ID_OBJCMO = 0x0015; /// Common object settings. + +// record constants ----------------------------------------------------------- + +const sal_uInt16 BIFF_BOF_BIFF2 = 0x0200; +const sal_uInt16 BIFF_BOF_BIFF3 = 0x0300; +const sal_uInt16 BIFF_BOF_BIFF4 = 0x0400; +const sal_uInt16 BIFF_BOF_BIFF5 = 0x0500; +const sal_uInt16 BIFF_BOF_BIFF8 = 0x0600; + +const sal_uInt8 BIFF_ERR_NULL = 0x00; +const sal_uInt8 BIFF_ERR_DIV0 = 0x07; +const sal_uInt8 BIFF_ERR_VALUE = 0x0F; +const sal_uInt8 BIFF_ERR_REF = 0x17; +const sal_uInt8 BIFF_ERR_NAME = 0x1D; +const sal_uInt8 BIFF_ERR_NUM = 0x24; +const sal_uInt8 BIFF_ERR_NA = 0x2A; + +const sal_uInt8 BIFF_DATATYPE_EMPTY = 0; +const sal_uInt8 BIFF_DATATYPE_DOUBLE = 1; +const sal_uInt8 BIFF_DATATYPE_STRING = 2; +const sal_uInt8 BIFF_DATATYPE_BOOL = 4; +const sal_uInt8 BIFF_DATATYPE_ERROR = 16; + +const sal_uInt8 BIFF_BOOLERR_BOOL = 0; +const sal_uInt8 BIFF_BOOLERR_ERROR = 1; + +// BIFF8 unicode strings ------------------------------------------------------ + +const sal_uInt8 BIFF_STRF_16BIT = 0x01; +const sal_uInt8 BIFF_STRF_PHONETIC = 0x04; +const sal_uInt8 BIFF_STRF_RICH = 0x08; +const sal_uInt8 BIFF_STRF_UNKNOWN = 0xF2; + +// ============================================================================ + +/** Static helper functions for BIFF filters. */ +class BiffHelper +{ +public: + // conversion ------------------------------------------------------------- + + /** Converts the passed packed number to a double. */ + static double calcDoubleFromRk( sal_Int32 nRkValue ); + /** Converts the passed double to a packed number, returns true on success. */ + static bool calcRkFromDouble( sal_Int32& ornRkValue, double fValue ); + + /** Converts the passed BIFF error to a double containing the respective Calc error code. */ + static double calcDoubleFromError( sal_uInt8 nErrorCode ); + + /** Returns a text encoding from an Windows code page. + @return The corresponding text encoding or RTL_TEXTENCODING_DONTKNOW. */ + static rtl_TextEncoding calcTextEncodingFromCodePage( sal_uInt16 nCodePage ); + /** Returns a Windows code page from a text encoding. */ + static sal_uInt16 calcCodePageFromTextEncoding( rtl_TextEncoding eTextEnc ); + + // BIFF12 import ---------------------------------------------------------- + + /** Reads a BIFF12 string with leading 16-bit or 32-bit length field. */ + static ::rtl::OUString readString( SequenceInputStream& rStrm, bool b32BitLen = true, bool bAllowNulChars = false ); + + // BIFF2-BIFF8 import ----------------------------------------------------- + + /** Returns true, if the current record of the stream is a BOF record. */ + static bool isBofRecord( BiffInputStream& rStrm ); + + /** Skips a block of records up to the specified end record. + + Skips all records until next end record. When this function returns, + the stream points to the end record, and the next call of the function + startNextRecord() at the stream will start the record following the end + record. + + The identifier of the record that is active while this function is + called is used as start record identifier. This identifier is used to + correctly skip embedded record blocks with the same start and end + record identifier. + + @return True = stream points to the end record. + */ + static bool skipRecordBlock( BiffInputStream& rStrm, sal_uInt16 nEndRecId ); + + /** Imports a picture from an IMGDATA record. */ + static void importImgData( StreamDataSequence& orDataSeq, BiffInputStream& rStrm, BiffType eBiff ); + +private: + BiffHelper(); // not implemented + ~BiffHelper(); // not implemented +}; + +// ---------------------------------------------------------------------------- + +/** BIFF12 stream operator for an ::rtl::OUString, reads 32-bit string length and Unicode array. */ +inline SequenceInputStream& operator>>( SequenceInputStream& rStrm, ::rtl::OUString& orString ) +{ + orString = BiffHelper::readString( rStrm ); + return rStrm; +} + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/biffinputstream.hxx b/sc/source/filter/inc/biffinputstream.hxx new file mode 100644 index 000000000000..9f01b023a074 --- /dev/null +++ b/sc/source/filter/inc/biffinputstream.hxx @@ -0,0 +1,411 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_BIFFINPUTSTREAM_HXX +#define OOX_XLS_BIFFINPUTSTREAM_HXX + +#include +#include "oox/helper/binaryinputstream.hxx" +#include "biffhelper.hxx" +#include "biffcodec.hxx" + +namespace rtl { class OUStringBuffer; } + +namespace oox { +namespace xls { + +// ============================================================================ + +namespace prv { + +/** Buffers the contents of a raw record and encapsulates stream decoding. */ +class BiffInputRecordBuffer +{ +public: + explicit BiffInputRecordBuffer( BinaryInputStream& rInStrm ); + + /** Returns the wrapped binary base stream. */ + inline const BinaryInputStream& getBaseStream() const { return mrInStrm; } + + /** Sets a decoder object and decrypts buffered record data. */ + void setDecoder( const BiffDecoderRef& rxDecoder ); + /** Returns the current decoder object. */ + inline BiffDecoderRef getDecoder() const { return mxDecoder; } + /** Enables/disables usage of current decoder. */ + void enableDecoder( bool bEnable ); + + /** Restarts the stream at the passed position. Buffer is invalid until the + next call of startRecord() or startNextRecord(). */ + void restartAt( sal_Int64 nPos ); + + /** Reads the record header at the passed position. */ + bool startRecord( sal_Int64 nHeaderPos ); + /** Reads the next record header from the stream. */ + bool startNextRecord(); + /** Returns the start position of the record header in the core stream. */ + sal_uInt16 getNextRecId(); + + /** Returns the start position of the record header in the core stream. */ + inline sal_Int64 getRecHeaderPos() const { return mnHeaderPos; } + /** Returns the current record identifier. */ + inline sal_uInt16 getRecId() const { return mnRecId; } + /** Returns the current record size. */ + inline sal_uInt16 getRecSize() const { return mnRecSize; } + /** Returns the current read position in the current record body. */ + inline sal_uInt16 getRecPos() const { return mnRecPos; } + /** Returns the number of remaining bytes in the current record body. */ + inline sal_uInt16 getRecLeft() const { return mnRecSize - mnRecPos; } + + /** Reads nBytes bytes to the existing buffer opData. Must NOT overread the source buffer. */ + void read( void* opData, sal_uInt16 nBytes ); + /** Ignores nBytes bytes. Must NOT overread the buffer. */ + void skip( sal_uInt16 nBytes ); + +private: + /** Updates data buffer from stream, if needed. */ + void updateBuffer(); + /** Updates decoded data from original data. */ + void updateDecoded(); + +private: + typedef ::std::vector< sal_uInt8 > DataBuffer; + + BinaryInputStream& mrInStrm; /// Core input stream. + DataBuffer maOriginalData; /// Original data read from stream. + DataBuffer maDecodedData; /// Decoded data. + DataBuffer* mpCurrentData; /// Points to data buffer currently in use. + BiffDecoderRef mxDecoder; /// Decoder object. + sal_Int64 mnHeaderPos; /// Stream start position of current record header. + sal_Int64 mnBodyPos; /// Stream start position of current record body. + sal_Int64 mnBufferBodyPos; /// Stream start position of buffered data. + sal_Int64 mnNextHeaderPos; /// Stream start position of next record header. + sal_uInt16 mnRecId; /// Current record identifier. + sal_uInt16 mnRecSize; /// Current record size. + sal_uInt16 mnRecPos; /// Current position in record body. + bool mbValidHeader; /// True = valid record header. +}; + +} // namespace prv + +// ============================================================================ + +/** This class is used to read BIFF record streams. + + An instance is constructed with a BinaryInputStream object. The passed + stream is reset to its start while constructing this stream. + + To start reading a record call startNextRecord(). Now it is possible to + read all contents of the record using operator>>() or any of the read***() + functions. If some data exceeds the record size limit, the stream looks for + a following CONTINUE record and jumps automatically to it. It is NOT + allowed that an atomic data type is split into two records (e.g. 4 bytes of + a double in one record and the other 4 bytes in a following CONTINUE). + + Trying to read over the record limits results in a stream error. The + isValid() function indicates that by returning false. From now on the data + returned by the read functions is undefined. The error state will be reset, + if the record is reset (with the function resetRecord()), or if the next + record is started. + + To switch off the automatic lookup of CONTINUE records, use resetRecord() + with false parameter. This is useful e.g. on import of drawing layer data, + where sometimes solely CONTINUE records will occur. The automatic lookup + keeps switched off until the method resetRecord() is called with parameter + true. All other settings done on the stream (e.g. alternative CONTINUE + record identifier, enabled decryption, NUL substitution character) will be + reset to default values, if a new record is started. + + The import stream supports decrypting the stream data. The contents of a + record (not the record header) will be encrypted by Excel if the file has + been stored with password protection. The functions setDecoder() and + enableDecoder() control the usage of the decryption algorithms. + setDecoder() sets a new decryption algorithm and initially enables it. + enableDecoder( false ) may be used to stop the usage of the decryption + temporarily (sometimes record contents are never encrypted, e.g. all BOF + records or the stream position in SHEET records). Decryption will be + reenabled automatically, if a new record is started with the function + startNextRecord(). +*/ +class BiffInputStream : public BinaryInputStream +{ +public: + /** Constructs the BIFF record stream using the passed binary stream. + + @param rInStream + The base input stream. Must be seekable. Will be seeked to its + start position. + + @param bContLookup Automatic CONTINUE lookup on/off. + */ + explicit BiffInputStream( + BinaryInputStream& rInStream, + bool bContLookup = true ); + + // record control --------------------------------------------------------- + + /** Sets stream pointer to the start of the next record content. + + Ignores all CONTINUE records of the current record, if automatic + CONTINUE usage is switched on. + + @return False = no record found (end of stream). + */ + bool startNextRecord(); + + /** Sets stream pointer to the start of the content of the specified record. + + The handle of the current record can be received and stored using the + function getRecHandle() for later usage with this function. The record + handle is equivalent to the position of the underlying binary stream, + thus the function can be used to perform a hard seek to a specific + position, if it is sure that a record starts exactly at this position. + + @return False = no record found (invalid handle passed). + */ + bool startRecordByHandle( sal_Int64 nRecHandle ); + + /** Sets stream pointer to begin of record content. + + @param bContLookup + Automatic CONTINUE lookup on/off. In difference to other stream + settings, this setting is persistent until next call of this + function (because it is wanted to receive the next CONTINUE records + separately). + @param nAltContId + Sets an alternative record identifier for content continuation. + This value is reset automatically when a new record is started with + startNextRecord(). + */ + void resetRecord( + bool bContLookup, + sal_uInt16 nAltContId = BIFF_ID_UNKNOWN ); + + /** Sets stream pointer before current record and invalidates stream. + + The next call to startNextRecord() will start again the current record. + This can be used in situations where a loop or a function leaves on a + specific record, but the parent context expects to start this record by + itself. The stream is invalid as long as the first record has not been + started (it is not allowed to call any other stream operation then). + */ + void rewindRecord(); + + // decoder ---------------------------------------------------------------- + + /** Sets a new decoder object. + + Enables decryption of record contents for the rest of the stream. + */ + void setDecoder( const BiffDecoderRef& rxDecoder ); + + /** Enables/disables usage of current decoder. + + Decryption is reenabled automatically, if a new record is started using + the function startNextRecord(). + */ + void enableDecoder( bool bEnable = true ); + + // stream/record state and info ------------------------------------------- + + /** Returns the current record identifier. */ + inline sal_uInt16 getRecId() const { return mnRecId; } + /** Returns the record identifier of the following record. */ + sal_uInt16 getNextRecId(); + + /** Returns a unique handle for the current record that can be used with + the function startRecordByHandle(). */ + inline sal_Int64 getRecHandle() const { return mnRecHandle; } + + // BinaryStreamBase interface (seeking) ----------------------------------- + + /** Returns the data size of the whole record without record headers. */ + virtual sal_Int64 size() const; + /** Returns the position inside of the whole record content. */ + virtual sal_Int64 tell() const; + /** Seeks in record content to the specified position. */ + virtual void seek( sal_Int64 nRecPos ); + /** Closes the input stream but not the wrapped stream. */ + virtual void close(); + + /** Returns the absolute position in the wrapped binary stream. */ + sal_Int64 tellBase() const; + + // BinaryInputStream interface (stream read access) ----------------------- + + /** Reads nBytes bytes to the passed sequence. + @return Number of bytes really read. */ + virtual sal_Int32 readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize = 1 ); + /** Reads nBytes bytes and copies them to the passed buffer opMem. + @return Number of bytes really read. */ + virtual sal_Int32 readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize = 1 ); + /** Seeks forward inside the current record. */ + virtual void skip( sal_Int32 nBytes, size_t nAtomSize = 1 ); + + /** Stream operator for integral and floating-point types. */ + template< typename Type > + inline BiffInputStream& operator>>( Type& ornValue ) { readValue( ornValue ); return *this; } + + // byte strings ----------------------------------------------------------- + + /** Reads 8/16 bit string length and character array, and returns the string. + @param b16BitLen + True = Read 16-bit string length field before the character array. + False = Read 8-bit string length field before the character array. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OString readByteString( bool b16BitLen, bool bAllowNulChars = false ); + + /** Reads 8/16 bit string length and character array, and returns a Unicode string. + @param b16BitLen + True = Read 16-bit string length field before the character array. + False = Read 8-bit string length field before the character array. + @param eTextEnc The text encoding used to create the Unicode string. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OUString readByteStringUC( bool b16BitLen, rtl_TextEncoding eTextEnc, bool bAllowNulChars = false ); + + // Unicode strings -------------------------------------------------------- + + /** Reads nChars characters of a BIFF8 string, and returns the string. + @param nChars Number of characters to read from the stream. + @param b16BitChars + True = The character array contains 16-bit characters. + False = The character array contains truncated 8-bit characters. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OUString readUniStringChars( sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars = false ); + + /** Reads 8-bit flags, extended header, nChar characters, extended data of + a BIFF8 string, and returns the string. + @param nChars Number of characters to read from the stream. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OUString readUniStringBody( sal_uInt16 nChars, bool bAllowNulChars = false ); + + /** Reads 16-bit character count, 8-bit flags, extended header, character + array, extended data of a BIFF8 string, and returns the string. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OUString readUniString( bool bAllowNulChars = false ); + + // ------------------------------------------------------------------------ +private: + /** Initializes all members after base stream has been seeked to new record. */ + void setupRecord(); + /** Restarts the current record from the beginning. */ + void restartRecord( bool bInvalidateRecSize ); + /** Sets stream pointer before specified record and invalidates stream. */ + void rewindToRecord( sal_Int64 nRecHandle ); + /** Returns true, if stream was able to start a valid record. */ + inline bool isInRecord() const { return mnRecHandle >= 0; } + + /** Returns true, if the passed ID is real or alternative continuation record ID. */ + bool isContinueId( sal_uInt16 nRecId ) const; + /** Goes to start of the next CONTINUE record. + @descr Stream must be located at the end of a raw record, and handling + of CONTINUE records must be enabled. + @return True if next CONTINUE record has been found and initialized. */ + bool jumpToNextContinue(); + /** Goes to start of the next CONTINUE record while reading strings. + @descr Stream must be located at the end of a raw record. If reading + has been started in a CONTINUE record, jumps to an existing following + CONTINUE record, even if handling of CONTINUE records is disabled (this + is a special handling for TXO string data). Reads additional Unicode + flag byte at start of the new raw record and sets or resets rb16BitChars. + @return True if next CONTINUE record has been found and initialized. */ + bool jumpToNextStringContinue( bool& rb16BitChars ); + /** Calculates the complete length of the current record including CONTINUE + records, stores the length in mnComplRecSize. */ + void calcRecordLength(); + + /** Returns the maximum size of raw data possible to read in one block. */ + sal_uInt16 getMaxRawReadSize( sal_Int32 nBytes, size_t nAtomSize ) const; + + /** Reads the BIFF8 Unicode string header fields. */ + void readUniStringHeader( bool& orb16BitChars, sal_Int32& ornAddSize ); + +private: + prv::BiffInputRecordBuffer maRecBuffer; /// Raw record data buffer. + + sal_Int64 mnRecHandle; /// Handle of current record. + sal_uInt16 mnRecId; /// Identifier of current record (not the CONTINUE ID). + sal_uInt16 mnAltContId; /// Alternative identifier for content continuation records. + + sal_Int64 mnCurrRecSize; /// Helper for record size and position. + sal_Int64 mnComplRecSize; /// Size of complete record data (with CONTINUEs). + bool mbHasComplRec; /// True = mnComplRecSize is valid. + + bool mbCont; /// True = automatic CONTINUE lookup enabled. +}; + +// ============================================================================ + +class BiffInputStreamPos +{ +public: + explicit BiffInputStreamPos( BiffInputStream& rStrm ); + + bool restorePosition(); + + inline BiffInputStream& getStream() { return mrStrm; } + +private: + BiffInputStream& mrStrm; + sal_Int64 mnRecHandle; + sal_Int64 mnRecPos; +}; + +// ============================================================================ + +/** Stores the current position of the passed stream on construction and + restores it automatically on destruction. */ +class BiffInputStreamPosGuard : private BiffInputStreamPos +{ +public: + explicit BiffInputStreamPosGuard( BiffInputStream& rStrm ); + ~BiffInputStreamPosGuard(); +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/biffoutputstream.hxx b/sc/source/filter/inc/biffoutputstream.hxx new file mode 100644 index 000000000000..75440e146436 --- /dev/null +++ b/sc/source/filter/inc/biffoutputstream.hxx @@ -0,0 +1,161 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_BIFFOUTPUTSTREAM_HXX +#define OOX_XLS_BIFFOUTPUTSTREAM_HXX + +#include +#include "oox/helper/binaryoutputstream.hxx" +#include "biffhelper.hxx" + +namespace oox { class BinaryOutputStream; } + +namespace oox { +namespace xls { + +// ============================================================================ + +namespace prv { + +/** Buffers the contents of a raw record. */ +class BiffOutputRecordBuffer +{ +public: + explicit BiffOutputRecordBuffer( + BinaryOutputStream& rOutStrm, + sal_uInt16 nMaxRecSize ); + + /** Returns the wrapped binary base stream. */ + inline const BinaryOutputStream& getBaseStream() const { return mrOutStrm; } + + /** Starts a new record. */ + void startRecord( sal_uInt16 nRecId ); + /** Finishes the current record. Must be called for every started record. */ + void endRecord(); + + /** Returns the number of remaining bytes in the current record body. */ + inline sal_uInt16 getRecLeft() const { return static_cast< sal_uInt16 >( mnMaxRecSize - maData.size() ); } + + /** Writes nBytes bytes from the existing buffer pData. Must NOT overwrite the destination buffer. */ + void write( const void* pData, sal_uInt16 nBytes ); + /** Writes a sequence of nBytes bytes with the passed value. */ + void fill( sal_uInt8 nValue, sal_uInt16 nBytes ); + +private: + typedef ::std::vector< sal_uInt8 > DataBuffer; + + BinaryOutputStream& mrOutStrm; /// Core output stream. + DataBuffer maData; /// Record data buffer. + sal_uInt16 mnMaxRecSize; /// Maximum size of record contents. + sal_uInt16 mnRecId; /// Current record identifier. + bool mbInRec; /// True = currently writing inside of a record. +}; + +} // namespace prv + +// ============================================================================ + +/** This class is used to write BIFF record streams. + + An instance is constructed with a BinaryOutputStream object and the + maximum size of BIFF record contents (e.g. 2080 bytes in BIFF2-BIFF5, or + 8224 bytes in BIFF8). + + To start writing a record, call startRecord() with the record identifier. + Each record must be closed by calling endRecord(). + + If some data exceeds the record size limit, a CONTINUE record will be + started automatically and the new data will be written to this record. If + specific data pieces must not be split into the current and a following + CONTINUE record, use setPortionSize(). Example: To write a sequence of + 16-bit values where 4 values form a unit and cannot be split, call + setPortionSize(8) first (4*2 bytes == 8). +*/ +class BiffOutputStream : public BinaryOutputStream +{ +public: + explicit BiffOutputStream( + BinaryOutputStream& rOutStream, + sal_uInt16 nMaxRecSize ); + + // record control --------------------------------------------------------- + + /** Starts a new record. */ + void startRecord( sal_uInt16 nRecId ); + + /** Finishes the current record. Must be called for every started record. */ + void endRecord(); + + /** Sets size of data portion in bytes. 0 or 1 means no portions are used. */ + void setPortionSize( sal_uInt8 nSize ); + + // BinaryStreamBase interface (seeking) ----------------------------------- + + /** Returns the absolute position in the wrapped binary stream. */ + sal_Int64 tellBase() const; + /** Returns the total size of the wrapped binary stream. */ + sal_Int64 sizeBase() const; + + // BinaryOutputStream interface (stream write access) --------------------- + + /** Writes the passed data sequence. */ + virtual void writeData( const StreamDataSequence& rData, size_t nAtomSize = 1 ); + /** Writes nBytes bytes from the passed buffer pMem. */ + virtual void writeMemory( const void* pMem, sal_Int32 nBytes, size_t nAtomSize = 1 ); + + /** Writes a sequence of nBytes bytes with the passed value. */ + void fill( sal_uInt8 nValue, sal_Int32 nBytes, size_t nAtomSize = 1 ); + + /** Stream operator for all data types supported by the writeValue() function. */ + template< typename Type > + inline BiffOutputStream& operator<<( Type nValue ) { writeValue( nValue ); return *this; } + + // ------------------------------------------------------------------------ +private: + /** Checks the remaining size in the current record, creates CONTINUE record if needed. */ + void ensureRawBlock( sal_uInt16 nSize ); + + /** Checks the remaining size in the current record and creates a CONTINUE + record if needed. + @return Maximum size left for writing to current record. */ + sal_uInt16 prepareWriteBlock( sal_Int32 nTotalSize, size_t nAtomSize ); + +private: + prv::BiffOutputRecordBuffer maRecBuffer; /// Raw record data buffer. + sal_uInt8 mnPortionSize; /// Size of data portions. + sal_uInt8 mnPortionPos; /// Position in current portion. +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/chartsheetfragment.hxx b/sc/source/filter/inc/chartsheetfragment.hxx new file mode 100644 index 000000000000..504a17040625 --- /dev/null +++ b/sc/source/filter/inc/chartsheetfragment.hxx @@ -0,0 +1,83 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_CHARTSHEETFRAGMENT_HXX +#define OOX_XLS_CHARTSHEETFRAGMENT_HXX + +#include "excelhandlers.hxx" + +namespace oox { +namespace xls { + +// ============================================================================ + +class ChartsheetFragment : public WorksheetFragmentBase +{ +public: + explicit ChartsheetFragment( + const WorksheetHelper& rHelper, + const ::rtl::OUString& rFragmentPath ); + +protected: + virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ); + virtual void onCharacters( const ::rtl::OUString& rChars ); + + virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ); + + virtual const ::oox::core::RecordInfo* getRecordInfos() const; + virtual void initializeImport(); + virtual void finalizeImport(); + +private: + /** Imports the the relation identifier for the DrawingML part. */ + void importDrawing( const AttributeList& rAttribs ); + /** Imports the DRAWING record containing the relation identifier for the DrawingML part. */ + void importDrawing( SequenceInputStream& rStrm ); +}; + +// ============================================================================ + +class BiffChartsheetFragment : public BiffWorksheetFragmentBase +{ +public: + explicit BiffChartsheetFragment( + const WorksheetHelper& rHelper, + const BiffWorkbookFragmentBase& rParent ); + + /** Imports the entire sheet fragment, returns true, if EOF record has been reached. */ + virtual bool importFragment(); +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/commentsbuffer.hxx b/sc/source/filter/inc/commentsbuffer.hxx new file mode 100644 index 000000000000..81143a982235 --- /dev/null +++ b/sc/source/filter/inc/commentsbuffer.hxx @@ -0,0 +1,129 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_COMMENTSBUFFER_HXX +#define OOX_XLS_COMMENTSBUFFER_HXX + +#include "richstring.hxx" +#include "worksheethelper.hxx" +#include + +namespace oox { +namespace xls { + +// ============================================================================ + +struct CommentModel +{ + ::com::sun::star::table::CellRangeAddress + maRange; /// Position of the comment in the worksheet. + RichStringRef mxText; /// Formatted text of the comment. + ::rtl::OUString maAuthor; /// Comment author (BIFF8 only). + sal_Int32 mnAuthorId; /// Identifier of the comment's author. + sal_uInt16 mnObjId; /// Drawing object identifier (BIFF8 only). + sal_Bool mbAutoFill; /// Auto Selection of comment object's fill style + sal_Bool mbAutoScale; /// Auto Scale comment text + sal_Bool mbColHidden; /// Comment cell's Column is Hidden + sal_Bool mbLocked; /// Comment changes Locked + sal_Bool mbRowHidden; /// Comment cell's Row is Hidden + sal_Int32 mnTHA; /// Horizontal Alignment + sal_Int32 mnTVA; /// Vertical Alignment + ::com::sun::star::awt::Rectangle + maAnchor; /// Anchor parameters + bool mbVisible; /// True = comment is always shown (BIFF2-BIFF8 only). + + explicit CommentModel(); +}; + +// ---------------------------------------------------------------------------- + +class Comment : public WorksheetHelper +{ +public: + explicit Comment( const WorksheetHelper& rHelper ); + + /** Imports a cell comment from the passed attributes of the comment element. */ + void importComment( const AttributeList& rAttribs ); + /** Imports a cell comment Properties from the passed attributes of the comment element. */ + void importCommentPr( const AttributeList& rAttribs ); + /** Imports a cell comment from the passed stream of a COMMENT record. */ + void importComment( SequenceInputStream& rStrm ); + /** Imports a cell comment from the passed stream of a NOTE record. */ + void importNote( BiffInputStream& rStrm ); + + /** Creates and returns a new rich-string object for the comment text. */ + RichStringRef createText(); + + /** Finalizes the formatted string of the comment. */ + void finalizeImport(); + +private: + /** Reads a BIFF2-BIFF5 NOTE record. */ + void importNoteBiff2( BiffInputStream& rStrm ); + /** Reads a BIFF8 NOTE record. */ + void importNoteBiff8( BiffInputStream& rStrm ); + /** Reads a NOTESOUND record. */ + void importNoteSound( BiffInputStream& rStrm ); + +private: + CommentModel maModel; +}; + +typedef ::boost::shared_ptr< Comment > CommentRef; + +// ============================================================================ + +class CommentsBuffer : public WorksheetHelper +{ +public: + explicit CommentsBuffer( const WorksheetHelper& rHelper ); + + /** Appends a new author to the list of comment authors. */ + void appendAuthor( const ::rtl::OUString& rAuthor ); + /** Creates and returns a new comment. */ + CommentRef createComment(); + + /** Finalizes the formatted string of all comments. */ + void finalizeImport(); + +private: + typedef ::std::vector< ::rtl::OUString > OUStringVector; + typedef RefVector< Comment > CommentVector; + + OUStringVector maAuthors; + CommentVector maComments; +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/commentsfragment.hxx b/sc/source/filter/inc/commentsfragment.hxx new file mode 100644 index 000000000000..f03a557637e7 --- /dev/null +++ b/sc/source/filter/inc/commentsfragment.hxx @@ -0,0 +1,73 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ***********************************************************************/ + +#ifndef OOX_XLS_COMMENTSFRAGMENT_HXX +#define OOX_XLS_COMMENTSFRAGMENT_HXX + +#include "commentsbuffer.hxx" +#include "excelhandlers.hxx" + +namespace oox { +namespace xls { + +// ============================================================================ + +class CommentsFragment : public WorksheetFragmentBase +{ +public: + explicit CommentsFragment( + const WorksheetHelper& rHelper, + const ::rtl::OUString& rFragmentPath ); +protected: + virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ); + virtual void onCharacters( const ::rtl::OUString& rChars ); + virtual void onEndElement(); + + virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ); + virtual void onEndRecord(); + + virtual const ::oox::core::RecordInfo* getRecordInfos() const; + +private: + /** Imports comment data from the comment element. */ + void importComment( const AttributeList& rAttribs ); + /** Imports comment data from the COMMENT record. */ + void importComment( SequenceInputStream& rStrm ); + +private: + CommentRef mxComment; +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/condformatbuffer.hxx b/sc/source/filter/inc/condformatbuffer.hxx new file mode 100644 index 000000000000..393a9d0875a9 --- /dev/null +++ b/sc/source/filter/inc/condformatbuffer.hxx @@ -0,0 +1,195 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_CONDFORMATBUFFER_HXX +#define OOX_XLS_CONDFORMATBUFFER_HXX + +#include +#include "formulaparser.hxx" +#include "worksheethelper.hxx" + +namespace com { namespace sun { namespace star { + namespace sheet { class XSheetConditionalEntries; } +} } } + +namespace oox { +namespace xls { + +// ============================================================================ + +/** Model for a single rule in a conditional formatting. */ +struct CondFormatRuleModel +{ + typedef ::std::vector< ApiTokenSequence > ApiTokenSequenceVector; + + ApiTokenSequenceVector maFormulas; /// Formulas for rule conditions. + ::rtl::OUString maText; /// Text for 'contains' rules. + sal_Int32 mnPriority; /// Priority of this rule. + sal_Int32 mnType; /// Type of the rule. + sal_Int32 mnOperator; /// In cell-is rules: Comparison operator. + sal_Int32 mnTimePeriod; /// In time-period rules: Type of time period. + sal_Int32 mnRank; /// In top-10 rules: True = bottom, false = top. + sal_Int32 mnStdDev; /// In average rules: Number of std deviations. + sal_Int32 mnDxfId; /// Differential formatting identifier. + bool mbStopIfTrue; /// True = stop evaluating rules, if this rule is true. + bool mbBottom; /// In top-10 rules: True = bottom, false = top. + bool mbPercent; /// In top-10 rules: True = percent, false = rank. + bool mbAboveAverage; /// In average rules: True = above average, false = below. + bool mbEqualAverage; /// In average rules: True = include average, false = exclude. + + explicit CondFormatRuleModel(); + + /** Sets the passed BIFF operator for condition type cellIs. */ + void setBiffOperator( sal_Int32 nOperator ); + + /** Sets the passed BIFF12 text comparison type and operator. */ + void setBiff12TextType( sal_Int32 nOperator ); +}; + +// ============================================================================ + +class CondFormat; + +/** Represents a single rule in a conditional formatting. */ +class CondFormatRule : public WorksheetHelper +{ +public: + explicit CondFormatRule( const CondFormat& rCondFormat ); + + /** Imports rule settings from the cfRule element. */ + void importCfRule( const AttributeList& rAttribs ); + /** Appends a new condition formula string. */ + void appendFormula( const ::rtl::OUString& rFormula ); + + /** Imports rule settings from a CFRULE record. */ + void importCfRule( SequenceInputStream& rStrm ); + + /** Imports rule settings from a CFRULE record. */ + void importCfRule( BiffInputStream& rStrm, sal_Int32 nPriority ); + + /** Creates a conditional formatting rule in the Calc document. */ + void finalizeImport( + const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSheetConditionalEntries >& rxEntries ); + + /** Returns the priority of this rule. */ + inline sal_Int32 getPriority() const { return maModel.mnPriority; } + +private: + const CondFormat& mrCondFormat; + CondFormatRuleModel maModel; +}; + +typedef ::boost::shared_ptr< CondFormatRule > CondFormatRuleRef; + +// ============================================================================ + +/** Model for a conditional formatting object. */ +struct CondFormatModel +{ + ApiCellRangeList maRanges; /// Cell ranges for this conditional format. + bool mbPivot; /// Conditional formatting belongs to pivot table. + + explicit CondFormatModel(); +}; + +// ============================================================================ + +/** Represents a conditional formatting object with a list of affected cell ranges. */ +class CondFormat : public WorksheetHelper +{ +public: + explicit CondFormat( const WorksheetHelper& rHelper ); + + /** Imports settings from the conditionalFormatting element. */ + void importConditionalFormatting( const AttributeList& rAttribs ); + /** Imports a conditional formatting rule from the cfRule element. */ + CondFormatRuleRef importCfRule( const AttributeList& rAttribs ); + + /** Imports settings from the CONDFORMATTING record. */ + void importCondFormatting( SequenceInputStream& rStrm ); + /** Imports a conditional formatting rule from the CFRULE record. */ + void importCfRule( SequenceInputStream& rStrm ); + + /** Imports settings from the CFHEADER record. */ + void importCfHeader( BiffInputStream& rStrm ); + + /** Creates the conditional formatting in the Calc document. */ + void finalizeImport(); + + /** Returns the cell ranges this conditional formatting belongs to. */ + inline const ApiCellRangeList& getRanges() const { return maModel.maRanges; } + +private: + CondFormatRuleRef createRule(); + void insertRule( CondFormatRuleRef xRule ); + +private: + typedef RefMap< sal_Int32, CondFormatRule > CondFormatRuleMap; + + CondFormatModel maModel; /// Model of this conditional formatting. + CondFormatRuleMap maRules; /// Maps formatting rules by priority. +}; + +typedef ::boost::shared_ptr< CondFormat > CondFormatRef; + +// ============================================================================ + +class CondFormatBuffer : public WorksheetHelper +{ +public: + explicit CondFormatBuffer( const WorksheetHelper& rHelper ); + + /** Imports settings from the conditionalFormatting element. */ + CondFormatRef importConditionalFormatting( const AttributeList& rAttribs ); + /** Imports settings from the CONDFORMATTING record. */ + CondFormatRef importCondFormatting( SequenceInputStream& rStrm ); + /** Imports settings from the CFHEADER record. */ + void importCfHeader( BiffInputStream& rStrm ); + + /** Creates all conditional formatting in the Calc document. */ + void finalizeImport(); + + /** Converts an OOXML condition operator token to the API constant. */ + static sal_Int32 convertToApiOperator( sal_Int32 nToken ); + +private: + CondFormatRef createCondFormat(); + +private: + typedef RefVector< CondFormat > CondFormatVec; + CondFormatVec maCondFormats; /// All conditional formatting in a sheet. +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/condformatcontext.hxx b/sc/source/filter/inc/condformatcontext.hxx new file mode 100644 index 000000000000..1cfd42cadec0 --- /dev/null +++ b/sc/source/filter/inc/condformatcontext.hxx @@ -0,0 +1,65 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_CONDFORMATCONTEXT_HXX +#define OOX_XLS_CONDFORMATCONTEXT_HXX + +#include "condformatbuffer.hxx" +#include "excelhandlers.hxx" + +namespace oox { +namespace xls { + +// ============================================================================ + +class CondFormatContext : public WorksheetContextBase +{ +public: + explicit CondFormatContext( WorksheetFragmentBase& rFragment ); + +protected: + virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ); + virtual void onStartElement( const AttributeList& rAttribs ); + virtual void onCharacters( const ::rtl::OUString& rChars ); + + virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ); + virtual void onStartRecord( SequenceInputStream& rStrm ); + +private: + CondFormatRef mxCondFmt; + CondFormatRuleRef mxRule; +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/connectionsbuffer.hxx b/sc/source/filter/inc/connectionsbuffer.hxx new file mode 100644 index 000000000000..50dba76b3c67 --- /dev/null +++ b/sc/source/filter/inc/connectionsbuffer.hxx @@ -0,0 +1,189 @@ +/* -*- 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef OOX_XLS_CONNECTIONSBUFFER_HXX +#define OOX_XLS_CONNECTIONSBUFFER_HXX + +#include "oox/helper/refvector.hxx" +#include "workbookhelper.hxx" + +namespace oox { +namespace xls { + +// ============================================================================ + +const sal_Int32 BIFF12_CONNECTION_UNKNOWN = 0; +const sal_Int32 BIFF12_CONNECTION_ODBC = 1; +const sal_Int32 BIFF12_CONNECTION_DAO = 2; +const sal_Int32 BIFF12_CONNECTION_FILE = 3; +const sal_Int32 BIFF12_CONNECTION_HTML = 4; +const sal_Int32 BIFF12_CONNECTION_OLEDB = 5; +const sal_Int32 BIFF12_CONNECTION_TEXT = 6; +const sal_Int32 BIFF12_CONNECTION_ADO = 7; +const sal_Int32 BIFF12_CONNECTION_DSP = 8; + +// ============================================================================ + +/** Special properties for data connections representing web queries. */ +struct WebPrModel +{ + typedef ::std::vector< ::com::sun::star::uno::Any > TablesVector; + + TablesVector maTables; /// Names or indexes of the web query tables. + ::rtl::OUString maUrl; /// Source URL to refresh the data. + ::rtl::OUString maPostMethod; /// POST method to query data. + ::rtl::OUString maEditPage; /// Web page showing query data (for XML queries). + sal_Int32 mnHtmlFormat; /// Plain text, rich text, or HTML. + bool mbXml; /// True = XML query, false = HTML query. + bool mbSourceData; /// True = import XML source data referred by HTML table. + bool mbParsePre; /// True = parse preformatted sections (
 tag).
+    bool                mbConsecutive;      /// True = join consecutive delimiters.
+    bool                mbFirstRow;         /// True = use column withs of first row for entire 
 tag.
+    bool                mbXl97Created;      /// True = web query created with Excel 97.
+    bool                mbTextDates;        /// True = read date values as text, false = parse dates.
+    bool                mbXl2000Refreshed;  /// True = refreshed with Excel 2000 or newer.
+    bool                mbHtmlTables;       /// True = HTML tables, false = entire document.
+
+    explicit            WebPrModel();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Common properties of an external data connection. */
+struct ConnectionModel
+{
+    typedef ::std::auto_ptr< WebPrModel > WebPrModelPtr;
+
+    WebPrModelPtr       mxWebPr;            /// Special settings for web queries.
+    ::rtl::OUString     maName;             /// Unique name of this connection.
+    ::rtl::OUString     maDescription;      /// User description of this connection.
+    ::rtl::OUString     maSourceFile;       /// URL of a source data file.
+    ::rtl::OUString     maSourceConnFile;   /// URL of a source connection file.
+    ::rtl::OUString     maSsoId;            /// Single sign-on identifier.
+    sal_Int32           mnId;               /// Unique connection identifier.
+    sal_Int32           mnType;             /// Data source type.
+    sal_Int32           mnReconnectMethod;  /// Reconnection method.
+    sal_Int32           mnCredentials;      /// Credentials method.
+    sal_Int32           mnInterval;         /// Refresh interval in minutes.
+    bool                mbKeepAlive;        /// True = keep connection open after import.
+    bool                mbNew;              /// True = new connection, never updated.
+    bool                mbDeleted;          /// True = connection has been deleted.
+    bool                mbOnlyUseConnFile;  /// True = use maSourceConnFile, ignore mnReconnectMethod.
+    bool                mbBackground;       /// True = background refresh enabled.
+    bool                mbRefreshOnLoad;    /// True = refresh connection on import.
+    bool                mbSaveData;         /// True = save cached data with connection.
+    bool                mbSavePassword;     /// True = save password in connection string.
+
+    explicit            ConnectionModel();
+
+    WebPrModel&         createWebPr();
+};
+
+// ----------------------------------------------------------------------------
+
+/** An external data connection (database, web query, etc.). */
+class Connection : public WorkbookHelper
+{
+public:
+    explicit            Connection( const WorkbookHelper& rHelper, sal_Int32 nConnId = -1 );
+
+    /** Imports connection settings from the connection element. */
+    void                importConnection( const AttributeList& rAttribs );
+    /** Imports web query settings from the webPr element. */
+    void                importWebPr( const AttributeList& rAttribs );
+    /** Imports web query table settings from the tables element. */
+    void                importTables( const AttributeList& rAttribs );
+    /** Imports a web query table identifier from the m, s, or x element. */
+    void                importTable( const AttributeList& rAttribs, sal_Int32 nElement );
+
+    /** Imports connection settings from the CONNECTION record. */
+    void                importConnection( SequenceInputStream& rStrm );
+    /** Imports web query settings from the WEBPR record. */
+    void                importWebPr( SequenceInputStream& rStrm );
+    /** Imports web query table settings from the WEBPRTABLES record. */
+    void                importWebPrTables( SequenceInputStream& rStrm );
+    /** Imports a web query table identifier from the PCITEM_MISSING, PCITEM_STRING, or PCITEM_INDEX record. */
+    void                importWebPrTable( SequenceInputStream& rStrm, sal_Int32 nRecId );
+
+    /** Imports connection settings from the DBQUERY record. */
+    void                importDbQuery( BiffInputStream& rStrm );
+    /** Imports connection settings from the QUERYTABLESETTINGS record. */
+    void                importQueryTableSettings( BiffInputStream& rStrm );
+
+    /** Returns the unique connection identifier. */
+    inline sal_Int32    getConnectionId() const { return maModel.mnId; }
+    /** Returns the source data type of the connection. */
+    inline sal_Int32    getConnectionType() const { return maModel.mnType; }
+    /** Returns read-only access to the connection model data. */
+    const ConnectionModel& getModel() const { return maModel; }
+
+private:
+    ConnectionModel     maModel;
+};
+
+typedef ::boost::shared_ptr< Connection > ConnectionRef;
+
+// ============================================================================
+
+class ConnectionsBuffer : public WorkbookHelper
+{
+public:
+    explicit            ConnectionsBuffer( const WorkbookHelper& rHelper );
+
+    /** Creates a new empty connection. */
+    Connection&         createConnection();
+    /** Creates a new empty connection with a valid but unused identifier. */
+    Connection&         createConnectionWithId();
+
+    /** Maps all connections by their identifier. */
+    void                finalizeImport();
+
+    /** Returns a data connection by its unique identifier. */
+    ConnectionRef       getConnection( sal_Int32 nConnId ) const;
+
+private:
+    /** Inserts the passed connection into the map according to its identifier. */
+    void                insertConnectionToMap( const ConnectionRef& rxConnection );
+
+private:
+    typedef RefVector< Connection >         ConnectionVector;
+    typedef RefMap< sal_Int32, Connection > ConnectionMap;
+
+    ConnectionVector    maConnections;
+    ConnectionMap       maConnectionsById;
+    sal_Int32           mnUnusedId;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/connectionsfragment.hxx b/sc/source/filter/inc/connectionsfragment.hxx
new file mode 100644
index 000000000000..b791454dede3
--- /dev/null
+++ b/sc/source/filter/inc/connectionsfragment.hxx
@@ -0,0 +1,81 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_CONNECTIONSFRAGMENT_HXX
+#define OOX_XLS_CONNECTIONSFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+class Connection;
+
+// ============================================================================
+
+class ConnectionContext : public WorkbookContextBase
+{
+public:
+    explicit            ConnectionContext( WorkbookFragmentBase& rParent, Connection& rConnection );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onStartElement( const AttributeList& rAttribs );
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual void        onStartRecord( SequenceInputStream& rStrm );
+
+private:
+    Connection&         mrConnection;
+};
+
+// ============================================================================
+
+class ConnectionsFragment : public WorkbookFragmentBase
+{
+public:
+    explicit            ConnectionsFragment(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+    virtual void        finalizeImport();
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/defnamesbuffer.hxx b/sc/source/filter/inc/defnamesbuffer.hxx
new file mode 100644
index 000000000000..0d28b6ab747e
--- /dev/null
+++ b/sc/source/filter/inc/defnamesbuffer.hxx
@@ -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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_DEFINEDNAMESBUFFER_HXX
+#define OOX_XLS_DEFINEDNAMESBUFFER_HXX
+
+#include "formulabase.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace sheet { class XNamedRange; }
+} } }
+
+namespace oox {
+namespace xls {
+
+class BiffInputStreamPos;
+
+// ============================================================================
+
+// codes for built-in names
+const sal_Unicode BIFF_DEFNAME_CONSOLIDATEAREA  = '\x00';
+const sal_Unicode BIFF_DEFNAME_AUTOOPEN         = '\x01';   // Sheet macro executed when workbook is opened.
+const sal_Unicode BIFF_DEFNAME_AUTOCLOSE        = '\x02';   // Sheet macro executed when workbook is closed.
+const sal_Unicode BIFF_DEFNAME_EXTRACT          = '\x03';   // Filter output destination for advanced filter.
+const sal_Unicode BIFF_DEFNAME_DATABASE         = '\x04';
+const sal_Unicode BIFF_DEFNAME_CRITERIA         = '\x05';   // Filter criteria source range for advanced filter.
+const sal_Unicode BIFF_DEFNAME_PRINTAREA        = '\x06';   // Print ranges.
+const sal_Unicode BIFF_DEFNAME_PRINTTITLES      = '\x07';   // Rows/columns repeated on each page when printing.
+const sal_Unicode BIFF_DEFNAME_RECORDER         = '\x08';
+const sal_Unicode BIFF_DEFNAME_DATAFORM         = '\x09';
+const sal_Unicode BIFF_DEFNAME_AUTOACTIVATE     = '\x0A';   // Sheet macro executed when workbook is activated.
+const sal_Unicode BIFF_DEFNAME_AUTODEACTIVATE   = '\x0B';   // Sheet macro executed when workbook is deactivated.
+const sal_Unicode BIFF_DEFNAME_SHEETTITLE       = '\x0C';
+const sal_Unicode BIFF_DEFNAME_FILTERDATABASE   = '\x0D';   // Sheet range autofilter or advanced filter works on.
+const sal_Unicode BIFF_DEFNAME_UNKNOWN          = '\x0E';
+
+// ============================================================================
+
+struct DefinedNameModel
+{
+    ::rtl::OUString     maName;         /// The original name.
+    ::rtl::OUString     maFormula;      /// The formula string.
+    sal_Int32           mnSheet;        /// Sheet index for local names.
+    sal_Int32           mnFuncGroupId;  /// Function group identifier.
+    bool                mbMacro;        /// True = Macro name (VBA or sheet macro).
+    bool                mbFunction;     /// True = function, false = command.
+    bool                mbVBName;       /// True = VBA macro, false = sheet macro.
+    bool                mbHidden;       /// True = name hidden in UI.
+
+    explicit            DefinedNameModel();
+};
+
+// ============================================================================
+
+/** Base class for defined names and external names. */
+class DefinedNameBase : public WorkbookHelper
+{
+public:
+    explicit            DefinedNameBase( const WorkbookHelper& rHelper );
+
+    /** Returns the original name as imported from or exported to the file. */
+    inline const ::rtl::OUString& getModelName() const { return maModel.maName; }
+    /** Returns the name as used in the Calc document. */
+    inline const ::rtl::OUString& getCalcName() const { return maCalcName; }
+
+    /** Returns the original name as imported from or exported to the file. */
+    const ::rtl::OUString& getUpcaseModelName() const;
+    /** Returns an Any with a SingleReference or ComplexReference, or an empty Any. */
+    ::com::sun::star::uno::Any getReference( const ::com::sun::star::table::CellAddress& rBaseAddr ) const;
+
+protected:
+    /** Converts the OOXML formula string stored in the own model. */
+    ApiTokenSequence    importOoxFormula( sal_Int16 nBaseSheet );
+    /** Imports the BIFF12 formula from the passed stream. */
+    ApiTokenSequence    importBiff12Formula( sal_Int16 nBaseSheet, SequenceInputStream& rStrm );
+    /** Imports the BIFF formula from the passed stream. */
+    ApiTokenSequence    importBiffFormula( sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize = 0 );
+
+    /** Tries to convert the passed token sequence to a SingleReference or ComplexReference. */
+    void                extractReference( const ApiTokenSequence& rTokens );
+
+protected:
+    DefinedNameModel    maModel;            /// Model data for this defined name.
+    mutable ::rtl::OUString maUpModelName;  /// Model name converted to uppercase ASCII.
+    ::rtl::OUString     maCalcName;         /// Final name used in the Calc document.
+    ::com::sun::star::uno::Any maRefAny;    /// Single cell/range reference.
+};
+
+// ============================================================================
+
+class DefinedName : public DefinedNameBase
+{
+public:
+    explicit            DefinedName( const WorkbookHelper& rHelper );
+
+    /** Sets the attributes for this defined name from the passed attribute set. */
+    void                importDefinedName( const AttributeList& rAttribs );
+    /** Sets the formula string from the body of the definedName element. */
+    void                setFormula( const ::rtl::OUString& rFormula );
+    /** Imports the defined name from a DEFINEDNAME record in the passed stream. */
+    void                importDefinedName( SequenceInputStream& rStrm );
+    /** Imports the defined name from a DEFINEDNAME record in the passed BIFF stream. */
+    void                importDefinedName( BiffInputStream& rStrm, sal_Int16 nCalcSheet );
+
+    /** Creates a defined name in the Calc document. */
+    void                createNameObject();
+    /** Converts the formula string or BIFF token array for this defined name. */
+    void                convertFormula();
+
+    /** Returns true, if this defined name is global in the document. */
+    inline bool         isGlobalName() const { return mnCalcSheet < 0; }
+    /** Returns true, if this defined name is a special builtin name. */
+    inline bool         isBuiltinName() const { return mcBuiltinId != BIFF_DEFNAME_UNKNOWN; }
+    /** Returns true, if this defined name is a macro function call. */
+    inline bool         isMacroFunction() const { return maModel.mbMacro && maModel.mbFunction; }
+    /** Returns true, if this defined name is a reference to a VBA macro. */
+    inline bool         isVBName() const { return maModel.mbMacro && maModel.mbVBName; }
+
+    /** Returns the 0-based sheet index for local names, or -1 for global names. */
+    inline sal_Int16    getLocalCalcSheet() const { return mnCalcSheet; }
+    /** Returns the built-in identifier of the defined name. */
+    inline sal_Unicode  getBuiltinId() const { return mcBuiltinId; }
+    /** Returns the token index used in API token arrays (com.sun.star.sheet.FormulaToken). */
+    inline sal_Int32    getTokenIndex() const { return mnTokenIndex; }
+    /** Tries to resolve the defined name to an absolute cell range. */
+    bool                getAbsoluteRange( ::com::sun::star::table::CellRangeAddress& orRange ) const;
+
+private:
+    /** Imports the OOXML or BIFF12 definition of the name. */
+    void                implImportOoxFormula();
+    /** Imports the BIFF definition of the name. */
+    void                implImportBiffFormula();
+
+private:
+    typedef ::std::auto_ptr< StreamDataSequence >   StreamDataSeqPtr;
+    typedef ::std::auto_ptr< BiffInputStreamPos >   BiffStreamPosPtr;
+
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XNamedRange >
+                        mxNamedRange;       /// XNamedRange interface of the defined name.
+    sal_Int32           mnTokenIndex;       /// Name index used in API token array.
+    sal_Int16           mnCalcSheet;        /// Calc sheet index for sheet-local names.
+    sal_Unicode         mcBuiltinId;        /// Identifier for built-in defined names.
+    StreamDataSeqPtr    mxFormula;          /// Formula data for BIFF12 import.
+    BiffStreamPosPtr    mxBiffStrm;         /// Cached BIFF stream for formula import.
+    sal_uInt16          mnFmlaSize;         /// Cached BIFF formula size for formula import.
+};
+
+typedef ::boost::shared_ptr< DefinedName > DefinedNameRef;
+
+// ============================================================================
+
+class DefinedNamesBuffer : public WorkbookHelper
+{
+public:
+    explicit            DefinedNamesBuffer( const WorkbookHelper& rHelper );
+
+    /** Sets the sheet index for local names (BIFF2-BIFF4 only). */
+    void                setLocalCalcSheet( sal_Int16 nCalcSheet );
+
+    /** Imports a defined name from the passed attribute set. */
+    DefinedNameRef      importDefinedName( const AttributeList& rAttribs );
+    /** Imports a defined name from a DEFINEDNAME record in the passed stream. */
+    void                importDefinedName( SequenceInputStream& rStrm );
+    /** Imports a defined name from a DEFINEDNAME record in the passed BIFF stream. */
+    void                importDefinedName( BiffInputStream& rStrm );
+
+    /** Creates all defined names in the document. */
+    void                finalizeImport();
+
+    /** Returns a defined name by zero-based index (order of appearance). */
+    DefinedNameRef      getByIndex( sal_Int32 nIndex ) const;
+    /** Returns a defined name by token index (index in XDefinedNames container). */
+    DefinedNameRef      getByTokenIndex( sal_Int32 nIndex ) const;
+    /** Returns a defined name by its model name.
+        @param nSheet  The sheet index for local names or -1 for global names.
+            If no local name is found, tries to find a matching global name.
+        @return  Reference to the defined name or empty reference. */
+    DefinedNameRef      getByModelName( const ::rtl::OUString& rModelName, sal_Int16 nCalcSheet = -1 ) const;
+    /** Returns a built-in defined name by its built-in identifier.
+        @param nSheet  The sheet index of the built-in name.
+        @return  Reference to the defined name or empty reference. */
+    DefinedNameRef      getByBuiltinId( sal_Unicode cBuiltinId, sal_Int16 nCalcSheet ) const;
+
+private:
+    DefinedNameRef      createDefinedName();
+
+private:
+    typedef ::std::pair< sal_Int16, ::rtl::OUString >   SheetNameKey;
+    typedef ::std::pair< sal_Int16, sal_Unicode >       BuiltinKey;
+
+    typedef RefVector< DefinedName >            DefNameVector;
+    typedef RefMap< SheetNameKey, DefinedName > DefNameNameMap;
+    typedef RefMap< BuiltinKey, DefinedName >   DefNameBuiltinMap;
+    typedef RefMap< sal_Int32, DefinedName >    DefNameTokenIdMap;
+
+    DefNameVector       maDefNames;         /// List of all defined names in insertion order.
+    DefNameNameMap      maModelNameMap;     /// Maps all defined names by sheet index and model name.
+    DefNameBuiltinMap   maBuiltinMap;       /// Maps all defined names by sheet index and built-in identifier.
+    DefNameTokenIdMap   maTokenIdMap;       /// Maps all defined names by API token index.
+    sal_Int16           mnCalcSheet;        /// Current sheet index for BIFF2-BIFF4 names (always sheet-local).
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/drawingbase.hxx b/sc/source/filter/inc/drawingbase.hxx
new file mode 100644
index 000000000000..4c4769390ed3
--- /dev/null
+++ b/sc/source/filter/inc/drawingbase.hxx
@@ -0,0 +1,157 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_DRAWINGBASE_HXX
+#define OOX_XLS_DRAWINGBASE_HXX
+
+#include "oox/drawingml/drawingmltypes.hxx"
+#include "worksheethelper.hxx"
+
+#include 
+#include 
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Absolute position in a spreadsheet (in EMUs) independent from cells. */
+struct AnchorPointModel : public ::oox::drawingml::EmuPoint
+{
+    inline explicit     AnchorPointModel() : ::oox::drawingml::EmuPoint( -1, -1 ) {}
+    inline bool         isValid() const { return (X >= 0) && (Y >= 0); }
+};
+
+// ----------------------------------------------------------------------------
+
+/** Absolute size in a spreadsheet (in EMUs). */
+struct AnchorSizeModel : public ::oox::drawingml::EmuSize
+{
+    inline explicit     AnchorSizeModel() : ::oox::drawingml::EmuSize( -1, -1 ) {}
+    inline bool         isValid() const { return (Width >= 0) && (Height >= 0); }
+};
+
+// ----------------------------------------------------------------------------
+
+/** Position in spreadsheet (cell position and offset inside cell). */
+struct CellAnchorModel
+{
+    sal_Int32           mnCol;              /// Column index.
+    sal_Int32           mnRow;              /// Row index.
+    sal_Int64           mnColOffset;        /// X offset inside the column.
+    sal_Int64           mnRowOffset;        /// Y offset inside the row.
+
+    explicit            CellAnchorModel();
+    inline bool         isValid() const { return (mnCol >= 0) && (mnRow >= 0); }
+};
+
+// ----------------------------------------------------------------------------
+
+/** Application-specific client data of a shape. */
+struct AnchorClientDataModel
+{
+    bool                mbLocksWithSheet;
+    bool                mbPrintsWithSheet;
+
+    explicit            AnchorClientDataModel();
+};
+
+// ============================================================================
+
+/** Contains the position of a shape in the spreadsheet. Supports different
+    shape anchor modes (absolute, one-cell, two-cell). */
+class ShapeAnchor : public WorksheetHelper
+{
+public:
+    explicit            ShapeAnchor( const WorksheetHelper& rHelper );
+
+    /** Imports the shape anchor (one of the elements xdr:absoluteAnchor, xdr:oneCellAnchor, xdr:twoCellAnchor). */
+    void                importAnchor( sal_Int32 nElement, const AttributeList& rAttribs );
+    /** Imports the absolute anchor position from the xdr:pos element. */
+    void                importPos( const AttributeList& rAttribs );
+    /** Imports the absolute anchor size from the xdr:ext element. */
+    void                importExt( const AttributeList& rAttribs );
+    /** Imports the shape client data from the xdr:clientData element. */
+    void                importClientData( const AttributeList& rAttribs );
+    /** Sets an attribute of the cell-dependent anchor position from xdr:from and xdr:to elements. */
+    void                setCellPos( sal_Int32 nElement, sal_Int32 nParentContext, const ::rtl::OUString& rValue );
+    /** Imports the client anchor settings from a VML element. */
+    void                importVmlAnchor( const ::rtl::OUString& rAnchor );
+    /** Imports the client anchor settings from a BIFF or DFF stream. */
+    void                importBiffAnchor( BinaryInputStream& rStrm );
+
+    /** Calculates the resulting shape anchor in EMUs. */
+    ::oox::drawingml::EmuRectangle calcAnchorRectEmu(
+                            const ::com::sun::star::awt::Size& rPageSizeHmm ) const;
+    /** Calculates the resulting shape anchor in 1/100 mm. */
+    ::com::sun::star::awt::Rectangle calcAnchorRectHmm(
+                            const ::com::sun::star::awt::Size& rPageSizeHmm ) const;
+    /** Returns the 'from' cell if it exists */
+    ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > getFromCell() const;
+    /** Applies Cell Anchor to an XShape if needed*/
+    void applyToXShape( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape>& rxShape );
+private:
+    /** Converts the passed anchor to an absolute position in EMUs. */
+    ::oox::drawingml::EmuPoint calcCellAnchorEmu( const CellAnchorModel& rModel ) const;
+
+private:
+    enum AnchorType
+    {
+        ANCHOR_INVALID,         /// Anchor type is unknown.
+        ANCHOR_ABSOLUTE,        /// Absolute anchor (top-left corner and size in absolute units).
+        ANCHOR_ONECELL,         /// One-cell anchor (top-left corner at cell, size in absolute units).
+        ANCHOR_TWOCELL,         /// Two-cell anchor (top-left and bottom-right corner at cell).
+        ANCHOR_VML
+    };
+
+    /** Specifies how cell positions from CellAnchorModel have to be processed. */
+    enum CellAnchorType
+    {
+        CELLANCHOR_EMU,             /// Offsets are given in EMUs.
+        CELLANCHOR_PIXEL,           /// Offsets are given in screen pixels.
+        CELLANCHOR_COLROW           /// Offsets are given in fractions of column width or row height.
+    };
+
+    AnchorType          meAnchorType;       /// Type of this shape anchor.
+    CellAnchorType      meCellAnchorType;   /// Type of the cell anchor models.
+    AnchorPointModel    maPos;              /// Top-left position, if anchor is of type absolute.
+    AnchorSizeModel     maSize;             /// Anchor size, if anchor is not of type two-cell.
+    CellAnchorModel     maFrom;             /// Top-left position, if anchor is not of type absolute.
+    CellAnchorModel     maTo;               /// Bottom-right position, if anchor is of type two-cell.
+    AnchorClientDataModel maClientData;     /// Shape client data.
+    sal_Int32           mnEditAs;           /// Anchor mode as shown in the UI.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/drawingfragment.hxx b/sc/source/filter/inc/drawingfragment.hxx
new file mode 100644
index 000000000000..e8b1ed7abeae
--- /dev/null
+++ b/sc/source/filter/inc/drawingfragment.hxx
@@ -0,0 +1,238 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_DRAWINGFRAGMENT_HXX
+#define OOX_XLS_DRAWINGFRAGMENT_HXX
+
+#include 
+#include 
+#include "oox/drawingml/shape.hxx"
+#include "oox/drawingml/shapegroupcontext.hxx"
+#include "oox/ole/axcontrol.hxx"
+#include "oox/ole/vbaproject.hxx"
+#include "oox/vml/vmldrawing.hxx"
+#include "oox/vml/vmldrawingfragment.hxx"
+#include "oox/vml/vmltextbox.hxx"
+#include "drawingbase.hxx"
+#include "excelhandlers.hxx"
+
+namespace oox { namespace ole {
+    struct AxFontData;
+    class AxMorphDataModelBase;
+} }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+// DrawingML
+// ============================================================================
+
+class ShapeMacroAttacher : public ::oox::ole::VbaMacroAttacherBase
+{
+public:
+    explicit            ShapeMacroAttacher( const ::rtl::OUString& rMacroName,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& rxShape );
+
+private:
+    virtual void        attachMacro( const ::rtl::OUString& rMacroUrl );
+
+private:
+    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > mxShape;
+};
+
+// ============================================================================
+
+class Shape : public ::oox::drawingml::Shape, public WorksheetHelper
+{
+public:
+    explicit            Shape(
+                            const WorksheetHelper& rHelper,
+                            const AttributeList& rAttribs,
+                            const sal_Char* pcServiceName = 0 );
+
+protected:
+    virtual void        finalizeXShape(
+                            ::oox::core::XmlFilterBase& rFilter,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes );
+
+private:
+    ::rtl::OUString     maMacroName;
+};
+
+// ============================================================================
+
+/** Context handler for creation of shapes embedded in group shapes. */
+class GroupShapeContext : public ::oox::drawingml::ShapeGroupContext, public WorksheetHelper
+{
+public:
+    explicit            GroupShapeContext(
+                            ::oox::core::ContextHandler& rParent,
+                            const WorksheetHelper& rHelper,
+                            const ::oox::drawingml::ShapePtr& rxParentShape,
+                            const ::oox::drawingml::ShapePtr& rxShape );
+
+    static ::oox::core::ContextHandlerRef
+                        createShapeContext(
+                            ::oox::core::ContextHandler& rParent,
+                            const WorksheetHelper& rHelper,
+                            sal_Int32 nElement,
+                            const AttributeList& rAttribs,
+                            const ::oox::drawingml::ShapePtr& rxParentShape,
+                            ::oox::drawingml::ShapePtr* pxShape = 0 );
+
+protected:
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > SAL_CALL
+                        createFastChildContext(
+                            sal_Int32 nElement,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& rxAttribs )
+                        throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException);
+};
+
+// ============================================================================
+
+/** Fragment handler for a complete sheet drawing. */
+class DrawingFragment : public WorksheetFragmentBase
+{
+public:
+    explicit            DrawingFragment(
+                            const WorksheetHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onCharacters( const ::rtl::OUString& rChars );
+    virtual void        onEndElement();
+
+private:
+    typedef ::std::auto_ptr< ShapeAnchor > ShapeAnchorRef;
+
+    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >
+                        mxDrawPage;             /// Drawing page of this sheet.
+    ::oox::drawingml::ShapePtr mxShape;         /// Current top-level shape.
+    ShapeAnchorRef      mxAnchor;               /// Current anchor of top-level shape.
+};
+
+// ============================================================================
+// VML
+// ============================================================================
+
+class VmlControlMacroAttacher : public ::oox::ole::VbaMacroAttacherBase
+{
+public:
+    explicit            VmlControlMacroAttacher( const ::rtl::OUString& rMacroName,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer >& rxCtrlFormIC,
+                            sal_Int32 nCtrlIndex, sal_Int32 nCtrlType, sal_Int32 nDropStyle );
+
+private:
+    virtual void        attachMacro( const ::rtl::OUString& rMacroUrl );
+
+private:
+    ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer > mxCtrlFormIC;
+    sal_Int32           mnCtrlIndex;
+    sal_Int32           mnCtrlType;
+    sal_Int32           mnDropStyle;
+};
+
+// ============================================================================
+
+class VmlDrawing : public ::oox::vml::Drawing, public WorksheetHelper
+{
+public:
+    explicit            VmlDrawing( const WorksheetHelper& rHelper );
+
+    /** Returns the drawing shape for a cell note at the specified position. */
+    const ::oox::vml::ShapeBase* getNoteShape( const ::com::sun::star::table::CellAddress& rPos ) const;
+
+    /** Filters cell note shapes. */
+    virtual bool        isShapeSupported( const ::oox::vml::ShapeBase& rShape ) const;
+
+    /** Returns additional base names for automatic shape name creation. */
+    virtual ::rtl::OUString getShapeBaseName( const ::oox::vml::ShapeBase& rShape ) const;
+
+    /** Calculates the shape rectangle from a cell anchor string. */
+    virtual bool        convertClientAnchor(
+                            ::com::sun::star::awt::Rectangle& orShapeRect,
+                            const ::rtl::OUString& rShapeAnchor ) const;
+
+    /** Creates a UNO control shape for legacy drawing controls. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        createAndInsertClientXShape(
+                            const ::oox::vml::ShapeBase& rShape,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+
+    /** Updates the bounding box covering all shapes of this drawing. */
+    virtual void        notifyXShapeInserted(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& rxShape,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect,
+                            const ::oox::vml::ShapeBase& rShape, bool bGroupChild );
+
+private:
+    /** Converts the passed VML textbox text color to an OLE color. */
+    sal_uInt32          convertControlTextColor( const ::rtl::OUString& rTextColor ) const;
+    /** Converts the passed VML textbox font to an ActiveX form control font. */
+    void                convertControlFontData(
+                            ::oox::ole::AxFontData& rAxFontData, sal_uInt32& rnOleTextColor,
+                            const ::oox::vml::TextFontModel& rFontModel ) const;
+    /** Converts the caption, the font settings, and the horizontal alignment
+        from the passed VML textbox to ActiveX form control settings. */
+    void                convertControlText(
+                            ::oox::ole::AxFontData& rAxFontData, sal_uInt32& rnOleTextColor, ::rtl::OUString& rCaption,
+                            const ::oox::vml::TextBox* pTextBox, sal_Int32 nTextHAlign ) const;
+    /** Converts the passed VML shape background formatting to ActiveX control formatting. */
+    void                convertControlBackground(
+                            ::oox::ole::AxMorphDataModelBase& rAxModel,
+                            const ::oox::vml::ShapeBase& rShape ) const;
+
+private:
+    ::oox::ole::ControlConverter maControlConv;
+    ::oox::vml::TextFontModel maListBoxFont;
+};
+
+// ============================================================================
+
+class VmlDrawingFragment : public ::oox::vml::DrawingFragment, public WorksheetHelper
+{
+public:
+    explicit            VmlDrawingFragment(
+                            const WorksheetHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual void        finalizeImport();
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/drawingmanager.hxx b/sc/source/filter/inc/drawingmanager.hxx
new file mode 100644
index 000000000000..a7580a3e12e6
--- /dev/null
+++ b/sc/source/filter/inc/drawingmanager.hxx
@@ -0,0 +1,491 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_DRAWINGMANAGER_HXX
+#define OOX_XLS_DRAWINGMANAGER_HXX
+
+#include "drawingbase.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace drawing { class XDrawPage; }
+    namespace drawing { class XShape; }
+    namespace drawing { class XShapes; }
+} } }
+
+namespace oox { namespace drawingml { class ShapePropertyMap; } }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+const sal_uInt16 BIFF_OBJ_INVALID_ID        = 0;
+
+// ============================================================================
+// Model structures for BIFF OBJ record data
+// ============================================================================
+
+/** This structure contains line formatting attributes from an OBJ record. */
+struct BiffObjLineModel
+{
+    sal_uInt8           mnColorIdx;         /// Index into color palette.
+    sal_uInt8           mnStyle;            /// Line dash style.
+    sal_uInt8           mnWidth;            /// Line width.
+    bool                mbAuto;             /// True = automatic line format.
+
+    explicit            BiffObjLineModel();
+};
+
+// ============================================================================
+
+/** This structure contains fill formatting attributes from an OBJ record. */
+struct BiffObjFillModel
+{
+    sal_uInt8           mnBackColorIdx;     /// Index to color palette for background color.
+    sal_uInt8           mnPattColorIdx;     /// Index to color palette for pattern foreground color.
+    sal_uInt8           mnPattern;          /// Fill pattern.
+    bool                mbAuto;             /// True = automatic fill format.
+
+    explicit            BiffObjFillModel();
+
+    /** Returns true, if the fill formatting is visible (automatic or explicit). */
+    bool                isFilled() const;
+};
+
+// ============================================================================
+// BIFF drawing objects
+// ============================================================================
+
+class BiffDrawingBase;
+class BiffDrawingObjectBase;
+typedef ::boost::shared_ptr< BiffDrawingObjectBase > BiffDrawingObjectRef;
+
+// ----------------------------------------------------------------------------
+
+class BiffDrawingObjectContainer
+{
+public:
+    explicit            BiffDrawingObjectContainer();
+
+    /** Returns true, if the object list is empty. */
+    inline bool         empty() const { return maObjects.empty(); }
+
+    /** Appends the passed object to the list of objects. */
+    void                append( const BiffDrawingObjectRef& rxDrawingObj );
+    /** Tries to insert the passed object into the last group or appends it. */
+    void                insertGrouped( const BiffDrawingObjectRef& rxDrawingObj );
+
+    /** Creates and inserts all UNO shapes into the passed shape container. */
+    void                convertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle* pParentRect = 0 ) const;
+
+private:
+    typedef RefVector< BiffDrawingObjectBase > BiffDrawingObjectVector;
+    BiffDrawingObjectVector maObjects;
+};
+
+// ============================================================================
+
+/** Base class for all BIFF drawing objects (OBJ records). */
+class BiffDrawingObjectBase : public WorksheetHelper
+{
+public:
+    explicit            BiffDrawingObjectBase( const WorksheetHelper& rHelper );
+    virtual             ~BiffDrawingObjectBase();
+
+    /** Reads the BIFF3 OBJ record, returns a new drawing object. */
+    static BiffDrawingObjectRef importObjBiff3( const WorksheetHelper& rHelper, BiffInputStream& rStrm );
+    /** Reads the BIFF4 OBJ record, returns a new drawing object. */
+    static BiffDrawingObjectRef importObjBiff4( const WorksheetHelper& rHelper, BiffInputStream& rStrm );
+    /** Reads the BIFF5 OBJ record, returns a new drawing object. */
+    static BiffDrawingObjectRef importObjBiff5( const WorksheetHelper& rHelper, BiffInputStream& rStrm );
+    /** Reads the BIFF8 OBJ record, returns a new drawing object. */
+    static BiffDrawingObjectRef importObjBiff8( const WorksheetHelper& rHelper, BiffInputStream& rStrm );
+
+    /** Sets whether this is an area object (then its width and height must be greater than 0). */
+    inline void         setAreaObj( bool bAreaObj ) { mbAreaObj = bAreaObj; }
+    /** If set to true, the object supports a simple on-click macro and/or hyperlink. */
+    inline void         setSimpleMacro( bool bMacro ) { mbSimpleMacro = bMacro; }
+
+    /** If set to false, the UNO shape will not be created, processed, or inserted into the draw page. */
+    inline void         setProcessShape( bool bProcess ) { mbProcessShape = bProcess; }
+    /** If set to false, the UNO shape will be created or processed, but not be inserted into the draw page. */
+    inline void         setInsertShape( bool bInsert ) { mbInsertShape = bInsert; }
+    /** If set to true, a new custom UNO shape will be created while in DFF import (BIFF8 only). */
+    inline void         setCustomDffObj( bool bCustom ) { mbCustomDff = bCustom; }
+
+    /** Returns the object identifier from the OBJ record. */
+    inline sal_uInt16   getObjId() const { return mnObjId; }
+    /** Returns the object type from the OBJ record. */
+    inline sal_uInt16   getObjType() const { return mnObjType; }
+
+    /** Returns true, if the object is hidden. */
+    inline bool         isHidden() const { return mbHidden; }
+    /** Returns true, if the object is visible. */
+    inline bool         isVisible() const { return mbVisible; }
+    /** Returns true, if the object is printable. */
+    inline bool         isPrintable() const { return mbPrintable; }
+
+    /** Creates the UNO shape and inserts it into the passed shape container. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        convertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle* pParentRect = 0 ) const;
+
+protected:
+    /** Reads the object name in a BIFF5 OBJ record. */
+    void                readNameBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen );
+    /** Reads the macro link in a BIFF3 OBJ record. */
+    void                readMacroBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the macro link in a BIFF4 OBJ record. */
+    void                readMacroBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the macro link in a BIFF5 OBJ record. */
+    void                readMacroBiff5( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the ftMacro sub structure in an OBJ record. */
+    void                readMacroBiff8( BiffInputStream& rStrm );
+
+    /** Converts the passed line formatting to the passed property map. */
+    void                convertLineProperties( ::oox::drawingml::ShapePropertyMap& rPropMap, const BiffObjLineModel& rLineModel, sal_uInt16 nArrows = 0 ) const;
+    /** Converts the passed fill formatting to the passed property map. */
+    void                convertFillProperties( ::oox::drawingml::ShapePropertyMap& rPropMap, const BiffObjFillModel& rFillModel ) const;
+    /** Converts the passed frame flags to the passed property map. */
+    void                convertFrameProperties( ::oox::drawingml::ShapePropertyMap& rPropMap, sal_uInt16 nFrameFlags ) const;
+
+    /** Derived classes read the contents of the a BIFF3 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Derived classes read the contents of the a BIFF4 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Derived classes read the contents of the a BIFF5 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize );
+    /** Derived classes read the contents of the specified subrecord of a BIFF8 OBJ record from stream. */
+    virtual void        implReadObjBiff8SubRec( BiffInputStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize );
+
+    /** Derived classes create the corresponding XShape and insert it into the passed container. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        implConvertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const = 0;
+
+private:
+    /** Reads the contents of a BIFF3 OBJ record. */
+    void                importObjBiff3( BiffInputStream& rStrm );
+    /** Reads the contents of a BIFF4 OBJ record. */
+    void                importObjBiff4( BiffInputStream& rStrm );
+    /** Reads the contents of a BIFF5 OBJ record. */
+    void                importObjBiff5( BiffInputStream& rStrm );
+    /** Reads the contents of a BIFF8 OBJ record. */
+    void                importObjBiff8( BiffInputStream& rStrm );
+
+private:
+    ShapeAnchor         maAnchor;       /// Position of the drawing object.
+    ::rtl::OUString     maObjName;      /// Name of the object.
+    ::rtl::OUString     maMacroName;    /// Name of an attached macro.
+    ::rtl::OUString     maHyperlink;    /// On-click hyperlink URL.
+    sal_uInt32          mnDffShapeId;   /// Shape identifier from DFF stream (BIFF8 only).
+    sal_uInt32          mnDffFlags;     /// Shape flags from DFF stream.
+    sal_uInt16          mnObjId;        /// The object identifier (unique per drawing).
+    sal_uInt16          mnObjType;      /// The object type from OBJ record.
+    bool                mbHasAnchor;    /// True = anchor has been initialized.
+    bool                mbHidden;       /// True = object is hidden.
+    bool                mbVisible;      /// True = object is visible (form controls).
+    bool                mbPrintable;    /// True = object is printable.
+    bool                mbAreaObj;      /// True = width and height must be greater than 0.
+    bool                mbAutoMargin;   /// True = set automatic text margin.
+    bool                mbSimpleMacro;  /// True = create simple macro link and hyperlink.
+    bool                mbProcessShape; /// True = object is valid, do processing and insertion.
+    bool                mbInsertShape;  /// True = insert the UNO shape into the draw page.
+    bool                mbCustomDff;    /// True = recreate UNO shape in DFF import (BIFF8 only).
+};
+
+// ============================================================================
+
+/** A placeholder object for unknown/unsupported object types. */
+class BiffPlaceholderObject : public BiffDrawingObjectBase
+{
+public:
+    explicit            BiffPlaceholderObject( const WorksheetHelper& rHelper );
+
+protected:
+    /** Creates the corresponding XShape and insert it into the passed container. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        implConvertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+};
+
+// ============================================================================
+
+/** A group object that is able to contain other child objects. */
+class BiffGroupObject : public BiffDrawingObjectBase
+{
+public:
+    explicit            BiffGroupObject( const WorksheetHelper& rHelper );
+
+    /** Tries to insert the passed drawing object into this or a nested group. */
+    bool                tryInsert( const BiffDrawingObjectRef& rxDrawingObj );
+
+protected:
+    /** Reads the contents of the a BIFF3 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF4 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF5 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize );
+
+    /** Creates the corresponding XShape and insert it into the passed container. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        implConvertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+
+protected:
+    BiffDrawingObjectContainer maChildren;     /// All child objects contained in this group object.
+    sal_uInt16          mnFirstUngrouped;   /// Object identfier of first object not grouped into this group.
+};
+
+// ============================================================================
+
+/** A simple line object. */
+class BiffLineObject : public BiffDrawingObjectBase
+{
+public:
+    explicit            BiffLineObject( const WorksheetHelper& rHelper );
+
+protected:
+    /** Reads the contents of the a BIFF3 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF4 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF5 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize );
+
+    /** Creates the corresponding XShape and insert it into the passed container. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        implConvertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+
+protected:
+    BiffObjLineModel    maLineModel;    /// Line formatting.
+    sal_uInt16          mnArrows;       /// Line arrows.
+    sal_uInt8           mnStartPoint;   /// Starting point.
+};
+
+// ============================================================================
+
+/** A simple rectangle object (used as base class for oval objects). */
+class BiffRectObject : public BiffDrawingObjectBase
+{
+public:
+    explicit            BiffRectObject( const WorksheetHelper& rHelper );
+
+protected:
+    /** Reads the fill model, the line model, and frame flags. */
+    void                readFrameData( BiffInputStream& rStrm );
+
+    /** Converts fill formatting, line formatting, and frame style. */
+    void                convertRectProperties( ::oox::drawingml::ShapePropertyMap& rPropMap ) const;
+
+    /** Reads the contents of the a BIFF3 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF4 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF5 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize );
+
+    /** Creates the corresponding XShape and insert it into the passed container. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        implConvertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+
+protected:
+    BiffObjFillModel    maFillModel;    /// Fill formatting.
+    BiffObjLineModel    maLineModel;    /// Line formatting.
+    sal_uInt16          mnFrameFlags;   /// Additional flags.
+};
+
+// ============================================================================
+
+/** A simple oval object. */
+class BiffOvalObject : public BiffRectObject
+{
+public:
+    explicit            BiffOvalObject( const WorksheetHelper& rHelper );
+
+protected:
+    /** Creates the corresponding XShape and insert it into the passed container. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        implConvertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+};
+
+// ============================================================================
+
+/** A simple arc object. */
+class BiffArcObject : public BiffDrawingObjectBase
+{
+public:
+    explicit            BiffArcObject( const WorksheetHelper& rHelper );
+
+protected:
+    /** Reads the contents of the a BIFF3 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF4 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF5 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize );
+
+    /** Creates the corresponding XShape and insert it into the passed container. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        implConvertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+
+protected:
+    BiffObjFillModel    maFillModel;    /// Fill formatting.
+    BiffObjLineModel    maLineModel;    /// Line formatting.
+    sal_uInt8           mnQuadrant;     /// Visible quadrant of the circle.
+};
+
+// ============================================================================
+
+/** A simple polygon object. */
+class BiffPolygonObject : public BiffRectObject
+{
+public:
+    explicit            BiffPolygonObject( const WorksheetHelper& rHelper );
+
+protected:
+    /** Reads the contents of the a BIFF4 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize );
+    /** Reads the contents of the a BIFF5 OBJ record from the passed stream. */
+    virtual void        implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize );
+
+    /** Creates the corresponding XShape and insert it into the passed container. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        implConvertAndInsert( BiffDrawingBase& rDrawing,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+
+private:
+    /** Reads the COORDLIST record following the OBJ record. */
+    void                importCoordList( BiffInputStream& rStrm );
+
+protected:
+    typedef ::std::vector< ::com::sun::star::awt::Point > PointVector;
+    PointVector         maCoords;       /// Coordinates relative to bounding rectangle.
+    sal_uInt16          mnPolyFlags;    /// Additional flags.
+    sal_uInt16          mnPointCount;   /// Polygon point count.
+};
+
+// ============================================================================
+// BIFF drawing page
+// ============================================================================
+
+/** Base class for a container for all objects on a drawing page (in a
+    spreadsheet or in an embedded chart object).
+
+    For BIFF import, it is needed to load all drawing objects before converting
+    them to UNO shapes. There might be some dummy drawing objects (e.g. the
+    dropdown buttons of autofilters) which have to be skipped. The information,
+    that a drawing object is a dummy object, may be located after the drawing
+    objects themselves.
+
+    The BIFF8 format stores drawing objects in the DFF stream (stored
+    fragmented in MSODRAWING records), and in the OBJ records. The DFF stream
+    fragments are collected in a single stream, and the complete stream will be
+    processed afterwards.
+ */
+class BiffDrawingBase : public WorksheetHelper
+{
+public:
+    explicit            BiffDrawingBase( const WorksheetHelper& rHelper,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& rxDrawPage );
+
+    /** Imports a plain OBJ record (without leading DFF data). */
+    void                importObj( BiffInputStream& rStrm );
+    /** Sets the object with the passed identifier to be skipped on import. */
+    void                setSkipObj( sal_uInt16 nObjId );
+
+    /** Final processing after import of the all drawing objects. */
+    void                finalizeImport();
+
+    /** Creates a new UNO shape object, inserts it into the passed UNO shape
+        container, and sets the shape position and size. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+                        createAndInsertXShape(
+                            const ::rtl::OUString& rService,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) const;
+
+    /** Derived classes may want to know that a shape has been inserted. Will
+        be called from the convertAndInsert() implementation. */
+    virtual void        notifyShapeInserted(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& rxShape,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect ) = 0;
+
+protected:
+    /** Appends a new drawing object to the list of raw objects (without DFF data). */
+    void                appendRawObject( const BiffDrawingObjectRef& rxDrawingObj );
+
+private:
+    typedef RefMap< sal_uInt16, BiffDrawingObjectBase > BiffDrawingObjectMapById;
+    typedef ::std::vector< sal_uInt16 >                 BiffObjIdVector;
+
+    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >
+                        mxDrawPage;         /// UNO draw page used to insert the shapes.
+    BiffDrawingObjectContainer maRawObjs;   /// Drawing objects without DFF data.
+    BiffDrawingObjectMapById maObjMapId;    /// Maps drawing objects by their object identifiers.
+    BiffObjIdVector     maSkipObjs;         /// Identifiers of all objects to be skipped.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Drawing manager of a single sheet. */
+class BiffSheetDrawing : public BiffDrawingBase
+{
+public:
+    explicit            BiffSheetDrawing( const WorksheetHelper& rHelper );
+
+    /** Called when a new UNO shape has been inserted into the draw page. */
+    virtual void        notifyShapeInserted(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& rxShape,
+                            const ::com::sun::star::awt::Rectangle& rShapeRect );
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/excelchartconverter.hxx b/sc/source/filter/inc/excelchartconverter.hxx
new file mode 100644
index 000000000000..0bc0539ed40c
--- /dev/null
+++ b/sc/source/filter/inc/excelchartconverter.hxx
@@ -0,0 +1,64 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_EXCELCHARTCONVERTER_HXX
+#define OOX_XLS_EXCELCHARTCONVERTER_HXX
+
+#include "oox/drawingml/chart/chartconverter.hxx"
+#include "workbookhelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+class ExcelChartConverter : public ::oox::drawingml::chart::ChartConverter, public WorkbookHelper
+{
+public:
+    explicit            ExcelChartConverter( const WorkbookHelper& rHelper );
+    virtual             ~ExcelChartConverter();
+
+    /** Creates an external data provider that is able to use spreadsheet data. */
+    virtual void        createDataProvider(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XChartDocument >& rxChartDoc );
+
+    /** Creates a data sequence from the passed formula. */
+    virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSequence >
+                        createDataSequence(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataProvider >& rxDataProvider,
+                            const ::oox::drawingml::chart::DataSequenceModel& rDataSeq );
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/excelfilter.hxx b/sc/source/filter/inc/excelfilter.hxx
new file mode 100644
index 000000000000..c15b6cc542cf
--- /dev/null
+++ b/sc/source/filter/inc/excelfilter.hxx
@@ -0,0 +1,125 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_EXCELFILTER_HXX
+#define OOX_XLS_EXCELFILTER_HXX
+
+#include "oox/core/binaryfilterbase.hxx"
+#include "oox/core/xmlfilterbase.hxx"
+#include "oox/ole/vbaprojectfilter.hxx"
+
+namespace oox {
+namespace xls {
+
+class WorkbookGlobals;
+
+// ============================================================================
+
+class ExcelFilterBase
+{
+public:
+    void                registerWorkbookGlobals( WorkbookGlobals& rBookGlob );
+    WorkbookGlobals&    getWorkbookGlobals() const;
+    void                unregisterWorkbookGlobals();
+
+protected:
+    explicit            ExcelFilterBase();
+    virtual             ~ExcelFilterBase();
+
+private:
+    WorkbookGlobals*    mpBookGlob;
+};
+
+// ============================================================================
+
+class ExcelFilter : public ::oox::core::XmlFilterBase, public ExcelFilterBase
+{
+public:
+    explicit            ExcelFilter(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext )
+                            throw( ::com::sun::star::uno::RuntimeException );
+    virtual             ~ExcelFilter();
+
+    virtual bool        importDocument() throw();
+    virtual bool        exportDocument() throw();
+
+    virtual const ::oox::drawingml::Theme* getCurrentTheme() const;
+    virtual ::oox::vml::Drawing* getVmlDrawing();
+    virtual const ::oox::drawingml::table::TableStyleListPtr getTableStyles();
+    virtual ::oox::drawingml::chart::ChartConverter* getChartConverter();
+
+    virtual sal_Bool SAL_CALL filter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rDescriptor ) throw( ::com::sun::star::uno::RuntimeException );
+
+private:
+    virtual GraphicHelper* implCreateGraphicHelper() const;
+    virtual ::oox::ole::VbaProject* implCreateVbaProject() const;
+    virtual ::rtl::OUString implGetImplementationName() const;
+};
+
+// ============================================================================
+
+class ExcelBiffFilter : public ::oox::core::BinaryFilterBase, public ExcelFilterBase
+{
+public:
+    explicit            ExcelBiffFilter(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext )
+                            throw( ::com::sun::star::uno::RuntimeException );
+    virtual             ~ExcelBiffFilter();
+
+    virtual bool        importDocument() throw();
+    virtual bool        exportDocument() throw();
+
+private:
+    virtual GraphicHelper* implCreateGraphicHelper() const;
+    virtual ::oox::ole::VbaProject* implCreateVbaProject() const;
+    virtual ::rtl::OUString implGetImplementationName() const;
+};
+
+// ============================================================================
+
+class ExcelVbaProjectFilter : public ExcelBiffFilter
+{
+public:
+    explicit            ExcelVbaProjectFilter(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext )
+                            throw( ::com::sun::star::uno::RuntimeException );
+
+    virtual bool        importDocument() throw();
+    virtual bool        exportDocument() throw();
+
+private:
+    virtual ::rtl::OUString implGetImplementationName() const;
+};
+ // ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/excelhandlers.hxx b/sc/source/filter/inc/excelhandlers.hxx
new file mode 100644
index 000000000000..46cc1c217f60
--- /dev/null
+++ b/sc/source/filter/inc/excelhandlers.hxx
@@ -0,0 +1,252 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_EXCELHANDLERS_HXX
+#define OOX_XLS_EXCELHANDLERS_HXX
+
+#include "oox/core/fragmenthandler2.hxx"
+#include "worksheethelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+// ============================================================================
+
+/** Context handler derived from the WorkbookHelper helper class.
+
+    Used to import contexts in global workbook fragments.
+ */
+class WorkbookContextBase : public ::oox::core::ContextHandler2, public WorkbookHelper
+{
+public:
+    template< typename ParentType >
+    inline explicit     WorkbookContextBase( ParentType& rParent ) :
+                            ::oox::core::ContextHandler2( rParent ), WorkbookHelper( rParent ) {}
+};
+
+// ============================================================================
+
+/** Context handler derived from the WorksheetHelper helper class.
+
+    Used to import contexts in sheet fragments.
+ */
+class WorksheetContextBase : public ::oox::core::ContextHandler2, public WorksheetHelper
+{
+public:
+    template< typename ParentType >
+    inline explicit     WorksheetContextBase( ParentType& rParent ) :
+                            ::oox::core::ContextHandler2( rParent ), WorksheetHelper( rParent ) {}
+};
+
+// ============================================================================
+
+/** Fragment handler derived from the WorkbookHelper helper class.
+
+    Used to import global workbook fragments.
+ */
+class WorkbookFragmentBase : public ::oox::core::FragmentHandler2, public WorkbookHelper
+{
+public:
+    explicit            WorkbookFragmentBase(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+};
+
+// ============================================================================
+
+/** Fragment handler derived from the WorksheetHelper helper class.
+
+    Used to import sheet fragments.
+ */
+class WorksheetFragmentBase : public ::oox::core::FragmentHandler2, public WorksheetHelper
+{
+public:
+    explicit            WorksheetFragmentBase(
+                            const WorksheetHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+};
+
+// ============================================================================
+// ============================================================================
+
+/** Base class for all BIFF context handlers.
+
+    Derived handlers have to implement the importRecord() function that has to
+    import the record the passed BIFF input stream currently points to.
+ */
+class BiffContextHandler
+{
+public:
+    virtual             ~BiffContextHandler();
+
+    /** Derived classes have to implement importing the current record. */
+    virtual void        importRecord( BiffInputStream& rStrm ) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+/** Context handler derived from the WorkbookHelper helper class.
+
+    Used to import contexts in global workbook fragments.
+ */
+class BiffWorkbookContextBase : public BiffContextHandler, public WorkbookHelper
+{
+protected:
+    explicit            BiffWorkbookContextBase( const WorkbookHelper& rHelper );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Context handler derived from the WorksheetHelper helper class.
+
+    Used to import contexts in sheet fragments.
+ */
+class BiffWorksheetContextBase : public BiffContextHandler, public WorksheetHelper
+{
+protected:
+    explicit            BiffWorksheetContextBase( const WorksheetHelper& rHelper );
+};
+
+// ============================================================================
+
+/** An enumeration for all types of fragments in a BIFF workbook stream. */
+enum BiffFragmentType
+{
+    BIFF_FRAGMENT_GLOBALS,      /// Workbook globals fragment.
+    BIFF_FRAGMENT_WORKSHEET,    /// Worksheet fragment.
+    BIFF_FRAGMENT_CHARTSHEET,   /// Chart sheet fragment.
+    BIFF_FRAGMENT_MACROSHEET,   /// Macro sheet fragment.
+    BIFF_FRAGMENT_MODULESHEET,  /// BIFF5 VB module fragment.
+    BIFF_FRAGMENT_EMPTYSHEET,   /// Sheet fragment of unsupported type.
+    BIFF_FRAGMENT_WORKSPACE,    /// BIFF4 workspace/workbook globals.
+    BIFF_FRAGMENT_UNKNOWN       /// Unknown fragment/error.
+};
+
+// ----------------------------------------------------------------------------
+
+class BiffFragmentHandler
+{
+public:
+    /** Opens the stream with the passed full name. */
+    explicit            BiffFragmentHandler(
+                            const ::oox::core::FilterBase& rFilter,
+                            const ::rtl::OUString& rStrmName );
+
+    virtual             ~BiffFragmentHandler();
+
+    /** Imports the fragment, returns true, if EOF record has been reached. */
+    virtual bool        importFragment() = 0;
+
+protected:
+    /** Returns the BIFF input stream of this fragment. */
+    inline BiffInputStream& getInputStream() { return *mxBiffStrm; }
+
+    /** Starts a new fragment in a workbbok stream and returns the fragment type.
+
+        The passed stream must point before a BOF record. The function will
+        try to start the next record and read the contents of the BOF record,
+        if extant.
+
+        @return  Fragment type according to the imported BOF record.
+     */
+    BiffFragmentType    startFragment( BiffType eBiff );
+
+    /** Skips the current fragment up to its trailing EOF record.
+
+        Skips all records until next EOF record. When this function returns,
+        stream points to the EOF record, and the next call of startNextRecord()
+        at the stream will start the record following the EOF record.
+
+        Embedded fragments enclosed in BOF/EOF records (e.g. embedded chart
+        objects) are skipped correctly.
+
+        @return  True = stream points to the EOF record of the current fragment.
+     */
+    bool                skipFragment();
+
+private:
+    typedef ::boost::shared_ptr< BinaryXInputStream >   XInputStreamRef;
+    typedef ::boost::shared_ptr< BiffInputStream >      BiffInputStreamRef;
+
+    XInputStreamRef     mxXInStrm;
+    BiffInputStreamRef  mxBiffStrm;
+};
+
+// ----------------------------------------------------------------------------
+
+/** Fragment handler derived from the WorkbookHelper helper class.
+
+    Used to import global workbook fragments.
+ */
+class BiffWorkbookFragmentBase : public BiffFragmentHandler, public WorkbookHelper
+{
+protected:
+    explicit            BiffWorkbookFragmentBase(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rStrmName,
+                            bool bCloneDecoder = false );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Fragment handler derived from the WorksheetHelper helper class.
+
+    Used to import sheet fragments.
+ */
+class BiffWorksheetFragmentBase : public BiffFragmentHandler, public WorksheetHelper
+{
+protected:
+    explicit            BiffWorksheetFragmentBase(
+                            const WorksheetHelper& rHelper,
+                            const BiffWorkbookFragmentBase& rParent );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Special fragment handler for worksheets that have to be skipped.
+ */
+class BiffSkipWorksheetFragment : public BiffWorksheetFragmentBase
+{
+public:
+    explicit            BiffSkipWorksheetFragment(
+                            const WorksheetHelper& rHelper,
+                            const BiffWorkbookFragmentBase& rParent );
+
+    virtual bool        importFragment();
+};
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/excelvbaproject.hxx b/sc/source/filter/inc/excelvbaproject.hxx
new file mode 100644
index 000000000000..fbc5badd7cdc
--- /dev/null
+++ b/sc/source/filter/inc/excelvbaproject.hxx
@@ -0,0 +1,67 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_EXCELVBAPROJECT_HXX
+#define OOX_XLS_EXCELVBAPROJECT_HXX
+
+#include "oox/ole/vbaproject.hxx"
+
+namespace com { namespace sun { namespace star {
+        namespace sheet { class XSpreadsheetDocument; }
+} } }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Special implementation of the VBA project for the Excel filters. */
+class ExcelVbaProject : public ::oox::ole::VbaProject
+{
+public:
+    explicit            ExcelVbaProject(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheetDocument >& rxDocument );
+
+protected:
+    /** Adds dummy modules for sheets without imported code name. */
+    virtual void        prepareImport();
+
+private:
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheetDocument >
+                        mxDocument;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/externallinkbuffer.hxx b/sc/source/filter/inc/externallinkbuffer.hxx
new file mode 100644
index 000000000000..f7f37fe8f2ec
--- /dev/null
+++ b/sc/source/filter/inc/externallinkbuffer.hxx
@@ -0,0 +1,405 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_EXTERNALLINKBUFFER_HXX
+#define OOX_XLS_EXTERNALLINKBUFFER_HXX
+
+#include 
+#include "oox/helper/containerhelper.hxx"
+#include "defnamesbuffer.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace sheet { struct DDEItemInfo; }
+    namespace sheet { class XDDELink; }
+    namespace sheet { class XExternalDocLink; }
+    namespace sheet { class XExternalSheetCache; }
+} } }
+
+namespace oox { namespace core {
+    class Relations;
+} }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+struct ExternalNameModel
+{
+    bool                mbBuiltIn;          /// Name is a built-in name.
+    bool                mbNotify;           /// Notify application on data change.
+    bool                mbPreferPic;        /// Picture link.
+    bool                mbStdDocName;       /// Name is the StdDocumentName for DDE.
+    bool                mbOleObj;           /// Name is an OLE object.
+    bool                mbIconified;        /// Iconified object link.
+
+    explicit            ExternalNameModel();
+};
+
+// ============================================================================
+
+class ExternalLink;
+
+class ExternalName : public DefinedNameBase
+{
+public:
+    explicit            ExternalName( const ExternalLink& rParentLink );
+
+    /** Appends the passed value to the result set. */
+    template< typename Type >
+    inline void         appendResultValue( const Type& rValue )
+                            { if( maCurrIt != maResults.end() ) (*maCurrIt++) <<= rValue; }
+
+    /** Imports the definedName element. */
+    void                importDefinedName( const AttributeList& rAttribs );
+    /** Imports the ddeItem element describing an item of a DDE link. */
+    void                importDdeItem( const AttributeList& rAttribs );
+    /** Imports the values element containing the size of the DDE result matrix. */
+    void                importValues( const AttributeList& rAttribs );
+    /** Imports the oleItem element describing an object of an OLE link. */
+    void                importOleItem( const AttributeList& rAttribs );
+
+    /** Imports the EXTERNALNAME record containing the name (only). */
+    void                importExternalName( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALNAMEFLAGS record containing the settings of an external name. */
+    void                importExternalNameFlags( SequenceInputStream& rStrm );
+    /** Imports the DDEITEMVALUES record containing the size of the DDE result matrix. */
+    void                importDdeItemValues( SequenceInputStream& rStrm );
+    /** Imports the DDEITEM_BOOL record containing a boolean value in a link result. */
+    void                importDdeItemBool( SequenceInputStream& rStrm );
+    /** Imports the DDEITEM_DOUBLE record containing a double value in a link result. */
+    void                importDdeItemDouble( SequenceInputStream& rStrm );
+    /** Imports the DDEITEM_ERROR record containing an error code in a link result. */
+    void                importDdeItemError( SequenceInputStream& rStrm );
+    /** Imports the DDEITEM_STRING record containing a string in a link result. */
+    void                importDdeItemString( SequenceInputStream& rStrm );
+
+    /** Imports the EXTERNALNAME record from the passed stream. */
+    void                importExternalName( BiffInputStream& rStrm );
+
+    /** Returns true, if the name refers to an OLE object. */
+    inline bool         isOleObject() const { return maExtNameModel.mbOleObj; }
+
+#if 0
+    /** Returns the sheet cache index if this is a sheet-local external name. */
+    sal_Int32           getSheetCacheIndex() const;
+#endif
+
+    /** Returns the DDE item info needed by the XML formula parser. */
+    bool                getDdeItemInfo(
+                            ::com::sun::star::sheet::DDEItemInfo& orItemInfo ) const;
+
+    /** Returns the complete DDE link data of this DDE item. */
+    bool                getDdeLinkData(
+                            ::rtl::OUString& orDdeServer,
+                            ::rtl::OUString& orDdeTopic,
+                            ::rtl::OUString& orDdeItem );
+
+private:
+    /** Tries to convert the passed token sequence to an ExternalReference. */
+    void                extractExternalReference( const ApiTokenSequence& rTokens );
+    /** Sets the size of the result matrix. */
+    void                setResultSize( sal_Int32 nColumns, sal_Int32 nRows );
+
+private:
+    typedef Matrix< ::com::sun::star::uno::Any > ResultMatrix;
+
+    const ExternalLink& mrParentLink;       /// External link this name belongs to.
+    ExternalNameModel   maExtNameModel;     /// Additional name data.
+    ResultMatrix        maResults;          /// DDE/OLE link results.
+    ResultMatrix::iterator maCurrIt;        /// Current position in result matrix.
+    sal_uInt32          mnStorageId;        /// OLE storage identifier (BIFF).
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDDELink >
+                        mxDdeLink;          /// Interface of a DDE link.
+    bool                mbDdeLinkCreated;   /// True = already tried to create the DDE link.
+};
+
+typedef ::boost::shared_ptr< ExternalName > ExternalNameRef;
+
+// ============================================================================
+
+/** Contains indexes for a range of sheets in the spreadsheet document. */
+class LinkSheetRange
+{
+public:
+    inline explicit     LinkSheetRange() { setDeleted(); }
+    inline explicit     LinkSheetRange( sal_Int32 nFirst, sal_Int32 nLast ) { setRange( nFirst, nLast ); }
+    inline explicit     LinkSheetRange( sal_Int32 nDocLink, sal_Int32 nFirst, sal_Int32 nLast ) { setExternalRange( nDocLink, nFirst, nLast ); }
+
+    /** Sets this struct to deleted state. */
+    void                setDeleted();
+    /** Sets this struct to "use current sheet" state. */
+    void                setSameSheet();
+    /** Sets the passed absolute sheet range to the members of this struct. */
+    void                setRange( sal_Int32 nFirst, sal_Int32 nLast );
+    /** Sets the passed external sheet cache range to the members of this struct. */
+    void                setExternalRange( sal_Int32 nDocLink, sal_Int32 nFirst, sal_Int32 nLast );
+
+    /** Returns true, if the sheet indexes are valid and different. */
+    inline bool         isDeleted() const { return mnFirst < 0; }
+    /** Returns true, if the sheet range points to an external document. */
+    inline bool         isExternal() const { return !isDeleted() && (meType == LINKSHEETRANGE_EXTERNAL); }
+    /** Returns true, if the sheet indexes are valid and different. */
+    inline bool         isSameSheet() const { return meType == LINKSHEETRANGE_SAMESHEET; }
+    /** Returns true, if the sheet indexes are valid and different. */
+    inline bool         is3dRange() const { return (0 <= mnFirst) && (mnFirst < mnLast); }
+
+    inline sal_Int32    getDocLinkIndex() const { return mnDocLink; }
+    inline sal_Int32    getFirstSheet() const { return mnFirst; }
+    inline sal_Int32    getLastSheet() const { return mnLast; }
+
+private:
+    enum LinkSheetRangeType
+    {
+        LINKSHEETRANGE_INTERNAL,    /// Sheet range in the own document.
+        LINKSHEETRANGE_EXTERNAL,    /// Sheet range in an external document.
+        LINKSHEETRANGE_SAMESHEET    /// Current sheet depending on context.
+    };
+
+    LinkSheetRangeType  meType;         /// Link sheet range type.
+    sal_Int32           mnDocLink;      /// Document link token index for external links.
+    sal_Int32           mnFirst;        /// Index of the first sheet or index of first external sheet cache.
+    sal_Int32           mnLast;         /// Index of the last sheet or index of last external sheet cache.
+};
+
+// ============================================================================
+
+enum ExternalLinkType
+{
+    LINKTYPE_SELF,          /// Link refers to the current workbook.
+    LINKTYPE_SAME,          /// Link refers to the current sheet.
+    LINKTYPE_INTERNAL,      /// Link refers to a sheet in the own workbook.
+    LINKTYPE_EXTERNAL,      /// Link refers to an external spreadsheet document.
+    LINKTYPE_ANALYSIS,      /// Link refers to the Analysis add-in.
+    LINKTYPE_LIBRARY,       /// Link refers to an external add-in.
+    LINKTYPE_DDE,           /// DDE link.
+    LINKTYPE_OLE,           /// OLE link.
+    LINKTYPE_MAYBE_DDE_OLE, /// Could be DDE or OLE link (BIFF only).
+    LINKTYPE_UNKNOWN        /// Unknown or unsupported link type.
+};
+
+// ----------------------------------------------------------------------------
+
+class ExternalLink : public WorkbookHelper
+{
+public:
+    explicit            ExternalLink( const WorkbookHelper& rHelper );
+
+    /** Imports the externalReference element containing the relation identifier. */
+    void                importExternalReference( const AttributeList& rAttribs );
+    /** Imports the externalBook element describing an externally linked document. */
+    void                importExternalBook( const ::oox::core::Relations& rRelations, const AttributeList& rAttribs );
+    /** Imports the sheetName element containing the sheet name in an externally linked document. */
+    void                importSheetName( const AttributeList& rAttribs );
+    /** Imports the definedName element describing an external name. */
+    void                importDefinedName( const AttributeList& rAttribs );
+    /** Imports the ddeLink element describing a DDE link. */
+    void                importDdeLink( const AttributeList& rAttribs );
+    /** Imports the ddeItem element describing an item of a DDE link. */
+    ExternalNameRef     importDdeItem( const AttributeList& rAttribs );
+    /** Imports the oleLink element describing an OLE link. */
+    void                importOleLink( const ::oox::core::Relations& rRelations, const AttributeList& rAttribs );
+    /** Imports the oleItem element describing an object of an OLE link. */
+    ExternalNameRef     importOleItem( const AttributeList& rAttribs );
+
+    /** Imports the EXTERNALBOOK record describing an externally linked document, DDE link, or OLE link. */
+    void                importExternalBook( const ::oox::core::Relations& rRelations, SequenceInputStream& rStrm );
+    /** Imports the EXTSHEETNAMES record containing the sheet names in an externally linked document. */
+    void                importExtSheetNames( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALNAME record describing an external name. */
+    ExternalNameRef     importExternalName( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALREF record from the passed stream. */
+    void                importExternalRef( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALSELF record from the passed stream. */
+    void                importExternalSelf( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALSAME record from the passed stream. */
+    void                importExternalSame( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALADDIN record from the passed stream. */
+    void                importExternalAddin( SequenceInputStream& rStrm );
+
+    /** Imports the EXTERNSHEET record from the passed stream. */
+    void                importExternSheet( BiffInputStream& rStrm );
+    /** Imports the EXTERNALBOOK record from the passed stream. */
+    void                importExternalBook( BiffInputStream& rStrm );
+    /** Imports the EXTERNALNAME record from the passed stream. */
+    void                importExternalName( BiffInputStream& rStrm );
+
+    /** Sets the link type to 'self reference'. */
+    inline void         setSelfLinkType() { meLinkType = LINKTYPE_SELF; }
+
+    /** Returns the type of this external link. */
+    inline ExternalLinkType getLinkType() const { return meLinkType; }
+    /** Returns true, if the link refers to the current workbook. */
+    inline bool         isInternalLink() const { return (meLinkType == LINKTYPE_SELF) || (meLinkType == LINKTYPE_INTERNAL); }
+
+    /** Returns the relation identifier for the external link fragment. */
+    inline const ::rtl::OUString& getRelId() const { return maRelId; }
+    /** Returns the class name of this external link. */
+    inline const ::rtl::OUString& getClassName() const { return maClassName; }
+    /** Returns the target URL of this external link. */
+    inline const ::rtl::OUString& getTargetUrl() const { return maTargetUrl; }
+    /** Returns the link info needed by the XML formula parser. */
+    ::com::sun::star::sheet::ExternalLinkInfo getLinkInfo() const;
+
+    /** Returns the type of the external library if this is a library link. */
+    FunctionLibraryType getFuncLibraryType() const;
+
+    /** Returns the internal Calc sheet index or for the passed sheet. */
+    sal_Int16           getCalcSheetIndex( sal_Int32 nTabId = 0 ) const;
+
+    /** Returns the token index of the external document. */
+    sal_Int32           getDocumentLinkIndex() const;
+    /** Returns the external sheet cache index or for the passed sheet. */
+    sal_Int32           getSheetCacheIndex( sal_Int32 nTabId = 0 ) const;
+    /** Returns the sheet cache of the external sheet with the passed index. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalSheetCache >
+                        getSheetCache( sal_Int32 nTabId ) const;
+
+    /** Returns the internal sheet range or range of external sheet caches for the passed sheet range (BIFF only). */
+    void                getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId1, sal_Int32 nTabId2 ) const;
+
+    /** Returns the external name with the passed zero-based index. */
+    ExternalNameRef     getNameByIndex( sal_Int32 nIndex ) const;
+
+private:
+    void                setExternalTargetUrl( const ::rtl::OUString& rTargetUrl, const ::rtl::OUString& rTargetType );
+    void                setDdeOleTargetUrl( const ::rtl::OUString& rClassName, const ::rtl::OUString& rTargetUrl, ExternalLinkType eLinkType );
+    void                parseExternalReference( const ::oox::core::Relations& rRelations, const ::rtl::OUString& rRelId );
+    ::rtl::OUString     parseBiffTargetUrl( const ::rtl::OUString& rBiffTargetUrl );
+
+    /** Creates an external locument link and the sheet cache for the passed sheet name. */
+    void                insertExternalSheet( const ::rtl::OUString& rSheetName );
+
+    ExternalNameRef     createExternalName();
+
+private:
+    typedef ::std::vector< sal_Int16 >  Int16Vector;
+    typedef ::std::vector< sal_Int32 >  Int32Vector;
+    typedef RefVector< ExternalName >   ExternalNameVector;
+
+    ExternalLinkType    meLinkType;         /// Type of this link object.
+    FunctionLibraryType meFuncLibType;      /// Type of the function library, if link type is LINKTYPE_LIBRARY.
+    ::rtl::OUString     maRelId;            /// Relation identifier for the external link fragment.
+    ::rtl::OUString     maClassName;        /// DDE service, OLE class name.
+    ::rtl::OUString     maTargetUrl;        /// Target link, DDE topic, OLE target.
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalDocLink >
+                        mxDocLink;          /// Interface for an external document.
+    Int16Vector         maCalcSheets;       /// Internal sheet indexes.
+    Int32Vector         maSheetCaches;      /// External sheet cache indexes.
+    ExternalNameVector  maExtNames;         /// Defined names in external document.
+};
+
+typedef ::boost::shared_ptr< ExternalLink > ExternalLinkRef;
+
+// ============================================================================
+
+/** Represents a REF entry in the BIFF12 EXTERNALSHEETS or in the BIFF8
+    EXTERNSHEET record.
+
+    This struct is used to map ref identifiers to external books (BIFF12:
+    EXTERNALREF records, BIFF8: EXTERNALBOOK records), and provides sheet
+    indexes into the sheet list of the external document.
+ */
+struct RefSheetsModel
+{
+    sal_Int32           mnExtRefId;         /// Zero-based index into list of external documents.
+    sal_Int32           mnTabId1;           /// Zero-based index to first sheet in external document.
+    sal_Int32           mnTabId2;           /// Zero-based index to last sheet in external document.
+
+    explicit            RefSheetsModel();
+
+    void                readBiff12Data( SequenceInputStream& rStrm );
+    void                readBiff8Data( BiffInputStream& rStrm );
+};
+
+// ----------------------------------------------------------------------------
+
+class ExternalLinkBuffer : public WorkbookHelper
+{
+public:
+    explicit            ExternalLinkBuffer( const WorkbookHelper& rHelper );
+
+    /** Imports the externalReference element containing . */
+    ExternalLinkRef     importExternalReference( const AttributeList& rAttribs );
+
+    /** Imports the EXTERNALREF record from the passed stream. */
+    ExternalLinkRef     importExternalRef( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALSELF record from the passed stream. */
+    void                importExternalSelf( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALSAME record from the passed stream. */
+    void                importExternalSame( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALADDIN record from the passed stream. */
+    void                importExternalAddin( SequenceInputStream& rStrm );
+    /** Imports the EXTERNALSHEETS record from the passed stream. */
+    void                importExternalSheets( SequenceInputStream& rStrm );
+
+    /** Imports the EXTERNSHEET record from the passed stream. */
+    ExternalLinkRef     importExternSheet( BiffInputStream& rStrm );
+    /** Imports the EXTERNALBOOK record from the passed stream. */
+    ExternalLinkRef     importExternalBook( BiffInputStream& rStrm );
+    /** Imports the BIFF8 EXTERNSHEET record from the passed stream. */
+    void                importExternSheet8( BiffInputStream& rStrm );
+
+    /** Returns the sequence of link infos needed by the XML formula parser. */
+    ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::ExternalLinkInfo >
+                        getLinkInfos() const;
+
+    /** Returns the external link for the passed reference identifier. */
+    ExternalLinkRef     getExternalLink( sal_Int32 nRefId, bool bUseRefSheets = true ) const;
+
+    /** Returns the sheet range for the specified reference (BIFF2-BIFF5 only). */
+    LinkSheetRange      getSheetRange( sal_Int32 nRefId, sal_Int16 nTabId1, sal_Int16 nTabId2 ) const;
+    /** Returns the sheet range for the specified reference (BIFF8 only). */
+    LinkSheetRange      getSheetRange( sal_Int32 nRefId ) const;
+
+private:
+    /** Creates a new external link and inserts it into the list of links. */
+    ExternalLinkRef     createExternalLink();
+
+    /** Returns the specified sheet indexes for a reference identifier. */
+    const RefSheetsModel* getRefSheets( sal_Int32 nRefId ) const;
+
+private:
+    typedef RefVector< ExternalLink >       ExternalLinkVec;
+    typedef ::std::vector< RefSheetsModel > RefSheetsModelVec;
+
+    ExternalLinkRef     mxSelfRef;          /// Implicit self reference at index 0.
+    ExternalLinkVec     maLinks;            /// List of link structures for all kinds of links.
+    ExternalLinkVec     maExtLinks;         /// Real external links needed for formula parser.
+    RefSheetsModelVec   maRefSheets;        /// Sheet indexes for reference ids.
+    bool                mbUseRefSheets;     /// True = use maRefSheets list (BIFF12 only).
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/externallinkfragment.hxx b/sc/source/filter/inc/externallinkfragment.hxx
new file mode 100644
index 000000000000..36b1d77296fb
--- /dev/null
+++ b/sc/source/filter/inc/externallinkfragment.hxx
@@ -0,0 +1,164 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_EXTERNALLINKFRAGMENT_HXX
+#define OOX_XLS_EXTERNALLINKFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+#include "externallinkbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+class ExternalLink;
+
+// ============================================================================
+// ============================================================================
+
+/** This class implements importing the sheetData element in external sheets.
+
+    The sheetData element embedded in the externalBook element contains cached
+    cells from externally linked sheets.
+ */
+class ExternalSheetDataContext : public WorkbookContextBase
+{
+public:
+    explicit            ExternalSheetDataContext(
+                            WorkbookFragmentBase& rFragment,
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalSheetCache >& rxSheetCache );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onCharacters( const ::rtl::OUString& rChars );
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+private:
+    /** Imports cell settings from a c element. */
+    void                importCell( const AttributeList& rAttribs );
+
+    /** Imports the EXTCELL_BLANK from the passed stream. */
+    void                importExtCellBlank( SequenceInputStream& rStrm );
+    /** Imports the EXTCELL_BOOL from the passed stream. */
+    void                importExtCellBool( SequenceInputStream& rStrm );
+    /** Imports the EXTCELL_DOUBLE from the passed stream. */
+    void                importExtCellDouble( SequenceInputStream& rStrm );
+    /** Imports the EXTCELL_ERROR from the passed stream. */
+    void                importExtCellError( SequenceInputStream& rStrm );
+    /** Imports the EXTCELL_STRING from the passed stream. */
+    void                importExtCellString( SequenceInputStream& rStrm );
+
+    /** Sets the passed cell value to the current position in the sheet cache. */
+    void                setCellValue( const ::com::sun::star::uno::Any& rValue );
+
+private:
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalSheetCache >
+                        mxSheetCache;               /// The sheet cache used to store external cell values.
+    ::com::sun::star::table::CellAddress maCurrPos; /// Position of current cell.
+    sal_Int32           mnCurrType;                 /// Data type of current cell.
+};
+
+// ============================================================================
+
+class ExternalLinkFragment : public WorkbookFragmentBase
+{
+public:
+    explicit            ExternalLinkFragment(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath,
+                            ExternalLink& rExtLink );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onCharacters( const ::rtl::OUString& rChars );
+    virtual void        onEndElement();
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+
+private:
+    ::oox::core::ContextHandlerRef createSheetDataContext( sal_Int32 nSheetId );
+
+private:
+    ExternalLink&       mrExtLink;
+    ExternalNameRef     mxExtName;
+    ::rtl::OUString     maResultValue;
+    sal_Int32           mnResultType;
+};
+
+// ============================================================================
+// ============================================================================
+
+class BiffExternalSheetDataContext : public BiffWorkbookContextBase
+{
+public:
+    explicit            BiffExternalSheetDataContext( const WorkbookHelper& rHelper, bool bImportDefNames );
+    virtual             ~BiffExternalSheetDataContext();
+
+    /** Tries to import a record related to external links and defined names. */
+    virtual void        importRecord( BiffInputStream& rStrm );
+
+private:
+    void                importExternSheet( BiffInputStream& rStrm );
+    void                importExternalBook( BiffInputStream& rStrm );
+    void                importExternalName( BiffInputStream& rStrm );
+    void                importXct( BiffInputStream& rStrm );
+    void                importCrn( BiffInputStream& rStrm );
+    void                importDefinedName( BiffInputStream& rStrm );
+
+    /** Sets the passed cell value to the passed position in the sheet cache. */
+    void                setCellValue( const BinAddress& rBinAddr, const ::com::sun::star::uno::Any& rValue );
+
+private:
+    ExternalLinkRef     mxExtLink;              /// Current external link.
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalSheetCache >
+                        mxSheetCache;           /// The sheet cache used to store external cell values.
+    bool                mbImportDefNames;
+};
+
+// ============================================================================
+
+class BiffExternalLinkFragment : public BiffWorkbookFragmentBase
+{
+public:
+    explicit            BiffExternalLinkFragment( const BiffWorkbookFragmentBase& rParent );
+
+    /** Imports all records related to external links. */
+    virtual bool        importFragment();
+};
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/formulabase.hxx b/sc/source/filter/inc/formulabase.hxx
new file mode 100644
index 000000000000..0199d178a62c
--- /dev/null
+++ b/sc/source/filter/inc/formulabase.hxx
@@ -0,0 +1,845 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_FORMULABASE_HXX
+#define OOX_XLS_FORMULABASE_HXX
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/propertyset.hxx"
+#include "oox/helper/refvector.hxx"
+#include "addressconverter.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace sheet { class XFormulaOpCodeMapper; }
+    namespace sheet { class XFormulaParser; }
+} } }
+
+namespace oox { template< typename Type > class Matrix; }
+
+namespace oox {
+namespace xls {
+
+// Constants ==================================================================
+
+const size_t BIFF_TOKARR_MAXLEN                 = 4096;     /// Maximum size of a token array.
+
+// token class flags ----------------------------------------------------------
+
+const sal_uInt8 BIFF_TOKCLASS_MASK              = 0x60;
+const sal_uInt8 BIFF_TOKCLASS_NONE              = 0x00;     /// 00-1F: Base tokens.
+const sal_uInt8 BIFF_TOKCLASS_REF               = 0x20;     /// 20-3F: Reference class tokens.
+const sal_uInt8 BIFF_TOKCLASS_VAL               = 0x40;     /// 40-5F: Value class tokens.
+const sal_uInt8 BIFF_TOKCLASS_ARR               = 0x60;     /// 60-7F: Array class tokens.
+
+const sal_uInt8 BIFF_TOKFLAG_INVALID            = 0x80;     /// This bit must be null for a valid token identifier.
+
+// base token identifiers -----------------------------------------------------
+
+const sal_uInt8 BIFF_TOKID_MASK                 = 0x1F;
+
+const sal_uInt8 BIFF_TOKID_NONE                 = 0x00;     /// Placeholder for invalid token id.
+const sal_uInt8 BIFF_TOKID_EXP                  = 0x01;     /// Array or shared formula reference.
+const sal_uInt8 BIFF_TOKID_TBL                  = 0x02;     /// Multiple operation reference.
+const sal_uInt8 BIFF_TOKID_ADD                  = 0x03;     /// Addition operator.
+const sal_uInt8 BIFF_TOKID_SUB                  = 0x04;     /// Subtraction operator.
+const sal_uInt8 BIFF_TOKID_MUL                  = 0x05;     /// Multiplication operator.
+const sal_uInt8 BIFF_TOKID_DIV                  = 0x06;     /// Division operator.
+const sal_uInt8 BIFF_TOKID_POWER                = 0x07;     /// Power operator.
+const sal_uInt8 BIFF_TOKID_CONCAT               = 0x08;     /// String concatenation operator.
+const sal_uInt8 BIFF_TOKID_LT                   = 0x09;     /// Less than operator.
+const sal_uInt8 BIFF_TOKID_LE                   = 0x0A;     /// Less than or equal operator.
+const sal_uInt8 BIFF_TOKID_EQ                   = 0x0B;     /// Equal operator.
+const sal_uInt8 BIFF_TOKID_GE                   = 0x0C;     /// Greater than or equal operator.
+const sal_uInt8 BIFF_TOKID_GT                   = 0x0D;     /// Greater than operator.
+const sal_uInt8 BIFF_TOKID_NE                   = 0x0E;     /// Not equal operator.
+const sal_uInt8 BIFF_TOKID_ISECT                = 0x0F;     /// Intersection operator.
+const sal_uInt8 BIFF_TOKID_LIST                 = 0x10;     /// List operator.
+const sal_uInt8 BIFF_TOKID_RANGE                = 0x11;     /// Range operator.
+const sal_uInt8 BIFF_TOKID_UPLUS                = 0x12;     /// Unary plus.
+const sal_uInt8 BIFF_TOKID_UMINUS               = 0x13;     /// Unary minus.
+const sal_uInt8 BIFF_TOKID_PERCENT              = 0x14;     /// Percent sign.
+const sal_uInt8 BIFF_TOKID_PAREN                = 0x15;     /// Parentheses.
+const sal_uInt8 BIFF_TOKID_MISSARG              = 0x16;     /// Missing argument.
+const sal_uInt8 BIFF_TOKID_STR                  = 0x17;     /// String constant.
+const sal_uInt8 BIFF_TOKID_NLR                  = 0x18;     /// Natural language reference (NLR).
+const sal_uInt8 BIFF_TOKID_ATTR                 = 0x19;     /// Special attribute.
+const sal_uInt8 BIFF_TOKID_SHEET                = 0x1A;     /// Start of a sheet reference (BIFF2-BIFF4).
+const sal_uInt8 BIFF_TOKID_ENDSHEET             = 0x1B;     /// End of a sheet reference (BIFF2-BIFF4).
+const sal_uInt8 BIFF_TOKID_ERR                  = 0x1C;     /// Error constant.
+const sal_uInt8 BIFF_TOKID_BOOL                 = 0x1D;     /// Boolean constant.
+const sal_uInt8 BIFF_TOKID_INT                  = 0x1E;     /// Integer constant.
+const sal_uInt8 BIFF_TOKID_NUM                  = 0x1F;     /// Floating-point constant.
+
+// base identifiers of classified tokens --------------------------------------
+
+const sal_uInt8 BIFF_TOKID_ARRAY                = 0x00;     /// Array constant.
+const sal_uInt8 BIFF_TOKID_FUNC                 = 0x01;     /// Function, fixed number of arguments.
+const sal_uInt8 BIFF_TOKID_FUNCVAR              = 0x02;     /// Function, variable number of arguments.
+const sal_uInt8 BIFF_TOKID_NAME                 = 0x03;     /// Defined name.
+const sal_uInt8 BIFF_TOKID_REF                  = 0x04;     /// 2D cell reference.
+const sal_uInt8 BIFF_TOKID_AREA                 = 0x05;     /// 2D area reference.
+const sal_uInt8 BIFF_TOKID_MEMAREA              = 0x06;     /// Constant reference subexpression.
+const sal_uInt8 BIFF_TOKID_MEMERR               = 0x07;     /// Deleted reference subexpression.
+const sal_uInt8 BIFF_TOKID_MEMNOMEM             = 0x08;     /// Constant reference subexpression without result.
+const sal_uInt8 BIFF_TOKID_MEMFUNC              = 0x09;     /// Variable reference subexpression.
+const sal_uInt8 BIFF_TOKID_REFERR               = 0x0A;     /// Deleted 2D cell reference.
+const sal_uInt8 BIFF_TOKID_AREAERR              = 0x0B;     /// Deleted 2D area reference.
+const sal_uInt8 BIFF_TOKID_REFN                 = 0x0C;     /// Relative 2D cell reference (in names).
+const sal_uInt8 BIFF_TOKID_AREAN                = 0x0D;     /// Relative 2D area reference (in names).
+const sal_uInt8 BIFF_TOKID_MEMAREAN             = 0x0E;     /// Reference subexpression (in names).
+const sal_uInt8 BIFF_TOKID_MEMNOMEMN            = 0x0F;     /// Reference subexpression (in names) without result.
+const sal_uInt8 BIFF_TOKID_FUNCCE               = 0x18;
+const sal_uInt8 BIFF_TOKID_NAMEX                = 0x19;     /// External reference.
+const sal_uInt8 BIFF_TOKID_REF3D                = 0x1A;     /// 3D cell reference.
+const sal_uInt8 BIFF_TOKID_AREA3D               = 0x1B;     /// 3D area reference.
+const sal_uInt8 BIFF_TOKID_REFERR3D             = 0x1C;     /// Deleted 3D cell reference.
+const sal_uInt8 BIFF_TOKID_AREAERR3D            = 0x1D;     /// Deleted 3D area reference
+
+// specific token constants ---------------------------------------------------
+
+const sal_uInt8 BIFF_TOK_ARRAY_DOUBLE           = 0;        /// Double value in an array.
+const sal_uInt8 BIFF_TOK_ARRAY_STRING           = 1;        /// String value in an array.
+const sal_uInt8 BIFF_TOK_ARRAY_BOOL             = 2;        /// Boolean value in an array.
+const sal_uInt8 BIFF_TOK_ARRAY_ERROR            = 4;        /// Error code in an array.
+
+const sal_uInt8 BIFF_TOK_BOOL_FALSE             = 0;        /// FALSE value of a tBool token.
+const sal_uInt8 BIFF_TOK_BOOL_TRUE              = 1;        /// TRUE value of a tBool token.
+
+const sal_uInt8 BIFF_TOK_ATTR_VOLATILE          = 0x01;     /// Volatile function.
+const sal_uInt8 BIFF_TOK_ATTR_IF                = 0x02;     /// Start of true condition in IF function.
+const sal_uInt8 BIFF_TOK_ATTR_CHOOSE            = 0x04;     /// Jump array of CHOOSE function.
+const sal_uInt8 BIFF_TOK_ATTR_SKIP              = 0x08;     /// Skip tokens.
+const sal_uInt8 BIFF_TOK_ATTR_SUM               = 0x10;     /// SUM function with one parameter.
+const sal_uInt8 BIFF_TOK_ATTR_ASSIGN            = 0x20;     /// BASIC style assignment.
+const sal_uInt8 BIFF_TOK_ATTR_SPACE             = 0x40;     /// Spaces in formula representation.
+const sal_uInt8 BIFF_TOK_ATTR_SPACE_VOLATILE    = 0x41;     /// Leading spaces and volatile formula.
+const sal_uInt8 BIFF_TOK_ATTR_IFERROR           = 0x80;     /// Start of condition in IFERROR function (BIFF12 only).
+
+const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP          = 0x00;     /// Spaces before next token.
+const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR          = 0x01;     /// Line breaks before next token.
+const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP_OPEN     = 0x02;     /// Spaces before opening parenthesis.
+const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR_OPEN     = 0x03;     /// Line breaks before opening parenthesis.
+const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP_CLOSE    = 0x04;     /// Spaces before closing parenthesis.
+const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR_CLOSE    = 0x05;     /// Line breaks before closing parenthesis.
+const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP_PRE      = 0x06;     /// Spaces before formula (BIFF3).
+
+const sal_uInt16 BIFF_TOK_FUNCVAR_CMD           = 0x8000;   /// Macro command.
+const sal_uInt16 BIFF_TOK_FUNCVAR_FUNCIDMASK    = 0x7FFF;   /// Mask for function/command index.
+const sal_uInt8 BIFF_TOK_FUNCVAR_CMDPROMPT      = 0x80;     /// User prompt for macro commands.
+const sal_uInt8 BIFF_TOK_FUNCVAR_COUNTMASK      = 0x7F;     /// Mask for parameter count.
+
+const sal_uInt16 BIFF12_TOK_REF_COLMASK         = 0x3FFF;   /// Mask to extract column from reference (BIFF12).
+const sal_Int32 BIFF12_TOK_REF_ROWMASK          = 0xFFFFF;  /// Mask to extract row from reference (BIFF12).
+const sal_uInt16 BIFF12_TOK_REF_COLREL          = 0x4000;   /// True = column is relative (BIFF12).
+const sal_uInt16 BIFF12_TOK_REF_ROWREL          = 0x8000;   /// True = row is relative (BIFF12).
+
+const sal_uInt16 BIFF_TOK_REF_COLMASK           = 0x00FF;   /// Mask to extract BIFF8 column from reference.
+const sal_uInt16 BIFF_TOK_REF_ROWMASK           = 0x3FFF;   /// Mask to extract BIFF2-BIFF5 row from reference.
+const sal_uInt16 BIFF_TOK_REF_COLREL            = 0x4000;   /// True = column is relative.
+const sal_uInt16 BIFF_TOK_REF_ROWREL            = 0x8000;   /// True = row is relative.
+
+const sal_uInt16 BIFF12_TOK_TABLE_COLUMN         = 0x0001;   /// Table reference: Single column.
+const sal_uInt16 BIFF12_TOK_TABLE_COLRANGE       = 0x0002;   /// Table reference: Range of columns.
+const sal_uInt16 BIFF12_TOK_TABLE_ALL            = 0x0004;   /// Table reference: Special [#All] range.
+const sal_uInt16 BIFF12_TOK_TABLE_HEADERS        = 0x0008;   /// Table reference: Special [#Headers] range.
+const sal_uInt16 BIFF12_TOK_TABLE_DATA           = 0x0010;   /// Table reference: Special [#Data] range.
+const sal_uInt16 BIFF12_TOK_TABLE_TOTALS         = 0x0020;   /// Table reference: Special [#Totals] range.
+const sal_uInt16 BIFF12_TOK_TABLE_THISROW        = 0x0040;   /// Table reference: Special [#This Row] range.
+const sal_uInt16 BIFF12_TOK_TABLE_SP_BRACKETS    = 0x0080;   /// Table reference: Spaces in outer brackets.
+const sal_uInt16 BIFF12_TOK_TABLE_SP_SEP         = 0x0100;   /// Table reference: Spaces after separators.
+const sal_uInt16 BIFF12_TOK_TABLE_ROW            = 0x0200;   /// Table reference: Single row.
+const sal_uInt16 BIFF12_TOK_TABLE_CELL           = 0x0400;   /// Table reference: Single cell.
+
+const sal_uInt8 BIFF_TOK_NLR_ERR                = 0x01;     /// NLR: Invalid/deleted.
+const sal_uInt8 BIFF_TOK_NLR_ROWR               = 0x02;     /// NLR: Row index.
+const sal_uInt8 BIFF_TOK_NLR_COLR               = 0x03;     /// NLR: Column index.
+const sal_uInt8 BIFF_TOK_NLR_ROWV               = 0x06;     /// NLR: Value in row.
+const sal_uInt8 BIFF_TOK_NLR_COLV               = 0x07;     /// NLR: Value in column.
+const sal_uInt8 BIFF_TOK_NLR_RANGE              = 0x0A;     /// NLR: Range.
+const sal_uInt8 BIFF_TOK_NLR_SRANGE             = 0x0B;     /// Stacked NLR: Range.
+const sal_uInt8 BIFF_TOK_NLR_SROWR              = 0x0C;     /// Stacked NLR: Row index.
+const sal_uInt8 BIFF_TOK_NLR_SCOLR              = 0x0D;     /// Stacked NLR: Column index.
+const sal_uInt8 BIFF_TOK_NLR_SROWV              = 0x0E;     /// Stacked NLR: Value in row.
+const sal_uInt8 BIFF_TOK_NLR_SCOLV              = 0x0F;     /// Stacked NLR: Value in column.
+const sal_uInt8 BIFF_TOK_NLR_RANGEERR           = 0x10;     /// NLR: Invalid/deleted range.
+const sal_uInt8 BIFF_TOK_NLR_SXNAME             = 0x1D;     /// NLR: Pivot table name.
+const sal_uInt16 BIFF_TOK_NLR_REL               = 0x8000;   /// True = NLR is relative.
+const sal_uInt16 BIFF_TOK_NLR_MASK              = 0x3FFF;   /// Mask to extract BIFF8 column from NLR.
+
+const sal_uInt32 BIFF_TOK_NLR_ADDREL            = 0x80000000;   /// NLR relative (in appended data).
+const sal_uInt32 BIFF_TOK_NLR_ADDMASK           = 0x3FFFFFFF;   /// Mask for number of appended ranges.
+
+// function constants ---------------------------------------------------------
+
+const sal_uInt8 OOX_MAX_PARAMCOUNT              = 255;      /// Maximum parameter count for OOXML/BIFF12 files.
+const sal_uInt8 BIFF_MAX_PARAMCOUNT             = 30;       /// Maximum parameter count for BIFF2-BIFF8 files.
+
+const sal_uInt16 BIFF_FUNC_IF                   = 1;        /// Function identifier of the IF function.
+const sal_uInt16 BIFF_FUNC_SUM                  = 4;        /// Function identifier of the SUM function.
+const sal_uInt16 BIFF_FUNC_TRUE                 = 34;       /// Function identifier of the TRUE function.
+const sal_uInt16 BIFF_FUNC_FALSE                = 35;       /// Function identifier of the FALSE function.
+const sal_uInt16 BIFF_FUNC_ROWS                 = 76;       /// Function identifier of the ROWS function.
+const sal_uInt16 BIFF_FUNC_COLUMNS              = 77;       /// Function identifier of the COLUMNS function.
+const sal_uInt16 BIFF_FUNC_OFFSET               = 78;       /// Function identifier of the OFFSET function.
+const sal_uInt16 BIFF_FUNC_EXTERNCALL           = 255;      /// BIFF function id of the EXTERN.CALL function.
+const sal_uInt16 BIFF_FUNC_FLOOR                = 285;      /// Function identifier of the FLOOR function.
+const sal_uInt16 BIFF_FUNC_CEILING              = 288;      /// Function identifier of the CEILING function.
+const sal_uInt16 BIFF_FUNC_HYPERLINK            = 359;      /// Function identifier of the HYPERLINK function.
+const sal_uInt16 BIFF_FUNC_WEEKNUM              = 465;      /// Function identifier of the WEEKNUM function.
+
+// Formula type ===============================================================
+
+/** Enumerates all possible types of a formula. */
+enum FormulaType
+{
+    FORMULATYPE_CELL,           /// Simple cell formula, or reference to a shared formula name.
+    FORMULATYPE_ARRAY,          /// Array (matrix) formula.
+    FORMULATYPE_SHAREDFORMULA,  /// Shared formula definition.
+    FORMULATYPE_CONDFORMAT,     /// Condition of a conditional format rule.
+    FORMULATYPE_VALIDATION,     /// Condition of a data validation.
+    FORMULATYPE_DEFINEDNAME     /// Definition of a defined name.
+};
+
+// Reference helpers ==========================================================
+
+/** A 2D formula cell reference struct with relative flags. */
+struct BinSingleRef2d
+{
+    sal_Int32           mnCol;              /// Column index.
+    sal_Int32           mnRow;              /// Row index.
+    bool                mbColRel;           /// True = relative column reference.
+    bool                mbRowRel;           /// True = relative row reference.
+
+    explicit            BinSingleRef2d();
+
+    void                setBiff12Data( sal_uInt16 nCol, sal_Int32 nRow, bool bRelativeAsOffset );
+    void                setBiff2Data( sal_uInt8 nCol, sal_uInt16 nRow, bool bRelativeAsOffset );
+    void                setBiff8Data( sal_uInt16 nCol, sal_uInt16 nRow, bool bRelativeAsOffset );
+
+    void                readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset );
+    void                readBiff2Data( BiffInputStream& rStrm, bool bRelativeAsOffset );
+    void                readBiff8Data( BiffInputStream& rStrm, bool bRelativeAsOffset );
+};
+
+// ----------------------------------------------------------------------------
+
+/** A 2D formula cell range reference struct with relative flags. */
+struct BinComplexRef2d
+{
+    BinSingleRef2d      maRef1;             /// Start (top-left) cell address.
+    BinSingleRef2d      maRef2;             /// End (bottom-right) cell address.
+
+    void                readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset );
+    void                readBiff2Data( BiffInputStream& rStrm, bool bRelativeAsOffset );
+    void                readBiff8Data( BiffInputStream& rStrm, bool bRelativeAsOffset );
+};
+
+// Token vector, token sequence ===============================================
+
+typedef ::com::sun::star::sheet::FormulaToken       ApiToken;
+typedef ::com::sun::star::uno::Sequence< ApiToken > ApiTokenSequence;
+
+/** Contains the base address and type of a special token representing an array
+    formula or a shared formula (sal_False), or a table operation (sal_True). */
+typedef ::com::sun::star::beans::Pair< ::com::sun::star::table::CellAddress, sal_Bool > ApiSpecialTokenInfo;
+
+/** A vector of formula tokens with additional convenience functions. */
+class ApiTokenVector : public ::std::vector< ApiToken >
+{
+public:
+    explicit            ApiTokenVector();
+
+    /** Appends a new token with the passed op-code, returns its data field. */
+    ::com::sun::star::uno::Any&
+                        append( sal_Int32 nOpCode );
+
+    /** Appends a new token with the passed op-code and data. */
+    template< typename Type >
+    inline void         append( sal_Int32 nOpCode, const Type& rData ) { append( nOpCode ) <<= rData; }
+};
+
+// Token sequence iterator ====================================================
+
+/** Token sequence iterator that is able to skip space tokens. */
+class ApiTokenIterator
+{
+public:
+    explicit            ApiTokenIterator( const ApiTokenSequence& rTokens, sal_Int32 nSpacesOpCode, bool bSkipSpaces );
+    /** Copy constructor that allows to change the skip spaces mode. */
+    explicit            ApiTokenIterator( const ApiTokenIterator& rIter, bool bSkipSpaces );
+
+    inline bool         is() const { return mpToken != mpTokenEnd; }
+    inline const ApiToken* get() const { return mpToken; }
+    inline const ApiToken* operator->() const { return mpToken; }
+    inline const ApiToken& operator*() const { return *mpToken; }
+
+    ApiTokenIterator&   operator++();
+
+private:
+    void                skipSpaces();
+
+private:
+    const ApiToken*     mpToken;            /// Pointer to current token of the token sequence.
+    const ApiToken*     mpTokenEnd;         /// Pointer behind last token of the token sequence.
+    const sal_Int32     mnSpacesOpCode;     /// Op-code for whitespace tokens.
+    const bool          mbSkipSpaces;       /// true = Skip whitespace tokens.
+};
+
+// List of API op-codes =======================================================
+
+/** Contains all API op-codes needed to build formulas with tokens. */
+struct ApiOpCodes
+{
+    // special
+    sal_Int32           OPCODE_UNKNOWN;         /// Internal: function name unknown to mapper.
+    sal_Int32           OPCODE_EXTERNAL;        /// External function call (e.g. add-ins).
+    // formula structure
+    sal_Int32           OPCODE_PUSH;            /// Op-code for common value operands.
+    sal_Int32           OPCODE_MISSING;         /// Placeholder for a missing function parameter.
+    sal_Int32           OPCODE_SPACES;          /// Spaces between other formula tokens.
+    sal_Int32           OPCODE_NAME;            /// Index of a defined name.
+    sal_Int32           OPCODE_DBAREA;          /// Index of a database area.
+    sal_Int32           OPCODE_NLR;             /// Natural language reference.
+    sal_Int32           OPCODE_DDE;             /// DDE link function.
+    sal_Int32           OPCODE_MACRO;           /// Macro function call.
+    sal_Int32           OPCODE_BAD;             /// Bad token (unknown name, formula error).
+    sal_Int32           OPCODE_NONAME;          /// Function style #NAME? error.
+    // separators
+    sal_Int32           OPCODE_OPEN;            /// Opening parenthesis.
+    sal_Int32           OPCODE_CLOSE;           /// Closing parenthesis.
+    sal_Int32           OPCODE_SEP;             /// Function parameter separator.
+    // array separators
+    sal_Int32           OPCODE_ARRAY_OPEN;      /// Opening brace for constant arrays.
+    sal_Int32           OPCODE_ARRAY_CLOSE;     /// Closing brace for constant arrays.
+    sal_Int32           OPCODE_ARRAY_ROWSEP;    /// Row separator in constant arrays.
+    sal_Int32           OPCODE_ARRAY_COLSEP;    /// Column separator in constant arrays.
+    // unary operators
+    sal_Int32           OPCODE_PLUS_SIGN;       /// Unary plus sign.
+    sal_Int32           OPCODE_MINUS_SIGN;      /// Unary minus sign.
+    sal_Int32           OPCODE_PERCENT;         /// Percent sign.
+    // binary operators
+    sal_Int32           OPCODE_ADD;             /// Addition operator.
+    sal_Int32           OPCODE_SUB;             /// Subtraction operator.
+    sal_Int32           OPCODE_MULT;            /// Multiplication operator.
+    sal_Int32           OPCODE_DIV;             /// Division operator.
+    sal_Int32           OPCODE_POWER;           /// Power operator.
+    sal_Int32           OPCODE_CONCAT;          /// String concatenation operator.
+    sal_Int32           OPCODE_EQUAL;           /// Compare equal operator.
+    sal_Int32           OPCODE_NOT_EQUAL;       /// Compare not equal operator.
+    sal_Int32           OPCODE_LESS;            /// Compare less operator.
+    sal_Int32           OPCODE_LESS_EQUAL;      /// Compare less or equal operator.
+    sal_Int32           OPCODE_GREATER;         /// Compare greater operator.
+    sal_Int32           OPCODE_GREATER_EQUAL;   /// Compare greater or equal operator.
+    sal_Int32           OPCODE_INTERSECT;       /// Range intersection operator.
+    sal_Int32           OPCODE_LIST;            /// Range list operator.
+    sal_Int32           OPCODE_RANGE;           /// Range operator.
+};
+
+// Function parameter info ====================================================
+
+/** Enumerates validity modes for a function parameter. */
+enum FuncParamValidity
+{
+    FUNC_PARAM_NONE = 0,        /// Default for an unspecified entry in a C-array.
+    FUNC_PARAM_REGULAR,         /// Parameter supported by Calc and Excel.
+    FUNC_PARAM_CALCONLY,        /// Parameter supported by Calc only.
+    FUNC_PARAM_EXCELONLY        /// Parameter supported by Excel only.
+};
+
+/** Enumerates different types of token class conversion in function parameters. */
+enum FuncParamConversion
+{
+    FUNC_PARAMCONV_ORG,         /// Use original class of current token.
+    FUNC_PARAMCONV_VAL,         /// Convert tokens to VAL class.
+    FUNC_PARAMCONV_ARR,         /// Convert tokens to ARR class.
+    FUNC_PARAMCONV_RPT,         /// Repeat parent conversion in VALTYPE parameters.
+    FUNC_PARAMCONV_RPX,         /// Repeat parent conversion in REFTYPE parameters.
+    FUNC_PARAMCONV_RPO          /// Repeat parent conversion in operands of operators.
+};
+
+/** Structure that contains all needed information for a parameter in a
+    function.
+
+    The member meValid specifies which application supports the parameter. If
+    set to CALCONLY, import filters have to insert a default value for this
+    parameter, and export filters have to skip the parameter. If set to
+    EXCELONLY, import filters have to skip the parameter, and export filters
+    have to insert a default value for this parameter.
+
+    The member mbValType specifies whether the parameter requires tokens to be
+    of value type (VAL or ARR class).
+
+        If set to false, the parameter is called to be REFTYPE. Tokens with REF
+        default class can be inserted for the parameter (e.g. tAreaR tokens).
+
+        If set to true, the parameter is called to be VALTYPE. Tokens with REF
+        class need to be converted to VAL tokens first (e.g. tAreaR will be
+        converted to tAreaV), and further conversion is done according to this
+        new token class.
+
+    The member meConv specifies how to convert the current token class of the
+    token inserted for the parameter. If the token class is still REF this
+    means that the token has default REF class and the parameter is REFTYPE
+    (see member mbValType), the token will not be converted at all and remains
+    in REF class. Otherwise, token class conversion is depending on the actual
+    token class of the return value of the function containing this parameter.
+    The function may return REF class (tFuncR, tFuncVarR, tFuncCER), or it may
+    return VAL or ARR class (tFuncV, tFuncA, tFuncVarV, tFuncVarA, tFuncCEV,
+    tFuncCEA). Even if the function is able to return REF class, it may return
+    VAL or ARR class instead due to the VALTYPE data type of the parent
+    function parameter that calls the own function. Example: The INDIRECT
+    function returns REF class by default. But if called from a VALTYPE
+    function parameter, e.g. in the formula =ABS(INDIRECT("A1")), it returns
+    VAL or ARR class instead. Additionally, the repeating conversion types RPT
+    and RPX rely on the conversion executed for the function token class.
+
+        1) ORG:
+        Use the original class of the token (VAL or ARR), regardless of any
+        conversion done for the function return class.
+
+        2) VAL:
+        Convert ARR tokens to VAL class, regardless of any conversion done for
+        the function return class.
+
+        3) ARR:
+        Convert VAL tokens to ARR class, regardless of any conversion done for
+        the function return class.
+
+        4) RPT:
+        If the own function returns REF class (thus it is called from a REFTYPE
+        parameter, see above), and the parent conversion type (for the function
+        return class) was ORG, VAL, or ARR, ignore that conversion and always
+        use VAL conversion for the own token instead. If the parent conversion
+        type was RPT or RPX, repeat the conversion that would have been used if
+        the function would return value type.
+        If the own function returns value type (VAL or ARR class, see above),
+        and the parent conversion type (for the function return class) was ORG,
+        VAL, ARR, or RPT, repeat this conversion for the own token. If the
+        parent conversion type was RPX, always use ORG conversion type for the
+        own token instead.
+
+        5) RPX:
+        This type of conversion only occurs in functions returning VAL class by
+        default. If the own token is value type, and the VAL return class of
+        the own function has been changed to ARR class (due to direct ARR
+        conversion, or due to ARR conversion repeated by RPT or RPX), set the
+        own token to ARR type. Otherwise use the original token type (VAL
+        conversion from parent parameter will not be repeated at all). If
+        nested functions have RPT or value-type RPX parameters, they will not
+        repeat this conversion type, but will use ORG conversion instead (see
+        description of RPT above).
+
+        6) RPO:
+        This type of conversion is only used for the operands of all operators
+        (unary and binary arithmetic operators, comparison operators, and range
+        operators). It is not used for function parameters. On conversion, it
+        will be replaced by the last conversion type that was not the RPO
+        conversion. This leads to a slightly different behaviour than the RPT
+        conversion for operands in conjunction with a parent RPX conversion.
+ */
+struct FunctionParamInfo
+{
+    FuncParamValidity   meValid;        /// Parameter validity.
+    FuncParamConversion meConv;         /// Token class conversion type.
+    bool                mbValType;      /// Data type (false = REFTYPE, true = VALTYPE).
+};
+
+// Function data ==============================================================
+
+/** This enumeration contains constants for all known external libraries
+    containing supported sheet functions. */
+enum FunctionLibraryType
+{
+    FUNCLIB_UNKNOWN = 0,        /// Unknown library (must be zero).
+    FUNCLIB_EUROTOOL            /// EuroTool add-in with EUROCONVERT function.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Represents information for a spreadsheet function.
+
+    The member mpParamInfos points to a C-array of type information structures
+    for all parameters of the function. The last initialized structure
+    describing a regular parameter (member meValid == FUNC_PARAM_REGULAR) in
+    this array is used repeatedly for all following parameters supported by a
+    function.
+ */
+struct FunctionInfo
+{
+    ::rtl::OUString     maOdfFuncName;      /// ODF function name.
+    ::rtl::OUString     maOoxFuncName;      /// OOXML function name.
+    ::rtl::OUString     maBiffMacroName;    /// Expected macro name in EXTERN.CALL function.
+    ::rtl::OUString     maExtProgName;      /// Programmatic function name for external functions.
+    FunctionLibraryType meFuncLibType;      /// The external library this function is part of.
+    sal_Int32           mnApiOpCode;        /// API function opcode.
+    sal_uInt16          mnBiff12FuncId;     /// BIFF12 function identifier.
+    sal_uInt16          mnBiffFuncId;       /// BIFF2-BIFF8 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.
+    const FunctionParamInfo* mpParamInfos;  /// Information about all parameters.
+    bool                mbParamPairs;       /// True = optional parameters are expected to appear in pairs.
+    bool                mbVolatile;         /// True = volatile function.
+    bool                mbExternal;         /// True = external function in Calc.
+    bool                mbMacroFunc;        /// True = macro sheet function or command.
+    bool                mbVarParam;         /// True = use a tFuncVar token, also if min/max are equal.
+};
+
+typedef RefVector< FunctionInfo > FunctionInfoVector;
+
+// Function info parameter class iterator =====================================
+
+/** Iterator working on the mpParamInfos member of the FunctionInfo struct.
+
+    This iterator can be used to iterate through the array containing the
+    token class conversion information of function parameters. This iterator
+    repeats the last valid structure in the array - it stops automatically
+    before the first empty array entry or before the end of the array, even for
+    repeated calls to the increment operator.
+ */
+class FunctionParamInfoIterator
+{
+public:
+    explicit            FunctionParamInfoIterator( const FunctionInfo& rFuncInfo );
+
+    bool                isCalcOnlyParam() const;
+    bool                isExcelOnlyParam() const;
+    FunctionParamInfoIterator& operator++();
+
+private:
+    const FunctionParamInfo* mpParamInfo;
+    const FunctionParamInfo* mpParamInfoEnd;
+    bool                mbParamPairs;
+};
+
+// Base function provider =====================================================
+
+struct FunctionProviderImpl;
+
+/** Provides access to function info structs for all available sheet functions.
+ */
+class FunctionProvider  // not derived from WorkbookHelper to make it usable in file dumpers
+{
+public:
+    explicit            FunctionProvider( FilterType eFilter, BiffType eBiff, bool bImportFilter );
+    virtual             ~FunctionProvider();
+
+    /** Returns the function info for an OOXML function name, or 0 on error. */
+    const FunctionInfo* getFuncInfoFromOoxFuncName( const ::rtl::OUString& rFuncName ) const;
+
+    /** Returns the function info for a BIFF12 function index, or 0 on error. */
+    const FunctionInfo* getFuncInfoFromBiff12FuncId( sal_uInt16 nFuncId ) const;
+
+    /** Returns the function info for a BIFF2-BIFF8 function index, or 0 on error. */
+    const FunctionInfo* getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const;
+
+    /** Returns the function info for a macro function referred by the
+        EXTERN.CALL function, or 0 on error. */
+    const FunctionInfo* getFuncInfoFromMacroName( const ::rtl::OUString& rFuncName ) const;
+
+    /** Returns the library type associated with the passed URL of a function
+        library (function add-in). */
+    FunctionLibraryType getFuncLibTypeFromLibraryName( const ::rtl::OUString& rLibraryName ) const;
+
+protected:
+    /** Returns the list of all function infos. */
+    const FunctionInfoVector& getFuncs() const;
+
+private:
+    typedef ::boost::shared_ptr< FunctionProviderImpl > FunctionProviderImplRef;
+    FunctionProviderImplRef mxFuncImpl;     /// Shared implementation between all copies of the provider.
+};
+
+// Op-code and function provider ==============================================
+
+struct OpCodeProviderImpl;
+
+/** Provides access to API op-codes for all available formula tokens and to
+    function info structs for all available sheet functions.
+ */
+class OpCodeProvider : public FunctionProvider // not derived from WorkbookHelper to make it usable as UNO service
+{
+public:
+    explicit            OpCodeProvider(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxModelFactory,
+                            FilterType eFilter, BiffType eBiff, bool bImportFilter );
+    virtual             ~OpCodeProvider();
+
+    /** Returns the structure containing all token op-codes for operators and
+        special tokens used by the Calc document and its formula parser. */
+    const ApiOpCodes&   getOpCodes() const;
+
+    /** Returns the function info for an API token, or 0 on error. */
+    const FunctionInfo* getFuncInfoFromApiToken( const ApiToken& rToken ) const;
+
+    /** Returns the op-code map that is used by the OOXML formula parser. */
+    ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaOpCodeMapEntry >
+                        getOoxParserMap() const;
+
+private:
+    typedef ::boost::shared_ptr< OpCodeProviderImpl > OpCodeProviderImplRef;
+    OpCodeProviderImplRef mxOpCodeImpl;     /// Shared implementation between all copies of the provider.
+};
+
+// API formula parser wrapper =================================================
+
+/** A wrapper around the FormulaParser service provided by the Calc document. */
+class ApiParserWrapper : public OpCodeProvider
+{
+public:
+    explicit            ApiParserWrapper(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxModelFactory,
+                            const OpCodeProvider& rOpCodeProv );
+
+    /** Returns read/write access to the formula parser property set. */
+    inline PropertySet& getParserProperties() { return maParserProps; }
+
+    /** Calls the XFormulaParser::parseFormula() function of the API parser. */
+    ApiTokenSequence    parseFormula(
+                            const ::rtl::OUString& rFormula,
+                            const ::com::sun::star::table::CellAddress& rRefPos );
+
+private:
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaParser >
+                        mxParser;
+    PropertySet         maParserProps;
+};
+
+// Formula parser/printer base class for filters ==============================
+
+/** Base class for import formula parsers and export formula compilers. */
+class FormulaProcessorBase : public OpCodeProvider, protected ApiOpCodes, public WorkbookHelper
+{
+public:
+    explicit            FormulaProcessorBase( const WorkbookHelper& rHelper );
+
+    // ------------------------------------------------------------------------
+
+    /** Generates a cell address string in A1 notation from the passed cell
+        address.
+
+        @param rAddress  The cell address containing column and row index.
+        @param bAbsolute  True = adds dollar signs before column and row.
+     */
+    static ::rtl::OUString generateAddress2dString(
+                            const ::com::sun::star::table::CellAddress& rAddress,
+                            bool bAbsolute );
+
+    /** Generates a cell address string in A1 notation from the passed binary
+        cell address.
+
+        @param rAddress  The cell address containing column and row index.
+        @param bAbsolute  True = adds dollar signs before column and row.
+     */
+    static ::rtl::OUString generateAddress2dString(
+                            const BinAddress& rAddress,
+                            bool bAbsolute );
+
+    /** Generates a cell range string in A1:A1 notation from the passed cell
+        range address.
+
+        @param rRange  The cell range address containing column and row indexes.
+        @param bAbsolute  True = adds dollar signs before columns and rows.
+     */
+    static ::rtl::OUString generateRange2dString(
+                            const ::com::sun::star::table::CellRangeAddress& rRange,
+                            bool bAbsolute );
+
+    /** Generates a cell range string in A1:A1 notation from the passed binary
+        cell range address.
+
+        @param rRange  The cell range address containing column and row indexes.
+        @param bAbsolute  True = adds dollar signs before columns and rows.
+     */
+    static ::rtl::OUString generateRange2dString(
+                            const BinRange& rRange,
+                            bool bAbsolute );
+
+    /** Generates a cell range list string in A1:A1 notation from the passed
+        cell range addresses. May enclose multiple ranges into parentheses.
+
+        @param rRanges  The list of cell range addresses.
+        @param bAbsolute  True = adds dollar signs before columns and rows.
+        @param cSeparator  Separator character between ranges.
+        @param bEncloseMultiple  True = enclose multiple ranges in parentheses.
+     */
+    static ::rtl::OUString generateRangeList2dString(
+                            const ApiCellRangeList& rRanges,
+                            bool bAbsolute,
+                            sal_Unicode cSeparator,
+                            bool bEncloseMultiple );
+
+    // ------------------------------------------------------------------------
+
+    /** Generates a string in Calc formula notation from the passed string.
+
+        @param rString  The string value.
+
+        @return  The string enclosed in double quotes, where all contained
+            quote characters are doubled.
+     */
+    static ::rtl::OUString generateApiString( const ::rtl::OUString& rString );
+
+    /** Generates an array string in Calc formula notation from the passed
+        matrix with Any's containing double values or strings.
+
+        @param rMatrix  The matrix containing double values or strings.
+     */
+    static ::rtl::OUString generateApiArray( const Matrix< ::com::sun::star::uno::Any >& rMatrix );
+
+    // ------------------------------------------------------------------------
+
+    /** Tries to extract a single cell reference from a formula token sequence.
+
+        @param rTokens  The token sequence to be parsed. Should contain exactly
+            one address token or cell range address token. The token sequence
+            may contain whitespace tokens.
+
+        @return  If the token sequence is valid, this function returns an Any
+            containing a com.sun.star.sheet.SingleReference object, or a
+            com.sun.star.sheet.ComplexReference object. If the token sequence
+            contains too many, or unexpected tokens, an empty Any is returned.
+     */
+    ::com::sun::star::uno::Any
+                        extractReference( const ApiTokenSequence& rTokens ) const;
+
+    /** Tries to extract a cell range address from a formula token sequence.
+
+        @param orAddress  (output parameter) If the token sequence is valid,
+            this parameter will contain the extracted cell range address. If
+            the token sequence contains unexpected tokens, nothing meaningful
+            is inserted, and the function returns false.
+
+        @param rTokens  The token sequence to be parsed. Should contain exactly
+            one cell range address token. The token sequence may contain
+            whitespace tokens.
+
+        @param bAllowRelative  True = it is allowed that rTokens contains
+            relative references (based on cell A1 of the current sheet).
+            False = only real absolute references will be accepted.
+
+        @return  True, if the token sequence contains a valid cell range
+            address which has been extracted to orRange, false otherwise.
+     */
+    bool                extractCellRange(
+                            ::com::sun::star::table::CellRangeAddress& orRange,
+                            const ApiTokenSequence& rTokens,
+                            bool bAllowRelative ) const;
+
+    /** Tries to extract a cell range list from a formula token sequence.
+
+        @param orRanges  (output parameter) If the token sequence is valid,
+            this parameter will contain the extracted cell range list. Deleted
+            cells or cell ranges (shown as #REF! error in a formula) will be
+            skipped. If the token sequence contains unexpected tokens, an empty
+            list is returned here.
+
+        @param rTokens  The token sequence to be parsed. Should contain cell
+            address tokens or cell range address tokens, separated by the
+            standard function parameter separator token. The token sequence may
+            contain parentheses and whitespace tokens.
+
+        @param bAllowRelative  True = it is allowed that rTokens contains
+            relative references (based on cell A1 of the current sheet).
+            False = only real absolute references will be accepted.
+
+        @param nFilterBySheet  If non-negative, this function returns only cell
+            ranges located in the specified sheet, otherwise returns all cell
+            ranges contained in the token sequence.
+     */
+    void                extractCellRangeList(
+                            ApiCellRangeList& orRanges,
+                            const ApiTokenSequence& rTokens,
+                            bool bAllowRelative,
+                            sal_Int32 nFilterBySheet = -1 ) const;
+
+    /** Tries to extract a string from a formula token sequence.
+
+        @param orString  (output parameter) The extracted string.
+
+        @param rTokens  The token sequence to be parsed. Should contain exactly
+            one string token, may contain whitespace tokens.
+
+        @return  True = token sequence is valid, output parameter orString
+            contains the string extracted from the token sequence.
+     */
+    bool                extractString(
+                            ::rtl::OUString& orString,
+                            const ApiTokenSequence& rTokens ) const;
+
+    /** Tries to extract information about a special token used for array
+        formulas, shared formulas, or table operations.
+
+        @param orTokenInfo  (output parameter) The extracted information about
+            the token. Contains the base address and the token type (sal_False
+            for array or shared formulas, sal_True for table operations).
+
+        @param rTokens  The token sequence to be parsed. If it contains exactly
+            one OPCODE_BAD token with special token information, this
+            information will be extracted.
+
+        @return  True = token sequence is valid, output parameter orTokenInfo
+            contains the token information extracted from the token sequence.
+     */
+    bool                extractSpecialTokenInfo(
+                            ApiSpecialTokenInfo& orTokenInfo,
+                            const ApiTokenSequence& rTokens ) const;
+
+    /** Converts a single string with separators in the passed formula token
+        sequence to a list of string tokens.
+
+        @param orTokens  (input/output parameter) Expects a single string token
+            in this token sequence (whitespace tokens are allowed). The string
+            is split into substrings. A list of string tokens separated with
+            parameter separator tokens is returned in this psrameter.
+
+        @param cStringSep  The separator character used to split the input
+            string.
+
+        @param bTrimLeadingSpaces  True = removes leading whitespace from all
+            substrings inserted into the formula token sequence.
+     */
+    void                convertStringToStringList(
+                            ApiTokenSequence& orTokens,
+                            sal_Unicode cStringSep,
+                            bool bTrimLeadingSpaces ) const;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/formulaparser.hxx b/sc/source/filter/inc/formulaparser.hxx
new file mode 100644
index 000000000000..6bbe5fc2651b
--- /dev/null
+++ b/sc/source/filter/inc/formulaparser.hxx
@@ -0,0 +1,166 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_FORMULAPARSER_HXX
+#define OOX_XLS_FORMULAPARSER_HXX
+
+#include "formulabase.hxx"
+
+namespace oox {
+namespace xls {
+
+// formula finalizer ==========================================================
+
+/** A generic formula token array finalizer.
+
+    After building a formula token array from alien binary file formats, or
+    parsing an XML formula string using the com.sun.star.sheet.FormulaParser
+    service, the token array is still not ready to be put into the spreadsheet
+    document. There may be functions with a wrong number of parameters (missing
+    but required parameters, or unsupported parameters) or intermediate tokens
+    used to encode references to macro functions or add-in functions. This
+    helper processes a passed token array and builds a new compatible token
+    array.
+
+    Derived classes may add more functionality by overwriting the virtual
+    functions.
+ */
+class FormulaFinalizer : public OpCodeProvider, protected ApiOpCodes
+{
+public:
+    explicit            FormulaFinalizer( const OpCodeProvider& rOpCodeProv );
+
+    /** Finalizes and returns the passed token array. */
+    ApiTokenSequence    finalizeTokenArray( const ApiTokenSequence& rTokens );
+
+protected:
+    /** Derived classed may try to find a function info struct from the passed
+        string extracted from an OPCODE_BAD token.
+
+        @param rTokenData  The string that has been found in an OPCODE_BAD
+            token preceding the function parentheses.
+     */
+    virtual const FunctionInfo* resolveBadFuncName( const ::rtl::OUString& rTokenData ) const;
+
+    /** Derived classed may try to find the name of a defined name with the
+        passed index extracted from an OPCODE_NAME token.
+
+        @param nTokenIndex  The index of the defined name that has been found
+            in an OPCODE_NAME token preceding the function parentheses.
+     */
+    virtual ::rtl::OUString resolveDefinedName( sal_Int32 nTokenIndex ) const;
+
+private:
+    typedef ::std::vector< const ApiToken* > ParameterPosVector;
+
+    const FunctionInfo* getFunctionInfo( ApiToken& orFuncToken );
+    const FunctionInfo* getExternCallInfo( ApiToken& orFuncToken, const ApiToken& rECToken );
+
+    void                processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd );
+    const ApiToken*     processParameters( const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd );
+
+    bool                isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+    const ApiToken*     getSingleToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+    const ApiToken*     skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+    const ApiToken*     findParameters( ParameterPosVector& rParams, const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+    void                appendEmptyParameter( const FunctionInfo& rFuncInfo, size_t nParam );
+    void                appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam );
+    void                appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount );
+
+    bool                appendFinalToken( const ApiToken& rToken );
+
+private:
+    ApiTokenVector      maTokens;
+};
+
+// ============================================================================
+
+class FormulaParserImpl;
+
+/** Import formula parser for OOXML and BIFF filters.
+
+    This class implements formula import for the OOXML and BIFF filter. One
+    instance is contained in the global filter data to prevent construction and
+    destruction of internal buffers for every imported formula.
+ */
+class FormulaParser : public FormulaProcessorBase
+{
+public:
+    explicit            FormulaParser( const WorkbookHelper& rHelper );
+    virtual             ~FormulaParser();
+
+    /** Converts an OOXML formula string. */
+    ApiTokenSequence    importFormula(
+                            const ::com::sun::star::table::CellAddress& rBaseAddr,
+                            const ::rtl::OUString& rFormulaString ) const;
+
+    /** Imports and converts a BIFF12 token array from the passed stream. */
+    ApiTokenSequence    importFormula(
+                            const ::com::sun::star::table::CellAddress& rBaseAddr,
+                            FormulaType eType,
+                            SequenceInputStream& rStrm ) const;
+
+    /** Imports and converts a BIFF2-BIFF8 token array from the passed stream.
+        @param pnFmlaSize  Size of the token array. If null is passed, reads
+        it from stream (1 byte in BIFF2, 2 bytes otherwise) first. */
+    ApiTokenSequence    importFormula(
+                            const ::com::sun::star::table::CellAddress& rBaseAddr,
+                            FormulaType eType,
+                            BiffInputStream& rStrm,
+                            const sal_uInt16* pnFmlaSize = 0 ) const;
+
+    /** Converts the passed Boolean value to a similar formula. */
+    ApiTokenSequence    convertBoolToFormula( bool bValue ) const;
+
+    /** Converts the passed BIFF error code to a similar formula. */
+    ApiTokenSequence    convertErrorToFormula( sal_uInt8 nErrorCode ) const;
+
+    /** Converts the passed token index of a defined name to a formula calling that name. */
+    ApiTokenSequence    convertNameToFormula( sal_Int32 nTokenIndex ) const;
+
+    /** Converts the passed XML formula to an OLE link target. */
+    ::rtl::OUString     importOleTargetLink( const ::rtl::OUString& rFormulaString );
+
+    /** Imports and converts an OLE link target from the passed stream. */
+    ::rtl::OUString     importOleTargetLink( SequenceInputStream& rStrm );
+
+    /** Converts the passed formula to a macro name for a drawing shape. */
+    ::rtl::OUString     importMacroName( const ::rtl::OUString& rFormulaString );
+
+private:
+    ::std::auto_ptr< FormulaParserImpl > mxImpl;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/numberformatsbuffer.hxx b/sc/source/filter/inc/numberformatsbuffer.hxx
new file mode 100644
index 000000000000..5914ab90c6b8
--- /dev/null
+++ b/sc/source/filter/inc/numberformatsbuffer.hxx
@@ -0,0 +1,141 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_NUMBERFORMATSBUFFER_HXX
+#define OOX_XLS_NUMBERFORMATSBUFFER_HXX
+
+#include 
+#include "workbookhelper.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace util { class XNumberFormats; }
+} } }
+
+namespace oox { class PropertyMap; }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+struct NumFmtModel
+{
+    ::com::sun::star::lang::Locale maLocale;
+    ::rtl::OUString     maFmtCode;
+    sal_Int16           mnPredefId;
+
+    explicit            NumFmtModel();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains all API number format attributes. */
+struct ApiNumFmtData
+{
+    sal_Int32           mnIndex;            /// API number format index.
+
+    explicit            ApiNumFmtData();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains all data for a number format code. */
+class NumberFormat : public WorkbookHelper
+{
+public:
+    explicit            NumberFormat( const WorkbookHelper& rHelper );
+
+    /** Sets the passed format code. */
+    void                setFormatCode( const ::rtl::OUString& rFmtCode );
+    /** Sets the passed format code, encoded in UTF-8. */
+    void                setFormatCode(
+                            const ::com::sun::star::lang::Locale& rLocale,
+                            const sal_Char* pcFmtCode );
+    /** Sets the passed predefined format code identifier. */
+    void                setPredefinedId(
+                            const ::com::sun::star::lang::Locale& rLocale,
+                            sal_Int16 nPredefId );
+
+    /** Final processing after import of all style settings. Returns the API format index. */
+    sal_Int32           finalizeImport(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormats >& rxNumFmts,
+                            const ::com::sun::star::lang::Locale& rFromLocale );
+
+    /** Writes the number format to the passed property map. */
+    void                writeToPropertyMap( PropertyMap& rPropMap ) const;
+
+private:
+    NumFmtModel         maModel;
+    ApiNumFmtData       maApiData;
+};
+
+typedef ::boost::shared_ptr< NumberFormat > NumberFormatRef;
+
+// ============================================================================
+
+class NumberFormatsBuffer : public WorkbookHelper
+{
+public:
+    explicit            NumberFormatsBuffer( const WorkbookHelper& rHelper );
+
+    /** Inserts a new number format. */
+    NumberFormatRef     createNumFmt( sal_Int32 nNumFmtId, const ::rtl::OUString& rFmtCode );
+
+    /** Inserts a new number format code. */
+    NumberFormatRef     importNumFmt( const AttributeList& rAttribs );
+    /** Inserts a new number format code from a NUMFMT record. */
+    void                importNumFmt( SequenceInputStream& rStrm );
+    /** Inserts a new number format code from a FORMAT record. */
+    void                importFormat( BiffInputStream& rStrm );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Writes the specified number format to the passed property map. */
+    void                writeToPropertyMap( PropertyMap& rPropMap, sal_Int32 nNumFmtId ) const;
+
+private:
+    /** Inserts built-in number formats for the current system language. */
+    void                insertBuiltinFormats();
+
+private:
+    typedef RefMap< sal_Int32, NumberFormat > NumberFormatMap;
+
+    NumberFormatMap     maNumFmts;          /// List of number formats.
+    ::rtl::OUString     maLocaleStr;        /// Current office locale.
+    sal_Int32           mnNextBiffIndex;    /// Format id counter for BIFF2-BIFF4.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/ooxformulaparser.hxx b/sc/source/filter/inc/ooxformulaparser.hxx
new file mode 100644
index 000000000000..757aec615860
--- /dev/null
+++ b/sc/source/filter/inc/ooxformulaparser.hxx
@@ -0,0 +1,111 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_OOXFORMULAPARSER_HXX
+#define OOX_XLS_OOXFORMULAPARSER_HXX
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace oox {
+namespace xls {
+
+class OOXMLFormulaParserImpl;
+
+// ============================================================================
+
+typedef ::cppu::WeakImplHelper3<
+    ::com::sun::star::lang::XServiceInfo,
+    ::com::sun::star::lang::XInitialization,
+    ::com::sun::star::sheet::XFilterFormulaParser > OOXMLFormulaParser_BASE;
+
+/** OOXML formula parser/compiler service for usage in ODF filters. */
+class OOXMLFormulaParser : public OOXMLFormulaParser_BASE
+{
+public:
+    explicit            OOXMLFormulaParser();
+    virtual             ~OOXMLFormulaParser();
+
+    // com.sun.star.lang.XServiceInfo interface -------------------------------
+
+    virtual ::rtl::OUString SAL_CALL
+                        getImplementationName() throw( ::com::sun::star::uno::RuntimeException );
+
+    virtual sal_Bool SAL_CALL
+                        supportsService( const ::rtl::OUString& rService )
+                            throw( ::com::sun::star::uno::RuntimeException );
+
+    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL
+                        getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException );
+
+    // com.sun.star.lang.XInitialization interface ----------------------------
+
+    virtual void SAL_CALL initialize(
+                            const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rArgs )
+                            throw( ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException );
+
+    // com.sun.star.sheet.XFilterFormulaParser interface ----------------------
+
+    virtual ::rtl::OUString SAL_CALL
+                        getSupportedNamespace()
+                            throw( ::com::sun::star::uno::RuntimeException );
+
+    // com.sun.star.sheet.XFormulaParser interface ----------------------------
+
+    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken > SAL_CALL
+                        parseFormula(
+                            const ::rtl::OUString& rFormula,
+                            const ::com::sun::star::table::CellAddress& rReferencePos )
+                        throw( ::com::sun::star::uno::RuntimeException );
+
+    virtual ::rtl::OUString SAL_CALL
+                        printFormula(
+                            const ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken >& rTokens,
+                            const ::com::sun::star::table::CellAddress& rReferencePos )
+                        throw( ::com::sun::star::uno::RuntimeException );
+
+private:
+    typedef ::boost::shared_ptr< OOXMLFormulaParserImpl >   ParserImplRef;
+
+    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >
+                        mxComponent;
+    ParserImplRef       mxParserImpl;       /// Implementation of import parser.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/pagesettings.hxx b/sc/source/filter/inc/pagesettings.hxx
new file mode 100644
index 000000000000..0ce662c5fb66
--- /dev/null
+++ b/sc/source/filter/inc/pagesettings.hxx
@@ -0,0 +1,224 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_PAGESETTINGS_HXX
+#define OOX_XLS_PAGESETTINGS_HXX
+
+#include "worksheethelper.hxx"
+
+namespace oox { class PropertySet; }
+namespace oox { namespace core { class Relations; } }
+
+namespace oox {
+namespace xls {
+
+class HeaderFooterParser;
+
+// ============================================================================
+
+/** Holds page style data for a single sheet. */
+struct PageSettingsModel
+{
+    ::rtl::OUString     maGraphicUrl;           /// URL of the graphic object.
+    ::rtl::OUString     maBinSettPath;          /// Relation identifier of binary printer settings.
+    ::rtl::OUString     maOddHeader;            /// Header string for odd pages.
+    ::rtl::OUString     maOddFooter;            /// Footer string for odd pages.
+    ::rtl::OUString     maEvenHeader;           /// Header string for even pages.
+    ::rtl::OUString     maEvenFooter;           /// Footer string for even pages.
+    ::rtl::OUString     maFirstHeader;          /// Header string for first page of the sheet.
+    ::rtl::OUString     maFirstFooter;          /// Footer string for first page of the sheet.
+    double              mfLeftMargin;           /// Margin between left edge of page and begin of sheet area.
+    double              mfRightMargin;          /// Margin between end of sheet area and right edge of page.
+    double              mfTopMargin;            /// Margin between top egde of page and begin of sheet area.
+    double              mfBottomMargin;         /// Margin between end of sheet area and bottom edge of page.
+    double              mfHeaderMargin;         /// Margin between top edge of page and begin of header.
+    double              mfFooterMargin;         /// Margin between end of footer and bottom edge of page.
+    sal_Int32           mnPaperSize;            /// Paper size (enumeration).
+    sal_Int32           mnPaperWidth;           /// Paper width in twips
+    sal_Int32           mnPaperHeight;          /// Paper height in twips
+    sal_Int32           mnCopies;               /// Number of copies to print.
+    sal_Int32           mnScale;                /// Page scale (zoom in percent).
+    sal_Int32           mnFirstPage;            /// First page number.
+    sal_Int32           mnFitToWidth;           /// Fit to number of pages in horizontal direction.
+    sal_Int32           mnFitToHeight;          /// Fit to number of pages in vertical direction.
+    sal_Int32           mnHorPrintRes;          /// Horizontal printing resolution in DPI.
+    sal_Int32           mnVerPrintRes;          /// Vertical printing resolution in DPI.
+    sal_Int32           mnOrientation;          /// Landscape or portrait.
+    sal_Int32           mnPageOrder;            /// Page order through sheet area (to left or down).
+    sal_Int32           mnCellComments;         /// Cell comments printing mode.
+    sal_Int32           mnPrintErrors;          /// Cell error printing mode.
+    bool                mbUseEvenHF;            /// True = use maEvenHeader/maEvenFooter.
+    bool                mbUseFirstHF;           /// True = use maFirstHeader/maFirstFooter.
+    bool                mbValidSettings;        /// True = use imported settings.
+    bool                mbUseFirstPage;         /// True = start page numbering with mnFirstPage.
+    bool                mbBlackWhite;           /// True = print black and white.
+    bool                mbDraftQuality;         /// True = print in draft quality.
+    bool                mbFitToPages;           /// True = Fit to width/height; false = scale in percent.
+    bool                mbHorCenter;            /// True = horizontally centered.
+    bool                mbVerCenter;            /// True = vertically centered.
+    bool                mbPrintGrid;            /// True = print grid lines.
+    bool                mbPrintHeadings;        /// True = print column/row headings.
+
+    explicit            PageSettingsModel();
+
+    /** Sets the BIFF print errors mode. */
+    void                setBiffPrintErrors( sal_uInt8 nPrintErrors );
+};
+
+// ============================================================================
+
+class PageSettings : public WorksheetHelper
+{
+public:
+    explicit            PageSettings( const WorksheetHelper& rHelper );
+
+    /** Imports printing options from a printOptions element. */
+    void                importPrintOptions( const AttributeList& rAttribs );
+    /** Imports pageMarings element containing page margins. */
+    void                importPageMargins( const AttributeList& rAttribs );
+    /** Imports pageSetup element for worksheets. */
+    void                importPageSetup( const ::oox::core::Relations& rRelations, const AttributeList& rAttribs );
+    /** Imports pageSetup element for chart sheets. */
+    void                importChartPageSetup( const ::oox::core::Relations& rRelations, const AttributeList& rAttribs );
+    /** Imports header and footer settings from a headerFooter element. */
+    void                importHeaderFooter( const AttributeList& rAttribs );
+    /** Imports header/footer characters from a headerFooter element. */
+    void                importHeaderFooterCharacters( const ::rtl::OUString& rChars, sal_Int32 nElement );
+    /** Imports the picture element. */
+    void                importPicture( const ::oox::core::Relations& rRelations, const AttributeList& rAttribs );
+
+    /** Imports the PRINTOPTIONS record from the passed stream. */
+    void                importPrintOptions( SequenceInputStream& rStrm );
+    /** Imports the PAGEMARGINS record from the passed stream. */
+    void                importPageMargins( SequenceInputStream& rStrm );
+    /** Imports the PAGESETUP record from the passed stream. */
+    void                importPageSetup( const ::oox::core::Relations& rRelations, SequenceInputStream& rStrm );
+    /** Imports the CHARTPAGESETUP record from the passed stream. */
+    void                importChartPageSetup( const ::oox::core::Relations& rRelations, SequenceInputStream& rStrm );
+    /** Imports the HEADERFOOTER record from the passed stream. */
+    void                importHeaderFooter( SequenceInputStream& rStrm );
+    /** Imports the PICTURE record from the passed stream. */
+    void                importPicture( const ::oox::core::Relations& rRelations, SequenceInputStream& rStrm );
+
+    /** Imports the LEFTMARGIN record from the passed BIFF stream. */
+    void                importLeftMargin( BiffInputStream& rStrm );
+    /** Imports the RIGHTMARGIN record from the passed BIFF stream. */
+    void                importRightMargin( BiffInputStream& rStrm );
+    /** Imports the TOPMARGIN record from the passed BIFF stream. */
+    void                importTopMargin( BiffInputStream& rStrm );
+    /** Imports the BOTTOMMARGIN record from the passed BIFF stream. */
+    void                importBottomMargin( BiffInputStream& rStrm );
+    /** Imports the SETUP record from the passed BIFF stream. */
+    void                importPageSetup( BiffInputStream& rStrm );
+    /** Imports the HCENTER record from the passed BIFF stream. */
+    void                importHorCenter( BiffInputStream& rStrm );
+    /** Imports the VCENTER record from the passed BIFF stream. */
+    void                importVerCenter( BiffInputStream& rStrm );
+    /** Imports the PRINTHEADERS record from the passed BIFF stream. */
+    void                importPrintHeaders( BiffInputStream& rStrm );
+    /** Imports the PRINTGRIDLINES record from the passed BIFF stream. */
+    void                importPrintGridLines( BiffInputStream& rStrm );
+    /** Imports the HEADER record from the passed BIFF stream. */
+    void                importHeader( BiffInputStream& rStrm );
+    /** Imports the FOOTER record from the passed BIFF stream. */
+    void                importFooter( BiffInputStream& rStrm );
+    /** Imports the PICTURE record from the passed BIFF stream. */
+    void                importPicture( BiffInputStream& rStrm );
+
+    /** Sets whether percentual scaling or fit to width/height scaling is used. */
+    void                setFitToPagesMode( bool bFitToPages );
+
+    /** Creates a page style for the spreadsheet and sets all page properties. */
+    void                finalizeImport();
+
+private:
+    /** Imports the binary picture data from the fragment with the passed identifier. */
+    void                importPictureData( const ::oox::core::Relations& rRelations, const ::rtl::OUString& rRelId );
+
+private:
+    PageSettingsModel   maModel;
+};
+
+// ============================================================================
+
+class PageSettingsConverter : public WorkbookHelper
+{
+public:
+    explicit            PageSettingsConverter( const WorkbookHelper& rHelper );
+    virtual             ~PageSettingsConverter();
+
+    /** Writes all properties to the passed property set of a page style object. */
+    void                writePageSettingsProperties(
+                            PropertySet& rPropSet,
+                            const PageSettingsModel& rModel,
+                            WorksheetType eSheetType );
+
+private:
+    struct HFHelperData
+    {
+        sal_Int32           mnLeftPropId;
+        sal_Int32           mnRightPropId;
+        sal_Int32           mnHeight;
+        sal_Int32           mnBodyDist;
+        bool                mbHasContent;
+        bool                mbShareOddEven;
+        bool                mbDynamicHeight;
+
+        explicit            HFHelperData( sal_Int32 nLeftPropId, sal_Int32 nRightPropId );
+    };
+
+private:
+    void                convertHeaderFooterData(
+                            PropertySet& rPropSet,
+                            HFHelperData& orHFData,
+                            const ::rtl::OUString rOddContent,
+                            const ::rtl::OUString rEvenContent,
+                            bool bUseEvenContent,
+                            double fPageMargin,
+                            double fContentMargin );
+
+    sal_Int32           writeHeaderFooter(
+                            PropertySet& rPropSet,
+                            sal_Int32 nPropId,
+                            const ::rtl::OUString& rContent );
+
+private:
+    typedef ::std::auto_ptr< HeaderFooterParser > HeaderFooterParserPtr;
+    HeaderFooterParserPtr mxHFParser;
+    HFHelperData        maHeaderData;
+    HFHelperData        maFooterData;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/pivotcachebuffer.hxx b/sc/source/filter/inc/pivotcachebuffer.hxx
new file mode 100644
index 000000000000..3c339160054d
--- /dev/null
+++ b/sc/source/filter/inc/pivotcachebuffer.hxx
@@ -0,0 +1,532 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_PIVOTCACHEBUFFER_HXX
+#define OOX_XLS_PIVOTCACHEBUFFER_HXX
+
+#include 
+#include 
+#include 
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/refvector.hxx"
+#include "workbookhelper.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace sheet { class XDataPilotField; }
+} } }
+
+namespace oox { namespace core { class Relations; } }
+
+namespace oox {
+namespace xls {
+
+class WorksheetHelper;
+
+// ============================================================================
+
+typedef ::std::pair< sal_Int32, rtl::OUString > IdCaptionPair;
+typedef ::std::vector< IdCaptionPair > IdCaptionPairList;
+
+class PivotCacheItem
+{
+public:
+    explicit            PivotCacheItem();
+
+    /** Reads the string value from a pivot cache item. */
+    void                readString( const AttributeList& rAttribs );
+    /** Reads the double value from a pivot cache item. */
+    void                readNumeric( const AttributeList& rAttribs );
+    /** Reads the date/time value from a pivot cache item. */
+    void                readDate( const AttributeList& rAttribs );
+    /** Reads the boolean value from a pivot cache item. */
+    void                readBool( const AttributeList& rAttribs );
+    /** Reads the error code value from a pivot cache item. */
+    void                readError( const AttributeList& rAttribs, const UnitConverter& rUnitConverter );
+    /** Reads the index of a shared item. */
+    void                readIndex( const AttributeList& rAttribs );
+
+    /** Reads the string value from a pivot cache item. */
+    void                readString( SequenceInputStream& rStrm );
+    /** Reads the double value from a pivot cache item. */
+    void                readDouble( SequenceInputStream& rStrm );
+    /** Reads the date/time value from a pivot cache item. */
+    void                readDate( SequenceInputStream& rStrm );
+    /** Reads the boolean value from a pivot cache item. */
+    void                readBool( SequenceInputStream& rStrm );
+    /** Reads the error code value from a pivot cache item. */
+    void                readError( SequenceInputStream& rStrm );
+    /** Reads the index of a shared item. */
+    void                readIndex( SequenceInputStream& rStrm );
+
+    /** Reads the string value from a pivot cache item. */
+    void                readString( BiffInputStream& rStrm, const WorkbookHelper& rHelper );
+    /** Reads the double value from a pivot cache item. */
+    void                readDouble( BiffInputStream& rStrm );
+    /** Reads the integer value from a pivot cache item. */
+    void                readInteger( BiffInputStream& rStrm );
+    /** Reads the date/time value from a pivot cache item. */
+    void                readDate( BiffInputStream& rStrm );
+    /** Reads the boolean value from a pivot cache item. */
+    void                readBool( BiffInputStream& rStrm );
+    /** Reads the error code value from a pivot cache item. */
+    void                readError( BiffInputStream& rStrm );
+
+    /** Returns the type of the item. */
+    inline sal_Int32    getType() const { return mnType; }
+    /** Returns the value of the item. */
+    inline const ::com::sun::star::uno::Any& getValue() const { return maValue; }
+    /** Returns the string representation of the item. */
+    ::rtl::OUString     getName() const;
+    /** Returns true if the item is unused. */
+    inline bool         isUnused() const { return mbUnused; }
+
+private:
+friend class PivotCacheItemList;
+    // #FIXME hack Sets the value of this item to the given string ( and overwrites type if necessary
+    void                setStringValue( const rtl::OUString& sName );
+    ::com::sun::star::uno::Any maValue;     /// Value of the item.
+    sal_Int32           mnType;             /// Value type (OOXML token identifier).
+    bool                mbUnused;
+};
+
+// ----------------------------------------------------------------------------
+
+class PivotCacheItemList : public WorkbookHelper
+{
+public:
+    explicit            PivotCacheItemList( const WorkbookHelper& rHelper );
+
+    /** Imports the item from the passed attribute list. */
+    void                importItem( sal_Int32 nElement, const AttributeList& rAttribs );
+    /** Imports the item from the passed stream and record. */
+    void                importItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    /** Imports a complete item list from the passed stream. */
+    void                importItemList( BiffInputStream& rStrm, sal_uInt16 nCount );
+
+    /** Returns true, if this item list is empty. */
+    inline bool         empty() const { return maItems.empty(); }
+    /** Returns the size of the item list. */
+    inline size_t       size() const { return maItems.size(); }
+
+    /** Returns the specified item. */
+    const PivotCacheItem* getCacheItem( sal_Int32 nItemIdx ) const;
+    /** Returns the names of all items. */
+    void                getCacheItemNames( ::std::vector< ::rtl::OUString >& orItemNames ) const;
+    void                applyItemCaptions( const IdCaptionPairList& vCaptions );
+
+private:
+    /** Creates and returns a new item at the end of the items list. */
+    PivotCacheItem&     createItem();
+    /** Imports an array of items from the PCITEM_ARRAY record */
+    void                importArray( SequenceInputStream& rStrm );
+
+private:
+    typedef ::std::vector< PivotCacheItem > CacheItemVector;
+    CacheItemVector     maItems;            /// All items of this list.
+};
+
+// ============================================================================
+
+struct PCFieldModel
+{
+    ::rtl::OUString     maName;             /// Fixed name of the cache field.
+    ::rtl::OUString     maCaption;          /// Caption of the ccahe field.
+    ::rtl::OUString     maPropertyName;     /// OLAP property name.
+    ::rtl::OUString     maFormula;          /// Formula of a calculated field.
+    sal_Int32           mnNumFmtId;         /// Number format for all items.
+    sal_Int32           mnSqlType;          /// Data type from ODBC data source.
+    sal_Int32           mnHierarchy;        /// Hierarchy this field is part of.
+    sal_Int32           mnLevel;            /// Hierarchy level this field is part of.
+    sal_Int32           mnMappingCount;     /// Number of property mappings.
+    bool                mbDatabaseField;    /// True = field from source data; false = calculated field.
+    bool                mbServerField;      /// True = ODBC server-based page field.
+    bool                mbUniqueList;       /// True = list of unique ODBC items exists.
+    bool                mbMemberPropField;  /// True = contains OLAP member properties.
+
+    explicit            PCFieldModel();
+};
+
+// ----------------------------------------------------------------------------
+
+struct PCSharedItemsModel
+{
+    bool                mbHasSemiMixed;     /// True = has (blank|string|bool|error) item(s), maybe other types.
+    bool                mbHasNonDate;       /// True = has non-date item(s), maybe date items.
+    bool                mbHasDate;          /// True = has date item(s), maybe other types.
+    bool                mbHasString;        /// True = has (string|bool|error) item(s), maybe other types.
+    bool                mbHasBlank;         /// True = has blank item(s), maybe other types.
+    bool                mbHasMixed;         /// True = has [(string|bool|error) and (number|date)] or (number and date).
+    bool                mbIsNumeric;        /// True = has numeric item(s), maybe other types except date.
+    bool                mbIsInteger;        /// True = has numeric item(s) with only integers, maybe other types except date.
+    bool                mbHasLongText;      /// True = contains strings with >255 charascters.
+    bool                mbHasLongIndexes;   /// True = indexes to shared items are 16-bit (BIFF only).
+
+    explicit            PCSharedItemsModel();
+};
+
+// ----------------------------------------------------------------------------
+
+struct PCFieldGroupModel
+{
+    ::com::sun::star::util::DateTime maStartDate;   /// Manual or calculated start date for range grouping.
+    ::com::sun::star::util::DateTime maEndDate;     /// Manual or calculated end date for range grouping.
+    double              mfStartValue;       /// Manual or calculated start value for range grouping.
+    double              mfEndValue;         /// Manual or calculated end value for range grouping.
+    double              mfInterval;         /// Interval for numeric range grouping.
+    sal_Int32           mnParentField;      /// Index of cache field that contains item groups based on this field.
+    sal_Int32           mnBaseField;        /// Index of cache field this grouped field is based on.
+    sal_Int32           mnGroupBy;          /// Type of numeric or date range grouping.
+    bool                mbRangeGroup;       /// True = items are grouped by numeric ranges or date ranges.
+    bool                mbDateGroup;        /// True = items are grouped by date ranges or by item names.
+    bool                mbAutoStart;        /// True = start value for range groups is calculated from source data.
+    bool                mbAutoEnd;          /// True = end value for range groups is calculated from source data.
+
+    explicit            PCFieldGroupModel();
+
+    /** Sets the group-by value for BIFF import. */
+    void                setBiffGroupBy( sal_uInt8 nGroupBy );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Helper struct for mapping original item names from/to group item names. */
+struct PivotCacheGroupItem
+{
+    ::rtl::OUString     maOrigName;
+    ::rtl::OUString     maGroupName;
+
+    inline explicit     PivotCacheGroupItem( const ::rtl::OUString& rItemName ) :
+                            maOrigName( rItemName ), maGroupName( rItemName ) {}
+};
+
+typedef ::std::vector< PivotCacheGroupItem > PivotCacheGroupItemVector;
+
+// ----------------------------------------------------------------------------
+
+class PivotCacheField : public WorkbookHelper
+{
+public:
+    explicit            PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField );
+
+    /** Imports pivot cache field settings from the cacheField element. */
+    void                importCacheField( const AttributeList& rAttribs );
+    /** Imports shared items settings from the sharedItems element. */
+    void                importSharedItems( const AttributeList& rAttribs );
+    /** Imports a shared item from the passed element. */
+    void                importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs );
+    /** Imports grouping settings from the fieldGroup element. */
+    void                importFieldGroup( const AttributeList& rAttribs );
+    /** Imports numeric grouping settings from the rangePr element. */
+    void                importRangePr( const AttributeList& rAttribs );
+    /** Imports an item of the mapping between group items and base items from the passed element. */
+    void                importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs );
+    /** Imports a group item from the passed element. */
+    void                importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs );
+
+    /** Imports pivot cache field settings from the PCDFIELD record. */
+    void                importPCDField( SequenceInputStream& rStrm );
+    /** Imports shared items settings from the PCDFSHAREDITEMS record. */
+    void                importPCDFSharedItems( SequenceInputStream& rStrm );
+    /** Imports one or more shared items from the passed record. */
+    void                importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    /** Imports grouping settings from the PCDFIELDGROUP record. */
+    void                importPCDFieldGroup( SequenceInputStream& rStrm );
+    /** Imports numeric grouping settings from the PCDFRANGEPR record. */
+    void                importPCDFRangePr( SequenceInputStream& rStrm );
+    /** Imports an item of the mapping between group items and base items from the passed record. */
+    void                importPCDFDiscretePrItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    /** Imports one or more group items from the passed record. */
+    void                importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    /** Imports pivot cache field settings from the PCDFIELD record. */
+    void                importPCDField( BiffInputStream& rStrm );
+    /** Imports numeric grouping settings from the PCDFRANGEPR record. */
+    void                importPCDFRangePr( BiffInputStream& rStrm );
+    /** Imports the mapping between group items and base items from the PCDFDISCRETEPR record. */
+    void                importPCDFDiscretePr( BiffInputStream& rStrm );
+    /** Apply user Captions to imported group data */
+    void                applyItemCaptions( const IdCaptionPairList& vCaptions );
+
+    /** Returns true, if the field is based on source data, or false if it is grouped or calculated. */
+    inline bool         isDatabaseField() const { return maFieldModel.mbDatabaseField; }
+
+    /** Returns true, if the field contains a list of shared items. */
+    inline bool         hasSharedItems() const { return !maSharedItems.empty(); }
+    /** Returns true, if the field contains a list of grouping items. */
+    inline bool         hasGroupItems() const { return !maGroupItems.empty(); }
+    /** Returns true, if the field has inplace numeric grouping settings. */
+    inline bool         hasNumericGrouping() const { return maFieldGroupModel.mbRangeGroup && !maFieldGroupModel.mbDateGroup; }
+    /** Returns true, if the field has inplace date grouping settings. */
+    inline bool         hasDateGrouping() const { return maFieldGroupModel.mbRangeGroup && maFieldGroupModel.mbDateGroup; }
+    /** Returns true, if the field has a parent group field that groups the items of this field. */
+    inline bool         hasParentGrouping() const { return maFieldGroupModel.mnParentField >= 0; }
+
+    /** Returns the name of the cache field. */
+    inline const ::rtl::OUString& getName() const { return maFieldModel.maName; }
+    /** Returns the index of the parent group field that groups the items of this field. */
+    inline sal_Int32    getParentGroupField() const { return maFieldGroupModel.mnParentField; }
+    /** Returns the index of the base field grouping is based on. */
+    inline sal_Int32    getGroupBaseField() const { return maFieldGroupModel.mnBaseField; }
+
+    /** Returns the shared or group item with the specified index. */
+    const PivotCacheItem* getCacheItem( sal_Int32 nItemIdx ) const;
+    /** Returns the names of all shared or group items. */
+    void                getCacheItemNames( ::std::vector< ::rtl::OUString >& orItemNames ) const;
+    /** Returns shared or group items. */
+    PivotCacheItemList  getCacheItems() const;
+
+    /** Creates inplace numeric grouping settings. */
+    void                convertNumericGrouping(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >& rxDPField ) const;
+    /** Creates inplace date grouping settings or a new date group field. */
+    ::rtl::OUString     createDateGroupField(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >& rxBaseDPField ) const;
+    /** Creates a new grouped DataPilot field and returns its name. */
+    ::rtl::OUString     createParentGroupField(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >& rxBaseDPField,
+                            const PivotCacheField& rBaseCacheField,
+                            PivotCacheGroupItemVector& orItemNames ) const;
+
+    /** Writes the title of the field into the passed sheet at the passed address. */
+    void                writeSourceHeaderCell( WorksheetHelper& rSheetHelper,
+                            sal_Int32 nCol, sal_Int32 nRow ) const;
+    /** Writes a source field item value into the passed sheet. */
+    void                writeSourceDataCell( WorksheetHelper& rSheetHelper,
+                            sal_Int32 nCol, sal_Int32 nRow,
+                            const PivotCacheItem& rItem ) const;
+
+    /** Reads an item from the PCRECORD record and writes it to the passed sheet. */
+    void                importPCRecordItem( SequenceInputStream& rStrm,
+                            WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const;
+    /** Reads an item index from the PCITEM_INDEXLIST record and writes the item to the passed sheet. */
+    void                importPCItemIndex( BiffInputStream& rStrm,
+                            WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const;
+
+private:
+    /** Tries to write the passed value to the passed sheet position. */
+    void                writeItemToSourceDataCell( WorksheetHelper& rSheetHelper,
+                            sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const;
+    /** Tries to write the value of a shared item to the passed sheet position. */
+    void                writeSharedItemToSourceDataCell( WorksheetHelper& rSheetHelper,
+                            sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const;
+
+private:
+    typedef ::std::vector< sal_Int32 > IndexVector;
+
+    PivotCacheItemList  maSharedItems;      /// All shared items of this field.
+    PivotCacheItemList  maGroupItems;       /// All group items of this field.
+    IndexVector         maDiscreteItems;    /// Mapping between group and base items.
+    PCFieldModel        maFieldModel;       /// Settings for this cache field.
+    PCSharedItemsModel  maSharedItemsModel; /// Settings for shared items.
+    PCFieldGroupModel   maFieldGroupModel;  /// Settings for item grouping.
+};
+
+// ============================================================================
+
+struct PCDefinitionModel
+{
+    ::rtl::OUString     maRelId;            /// Relation identifier for cache records fragment.
+    ::rtl::OUString     maRefreshedBy;      /// Name of user who last refreshed the cache.
+    double              mfRefreshedDate;    /// Date/time of last refresh.
+    sal_Int32           mnRecords;          /// Number of data records in the cache.
+    sal_Int32           mnMissItemsLimit;   /// Limit for discarding unused items.
+    sal_uInt16          mnDatabaseFields;   /// Number of database (source data) fields (BIFF only).
+    bool                mbInvalid;          /// True = cache needs refresh.
+    bool                mbSaveData;         /// True = cached item values are present.
+    bool                mbRefreshOnLoad;    /// True = try to refresh cache on load.
+    bool                mbOptimizeMemory;   /// True = application may optimize memory usage.
+    bool                mbEnableRefresh;    /// True = refreshing cache is enabled in UI.
+    bool                mbBackgroundQuery;  /// True = application queries data asynchonously.
+    bool                mbUpgradeOnRefresh; /// True = application may upgrade cache version.
+    bool                mbTupleCache;       /// True = cache stores OLAP functions.
+    bool                mbSupportSubquery;  /// True = data source supports subqueries.
+    bool                mbSupportDrill;     /// True = data source supports drilldown.
+
+    explicit            PCDefinitionModel();
+};
+
+// ----------------------------------------------------------------------------
+
+struct PCSourceModel
+{
+    sal_Int32           mnSourceType;       /// Type of the source data (sheet, consolidation, scenario, external).
+    sal_Int32           mnConnectionId;     /// Connection identifier for external data source.
+
+    explicit            PCSourceModel();
+};
+
+// ----------------------------------------------------------------------------
+
+struct PCWorksheetSourceModel
+{
+    ::rtl::OUString     maRelId;            /// Relation identifier for an external document URL.
+    ::rtl::OUString     maSheet;            /// Sheet name for cell range or sheet-local defined names.
+    ::rtl::OUString     maDefName;          /// Defined name containing a cell range if present.
+    ::com::sun::star::table::CellRangeAddress
+                        maRange;            /// Source cell range of the data.
+
+    explicit            PCWorksheetSourceModel();
+};
+
+// ----------------------------------------------------------------------------
+
+class PivotCache : public WorkbookHelper
+{
+public:
+    explicit            PivotCache( const WorkbookHelper& rHelper );
+
+    /** Reads pivot cache global settings from the pivotCacheDefinition element. */
+    void                importPivotCacheDefinition( const AttributeList& rAttribs );
+    /** Reads cache source settings from the cacheSource element. */
+    void                importCacheSource( const AttributeList& rAttribs );
+    /** Reads sheet source settings from the worksheetSource element. */
+    void                importWorksheetSource( const AttributeList& rAttribs, const ::oox::core::Relations& rRelations );
+
+    /** Reads pivot cache global settings from the PCDEFINITION record. */
+    void                importPCDefinition( SequenceInputStream& rStrm );
+    /** Reads cache source settings from the PCDSOURCE record. */
+    void                importPCDSource( SequenceInputStream& rStrm );
+    /** Reads sheet source settings from the PCDSHEETSOURCE record. */
+    void                importPCDSheetSource( SequenceInputStream& rStrm, const ::oox::core::Relations& rRelations );
+
+    /** Reads cache source settings from the PCDSOURCE record. */
+    void                importPCDSource( BiffInputStream& rStrm );
+    /** Reads pivot cache global settings from the PCDEFINITION record. */
+    void                importPCDefinition( BiffInputStream& rStrm );
+
+    /** Creates and returns a new pivot cache field. */
+    PivotCacheField&    createCacheField( bool bInitDatabaseField = false );
+    /** Checks validity of source data and creates a dummy data sheet for external sheet sources. */
+    void                finalizeImport();
+
+    /** Returns true, if the pivot cache is based on a valid data source, so
+        that pivot tables can be created based on this pivot cache. */
+    inline bool         isValidDataSource() const { return mbValidSource; }
+    /** Returns true, if the pivot cache is based on a dummy sheet created in finalizeImport. */
+    inline bool         isBasedOnDummySheet() const { return mbDummySheet; }
+    /** Returns the internal cell range the cache is based on. */
+    inline const ::com::sun::star::table::CellRangeAddress&
+                        getSourceRange() const { return maSheetSrcModel.maRange; }
+    /** Returns the relation identifier of the pivot cache records fragment. */
+    inline const ::rtl::OUString& getRecordsRelId() const { return maDefModel.maRelId; }
+
+    /** Returns the number of pivot cache fields. */
+    sal_Int32           getCacheFieldCount() const;
+    /** Returns the cache field with the specified index. */
+    const PivotCacheField* getCacheField( sal_Int32 nFieldIdx ) const;
+    /** Returns the source column index of the field with the passed index. */
+    sal_Int32           getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const;
+
+    /** Writes the titles of all source fields into the passed sheet. */
+    void                writeSourceHeaderCells( WorksheetHelper& rSheetHelper ) const;
+    /** Writes a source field item value into the passed sheet. */
+    void                writeSourceDataCell( WorksheetHelper& rSheetHelper,
+                            sal_Int32 nColIdx, sal_Int32 nRowIdx,
+                            const PivotCacheItem& rItem ) const;
+
+    /** Reads a PCRECORD record and writes all item values to the passed sheet. */
+    void                importPCRecord( SequenceInputStream& rStrm,
+                            WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const;
+    /** Reads a PCITEM_INDEXLIST record and writes all item values to the passed sheet. */
+    void                importPCItemIndexList( BiffInputStream& rStrm,
+                            WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const;
+
+private:
+    /** Reads the worksheet source range from the DCONREF record. */
+    void                importDConRef( BiffInputStream& rStrm );
+    /** Reads the defined name used for source data from the DCONNAME record. */
+    void                importDConName( BiffInputStream& rStrm );
+    /** Reads the built-in defined name used for source data from the DCONBINAME record. */
+    void                importDConBIName( BiffInputStream& rStrm );
+    /** Reads the sheet name and URL from the DCONREF, DCONNAME, or DCONBINAME records. */
+    void                importDConUrl( BiffInputStream& rStrm );
+
+    /** Finalizes the pivot cache if it is based on internal sheet data. */
+    void                finalizeInternalSheetSource();
+    /** Finalizes the pivot cache if it is based on sheet data of an external spreadsheet document. */
+    void                finalizeExternalSheetSource();
+    /** Creates a dummy sheet that will be filled with the pivot cache data. */
+    void                prepareSourceDataSheet();
+    /** Checks, if the row index has changed since last call, and initializes the sheet data buffer. */
+    void                updateSourceDataRow( WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const;
+
+private:
+    typedef RefVector< PivotCacheField >    PivotCacheFieldVector;
+    typedef ::std::vector< sal_Int32 >      IndexVector;
+
+    PivotCacheFieldVector maFields;         /// All pivot cache fields.
+    PivotCacheFieldVector maDatabaseFields; /// All cache fields that are based on source data.
+    IndexVector         maDatabaseIndexes;  /// Database field index for all fields.
+    PCDefinitionModel   maDefModel;         /// Global pivot cache settings.
+    PCSourceModel       maSourceModel;      /// Pivot cache source settings.
+    PCWorksheetSourceModel maSheetSrcModel; /// Sheet source data if cache type is sheet.
+    ValueRangeSet       maColSpans;         /// Column spans used by SheetDataBuffer for optimized cell import.
+    ::rtl::OUString     maTargetUrl;        /// URL of an external source document.
+    mutable sal_Int32   mnCurrRow;          /// Current row index in dummy sheet.
+    bool                mbValidSource;      /// True = pivot cache is based on supported data source.
+    bool                mbDummySheet;       /// True = pivot cache is based on a dummy sheet.
+};
+
+// ============================================================================
+
+class PivotCacheBuffer : public WorkbookHelper
+{
+public:
+    explicit            PivotCacheBuffer( const WorkbookHelper& rHelper );
+
+    /** Registers a pivot cache definition fragment. The fragment will be loaded on demand (OOXML/BIFF12 only). */
+    void                registerPivotCacheFragment( sal_Int32 nCacheId, const ::rtl::OUString& rFragmentPath );
+    /** Reads the reference to a pivot cache stream. The stream will be loaded on demand (BIFF2-BIFF8 only). */
+    void                importPivotCacheRef( BiffInputStream& rStrm );
+
+    /** Imports and stores a pivot cache definition fragment on first call,
+        returns the imported cache on subsequent calls with the same identifier. */
+    PivotCache*         importPivotCacheFragment( sal_Int32 nCacheId );
+
+private:
+    /** Creates and returns a new pivot cache object with the passed identifier. */
+    PivotCache&         createPivotCache( sal_Int32 nCacheId );
+
+private:
+    typedef ::std::map< sal_Int32, ::rtl::OUString >    FragmentPathMap;
+    typedef RefMap< sal_Int32, PivotCache >             PivotCacheMap;
+    typedef ::std::vector< sal_Int32 >                  PivotCacheIdVector;
+
+    FragmentPathMap     maFragmentPaths;
+    PivotCacheMap       maCaches;
+    PivotCacheIdVector  maCacheIds;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/pivotcachefragment.hxx b/sc/source/filter/inc/pivotcachefragment.hxx
new file mode 100644
index 000000000000..a52c5b2c9377
--- /dev/null
+++ b/sc/source/filter/inc/pivotcachefragment.hxx
@@ -0,0 +1,158 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_PIVOTCACHEFRAGMENT_HXX
+#define OOX_XLS_PIVOTCACHEFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+class PivotCache;
+class PivotCacheField;
+
+// ============================================================================
+
+class PivotCacheFieldContext : public WorkbookContextBase
+{
+public:
+    explicit            PivotCacheFieldContext(
+                            WorkbookFragmentBase& rFragment,
+                            PivotCacheField& rCacheField );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onStartElement( const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual void        onStartRecord( SequenceInputStream& rStrm );
+
+private:
+    PivotCacheField&    mrCacheField;
+};
+
+// ============================================================================
+
+class PivotCacheDefinitionFragment : public WorkbookFragmentBase
+{
+public:
+    explicit            PivotCacheDefinitionFragment(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath,
+                            PivotCache& rPivotCache );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+    virtual void        finalizeImport();
+
+private:
+    PivotCache&         mrPivotCache;
+};
+
+// ============================================================================
+
+class PivotCacheRecordsFragment : public WorksheetFragmentBase
+{
+public:
+    explicit            PivotCacheRecordsFragment(
+                            const WorksheetHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath,
+                            const PivotCache& rPivotCache );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+
+private:
+    void                startCacheRecord();
+    void                importPCRecord( SequenceInputStream& rStrm );
+    void                importPCRecordItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+private:
+    const PivotCache&   mrPivotCache;
+    sal_Int32           mnColIdx;           /// Relative column index in source data.
+    sal_Int32           mnRowIdx;           /// Relative row index in source data.
+    bool                mbInRecord;
+};
+
+// ============================================================================
+// ============================================================================
+
+class BiffPivotCacheFragment : public BiffWorkbookFragmentBase
+{
+public:
+    explicit            BiffPivotCacheFragment(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rStrmName,
+                            PivotCache& rPivotCache );
+
+    /** Imports the entire fragment, returns true, if EOF record has been reached. */
+    virtual bool        importFragment();
+
+private:
+    PivotCache&         mrPivotCache;
+};
+
+// ============================================================================
+
+class BiffPivotCacheRecordsContext : public BiffWorksheetContextBase
+{
+public:
+    explicit            BiffPivotCacheRecordsContext(
+                            const WorksheetHelper& rHelper,
+                            const PivotCache& rPivotCache );
+
+    /** Reads the current record from stream and tries to insert a cell into
+        the source data sheet. */
+    virtual void        importRecord( BiffInputStream& rStrm );
+
+private:
+    void                startNextRow();
+
+private:
+    typedef ::std::vector< sal_Int32 > ColumnIndexVector;
+
+    const PivotCache&   mrPivotCache;
+    ColumnIndexVector   maUnsharedCols; /// Column indexes of all unshared cache fields.
+    size_t              mnColIdx;       /// Current index into maUnsharedCols.
+    sal_Int32           mnRowIdx;       /// Current row in source data (0-based).
+    bool                mbHasShared;    /// True = pivot cache contains fields with shared items.
+    bool                mbInRow;        /// True = a data row has been started.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/pivottablebuffer.hxx b/sc/source/filter/inc/pivottablebuffer.hxx
new file mode 100644
index 000000000000..3be869169fea
--- /dev/null
+++ b/sc/source/filter/inc/pivottablebuffer.hxx
@@ -0,0 +1,453 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_PIVOTTABLEBUFFER_HXX
+#define OOX_XLS_PIVOTTABLEBUFFER_HXX
+
+#include 
+#include "pivotcachebuffer.hxx"
+#include "stylesbuffer.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace sheet { class XDataPilotDescriptor; }
+    namespace sheet { class XDataPilotField; }
+} } }
+
+namespace oox {
+namespace xls {
+
+class PivotTable;
+
+// ============================================================================
+
+struct PTFieldItemModel
+{
+    sal_Int32           mnCacheItem;        /// Index to shared item in pivot cache.
+    sal_Int32           mnType;             /// Type of the item.
+    rtl::OUString       msCaption;          /// User caption of the item
+    bool                mbShowDetails;      /// True = show item details (items of child fields).
+    bool                mbHidden;           /// True = item is hidden.
+
+    explicit            PTFieldItemModel();
+
+    /** Sets item type for BIFF import. */
+    void                setBiffType( sal_uInt16 nType );
+};
+
+// ----------------------------------------------------------------------------
+
+struct PTFieldModel
+{
+    sal_Int32           mnAxis;             /// Axis this field is assigned to (none, row, column, page).
+    sal_Int32           mnNumFmtId;         /// Number format for field items.
+    sal_Int32           mnAutoShowItems;    /// Number of items (or percent/sum) to be shown in auto show filter.
+    sal_Int32           mnAutoShowRankBy;   /// Index of the data field auto show filter is based on.
+    sal_Int32           mnSortType;         /// Autosorting type.
+    sal_Int32           mnSortRefField;     /// Reference field for autosorting.
+    sal_Int32           mnSortRefItem;      /// Item in reference field for autosorting.
+    bool                mbDataField;        /// True = field appears in data area.
+    bool                mbDefaultSubtotal;  /// True = show default subtotals.
+    bool                mbSumSubtotal;      /// True = show sum subtotals.
+    bool                mbCountASubtotal;   /// True = show count all subtotals.
+    bool                mbAverageSubtotal;  /// True = show average subtotals.
+    bool                mbMaxSubtotal;      /// True = show maximum subtotals.
+    bool                mbMinSubtotal;      /// True = show minimum subtotals.
+    bool                mbProductSubtotal;  /// True = show product subtotals.
+    bool                mbCountSubtotal;    /// True = show count numbers subtotals.
+    bool                mbStdDevSubtotal;   /// True = show standard deviation subtotals.
+    bool                mbStdDevPSubtotal;  /// True = show standard deviation of population subtotals.
+    bool                mbVarSubtotal;      /// True = show variance subtotals.
+    bool                mbVarPSubtotal;     /// True = show variance of population subtotals.
+    bool                mbShowAll;          /// True = show items without data.
+    bool                mbOutline;          /// True = show in outline view, false = show in tabular view.
+    bool                mbSubtotalTop;      /// True = show subtotals on top of items in outline or compact mode.
+    bool                mbInsertBlankRow;   /// True = insert blank rows after items.
+    bool                mbInsertPageBreak;  /// True = insert page breaks after items.
+    bool                mbAutoShow;         /// True = auto show (top 10) filter enabled.
+    bool                mbTopAutoShow;      /// True = auto show filter shows top entries, false = bottom.
+    bool                mbMultiPageItems;   /// True = multiple items selectable in page diemsion.
+
+    explicit            PTFieldModel();
+
+    /** Sets axis type for BIFF import. */
+    void                setBiffAxis( sal_uInt8 nAxisFlags );
+};
+
+// ----------------------------------------------------------------------------
+
+struct PTPageFieldModel
+{
+    ::rtl::OUString     maName;             /// Unique name of the page field.
+    sal_Int32           mnField;            /// Base pivot field.
+    sal_Int32           mnItem;             /// Index of field item that is shown by the page field.
+
+    explicit            PTPageFieldModel();
+};
+
+// ----------------------------------------------------------------------------
+
+struct PTDataFieldModel
+{
+    ::rtl::OUString     maName;             /// Name of the data field.
+    sal_Int32           mnField;            /// Base pivot field.
+    sal_Int32           mnSubtotal;         /// Subtotal aggregation function.
+    sal_Int32           mnShowDataAs;       /// Show data as, based on another field.
+    sal_Int32           mnBaseField;        /// Base field for 'show data as'.
+    sal_Int32           mnBaseItem;         /// Base item for 'show data as'.
+    sal_Int32           mnNumFmtId;         /// Number format for the result.
+
+    explicit            PTDataFieldModel();
+
+    /** Sets the subtotal aggregation function for BIFF import. */
+    void                setBiffSubtotal( sal_Int32 nSubtotal );
+    /** Sets the 'show data as' type for BIFF import. */
+    void                setBiffShowDataAs( sal_Int32 nShowDataAs );
+};
+
+// ----------------------------------------------------------------------------
+
+class PivotTableField : public WorkbookHelper
+{
+public:
+    explicit            PivotTableField( PivotTable& rPivotTable, sal_Int32 nFieldIndex );
+
+    /** Imports pivot field settings from the pivotField element. */
+    void                importPivotField( const AttributeList& rAttribs );
+    /** Imports settings of an item in this pivot field from the item element. */
+    void                importItem( const AttributeList& rAttribs );
+    /** Imports pivot field reference settings from the reference element. */
+    void                importReference( const AttributeList& rAttribs );
+    /** Imports pivot field item reference settings from the x element. */
+    void                importReferenceItem( const AttributeList& rAttribs );
+
+    /** Imports pivot field settings from the PTFIELD record. */
+    void                importPTField( SequenceInputStream& rStrm );
+    /** Imports settings of an item in this pivot field from the PTFITEM record. */
+    void                importPTFItem( SequenceInputStream& rStrm );
+    /** Imports pivot field reference settings from the PTREFERENCE record. */
+    void                importPTReference( SequenceInputStream& rStrm );
+    /** Imports pivot field item reference settings from the PTREFERENCEITEM record. */
+    void                importPTReferenceItem( SequenceInputStream& rStrm );
+
+    /** Imports pivot field settings from the PTFIELD and following records. */
+    void                importPTField( BiffInputStream& rStrm );
+    /** Imports pivot field settings from the PTFIELD2 record. */
+    void                importPTField2( BiffInputStream& rStrm );
+    /** Imports settings of an item in this pivot field from the PTFITEM record. */
+    void                importPTFItem( BiffInputStream& rStrm );
+
+    /** Finalizes the field after import, creates grouping and other settings. */
+    void                finalizeImport(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotDescriptor >& rxDPDesc );
+    /** Finalizes the grouped date field after import. */
+    void                finalizeDateGroupingImport(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >& rxBaseDPField,
+                            sal_Int32 nBaseFieldIdx );
+    /** Finalizes the grouped field after import. */
+    void                finalizeParentGroupingImport(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >& rxBaseDPField,
+                            const PivotCacheField& rBaseCacheField,
+                            PivotCacheGroupItemVector& orItemNames );
+
+    /** Returns the name of the DataPilot field in the fields collection. */
+    inline const ::rtl::OUString& getDPFieldName() const { return maDPFieldName; }
+
+    /** Converts dimension and other settings for a row field. */
+    void                convertRowField();
+    /** Converts dimension and other settings for a column field. */
+    void                convertColField();
+    /** Converts dimension and other settings for a hidden field. */
+    void                convertHiddenField();
+    /** Converts dimension and other settings for a page field */
+    void                convertPageField( const PTPageFieldModel& rPageField );
+    /** Converts dimension and other settings for a data field. */
+    void                convertDataField( const PTDataFieldModel& rDataField );
+
+private:
+    /** Converts dimension and other settings for row, column, page, or hidden fields. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >
+                        convertRowColPageField( sal_Int32 nAxis );
+
+private:
+    typedef ::std::vector< PTFieldItemModel > ItemModelVector;
+
+    PivotTable&         mrPivotTable;       /// The parent pivot table object.
+    ItemModelVector     maItems;            /// All items of this field.
+    PTFieldModel        maModel;            /// Pivot field settings.
+    ::rtl::OUString     maDPFieldName;      /// Name of the field in DataPilot field collection.
+    sal_Int32           mnFieldIndex;       /// Zero-based index of this field.
+};
+
+// ============================================================================
+
+struct PTFilterModel
+{
+    ::rtl::OUString     maName;             /// Name of the field filter.
+    ::rtl::OUString     maDescription;      /// Description of the field filter.
+    ::rtl::OUString     maStrValue1;        /// First string value for label filter.
+    ::rtl::OUString     maStrValue2;        /// Second string value for label filter.
+    double              mfValue;            /// Number of items or percent or sum to be shown.
+    sal_Int32           mnField;            /// Base pivot field.
+    sal_Int32           mnMemPropField;     /// Member property field.
+    sal_Int32           mnType;             /// Filter type.
+    sal_Int32           mnEvalOrder;        /// Evaluation order index.
+    sal_Int32           mnId;               /// Unique identifier.
+    sal_Int32           mnMeasureField;     /// Data field for filter calculation.
+    sal_Int32           mnMeasureHier;      /// Hierarchy for filter calculation.
+    bool                mbTopFilter;        /// True = filter shows top entries, false = bottom.
+
+    explicit            PTFilterModel();
+};
+
+// ----------------------------------------------------------------------------
+
+class PivotTableFilter : public WorkbookHelper
+{
+public:
+    explicit            PivotTableFilter( const PivotTable& rPivotTable );
+
+    /** Reads the settings of a field filter from the filter element. */
+    void                importFilter( const AttributeList& rAttribs );
+    /** Reads additional settings of a field filter from the top10 element. */
+    void                importTop10( const AttributeList& rAttribs );
+
+    /** Reads the settings of a field filter from the PTFILTER record. */
+    void                importPTFilter( SequenceInputStream& rStrm );
+    /** Reads additional settings of a field filter from the TOP10FILTER record. */
+    void                importTop10Filter( SequenceInputStream& rStrm );
+
+    /** Applies the filter to the associated pivot table field if possible. */
+    void                finalizeImport();
+
+private:
+    const PivotTable&   mrPivotTable;
+    PTFilterModel       maModel;
+};
+
+// ============================================================================
+
+struct PTDefinitionModel : public AutoFormatModel
+{
+    ::rtl::OUString     maName;
+    ::rtl::OUString     maDataCaption;
+    ::rtl::OUString     maGrandTotalCaption;
+    ::rtl::OUString     maRowHeaderCaption;
+    ::rtl::OUString     maColHeaderCaption;
+    ::rtl::OUString     maErrorCaption;
+    ::rtl::OUString     maMissingCaption;
+    ::rtl::OUString     maPageStyle;
+    ::rtl::OUString     maPivotTableStyle;
+    ::rtl::OUString     maVacatedStyle;
+    ::rtl::OUString     maTag;
+    sal_Int32           mnCacheId;
+    sal_Int32           mnDataPosition;
+    sal_Int32           mnPageWrap;
+    sal_Int32           mnIndent;
+    sal_Int32           mnChartFormat;
+    sal_uInt16          mnRowFields;
+    sal_uInt16          mnColFields;
+    bool                mbDataOnRows;
+    bool                mbShowError;
+    bool                mbShowMissing;
+    bool                mbShowItems;
+    bool                mbDisableFieldList;
+    bool                mbShowCalcMembers;
+    bool                mbVisualTotals;
+    bool                mbShowDataDropDown;
+    bool                mbShowDrill;
+    bool                mbPrintDrill;
+    bool                mbEnableDrill;
+    bool                mbPreserveFormatting;
+    bool                mbUseAutoFormat;
+    bool                mbPageOverThenDown;
+    bool                mbSubtotalHiddenItems;
+    bool                mbRowGrandTotals;
+    bool                mbColGrandTotals;
+    bool                mbFieldPrintTitles;
+    bool                mbItemPrintTitles;
+    bool                mbMergeItem;
+    bool                mbShowEmptyRow;
+    bool                mbShowEmptyCol;
+    bool                mbShowHeaders;
+    bool                mbFieldListSortAsc;
+    bool                mbCustomListSort;
+
+    explicit            PTDefinitionModel();
+};
+
+// ----------------------------------------------------------------------------
+
+struct PTLocationModel
+{
+    ::com::sun::star::table::CellRangeAddress
+                        maRange;            /// Target cell range for the pivot table.
+    sal_Int32           mnFirstHeaderRow;   /// First row of header cells (relative in pivot table).
+    sal_Int32           mnFirstDataRow;     /// First row of data cells (relative in pivot table).
+    sal_Int32           mnFirstDataCol;     /// First column of data cells (relative in pivot table).
+    sal_Int32           mnRowPageCount;     /// Number of rows in page filter area.
+    sal_Int32           mnColPageCount;     /// Number of columns in page filter area.
+
+    explicit            PTLocationModel();
+};
+
+// ----------------------------------------------------------------------------
+
+class PivotTable : public WorkbookHelper
+{
+public:
+    explicit            PivotTable( const WorkbookHelper& rHelper );
+
+    /** Reads global pivot table settings from the pivotTableDefinition element. */
+    void                importPivotTableDefinition( const AttributeList& rAttribs );
+    /** Reads the location of the pivot table from the location element. */
+    void                importLocation( const AttributeList& rAttribs, sal_Int16 nSheet );
+    /** Reads the index of a field located in the row dimension. */
+    void                importRowField( const AttributeList& rAttribs );
+    /** Reads the index of a field located in the column dimension. */
+    void                importColField( const AttributeList& rAttribs );
+    /** Reads the settings of a field located in the page dimension from the pageField element. */
+    void                importPageField( const AttributeList& rAttribs );
+    /** Reads the settings of a field located in the data dimension from the dataField element. */
+    void                importDataField( const AttributeList& rAttribs );
+
+    /** Reads global pivot table settings from the PTDEFINITION record. */
+    void                importPTDefinition( SequenceInputStream& rStrm );
+    /** Reads the location of the pivot table from the PTLOCATION record. */
+    void                importPTLocation( SequenceInputStream& rStrm, sal_Int16 nSheet );
+    /** Reads the indexes of all fields located in the row dimension from a PTROWFIELDS record. */
+    void                importPTRowFields( SequenceInputStream& rStrm );
+    /** Reads the indexes of all fields located in the column dimension from a PTCOLFIELDS record. */
+    void                importPTColFields( SequenceInputStream& rStrm );
+    /** Reads the settings of a field located in the page dimension from the PTPAGEFIELD record. */
+    void                importPTPageField( SequenceInputStream& rStrm );
+    /** Reads the settings of a field located in the data dimension from the PTDATAFIELD record. */
+    void                importPTDataField( SequenceInputStream& rStrm );
+
+    /** Reads global pivot table settings from the PTDEFINITION record. */
+    void                importPTDefinition( BiffInputStream& rStrm, sal_Int16 nSheet );
+    /** Reads additional global pivot table settings from the PTDEFINITION2 record. */
+    void                importPTDefinition2( BiffInputStream& rStrm );
+    /** Reads the indexes of all fields located in the row or column dimension from a PTROWCOLFIELDS record. */
+    void                importPTRowColFields( BiffInputStream& rStrm );
+    /** Reads the settings of all fields located in the page dimension from a PTPAGEFIELDS record. */
+    void                importPTPageFields( BiffInputStream& rStrm );
+    /** Reads the settings of a field located in the data dimension from a PTDATAFIELD record. */
+    void                importPTDataField( BiffInputStream& rStrm );
+
+    /** Creates and returns a new pivot table field. */
+    PivotTableField&    createTableField();
+    /** Creates and returns a new pivot table filter. */
+    PivotTableFilter&   createTableFilter();
+    /** Inserts the pivot table into the sheet. */
+    void                finalizeImport();
+    /** Creates all date group fields for the specified cache field after import. */
+    void                finalizeDateGroupingImport(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >& rxBaseDPField,
+                            sal_Int32 nBaseFieldIdx );
+    /** Creates all grouped fields for the specified cache field after import. */
+    void                finalizeParentGroupingImport(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >& rxBaseDPField,
+                            const PivotCacheField& rBaseCacheField,
+                            PivotCacheGroupItemVector& orItemNames );
+
+    /** Returns the associated data pilot field for the specified pivot table field. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >
+                        getDataPilotField( const ::rtl::OUString& rFieldName ) const;
+    /** Returns the associated data pilot field for the specified pivot table field. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >
+                        getDataPilotField( sal_Int32 nFieldIdx ) const;
+    /** Returns the data layout field used to store all data fields in row/col dimension. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotField >
+                        getDataLayoutField() const;
+
+    /** Returns the cache field with the specified index. */
+    const PivotCacheField* getCacheField( sal_Int32 nFieldIdx ) const;
+    /** Returns the base cache field of the data field item with the specified index. */
+    const PivotCacheField* getCacheFieldOfDataField( sal_Int32 nDataItemIdx ) const;
+    /** Returns the source column index of the pivot field with the passed index, or -1. */
+    sal_Int32           getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const;
+
+private:
+    typedef RefVector< PivotTableField >        PivotTableFieldVector;
+    typedef RefVector< PivotTableFilter >       PivotTableFilterVector;
+    typedef ::std::vector< sal_Int32 >          IndexVector;
+    typedef ::std::vector< PTPageFieldModel >   PageFieldVector;
+    typedef ::std::vector< PTDataFieldModel >   DataFieldVector;
+
+private:
+    /** Returns a pivot table field by its index. */
+    PivotTableField*    getTableField( sal_Int32 nFieldIdx );
+
+    /** Reads a field index for the row or column dimension. */
+    static void         importField( IndexVector& orFields, const AttributeList& rAttribs );
+    /** Reads an array of field indexes for the row or column dimension. */
+    static void         importFields( IndexVector& orFields, SequenceInputStream& rStrm );
+    /** Reads an array of field indexes for the row or column dimension. */
+    static void         importFields( IndexVector& orFields, BiffInputStream& rStrm, sal_Int32 nCount );
+
+private:
+    PivotTableFieldVector maFields;         /// All pivot table fields.
+    PivotTableField     maDataField;        /// Data layout field.
+    IndexVector         maRowFields;        /// Indexes to fields in row dimension.
+    IndexVector         maColFields;        /// Indexes to fields in column dimension.
+    PageFieldVector     maPageFields;       /// Settings for all fields in page dimension.
+    DataFieldVector     maDataFields;       /// Settings for all fields in data area.
+    PivotTableFilterVector maFilters;       /// All field filters.
+    PTDefinitionModel   maDefModel;         /// Global pivot table settings.
+    PTLocationModel     maLocationModel;    /// Location settings of the pivot table.
+    const PivotCache*   mpPivotCache;       /// The pivot cache this table is based on.
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDataPilotDescriptor >
+                        mxDPDescriptor;     /// Descriptor of the DataPilot object.
+};
+
+// ============================================================================
+
+class PivotTableBuffer : public WorkbookHelper
+{
+public:
+    explicit            PivotTableBuffer( const WorkbookHelper& rHelper );
+
+    /** Creates and returns a new pivot table. */
+    PivotTable&         createPivotTable();
+
+    /** Inserts all pivot tables into the sheet. */
+    void                finalizeImport();
+
+private:
+    typedef RefVector< PivotTable > PivotTableVector;
+    PivotTableVector    maTables;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/pivottablefragment.hxx b/sc/source/filter/inc/pivottablefragment.hxx
new file mode 100644
index 000000000000..5053c726ccb1
--- /dev/null
+++ b/sc/source/filter/inc/pivottablefragment.hxx
@@ -0,0 +1,120 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_PIVOTTABLEFRAGMENT_HXX
+#define OOX_XLS_PIVOTTABLEFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+#include "worksheethelper.hxx"
+
+namespace oox {
+namespace xls {
+
+class PivotTable;
+class PivotTableField;
+class PivotTableFilter;
+
+// ============================================================================
+
+class PivotTableFieldContext : public WorksheetContextBase
+{
+public:
+    explicit            PivotTableFieldContext(
+                            WorksheetFragmentBase& rFragment,
+                            PivotTableField& rTableField );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onStartElement( const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual void        onStartRecord( SequenceInputStream& rStrm );
+
+private:
+    PivotTableField&    mrTableField;
+};
+
+// ============================================================================
+
+class PivotTableFilterContext : public WorksheetContextBase
+{
+public:
+    explicit            PivotTableFilterContext(
+                            WorksheetFragmentBase& rFragment,
+                            PivotTableFilter& rTableFilter );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onStartElement( const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual void        onStartRecord( SequenceInputStream& rStrm );
+
+private:
+    PivotTableFilter&   mrTableFilter;
+};
+
+// ============================================================================
+
+class PivotTableFragment : public WorksheetFragmentBase
+{
+public:
+    explicit            PivotTableFragment(
+                            const WorksheetHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+
+private:
+    PivotTable&         mrPivotTable;
+};
+
+// ============================================================================
+// ============================================================================
+
+class BiffPivotTableContext : public BiffWorksheetContextBase
+{
+public:
+    explicit            BiffPivotTableContext( const WorksheetHelper& rHelper );
+
+    /** Imports all records related to the current pivot table. */
+    virtual void        importRecord( BiffInputStream& rStrm );
+
+private:
+    PivotTable&         mrPivotTable;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/querytablebuffer.hxx b/sc/source/filter/inc/querytablebuffer.hxx
new file mode 100644
index 000000000000..8496e40e3529
--- /dev/null
+++ b/sc/source/filter/inc/querytablebuffer.hxx
@@ -0,0 +1,112 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_QUERYTABLEBUFFER_HXX
+#define OOX_XLS_QUERYTABLEBUFFER_HXX
+
+#include "stylesbuffer.hxx"
+#include "worksheethelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+struct QueryTableModel : public AutoFormatModel
+{
+    ::rtl::OUString     maDefName;          /// Defined name containing the target cell range.
+    sal_Int32           mnConnId;           /// Identifier of the external connection used to query the data.
+    sal_Int32           mnGrowShrinkType;   /// Behaviour when source data size changes.
+    bool                mbHeaders;          /// True = source data contains a header row.
+    bool                mbRowNumbers;       /// True = first column contains row numbers.
+    bool                mbDisableRefresh;   /// True = refreshing data disabled.
+    bool                mbBackground;       /// True = refresh asynchronously.
+    bool                mbFirstBackground;  /// True = first background refresh not yet finished.
+    bool                mbRefreshOnLoad;    /// True = refresh table after import.
+    bool                mbFillFormulas;     /// True = expand formulas next to range when source data grows.
+    bool                mbRemoveDataOnSave; /// True = remove querried data before saving.
+    bool                mbDisableEdit;      /// True = connection locked for editing.
+    bool                mbPreserveFormat;   /// True = use existing formatting for new rows.
+    bool                mbAdjustColWidth;   /// True = adjust column widths after refresh.
+    bool                mbIntermediate;     /// True = query table defined but not built yet.
+
+    explicit            QueryTableModel();
+};
+
+// ----------------------------------------------------------------------------
+
+class QueryTable : public WorksheetHelper
+{
+public:
+    explicit            QueryTable( const WorksheetHelper& rHelper );
+
+    /** Imports query table settings from the queryTable element. */
+    void                importQueryTable( const AttributeList& rAttribs );
+    /** Imports query table settings from the QUERYTABLE record. */
+    void                importQueryTable( SequenceInputStream& rStrm );
+
+    /** Imports query table settings from the QUERYTABLE record. */
+    void                importQueryTable( BiffInputStream& rStrm );
+    /** Imports query table settings from the QUERYTABLEREFRESH record. */
+    void                importQueryTableRefresh( BiffInputStream& rStrm );
+    /** Imports query table settings from the QUERYTABLESETTINGS record. */
+    void                importQueryTableSettings( BiffInputStream& rStrm );
+
+    /** Inserts a web query into the sheet. */
+    void                finalizeImport();
+
+private:
+    QueryTableModel     maModel;
+};
+
+// ============================================================================
+
+class QueryTableBuffer : public WorksheetHelper
+{
+public:
+    explicit            QueryTableBuffer( const WorksheetHelper& rHelper );
+
+    /** Creates a new query table and stores it into the internal vector. */
+    QueryTable&         createQueryTable();
+
+    /** Inserts all web queries into the sheet. */
+    void                finalizeImport();
+
+private:
+    typedef RefVector< QueryTable > QueryTableVector;
+    QueryTableVector    maQueryTables;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/querytablefragment.hxx b/sc/source/filter/inc/querytablefragment.hxx
new file mode 100644
index 000000000000..5609eb0d065c
--- /dev/null
+++ b/sc/source/filter/inc/querytablefragment.hxx
@@ -0,0 +1,79 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_QUERYTABLEFRAGMENT_HXX
+#define OOX_XLS_QUERYTABLEFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+class QueryTable;
+
+// ============================================================================
+
+class QueryTableFragment : public WorksheetFragmentBase
+{
+public:
+    explicit            QueryTableFragment(
+                            const WorksheetHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+
+private:
+    QueryTable&         mrQueryTable;
+};
+
+// ============================================================================
+
+class BiffQueryTableContext : public BiffWorksheetContextBase
+{
+public:
+    explicit            BiffQueryTableContext( const WorksheetHelper& rHelper );
+
+    /** Imports all records related to the current query table. */
+    virtual void        importRecord( BiffInputStream& rStrm );
+
+private:
+    QueryTable&         mrQueryTable;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/richstring.hxx b/sc/source/filter/inc/richstring.hxx
new file mode 100644
index 000000000000..588deae288d3
--- /dev/null
+++ b/sc/source/filter/inc/richstring.hxx
@@ -0,0 +1,313 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_RICHSTRING_HXX
+#define OOX_XLS_RICHSTRING_HXX
+
+#include "oox/helper/refvector.hxx"
+#include "stylesbuffer.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace text { class XText; }
+} } }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Flags used to specify import/export mode of strings. */
+typedef sal_Int32 BiffStringFlags;
+
+const BiffStringFlags BIFF_STR_DEFAULT      = 0x0000;   /// Default string settings.
+const BiffStringFlags BIFF_STR_FORCEUNICODE = 0x0001;   /// Always use UCS-2 characters (default: try to compress). BIFF8 export only.
+const BiffStringFlags BIFF_STR_8BITLENGTH   = 0x0002;   /// 8-bit string length field (default: 16-bit).
+const BiffStringFlags BIFF_STR_SMARTFLAGS   = 0x0004;   /// Omit flags on empty string (default: read/write always). BIFF8 only.
+const BiffStringFlags BIFF_STR_KEEPFONTS    = 0x0008;   /// Keep old fonts when reading unformatted string (default: clear fonts). Import only.
+const BiffStringFlags BIFF_STR_EXTRAFONTS   = 0x0010;   /// Read trailing rich-string font array (default: nothing). BIFF2-BIFF5 import only.
+
+// ============================================================================
+
+/** Contains text data and font attributes for a part of a rich formatted string. */
+class RichStringPortion : public WorkbookHelper
+{
+public:
+    explicit            RichStringPortion( const WorkbookHelper& rHelper );
+
+    /** Sets text data for this portion. */
+    void                setText( const ::rtl::OUString& rText );
+    /** Creates and returns a new font formatting object. */
+    FontRef             createFont();
+    /** Links this portion to a font object from the global font list. */
+    void                setFontId( sal_Int32 nFontId );
+
+    /** Final processing after import of all strings. */
+    void                finalizeImport();
+
+    /** Returns the text data of this portion. */
+    inline const ::rtl::OUString& getText() const { return maText; }
+    /** Returns true, if the portion fontains font formatting. */
+    inline bool         hasFont() const { return mxFont.get() != 0; }
+
+    /** Converts the portion and replaces or appends to the passed XText. */
+    void                convert(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::text::XText >& rxText,
+                            const Font* pFont, bool bReplace );
+
+    void                writeFontProperties(
+        const ::com::sun::star::uno::Reference< ::com::sun::star::text::XText >& rxText,
+        const Font* pFont ) const;
+
+private:
+    ::rtl::OUString     maText;         /// Portion text.
+    FontRef             mxFont;         /// Embedded portion font, may be empty.
+    sal_Int32           mnFontId;       /// Link to global font list.
+};
+
+typedef ::boost::shared_ptr< RichStringPortion > RichStringPortionRef;
+
+// ----------------------------------------------------------------------------
+
+enum BiffFontPortionMode
+{
+    BIFF_FONTPORTION_8BIT,              /// Font portion with 8-bit values.
+    BIFF_FONTPORTION_16BIT,             /// Font portion with 16-bit values.
+    BIFF_FONTPORTION_OBJ                /// Font portion in OBJ or TXO record.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Represents a position in a rich-string containing current font identifier.
+
+    This object stores the position of a formatted character in a rich-string
+    and the identifier of a font from the global font list used to format this
+    and the following characters. Used in binary filters only.
+ */
+struct FontPortionModel
+{
+    sal_Int32           mnPos;          /// First character in the string.
+    sal_Int32           mnFontId;       /// Font identifier for the next characters.
+
+    explicit inline     FontPortionModel() : mnPos( 0 ), mnFontId( -1 ) {}
+    explicit inline     FontPortionModel( sal_Int32 nPos, sal_Int32 nFontId ) :
+                            mnPos( nPos ), mnFontId( nFontId ) {}
+
+    void                read( SequenceInputStream& rStrm );
+    void                read( BiffInputStream& rStrm, BiffFontPortionMode eMode );
+};
+
+// ----------------------------------------------------------------------------
+
+/** A vector with all font portions in a rich-string. */
+class FontPortionModelList : public ::std::vector< FontPortionModel >
+{
+public:
+    inline explicit     FontPortionModelList() {}
+
+    /** Appends a rich-string font identifier. */
+    void                appendPortion( const FontPortionModel& rPortion );
+    /** Reads count and font identifiers from the passed stream. */
+    void                importPortions( SequenceInputStream& rStrm );
+    /** Reads nCount font identifiers from the passed stream. */
+    void                importPortions( BiffInputStream& rStrm, sal_uInt16 nCount, BiffFontPortionMode eMode );
+    /** Reads count and font identifiers from the passed stream. */
+    void                importPortions( BiffInputStream& rStrm, bool b16Bit );
+};
+
+// ============================================================================
+
+struct PhoneticDataModel
+{
+    sal_Int32           mnFontId;       /// Font identifier for text formatting.
+    sal_Int32           mnType;         /// Phonetic text type.
+    sal_Int32           mnAlignment;    /// Phonetic portion alignment.
+
+    explicit            PhoneticDataModel();
+
+    /** Sets the passed data from binary import. */
+    void                setBiffData( sal_Int32 nType, sal_Int32 nAlignment );
+};
+
+// ----------------------------------------------------------------------------
+
+class PhoneticSettings : public WorkbookHelper
+{
+public:
+    explicit            PhoneticSettings( const WorkbookHelper& rHelper );
+
+    /** Imports phonetic settings from the phoneticPr element. */
+    void                importPhoneticPr( const AttributeList& rAttribs );
+    /** Imports phonetic settings from the PHONETICPR record. */
+    void                importPhoneticPr( SequenceInputStream& rStrm );
+    /** Imports phonetic settings from the PHONETICPR record. */
+    void                importPhoneticPr( BiffInputStream& rStrm );
+
+    /** Imports phonetic settings from a rich string. */
+    void                importStringData( SequenceInputStream& rStrm );
+    /** Imports phonetic settings from a rich string. */
+    void                importStringData( BiffInputStream& rStrm );
+
+private:
+    PhoneticDataModel   maModel;
+};
+
+// ============================================================================
+
+/** Contains text data and positioning information for a phonetic text portion. */
+class RichStringPhonetic : public WorkbookHelper
+{
+public:
+    explicit            RichStringPhonetic( const WorkbookHelper& rHelper );
+
+    /** Sets text data for this phonetic portion. */
+    void                setText( const ::rtl::OUString& rText );
+    /** Imports attributes of a phonetic run (rPh element). */
+    void                importPhoneticRun( const AttributeList& rAttribs );
+    /** Sets the associated range in base text for this phonetic portion. */
+    void                setBaseRange( sal_Int32 nBasePos, sal_Int32 nBaseEnd );
+
+private:
+    ::rtl::OUString     maText;         /// Portion text.
+    sal_Int32           mnBasePos;      /// Start position in base text.
+    sal_Int32           mnBaseEnd;      /// One-past-end position in base text.
+};
+
+typedef ::boost::shared_ptr< RichStringPhonetic > RichStringPhoneticRef;
+
+// ----------------------------------------------------------------------------
+
+/** Represents a phonetic text portion in a rich-string with phonetic text.
+    Used in binary filters only. */
+struct PhoneticPortionModel
+{
+    sal_Int32           mnPos;          /// First character in phonetic text.
+    sal_Int32           mnBasePos;      /// First character in base text.
+    sal_Int32           mnBaseLen;      /// Number of characters in base text.
+
+    explicit inline     PhoneticPortionModel() : mnPos( -1 ), mnBasePos( -1 ), mnBaseLen( 0 ) {}
+    explicit inline     PhoneticPortionModel( sal_Int32 nPos, sal_Int32 nBasePos, sal_Int32 nBaseLen ) :
+                            mnPos( nPos ), mnBasePos( nBasePos ), mnBaseLen( nBaseLen ) {}
+
+    void                read( SequenceInputStream& rStrm );
+    void                read( BiffInputStream& rStrm );
+};
+
+// ----------------------------------------------------------------------------
+
+/** A vector with all phonetic portions in a rich-string. */
+class PhoneticPortionModelList : public ::std::vector< PhoneticPortionModel >
+{
+public:
+    inline explicit     PhoneticPortionModelList() {}
+
+    /** Appends a rich-string phonetic portion. */
+    void                appendPortion( const PhoneticPortionModel& rPortion );
+    /** Reads all phonetic portions from the passed stream. */
+    void                importPortions( SequenceInputStream& rStrm );
+    /** Reads phonetic portion data from the passed stream. */
+    ::rtl::OUString     importPortions( BiffInputStream& rStrm, sal_Int32 nPhoneticSize );
+};
+
+// ============================================================================
+
+/** Contains string data and a list of formatting runs for a rich formatted string. */
+class RichString : public WorkbookHelper
+{
+public:
+    explicit            RichString( const WorkbookHelper& rHelper );
+
+    /** Appends and returns a portion object for a plain string (t element). */
+    RichStringPortionRef importText( const AttributeList& rAttribs );
+    /** Appends and returns a portion object for a new formatting run (r element). */
+    RichStringPortionRef importRun( const AttributeList& rAttribs );
+    /** Appends and returns a phonetic text object for a new phonetic run (rPh element). */
+    RichStringPhoneticRef importPhoneticRun( const AttributeList& rAttribs );
+    /** Imports phonetic settings from the rPhoneticPr element. */
+    void                importPhoneticPr( const AttributeList& rAttribs );
+
+    /** Imports a Unicode rich-string from the passed record stream. */
+    void                importString( SequenceInputStream& rStrm, bool bRich );
+
+    /** Imports nChars byte characters from the passed BIFF stream and appends a new text portion. */
+    void                importCharArray( BiffInputStream& rStrm, sal_uInt16 nChars, rtl_TextEncoding eTextEnc );
+    /** Imports a byte string from the passed BIFF stream and appends new text portions. */
+    void                importByteString( BiffInputStream& rStrm, rtl_TextEncoding eTextEnc, BiffStringFlags nFlags = BIFF_STR_DEFAULT );
+    /** Imports a Unicode rich-string from the passed BIFF stream and appends new text portions. */
+    void                importUniString( BiffInputStream& rStrm, BiffStringFlags nFlags = BIFF_STR_DEFAULT );
+
+    /** Final processing after import of all strings. */
+    void                finalizeImport();
+
+    /** Tries to extract a plain string from this object. Returns the string,
+        if there is only one unformatted portion. */
+    bool                extractPlainString(
+                            ::rtl::OUString& orString,
+                            const Font* pFirstPortionFont = 0 ) const;
+
+    /** Converts the string and writes it into the passed XText.
+        @param rxText  The XText interface of the target object.
+        @param bReplaceOld  True = replace old contents of the text object.
+        @param pFirstPortionFont  Optional font providing additional rich-text
+            formatting for the first text portion, e.g. font escapement. */
+    void                convert(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::text::XText >& rxText,
+                            bool bReplaceOld,
+                            const Font* pFirstPortionFont = 0 ) const;
+
+private:
+    /** Creates, appends, and returns a new empty string portion. */
+    RichStringPortionRef createPortion();
+    /** Creates, appends, and returns a new empty phonetic text portion. */
+    RichStringPhoneticRef createPhonetic();
+
+    /** Create base text portions from the passed string and character formatting. */
+    void                createTextPortions( const ::rtl::OString& rText, rtl_TextEncoding eTextEnc, FontPortionModelList& rPortions );
+    /** Create base text portions from the passed string and character formatting. */
+    void                createTextPortions( const ::rtl::OUString& rText, FontPortionModelList& rPortions );
+    /** Create phonetic text portions from the passed string and portion data. */
+    void                createPhoneticPortions( const ::rtl::OUString& rText, PhoneticPortionModelList& rPortions, sal_Int32 nBaseLen );
+
+private:
+    typedef RefVector< RichStringPortion >  PortionVector;
+    typedef RefVector< RichStringPhonetic > PhoneticVector;
+
+    PortionVector       maTextPortions; /// String portions with font data.
+    PhoneticSettings    maPhonSettings; /// Phonetic settings for this string.
+    PhoneticVector      maPhonPortions; /// Phonetic text portions.
+};
+
+typedef ::boost::shared_ptr< RichString > RichStringRef;
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/richstringcontext.hxx b/sc/source/filter/inc/richstringcontext.hxx
new file mode 100644
index 000000000000..36e49d4686df
--- /dev/null
+++ b/sc/source/filter/inc/richstringcontext.hxx
@@ -0,0 +1,74 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_RICHSTRINGCONTEXT_HXX
+#define OOX_XLS_RICHSTRINGCONTEXT_HXX
+
+#include "excelhandlers.hxx"
+#include "richstring.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+class RichStringContext : public WorkbookContextBase
+{
+public:
+    template< typename ParentType >
+    explicit            RichStringContext( ParentType& rParent, RichStringRef xString );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onCharacters( const ::rtl::OUString& rChars );
+
+private:
+    RichStringRef       mxString;       /// Processed string.
+    RichStringPortionRef mxPortion;     /// Processed portion in the string.
+    RichStringPhoneticRef mxPhonetic;   /// Processed phonetic text portion.
+    FontRef             mxFont;         /// Processed font of the portion.
+};
+
+// ----------------------------------------------------------------------------
+
+template< typename ParentType >
+RichStringContext::RichStringContext( ParentType& rParent, RichStringRef xString ) :
+    WorkbookContextBase( rParent ),
+    mxString( xString )
+{
+    OSL_ENSURE( mxString.get(), "RichStringContext::RichStringContext - missing string object" );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/scenariobuffer.hxx b/sc/source/filter/inc/scenariobuffer.hxx
new file mode 100644
index 000000000000..dc996c71e30f
--- /dev/null
+++ b/sc/source/filter/inc/scenariobuffer.hxx
@@ -0,0 +1,158 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_SCENARIOBUFFER_HXX
+#define OOX_XLS_SCENARIOBUFFER_HXX
+
+#include 
+#include "oox/helper/refmap.hxx"
+#include "oox/helper/refvector.hxx"
+#include "workbookhelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+struct ScenarioCellModel
+{
+    ::com::sun::star::table::CellAddress maPos;
+    ::rtl::OUString     maValue;
+    sal_Int32           mnNumFmtId;
+    bool                mbDeleted;
+
+    explicit            ScenarioCellModel();
+};
+
+// ----------------------------------------------------------------------------
+
+struct ScenarioModel
+{
+    ::rtl::OUString     maName;             /// Name of the scenario.
+    ::rtl::OUString     maComment;          /// Comment.
+    ::rtl::OUString     maUser;             /// Name of user created the scenario.
+    bool                mbLocked;           /// True = input cell values locked.
+    bool                mbHidden;           /// True = scenario is hidden.
+
+    explicit            ScenarioModel();
+};
+
+// ----------------------------------------------------------------------------
+
+class Scenario : public WorkbookHelper
+{
+public:
+    explicit            Scenario( const WorkbookHelper& rHelper, sal_Int16 nSheet );
+
+    /** Imports a scenario definition from a scenario element. */
+    void                importScenario( const AttributeList& rAttribs );
+    /** Imports a new cell for this scenario from a inputCells element. */
+    void                importInputCells( const AttributeList& rAttribs );
+
+    /** Imports a scenario definition from a SCENARIO record. */
+    void                importScenario( SequenceInputStream& rStrm );
+    /** Imports a new cell for this scenario from a INPUTCELLS record. */
+    void                importInputCells( SequenceInputStream& rStrm );
+
+    /** Imports a scenario definition from a SCENARIO record. */
+    void                importScenario( BiffInputStream& rStrm );
+
+    /** Creates the scenario in the Calc document. */
+    void                finalizeImport();
+
+private:
+    typedef ::std::vector< ScenarioCellModel > ScenarioCellVector;
+
+    ScenarioCellVector  maCells;            /// Scenario cells.
+    ScenarioModel       maModel;            /// Scenario model data.
+    sal_Int16           mnSheet;            /// Index of the sheet this scenario is based on.
+};
+
+// ============================================================================
+
+struct SheetScenariosModel
+{
+    sal_Int32           mnCurrent;          /// Selected scenario.
+    sal_Int32           mnShown;            /// Visible scenario.
+
+    explicit            SheetScenariosModel();
+};
+
+// ----------------------------------------------------------------------------
+
+class SheetScenarios : public WorkbookHelper
+{
+public:
+    explicit            SheetScenarios( const WorkbookHelper& rHelper, sal_Int16 nSheet );
+
+    /** Imports sheet scenario settings from a scenarios element. */
+    void                importScenarios( const AttributeList& rAttribs );
+    /** Imports sheet scenario settings from a SCENARIOS record. */
+    void                importScenarios( SequenceInputStream& rStrm );
+    /** Imports sheet scenario settings from a SCENARIOS record. */
+    void                importScenarios( BiffInputStream& rStrm );
+
+    /** Creates and returns a new scenario in this collection. */
+    Scenario&           createScenario();
+
+    /** Creates all scenarios in the Calc sheet. */
+    void                finalizeImport();
+
+private:
+    typedef RefVector< Scenario > ScenarioVector;
+    ScenarioVector      maScenarios;
+    SheetScenariosModel maModel;
+    sal_Int16           mnSheet;
+};
+
+// ============================================================================
+
+class ScenarioBuffer : public WorkbookHelper
+{
+public:
+    explicit            ScenarioBuffer( const WorkbookHelper& rHelper );
+
+    /** Creates and returns a scenario collection for the passed sheet. */
+    SheetScenarios&     createSheetScenarios( sal_Int16 nSheet );
+
+    /** Creates all scenarios in the Calc document. */
+    void                finalizeImport();
+
+private:
+    typedef RefMap< sal_Int16, SheetScenarios, ::std::greater< sal_Int16 > > SheetScenariosMap;
+    SheetScenariosMap   maSheetScenarios;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/scenariocontext.hxx b/sc/source/filter/inc/scenariocontext.hxx
new file mode 100644
index 000000000000..87a9baa087a8
--- /dev/null
+++ b/sc/source/filter/inc/scenariocontext.hxx
@@ -0,0 +1,83 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_SCENARIOCONTEXT_HXX
+#define OOX_XLS_SCENARIOCONTEXT_HXX
+
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+class Scenario;
+class SheetScenarios;
+
+// ============================================================================
+
+class ScenarioContext : public WorksheetContextBase
+{
+public:
+    explicit            ScenarioContext( WorksheetContextBase& rParent, SheetScenarios& rSheetScenarios );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onStartElement( const AttributeList& rAttribs );
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual void        onStartRecord( SequenceInputStream& rStrm );
+
+private:
+    Scenario&           mrScenario;
+};
+
+// ============================================================================
+
+class ScenariosContext : public WorksheetContextBase
+{
+public:
+    explicit            ScenariosContext( WorksheetFragmentBase& rFragment );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onStartElement( const AttributeList& rAttribs );
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+    virtual void        onStartRecord( SequenceInputStream& rStrm );
+
+private:
+    SheetScenarios&     mrSheetScenarios;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/sharedstringsbuffer.hxx b/sc/source/filter/inc/sharedstringsbuffer.hxx
new file mode 100644
index 000000000000..124213d1504c
--- /dev/null
+++ b/sc/source/filter/inc/sharedstringsbuffer.hxx
@@ -0,0 +1,68 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_SHAREDSTRINGSBUFFER_HXX
+#define OOX_XLS_SHAREDSTRINGSBUFFER_HXX
+
+#include "richstring.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Collects all strings from the shared strings substream. */
+class SharedStringsBuffer : public WorkbookHelper
+{
+public:
+    explicit            SharedStringsBuffer( const WorkbookHelper& rHelper );
+
+    /** Creates and returns a new string entry. */
+    RichStringRef       createRichString();
+    /** Imports the complete shared string table from a BIFF file. */
+    void                importSst( BiffInputStream& rStrm );
+
+    /** Final processing after import of all strings. */
+    void                finalizeImport();
+
+    /** Returns the specified string. */
+    RichStringRef       getString( sal_Int32 nStringId ) const;
+
+private:
+    typedef RefVector< RichString > StringVector;
+    StringVector        maStrings;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/sharedstringsfragment.hxx b/sc/source/filter/inc/sharedstringsfragment.hxx
new file mode 100644
index 000000000000..2ed204b45f93
--- /dev/null
+++ b/sc/source/filter/inc/sharedstringsfragment.hxx
@@ -0,0 +1,61 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_SHAREDSTRINGSFRAGMENT_HXX
+#define OOX_XLS_SHAREDSTRINGSFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+class SharedStringsFragment : public WorkbookFragmentBase
+{
+public:
+    explicit            SharedStringsFragment(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+    virtual void        finalizeImport();
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/sheetdatabuffer.hxx b/sc/source/filter/inc/sheetdatabuffer.hxx
new file mode 100644
index 000000000000..ac7fc81a9f4b
--- /dev/null
+++ b/sc/source/filter/inc/sheetdatabuffer.hxx
@@ -0,0 +1,343 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_SHEETDATABUFFER_HXX
+#define OOX_XLS_SHEETDATABUFFER_HXX
+
+#include 
+#include 
+#include "richstring.hxx"
+#include "worksheethelper.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace sheet { class XNamedRange; }
+    namespace util { struct DateTime; }
+} } }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Stores basic data about cell values and formatting. */
+struct CellModel
+{
+    ::com::sun::star::table::CellAddress
+                        maCellAddr;         /// The address of the current cell.
+    sal_Int32           mnCellType;         /// Data type of the cell value.
+    sal_Int32           mnXfId;             /// XF (cell formatting) identifier.
+    bool                mbShowPhonetic;     /// True = show phonetic text.
+
+    explicit            CellModel();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Stores data about cell formulas. */
+struct CellFormulaModel
+{
+    ::com::sun::star::table::CellRangeAddress
+                        maFormulaRef;       /// Formula range for array/shared formulas and data tables.
+    sal_Int32           mnFormulaType;      /// Type of the formula (regular, array, shared, table).
+    sal_Int32           mnSharedId;         /// Identifier of a shared formula (OOXML only).
+
+    explicit            CellFormulaModel();
+
+    /** Returns true, if the passed cell address is valid for an array formula. */
+    bool                isValidArrayRef( const ::com::sun::star::table::CellAddress& rCellAddr );
+    /** Returns true, if the passed cell address is valid for a shared formula. */
+    bool                isValidSharedRef( const ::com::sun::star::table::CellAddress& rCellAddr );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Stores data about table operations. */
+struct DataTableModel
+{
+    ::rtl::OUString     maRef1;             /// First reference cell for table operations.
+    ::rtl::OUString     maRef2;             /// Second reference cell for table operations.
+    bool                mb2dTable;          /// True = 2-dimensional data table.
+    bool                mbRowTable;         /// True = row oriented data table.
+    bool                mbRef1Deleted;      /// True = first reference cell deleted.
+    bool                mbRef2Deleted;      /// True = second reference cell deleted.
+
+    explicit            DataTableModel();
+};
+
+// ============================================================================
+
+/** Stores position and contents of a range of cells for optimized import. */
+class CellBlock : public WorksheetHelper
+{
+public:
+    explicit            CellBlock( const WorksheetHelper& rHelper, const ValueRange& rColSpan, sal_Int32 nRow );
+
+    /** Returns true, if the end index of the passed colspan is greater than
+        the own column end index, or if the passed range has the same end index
+        but the start indexes do not match. */
+    bool                isBefore( const ValueRange& rColSpan ) const;
+    /** Returns true, if the cell block can be expanded with the passed colspan. */
+    bool                isExpandable( const ValueRange& rColSpan ) const;
+    /** Returns true, if the own colspan contains the passed column. */
+    bool                contains( sal_Int32 nCol ) const;
+
+    /** Returns the specified cell from the last row in the cell buffer array. */
+    ::com::sun::star::uno::Any& getCellAny( sal_Int32 nCol );
+    /** Inserts a rich-string into the cell block. */
+    void                insertRichString(
+                            const ::com::sun::star::table::CellAddress& rAddress,
+                            const RichStringRef& rxString,
+                            const Font* pFirstPortionFont );
+
+    /** Appends a new row to the cell buffer array. */
+    void                startNextRow();
+    /** Writes all buffered cells into the Calc sheet. */
+    void                finalizeImport();
+
+private:
+    /** Fills unused cells before passed index with empty strings. */
+    void                fillUnusedCells( sal_Int32 nIndex );
+
+private:
+    /** Stores position and string data of a rich-string cell. */
+    struct RichStringCell
+    {
+        ::com::sun::star::table::CellAddress
+                            maCellAddr;         /// The address of the rich-string cell.
+        RichStringRef       mxString;           /// The string with rich formatting.
+        const Font*         mpFirstPortionFont; /// Font information from cell for first text portion.
+
+        explicit            RichStringCell(
+                                const ::com::sun::star::table::CellAddress& rCellAddr,
+                                const RichStringRef& rxString,
+                                const Font* pFirstPortionFont );
+    };
+    typedef ::std::list< RichStringCell > RichStringCellList;
+
+    ::com::sun::star::table::CellRangeAddress
+                        maRange;            /// Cell range covered by this cell block.
+    RichStringCellList  maRichStrings;      /// Cached rich-string cells.
+    ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >
+                        maCellArray;        /// The array of cells of this cell block.
+    ::com::sun::star::uno::Any*
+                        mpCurrCellRow;      /// Pointer to first cell of current row (last row in maCellArray).
+    const sal_Int32     mnRowLength;        /// Number of cells covered by row of this cell block.
+    sal_Int32           mnFirstFreeIndex;   /// Relative index of first unused cell in current row.
+};
+
+// ============================================================================
+
+/** Manages all cell blocks currently in use. */
+class CellBlockBuffer : public WorksheetHelper
+{
+public:
+    explicit            CellBlockBuffer( const WorksheetHelper& rHelper );
+
+    /** Sets column span information for a row. */
+    void                setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans );
+
+    /** Tries to find a cell block. Recalculates the map of cell blocks, if the
+        passed cell address is located in another row than the last cell. */
+    CellBlock*          getCellBlock( const ::com::sun::star::table::CellAddress& rCellAddr );
+
+    /** Inserts all cells of all open cell blocks into the Calc document. */
+    void                finalizeImport();
+
+private:
+    typedef ::std::map< sal_Int32, ValueRangeVector >   ColSpanVectorMap;
+    typedef RefMap< sal_Int32, CellBlock >              CellBlockMap;
+
+    ColSpanVectorMap    maColSpans;             /// Buffereed column spans, mapped by row index.
+    CellBlockMap        maCellBlocks;           /// All open cell blocks, mapped by last (!) column of the block span.
+    CellBlockMap::iterator maCellBlockIt;       /// Pointer to cell block currently in use.
+    sal_Int32           mnCurrRow;              /// Current row index used for buffered cell import.
+};
+
+// ============================================================================
+
+/** Manages the cell contents and cell formatting of a sheet.
+ */
+class SheetDataBuffer : public WorksheetHelper
+{
+public:
+    explicit            SheetDataBuffer( const WorksheetHelper& rHelper );
+
+    /** Sets column span information for a row. */
+    void                setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans );
+
+    /** Inserts a blank cell (with formatting) into the sheet. */
+    void                setBlankCell( const CellModel& rModel );
+    /** Inserts a value cell into the sheet. */
+    void                setValueCell( const CellModel& rModel, double fValue );
+    /** Inserts a simple string cell into the sheet. */
+    void                setStringCell( const CellModel& rModel, const ::rtl::OUString& rText );
+    /** Inserts a rich-string cell into the sheet. */
+    void                setStringCell( const CellModel& rModel, const RichStringRef& rxString );
+    /** Inserts a shared string cell into the sheet. */
+    void                setStringCell( const CellModel& rModel, sal_Int32 nStringId );
+    /** Inserts a date/time cell into the sheet and adjusts number format. */
+    void                setDateTimeCell( const CellModel& rModel, const ::com::sun::star::util::DateTime& rDateTime );
+    /** Inserts a boolean cell into the sheet and adjusts number format. */
+    void                setBooleanCell( const CellModel& rModel, bool bValue );
+    /** Inserts an error cell from the passed error code into the sheet. */
+    void                setErrorCell( const CellModel& rModel, const ::rtl::OUString& rErrorCode );
+    /** Inserts an error cell from the passed BIFF error code into the sheet. */
+    void                setErrorCell( const CellModel& rModel, sal_uInt8 nErrorCode );
+    /** Inserts a formula cell into the sheet. */
+    void                setFormulaCell( const CellModel& rModel, const ApiTokenSequence& rTokens );
+    /** Inserts a shared formula cell into the sheet (OOXML only). */
+    void                setFormulaCell( const CellModel& rModel, sal_Int32 nSharedId );
+
+    /** Inserts the passed token array as array formula. */
+    void                createArrayFormula(
+                            const ::com::sun::star::table::CellRangeAddress& rRange,
+                            const ApiTokenSequence& rTokens );
+    /** Sets a multiple table operation to the passed range. */
+    void                createTableOperation(
+                            const ::com::sun::star::table::CellRangeAddress& rRange,
+                            const DataTableModel& rModel );
+    /** Creates a named range with a special name for a shared formula with the
+        specified identifier and formula definition (OOXML only). */
+    void                createSharedFormula(
+                            sal_Int32 nSharedId,
+                            const ApiTokenSequence& rTokens );
+    /** Creates a named range with a special name for a shared formula with the
+        specified base address and formula definition (BIFF only). */
+    void                createSharedFormula(
+                            const ::com::sun::star::table::CellAddress& rCellAddr,
+                            const ApiTokenSequence& rTokens );
+
+    /** Sets default cell formatting for the specified range of rows. */
+    void                setRowFormat( sal_Int32 nRow, sal_Int32 nXfId, bool bCustomFormat );
+    /** Merges the cells in the passed cell range. */
+    void                setMergedRange( const ::com::sun::star::table::CellRangeAddress& rRange );
+    /** Sets a standard number format (constant from com.sun.star.util.NumberFormat) to the specified cell. */
+    void                setStandardNumFmt(
+                            const ::com::sun::star::table::CellAddress& rCellAddr,
+                            sal_Int16 nStdNumFmt );
+
+    /** Final processing after the sheet has been imported. */
+    void                finalizeImport();
+
+private:
+    struct XfIdRowRange;
+
+    /** Sets the passed formula token array into a cell. */
+    void                setCellFormula(
+                            const ::com::sun::star::table::CellAddress& rCellAddr,
+                            const ApiTokenSequence& rTokens );
+
+    /** Creates a named range with a special name for a shared formula with the
+        specified base address and formula definition. */
+    void                createSharedFormula( const BinAddress& rMapKey, const ApiTokenSequence& rTokens );
+    /** Creates a formula token array representing the shared formula with the
+        passed identifier. */
+    ApiTokenSequence    resolveSharedFormula( const BinAddress& rMapKey ) const;
+
+    /** Inserts the passed array formula into the sheet. */
+    void                finalizeArrayFormula(
+                            const ::com::sun::star::table::CellRangeAddress& rRange,
+                            const ApiTokenSequence& rTokens ) const;
+    /** Inserts the passed table operation into the sheet. */
+    void                finalizeTableOperation(
+                            const ::com::sun::star::table::CellRangeAddress& rRange,
+                            const DataTableModel& rModel ) const;
+
+    /** Processes the cell formatting data of the passed cell.
+        @param nNumFmtId  If set, overrides number format of the cell XF. */
+    void                setCellFormat( const CellModel& rModel, sal_Int32 nNumFmtId = -1 );
+
+    /** 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 list. (depreciates writeXfIdRangeProperties) */
+    void                writeXfIdRangeListProperties( sal_Int32 nXfId, sal_Int32 nNumFmtId, const ApiCellRangeList& rRanges ) const;
+
+    /** Merges the passed merged range and updates right/bottom cell borders. */
+    void                finalizeMergedRange( const ::com::sun::star::table::CellRangeAddress& rRange );
+
+private:
+    /** Stores cell range address and formula token array of an array formula. */
+    typedef ::std::pair< ::com::sun::star::table::CellRangeAddress, ApiTokenSequence > ArrayFormula;
+    typedef ::std::list< ArrayFormula > ArrayFormulaList;
+
+    /** Stores cell range address and settings of a table operation. */
+    typedef ::std::pair< ::com::sun::star::table::CellRangeAddress, DataTableModel > TableOperation;
+    typedef ::std::list< TableOperation > TableOperationList;
+
+    typedef ::std::map< BinAddress, sal_Int32 > SharedFormulaMap;
+
+    /** Stores information about a range of rows with equal cell formatting. */
+    struct XfIdRowRange
+    {
+        ValueRange          maRowRange;         /// Indexes of first and last row.
+        sal_Int32           mnXfId;             /// XF identifier for the row range.
+
+        explicit            XfIdRowRange();
+        void                set( sal_Int32 nRow, sal_Int32 nXfId );
+        bool                tryExpand( sal_Int32 nRow, sal_Int32 nXfId );
+    };
+
+    typedef ::std::pair< sal_Int32, sal_Int32 > XfIdNumFmtKey;
+    typedef ::std::map< XfIdNumFmtKey, ApiCellRangeList > XfIdRangeListMap;
+
+    /** Stores information about a merged cell range. */
+    struct MergedRange
+    {
+        ::com::sun::star::table::CellRangeAddress
+                            maRange;            /// The formatted cell range.
+        sal_Int32           mnHorAlign;         /// Horizontal alignment in the range.
+
+        explicit            MergedRange( const ::com::sun::star::table::CellRangeAddress& rRange );
+        explicit            MergedRange( const ::com::sun::star::table::CellAddress& rAddress, sal_Int32 nHorAlign );
+        bool                tryExpand( const ::com::sun::star::table::CellAddress& rAddress, sal_Int32 nHorAlign );
+    };
+    typedef ::std::list< MergedRange > MergedRangeList;
+
+    CellBlockBuffer     maCellBlocks;           /// Manages all open cell blocks.
+    ArrayFormulaList    maArrayFormulas;        /// All array formulas in the sheet.
+    TableOperationList  maTableOperations;      /// All table operations in the sheet.
+    SharedFormulaMap    maSharedFormulas;       /// Maps shared formula base address to defined name token index.
+    ::com::sun::star::table::CellAddress
+                        maSharedFmlaAddr;       /// Address of a cell containing a pending shared formula.
+    BinAddress          maSharedBaseAddr;       /// Base address of the pending shared formula.
+    XfIdRowRange        maXfIdRowRange;         /// Cached XF identifier for a range of rows.
+    XfIdRangeListMap    maXfIdRangeLists;       /// Collected XF identifiers for cell rangelists.
+    MergedRangeList     maMergedRanges;         /// Merged cell ranges.
+    MergedRangeList     maCenterFillRanges;     /// Merged cell ranges from 'center across' or 'fill' alignment.
+    bool                mbPendingSharedFmla;    /// True = maSharedFmlaAddr and maSharedBaseAddr are valid.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/sheetdatacontext.hxx b/sc/source/filter/inc/sheetdatacontext.hxx
new file mode 100644
index 000000000000..324b12a1837c
--- /dev/null
+++ b/sc/source/filter/inc/sheetdatacontext.hxx
@@ -0,0 +1,196 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_SHEETDATACONTEXT_HXX
+#define OOX_XLS_SHEETDATACONTEXT_HXX
+
+#include "excelhandlers.hxx"
+#include "richstring.hxx"
+#include "sheetdatabuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Used as base for sheet data context classes. Provides fast access to often
+    used converter objects and sheet index, to improve performance.
+ */
+struct SheetDataContextBase
+{
+    AddressConverter&   mrAddressConv;      /// The address converter.
+    FormulaParser&      mrFormulaParser;    /// The formula parser.
+    SheetDataBuffer&    mrSheetData;        /// The sheet data buffer for cell content and formatting.
+    CellModel           maCellData;         /// Position, contents, formatting of current imported cell.
+    CellFormulaModel    maFmlaData;         /// Settings for a cell formula.
+    sal_Int16           mnSheet;            /// Index of the current sheet.
+
+    explicit            SheetDataContextBase( const WorksheetHelper& rHelper );
+    virtual             ~SheetDataContextBase();
+};
+
+// ============================================================================
+
+/** This class implements importing the sheetData element.
+
+    The sheetData element contains all row settings and all cells in a single
+    sheet of a spreadsheet document.
+ */
+class SheetDataContext : public WorksheetContextBase, private SheetDataContextBase
+{
+public:
+    explicit            SheetDataContext( WorksheetFragmentBase& rFragment );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onCharacters( const ::rtl::OUString& rChars );
+    virtual void        onEndElement();
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+private:
+    /** Different types of cell records. */
+    enum CellType { CELLTYPE_VALUE, CELLTYPE_MULTI, CELLTYPE_FORMULA };
+
+    /** Imports row settings from a row element. */
+    void                importRow( const AttributeList& rAttribs );
+    /** Imports cell settings from a c element. */
+    bool                importCell( const AttributeList& rAttribs );
+    /** Imports cell settings from an f element. */
+    void                importFormula( const AttributeList& rAttribs );
+
+    /** Imports row settings from a ROW record. */
+    void                importRow( SequenceInputStream& rStrm );
+
+    /** Reads a cell address and the following XF identifier. */
+    bool                readCellHeader( SequenceInputStream& rStrm, CellType eCellType );
+    /** Reads a cell formula for the current cell. */
+    ApiTokenSequence    readCellFormula( SequenceInputStream& rStrm );
+    /** Reads the formula range used by shared formulas, arrays, and data tables. */
+    bool                readFormulaRef( SequenceInputStream& rStrm );
+
+    /** Imports an empty cell from a CELL_BLANK or MULTCELL_BLANK record. */
+    void                importCellBlank( SequenceInputStream& rStrm, CellType eCellType );
+    /** Imports a boolean cell from a CELL_BOOL, MULTCELL_BOOL, or FORMULA_BOOL record. */
+    void                importCellBool( SequenceInputStream& rStrm, CellType eCellType );
+    /** Imports a numeric cell from a CELL_DOUBLE, MULTCELL_DOUBLE, or FORMULA_DOUBLE record. */
+    void                importCellDouble( SequenceInputStream& rStrm, CellType eCellType );
+    /** Imports an error code cell from a CELL_ERROR, MULTCELL_ERROR, or FORMULA_ERROR record. */
+    void                importCellError( SequenceInputStream& rStrm, CellType eCellType );
+    /** Imports an encoded numeric cell from a CELL_RK or MULTCELL_RK record. */
+    void                importCellRk( SequenceInputStream& rStrm, CellType eCellType );
+    /** Imports a rich-string cell from a CELL_RSTRING or MULTCELL_RSTRING record. */
+    void                importCellRString( SequenceInputStream& rStrm, CellType eCellType );
+    /** Imports a string cell from a CELL_SI or MULTCELL_SI record. */
+    void                importCellSi( SequenceInputStream& rStrm, CellType eCellType );
+    /** Imports a string cell from a CELL_STRING, MULTCELL_STRING, or FORMULA_STRING record. */
+    void                importCellString( SequenceInputStream& rStrm, CellType eCellType );
+
+    /** Imports an array formula from an ARRAY record. */
+    void                importArray( SequenceInputStream& rStrm );
+    /** Imports table operation from a DATATABLE record. */
+    void                importDataTable( SequenceInputStream& rStrm );
+    /** Imports a shared formula from a SHAREDFORMULA record. */
+    void                importSharedFmla( SequenceInputStream& rStrm );
+
+private:
+    ::rtl::OUString     maCellValue;        /// Cell value string (OOXML only).
+    RichStringRef       mxInlineStr;        /// Inline rich string (OOXML only).
+    ApiTokenSequence    maTokens;           /// Formula token array (OOXML only).
+    DataTableModel      maTableData;        /// Settings for table operations.
+    BinAddress          maCurrPos;          /// Current cell position (BIFF12 only).
+    bool                mbHasFormula;       /// True = current cell has formula data (OOXML only).
+    bool                mbValidRange;       /// True = maFmlaData.maFormulaRef is valid (OOXML only).
+};
+
+// ============================================================================
+
+/** This class implements importing row settings and all cells of a sheet.
+ */
+class BiffSheetDataContext : public BiffWorksheetContextBase, private SheetDataContextBase
+{
+public:
+    explicit            BiffSheetDataContext( const WorksheetHelper& rHelper );
+
+    /** Tries to import a sheet data record. */
+    virtual void        importRecord( BiffInputStream& rStrm );
+
+private:
+    /** Imports row settings from a ROW record. */
+    void                importRow( BiffInputStream& rStrm );
+
+    /** Reads an XF identifier and initializes a new cell. */
+    bool                readCellXfId( BiffInputStream& rStrm, const BinAddress& rAddr, bool bBiff2 );
+    /** Reads a BIFF cell address and the following XF identifier. */
+    bool                readCellHeader( BiffInputStream& rStrm, bool bBiff2 );
+    /** Reads the formula range used by shared formulas, arrays, and data tables. */
+    bool                readFormulaRef( BiffInputStream& rStrm );
+
+    /** Imports a BLANK record describing a blank but formatted cell. */
+    void                importBlank( BiffInputStream& rStrm );
+    /** Imports a BOOLERR record describing a boolean or error code cell. */
+    void                importBoolErr( BiffInputStream& rStrm );
+    /** Imports a FORMULA record describing a formula cell. */
+    void                importFormula( BiffInputStream& rStrm );
+    /** Imports an INTEGER record describing a BIFF2 integer cell. */
+    void                importInteger( BiffInputStream& rStrm );
+    /** Imports a LABEL record describing an unformatted string cell. */
+    void                importLabel( BiffInputStream& rStrm );
+    /** Imports a LABELSST record describing a string cell using the shared string list. */
+    void                importLabelSst( BiffInputStream& rStrm );
+    /** Imports a MULTBLANK record describing a range of blank but formatted cells. */
+    void                importMultBlank( BiffInputStream& rStrm );
+    /** Imports a MULTRK record describing a range of numeric cells. */
+    void                importMultRk( BiffInputStream& rStrm );
+    /** Imports a NUMBER record describing a floating-point cell. */
+    void                importNumber( BiffInputStream& rStrm );
+    /** Imports an RK record describing a numeric cell. */
+    void                importRk( BiffInputStream& rStrm );
+
+    /** Imports an ARRAY record describing an array formula of a cell range. */
+    void                importArray( BiffInputStream& rStrm );
+    /** Imports table operation from a DATATABLE or DATATABLE2 record. */
+    void                importDataTable( BiffInputStream& rStrm );
+    /** Imports a SHAREDFMLA record describing a shared formula in a cell range. */
+    void                importSharedFmla( BiffInputStream& rStrm );
+
+private:
+    sal_uInt32          mnFormulaSkipSize;  /// Number of bytes to be ignored in FORMULA record.
+    sal_uInt32          mnArraySkipSize;    /// Number of bytes to be ignored in ARRAY record.
+    sal_uInt16          mnBiff2XfId;        /// Current XF identifier from IXFE record.
+    OptValue< bool >    mobBiff2HasXfs;     /// Select XF formatting or direct formatting in BIFF2.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/stylesbuffer.hxx b/sc/source/filter/inc/stylesbuffer.hxx
new file mode 100644
index 000000000000..4b98cb9baa14
--- /dev/null
+++ b/sc/source/filter/inc/stylesbuffer.hxx
@@ -0,0 +1,1099 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_STYLESBUFFER_HXX
+#define OOX_XLS_STYLESBUFFER_HXX
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/drawingml/color.hxx"
+#include "oox/helper/graphichelper.hxx"
+#include "oox/helper/refmap.hxx"
+#include "oox/helper/refvector.hxx"
+#include "numberformatsbuffer.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace awt { struct FontDescrtiptor; }
+} } }
+
+namespace oox { class PropertySet; }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+const sal_Int32 OOX_COLOR_WINDOWTEXT3       = 24;       /// System window text color (BIFF3-BIFF4).
+const sal_Int32 OOX_COLOR_WINDOWBACK3       = 25;       /// System window background color (BIFF3-BIFF4).
+const sal_Int32 OOX_COLOR_WINDOWTEXT        = 64;       /// System window text color (BIFF5+).
+const sal_Int32 OOX_COLOR_WINDOWBACK        = 65;       /// System window background color (BIFF5+).
+const sal_Int32 OOX_COLOR_BUTTONBACK        = 67;       /// System button background color (face color).
+const sal_Int32 OOX_COLOR_CHWINDOWTEXT      = 77;       /// System window text color (BIFF8 charts).
+const sal_Int32 OOX_COLOR_CHWINDOWBACK      = 78;       /// System window background color (BIFF8 charts).
+const sal_Int32 OOX_COLOR_CHBORDERAUTO      = 79;       /// Automatic frame border (BIFF8 charts).
+const sal_Int32 OOX_COLOR_NOTEBACK          = 80;       /// Note background color.
+const sal_Int32 OOX_COLOR_NOTETEXT          = 81;       /// Note text color.
+const sal_Int32 OOX_COLOR_FONTAUTO          = 0x7FFF;   /// Font auto color (system window text color).
+
+// ----------------------------------------------------------------------------
+
+const sal_Int16 API_LINE_NONE               = 0;
+const sal_Int16 API_LINE_HAIR               = 2;
+const sal_Int16 API_LINE_THIN               = 35;
+const sal_Int16 API_LINE_MEDIUM             = 88;
+const sal_Int16 API_LINE_THICK              = 141;
+
+const sal_Int16 API_ESCAPE_NONE             = 0;        /// No escapement.
+const sal_Int16 API_ESCAPE_SUPERSCRIPT      = 101;      /// Superscript: raise characters automatically (magic value 101).
+const sal_Int16 API_ESCAPE_SUBSCRIPT        = -101;     /// Subscript: lower characters automatically (magic value -101).
+
+const sal_Int8 API_ESCAPEHEIGHT_NONE        = 100;      /// Relative character height if not escaped.
+const sal_Int8 API_ESCAPEHEIGHT_DEFAULT     = 58;       /// Relative character height if escaped.
+
+// ============================================================================
+
+/** Special implementation of the GraphicHelper for Excel palette and scheme
+    colors.
+ */
+class ExcelGraphicHelper : public GraphicHelper, public WorkbookHelper
+{
+public:
+    explicit            ExcelGraphicHelper( const WorkbookHelper& rHelper );
+
+    /** Derived classes may implement to resolve a scheme color from the passed XML token identifier. */
+    virtual sal_Int32   getSchemeColor( sal_Int32 nToken ) const;
+    /** Derived classes may implement to resolve a palette index to an RGB color. */
+    virtual sal_Int32   getPaletteColor( sal_Int32 nPaletteIdx ) const;
+};
+
+// ============================================================================
+
+class Color : public ::oox::drawingml::Color
+{
+public:
+    /** Sets the color to automatic. */
+    void                setAuto();
+    /** Sets the color to the passed RGB value. */
+    void                setRgb( sal_Int32 nRgbValue, double fTint = 0.0 );
+    /** Sets the color to the passed theme index. */
+    void                setTheme( sal_Int32 nThemeIdx, double fTint = 0.0 );
+    /** Sets the color to the passed palette index. */
+    void                setIndexed( sal_Int32 nPaletteIdx, double fTint = 0.0 );
+
+    /** Imports the color from the passed attribute list. */
+    void                importColor( const AttributeList& rAttribs );
+
+    /** Imports a 64-bit color from the passed binary stream. */
+    void                importColor( SequenceInputStream& rStrm );
+    /** Imports a 32-bit palette color identifier from the passed BIFF12 stream. */
+    void                importColorId( SequenceInputStream& rStrm );
+
+    /** Imports an 8-bit or 16-bit palette color identifier from the passed BIFF stream. */
+    void                importColorId( BiffInputStream& rStrm, bool b16Bit = true );
+    /** Imports a 32-bit RGBA color value from the passed BIFF stream. */
+    void                importColorRgb( BiffInputStream& rStrm );
+
+    /** Returns true, if the color is set to automatic. */
+    inline bool         isAuto() const { return isPlaceHolder(); }
+};
+
+// ----------------------------------------------------------------------------
+
+SequenceInputStream& operator>>( SequenceInputStream& rStrm, Color& orColor );
+
+// ============================================================================
+
+/** Stores all colors of the color palette. */
+class ColorPalette : public WorkbookHelper
+{
+public:
+    /** Constructs the color palette with predefined color values. */
+    explicit            ColorPalette( const WorkbookHelper& rHelper );
+
+    /** Appends a new color from the passed attributes. */
+    void                importPaletteColor( const AttributeList& rAttribs );
+    /** Appends a new color from the passed RGBCOLOR record. */
+    void                importPaletteColor( SequenceInputStream& rStrm );
+    /** Imports the PALETTE record from the passed stream. */
+    void                importPalette( BiffInputStream& rStrm );
+    /** Imports a color palette from a UNO sequence in the passed any. */
+    void                importPalette( const ::com::sun::star::uno::Any& rPalette );
+
+    /** Rturns the RGB value of the color with the passed index. */
+    sal_Int32           getColor( sal_Int32 nPaletteIdx ) const;
+
+private:
+    /** Appends the passed color. */
+    void                appendColor( sal_Int32 nRGBValue );
+
+private:
+    ::std::vector< sal_Int32 > maColors;    /// List of RGB values.
+    size_t              mnAppendIndex;      /// Index to append a new color.
+};
+
+// ============================================================================
+
+/** Contains all XML font attributes, e.g. from a font or rPr element. */
+struct FontModel
+{
+    ::rtl::OUString     maName;             /// Font name.
+    Color               maColor;            /// Font color.
+    sal_Int32           mnScheme;           /// Major/minor scheme font.
+    sal_Int32           mnFamily;           /// Font family.
+    sal_Int32           mnCharSet;          /// Windows font character set.
+    double              mfHeight;           /// Font height in points.
+    sal_Int32           mnUnderline;        /// Underline style.
+    sal_Int32           mnEscapement;       /// Escapement style.
+    bool                mbBold;             /// True = bold characters.
+    bool                mbItalic;           /// True = italic characters.
+    bool                mbStrikeout;        /// True = Strike out characters.
+    bool                mbOutline;          /// True = outlined characters.
+    bool                mbShadow;           /// True = shadowed chgaracters.
+
+    explicit            FontModel();
+
+    void                setBiff12Scheme( sal_uInt8 nScheme );
+    void                setBiffHeight( sal_uInt16 nHeight );
+    void                setBiffWeight( sal_uInt16 nWeight );
+    void                setBiffUnderline( sal_uInt16 nUnderline );
+    void                setBiffEscapement( sal_uInt16 nEscapement );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Enumerates different types of API font property sets. */
+enum FontPropertyType
+{
+    FONT_PROPTYPE_CELL,             /// Font properties in a spreadsheet cell (table::Cell service).
+    FONT_PROPTYPE_TEXT              /// Font properties in a text object (text::Text service).
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains used flags for all API font attributes. */
+struct ApiFontUsedFlags
+{
+    bool                mbNameUsed;         /// True = font name/family/char set are used.
+    bool                mbColorUsed;        /// True = font color is used.
+    bool                mbSchemeUsed;       /// True = font scheme is used.
+    bool                mbHeightUsed;       /// True = font height is used.
+    bool                mbUnderlineUsed;    /// True = underline style is used.
+    bool                mbEscapementUsed;   /// True = escapement style is used.
+    bool                mbWeightUsed;       /// True = font weight (boldness) is used.
+    bool                mbPostureUsed;      /// True = font posture (italic) is used.
+    bool                mbStrikeoutUsed;    /// True = strike out style is used.
+    bool                mbOutlineUsed;      /// True = outline style is used.
+    bool                mbShadowUsed;       /// True = shadow style is used.
+
+    explicit            ApiFontUsedFlags( bool bAllUsed );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains API font name, family, and charset for a script type. */
+struct ApiScriptFontName
+{
+    ::rtl::OUString     maName;             /// Font name.
+    sal_Int16           mnFamily;           /// Font family.
+    sal_Int16           mnTextEnc;          /// Font text encoding.
+
+    explicit            ApiScriptFontName();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains all API font attributes. */
+struct ApiFontData
+{
+    typedef ::com::sun::star::awt::FontDescriptor ApiFontDescriptor;
+
+    ApiScriptFontName   maLatinFont;        /// Font name for latin scripts.
+    ApiScriptFontName   maAsianFont;        /// Font name for east-asian scripts.
+    ApiScriptFontName   maCmplxFont;        /// Font name for complex scripts.
+    ApiFontDescriptor   maDesc;             /// Font descriptor (height in twips, weight in %).
+    sal_Int32           mnColor;            /// Font color.
+    sal_Int16           mnEscapement;       /// Escapement style.
+    sal_Int8            mnEscapeHeight;     /// Escapement font height.
+    bool                mbOutline;          /// True = outlined characters.
+    bool                mbShadow;           /// True = shadowed chgaracters.
+
+    explicit            ApiFontData();
+};
+
+// ============================================================================
+
+class Font : public WorkbookHelper
+{
+public:
+    explicit            Font( const WorkbookHelper& rHelper, bool bDxf );
+    explicit            Font( const WorkbookHelper& rHelper, const FontModel& rModel );
+
+    /** Sets font formatting attributes for the passed element. */
+    void                importAttribs( sal_Int32 nElement, const AttributeList& rAttribs );
+
+    /** Imports the FONT record from the passed stream. */
+    void                importFont( SequenceInputStream& rStrm );
+    /** Imports the font name from a DXF record. */
+    void                importDxfName( SequenceInputStream& rStrm );
+    /** Imports the font color from a DXF record. */
+    void                importDxfColor( SequenceInputStream& rStrm );
+    /** Imports the font scheme from a DXF record. */
+    void                importDxfScheme( SequenceInputStream& rStrm );
+    /** Imports the font height from a DXF record. */
+    void                importDxfHeight( SequenceInputStream& rStrm );
+    /** Imports the font weight from a DXF record. */
+    void                importDxfWeight( SequenceInputStream& rStrm );
+    /** Imports the font underline style from a DXF record. */
+    void                importDxfUnderline( SequenceInputStream& rStrm );
+    /** Imports the font escapement style from a DXF record. */
+    void                importDxfEscapement( SequenceInputStream& rStrm );
+    /** Imports a font style flag from a DXF record. */
+    void                importDxfFlag( sal_Int32 nElement, SequenceInputStream& rStrm );
+
+    /** Imports the FONT record from the passed stream. */
+    void                importFont( BiffInputStream& rStrm );
+    /** Imports the FONTCOLOR record from the passed stream. */
+    void                importFontColor( BiffInputStream& rStrm );
+    /** Sets the font attributes from the font block of a CFRULE record. */
+    void                importCfRule( BiffInputStream& rStrm );
+
+    /** Returns the font model structure. This function can be called before
+        finalizeImport() has been called. */
+    inline const FontModel& getModel() const { return maModel; }
+    /** Returns the text encoding for strings used with this font. This
+        function can be called before finalizeImport() has been called. */
+    rtl_TextEncoding    getFontEncoding() const;
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Returns an API font descriptor with own font information. */
+    const ::com::sun::star::awt::FontDescriptor& getFontDescriptor() const;
+    /** Returns true, if the font requires rich text formatting in Calc.
+        @descr  Example: Font escapement is a cell attribute in Excel, but Calc
+        needs an rich text cell for this attribute. */
+    bool                needsRichTextFormat() const;
+
+    /** Writes all font attributes to the passed property map. */
+    void                writeToPropertyMap(
+                            PropertyMap& rPropMap,
+                            FontPropertyType ePropType ) const;
+    /** Writes all font attributes to the passed property set. */
+    void                writeToPropertySet(
+                            PropertySet& rPropSet,
+                            FontPropertyType ePropType ) const;
+
+private:
+    /** Reads and sets height and flags. */
+    void                importFontData2( BiffInputStream& rStrm );
+    /** Reads and sets weight, escapement, underline, family, charset (BIFF5+). */
+    void                importFontData5( BiffInputStream& rStrm );
+
+    /** Reads and sets a byte string as font name. */
+    void                importFontName2( BiffInputStream& rStrm );
+    /** Reads and sets a Unicode string as font name. */
+    void                importFontName8( BiffInputStream& rStrm );
+
+private:
+    FontModel           maModel;
+    ApiFontData         maApiData;
+    ApiFontUsedFlags    maUsedFlags;
+    bool                mbDxf;
+};
+
+typedef ::boost::shared_ptr< Font > FontRef;
+
+// ============================================================================
+
+/** Contains all XML cell alignment attributes, e.g. from an alignment element. */
+struct AlignmentModel
+{
+    sal_Int32           mnHorAlign;         /// Horizontal alignment.
+    sal_Int32           mnVerAlign;         /// Vertical alignment.
+    sal_Int32           mnTextDir;          /// CTL text direction.
+    sal_Int32           mnRotation;         /// Text rotation angle.
+    sal_Int32           mnIndent;           /// Indentation.
+    bool                mbWrapText;         /// True = multi-line text.
+    bool                mbShrink;           /// True = shrink to fit cell size.
+    bool                mbJustLastLine;     /// True = justify last line in block text.
+
+    explicit            AlignmentModel();
+
+    /** Sets horizontal alignment from the passed BIFF data. */
+    void                setBiffHorAlign( sal_uInt8 nHorAlign );
+    /** Sets vertical alignment from the passed BIFF data. */
+    void                setBiffVerAlign( sal_uInt8 nVerAlign );
+    /** Sets rotation from the passed BIFF text orientation. */
+    void                setBiffTextOrient( sal_uInt8 nTextOrient );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains all API cell alignment attributes. */
+struct ApiAlignmentData
+{
+    typedef ::com::sun::star::table::CellHoriJustify ApiCellHoriJustify;
+    typedef ::com::sun::star::table::CellOrientation ApiCellOrientation;
+
+    ApiCellHoriJustify  meHorJustify;       /// Horizontal alignment.
+    sal_Int32           mnHorJustifyMethod;
+    sal_Int32           mnVerJustify;       /// Vertical alignment.
+    sal_Int32           mnVerJustifyMethod;
+    ApiCellOrientation  meOrientation;      /// Normal or stacked text.
+    sal_Int32           mnRotation;         /// Text rotation angle.
+    sal_Int16           mnWritingMode;      /// CTL text direction.
+    sal_Int16           mnIndent;           /// Indentation.
+    bool                mbWrapText;         /// True = multi-line text.
+    bool                mbShrink;           /// True = shrink to fit cell size.
+
+    explicit            ApiAlignmentData();
+};
+
+bool operator==( const ApiAlignmentData& rLeft, const ApiAlignmentData& rRight );
+
+// ============================================================================
+
+class Alignment : public WorkbookHelper
+{
+public:
+    explicit            Alignment( const WorkbookHelper& rHelper );
+
+    /** Sets all attributes from the alignment element. */
+    void                importAlignment( const AttributeList& rAttribs );
+
+    /** Sets the alignment attributes from the passed BIFF12 XF record data. */
+    void                setBiff12Data( sal_uInt32 nFlags );
+    /** Sets the alignment attributes from the passed BIFF2 XF record data. */
+    void                setBiff2Data( sal_uInt8 nFlags );
+    /** Sets the alignment attributes from the passed BIFF3 XF record data. */
+    void                setBiff3Data( sal_uInt16 nAlign );
+    /** Sets the alignment attributes from the passed BIFF4 XF record data. */
+    void                setBiff4Data( sal_uInt16 nAlign );
+    /** Sets the alignment attributes from the passed BIFF5 XF record data. */
+    void                setBiff5Data( sal_uInt16 nAlign );
+    /** Sets the alignment attributes from the passed BIFF8 XF record data. */
+    void                setBiff8Data( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Returns the alignment model structure. */
+    inline const AlignmentModel& getModel() const { return maModel; }
+    /** Returns the converted API alignment data struct. */
+    inline const ApiAlignmentData& getApiData() const { return maApiData; }
+
+    /** Writes all alignment attributes to the passed property map. */
+    void                writeToPropertyMap( PropertyMap& rPropMap ) const;
+
+private:
+    AlignmentModel      maModel;            /// Alignment model data.
+    ApiAlignmentData    maApiData;          /// Alignment data converted to API constants.
+};
+
+typedef ::boost::shared_ptr< Alignment > AlignmentRef;
+
+// ============================================================================
+
+/** Contains all XML cell protection attributes, e.g. from a protection element. */
+struct ProtectionModel
+{
+    bool                mbLocked;           /// True = locked against editing.
+    bool                mbHidden;           /// True = formula is hidden.
+
+    explicit            ProtectionModel();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains all API cell protection attributes. */
+struct ApiProtectionData
+{
+    typedef ::com::sun::star::util::CellProtection ApiCellProtection;
+
+    ApiCellProtection   maCellProt;
+
+    explicit            ApiProtectionData();
+};
+
+bool operator==( const ApiProtectionData& rLeft, const ApiProtectionData& rRight );
+
+// ============================================================================
+
+class Protection : public WorkbookHelper
+{
+public:
+    explicit            Protection( const WorkbookHelper& rHelper );
+
+    /** Sets all attributes from the protection element. */
+    void                importProtection( const AttributeList& rAttribs );
+
+    /** Sets the protection attributes from the passed BIFF12 XF record data. */
+    void                setBiff12Data( sal_uInt32 nFlags );
+    /** Sets the protection attributes from the passed BIFF2 XF record data. */
+    void                setBiff2Data( sal_uInt8 nNumFmt );
+    /** Sets the protection attributes from the passed BIFF3-BIFF8 XF record data. */
+    void                setBiff3Data( sal_uInt16 nProt );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Returns the protection model structure. */
+    inline const ProtectionModel& getModel() const { return maModel; }
+    /** Returns the converted API protection data struct. */
+    inline const ApiProtectionData& getApiData() const { return maApiData; }
+
+    /** Writes all protection attributes to the passed property map. */
+    void                writeToPropertyMap( PropertyMap& rPropMap ) const;
+
+private:
+    ProtectionModel     maModel;            /// Protection model data.
+    ApiProtectionData   maApiData;          /// Protection data converted to API constants.
+};
+
+typedef ::boost::shared_ptr< Protection > ProtectionRef;
+
+// ============================================================================
+
+/** Contains XML attributes of a single border line. */
+struct BorderLineModel
+{
+    Color               maColor;            /// Borderline color.
+    sal_Int32           mnStyle;            /// Border line style.
+    bool                mbUsed;             /// True = line format used.
+
+    explicit            BorderLineModel( bool bDxf );
+
+    /** Sets the passed BIFF line style. */
+    void                setBiffStyle( sal_Int32 nLineStyle );
+    /** Sets line style and line color from the passed BIFF data. */
+    void                setBiffData( sal_uInt8 nLineStyle, sal_uInt16 nLineColor );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains XML attributes of a complete cell border. */
+struct BorderModel
+{
+    BorderLineModel     maLeft;             /// Left line format.
+    BorderLineModel     maRight;            /// Right line format.
+    BorderLineModel     maTop;              /// Top line format.
+    BorderLineModel     maBottom;           /// Bottom line format.
+    BorderLineModel     maDiagonal;         /// Diagonal line format.
+    bool                mbDiagTLtoBR;       /// True = top-left to bottom-right on.
+    bool                mbDiagBLtoTR;       /// True = bottom-left to top-right on.
+
+    explicit            BorderModel( bool bDxf );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains API attributes of a complete cell border. */
+struct ApiBorderData
+{
+    typedef ::com::sun::star::table::BorderLine2     ApiBorderLine;
+
+    ApiBorderLine       maLeft;             /// Left line format
+    ApiBorderLine       maRight;            /// Right line format
+    ApiBorderLine       maTop;              /// Top line format
+    ApiBorderLine       maBottom;           /// Bottom line format
+    ApiBorderLine       maTLtoBR;           /// Diagonal top-left to bottom-right line format.
+    ApiBorderLine       maBLtoTR;           /// Diagonal bottom-left to top-right line format.
+    bool                mbBorderUsed;       /// True = left/right/top/bottom line format used.
+    bool                mbDiagUsed;         /// True = diagonal line format used.
+
+    explicit            ApiBorderData();
+
+    /** Returns true, if any of the outer border lines is visible. */
+    bool                hasAnyOuterBorder() const;
+};
+
+bool operator==( const ApiBorderData& rLeft, const ApiBorderData& rRight );
+
+// ============================================================================
+
+class Border : public WorkbookHelper
+{
+public:
+    explicit            Border( const WorkbookHelper& rHelper, bool bDxf );
+
+    /** Sets global border attributes from the border element. */
+    void                importBorder( const AttributeList& rAttribs );
+    /** Sets border attributes for the border line with the passed element identifier. */
+    void                importStyle( sal_Int32 nElement, const AttributeList& rAttribs );
+    /** Sets color attributes for the border line with the passed element identifier. */
+    void                importColor( sal_Int32 nElement, const AttributeList& rAttribs );
+
+    /** Imports the BORDER record from the passed stream. */
+    void                importBorder( SequenceInputStream& rStrm );
+    /** Imports a border from a DXF record from the passed stream. */
+    void                importDxfBorder( sal_Int32 nElement, SequenceInputStream& rStrm );
+
+    /** Sets the border attributes from the passed BIFF2 XF record data. */
+    void                setBiff2Data( sal_uInt8 nFlags );
+    /** Sets the border attributes from the passed BIFF3/BIFF4 XF record data. */
+    void                setBiff3Data( sal_uInt32 nBorder );
+    /** Sets the border attributes from the passed BIFF5 XF record data. */
+    void                setBiff5Data( sal_uInt32 nBorder, sal_uInt32 nArea );
+    /** Sets the border attributes from the passed BIFF8 XF record data. */
+    void                setBiff8Data( sal_uInt32 nBorder1, sal_uInt32 nBorder2 );
+    /** Sets the border attributes from the border block of a CFRULE record. */
+    void                importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Returns the border model structure. */
+    inline const BorderModel& getModel() const { return maModel; }
+    /** Returns the converted API border data struct. */
+    inline const ApiBorderData& getApiData() const { return maApiData; }
+
+    /** Writes all border attributes to the passed property map. */
+    void                writeToPropertyMap( PropertyMap& rPropMap ) const;
+
+    bool                hasBorder() const;
+
+private:
+    /** Returns the border line struct specified by the passed XML token identifier. */
+    BorderLineModel*    getBorderLine( sal_Int32 nElement );
+
+    /** Converts border line data to an API struct, returns true, if the line is marked as used. */
+    bool                convertBorderLine(
+                            ::com::sun::star::table::BorderLine2& rBorderLine,
+                            const BorderLineModel& rModel );
+
+private:
+    BorderModel         maModel;
+    ApiBorderData       maApiData;
+    bool                mbDxf;
+};
+
+typedef ::boost::shared_ptr< Border > BorderRef;
+
+// ============================================================================
+
+/** Contains XML pattern fill attributes from the patternFill element. */
+struct PatternFillModel
+{
+    Color               maPatternColor;     /// Pattern foreground color.
+    Color               maFillColor;        /// Background fill color.
+    sal_Int32           mnPattern;          /// Pattern identifier (e.g. solid).
+    bool                mbPattColorUsed;    /// True = pattern foreground color used.
+    bool                mbFillColorUsed;    /// True = background fill color used.
+    bool                mbPatternUsed;      /// True = pattern used.
+
+    explicit            PatternFillModel( bool bDxf );
+
+    /** Sets the passed BIFF pattern identifier. */
+    void                setBiffPattern( sal_Int32 nPattern );
+    /** Sets the pattern and pattern colors from the passed BIFF data. */
+    void                setBiffData( sal_uInt16 nPatternColor, sal_uInt16 nFillColor, sal_uInt8 nPattern );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains XML gradient fill attributes from the gradientFill element. */
+struct GradientFillModel
+{
+    typedef ::std::map< double, Color > ColorMap;
+
+    sal_Int32           mnType;             /// Gradient type, linear or path.
+    double              mfAngle;            /// Rotation angle for type linear.
+    double              mfLeft;             /// Left convergence for type path.
+    double              mfRight;            /// Right convergence for type path.
+    double              mfTop;              /// Top convergence for type path.
+    double              mfBottom;           /// Bottom convergence for type path.
+    ColorMap            maColors;           /// Gradient colors.
+
+    explicit            GradientFillModel();
+
+    /** Reads BIFF12 gradient settings from a FILL or DXF record. */
+    void                readGradient( SequenceInputStream& rStrm );
+    /** Reads BIFF12 gradient stop settings from a FILL or DXF record. */
+    void                readGradientStop( SequenceInputStream& rStrm, bool bDxf );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains API fill attributes. */
+struct ApiSolidFillData
+{
+    sal_Int32           mnColor;            /// Fill color.
+    bool                mbTransparent;      /// True = transparent area.
+    bool                mbUsed;             /// True = fill data is valid.
+
+    explicit            ApiSolidFillData();
+};
+
+bool operator==( const ApiSolidFillData& rLeft, const ApiSolidFillData& rRight );
+
+// ============================================================================
+
+/** Contains cell fill attributes, either a pattern fill or a gradient fill. */
+class Fill : public WorkbookHelper
+{
+public:
+    explicit            Fill( const WorkbookHelper& rHelper, bool bDxf );
+
+    /** Sets attributes of a patternFill element. */
+    void                importPatternFill( const AttributeList& rAttribs );
+    /** Sets the pattern color from the fgColor element. */
+    void                importFgColor( const AttributeList& rAttribs );
+    /** Sets the background color from the bgColor element. */
+    void                importBgColor( const AttributeList& rAttribs );
+    /** Sets attributes of a gradientFill element. */
+    void                importGradientFill( const AttributeList& rAttribs );
+    /** Sets a color from the color element in a gradient fill. */
+    void                importColor( const AttributeList& rAttribs, double fPosition );
+
+    /** Imports the FILL record from the passed stream. */
+    void                importFill( SequenceInputStream& rStrm );
+    /** Imports the fill pattern from a DXF record. */
+    void                importDxfPattern( SequenceInputStream& rStrm );
+    /** Imports the pattern color from a DXF record. */
+    void                importDxfFgColor( SequenceInputStream& rStrm );
+    /** Imports the background color from a DXF record. */
+    void                importDxfBgColor( SequenceInputStream& rStrm );
+    /** Imports gradient settings from a DXF record. */
+    void                importDxfGradient( SequenceInputStream& rStrm );
+    /** Imports gradient stop settings from a DXF record. */
+    void                importDxfStop( SequenceInputStream& rStrm );
+
+    /** Sets the fill attributes from the passed BIFF2 XF record data. */
+    void                setBiff2Data( sal_uInt8 nFlags );
+    /** Sets the fill attributes from the passed BIFF3/BIFF4 XF record data. */
+    void                setBiff3Data( sal_uInt16 nArea );
+    /** Sets the fill attributes from the passed BIFF5 XF record data. */
+    void                setBiff5Data( sal_uInt32 nArea );
+    /** Sets the fill attributes from the passed BIFF8 XF record data. */
+    void                setBiff8Data( sal_uInt32 nBorder2, sal_uInt16 nArea );
+    /** Sets the fill attributes from the fill block of a CFRULE record. */
+    void                importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Returns the fill pattern model structure, if extant. */
+    inline const PatternFillModel* getPatternModel() const { return mxPatternModel.get(); }
+    /** Returns the fill gradient model structure, if extant. */
+    inline const GradientFillModel* getGradientModel() const { return mxGradientModel.get(); }
+    /** Returns the converted API fill data struct. */
+    inline const ApiSolidFillData& getApiData() const { return maApiData; }
+
+    /** Writes all fill attributes to the passed property map. */
+    void                writeToPropertyMap( PropertyMap& rPropMap ) const;
+
+private:
+    typedef ::boost::shared_ptr< PatternFillModel >   PatternModelRef;
+    typedef ::boost::shared_ptr< GradientFillModel >  GradientModelRef;
+
+    PatternModelRef     mxPatternModel;
+    GradientModelRef    mxGradientModel;
+    ApiSolidFillData    maApiData;
+    bool                mbDxf;
+};
+
+typedef ::boost::shared_ptr< Fill > FillRef;
+
+// ============================================================================
+
+/** Contains all data for a cell format or cell style. */
+struct XfModel
+{
+    sal_Int32           mnStyleXfId;        /// Index to parent style XF.
+    sal_Int32           mnFontId;           /// Index to font data list.
+    sal_Int32           mnNumFmtId;         /// Index to number format list.
+    sal_Int32           mnBorderId;         /// Index to list of cell borders.
+    sal_Int32           mnFillId;           /// Index to list of cell areas.
+    bool                mbCellXf;           /// True = cell XF, false = style XF.
+    bool                mbFontUsed;         /// True = font index used.
+    bool                mbNumFmtUsed;       /// True = number format used.
+    bool                mbAlignUsed;        /// True = alignment used.
+    bool                mbProtUsed;         /// True = cell protection used.
+    bool                mbBorderUsed;       /// True = border data used.
+    bool                mbAreaUsed;         /// True = area data used.
+
+    explicit            XfModel();
+};
+
+// ============================================================================
+
+/** Represents a cell format or a cell style (called XF, extended format).
+
+    This class stores the type (cell/style), the index to the parent style (if
+    it is a cell format) and all "attribute used" flags, which reflect the
+    state of specific attribute groups (true = user has changed the attributes)
+    and all formatting data.
+ */
+class Xf : public WorkbookHelper
+{
+public:
+    explicit            Xf( const WorkbookHelper& rHelper );
+
+    /** Sets all "attribute used" flags to the passed state. */
+    void                setAllUsedFlags( bool bUsed );
+
+    /** Sets all attributes from the xf element. */
+    void                importXf( const AttributeList& rAttribs, bool bCellXf );
+    /** Sets all attributes from the alignment element. */
+    void                importAlignment( const AttributeList& rAttribs );
+    /** Sets all attributes from the protection element. */
+    void                importProtection( const AttributeList& rAttribs );
+
+    /** Imports the XF record from the passed stream. */
+    void                importXf( SequenceInputStream& rStrm, bool bCellXf );
+
+    /** Imports the XF record from the passed stream. */
+    void                importXf( BiffInputStream& rStrm );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Returns true, if the XF is a cell XF, and false, if it is a style XF. */
+    inline bool         isCellXf() const { return maModel.mbCellXf; }
+
+    /** Returns the referred font object. */
+    FontRef             getFont() const;
+    /** Returns the alignment data of this style. */
+    inline const Alignment& getAlignment() const { return maAlignment; }
+    /** Returns the cell protection data of this style. */
+    inline const Protection& getProtection() const { return maProtection; }
+
+    /** Writes all formatting attributes to the passed property map. */
+    void                writeToPropertyMap( PropertyMap& rPropMap ) const;
+    /** Writes all formatting attributes to the passed property set. */
+    void                writeToPropertySet( PropertySet& rPropSet ) const;
+
+    /** Converts formatting information from BIFF2 cell record data directly. */
+    static void         writeBiff2CellFormatToPropertySet(
+                            const WorkbookHelper& rHelper, PropertySet& rPropSet,
+                            sal_uInt8 nFlags1, sal_uInt8 nFlags2, sal_uInt8 nFlags3 );
+
+private:
+    /** Sets 'attribute used' flags from the passed BIFF bit field. */
+    void                setBiffUsedFlags( sal_uInt8 nUsedFlags );
+
+private:
+    XfModel             maModel;            /// Cell XF or style XF model data.
+    Alignment           maAlignment;        /// Cell alignment data.
+    Protection          maProtection;       /// Cell protection data.
+    sal_Int32           meRotationRef;      /// Rotation reference dependent on border.
+};
+
+typedef ::boost::shared_ptr< Xf > XfRef;
+
+// ============================================================================
+
+class Dxf : public WorkbookHelper
+{
+public:
+    explicit            Dxf( const WorkbookHelper& rHelper );
+
+    /** Creates a new empty font object. */
+    FontRef             createFont( bool bAlwaysNew = true );
+    /** Creates a new empty border object. */
+    BorderRef           createBorder( bool bAlwaysNew = true );
+    /** Creates a new empty fill object. */
+    FillRef             createFill( bool bAlwaysNew = true );
+
+    /** Inserts a new number format code. */
+    void                importNumFmt( const AttributeList& rAttribs );
+
+    /** Imports the DXF record from the passed stream. */
+    void                importDxf( SequenceInputStream& rStrm );
+
+    /** Imports font, border, and fill settings from the CFRULE record. */
+    void                importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Writes all formatting attributes to the passed property map. */
+    void                writeToPropertyMap( PropertyMap& rPropMap ) const;
+    /** Writes all formatting attributes to the passed property set. */
+    void                writeToPropertySet( PropertySet& rPropSet ) const;
+
+private:
+    FontRef             mxFont;             /// Font data.
+    NumberFormatRef     mxNumFmt;           /// Number format data.
+    AlignmentRef        mxAlignment;        /// Alignment data.
+    ProtectionRef       mxProtection;       /// Protection data.
+    BorderRef           mxBorder;           /// Border data.
+    FillRef             mxFill;             /// Fill data.
+};
+
+typedef ::boost::shared_ptr< Dxf > DxfRef;
+
+// ============================================================================
+
+/** Contains attributes of a cell style, e.g. from the cellStyle element. */
+struct CellStyleModel
+{
+    ::rtl::OUString     maName;             /// Cell style name.
+    sal_Int32           mnXfId;             /// Formatting for this cell style.
+    sal_Int32           mnBuiltinId;        /// Identifier for builtin styles.
+    sal_Int32           mnLevel;            /// Level for builtin column/row styles.
+    bool                mbBuiltin;          /// True = builtin style.
+    bool                mbCustom;           /// True = customized builtin style.
+    bool                mbHidden;           /// True = style not visible in GUI.
+
+    explicit            CellStyleModel();
+
+    /** Returns true, if this style is a builtin style. */
+    bool                isBuiltin() const;
+    /** Returns true, if this style represents the default document cell style. */
+    bool                isDefaultStyle() const;
+};
+
+// ============================================================================
+
+class CellStyle : public WorkbookHelper
+{
+public:
+    explicit            CellStyle( const WorkbookHelper& rHelper );
+
+    /** Imports passed attributes from the cellStyle element. */
+    void                importCellStyle( const AttributeList& rAttribs );
+    /** Imports style settings from a CELLSTYLE record. */
+    void                importCellStyle( SequenceInputStream& rStrm );
+    /** Imports style settings from a STYLE record. */
+    void                importStyle( BiffInputStream& rStrm );
+
+    /** Creates the style sheet in the document described by this cell style object. */
+    void                createCellStyle();
+    /** Stores tha passed final style name and creates the cell style, if it is
+        user-defined or modified built-in. */
+    void                finalizeImport( const ::rtl::OUString& rFinalName );
+
+    /** Returns the cell style model structure. */
+    inline const CellStyleModel& getModel() const { return maModel; }
+    /** Returns the final style name used in the document. */
+    inline const ::rtl::OUString& getFinalStyleName() const { return maFinalName; }
+
+private:
+    CellStyleModel      maModel;
+    ::rtl::OUString     maFinalName;        /// Final style name used in API.
+    bool                mbCreated;          /// True = style sheet created.
+};
+
+typedef ::boost::shared_ptr< CellStyle > CellStyleRef;
+
+// ============================================================================
+
+class CellStyleBuffer : public WorkbookHelper
+{
+public:
+    explicit            CellStyleBuffer( const WorkbookHelper& rHelper );
+
+    /** Appends and returns a new named cell style object. */
+    CellStyleRef        importCellStyle( const AttributeList& rAttribs );
+    /** Imports the CELLSTYLE record from the passed stream. */
+    CellStyleRef        importCellStyle( SequenceInputStream& rStrm );
+    /** Imports the STYLE record from the passed stream. */
+    CellStyleRef        importStyle( BiffInputStream& rStrm );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Returns the XF identifier associated to the default cell style. */
+    sal_Int32           getDefaultXfId() const;
+    /** Returns the default style sheet for unused cells. */
+    ::rtl::OUString     getDefaultStyleName() const;
+    /** Creates the style sheet described by the style XF with the passed identifier. */
+    ::rtl::OUString     createCellStyle( sal_Int32 nXfId ) const;
+
+private:
+    /** Inserts the passed cell style object into the internal maps. */
+    void                insertCellStyle( CellStyleRef xCellStyle );
+    /** Creates the style sheet described by the passed cell style object. */
+    ::rtl::OUString     createCellStyle( const CellStyleRef& rxCellStyle ) const;
+
+private:
+    typedef RefVector< CellStyle >          CellStyleVector;
+    typedef RefMap< sal_Int32, CellStyle >  CellStyleXfIdMap;
+
+    CellStyleVector     maBuiltinStyles;    /// All built-in cell styles.
+    CellStyleVector     maUserStyles;       /// All user defined cell styles.
+    CellStyleXfIdMap    maStylesByXf;       /// All cell styles, mapped by XF identifier.
+    CellStyleRef        mxDefStyle;         /// Default cell style.
+};
+
+// ============================================================================
+
+struct AutoFormatModel
+{
+    sal_Int32           mnAutoFormatId;     /// Index of predefined autoformatting.
+    bool                mbApplyNumFmt;      /// True = apply number format from autoformatting.
+    bool                mbApplyFont;        /// True = apply font from autoformatting.
+    bool                mbApplyAlignment;   /// True = apply alignment from autoformatting.
+    bool                mbApplyBorder;      /// True = apply border from autoformatting.
+    bool                mbApplyFill;        /// True = apply fill from autoformatting.
+    bool                mbApplyProtection;  /// True = apply protection from autoformatting.
+
+    explicit            AutoFormatModel();
+};
+
+// ============================================================================
+
+class StylesBuffer : public WorkbookHelper
+{
+public:
+    explicit            StylesBuffer( const WorkbookHelper& rHelper );
+
+    /** Creates a new empty font object.
+        @param opnFontId  (out-param) The identifier of the new font object. */
+    FontRef             createFont( sal_Int32* opnFontId = 0 );
+    /** Creates a number format. */
+    NumberFormatRef     createNumFmt( sal_Int32 nNumFmtId, const ::rtl::OUString& rFmtCode );
+    /** Creates a new empty border object.
+        @param opnBorderId  (out-param) The identifier of the new border object. */
+    BorderRef           createBorder( sal_Int32* opnBorderId = 0 );
+    /** Creates a new empty fill object.
+        @param opnFillId  (out-param) The identifier of the new fill object. */
+    FillRef             createFill( sal_Int32* opnFillId = 0 );
+    /** Creates a new empty cell formatting object.
+        @param opnXfId  (out-param) The identifier of the new XF object. */
+    XfRef               createCellXf( sal_Int32* opnXfId = 0 );
+    /** Creates a new empty style formatting object.
+        @param opnXfId  (out-param) The identifier of the new XF object. */
+    XfRef               createStyleXf( sal_Int32* opnXfId = 0 );
+    /** Creates a new empty differential formatting object.
+        @param opnDxfId  (out-param) The identifier of the new DXF object. */
+    DxfRef              createDxf( sal_Int32* opnDxfId = 0 );
+
+    /** Appends a new color to the color palette. */
+    void                importPaletteColor( const AttributeList& rAttribs );
+    /** Inserts a new number format code. */
+    NumberFormatRef     importNumFmt( const AttributeList& rAttribs );
+    /** Appends and returns a new named cell style object. */
+    CellStyleRef        importCellStyle( const AttributeList& rAttribs );
+
+    /** Appends a new color to the color palette. */
+    void                importPaletteColor( SequenceInputStream& rStrm );
+    /** Imports the NUMFMT record from the passed stream. */
+    void                importNumFmt( SequenceInputStream& rStrm );
+    /** Imports the CELLSTYLE record from the passed stream. */
+    void                importCellStyle( SequenceInputStream& rStrm );
+
+    /** Imports the PALETTE record from the passed stream. */
+    void                importPalette( BiffInputStream& rStrm );
+    /** Imports the FONT record from the passed stream. */
+    void                importFont( BiffInputStream& rStrm );
+    /** Imports the FONTCOLOR record from the passed stream. */
+    void                importFontColor( BiffInputStream& rStrm );
+    /** Imports the FORMAT record from the passed stream. */
+    void                importFormat( BiffInputStream& rStrm );
+    /** Imports the XF record from the passed stream. */
+    void                importXf( BiffInputStream& rStrm );
+    /** Imports the STYLE record from the passed stream. */
+    void                importStyle( BiffInputStream& rStrm );
+
+    /** Imports a color palette from a UNO sequence in the passed any. */
+    void                importPalette( const ::com::sun::star::uno::Any& rPalette );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+
+    /** Returns the palette color with the specified index. */
+    sal_Int32           getPaletteColor( sal_Int32 nIndex ) const;
+    /** Returns the specified font object. */
+    FontRef             getFont( sal_Int32 nFontId ) const;
+    /** Returns the specified border object. */
+    BorderRef           getBorder( sal_Int32 nBorderId ) const;
+    /** Returns the specified cell format object. */
+    XfRef               getCellXf( sal_Int32 nXfId ) const;
+    /** Returns the specified style format object. */
+    XfRef               getStyleXf( sal_Int32 nXfId ) const;
+
+    /** Returns the font object of the specified cell XF. */
+    FontRef             getFontFromCellXf( sal_Int32 nXfId ) const;
+    /** Returns the default application font (used in the "Normal" cell style). */
+    FontRef             getDefaultFont() const;
+    /** Returns the model of the default application font (used in the "Normal" cell style). */
+    const FontModel&    getDefaultFontModel() const;
+
+    /** Returns true, if the specified borders are equal. */
+    bool                equalBorders( sal_Int32 nBorderId1, sal_Int32 nBorderId2 ) const;
+    /** Returns true, if the specified fills are equal. */
+    bool                equalFills( sal_Int32 nFillId1, sal_Int32 nFillId2 ) const;
+
+    /** Returns the default style sheet for unused cells. */
+    ::rtl::OUString     getDefaultStyleName() const;
+    /** Creates the style sheet described by the style XF with the passed identifier. */
+    ::rtl::OUString     createCellStyle( sal_Int32 nXfId ) const;
+    /** Creates the style sheet described by the DXF with the passed identifier. */
+    ::rtl::OUString     createDxfStyle( sal_Int32 nDxfId ) const;
+
+    /** Writes the font attributes of the specified font data to the passed property map. */
+    void                writeFontToPropertyMap( PropertyMap& rPropMap, sal_Int32 nFontId ) const;
+    /** Writes the specified number format to the passed property map. */
+    void                writeNumFmtToPropertyMap( PropertyMap& rPropMap, sal_Int32 nNumFmtId ) const;
+    /** Writes the border attributes of the specified border data to the passed property map. */
+    void                writeBorderToPropertyMap( PropertyMap& rPropMap, sal_Int32 nBorderId ) const;
+    /** Writes the fill attributes of the specified fill data to the passed property map. */
+    void                writeFillToPropertyMap( PropertyMap& rPropMap, sal_Int32 nFillId ) const;
+    /** Writes the cell formatting attributes of the specified XF to the passed property map. */
+    void                writeCellXfToPropertyMap( PropertyMap& rPropMap, sal_Int32 nXfId ) const;
+
+    /** Writes the cell formatting attributes of the specified XF to the passed property set. */
+    void                writeCellXfToPropertySet( PropertySet& rPropSet, sal_Int32 nXfId ) const;
+    /** Writes the cell formatting attributes of the specified style XF to the passed property set. */
+    void                writeStyleXfToPropertySet( PropertySet& rPropSet, sal_Int32 nXfId ) const;
+
+    bool                hasBorder( sal_Int32 nBorderId ) const;
+private:
+    typedef RefVector< Font >                           FontVector;
+    typedef RefVector< Border >                         BorderVector;
+    typedef RefVector< Fill >                           FillVector;
+    typedef RefVector< Xf >                             XfVector;
+    typedef RefVector< Dxf >                            DxfVector;
+    typedef ::std::map< sal_Int32, ::rtl::OUString >    DxfStyleMap;
+
+    ColorPalette        maPalette;          /// Color palette.
+    FontVector          maFonts;            /// List of font objects.
+    NumberFormatsBuffer maNumFmts;          /// List of all number format codes.
+    BorderVector        maBorders;          /// List of cell border objects.
+    FillVector          maFills;            /// List of cell area fill objects.
+    XfVector            maCellXfs;          /// List of cell formats.
+    XfVector            maStyleXfs;         /// List of cell styles.
+    CellStyleBuffer     maCellStyles;       /// All built-in and user defined cell styles.
+    DxfVector           maDxfs;             /// List of differential cell styles.
+    mutable DxfStyleMap maDxfStyles;        /// Maps DXF identifiers to Calc style sheet names.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/stylesfragment.hxx b/sc/source/filter/inc/stylesfragment.hxx
new file mode 100644
index 000000000000..e5815695a57f
--- /dev/null
+++ b/sc/source/filter/inc/stylesfragment.hxx
@@ -0,0 +1,158 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ***********************************************************************/
+
+#ifndef OOX_XLS_STYLESFRAGMENT_HXX
+#define OOX_XLS_STYLESFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+#include "stylesbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+class IndexedColorsContext : public WorkbookContextBase
+{
+public:
+    explicit            IndexedColorsContext( WorkbookFragmentBase& rFragment );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+};
+
+// ============================================================================
+
+class FontContext : public WorkbookContextBase
+{
+public:
+    template< typename ParentType >
+    inline explicit     FontContext( ParentType& rParent, const FontRef& rxFont ) :
+                            WorkbookContextBase( rParent ), mxFont( rxFont ) {}
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+
+private:
+    FontRef             mxFont;
+};
+
+// ============================================================================
+
+class BorderContext : public WorkbookContextBase
+{
+public:
+    template< typename ParentType >
+    inline explicit     BorderContext( ParentType& rParent, const BorderRef& rxBorder ) :
+                            WorkbookContextBase( rParent ), mxBorder( rxBorder ) {}
+
+protected:
+    virtual void        onStartElement( const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+
+private:
+    BorderRef           mxBorder;
+};
+
+// ============================================================================
+
+class FillContext : public WorkbookContextBase
+{
+public:
+    template< typename ParentType >
+    inline explicit     FillContext( ParentType& rParent, const FillRef& rxFill ) :
+                            WorkbookContextBase( rParent ), mxFill( rxFill ), mfGradPos( -1.0 ) {}
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+
+private:
+    FillRef             mxFill;
+    double              mfGradPos;      /// Gradient color position.
+};
+
+// ============================================================================
+
+class XfContext : public WorkbookContextBase
+{
+public:
+    template< typename ParentType >
+    inline explicit     XfContext( ParentType& rParent, const XfRef& rxXf, bool bCellXf ) :
+                            WorkbookContextBase( rParent ), mxXf( rxXf ), mbCellXf( bCellXf ) {}
+
+protected:
+    virtual void        onStartElement( const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+
+private:
+    XfRef               mxXf;
+    bool                mbCellXf;       /// True = cell XF, false = style XF.
+};
+
+// ============================================================================
+
+class DxfContext : public WorkbookContextBase
+{
+public:
+    template< typename ParentType >
+    inline explicit     DxfContext( ParentType& rParent, const DxfRef& rxDxf ) :
+                            WorkbookContextBase( rParent ), mxDxf( rxDxf ) {}
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+
+private:
+    DxfRef              mxDxf;
+};
+
+// ============================================================================
+
+class StylesFragment : public WorkbookFragmentBase
+{
+public:
+    explicit            StylesFragment(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+    virtual void        finalizeImport();
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/tablebuffer.hxx b/sc/source/filter/inc/tablebuffer.hxx
new file mode 100644
index 000000000000..08ce3e80f5ad
--- /dev/null
+++ b/sc/source/filter/inc/tablebuffer.hxx
@@ -0,0 +1,142 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_TABLEBUFFER_HXX
+#define OOX_XLS_TABLEBUFFER_HXX
+
+#include 
+#include "autofilterbuffer.hxx"
+#include "workbookhelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+struct TableModel
+{
+    ::com::sun::star::table::CellRangeAddress
+                        maRange;            /// Original (unchecked) range of the table.
+    ::rtl::OUString     maProgName;         /// Programmatical name.
+    ::rtl::OUString     maDisplayName;      /// Display name.
+    sal_Int32           mnId;               /// Unique table identifier.
+    sal_Int32           mnType;             /// Table type (worksheet, query, etc.).
+    sal_Int32           mnHeaderRows;       /// Number of header rows.
+    sal_Int32           mnTotalsRows;       /// Number of totals rows.
+
+    explicit            TableModel();
+};
+
+// ----------------------------------------------------------------------------
+
+class Table : public WorkbookHelper
+{
+public:
+    explicit            Table( const WorkbookHelper& rHelper );
+
+    /** Imports a table definition from the passed attributes. */
+    void                importTable( const AttributeList& rAttribs, sal_Int16 nSheet );
+    /** Imports a table definition from a TABLE record. */
+    void                importTable( SequenceInputStream& rStrm, sal_Int16 nSheet );
+    /** Creates a new auto filter and stores it internally. */
+    inline AutoFilter&  createAutoFilter() { return maAutoFilters.createAutoFilter(); }
+
+    /** Creates a database range from this tables. */
+    void                finalizeImport();
+
+    /** Returns the unique table identifier. */
+    inline sal_Int32    getTableId() const { return maModel.mnId; }
+    /** Returns the token index used in API token arrays (com.sun.star.sheet.FormulaToken). */
+    inline sal_Int32    getTokenIndex() const { return mnTokenIndex; }
+    /** Returns the original display name of the table. */
+    inline const ::rtl::OUString& getDisplayName() const { return maModel.maDisplayName; }
+
+    /** Returns the original (unchecked) total range of the table. */
+    inline const ::com::sun::star::table::CellRangeAddress& getOriginalRange() const { return maModel.maRange; }
+    /** Returns the cell range of this table. */
+    inline const ::com::sun::star::table::CellRangeAddress& getRange() const { return maDestRange; }
+    /** Returns the number of columns of this table. */
+    inline sal_Int32    getWidth() const { return maDestRange.EndColumn - maDestRange.StartColumn + 1; }
+    /** Returns the number of rows of this table. */
+    inline sal_Int32    getHeight() const { return maDestRange.EndRow - maDestRange.StartRow + 1; }
+    /** Returns the number of header rows in the table range. */
+    inline sal_Int32    getHeaderRows() const { return maModel.mnHeaderRows; }
+    /** Returns the number of totals rows in the table range. */
+    inline sal_Int32    getTotalsRows() const { return maModel.mnTotalsRows; }
+
+private:
+    TableModel          maModel;
+    AutoFilterBuffer    maAutoFilters;      /// Filter settings for this table.
+    ::rtl::OUString     maDBRangeName;      /// Name of the databae range in the Calc document.
+    ::com::sun::star::table::CellRangeAddress
+                        maDestRange;        /// Validated range of the table in the worksheet.
+    sal_Int32           mnTokenIndex;       /// Token index used in API token array.
+};
+
+typedef ::boost::shared_ptr< Table > TableRef;
+
+// ============================================================================
+
+class TableBuffer : public WorkbookHelper
+{
+public:
+    explicit            TableBuffer( const WorkbookHelper& rHelper );
+
+    /** Creates a new empty table. */
+    Table&              createTable();
+
+    /** Creates database ranges from all imported tables. */
+    void                finalizeImport();
+
+    /** Returns a table by its identifier. */
+    TableRef            getTable( sal_Int32 nTableId ) const;
+    /** Returns a table by its display name. */
+    TableRef            getTable( const ::rtl::OUString& rDispName ) const;
+
+private:
+    /** Inserts the passed table into the maps according to its identifier and name. */
+    void                insertTableToMaps( const TableRef& rxTable );
+
+private:
+    typedef RefVector< Table >                  TableVector;
+    typedef RefMap< sal_Int32, Table >          TableIdMap;
+    typedef RefMap< ::rtl::OUString, Table >    TableNameMap;
+
+    TableVector         maTables;
+    TableIdMap          maIdTables;
+    TableNameMap        maNameTables;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/tablefragment.hxx b/sc/source/filter/inc/tablefragment.hxx
new file mode 100644
index 000000000000..956b8a5b5f10
--- /dev/null
+++ b/sc/source/filter/inc/tablefragment.hxx
@@ -0,0 +1,65 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_TABLEFRAGMENT_HXX
+#define OOX_XLS_TABLEFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+class Table;
+
+// ============================================================================
+
+class TableFragment : public WorksheetFragmentBase
+{
+public:
+    explicit            TableFragment(
+                            const WorksheetHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+
+private:
+    Table&              mrTable;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/themebuffer.hxx b/sc/source/filter/inc/themebuffer.hxx
new file mode 100644
index 000000000000..be8f15508df8
--- /dev/null
+++ b/sc/source/filter/inc/themebuffer.hxx
@@ -0,0 +1,66 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_THEMEBUFFER_HXX
+#define OOX_XLS_THEMEBUFFER_HXX
+
+#include "oox/drawingml/theme.hxx"
+#include "workbookhelper.hxx"
+
+namespace oox {
+namespace xls {
+
+struct FontModel;
+
+// ============================================================================
+
+class ThemeBuffer : public ::oox::drawingml::Theme, public WorkbookHelper
+{
+public:
+    explicit            ThemeBuffer( const WorkbookHelper& rHelper );
+    virtual             ~ThemeBuffer();
+
+    /** Returns the theme color with the specified token identifier. */
+    sal_Int32           getColorByToken( sal_Int32 nToken ) const;
+
+    /** Returns the default font data for the current file type. */
+    inline const FontModel& getDefaultFontModel() const { return *mxDefFontModel; }
+
+private:
+    typedef ::std::auto_ptr< FontModel > FontModelPtr;
+    FontModelPtr        mxDefFontModel;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/unitconverter.hxx b/sc/source/filter/inc/unitconverter.hxx
new file mode 100644
index 000000000000..e3a0dc519ec5
--- /dev/null
+++ b/sc/source/filter/inc/unitconverter.hxx
@@ -0,0 +1,123 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_UNITCONVERTER_HXX
+#define OOX_XLS_UNITCONVERTER_HXX
+
+#include 
+#include 
+#include "workbookhelper.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace util { struct Date; struct DateTime; }
+} } }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Units supported by the UnitConverter class. */
+enum Unit
+{
+    UNIT_INCH,          /// Inches.
+    UNIT_POINT,         /// Points.
+    UNIT_TWIP,          /// Twips (1/20 point).
+    UNIT_EMU,           /// English Metric Unit (1/360,000 cm).
+    UNIT_SCREENX,       /// Horizontal screen pixels.
+    UNIT_SCREENY,       /// Vertical screen pixels.
+    UNIT_REFDEVX,       /// Horizontal pixels in Calc reference device.
+    UNIT_REFDEVY,       /// Vertical pixels in Calc reference device.
+    UNIT_DIGIT,         /// Digit width of document default font.
+    UNIT_SPACE,         /// Space character width of document default font.
+
+    UNIT_ENUM_SIZE
+};
+
+/** Helper class that provides functions to convert values from and to
+    different units.
+
+    Provides functions to calculate the width of certain characters of the
+    default font of the imported/exported document. The default font is always
+    the first font in the styles font list, and is always referenced by the
+    default cell style ("Normal" style in Excel) which is used by all empty
+    unformatted cells in the document. To be able to calculate the charcter
+    width correctly, the default font must be known, which is the case after
+    the finalizeImport() or finalizeExport() functions have been called. Caller
+    must make sure to not call the character width conversion functions before.
+ */
+class UnitConverter : public WorkbookHelper
+{
+public:
+    explicit            UnitConverter( const WorkbookHelper& rHelper );
+
+    /** Final processing after import of all style settings. */
+    void                finalizeImport();
+    /** Updates internal nulldate for date/serial conversion. */
+    void                finalizeNullDate( const ::com::sun::star::util::Date& rNullDate );
+
+    /** Converts the passed value between the passed units. */
+    double              scaleValue( double fValue, Unit eFromUnit, Unit eToUnit ) const;
+
+    /** Converts the passed value to 1/100 millimeters. */
+    sal_Int32           scaleToMm100( double fValue, Unit eUnit ) const;
+    /** Converts the passed value from 1/100 millimeters to the passed unit. */
+    double              scaleFromMm100( sal_Int32 nMm100, Unit eUnit ) const;
+
+    /** Returns the serial value of the passed datetime, based on current nulldate. */
+    double              calcSerialFromDateTime( const ::com::sun::star::util::DateTime& rDateTime ) const;
+    /** Returns the datetime of the passed serial value, based on current nulldate. */
+    ::com::sun::star::util::DateTime calcDateTimeFromSerial( double fSerial ) const;
+
+    /** Returns a BIFF error code from the passed error string. */
+    sal_uInt8           calcBiffErrorCode( const ::rtl::OUString& rErrorCode ) const;
+
+private:
+    /** Adds an error code to the internal maps. */
+    void                addErrorCode( sal_uInt8 nErrorCode, const ::rtl::OUString& rErrorCode );
+    /** Returns the conversion coefficient for the passed unit. */
+    double              getCoefficient( Unit eUnit ) const;
+
+private:
+    typedef ::std::vector< double >                     DoubleVector;
+    typedef ::std::map< ::rtl::OUString, sal_uInt8 >    OoxErrorCodeMap;
+    typedef ::std::map< sal_uInt8, ::rtl::OUString >    BiffErrorCodeMap;
+
+    DoubleVector        maCoeffs;           /// Coefficients for unit conversion.
+    OoxErrorCodeMap     maOoxErrCodes;      /// Maps error code strings to BIFF error constants.
+    sal_Int32           mnNullDate;         /// Nulldate of this workbook (number of days since 0000-01-01).
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/viewsettings.hxx b/sc/source/filter/inc/viewsettings.hxx
new file mode 100644
index 000000000000..10da445c358e
--- /dev/null
+++ b/sc/source/filter/inc/viewsettings.hxx
@@ -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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_VIEWSETTINGS_HXX
+#define OOX_XLS_VIEWSETTINGS_HXX
+
+#include 
+#include 
+#include "addressconverter.hxx"
+#include "stylesbuffer.hxx"
+#include "worksheethelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Contains all settings for a selection in a single pane of a sheet. */
+struct PaneSelectionModel
+{
+    ::com::sun::star::table::CellAddress maActiveCell;  /// Position of active cell (cursor).
+    ApiCellRangeList    maSelection;                    /// Selected cell ranges.
+    sal_Int32           mnActiveCellId;                 /// Index of active cell in selection list.
+
+    explicit            PaneSelectionModel();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Contains all view settings for a single sheet. */
+struct SheetViewModel
+{
+    typedef RefMap< sal_Int32, PaneSelectionModel > PaneSelectionModelMap;
+
+    PaneSelectionModelMap maPaneSelMap;                 /// Selections of all panes.
+    Color               maGridColor;                    /// Grid color.
+    ::com::sun::star::table::CellAddress maFirstPos;    /// First visible cell.
+    ::com::sun::star::table::CellAddress maSecondPos;   /// First visible cell in additional panes.
+    sal_Int32           mnWorkbookViewId;               /// Index into list of workbookView elements.
+    sal_Int32           mnViewType;                     /// View type (normal, page break, layout).
+    sal_Int32           mnActivePaneId;                 /// Active pane (with cell cursor).
+    sal_Int32           mnPaneState;                    /// Pane state (frozen, split).
+    double              mfSplitX;                       /// Split X position (twips), or number of frozen columns.
+    double              mfSplitY;                       /// Split Y position (twips), or number of frozen rows.
+    sal_Int32           mnCurrentZoom;                  /// Zoom factor for current view.
+    sal_Int32           mnNormalZoom;                   /// Zoom factor for normal view.
+    sal_Int32           mnSheetLayoutZoom;              /// Zoom factor for pagebreak preview.
+    sal_Int32           mnPageLayoutZoom;               /// Zoom factor for page layout view.
+    bool                mbSelected;                     /// True = sheet is selected.
+    bool                mbRightToLeft;                  /// True = sheet in right-to-left mode.
+    bool                mbDefGridColor;                 /// True = default grid color.
+    bool                mbShowFormulas;                 /// True = show formulas instead of results.
+    bool                mbShowGrid;                     /// True = show cell grid.
+    bool                mbShowHeadings;                 /// True = show column/row headings.
+    bool                mbShowZeros;                    /// True = show zero value zells.
+    bool                mbShowOutline;                  /// True = show outlines.
+    bool                mbZoomToFit;                    /// True = zoom chart sheet to fit window.
+
+    explicit            SheetViewModel();
+
+    /** Returns true, if page break preview is active. */
+    bool                isPageBreakPreview() const;
+    /** Returns the zoom in normal view (returns default, if current value is 0). */
+    sal_Int32           getNormalZoom() const;
+    /** Returns the zoom in pagebreak preview (returns default, if current value is 0). */
+    sal_Int32           getPageBreakZoom() const;
+    /** Returns the grid color as RGB value. */
+    sal_Int32           getGridColor( const ::oox::core::FilterBase& rFilter ) const;
+
+    /** Returns the selection data, if available, otherwise 0. */
+    const PaneSelectionModel* getPaneSelection( sal_Int32 nPaneId ) const;
+    /** Returns the selection data of the active pane. */
+    const PaneSelectionModel* getActiveSelection() const;
+    /** Returns read/write access to the selection data of the specified pane. */
+    PaneSelectionModel& createPaneSelection( sal_Int32 nPaneId );
+};
+
+typedef ::boost::shared_ptr< SheetViewModel > SheetViewModelRef;
+
+// ----------------------------------------------------------------------------
+
+class SheetViewSettings : public WorksheetHelper
+{
+public:
+    explicit            SheetViewSettings( const WorksheetHelper& rHelper );
+
+    /** Imports the sheetView element containing sheet view settings. */
+    void                importSheetView( const AttributeList& rAttribs );
+    /** Imports the pane element containing sheet pane settings. */
+    void                importPane( const AttributeList& rAttribs );
+    /** Imports the selection element containing selection settings for a pane. */
+    void                importSelection( const AttributeList& rAttribs );
+    /** Imports the sheetView element containing view settings of a chart sheet. */
+    void                importChartSheetView( const AttributeList& rAttribs );
+
+    /** Imports the SHEETVIEW record containing sheet view settings. */
+    void                importSheetView( SequenceInputStream& rStrm );
+    /** Imports the PANE record containing sheet pane settings. */
+    void                importPane( SequenceInputStream& rStrm );
+    /** Imports the SELECTION record containing selection settings for a pane. */
+    void                importSelection( SequenceInputStream& rStrm );
+    /** Imports the CHARTSHEETVIEW record containing view settings of a chart sheet. */
+    void                importChartSheetView( SequenceInputStream& rStrm );
+
+    /** Imports the WINDOW2 record containing sheet view settings. */
+    void                importWindow2( BiffInputStream& rStrm );
+    /** Imports the PANE record containing sheet pane settings. */
+    void                importPane( BiffInputStream& rStrm );
+    /** Imports the SCL record containing sheet zoom settings. */
+    void                importScl( BiffInputStream& rStrm );
+    /** Imports the SELECTION record containing selection settings for a pane. */
+    void                importSelection( BiffInputStream& rStrm );
+
+    /** Converts all imported sheet view settings. */
+    void                finalizeImport();
+
+    /** Returns true, if the sheet layout is set to right-to-left. */
+    bool                isSheetRightToLeft() const;
+
+private:
+    SheetViewModelRef   createSheetView();
+
+private:
+    typedef RefVector< SheetViewModel > SheetViewModelVec;
+    SheetViewModelVec   maSheetViews;
+};
+
+// ============================================================================
+
+/** Contains all view settings for the entire document. */
+struct WorkbookViewModel
+{
+    sal_Int32           mnWinX;             /// X position of the workbook window (twips).
+    sal_Int32           mnWinY;             /// Y position of the workbook window (twips).
+    sal_Int32           mnWinWidth;         /// Width of the workbook window (twips).
+    sal_Int32           mnWinHeight;        /// Height of the workbook window (twips).
+    sal_Int32           mnActiveSheet;      /// Displayed (active) sheet.
+    sal_Int32           mnFirstVisSheet;    /// First visible sheet in sheet tabbar.
+    sal_Int32           mnTabBarWidth;      /// Width of sheet tabbar (1/1000 of window width).
+    sal_Int32           mnVisibility;       /// Visibility state of workbook window.
+    bool                mbShowTabBar;       /// True = show sheet tabbar.
+    bool                mbShowHorScroll;    /// True = show horizontal sheet scrollbars.
+    bool                mbShowVerScroll;    /// True = show vertical sheet scrollbars.
+    bool                mbMinimized;        /// True = workbook window is minimized.
+
+    explicit            WorkbookViewModel();
+};
+
+typedef ::boost::shared_ptr< WorkbookViewModel > WorkbookViewModelRef;
+
+// ----------------------------------------------------------------------------
+
+class ViewSettings : public WorkbookHelper
+{
+public:
+    explicit            ViewSettings( const WorkbookHelper& rHelper );
+
+    /** Imports the workbookView element containing workbook view settings. */
+    void                importWorkbookView( const AttributeList& rAttribs );
+    /** Imports the oleSize element containing the visible size of the workbook. */
+    void                importOleSize( const AttributeList& rAttribs );
+    /** Imports the WORKBOOKVIEW record containing workbook view settings. */
+    void                importWorkbookView( SequenceInputStream& rStrm );
+    /** Imports the OLESIZE record containing the visible size of the workbook. */
+    void                importOleSize( SequenceInputStream& rStrm );
+    /** Imports the WINDOW1 record containing workbook view settings. */
+    void                importWindow1( BiffInputStream& rStrm );
+    /** Imports the OLESIZE record containing the visible size of the workbook. */
+    void                importOleSize( BiffInputStream& rStrm );
+
+    /** Stores converted view settings for a specific worksheet. */
+    void                setSheetViewSettings( sal_Int16 nSheet,
+                            const SheetViewModelRef& rxSheetView,
+                            const ::com::sun::star::uno::Any& rProperties );
+    /** Stores the used area for a specific worksheet. */
+    void                setSheetUsedArea(
+                            const ::com::sun::star::table::CellRangeAddress& rUsedArea );
+
+    /** Converts all imported document view settings. */
+    void                finalizeImport();
+
+    /** Returns the Calc index of the active sheet. */
+    sal_Int16           getActiveCalcSheet() const;
+
+private:
+    WorkbookViewModel&  createWorkbookView();
+
+private:
+    typedef RefVector< WorkbookViewModel >                                      WorkbookViewModelVec;
+    typedef RefMap< sal_Int16, SheetViewModel >                                 SheetViewModelMap;
+    typedef ::std::map< sal_Int16, ::com::sun::star::uno::Any >                 SheetPropertiesMap;
+    typedef ::std::map< sal_Int16, ::com::sun::star::table::CellRangeAddress >  SheetUsedAreaMap;
+
+    WorkbookViewModelVec maBookViews;       /// Workbook view models.
+    SheetViewModelMap   maSheetViews;       /// Active view model for each sheet.
+    SheetPropertiesMap  maSheetProps;       /// Converted property sequences for each sheet.
+    SheetUsedAreaMap    maSheetUsedAreas;   /// Used area (cell range) of every sheet.
+    ::com::sun::star::table::CellRangeAddress
+                        maOleSize;          /// Visible area if this is an embedded OLE object.
+    bool                mbValidOleSize;     /// True = imported OLE size is a valid cell range.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/workbookfragment.hxx b/sc/source/filter/inc/workbookfragment.hxx
new file mode 100644
index 000000000000..ab1aab6ee4a2
--- /dev/null
+++ b/sc/source/filter/inc/workbookfragment.hxx
@@ -0,0 +1,101 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_WORKBOOKFRAGMENT_HXX
+#define OOX_XLS_WORKBOOKFRAGMENT_HXX
+
+#include "defnamesbuffer.hxx"
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+class ExternalLink;
+
+// ============================================================================
+
+class WorkbookFragment : public WorkbookFragmentBase
+{
+public:
+    explicit            WorkbookFragment(
+                            const WorkbookHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onCharacters( const ::rtl::OUString& rChars );
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+    virtual void        finalizeImport();
+
+private:
+    void                importExternalReference( const AttributeList& rAttribs );
+    void                importDefinedName( const AttributeList& rAttribs );
+    void                importPivotCache( const AttributeList& rAttribs );
+
+    void                importExternalRef( SequenceInputStream& rStrm );
+    void                importPivotCache( SequenceInputStream& rStrm );
+
+    void                importExternalLinkFragment( ExternalLink& rExtLink );
+    void                importPivotCacheDefFragment( const ::rtl::OUString& rRelId, sal_Int32 nCacheId );
+
+private:
+    DefinedNameRef      mxCurrName;
+};
+
+// ============================================================================
+
+class BiffWorkbookFragment : public BiffWorkbookFragmentBase
+{
+public:
+    explicit            BiffWorkbookFragment( const WorkbookHelper& rHelper, const ::rtl::OUString& rStrmName );
+
+    /** Imports the entire workbook stream, including all contained worksheets. */
+    virtual bool        importFragment();
+
+private:
+    /** Imports a complete BIFF4 workspace fragment (with embedded sheets). */
+    bool                importWorkspaceFragment();
+    /** Imports the workbook globals fragment from current stream position. */
+    bool                importGlobalsFragment( ISegmentProgressBar& rProgressBar );
+    /** Imports a sheet fragment with passed type from current stream position. */
+    bool                importSheetFragment(
+                            ISegmentProgressBar& rProgressBar,
+                            BiffFragmentType eFragment, sal_Int16 nCalcSheet );
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/workbookhelper.hxx b/sc/source/filter/inc/workbookhelper.hxx
new file mode 100644
index 000000000000..368abf739c90
--- /dev/null
+++ b/sc/source/filter/inc/workbookhelper.hxx
@@ -0,0 +1,302 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_WORKBOOKHELPER_HXX
+#define OOX_XLS_WORKBOOKHELPER_HXX
+
+#include 
+#include 
+#include "oox/helper/storagebase.hxx"
+#include "biffhelper.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace container { class XNameAccess; }
+    namespace container { class XNameContainer; }
+    namespace lang { class XMultiServiceFactory; }
+    namespace sheet { class XDatabaseRange; }
+    namespace sheet { class XNamedRange; }
+    namespace sheet { class XSpreadsheet; }
+    namespace sheet { class XSpreadsheetDocument; }
+    namespace style { class XStyle; }
+    namespace table { struct CellAddress; }
+    namespace table { struct CellRangeAddress; }
+    namespace table { class XCell; }
+    namespace table { class XCellRange; }
+} } }
+
+namespace oox {
+    class AttributeList;
+    class SegmentProgressBar;
+    class SequenceInputStream;
+}
+
+namespace oox { namespace core {
+    class BinaryFilterBase;
+    class FilterBase;
+    class FragmentHandler;
+    class XmlFilterBase;
+} }
+
+namespace oox { namespace drawingml {
+    class Theme;
+} }
+
+namespace oox {
+namespace xls {
+
+class ExcelFilter;
+class ExcelBiffFilter;
+
+// ============================================================================
+
+/** An enumeration for all supported spreadsheet filter types. */
+enum FilterType
+{
+    FILTER_OOXML,       /// MS Excel OOXML (Office Open XML) or BIFF12.
+    FILTER_BIFF,        /// MS Excel BIFF2-BIFF8 (Binary Interchange File Format).
+    FILTER_UNKNOWN      /// Unknown filter type.
+};
+
+// ============================================================================
+
+/** Functor for case-insensitive string comparison, usable in maps etc. */
+struct IgnoreCaseCompare
+{
+    bool operator()( const ::rtl::OUString& rName1, const ::rtl::OUString& rName2 ) const;
+};
+
+// ============================================================================
+
+class AddressConverter;
+class BiffCodecHelper;
+class ConnectionsBuffer;
+class DefinedNamesBuffer;
+class ExcelChartConverter;
+class ExternalLinkBuffer;
+class FormulaParser;
+class PageSettingsConverter;
+class PivotCacheBuffer;
+class PivotTableBuffer;
+class ScenarioBuffer;
+class SharedStringsBuffer;
+class StylesBuffer;
+class TableBuffer;
+class ThemeBuffer;
+class UnitConverter;
+class ViewSettings;
+class WorkbookSettings;
+class WorksheetBuffer;
+
+class WorkbookGlobals;
+typedef ::boost::shared_ptr< WorkbookGlobals > WorkbookGlobalsRef;
+
+/** Helper class to provice access to global workbook data.
+
+    All classes derived from this helper class will have access to a singleton
+    object of type WorkbookGlobals containing global workbook settings,
+    buffers, converters, etc. Nearly all classes in this filter implementation
+    are derived directly or indirectly from this class.
+
+    This class contains just a simple reference to the WorkbookGlobals object
+    to prevent circular references, as the WorkbookGlobals object contains a
+    lot of objects derived from this class.
+ */
+class WorkbookHelper
+{
+public:
+    inline /*implicit*/ WorkbookHelper( WorkbookGlobals& rBookGlob ) : mrBookGlob( rBookGlob ) {}
+    virtual             ~WorkbookHelper();
+
+    static WorkbookGlobalsRef constructGlobals( ExcelFilter& rFilter );
+    static WorkbookGlobalsRef constructGlobals( ExcelBiffFilter& rFilter, BiffType eBiff );
+
+    // filter -----------------------------------------------------------------
+
+    /** Returns the base filter object (base class of all filters). */
+    ::oox::core::FilterBase& getBaseFilter() const;
+    /** Returns the file type of the current filter. */
+    FilterType          getFilterType() const;
+    /** Returns the filter progress bar. */
+    SegmentProgressBar& getProgressBar() const;
+    /** Returns true, if the file is a multi-sheet document, or false if single-sheet. */
+    bool                isWorkbookFile() const;
+    /** Returns the index of the current Calc sheet, if filter currently processes a sheet. */
+    sal_Int16           getCurrentSheetIndex() const;
+
+    /** Sets the VBA project storage used to import VBA source code and forms. */
+    void                setVbaProjectStorage( const StorageRef& rxVbaPrjStrg );
+    /** Sets the index of the current Calc sheet, if filter currently processes a sheet. */
+    void                setCurrentSheetIndex( sal_Int16 nSheet );
+    /** Final conversion after importing the workbook. */
+    void                finalizeWorkbookImport();
+
+    // document model ---------------------------------------------------------
+
+    /** Returns a reference to the source/target spreadsheet document model. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheetDocument >
+                        getDocument() const;
+
+    /** Returns a reference to the specified spreadsheet in the document model. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheet >
+                        getSheetFromDoc( sal_Int16 nSheet ) const;
+    /** Returns a reference to the specified spreadsheet in the document model. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheet >
+                        getSheetFromDoc( const ::rtl::OUString& rSheet ) const;
+
+    /** Returns the XCellRange interface for the passed cell range address. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange >
+                        getCellRangeFromDoc(
+                            const ::com::sun::star::table::CellRangeAddress& rRange ) const;
+
+    /** Returns the cell or page styles container from the Calc document. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
+                        getStyleFamily( bool bPageStyles ) const;
+    /** Returns the specified cell or page style from the Calc document. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::style::XStyle >
+                        getStyleObject( const ::rtl::OUString& rStyleName, bool bPageStyle ) const;
+
+    /** Creates and returns a defined name on-the-fly in the Calc document.
+        The name will not be buffered in the global defined names buffer.
+        @param orName  (in/out-parameter) Returns the resulting used name. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XNamedRange >
+                        createNamedRangeObject(
+                            ::rtl::OUString& orName,
+                            sal_Int32 nNameFlags = 0 ) const;
+
+    /** Creates and returns a defined name on-the-fly in the sheet.
+        The name will not be buffered in the global defined names buffer.
+        @param orName  (in/out-parameter) Returns the resulting used name. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XNamedRange >
+                        createLocalNamedRangeObject(
+                            ::rtl::OUString& orName,
+                            sal_Int32 nNameFlags = 0, sal_Int32 nTab = -1 ) const;
+
+    /** Creates and returns a database range on-the-fly in the Calc document.
+        The range will not be buffered in the global table buffer.
+        @param orName  (in/out-parameter) Returns the resulting used name. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDatabaseRange >
+                        createDatabaseRangeObject(
+                            ::rtl::OUString& orName,
+                            const ::com::sun::star::table::CellRangeAddress& rRangeAddr ) const;
+
+    /** Creates and returns an unnamed database range on-the-fly in the Calc document.
+        The range will not be buffered in the global table buffer. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XDatabaseRange >
+                        createUnnamedDatabaseRangeObject(
+                            const ::com::sun::star::table::CellRangeAddress& rRangeAddr ) const;
+
+    /** Creates and returns a com.sun.star.style.Style object for cells or pages. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::style::XStyle >
+                        createStyleObject(
+                            ::rtl::OUString& orStyleName,
+                            bool bPageStyle ) const;
+
+    // buffers ----------------------------------------------------------------
+
+    /** Returns the global workbook settings object. */
+    WorkbookSettings&   getWorkbookSettings() const;
+    /** Returns the workbook and sheet view settings object. */
+    ViewSettings&       getViewSettings() const;
+    /** Returns the worksheet buffer containing sheet names and properties. */
+    WorksheetBuffer&    getWorksheets() const;
+    /** Returns the office theme object read from the theme substorage. */
+    ThemeBuffer&        getTheme() const;
+    /** Returns all cell formatting objects read from the styles substream. */
+    StylesBuffer&       getStyles() const;
+    /** Returns the shared strings read from the shared strings substream. */
+    SharedStringsBuffer& getSharedStrings() const;
+    /** Returns the external links read from the external links substream. */
+    ExternalLinkBuffer& getExternalLinks() const;
+    /** Returns the defined names read from the workbook globals. */
+    DefinedNamesBuffer& getDefinedNames() const;
+    /** Returns the tables collection (equivalent to Calc's database ranges). */
+    TableBuffer&        getTables() const;
+    /** Returns the scenarios collection. */
+    ScenarioBuffer&     getScenarios() const;
+    /** Returns the collection of external data connections. */
+    ConnectionsBuffer&  getConnections() const;
+    /** Returns the collection of pivot caches. */
+    PivotCacheBuffer&   getPivotCaches() const;
+    /** Returns the collection of pivot tables. */
+    PivotTableBuffer&   getPivotTables() const;
+
+    // converters -------------------------------------------------------------
+
+    /** Returns the import formula parser (import filter only!). */
+    FormulaParser&      getFormulaParser() const;
+    /** Returns the measurement unit converter. */
+    UnitConverter&      getUnitConverter() const;
+    /** Returns the converter for string to cell address/range conversion. */
+    AddressConverter&   getAddressConverter() const;
+    /** Returns the chart object converter. */
+    ExcelChartConverter* getChartConverter() const;
+    /** Returns the page and print settings converter. */
+    PageSettingsConverter& getPageSettingsConverter() const;
+
+    // OOXML/BIFF12 specific (MUST NOT be called in BIFF filter) --------------
+
+    /** Returns the base OOXML/BIFF12 filter object.
+        Must not be called, if current filter is not the OOXML/BIFF12 filter. */
+    ::oox::core::XmlFilterBase& getOoxFilter() const;
+
+    /** Imports a fragment using the passed fragment handler, which contains
+        the full path to the fragment stream. */
+    bool                importOoxFragment( const ::rtl::Reference< ::oox::core::FragmentHandler >& rxHandler );
+
+    // BIFF2-BIFF8 specific (MUST NOT be called in OOXML/BIFF12 filter) -------
+
+    /** Returns the BIFF type in binary filter. */
+    BiffType            getBiff() const;
+
+    /** Returns the text encoding used to import/export byte strings. */
+    rtl_TextEncoding    getTextEncoding() const;
+    /** 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. */
+    BiffCodecHelper&    getCodecHelper() const;
+
+private:
+    WorkbookGlobals&    mrBookGlob;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/workbooksettings.hxx b/sc/source/filter/inc/workbooksettings.hxx
new file mode 100644
index 000000000000..a52ee61b7da8
--- /dev/null
+++ b/sc/source/filter/inc/workbooksettings.hxx
@@ -0,0 +1,168 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_WORKBOOKSETTINGS_HXX
+#define OOX_XLS_WORKBOOKSETTINGS_HXX
+
+#include "workbookhelper.hxx"
+
+namespace com { namespace sun { namespace star { namespace util { struct Date; } } } }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Settings for workbook write protection. */
+struct FileSharingModel
+{
+    ::rtl::OUString     maUserName;             /// User who added the write protection password.
+    sal_uInt16          mnPasswordHash;         /// Hash value of the write protection password.
+    bool                mbRecommendReadOnly;    /// True = recommend read-only mode on opening.
+
+    explicit            FileSharingModel();
+};
+
+// ============================================================================
+
+/** Global workbook settings. */
+struct WorkbookSettingsModel
+{
+    ::rtl::OUString     maCodeName;             /// VBA codename for the workbook.
+    sal_Int32           mnShowObjectMode;       /// Specifies how objects are shown.
+    sal_Int32           mnUpdateLinksMode;      /// Specifies how external links are updated.
+    sal_Int32           mnDefaultThemeVer;      /// Default theme version.
+    bool                mbDateMode1904;         /// True = null date is 1904-01-01.
+    bool                mbDateCompatibility;    /// False = null date is 1899-12-30.
+    bool                mbSaveExtLinkValues;    /// True = save cached cell values for external links.
+
+    explicit            WorkbookSettingsModel();
+
+    /** Sets BIFF object visibility mode. */
+    void                setBiffObjectMode( sal_uInt16 nObjMode );
+};
+
+// ============================================================================
+
+/** Workbook calculation settings. */
+struct CalcSettingsModel
+{
+    double              mfIterateDelta;         /// Minimum change in circular references.
+    sal_Int32           mnCalcId;               /// Calculation engine identifier.
+    sal_Int32           mnRefMode;              /// Cell reference mode: A1 or R1C1.
+    sal_Int32           mnCalcMode;             /// Automatic or manual recalculation.
+    sal_Int32           mnIterateCount;         /// Number of iterations in circular references.
+    sal_Int32           mnProcCount;            /// Number of processors for concurrent calculation.
+    bool                mbCalcOnSave;           /// True = always recalculate formulas before save.
+    bool                mbCalcCompleted;        /// True = formulas have been recalculated before save.
+    bool                mbFullPrecision;        /// True = use full precision on calculation.
+    bool                mbIterate;              /// True = allow circular references.
+    bool                mbConcurrent;           /// True = concurrent calculation enabled.
+    bool                mbUseNlr;               /// True = use natural language references in formulas.
+
+    explicit            CalcSettingsModel();
+};
+
+// ============================================================================
+
+class WorkbookSettings : public WorkbookHelper
+{
+public:
+    explicit            WorkbookSettings( const WorkbookHelper& rHelper );
+
+    /** Imports the fileSharing element containing write protection settings. */
+    void                importFileSharing( const AttributeList& rAttribs );
+    /** Imports the workbookPr element containing global workbook settings. */
+    void                importWorkbookPr( const AttributeList& rAttribs );
+    /** Imports the calcPr element containing workbook calculation settings. */
+    void                importCalcPr( const AttributeList& rAttribs );
+
+    /** Imports the FILESHARING record containing write protection settings. */
+    void                importFileSharing( SequenceInputStream& rStrm );
+    /** Imports the WORKBOOKPR record containing global workbook settings. */
+    void                importWorkbookPr( SequenceInputStream& rStrm );
+    /** Imports the CALCPR record containing workbook calculation settings. */
+    void                importCalcPr( SequenceInputStream& rStrm );
+
+    /** Sets the save external linked values flag, e.g. from the WSBOOL record. */
+    void                setSaveExtLinkValues( bool bSaveExtLinks );
+    /** Imports the BOOKBOOL record. */
+    void                importBookBool( BiffInputStream& rStrm );
+    /** Imports the CALCCOUNT record. */
+    void                importCalcCount( BiffInputStream& rStrm );
+    /** Imports the CALCMODE record. */
+    void                importCalcMode( BiffInputStream& rStrm );
+    /** Imports the CODENAME record. */
+    void                importCodeName( BiffInputStream& rStrm );
+    /** Imports the DATEMODE record. */
+    void                importDateMode( BiffInputStream& rStrm );
+    /** Imports the DELTA record. */
+    void                importDelta( BiffInputStream& rStrm );
+    /** Imports the FILESHARING record. */
+    void                importFileSharing( BiffInputStream& rStrm );
+    /** Imports the HIDEOBJ record. */
+    void                importHideObj( BiffInputStream& rStrm );
+    /** Imports the ITERATION record. */
+    void                importIteration( BiffInputStream& rStrm );
+    /** Imports the PRECISION record. */
+    void                importPrecision( BiffInputStream& rStrm );
+    /** Imports the REFMODE record. */
+    void                importRefMode( BiffInputStream& rStrm );
+    /** Imports the SAVERECALC record. */
+    void                importSaveRecalc( BiffInputStream& rStrm );
+    /** Imports the UNCALCED record. */
+    void                importUncalced( BiffInputStream& rStrm );
+    /** Imports the USESELFS record. */
+    void                importUsesElfs( BiffInputStream& rStrm );
+
+    /** Converts the imported workbook settings. */
+    void                finalizeImport();
+
+    /** Returns the show objects mode (considered a view setting in Calc). */
+    sal_Int16           getApiShowObjectMode() const;
+    /** Returns the nulldate of this workbook. */
+    ::com::sun::star::util::Date getNullDate() const;
+
+private:
+    /** Updates date mode and unit converter nulldate. */
+    void                setDateMode( bool bDateMode1904, bool bDateCompatibility=true );
+
+private:
+    FileSharingModel    maFileSharing;
+    WorkbookSettingsModel maBookSettings;
+    CalcSettingsModel   maCalcSettings;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/worksheetbuffer.hxx b/sc/source/filter/inc/worksheetbuffer.hxx
new file mode 100644
index 000000000000..f653c4410d2e
--- /dev/null
+++ b/sc/source/filter/inc/worksheetbuffer.hxx
@@ -0,0 +1,136 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_WORKSHEETBUFFER_HXX
+#define OOX_XLS_WORKSHEETBUFFER_HXX
+
+#include 
+#include "oox/helper/refmap.hxx"
+#include "oox/helper/refvector.hxx"
+#include "workbookhelper.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace i18n { class XCharacterClassification; }
+} } }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Contains data from the 'sheet' element describing a sheet in the workbook. */
+struct SheetInfoModel
+{
+    ::rtl::OUString     maRelId;        /// Relation identifier for the sheet substream.
+    ::rtl::OUString     maName;         /// Original name of the sheet.
+    sal_Int64           mnBiffHandle;   /// BIFF record handle of the sheet substream.
+    sal_Int32           mnSheetId;      /// Sheet identifier.
+    sal_Int32           mnState;        /// Visibility state.
+
+    explicit            SheetInfoModel();
+};
+
+// ============================================================================
+
+/** Stores information about all sheets in a spreadsheet document.
+
+    Information about sheets includes the sheet name, the visibility state, and
+    for the OOXML filter, the relation identifier of the sheet used to obtain
+    the related worksheet fragment.
+ */
+class WorksheetBuffer : public WorkbookHelper
+{
+public:
+    explicit            WorksheetBuffer( const WorkbookHelper& rHelper );
+
+    /** Returns the base file name without path and file extension. */
+    static ::rtl::OUString getBaseFileName( const ::rtl::OUString& rUrl );
+
+    /** Initializes the buffer for single sheet files (BIFF2-BIFF4). */
+    void                initializeSingleSheet();
+
+    /** Imports the attributes of a sheet element. */
+    void                importSheet( const AttributeList& rAttribs );
+    /** Imports the SHEET record from the passed BIFF12 stream. */
+    void                importSheet( SequenceInputStream& rStrm );
+    /** Imports the SHEET record from the passed BIFF stream. */
+    void                importSheet( BiffInputStream& rStrm );
+    /** Inserts a new empty sheet into the document. Looks for an unused name.
+         @return  Index of the new sheet in the Calc document. */
+    sal_Int16           insertEmptySheet( const ::rtl::OUString& rPreferredName, bool bVisible );
+
+    /** Returns the number of original sheets contained in the workbook. */
+    sal_Int32           getWorksheetCount() const;
+    /** Returns the OOXML relation identifier of the specified worksheet. */
+    ::rtl::OUString     getWorksheetRelId( sal_Int32 nWorksheet ) const;
+    /** Returns the BIFF record handle of the associated sheet substream. */
+    sal_Int64           getBiffRecordHandle( sal_Int32 nWorksheet ) const;
+
+    /** Returns the Calc index of the specified worksheet. */
+    sal_Int16           getCalcSheetIndex( sal_Int32 nWorksheet ) const;
+    /** Returns the finalized name of the specified worksheet. */
+    ::rtl::OUString     getCalcSheetName( sal_Int32 nWorksheet ) const;
+
+    /** Returns the Calc index of the sheet with the passed original worksheet name. */
+    sal_Int16           getCalcSheetIndex( const ::rtl::OUString& rWorksheetName ) const;
+    /** Returns the finalized name of the sheet with the passed worksheet name. */
+    ::rtl::OUString     getCalcSheetName( const ::rtl::OUString& rWorksheetName ) const;
+
+private:
+    struct SheetInfo : public SheetInfoModel
+    {
+        ::rtl::OUString     maCalcName;
+        ::rtl::OUString     maCalcQuotedName;
+        sal_Int16           mnCalcSheet;
+
+        explicit            SheetInfo( const SheetInfoModel& rModel, sal_Int16 nCalcSheet, const ::rtl::OUString& rCalcName );
+    };
+
+    typedef ::std::pair< sal_Int16, ::rtl::OUString > IndexNamePair;
+
+    /** Creates a new sheet in the Calc document. Does not insert anything in the own lists. */
+    IndexNamePair       createSheet( const ::rtl::OUString& rPreferredName, sal_Int32 nSheetPos, bool bVisible );
+    /** Creates a new sheet in the Calc document and inserts the related SheetInfo. */
+    void                insertSheet( const SheetInfoModel& rModel );
+
+private:
+    typedef RefVector< SheetInfo > SheetInfoVector;
+    SheetInfoVector     maSheetInfos;
+
+    typedef RefMap< ::rtl::OUString, SheetInfo, IgnoreCaseCompare > SheetInfoMap;
+    SheetInfoMap        maSheetInfosByName;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/worksheetfragment.hxx b/sc/source/filter/inc/worksheetfragment.hxx
new file mode 100644
index 000000000000..093b482f7da3
--- /dev/null
+++ b/sc/source/filter/inc/worksheetfragment.hxx
@@ -0,0 +1,193 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_WORKSHEETFRAGMENT_HXX
+#define OOX_XLS_WORKSHEETFRAGMENT_HXX
+
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+class DataValidationsContext : public WorksheetContextBase
+{
+public:
+    explicit            DataValidationsContext( WorksheetFragmentBase& rFragment );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onCharacters( const ::rtl::OUString& rChars );
+    virtual void        onEndElement();
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+private:
+    /** Imports the dataValidation element containing data validation settings. */
+    void                importDataValidation( const AttributeList& rAttribs );
+    /** Imports the DATAVALIDATION record containing data validation settings. */
+    void                importDataValidation( SequenceInputStream& rStrm );
+
+private:
+    ::std::auto_ptr< ValidationModel > mxValModel;
+};
+
+// ============================================================================
+
+class WorksheetFragment : public WorksheetFragmentBase
+{
+public:
+    explicit            WorksheetFragment(
+                            const WorksheetHelper& rHelper,
+                            const ::rtl::OUString& rFragmentPath );
+
+protected:
+    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    virtual void        onCharacters( const ::rtl::OUString& rChars );
+
+    virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
+
+    virtual const ::oox::core::RecordInfo* getRecordInfos() const;
+    virtual void        initializeImport();
+    virtual void        finalizeImport();
+
+private:
+    /** Imports page settings from a pageSetUpPr element. */
+    void                importPageSetUpPr( const AttributeList& rAttribs );
+    /** Imports the dimension element containing the used area of the sheet. */
+    void                importDimension( const AttributeList& rAttribs );
+    /** Imports sheet format properties from a sheetFormatPr element. */
+    void                importSheetFormatPr( const AttributeList& rAttribs );
+    /** Imports column settings from a col element. */
+    void                importCol( const AttributeList& rAttribs );
+    /** Imports a merged cell range from a mergeCell element. */
+    void                importMergeCell( const AttributeList& rAttribs );
+    /** Imports the hyperlink element containing a hyperlink for a cell range. */
+    void                importHyperlink( const AttributeList& rAttribs );
+    /** Imports individual break that is either within row or column break context. */
+    void                importBrk( const AttributeList& rAttribs, bool bRowBreak );
+    /** Imports the the relation identifier for the DrawingML part. */
+    void                importDrawing( const AttributeList& rAttribs );
+    /** Imports the the relation identifier for the legacy VML drawing part. */
+    void                importLegacyDrawing( const AttributeList& rAttribs );
+    /** Imports additional data for an OLE object. */
+    void                importOleObject( const AttributeList& rAttribs );
+    /** Imports additional data for an OCX form control. */
+    void                importControl( const AttributeList& rAttribs );
+
+    /** Imports the DIMENSION record containing the used area of the sheet. */
+    void                importDimension( SequenceInputStream& rStrm );
+    /** Imports sheet format properties from a SHEETFORMATPR record. */
+    void                importSheetFormatPr( SequenceInputStream& rStrm );
+    /** Imports column settings from a COL record. */
+    void                importCol( SequenceInputStream& rStrm );
+    /** Imports a merged cell range from a MERGECELL record. */
+    void                importMergeCell( SequenceInputStream& rStrm );
+    /** Imports a hyperlink for a cell range from a HYPERLINK record. */
+    void                importHyperlink( SequenceInputStream& rStrm );
+    /** Imports the BRK record for an individual row or column page break. */
+    void                importBrk( SequenceInputStream& rStrm, bool bRowBreak );
+    /** Imports the DRAWING record containing the relation identifier for the DrawingML part. */
+    void                importDrawing( SequenceInputStream& rStrm );
+    /** Imports the LEGACYDRAWING record containing the relation identifier for the VML drawing part. */
+    void                importLegacyDrawing( SequenceInputStream& rStrm );
+    /** Imports additional data for an OLE object. */
+    void                importOleObject( SequenceInputStream& rStrm );
+    /** Imports additional data for an OCX form control. */
+    void                importControl( SequenceInputStream& rStrm );
+
+    /** Imports the binary data of an embedded OLE object from the fragment with the passed ID. */
+    void                importEmbeddedOleData( StreamDataSequence& orEmbeddedData, const ::rtl::OUString& rRelId );
+};
+
+// ============================================================================
+
+class BiffWorksheetFragment : public BiffWorksheetFragmentBase
+{
+public:
+    explicit            BiffWorksheetFragment(
+                            const WorksheetHelper& rHelper,
+                            const BiffWorkbookFragmentBase& rParent );
+    virtual             ~BiffWorksheetFragment();
+
+    /** Imports the entire worksheet fragment, returns true, if EOF record has been reached. */
+    virtual bool        importFragment();
+
+private:
+    /** Imports the AUTOFILTER and following records with auto filter settings. */
+    void                importAutoFilter( BiffInputStream& rStrm );
+    /** Imports the COLINFO record and sets column properties and formatting. */
+    void                importColInfo( BiffInputStream& rStrm );
+    /** Imports the BIFF2 COLUMNDEFAULT record and sets column default formatting. */
+    void                importColumnDefault( BiffInputStream& rStrm );
+    /** Imports the BIFF2 COLWIDTH record and sets column width. */
+    void                importColWidth( BiffInputStream& rStrm );
+    /** Imports the DATAVALIDATION record containing cell ranges with data validation settings. */
+    void                importDataValidation( BiffInputStream& rStrm );
+    /** Imports the DATAVALIDATIONS record containing global data validation settings. */
+    void                importDataValidations( BiffInputStream& rStrm );
+    /** Imports the DEFCOLWIDTH record and sets default column width. */
+    void                importDefColWidth( BiffInputStream& rStrm );
+    /** Imports the DEFROWHEIGHT record and sets default row height and properties. */
+    void                importDefRowHeight( BiffInputStream& rStrm );
+    /** Imports the DIMENSION record containing the used area of the sheet. */
+    void                importDimension( BiffInputStream& rStrm );
+    /** Imports the HYPERLINK record and sets a cell hyperlink. */
+    void                importHyperlink( BiffInputStream& rStrm );
+    /** Imports the LABELRANGES record and sets the imported label ranges. */
+    void                importLabelRanges( BiffInputStream& rStrm );
+    /** Imports the MEREDCELLS record and merges all cells in the document. */
+    void                importMergedCells( BiffInputStream& rStrm );
+    /** Imports the NOTE record containing a cell note. */
+    void                importNote( BiffInputStream& rStrm );
+    /** Imports the HORPAGEBREAKS or VERPAGEBREAKS record and inserts page breaks. */
+    void                importPageBreaks( BiffInputStream& rStrm, bool bRowBreak );
+    /** Imports a pivot table. */
+    void                importPTDefinition( BiffInputStream& rStrm );
+    /** Imports the QUERYTABLE and following records and inserts a web query. */
+    void                importQueryTable( BiffInputStream& rStrm );
+    /** Imports the SCENARIOS record and the following scenarios. */
+    void                importScenarios( BiffInputStream& rStrm );
+    /** Imports the SHAREDFEATHEAD record. */
+    void                importSharedFeatHead( BiffInputStream& rStrm );
+    /** Imports the STANDARDWIDTH record and sets standard column width. */
+    void                importStandardWidth( BiffInputStream& rStrm );
+
+private:
+    ::boost::shared_ptr< BiffWorksheetContextBase > mxContext;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/worksheethelper.hxx b/sc/source/filter/inc/worksheethelper.hxx
new file mode 100644
index 000000000000..facb12e21520
--- /dev/null
+++ b/sc/source/filter/inc/worksheethelper.hxx
@@ -0,0 +1,339 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_WORKSHEETHELPER_HXX
+#define OOX_XLS_WORKSHEETHELPER_HXX
+
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/progressbar.hxx"
+#include "oox/ole/olehelper.hxx"
+#include "addressconverter.hxx"
+#include "formulabase.hxx"
+
+namespace com { namespace sun { namespace star {
+    namespace awt { struct Point; }
+    namespace awt { struct Rectangle; }
+    namespace awt { struct Size; }
+    namespace drawing { class XDrawPage; }
+    namespace sheet { class XSheetCellRanges; }
+    namespace sheet { class XSpreadsheet; }
+    namespace table { class XCell; }
+    namespace table { class XCell2; }
+    namespace table { class XCellRange; }
+    namespace table { class XTableColumns; }
+    namespace table { class XTableRows; }
+} } }
+
+namespace oox {
+namespace xls {
+
+class AutoFilterBuffer;
+struct BinAddress;
+struct BinRange;
+class BiffSheetDrawing;
+class BinRangeList;
+class CommentsBuffer;
+class CondFormatBuffer;
+class Font;
+class PageSettings;
+class QueryTableBuffer;
+class RichString;
+class SheetDataBuffer;
+class SheetViewSettings;
+class VmlDrawing;
+class WorksheetSettings;
+
+// ============================================================================
+// ============================================================================
+
+/** An enumeration for all types of sheets in a workbook. */
+enum WorksheetType
+{
+    SHEETTYPE_WORKSHEET,            /// Worksheet.
+    SHEETTYPE_CHARTSHEET,           /// Chart sheet.
+    SHEETTYPE_MACROSHEET,           /// Macro sheet.
+    SHEETTYPE_DIALOGSHEET,          /// Dialog sheet (BIFF5+).
+    SHEETTYPE_MODULESHEET,          /// VB module sheet (BIFF5 only).
+    SHEETTYPE_EMPTYSHEET            /// Other (unsupported) sheet type.
+};
+
+// ============================================================================
+
+/** Stores settings and formatting data about a range of sheet columns. */
+struct ColumnModel
+{
+    ValueRange          maRange;            /// 1-based (!) range of the described columns.
+    double              mfWidth;            /// Column width in number of characters.
+    sal_Int32           mnXfId;             /// Column default formatting.
+    sal_Int32           mnLevel;            /// Column outline level.
+    bool                mbShowPhonetic;     /// True = cells in column show phonetic settings.
+    bool                mbHidden;           /// True = column is hidden.
+    bool                mbCollapsed;        /// True = column outline is collapsed.
+
+    explicit            ColumnModel();
+
+    /** Returns true, if this entry can be merged with the passed column range (column settings are equal). */
+    bool                isMergeable( const ColumnModel& rModel ) const;
+};
+
+// ----------------------------------------------------------------------------
+
+/** Stores settings and formatting data about a sheet row. */
+struct RowModel
+{
+    sal_Int32           mnRow;              /// 1-based (!) index of the described row.
+    ValueRangeSet       maColSpans;         /// 0-based (!) column ranges of used cells.
+    double              mfHeight;           /// Row height in points.
+    sal_Int32           mnXfId;             /// Row default formatting (see mbIsFormatted).
+    sal_Int32           mnLevel;            /// Row outline level.
+    bool                mbCustomHeight;     /// True = row has custom height.
+    bool                mbCustomFormat;     /// True = cells in row have explicit formatting.
+    bool                mbShowPhonetic;     /// True = cells in row show phonetic settings.
+    bool                mbHidden;           /// True = row is hidden.
+    bool                mbCollapsed;        /// True = row outline is collapsed.
+    bool                mbThickTop;         /// True = row has extra space above text.
+    bool                mbThickBottom;      /// True = row has extra space below text.
+
+    explicit            RowModel();
+
+    /** Inserts the passed column span into the row model. */
+    void                insertColSpan( const ValueRange& rColSpan );
+    /** Returns true, if this entry can be merged with the passed row range (row settings are equal). */
+    bool                isMergeable( const RowModel& rModel ) const;
+};
+
+// ----------------------------------------------------------------------------
+
+/** Stores formatting data about a page break. */
+struct PageBreakModel
+{
+    sal_Int32           mnColRow;           /// 0-based (!) index of column/row.
+    sal_Int32           mnMin;              /// Start of limited break.
+    sal_Int32           mnMax;              /// End of limited break.
+    bool                mbManual;           /// True = manual page break.
+
+    explicit            PageBreakModel();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Stores data about a hyperlink range. */
+struct HyperlinkModel : public ::oox::ole::StdHlinkInfo
+{
+    ::com::sun::star::table::CellRangeAddress
+                        maRange;            /// The cell area containing the hyperlink.
+    ::rtl::OUString     maTooltip;          /// Additional tooltip text.
+
+    explicit            HyperlinkModel();
+};
+
+// ----------------------------------------------------------------------------
+
+/** Stores data about ranges with data validation settings. */
+struct ValidationModel
+{
+    ApiCellRangeList    maRanges;
+    ApiTokenSequence    maTokens1;
+    ApiTokenSequence    maTokens2;
+    ::rtl::OUString     maInputTitle;
+    ::rtl::OUString     maInputMessage;
+    ::rtl::OUString     maErrorTitle;
+    ::rtl::OUString     maErrorMessage;
+    sal_Int32           mnType;
+    sal_Int32           mnOperator;
+    sal_Int32           mnErrorStyle;
+    bool                mbShowInputMsg;
+    bool                mbShowErrorMsg;
+    bool                mbNoDropDown;
+    bool                mbAllowBlank;
+
+    explicit            ValidationModel();
+
+    /** Sets the passed BIFF validation type. */
+    void                setBiffType( sal_uInt8 nType );
+    /** Sets the passed BIFF operator. */
+    void                setBiffOperator( sal_uInt8 nOperator );
+    /** Sets the passed BIFF error style. */
+    void                setBiffErrorStyle( sal_uInt8 nErrorStyle );
+};
+
+// ============================================================================
+// ============================================================================
+
+class WorksheetGlobals;
+typedef ::boost::shared_ptr< WorksheetGlobals > WorksheetGlobalsRef;
+
+class WorksheetHelper : public WorkbookHelper
+{
+public:
+    /*implicit*/        WorksheetHelper( WorksheetGlobals& rSheetGlob );
+
+    static WorksheetGlobalsRef constructGlobals(
+                            const WorkbookHelper& rHelper,
+                            const ISegmentProgressBarRef& rxProgressBar,
+                            WorksheetType eSheetType,
+                            sal_Int16 nSheet );
+
+    // ------------------------------------------------------------------------
+
+    /** Returns the type of this sheet. */
+    WorksheetType       getSheetType() const;
+    /** Returns the index of the current sheet. */
+    sal_Int16           getSheetIndex() const;
+    /** Returns the XSpreadsheet interface of the current sheet. */
+    const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheet >&
+                        getSheet() const;
+
+    /** Returns the XCell interface for the passed cell address. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >
+                        getCell( const ::com::sun::star::table::CellAddress& rAddress ) const;
+    /** Returns the XCellRange interface for the passed cell range address. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange >
+                        getCellRange( const ::com::sun::star::table::CellRangeAddress& rRange ) const;
+    /** Returns the XSheetCellRanges interface for the passed cell range addresses. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSheetCellRanges >
+                        getCellRangeList( const ApiCellRangeList& rRanges ) const;
+
+    /** Returns the XDrawPage interface of the draw page of the current sheet. */
+    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >
+                        getDrawPage() const;
+
+    /** Returns the absolute cell position in 1/100 mm. */
+    ::com::sun::star::awt::Point getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const;
+    /** Returns the cell size in 1/100 mm. */
+    ::com::sun::star::awt::Size getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const;
+    /** Returns the size of the entire drawing page in 1/100 mm. */
+    ::com::sun::star::awt::Size getDrawPageSize() const;
+
+    /** Returns the buffer for cell contents and cell formatting. */
+    SheetDataBuffer&    getSheetData() const;
+    /** Returns the conditional formatting in this sheet. */
+    CondFormatBuffer&   getCondFormats() const;
+    /** Returns the buffer for all cell comments in this sheet. */
+    CommentsBuffer&     getComments() const;
+    /** Returns the auto filters for the sheet. */
+    AutoFilterBuffer&   getAutoFilters() const;
+    /** Returns the buffer for all web query tables in this sheet. */
+    QueryTableBuffer&   getQueryTables() const;
+    /** Returns the worksheet settings object. */
+    WorksheetSettings&  getWorksheetSettings() const;
+    /** Returns the page/print settings for this sheet. */
+    PageSettings&       getPageSettings() const;
+    /** Returns the view settings for this sheet. */
+    SheetViewSettings&  getSheetViewSettings() const;
+    /** Returns the VML drawing page for this sheet (OOXML/BIFF12 only). */
+    VmlDrawing&         getVmlDrawing() const;
+    /** Returns the BIFF drawing page for this sheet (BIFF2-BIFF8 only). */
+    BiffSheetDrawing&   getBiffDrawing() const;
+
+    /** Changes the current sheet type. */
+    void                setSheetType( WorksheetType eSheetType );
+    /** 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 passed label ranges to the current sheet. */
+    void                setLabelRanges( const ApiCellRangeList& rColRanges, const ApiCellRangeList& rRowRanges );
+    /** Sets the path to the DrawingML fragment of this sheet. */
+    void                setDrawingPath( const ::rtl::OUString& rDrawingPath );
+    /** Sets the path to the legacy VML drawing fragment of this sheet. */
+    void                setVmlDrawingPath( const ::rtl::OUString& rVmlDrawingPath );
+
+    /** Extends the used area of this sheet by the passed cell position. */
+    void                extendUsedArea( const ::com::sun::star::table::CellAddress& rAddress );
+    /** Extends the used area of this sheet by the passed cell range. */
+    void                extendUsedArea( const ::com::sun::star::table::CellRangeAddress& rRange );
+    /** Extends the shape bounding box by the position and size of the passed rectangle (in 1/100 mm). */
+    void                extendShapeBoundingBox( const ::com::sun::star::awt::Rectangle& rShapeRect );
+
+    /** Sets base width for all columns (without padding pixels). This value
+        is only used, if 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 );
+    /** Converts default cell formatting for a range of columns. */
+    void                setDefaultColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId );
+    /** Sets column settings for a specific range of columns.
+        @descr  Column default formatting is converted directly, other settings
+        are cached and converted in the finalizeWorksheetImport() 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 range of rows.
+        @descr  Row default formatting is converted directly, other settings
+        are cached and converted in the finalizeWorksheetImport() call. */
+    void                setRowModel( const RowModel& rModel );
+    /** Specifies that the passed row needs to set its height manually. */
+    void                setManualRowHeight( sal_Int32 nRow );
+
+    /** Inserts a value cell directly into the Calc sheet. */
+    void                putValue(
+                            const ::com::sun::star::table::CellAddress& rAddress,
+                            double fValue ) const;
+    void                putFormulaResult(
+                            const ::com::sun::star::table::CellAddress& rAddress,
+                            double fValue ) const;
+
+    /** Inserts a string cell directly into the Calc sheet. */
+    void                putString(
+                            const ::com::sun::star::table::CellAddress& rAddress,
+                            const ::rtl::OUString& rText ) const;
+    /** Inserts a rich-string cell directly into the Calc sheet. */
+    void                putRichString(
+                            const ::com::sun::star::table::CellAddress& rAddress,
+                            const RichString& rString,
+                            const Font* pFirstPortionFont ) const;
+    /** Inserts a formula cell directly into the Calc sheet. */
+    void                putFormulaTokens(
+                            const ::com::sun::star::table::CellAddress& rAddress,
+                            const ApiTokenSequence& rTokens ) const;
+
+    /** Initial conversion before importing the worksheet. */
+    void                initializeWorksheetImport();
+    /** Final conversion after importing the worksheet. */
+    void                finalizeWorksheetImport();
+
+private:
+    WorksheetGlobals&   mrSheetGlob;
+};
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/worksheetsettings.hxx b/sc/source/filter/inc/worksheetsettings.hxx
new file mode 100644
index 000000000000..175c61dd191b
--- /dev/null
+++ b/sc/source/filter/inc/worksheetsettings.hxx
@@ -0,0 +1,147 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_WORKSHEETSETTINGS_HXX
+#define OOX_XLS_WORKSHEETSETTINGS_HXX
+
+#include "richstring.hxx"
+#include "worksheethelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Sheet and outline settings. */
+struct SheetSettingsModel
+{
+    ::rtl::OUString     maCodeName;             /// VBA module codename.
+    Color               maTabColor;             /// Sheet tab color.
+    bool                mbFilterMode;           /// True = sheet contains active filter.
+    bool                mbApplyStyles;          /// True = automatic styles when creating outlines.
+    bool                mbSummaryBelow;         /// True = row outline symbols below group.
+    bool                mbSummaryRight;         /// True = column outline symbols right of group.
+
+    explicit            SheetSettingsModel();
+};
+
+// ============================================================================
+
+/** Sheet protection settings. */
+struct SheetProtectionModel
+{
+    sal_uInt16          mnPasswordHash;         /// Hash value from sheet protection password.
+    bool                mbSheet;                /// True = sheet protection enabled, locked cells are protcted.
+    bool                mbObjects;              /// True = objects locked.
+    bool                mbScenarios;            /// True = scenarios locked.
+    bool                mbFormatCells;          /// True = format cells locked.
+    bool                mbFormatColumns;        /// True = format columns locked.
+    bool                mbFormatRows;           /// True = format rows locked.
+    bool                mbInsertColumns;        /// True = insert columns locked.
+    bool                mbInsertRows;           /// True = insert rows locked.
+    bool                mbInsertHyperlinks;     /// True = insert hyperlinks locked.
+    bool                mbDeleteColumns;        /// True = delete columns locked.
+    bool                mbDeleteRows;           /// True = delete rows locked.
+    bool                mbSelectLocked;         /// True = select locked cells locked.
+    bool                mbSort;                 /// True = sorting locked.
+    bool                mbAutoFilter;           /// True = autofilters locked.
+    bool                mbPivotTables;          /// True = pivot tables locked.
+    bool                mbSelectUnlocked;       /// True = select unlocked cells locked.
+
+    explicit            SheetProtectionModel();
+};
+
+// ============================================================================
+
+class WorksheetSettings : public WorksheetHelper
+{
+public:
+    explicit            WorksheetSettings( const WorksheetHelper& rHelper );
+
+    /** Imports sheet settings from the sheetPr element. */
+    void                importSheetPr( const AttributeList& rAttribs );
+    /** Imports chart sheet settings from the sheetPr element. */
+    void                importChartSheetPr( const AttributeList& rAttribs );
+    /** Imports the sheet tab color from the tabColor element. */
+    void                importTabColor( const AttributeList& rAttribs );
+    /** Imports outline settings from the outlinePr element. */
+    void                importOutlinePr( const AttributeList& rAttribs );
+    /** Imports protection settings from the sheetProtection element. */
+    void                importSheetProtection( const AttributeList& rAttribs );
+    /** Imports protection settings from the sheetProtection element of a chart sheet. */
+    void                importChartProtection( const AttributeList& rAttribs );
+    /** Imports phonetic settings from the phoneticPr element. */
+    void                importPhoneticPr( const AttributeList& rAttribs );
+
+    /** Imports sheet properties from the SHEETPR record. */
+    void                importSheetPr( SequenceInputStream& rStrm );
+    /** Imports sheet properties from the CHARTSHEETPR record. */
+    void                importChartSheetPr( SequenceInputStream& rStrm );
+    /** Imports sheet protection settings from the SHEETPROTECTION record. */
+    void                importSheetProtection( SequenceInputStream& rStrm );
+    /** Imports chart sheet protection settings from the CHARTPROTECTION record. */
+    void                importChartProtection( SequenceInputStream& rStrm );
+    /** Imports phonetic settings from the PHONETICPR record. */
+    void                importPhoneticPr( SequenceInputStream& rStrm );
+
+    /** Imports sheet properties from a SHEETEXT record. */
+    void                importSheetExt( BiffInputStream& rStrm );
+    /** Imports sheet properties from a SHEETPR record. */
+    void                importSheetPr( BiffInputStream& rStrm );
+    /** Imports protection status from the PROTECT record. */
+    void                importProtect( BiffInputStream& rStrm );
+    /** Imports object protection status from the OBJECTPROTECT record. */
+    void                importObjectProtect( BiffInputStream& rStrm );
+    /** Imports scenario protection status from the SCENPROTECT record. */
+    void                importScenProtect( BiffInputStream& rStrm );
+    /** Imports sheet password hash from the PASSWORD record. */
+    void                importPassword( BiffInputStream& rStrm );
+    /** Imports protection settings from the SHEETPROTECTION record. */
+    void                importSheetProtection( BiffInputStream& rStrm );
+    /** Imports the VBA code module name from the CODENAME record. */
+    void                importCodeName( BiffInputStream& rStrm );
+    /** Imports phonetic settings from the PHONETICPR record. */
+    void                importPhoneticPr( BiffInputStream& rStrm );
+
+    /** Converts the imported worksheet settings. */
+    void                finalizeImport();
+
+private:
+    PhoneticSettings    maPhoneticSett;
+    SheetSettingsModel  maSheetSettings;
+    SheetProtectionModel maSheetProt;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/addressconverter.cxx b/sc/source/filter/oox/addressconverter.cxx
new file mode 100644
index 000000000000..9f0c09c89f20
--- /dev/null
+++ b/sc/source/filter/oox/addressconverter.cxx
@@ -0,0 +1,760 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "addressconverter.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "biffinputstream.hxx"
+#include "biffoutputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OStringBuffer;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OUStringToOString;
+
+// ============================================================================
+
+namespace {
+
+//! TODO: this limit may change, is there a way to obtain it via API?
+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_uInt8 lclGetBiffAddressSize( bool bCol16Bit, bool bRow32Bit )
+{
+    return (bCol16Bit ? 2 : 1) + (bRow32Bit ? 4 : 2);
+}
+
+inline sal_uInt8 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( SequenceInputStream& 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( SequenceInputStream& 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 );
+}
+
+// ============================================================================
+
+void BinRangeList::read( SequenceInputStream& 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_OOXML:
+            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 );
+}
+
+// ----------------------------------------------------------------------------
+
+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.isEmpty() && 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_FAIL( "AddressConverter::AddressConverter - cannot get sheet limits" );
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/autofilterbuffer.cxx b/sc/source/filter/oox/autofilterbuffer.cxx
new file mode 100644
index 000000000000..ed5f1c316204
--- /dev/null
+++ b/sc/source/filter/oox/autofilterbuffer.cxx
@@ -0,0 +1,871 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "autofilterbuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "defnamesbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt8 BIFF12_TOP10FILTER_TOP              = 0x01;
+const sal_uInt8 BIFF12_TOP10FILTER_PERCENT          = 0x02;
+
+const sal_uInt16 BIFF12_FILTERCOLUMN_HIDDENBUTTON   = 0x0001;
+const sal_uInt16 BIFF12_FILTERCOLUMN_SHOWBUTTON     = 0x0002;
+
+const sal_uInt16 BIFF_FILTERCOLUMN_OR               = 0x0001;
+const sal_uInt16 BIFF_FILTERCOLUMN_TOP10FILTER      = 0x0010;
+const sal_uInt16 BIFF_FILTERCOLUMN_TOP              = 0x0020;
+const sal_uInt16 BIFF_FILTERCOLUMN_PERCENT          = 0x0040;
+
+const sal_uInt8 BIFF_FILTER_DATATYPE_NONE           = 0;
+const sal_uInt8 BIFF_FILTER_DATATYPE_RK             = 2;
+const sal_uInt8 BIFF_FILTER_DATATYPE_DOUBLE         = 4;
+const sal_uInt8 BIFF_FILTER_DATATYPE_STRING         = 6;
+const sal_uInt8 BIFF_FILTER_DATATYPE_BOOLEAN        = 8;
+const sal_uInt8 BIFF_FILTER_DATATYPE_EMPTY          = 12;
+const sal_uInt8 BIFF_FILTER_DATATYPE_NOTEMPTY       = 14;
+
+// ----------------------------------------------------------------------------
+
+bool lclGetApiOperatorFromToken( sal_Int32& rnApiOperator, sal_Int32 nToken )
+{
+    switch( nToken )
+    {
+        case XML_lessThan:              rnApiOperator = FilterOperator2::NOT_EQUAL;     return true;
+        case XML_equal:                 rnApiOperator = FilterOperator2::EQUAL;         return true;
+        case XML_lessThanOrEqual:       rnApiOperator = FilterOperator2::LESS_EQUAL;    return true;
+        case XML_greaterThan:           rnApiOperator = FilterOperator2::GREATER;       return true;
+        case XML_notEqual:              rnApiOperator = FilterOperator2::NOT_EQUAL;     return true;
+        case XML_greaterThanOrEqual:    rnApiOperator = FilterOperator2::GREATER_EQUAL; return true;
+    }
+    return false;
+}
+
+/** Removes leading asterisk characters from the passed string.
+    @return  True = at least one asterisk character has been removed. */
+bool lclTrimLeadingAsterisks( OUString& rValue )
+{
+    sal_Int32 nLength = rValue.getLength();
+    sal_Int32 nPos = 0;
+    while( (nPos < nLength) && (rValue[ nPos ] == '*') )
+        ++nPos;
+    if( nPos > 0 )
+    {
+        rValue = rValue.copy( nPos );
+        return true;
+    }
+    return false;
+}
+
+/** Removes trailing asterisk characters from the passed string.
+    @return  True = at least one asterisk character has been removed. */
+bool lclTrimTrailingAsterisks( OUString& rValue )
+{
+    sal_Int32 nLength = rValue.getLength();
+    sal_Int32 nPos = nLength;
+    while( (nPos > 0) && (rValue[ nPos - 1 ] == '*') )
+        --nPos;
+    if( nPos < nLength )
+    {
+        rValue = rValue.copy( 0, nPos );
+        return true;
+    }
+    return false;
+}
+
+/** Converts wildcard characters '*' and '?' to regular expressions and quotes
+    RE meta characters.
+    @return  True = passed string has been changed (RE needs to be enabled). */
+bool lclConvertWildcardsToRegExp( OUString& rValue )
+{
+    // check existence of the wildcard characters '*' and '?'
+    if( !rValue.isEmpty() && ((rValue.indexOf( '*' ) >= 0) || (rValue.indexOf( '?' ) >= 0)) )
+    {
+        OUStringBuffer aBuffer;
+        aBuffer.ensureCapacity( rValue.getLength() + 5 );
+        const sal_Unicode* pcChar = rValue.getStr();
+        const sal_Unicode* pcEnd = pcChar + rValue.getLength();
+        for( ; pcChar < pcEnd; ++pcChar )
+        {
+            switch( *pcChar )
+            {
+                case '?':
+                    aBuffer.append( sal_Unicode( '.' ) );
+                break;
+                case '*':
+                    aBuffer.append( sal_Unicode( '.' ) ).append( sal_Unicode( '*' ) );
+                break;
+                case '\\': case '.': case '|': case '(': case ')': case '^': case '$':
+                    // quote RE meta characters
+                    aBuffer.append( sal_Unicode( '\\' ) ).append( *pcChar );
+                break;
+                default:
+                    aBuffer.append( *pcChar );
+            }
+        }
+        rValue = aBuffer.makeStringAndClear();
+        return true;
+    }
+    return false;
+}
+
+} // namespace
+
+// ============================================================================
+
+ApiFilterSettings::ApiFilterSettings()
+{
+}
+
+void ApiFilterSettings::appendField( bool bAnd, sal_Int32 nOperator, double fValue )
+{
+    maFilterFields.resize( maFilterFields.size() + 1 );
+    TableFilterField3& rFilterField = maFilterFields.back();
+    rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
+    rFilterField.Operator = nOperator;
+    rFilterField.Values.realloc(1);
+    rFilterField.Values[0].IsNumeric = true;
+    rFilterField.Values[0].NumericValue = fValue;
+}
+
+void ApiFilterSettings::appendField( bool bAnd, sal_Int32 nOperator, const OUString& rValue )
+{
+    maFilterFields.resize( maFilterFields.size() + 1 );
+    TableFilterField3& rFilterField = maFilterFields.back();
+    rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
+    rFilterField.Operator = nOperator;
+    rFilterField.Values.realloc(1);
+    rFilterField.Values[0].IsNumeric = false;
+    rFilterField.Values[0].StringValue = rValue;
+}
+
+void ApiFilterSettings::appendField( bool bAnd, const std::vector& rValues )
+{
+    maFilterFields.resize( maFilterFields.size() + 1 );
+    TableFilterField3& rFilterField = maFilterFields.back();
+    rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
+    rFilterField.Operator = FilterOperator2::EQUAL;
+    size_t n = rValues.size();
+    rFilterField.Values.realloc(n);
+    for (size_t i = 0; i < n; ++i)
+    {
+        rFilterField.Values[i].IsNumeric = false;
+        rFilterField.Values[i].StringValue = rValues[i];
+    }
+}
+
+// ============================================================================
+
+FilterSettingsBase::FilterSettingsBase( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper )
+{
+}
+
+void FilterSettingsBase::importAttribs( sal_Int32 /*nElement*/, const AttributeList& /*rAttribs*/ )
+{
+}
+
+void FilterSettingsBase::importRecord( sal_Int32 /*nRecId*/, SequenceInputStream& /*rStrm*/ )
+{
+}
+
+void FilterSettingsBase::importBiffRecord( BiffInputStream& /*rStrm*/, sal_uInt16 /*nFlags*/ )
+{
+}
+
+ApiFilterSettings FilterSettingsBase::finalizeImport( sal_Int32 /*nMaxCount*/ )
+{
+    return ApiFilterSettings();
+}
+
+// ============================================================================
+
+DiscreteFilter::DiscreteFilter( const WorkbookHelper& rHelper ) :
+    FilterSettingsBase( rHelper ),
+    mnCalendarType( XML_none ),
+    mbShowBlank( false )
+{
+}
+
+void DiscreteFilter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    switch( nElement )
+    {
+        case XLS_TOKEN( filters ):
+            mnCalendarType = rAttribs.getToken( XML_calendarType, XML_none );
+            mbShowBlank = rAttribs.getBool( XML_blank, false );
+        break;
+
+        case XLS_TOKEN( filter ):
+        {
+            OUString aValue = rAttribs.getXString( XML_val, OUString() );
+            if( !aValue.isEmpty() )
+                maValues.push_back( aValue );
+        }
+        break;
+    }
+}
+
+void DiscreteFilter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( nRecId )
+    {
+        case BIFF12_ID_DISCRETEFILTERS:
+        {
+            sal_Int32 nShowBlank, nCalendarType;
+            rStrm >> nShowBlank >> nCalendarType;
+
+            static const sal_Int32 spnCalendarTypes[] = {
+                XML_none, XML_gregorian, XML_gregorianUs, XML_japan, XML_taiwan, XML_korea, XML_hijri, XML_thai, XML_hebrew,
+                XML_gregorianMeFrench, XML_gregorianArabic, XML_gregorianXlitEnglish, XML_gregorianXlitFrench };
+            mnCalendarType = STATIC_ARRAY_SELECT( spnCalendarTypes, nCalendarType, XML_none );
+            mbShowBlank = nShowBlank != 0;
+        }
+        break;
+
+        case BIFF12_ID_DISCRETEFILTER:
+        {
+            OUString aValue = BiffHelper::readString( rStrm );
+            if( !aValue.isEmpty() )
+                maValues.push_back( aValue );
+        }
+        break;
+    }
+}
+
+ApiFilterSettings DiscreteFilter::finalizeImport( sal_Int32 nMaxCount )
+{
+    ApiFilterSettings aSettings;
+    if( static_cast< sal_Int32 >( maValues.size() ) <= nMaxCount )
+    {
+        aSettings.maFilterFields.reserve( maValues.size() );
+
+        // insert all filter values
+        aSettings.appendField( true, maValues );
+
+        // extra field for 'show empty'
+        if( mbShowBlank )
+            aSettings.appendField( false, FilterOperator2::EMPTY, OUString() );
+
+        /*  Require disabled regular expressions, filter entries may contain
+            any RE meta characters. */
+        if( !maValues.empty() )
+            aSettings.mobNeedsRegExp = false;
+    }
+    return aSettings;
+}
+
+// ============================================================================
+
+Top10Filter::Top10Filter( const WorkbookHelper& rHelper ) :
+    FilterSettingsBase( rHelper ),
+    mfValue( 0.0 ),
+    mbTop( true ),
+    mbPercent( false )
+{
+}
+
+void Top10Filter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    if( nElement == XLS_TOKEN( top10 ) )
+    {
+        mfValue = rAttribs.getDouble( XML_val, 0.0 );
+        mbTop = rAttribs.getBool( XML_top, true );
+        mbPercent = rAttribs.getBool( XML_percent, false );
+    }
+}
+
+void Top10Filter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    if( nRecId == BIFF12_ID_TOP10FILTER )
+    {
+        sal_uInt8 nFlags;
+        rStrm >> nFlags >> mfValue;
+        mbTop = getFlag( nFlags, BIFF12_TOP10FILTER_TOP );
+        mbPercent = getFlag( nFlags, BIFF12_TOP10FILTER_PERCENT );
+    }
+}
+
+void Top10Filter::importBiffRecord( BiffInputStream& /*rStrm*/, sal_uInt16 nFlags )
+{
+    mfValue = extractValue< sal_uInt16 >( nFlags, 7, 9 );
+    mbTop = getFlag( nFlags, BIFF_FILTERCOLUMN_TOP );
+    mbPercent = getFlag( nFlags, BIFF_FILTERCOLUMN_PERCENT );
+}
+
+ApiFilterSettings Top10Filter::finalizeImport( sal_Int32 /*nMaxCount*/ )
+{
+    sal_Int32 nOperator = mbTop ?
+        (mbPercent ? FilterOperator2::TOP_PERCENT : FilterOperator2::TOP_VALUES) :
+        (mbPercent ? FilterOperator2::BOTTOM_PERCENT : FilterOperator2::BOTTOM_VALUES);
+    ApiFilterSettings aSettings;
+    aSettings.appendField( true, nOperator, mfValue );
+    return aSettings;
+}
+
+// ============================================================================
+
+FilterCriterionModel::FilterCriterionModel() :
+    mnOperator( XML_equal ),
+    mnDataType( BIFF_FILTER_DATATYPE_NONE ),
+    mnStrLen( 0 )
+{
+}
+
+void FilterCriterionModel::setBiffOperator( sal_uInt8 nOperator )
+{
+    static const sal_Int32 spnOperators[] = { XML_TOKEN_INVALID,
+        XML_lessThan, XML_equal, XML_lessThanOrEqual, XML_greaterThan, XML_notEqual, XML_greaterThanOrEqual };
+    mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
+}
+
+void FilterCriterionModel::readBiffData( SequenceInputStream& rStrm )
+{
+    sal_uInt8 nOperator;
+    rStrm >> mnDataType >> nOperator;
+    setBiffOperator( nOperator );
+
+    switch( mnDataType )
+    {
+        case BIFF_FILTER_DATATYPE_DOUBLE:
+            maValue <<= rStrm.readDouble();
+        break;
+        case BIFF_FILTER_DATATYPE_STRING:
+        {
+            rStrm.skip( 8 );
+            OUString aValue = BiffHelper::readString( rStrm ).trim();
+            if( !aValue.isEmpty() )
+                maValue <<= aValue;
+        }
+        break;
+        case BIFF_FILTER_DATATYPE_BOOLEAN:
+            maValue <<= (rStrm.readuInt8() != 0);
+            rStrm.skip( 7 );
+        break;
+        case BIFF_FILTER_DATATYPE_EMPTY:
+            rStrm.skip( 8 );
+            if( mnOperator == XML_equal )
+                maValue <<= OUString();
+        break;
+        case BIFF_FILTER_DATATYPE_NOTEMPTY:
+            rStrm.skip( 8 );
+            if( mnOperator == XML_notEqual )
+                maValue <<= OUString();
+        break;
+        default:
+            OSL_ENSURE( false, "FilterCriterionModel::readBiffData - unexpected data type" );
+            rStrm.skip( 8 );
+    }
+}
+
+void FilterCriterionModel::readBiffData( BiffInputStream& rStrm )
+{
+    sal_uInt8 nOperator;
+    rStrm >> mnDataType >> nOperator;
+    setBiffOperator( nOperator );
+
+    switch( mnDataType )
+    {
+        case BIFF_FILTER_DATATYPE_NONE:
+            rStrm.skip( 8 );
+        break;
+        case BIFF_FILTER_DATATYPE_RK:
+            maValue <<= BiffHelper::calcDoubleFromRk( rStrm.readInt32() );
+            rStrm.skip( 4 );
+        break;
+        case BIFF_FILTER_DATATYPE_DOUBLE:
+            maValue <<= rStrm.readDouble();
+        break;
+        case BIFF_FILTER_DATATYPE_STRING:
+            rStrm.skip( 4 );
+            rStrm >> mnStrLen;
+            rStrm.skip( 3 );
+        break;
+        case BIFF_FILTER_DATATYPE_BOOLEAN:
+        {
+            sal_uInt8 nValue, nType;
+            rStrm >> nValue >> nType;
+            rStrm.skip( 6 );
+            switch( nType )
+            {
+                case BIFF_BOOLERR_BOOL:     maValue <<= (nValue != 0);                              break;
+                case BIFF_BOOLERR_ERROR:    maValue <<= BiffHelper::calcDoubleFromError( nValue );  break;
+                default:                    OSL_ENSURE( false, "FilterCriterionModel::readBiffData - unknown type" );
+            }
+        }
+        break;
+        case BIFF_FILTER_DATATYPE_EMPTY:
+            rStrm.skip( 8 );
+            if( mnOperator == XML_equal )
+                maValue <<= OUString();
+        break;
+        case BIFF_FILTER_DATATYPE_NOTEMPTY:
+            rStrm.skip( 8 );
+            if( mnOperator == XML_notEqual )
+                maValue <<= OUString();
+        break;
+        default:
+            OSL_ENSURE( false, "FilterCriterionModel::readBiffData - unexpected data type" );
+            rStrm.skip( 8 );
+    }
+}
+
+void FilterCriterionModel::readString( BiffInputStream& rStrm, BiffType eBiff, rtl_TextEncoding eTextEnc )
+{
+    if( (mnDataType == BIFF_FILTER_DATATYPE_STRING) && (mnStrLen > 0) )
+    {
+        OUString aValue = (eBiff == BIFF8) ?
+            rStrm.readUniStringBody( mnStrLen, true ) :
+            rStrm.readCharArrayUC( mnStrLen, eTextEnc, true );
+        aValue = aValue.trim();
+        if( !aValue.isEmpty() )
+            maValue <<= aValue;
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+CustomFilter::CustomFilter( const WorkbookHelper& rHelper ) :
+    FilterSettingsBase( rHelper ),
+    mbAnd( false )
+{
+}
+
+void CustomFilter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    switch( nElement )
+    {
+        case XLS_TOKEN( customFilters ):
+            mbAnd = rAttribs.getBool( XML_and, false );
+        break;
+
+        case XLS_TOKEN( customFilter ):
+        {
+            FilterCriterionModel aCriterion;
+            aCriterion.mnOperator = rAttribs.getToken( XML_operator, XML_equal );
+            OUString aValue = rAttribs.getXString( XML_val, OUString() ).trim();
+            if( (aCriterion.mnOperator == XML_equal) || (aCriterion.mnOperator == XML_notEqual) || (!aValue.isEmpty()) )
+                aCriterion.maValue <<= aValue;
+            appendCriterion( aCriterion );
+        }
+        break;
+    }
+}
+
+void CustomFilter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( nRecId )
+    {
+        case BIFF12_ID_CUSTOMFILTERS:
+            mbAnd = rStrm.readInt32() == 0;
+        break;
+
+        case BIFF12_ID_CUSTOMFILTER:
+        {
+            FilterCriterionModel aCriterion;
+            aCriterion.readBiffData( rStrm );
+            appendCriterion( aCriterion );
+        }
+        break;
+    }
+}
+
+void CustomFilter::importBiffRecord( BiffInputStream& rStrm, sal_uInt16 nFlags )
+{
+    mbAnd = !getFlag( nFlags, BIFF_FILTERCOLUMN_OR );
+
+    FilterCriterionModel aCriterion1, aCriterion2;
+    aCriterion1.readBiffData( rStrm );
+    aCriterion2.readBiffData( rStrm );
+    aCriterion1.readString( rStrm, getBiff(), getTextEncoding() );
+    aCriterion2.readString( rStrm, getBiff(), getTextEncoding() );
+    appendCriterion( aCriterion1 );
+    appendCriterion( aCriterion2 );
+}
+
+ApiFilterSettings CustomFilter::finalizeImport( sal_Int32 /*nMaxCount*/ )
+{
+    ApiFilterSettings aSettings;
+    OSL_ENSURE( maCriteria.size() <= 2, "CustomFilter::finalizeImport - too many filter criteria" );
+    for( FilterCriterionVector::iterator aIt = maCriteria.begin(), aEnd = maCriteria.end(); aIt != aEnd; ++aIt )
+    {
+        // first extract the filter operator
+        sal_Int32 nOperator = 0;
+        bool bValidOperator = lclGetApiOperatorFromToken( nOperator, aIt->mnOperator );
+        if( bValidOperator )
+        {
+            if( aIt->maValue.has< OUString >() )
+            {
+                // string argument
+                OUString aValue;
+                aIt->maValue >>= aValue;
+                // check for 'empty', 'contains', 'begins with', or 'ends with' text filters
+                bool bEqual = nOperator == FilterOperator2::EQUAL;
+                bool bNotEqual = nOperator == FilterOperator2::NOT_EQUAL;
+                if( bEqual || bNotEqual )
+                {
+                    if( aValue.isEmpty() )
+                    {
+                        // empty comparison string: create empty/not empty filters
+                        nOperator = bNotEqual ? FilterOperator2::NOT_EMPTY : FilterOperator2::EMPTY;
+                    }
+                    else
+                    {
+                        // compare to something: try to find begins/ends/contains
+                        bool bHasLeadingAsterisk = lclTrimLeadingAsterisks( aValue );
+                        bool bHasTrailingAsterisk = lclTrimTrailingAsterisks( aValue );
+                        // just '***' matches everything, do not create a filter field
+                        bValidOperator = !aValue.isEmpty();
+                        if( bValidOperator )
+                        {
+                            if( bHasLeadingAsterisk && bHasTrailingAsterisk )
+                                nOperator = bNotEqual ? FilterOperator2::DOES_NOT_CONTAIN : FilterOperator2::CONTAINS;
+                            else if( bHasLeadingAsterisk )
+                                nOperator = bNotEqual ? FilterOperator2::DOES_NOT_END_WITH : FilterOperator2::ENDS_WITH;
+                            else if( bHasTrailingAsterisk )
+                                nOperator = bNotEqual ? FilterOperator2::DOES_NOT_BEGIN_WITH : FilterOperator2::BEGINS_WITH;
+                            // else: no asterisks, stick to equal/not equal
+                        }
+                    }
+                }
+
+                if( bValidOperator )
+                {
+                    // if wildcards are present, require RE mode, otherwise keep don't care state
+                    if( lclConvertWildcardsToRegExp( aValue ) )
+                        aSettings.mobNeedsRegExp = true;
+                    // create a new UNO API filter field
+                    aSettings.appendField( mbAnd, nOperator, aValue );
+                }
+            }
+            else if( aIt->maValue.has< double >() )
+            {
+                // floating-point argument
+                double fValue = 0.0;
+                aIt->maValue >>= fValue;
+                aSettings.appendField( mbAnd, nOperator, fValue );
+            }
+        }
+    }
+    return aSettings;
+}
+
+void CustomFilter::appendCriterion( const FilterCriterionModel& rCriterion )
+{
+    if( (rCriterion.mnOperator != XML_TOKEN_INVALID) && rCriterion.maValue.hasValue() )
+        maCriteria.push_back( rCriterion );
+}
+
+// ============================================================================
+
+FilterColumn::FilterColumn( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper ),
+    mnColId( -1 ),
+    mbHiddenButton( false ),
+    mbShowButton( true )
+{
+}
+
+void FilterColumn::importFilterColumn( const AttributeList& rAttribs )
+{
+    mnColId = rAttribs.getInteger( XML_colId, -1 );
+    mbHiddenButton = rAttribs.getBool( XML_hiddenButton, false );
+    mbShowButton = rAttribs.getBool( XML_showButton, true );
+}
+
+void FilterColumn::importFilterColumn( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    rStrm >> mnColId >> nFlags;
+    mbHiddenButton = getFlag( nFlags, BIFF12_FILTERCOLUMN_HIDDENBUTTON );
+    mbShowButton = getFlag( nFlags, BIFF12_FILTERCOLUMN_SHOWBUTTON );
+}
+
+void FilterColumn::importFilterColumn( BiffInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    mnColId = rStrm.readuInt16();
+    rStrm >> nFlags;
+
+    // BIFF5/BIFF8 support top-10 filters and custom filters
+    if( getFlag( nFlags, BIFF_FILTERCOLUMN_TOP10FILTER ) )
+        createFilterSettings< Top10Filter >().importBiffRecord( rStrm, nFlags );
+    else
+        createFilterSettings< CustomFilter >().importBiffRecord( rStrm, nFlags );
+}
+
+ApiFilterSettings FilterColumn::finalizeImport( sal_Int32 nMaxCount )
+{
+    ApiFilterSettings aSettings;
+    if( (0 <= mnColId) && mxSettings.get() )
+    {
+        // filter settings object creates a sequence of filter fields
+        aSettings = mxSettings->finalizeImport( nMaxCount );
+        // add column index to all filter fields
+        for( ApiFilterSettings::FilterFieldVector::iterator aIt = aSettings.maFilterFields.begin(), aEnd = aSettings.maFilterFields.end(); aIt != aEnd; ++aIt )
+            aIt->Field = mnColId;
+    }
+    return aSettings;
+}
+
+// ============================================================================
+
+AutoFilter::AutoFilter( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper )
+{
+}
+
+void AutoFilter::importAutoFilter( const AttributeList& rAttribs, sal_Int16 nSheet )
+{
+    OUString aRangeStr = rAttribs.getString( XML_ref, OUString() );
+    getAddressConverter().convertToCellRangeUnchecked( maRange, aRangeStr, nSheet );
+}
+
+void AutoFilter::importAutoFilter( SequenceInputStream& rStrm, sal_Int16 nSheet )
+{
+    BinRange aBinRange;
+    rStrm >> aBinRange;
+    getAddressConverter().convertToCellRangeUnchecked( maRange, aBinRange, nSheet );
+}
+
+FilterColumn& AutoFilter::createFilterColumn()
+{
+    FilterColumnVector::value_type xFilterColumn( new FilterColumn( *this ) );
+    maFilterColumns.push_back( xFilterColumn );
+    return *xFilterColumn;
+}
+
+void AutoFilter::finalizeImport( const Reference& rxFilterDesc )
+{
+    if( rxFilterDesc.is() )
+    {
+        // set some common properties for the auto filter range
+        PropertySet aDescProps( rxFilterDesc );
+        aDescProps.setProperty( PROP_IsCaseSensitive, false );
+        aDescProps.setProperty( PROP_SkipDuplicates, false );
+        aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
+        aDescProps.setProperty( PROP_ContainsHeader, true );
+        aDescProps.setProperty( PROP_CopyOutputData, false );
+
+        // maximum number of UNO API filter fields
+        sal_Int32 nMaxCount = 0;
+        aDescProps.getProperty( nMaxCount, PROP_MaxFieldCount );
+        OSL_ENSURE( nMaxCount > 0, "AutoFilter::finalizeImport - invalid maximum filter field count" );
+
+        // resulting list of all UNO API filter fields
+        ::std::vector aFilterFields;
+
+        // track if columns require to enable or disable regular expressions
+        OptValue< bool > obNeedsRegExp;
+
+        /*  Track whether the filter fields of the first filter column are
+            connected with 'or'. In this case, other filter fields cannot be
+            inserted without altering the result of the entire filter, due to
+            Calc's precedence for the 'and' connection operator. Example:
+            Excel's filter conditions 'A1 and (B1 or B2) and C1' where B1 and
+            B2 belong to filter column B, will be evaluated by Calc as
+            '(A1 and B1) or (B2 and C1)'. */
+        bool bHasOrConnection = false;
+
+        // process all filter column objects, exit when 'or' connection exists
+        for( FilterColumnVector::iterator aIt = maFilterColumns.begin(), aEnd = maFilterColumns.end(); !bHasOrConnection && (aIt != aEnd); ++aIt )
+        {
+            // the filter settings object creates a list of filter fields
+            ApiFilterSettings aSettings = (*aIt)->finalizeImport( nMaxCount );
+            ApiFilterSettings::FilterFieldVector& rColumnFields = aSettings.maFilterFields;
+
+            // new total number of filter fields
+            sal_Int32 nNewCount = static_cast< sal_Int32 >( aFilterFields.size() + rColumnFields.size() );
+
+            /*  Check whether mode for regular expressions is compatible with
+                the global mode in obNeedsRegExp. If either one is still in
+                don't-care state, all is fine. If both are set, they must be
+                equal. */
+            bool bRegExpCompatible = !obNeedsRegExp || !aSettings.mobNeedsRegExp || (obNeedsRegExp.get() == aSettings.mobNeedsRegExp.get());
+
+            // check whether fields are connected by 'or' (see comments above).
+            if( rColumnFields.size() >= 2 )
+                for( ApiFilterSettings::FilterFieldVector::iterator aSIt = rColumnFields.begin() + 1, aSEnd = rColumnFields.end(); !bHasOrConnection && (aSIt != aSEnd); ++aSIt )
+                    bHasOrConnection = aSIt->Connection == FilterConnection_OR;
+
+            /*  Skip the column filter, if no filter fields have been created,
+                if the number of new filter fields would exceed the total limit
+                of filter fields, or if the mode for regular expressions of the
+                filter column does not fit. */
+            if( !rColumnFields.empty() && (nNewCount <= nMaxCount) && bRegExpCompatible )
+            {
+                /*  Add 'and' connection to the first filter field to connect
+                    it to the existing filter fields of other columns. */
+                rColumnFields[ 0 ].Connection = FilterConnection_AND;
+
+                // insert the new filter fields
+                aFilterFields.insert( aFilterFields.end(), rColumnFields.begin(), rColumnFields.end() );
+
+                // update the regular expressions mode
+                obNeedsRegExp.assignIfUsed( aSettings.mobNeedsRegExp );
+            }
+        }
+
+        // insert all filter fields to the filter descriptor
+        if( !aFilterFields.empty() )
+            rxFilterDesc->setFilterFields3( ContainerHelper::vectorToSequence( aFilterFields ) );
+
+        // regular expressions
+        bool bUseRegExp = obNeedsRegExp.get( false );
+        aDescProps.setProperty( PROP_UseRegularExpressions, bUseRegExp );
+    }
+}
+
+// ============================================================================
+
+AutoFilterBuffer::AutoFilterBuffer( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper )
+{
+}
+
+AutoFilter& AutoFilterBuffer::createAutoFilter()
+{
+    AutoFilterVector::value_type xAutoFilter( new AutoFilter( *this ) );
+    maAutoFilters.push_back( xAutoFilter );
+    return *xAutoFilter;
+}
+
+void AutoFilterBuffer::finalizeImport( sal_Int16 nSheet )
+{
+    // rely on existence of the defined name '_FilterDatabase' containing the range address of the filtered area
+    if( const DefinedName* pFilterDBName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_FILTERDATABASE, nSheet ).get() )
+    {
+        CellRangeAddress aFilterRange;
+        if( pFilterDBName->getAbsoluteRange( aFilterRange ) && (aFilterRange.Sheet == nSheet) )
+        {
+            // use the same name for the database range as used for the defined name '_FilterDatabase'
+            Reference< XDatabaseRange > xDatabaseRange = createUnnamedDatabaseRangeObject( aFilterRange );
+            // first, try to create an auto filter
+            bool bHasAutoFilter = finalizeImport( xDatabaseRange );
+            // no success: try to create an advanced filter
+            if( !bHasAutoFilter && xDatabaseRange.is() )
+            {
+                // the built-in defined name 'Criteria' must exist
+                if( const DefinedName* pCriteriaName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_CRITERIA, nSheet ).get() )
+                {
+                    CellRangeAddress aCriteriaRange;
+                    if( pCriteriaName->getAbsoluteRange( aCriteriaRange ) )
+                    {
+                        // set some common properties for the filter descriptor
+                        PropertySet aDescProps( xDatabaseRange->getFilterDescriptor() );
+                        aDescProps.setProperty( PROP_IsCaseSensitive, false );
+                        aDescProps.setProperty( PROP_SkipDuplicates, false );
+                        aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
+                        aDescProps.setProperty( PROP_ContainsHeader, true );
+                        // criteria range may contain wildcards, but these are incompatible with REs
+                        aDescProps.setProperty( PROP_UseRegularExpressions, false );
+
+                        // position of output data (if built-in defined name 'Extract' exists)
+                        DefinedNameRef xExtractName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_EXTRACT, nSheet );
+                        CellRangeAddress aOutputRange;
+                        bool bHasOutputRange = xExtractName.get() && xExtractName->getAbsoluteRange( aOutputRange );
+                        aDescProps.setProperty( PROP_CopyOutputData, bHasOutputRange );
+                        if( bHasOutputRange )
+                        {
+                            aDescProps.setProperty( PROP_SaveOutputPosition, true );
+                            aDescProps.setProperty( PROP_OutputPosition, CellAddress( aOutputRange.Sheet, aOutputRange.StartColumn, aOutputRange.StartRow ) );
+                        }
+
+                        /*  Properties of the database range (must be set after
+                            modifying properties of the filter descriptor,
+                            otherwise the 'FilterCriteriaSource' property gets
+                            deleted). */
+                        PropertySet aRangeProps( xDatabaseRange );
+                        aRangeProps.setProperty( PROP_AutoFilter, false );
+                        aRangeProps.setProperty( PROP_FilterCriteriaSource, aCriteriaRange );
+                    }
+                }
+            }
+        }
+    }
+}
+
+bool AutoFilterBuffer::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRange )
+{
+    AutoFilter* pAutoFilter = getActiveAutoFilter();
+    if( pAutoFilter && rxDatabaseRange.is() ) try
+    {
+        // the property 'AutoFilter' enables the drop-down buttons
+        PropertySet aRangeProps( rxDatabaseRange );
+        aRangeProps.setProperty( PROP_AutoFilter, true );
+        // convert filter settings using the filter descriptor of the database range
+        Reference< XSheetFilterDescriptor3 > xFilterDesc( rxDatabaseRange->getFilterDescriptor(), UNO_QUERY_THROW );
+        pAutoFilter->finalizeImport( xFilterDesc );
+        // return true to indicate enabled autofilter
+        return true;
+    }
+    catch( Exception& )
+    {
+    }
+    return false;
+}
+
+AutoFilter* AutoFilterBuffer::getActiveAutoFilter()
+{
+    // Excel expects not more than one auto filter per sheet or table
+    OSL_ENSURE( maAutoFilters.size() <= 1, "AutoFilterBuffer::getActiveAutoFilter - too many auto filters" );
+    // stick to the last imported auto filter
+    return maAutoFilters.empty() ? 0 : maAutoFilters.back().get();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/autofiltercontext.cxx b/sc/source/filter/oox/autofiltercontext.cxx
new file mode 100644
index 000000000000..c58cb4d80f18
--- /dev/null
+++ b/sc/source/filter/oox/autofiltercontext.cxx
@@ -0,0 +1,186 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "autofiltercontext.hxx"
+
+#include "autofilterbuffer.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+using ::oox::core::ContextHandlerRef;
+using ::rtl::OUString;
+
+// ============================================================================
+
+FilterSettingsContext::FilterSettingsContext( WorksheetContextBase& rParent, FilterSettingsBase& rFilterSettings ) :
+    WorksheetContextBase( rParent ),
+    mrFilterSettings( rFilterSettings )
+{
+}
+
+ContextHandlerRef FilterSettingsContext::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
+{
+    switch( getCurrentElement() )
+    {
+        case XLS_TOKEN( filters ):
+            if( nElement == XLS_TOKEN( filter ) ) return this;
+        break;
+        case XLS_TOKEN( customFilters ):
+            if( nElement == XLS_TOKEN( customFilter ) ) return this;
+        break;
+    }
+    return 0;
+}
+
+void FilterSettingsContext::onStartElement( const AttributeList& rAttribs )
+{
+    mrFilterSettings.importAttribs( getCurrentElement(), rAttribs );
+}
+
+ContextHandlerRef FilterSettingsContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& /*rStrm*/ )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_DISCRETEFILTERS:
+            if( nRecId == BIFF12_ID_DISCRETEFILTER ) return this;
+        break;
+        case BIFF12_ID_CUSTOMFILTERS:
+            if( nRecId == BIFF12_ID_CUSTOMFILTER ) return this;
+        break;
+    }
+    return 0;
+}
+
+void FilterSettingsContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    mrFilterSettings.importRecord( getCurrentElement(), rStrm );
+}
+
+// ============================================================================
+
+FilterColumnContext::FilterColumnContext( WorksheetContextBase& rParent, FilterColumn& rFilterColumn ) :
+    WorksheetContextBase( rParent ),
+    mrFilterColumn( rFilterColumn )
+{
+}
+
+ContextHandlerRef FilterColumnContext::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
+{
+    if( getCurrentElement() == XLS_TOKEN( filterColumn ) ) switch( nElement )
+    {
+        case XLS_TOKEN( filters ):
+            return new FilterSettingsContext( *this, mrFilterColumn.createFilterSettings< DiscreteFilter >() );
+        case XLS_TOKEN( top10 ):
+            return new FilterSettingsContext( *this, mrFilterColumn.createFilterSettings< Top10Filter >() );
+        case XLS_TOKEN( customFilters ):
+            return new FilterSettingsContext( *this, mrFilterColumn.createFilterSettings< CustomFilter >() );
+    }
+    return 0;
+}
+
+void FilterColumnContext::onStartElement( const AttributeList& rAttribs )
+{
+    mrFilterColumn.importFilterColumn( rAttribs );
+}
+
+ContextHandlerRef FilterColumnContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& /*rStrm*/ )
+{
+    if( getCurrentElement() == BIFF12_ID_FILTERCOLUMN ) switch( nRecId )
+    {
+        case BIFF12_ID_DISCRETEFILTERS:
+            return new FilterSettingsContext( *this, mrFilterColumn.createFilterSettings< DiscreteFilter >() );
+        case BIFF12_ID_TOP10FILTER:
+            return new FilterSettingsContext( *this, mrFilterColumn.createFilterSettings< Top10Filter >() );
+        case BIFF12_ID_CUSTOMFILTERS:
+            return new FilterSettingsContext( *this, mrFilterColumn.createFilterSettings< CustomFilter >() );
+    }
+    return 0;
+}
+
+void FilterColumnContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    mrFilterColumn.importFilterColumn( rStrm );
+}
+
+// ============================================================================
+
+AutoFilterContext::AutoFilterContext( WorksheetFragmentBase& rFragment, AutoFilter& rAutoFilter ) :
+    WorksheetContextBase( rFragment ),
+    mrAutoFilter( rAutoFilter )
+{
+}
+
+ContextHandlerRef AutoFilterContext::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
+{
+    if( (getCurrentElement() == XLS_TOKEN( autoFilter )) && (nElement == XLS_TOKEN( filterColumn )) )
+        return new FilterColumnContext( *this, mrAutoFilter.createFilterColumn() );
+    return 0;
+}
+
+void AutoFilterContext::onStartElement( const AttributeList& rAttribs )
+{
+    mrAutoFilter.importAutoFilter( rAttribs, getSheetIndex() );
+}
+
+ContextHandlerRef AutoFilterContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& /*rStrm*/ )
+{
+    if( (getCurrentElement() == BIFF12_ID_AUTOFILTER) && (nRecId == BIFF12_ID_FILTERCOLUMN) )
+        return new FilterColumnContext( *this, mrAutoFilter.createFilterColumn() );
+    return 0;
+}
+
+void AutoFilterContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    mrAutoFilter.importAutoFilter( rStrm, getSheetIndex() );
+}
+
+// ============================================================================
+
+BiffAutoFilterContext::BiffAutoFilterContext( const WorksheetHelper& rHelper, AutoFilter& rAutoFilter ) :
+    BiffWorksheetContextBase( rHelper ),
+    mrAutoFilter( rAutoFilter )
+{
+}
+
+void BiffAutoFilterContext::importRecord( BiffInputStream& rStrm )
+{
+    switch( rStrm.getRecId() )
+    {
+        // nothing to read for BIFF_ID_AUTOFILTER
+        case BIFF_ID_FILTERCOLUMN:  mrAutoFilter.createFilterColumn().importFilterColumn( rStrm );  break;
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/biffcodec.cxx b/sc/source/filter/oox/biffcodec.cxx
new file mode 100644
index 000000000000..5d791cdc911f
--- /dev/null
+++ b/sc/source/filter/oox/biffcodec.cxx
@@ -0,0 +1,382 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "biffcodec.hxx"
+
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::FilterBase;
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OStringToOUString;
+
+// ============================================================================
+
+BiffDecoderBase::BiffDecoderBase() :
+    mbValid( false )
+{
+}
+
+BiffDecoderBase::~BiffDecoderBase()
+{
+}
+
+::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData )
+{
+    o_rEncryptionData = implVerifyPassword( rPassword );
+    mbValid = o_rEncryptionData.hasElements();
+    return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+}
+
+::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
+{
+    mbValid = implVerifyEncryptionData( rEncryptionData );
+    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 ),
+    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 ),
+    maEncryptionData( rDecoder.maEncryptionData ),
+    mnKey( rDecoder.mnKey ),
+    mnHash( rDecoder.mnHash )
+{
+    if( isValid() )
+        maCodec.initCodec( maEncryptionData );
+}
+
+BiffDecoder_XOR* BiffDecoder_XOR::implClone()
+{
+    return new BiffDecoder_XOR( *this );
+}
+
+Sequence< NamedValue > BiffDecoder_XOR::implVerifyPassword( const OUString& rPassword )
+{
+    maEncryptionData.realloc( 0 );
+
+    /*  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) )
+    {
+        // init codec
+        maCodec.initKey( reinterpret_cast< const sal_uInt8* >( aBytePassword.getStr() ) );
+
+        if( maCodec.verifyKey( mnKey, mnHash ) )
+            maEncryptionData = maCodec.getEncryptionData();
+    }
+
+    return maEncryptionData;
+}
+
+bool BiffDecoder_XOR::implVerifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
+{
+    maEncryptionData.realloc( 0 );
+
+    if( rEncryptionData.hasElements() )
+    {
+        // init codec
+        maCodec.initCodec( rEncryptionData );
+
+        if( maCodec.verifyKey( mnKey, mnHash ) )
+            maEncryptionData = rEncryptionData;
+    }
+
+    return maEncryptionData.hasElements();
+}
+
+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 ] ) :
+    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
+    maEncryptionData( rDecoder.maEncryptionData ),
+    maSalt( rDecoder.maSalt ),
+    maVerifier( rDecoder.maVerifier ),
+    maVerifierHash( rDecoder.maVerifierHash )
+{
+    if( isValid() )
+        maCodec.initCodec( maEncryptionData );
+}
+
+BiffDecoder_RCF* BiffDecoder_RCF::implClone()
+{
+    return new BiffDecoder_RCF( *this );
+}
+
+Sequence< NamedValue > BiffDecoder_RCF::implVerifyPassword( const OUString& rPassword )
+{
+    maEncryptionData.realloc( 0 );
+
+    sal_Int32 nLen = rPassword.getLength();
+    if( (0 < nLen) && (nLen < 16) )
+    {
+        // copy string to sal_uInt16 array
+        ::std::vector< sal_uInt16 > aPassVect( 16 );
+        const sal_Unicode* pcChar = rPassword.getStr();
+        const sal_Unicode* pcCharEnd = pcChar + nLen;
+        ::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin();
+        for( ; pcChar < pcCharEnd; ++pcChar, ++aIt )
+            *aIt = static_cast< sal_uInt16 >( *pcChar );
+
+        // init codec
+        maCodec.initKey( &aPassVect.front(), &maSalt.front() );
+        if( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
+            maEncryptionData = maCodec.getEncryptionData();
+    }
+
+    return maEncryptionData;
+}
+
+bool BiffDecoder_RCF::implVerifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
+{
+    maEncryptionData.realloc( 0 );
+
+    if( rEncryptionData.hasElements() )
+    {
+        // init codec
+        maCodec.initCodec( rEncryptionData );
+
+        if( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
+            maEncryptionData = rEncryptionData;
+    }
+
+    return maEncryptionData.hasElements();
+}
+
+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_FAIL( "lclReadFilePassBiff8 - unknown BIFF8 encryption sub mode" );
+            }
+        }
+        break;
+
+        default:
+            OSL_FAIL( "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().requestEncryptionData( *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/sc/source/filter/oox/biffdetector.cxx b/sc/source/filter/oox/biffdetector.cxx
new file mode 100644
index 000000000000..5c5a2c26ef41
--- /dev/null
+++ b/sc/source/filter/oox/biffdetector.cxx
@@ -0,0 +1,232 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "biffdetector.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/ole/olestorage.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+using ::comphelper::MediaDescriptor;
+using ::rtl::OStringBuffer;
+using ::rtl::OUString;
+
+// ============================================================================
+
+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.xls.BiffDetector" );
+}
+
+Reference< XInterface > SAL_CALL BiffDetector_createInstance( const Reference< XComponentContext >& rxContext ) throw( Exception )
+{
+    return static_cast< ::cppu::OWeakObject* >( new BiffDetector( rxContext ) );
+}
+
+// ============================================================================
+
+BiffDetector::BiffDetector( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
+    mxContext( rxContext, UNO_SET_THROW )
+{
+}
+
+BiffDetector::~BiffDetector()
+{
+}
+
+/*static*/ BiffType BiffDetector::detectStreamBiffVersion( BinaryInputStream& rInStream )
+{
+    BiffType eBiff = BIFF_UNKNOWN;
+    if( !rInStream.isEof() && rInStream.isSeekable() && (rInStream.size() > 4) )
+    {
+        sal_Int64 nOldPos = rInStream.tell();
+        rInStream.seekToStart();
+        sal_uInt16 nBofId, nBofSize;
+        rInStream >> nBofId >> nBofSize;
+
+        if( (4 <= nBofSize) && (nBofSize <= 16) && (rInStream.tell() + nBofSize <= rInStream.size()) )
+        {
+            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_FAIL( 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;
+}
+
+/*static*/ BiffType BiffDetector::detectStorageBiffVersion( OUString& orWorkbookStreamName, const StorageRef& rxStorage )
+{
+    static const OUString saBookName = CREATE_OUSTRING( "Book" );
+    static const OUString saWorkbookName = CREATE_OUSTRING( "Workbook" );
+
+    BiffType eBiff = BIFF_UNKNOWN;
+    if( rxStorage.get() )
+    {
+        if( rxStorage->isStorage() )
+        {
+            // try to open the "Book" stream
+            BinaryXInputStream aBookStrm5( rxStorage->openInputStream( saBookName ), true );
+            BiffType eBookStrm5Biff = detectStreamBiffVersion( aBookStrm5 );
+
+            // try to open the "Workbook" stream
+            BinaryXInputStream aBookStrm8( rxStorage->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( rxStorage->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_THROW );
+    StorageRef xStorage( new ::oox::ole::OleStorage( mxContext, xInStrm, true ) );
+
+    OUString aWorkbookName;
+    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/sc/source/filter/oox/biffhelper.cxx b/sc/source/filter/oox/biffhelper.cxx
new file mode 100644
index 000000000000..d71249d76629
--- /dev/null
+++ b/sc/source/filter/oox/biffhelper.cxx
@@ -0,0 +1,334 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "biffhelper.hxx"
+
+#include 
+#include 
+#include "biffinputstream.hxx"
+#include "biffoutputstream.hxx"
+#include "worksheethelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+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
+
+// ============================================================================
+
+// conversion -----------------------------------------------------------------
+
+/*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_FAIL( "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 );
+}
+
+// BIFF12 import --------------------------------------------------------------
+
+/*static*/ OUString BiffHelper::readString( SequenceInputStream& rStrm, bool b32BitLen, bool bAllowNulChars )
+{
+    OUString aString;
+    if( !rStrm.isEof() )
+    {
+        sal_Int32 nCharCount = b32BitLen ? rStrm.readValue< sal_Int32 >() : rStrm.readValue< sal_Int16 >();
+        // string length -1 is often used to indicate a missing string
+        OSL_ENSURE( !rStrm.isEof() && (nCharCount >= -1), "BiffHelper::readString - invalid string length" );
+        if( !rStrm.isEof() && (nCharCount > 0) )
+        {
+            // SequenceInputStream always supports getRemaining()
+            nCharCount = ::std::min( nCharCount, static_cast< sal_Int32 >( rStrm.getRemaining() / 2 ) );
+            aString = rStrm.readUnicodeArray( nCharCount, bAllowNulChars );
+        }
+    }
+    return aString;
+}
+
+// BIFF2-BIFF8 import ---------------------------------------------------------
+
+/*static*/ bool BiffHelper::isBofRecord( BiffInputStream& rStrm )
+{
+    return
+        (rStrm.getRecId() == BIFF2_ID_BOF) ||
+        (rStrm.getRecId() == BIFF3_ID_BOF) ||
+        (rStrm.getRecId() == BIFF4_ID_BOF) ||
+        (rStrm.getRecId() == BIFF5_ID_BOF);
+}
+
+/*static*/ bool BiffHelper::skipRecordBlock( BiffInputStream& rStrm, sal_uInt16 nEndRecId )
+{
+    sal_uInt16 nStartRecId = rStrm.getRecId();
+    while( rStrm.startNextRecord() && (rStrm.getRecId() != nEndRecId) )
+        if( rStrm.getRecId() == nStartRecId )
+            skipRecordBlock( rStrm, nEndRecId );
+    return !rStrm.isEof() && (rStrm.getRecId() == nEndRecId);
+}
+
+/*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_FAIL( "BiffHelper::importImgData - unknown image format" );
+        }
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/biffinputstream.cxx b/sc/source/filter/oox/biffinputstream.cxx
new file mode 100644
index 000000000000..71641f51ba2d
--- /dev/null
+++ b/sc/source/filter/oox/biffinputstream.cxx
@@ -0,0 +1,555 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "biffinputstream.hxx"
+
+#include 
+#include 
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using ::rtl::OString;
+using ::rtl::OStringToOUString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+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.size());
+    if( mbValidHeader )
+    {
+        mnHeaderPos = nHeaderPos;
+        mrInStrm.seek( nHeaderPos );
+        mrInStrm >> mnRecId >> mnRecSize;
+        mnBodyPos = mrInStrm.tell();
+        mnNextHeaderPos = mnBodyPos + mnRecSize;
+        mbValidHeader = !mrInStrm.isEof() && (mnNextHeaderPos <= mrInStrm.size());
+    }
+    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.size()) )
+    {
+        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 ) :
+    BinaryStreamBase( true ),
+    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) ---------------------------------------
+
+sal_Int64 BiffInputStream::size() const
+{
+    if( !mbHasComplRec )
+        const_cast< BiffInputStream* >( this )->calcRecordLength();
+    return mnComplRecSize;
+}
+
+sal_Int64 BiffInputStream::tell() const
+{
+    return mbEof ? -1 : (mnCurrRecSize - maRecBuffer.getRecLeft());
+}
+
+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() ) );
+    }
+}
+
+void BiffInputStream::close()
+{
+}
+
+sal_Int64 BiffInputStream::tellBase() const
+{
+    return maRecBuffer.getBaseStream().tell();
+}
+
+// BinaryInputStream interface (stream read access) ---------------------------
+
+sal_Int32 BiffInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
+{
+    sal_Int32 nRet = 0;
+    if( !mbEof )
+    {
+        orData.realloc( ::std::max< sal_Int32 >( nBytes, 0 ) );
+        if( nBytes > 0 )
+            nRet = readMemory( orData.getArray(), nBytes, nAtomSize );
+    }
+    return nRet;
+}
+
+sal_Int32 BiffInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
+{
+    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, nAtomSize );
+            // 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, size_t nAtomSize )
+{
+    sal_Int32 nBytesLeft = nBytes;
+    while( !mbEof && (nBytesLeft > 0) )
+    {
+        sal_uInt16 nSkipSize = getMaxRawReadSize( nBytesLeft, nAtomSize );
+        // 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 );
+}
+
+// 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 which repeat the flags
+        field in their first byte and may change the 8bit/16bit character mode,
+        thus a plain call to readCompressedUnicodeArray() cannot be used here. */
+    sal_Int32 nCharsLeft = nChars;
+    while( !mbEof && (nCharsLeft > 0) )
+    {
+        /*  Read the character array from the remaining part of the current raw
+            record. First, calculate the maximum number of characters that can
+            be read without triggering to start a following CONTINUE record. */
+        sal_Int32 nRawChars = b16BitChars ? (getMaxRawReadSize( nCharsLeft * 2, 2 ) / 2) : getMaxRawReadSize( nCharsLeft, 1 );
+        aBuffer.append( readCompressedUnicodeArray( nRawChars, !b16BitChars, bAllowNulChars ) );
+
+        /*  Prepare for next CONTINUE record. Calling jumpToNextStringContinue()
+            reads the leading byte in the following CONTINUE record and updates
+            the b16BitChars flag. */
+        nCharsLeft -= nRawChars;
+        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 );
+}
+
+// private --------------------------------------------------------------------
+
+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 - alignment error" );
+
+    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
+}
+
+sal_uInt16 BiffInputStream::getMaxRawReadSize( sal_Int32 nBytes, size_t nAtomSize ) const
+{
+    sal_uInt16 nMaxSize = getLimitedValue< sal_uInt16, sal_Int32 >( nBytes, 0, maRecBuffer.getRecLeft() );
+    if( (0 < nMaxSize) && (nMaxSize < nBytes) && (nAtomSize > 1) )
+    {
+        // check that remaining data in record buffer is a multiple of the passed atom size
+        sal_uInt16 nPadding = static_cast< sal_uInt16 >( nMaxSize % nAtomSize );
+        OSL_ENSURE( nPadding == 0, "BiffInputStream::getMaxRawReadSize - alignment error" );
+        nMaxSize = nMaxSize - nPadding;
+    }
+    return nMaxSize;
+}
+
+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/sc/source/filter/oox/biffoutputstream.cxx b/sc/source/filter/oox/biffoutputstream.cxx
new file mode 100644
index 000000000000..88bded6e3be4
--- /dev/null
+++ b/sc/source/filter/oox/biffoutputstream.cxx
@@ -0,0 +1,212 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "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 ) :
+    BinaryStreamBase( true ),
+    maRecBuffer( rOutStream, nMaxRecSize ),
+    mnPortionSize( 0 ),
+    mnPortionPos( 0 )
+{
+}
+
+// record control -------------------------------------------------------------
+
+void BiffOutputStream::startRecord( sal_uInt16 nRecId )
+{
+    maRecBuffer.startRecord( nRecId );
+    setPortionSize( 1 );
+}
+
+void BiffOutputStream::endRecord()
+{
+    setPortionSize( 1 );
+    maRecBuffer.endRecord();
+}
+
+void BiffOutputStream::setPortionSize( sal_uInt8 nSize )
+{
+    OSL_ENSURE( mnPortionPos == 0, "BiffOutputStream::setPortionSize - block operation inside portion" );
+    mnPortionSize = ::std::max< sal_uInt8 >( nSize, 1 );
+    mnPortionPos = 0;
+}
+
+// BinaryStreamBase interface (seeking) ---------------------------------------
+
+sal_Int64 BiffOutputStream::tellBase() const
+{
+    return maRecBuffer.getBaseStream().tell();
+}
+
+sal_Int64 BiffOutputStream::sizeBase() const
+{
+    return maRecBuffer.getBaseStream().size();
+}
+
+// BinaryOutputStream interface (stream write access) -------------------------
+
+void BiffOutputStream::writeData( const StreamDataSequence& rData, size_t nAtomSize )
+{
+    if( rData.hasElements() )
+        writeMemory( rData.getConstArray(), rData.getLength(), nAtomSize );
+}
+
+void BiffOutputStream::writeMemory( const void* pMem, sal_Int32 nBytes, size_t nAtomSize )
+{
+    if( pMem && (nBytes > 0) )
+    {
+        const sal_uInt8* pnBuffer = reinterpret_cast< const sal_uInt8* >( pMem );
+        sal_Int32 nBytesLeft = nBytes;
+        while( nBytesLeft > 0 )
+        {
+            sal_uInt16 nBlockSize = prepareWriteBlock( nBytesLeft, nAtomSize );
+            maRecBuffer.write( pnBuffer, nBlockSize );
+            pnBuffer += nBlockSize;
+            nBytesLeft -= nBlockSize;
+        }
+    }
+}
+
+void BiffOutputStream::fill( sal_uInt8 nValue, sal_Int32 nBytes, size_t nAtomSize )
+{
+    sal_Int32 nBytesLeft = nBytes;
+    while( nBytesLeft > 0 )
+    {
+        sal_uInt16 nBlockSize = prepareWriteBlock( nBytesLeft, nAtomSize );
+        maRecBuffer.fill( nValue, nBlockSize );
+        nBytesLeft -= nBlockSize;
+    }
+}
+
+// private --------------------------------------------------------------------
+
+sal_uInt16 BiffOutputStream::prepareWriteBlock( sal_Int32 nTotalSize, size_t nAtomSize )
+{
+    sal_uInt16 nRecLeft = maRecBuffer.getRecLeft();
+    if( mnPortionSize <= 1 )
+    {
+        // no portions: restrict remaining record size to entire atoms
+        nRecLeft = static_cast< sal_uInt16 >( (nRecLeft / nAtomSize) * nAtomSize );
+    }
+    else
+    {
+        sal_Int32 nPortionLeft = mnPortionSize - mnPortionPos;
+        if( nTotalSize <= nPortionLeft )
+        {
+            // block fits into the current portion
+            OSL_ENSURE( nPortionLeft <= nRecLeft, "BiffOutputStream::prepareWriteBlock - portion exceeds record" );
+            mnPortionPos = static_cast< sal_uInt8 >( (mnPortionPos + nTotalSize) % mnPortionSize );
+        }
+        else
+        {
+            // restrict remaining record size to entire portions
+            OSL_ENSURE( mnPortionPos == 0, "BiffOutputStream::prepareWriteBlock - writing over multiple portions starts inside portion" );
+            mnPortionPos = 0;
+            // check that atom size matches portion size
+            OSL_ENSURE( mnPortionSize % nAtomSize == 0, "BiffOutputStream::prepareWriteBlock - atom size does not match portion size" );
+            sal_uInt8 nPortionSize = static_cast< sal_uInt8 >( (mnPortionSize / nAtomSize) * nAtomSize );
+            // restrict remaining record size to entire portions
+            nRecLeft = (nRecLeft / nPortionSize) * nPortionSize;
+        }
+    }
+
+    // current record has space for some data: return size of available space
+    if( nRecLeft > 0 )
+        return getLimitedValue< sal_uInt16, sal_Int32 >( nTotalSize, 0, nRecLeft );
+
+    // finish current record and start a new CONTINUE record
+    maRecBuffer.endRecord();
+    maRecBuffer.startRecord( BIFF_ID_CONT );
+    mnPortionPos = 0;
+    return prepareWriteBlock( nTotalSize, nAtomSize );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/chartsheetfragment.cxx b/sc/source/filter/oox/chartsheetfragment.cxx
new file mode 100644
index 000000000000..e6e0f0b427ac
--- /dev/null
+++ b/sc/source/filter/oox/chartsheetfragment.cxx
@@ -0,0 +1,292 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "chartsheetfragment.hxx"
+
+#include "oox/helper/attributelist.hxx"
+#include "biffinputstream.hxx"
+#include "pagesettings.hxx"
+#include "viewsettings.hxx"
+#include "workbooksettings.hxx"
+#include "worksheetsettings.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+ChartsheetFragment::ChartsheetFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    WorksheetFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+ContextHandlerRef ChartsheetFragment::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 onCharacters()
+            }
+        break;
+    }
+    return 0;
+}
+
+void ChartsheetFragment::onCharacters( 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 ChartsheetFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_WORKSHEET ) return this;
+        break;
+
+        case BIFF12_ID_WORKSHEET:
+            switch( nRecId )
+            {
+                case BIFF12_ID_CHARTSHEETVIEWS:  return this;
+
+                case BIFF12_ID_CHARTSHEETPR:    getWorksheetSettings().importChartSheetPr( rStrm );                 break;
+                case BIFF12_ID_CHARTPROTECTION: getWorksheetSettings().importChartProtection( rStrm );              break;
+                case BIFF12_ID_PAGEMARGINS:     getPageSettings().importPageMargins( rStrm );                       break;
+                case BIFF12_ID_CHARTPAGESETUP:  getPageSettings().importChartPageSetup( getRelations(), rStrm );    break;
+                case BIFF12_ID_HEADERFOOTER:    getPageSettings().importHeaderFooter( rStrm );                      break;
+                case BIFF12_ID_PICTURE:         getPageSettings().importPicture( getRelations(), rStrm );           break;
+                case BIFF12_ID_DRAWING:         importDrawing( rStrm );                                             break;
+            }
+        break;
+
+        case BIFF12_ID_CHARTSHEETVIEWS:
+            if( nRecId == BIFF12_ID_CHARTSHEETVIEW ) getSheetViewSettings().importChartSheetView( rStrm );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* ChartsheetFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_CHARTSHEETVIEW,     BIFF12_ID_CHARTSHEETVIEW + 1    },
+        { BIFF12_ID_CHARTSHEETVIEWS,    BIFF12_ID_CHARTSHEETVIEWS + 1   },
+        { BIFF12_ID_CUSTOMCHARTVIEW,    BIFF12_ID_CUSTOMCHARTVIEW + 1   },
+        { BIFF12_ID_CUSTOMCHARTVIEWS,   BIFF12_ID_CUSTOMCHARTVIEWS + 1  },
+        { BIFF12_ID_HEADERFOOTER,       BIFF12_ID_HEADERFOOTER + 1      },
+        { BIFF12_ID_WORKSHEET,          BIFF12_ID_WORKSHEET + 1         },
+        { -1,                           -1                              }
+    };
+    return spRecInfos;
+}
+
+void ChartsheetFragment::initializeImport()
+{
+    // initial processing in base class WorksheetHelper
+    initializeWorksheetImport();
+}
+
+void ChartsheetFragment::finalizeImport()
+{
+    // final processing in base class WorksheetHelper
+    finalizeWorksheetImport();
+}
+
+// private --------------------------------------------------------------------
+
+void ChartsheetFragment::importDrawing( const AttributeList& rAttribs )
+{
+    setDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
+}
+
+void ChartsheetFragment::importDrawing( SequenceInputStream& rStrm )
+{
+    setDrawingPath( getFragmentPathFromRelId( BiffHelper::readString( rStrm ) ) );
+}
+
+// ============================================================================
+
+BiffChartsheetFragment::BiffChartsheetFragment( const WorksheetHelper& rHelper, const BiffWorkbookFragmentBase& rParent ) :
+    BiffWorksheetFragmentBase( rHelper, rParent )
+{
+}
+
+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
+    BiffInputStream& rStrm = getInputStream();
+    while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+    {
+        if( BiffHelper::isBofRecord( rStrm ) )
+        {
+            // skip unknown embedded fragments (BOF/EOF blocks)
+            skipFragment();
+        }
+        else
+        {
+            sal_uInt16 nRecId = rStrm.getRecId();
+            switch( nRecId )
+            {
+                // records in all BIFF versions
+                case BIFF_ID_BOTTOMMARGIN:  rPageSett.importBottomMargin( rStrm );                  break;
+                case BIFF_ID_CHBEGIN:       BiffHelper::skipRecordBlock( rStrm, BIFF_ID_CHEND );    break;
+                case BIFF_ID_FOOTER:        rPageSett.importFooter( rStrm );                        break;
+                case BIFF_ID_HEADER:        rPageSett.importHeader( rStrm );                        break;
+                case BIFF_ID_LEFTMARGIN:    rPageSett.importLeftMargin( rStrm );                    break;
+                case BIFF_ID_PASSWORD:      rWorksheetSett.importPassword( rStrm );                 break;
+                case BIFF_ID_PROTECT:       rWorksheetSett.importProtect( rStrm );                  break;
+                case BIFF_ID_RIGHTMARGIN:   rPageSett.importRightMargin( rStrm );                   break;
+                case BIFF_ID_TOPMARGIN:     rPageSett.importTopMargin( rStrm );                     break;
+
+                // BIFF specific records
+                default: switch( getBiff() )
+                {
+                    case BIFF2: switch( nRecId )
+                    {
+                        case BIFF2_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
+                    }
+                    break;
+
+                    case BIFF3: switch( nRecId )
+                    {
+                        case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
+                        case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
+                        case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
+                        case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
+
+                    }
+                    break;
+
+                    case BIFF4: switch( nRecId )
+                    {
+                        case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
+                        case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
+                        case BIFF_ID_PAGESETUP:     rPageSett.importPageSetup( rStrm );             break;
+                        case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
+                        case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
+                    }
+                    break;
+
+                    case BIFF5: switch( nRecId )
+                    {
+                        case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
+                        case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
+                        case BIFF_ID_PAGESETUP:     rPageSett.importPageSetup( rStrm );             break;
+                        case BIFF_ID_SCENPROTECT:   rWorksheetSett.importScenProtect( rStrm );      break;
+                        case BIFF_ID_SCL:           rSheetViewSett.importScl( rStrm );              break;
+                        case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
+                        case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
+                    }
+                    break;
+
+                    case BIFF8: switch( nRecId )
+                    {
+                        case BIFF_ID_CODENAME:      rWorksheetSett.importCodeName( rStrm );         break;
+                        case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
+                        case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
+                        case BIFF_ID_PICTURE:       rPageSett.importPicture( rStrm );               break;
+                        case BIFF_ID_PAGESETUP:     rPageSett.importPageSetup( rStrm );             break;
+                        case BIFF_ID_SCL:           rSheetViewSett.importScl( rStrm );              break;
+                        case BIFF_ID_SHEETEXT:      rWorksheetSett.importSheetExt( rStrm );         break;
+                        case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
+                        case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
+                    }
+                    break;
+
+                    case BIFF_UNKNOWN: break;
+                }
+            }
+        }
+    }
+
+    // final processing in base class WorksheetHelper
+    finalizeWorksheetImport();
+    return rStrm.getRecId() == BIFF_ID_EOF;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/commentsbuffer.cxx b/sc/source/filter/oox/commentsbuffer.cxx
new file mode 100644
index 000000000000..a1bef7dfa5c5
--- /dev/null
+++ b/sc/source/filter/oox/commentsbuffer.cxx
@@ -0,0 +1,325 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include 
+#include 
+
+#include "commentsbuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/vml/vmlshape.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "drawingfragment.hxx"
+#include "svx/sdtaitm.hxx"
+#include "unitconverter.hxx"
+#include "drawingmanager.hxx"
+
+#include 
+#include 
+
+using ::com::sun::star::text::XText;
+using ::com::sun::star::text::XTextRange;
+using ::com::sun::star::awt::Size;
+using ::com::sun::star::awt::Point;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+
+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;
+    }
+}
+
+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;
+    }
+}
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF_NOTE_VISIBLE          = 0x0002;
+
+} // namespace
+
+// ============================================================================
+
+CommentModel::CommentModel() :
+    mnAuthorId( -1 ),
+    mnObjId( BIFF_OBJ_INVALID_ID ),
+    mbVisible( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+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::importComment( SequenceInputStream& 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() );
+}
+
+void Comment::importNote( BiffInputStream& rStrm )
+{
+    BinAddress aBinAddr;
+    rStrm >> aBinAddr;
+    // cell range will be checked while inserting the comment into the document
+    getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, BinRange( aBinAddr ), getSheetIndex() );
+
+    // remaining record data is BIFF dependent
+    switch( getBiff() )
+    {
+        case BIFF2:
+        case BIFF3:
+            importNoteBiff2( rStrm );
+        break;
+        case BIFF4:
+        case BIFF5:
+            importNoteBiff2( rStrm );
+            // in BIFF4 and BIFF5, comments can have an associated sound
+            if( (rStrm.getNextRecId() == BIFF_ID_NOTESOUND) && rStrm.startNextRecord() )
+                importNoteSound( rStrm );
+        break;
+        case BIFF8:
+            importNoteBiff8( rStrm );
+        break;
+        case BIFF_UNKNOWN:
+        break;
+    }
+}
+
+RichStringRef Comment::createText()
+{
+    maModel.mxText.reset( new RichString( *this ) );
+    return maModel.mxText;
+}
+
+void Comment::finalizeImport()
+{
+    // BIFF12 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
+    {
+        Reference< XSheetAnnotationsSupplier > xAnnosSupp( getSheet(), UNO_QUERY_THROW );
+        Reference< XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), UNO_SET_THROW );
+        // non-empty string required by note implementation (real text will be added below)
+        xAnnos->insertNew( aNotePos, OUString( sal_Unicode( ' ' ) ) );
+
+        // receive created 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 );
+
+        // convert shape formatting and visibility
+        sal_Bool bVisible = sal_True;
+        switch( getFilterType() )
+        {
+            case FILTER_OOXML:
+                {
+                    // 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::ClientData* pClientData = pNoteShape->getClientData();
+                        xAnno->setIsVisible( pClientData && pClientData->mbVisible );
+                    }
+                }
+            break;
+            case FILTER_BIFF:
+                bVisible = maModel.mbVisible;
+            break;
+            case FILTER_UNKNOWN:
+            break;
+        }
+        xAnno->setIsVisible( bVisible );
+
+        // insert text and convert text formatting
+        maModel.mxText->finalizeImport();
+        Reference< XText > xAnnoText( xAnnoShape, UNO_QUERY_THROW );
+        maModel.mxText->convert( xAnnoText, true );
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+// private --------------------------------------------------------------------
+
+void Comment::importNoteBiff2( BiffInputStream& rStrm )
+{
+    sal_uInt16 nTotalLen;
+    rStrm >> nTotalLen;
+    sal_uInt16 nPartLen = ::std::min( nTotalLen, static_cast< sal_uInt16 >( rStrm.getRemaining() ) );
+    RichStringRef xNoteText = createText();
+    xNoteText->importCharArray( rStrm, nPartLen, getTextEncoding() );
+
+    nTotalLen = nTotalLen - nPartLen;   // operator-=() gives compiler warning
+    while( (nTotalLen > 0) && (rStrm.getNextRecId() == BIFF_ID_NOTE) && rStrm.startNextRecord() )
+    {
+        sal_uInt16 nMarker;
+        rStrm >> nMarker;
+        rStrm.skip( 2 );
+        rStrm >> nPartLen;
+        OSL_ENSURE( nMarker == 0xFFFF, "Comment::importNoteBiff2 - missing continuation NOTE record" );
+        if( nMarker == 0xFFFF )
+        {
+            OSL_ENSURE( nPartLen <= nTotalLen, "Comment::importNoteBiff2 - string too long" );
+            // call to RichString::importCharArray() appends new text portion
+            xNoteText->importCharArray( rStrm, nPartLen, getTextEncoding() );
+            nTotalLen = nTotalLen - ::std::min( nTotalLen, nPartLen );
+        }
+        else
+        {
+            // seems to be a new note, rewind record, so worksheet fragment loop will find it
+            rStrm.rewindRecord();
+            nTotalLen = 0;
+        }
+    }
+}
+
+void Comment::importNoteBiff8( BiffInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    rStrm >> nFlags >> maModel.mnObjId;
+    maModel.maAuthor = rStrm.readUniString();
+    maModel.mbVisible = getFlag( nFlags, BIFF_NOTE_VISIBLE );
+}
+
+void Comment::importNoteSound( BiffInputStream& /*rStrm*/ )
+{
+}
+
+// ============================================================================
+
+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/sc/source/filter/oox/commentsfragment.cxx b/sc/source/filter/oox/commentsfragment.cxx
new file mode 100644
index 000000000000..54736fcd403a
--- /dev/null
+++ b/sc/source/filter/oox/commentsfragment.cxx
@@ -0,0 +1,161 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "commentsfragment.hxx"
+
+#include "richstringcontext.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+CommentsFragment::CommentsFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    WorksheetFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+ContextHandlerRef CommentsFragment::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 onCharacters()
+        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 RichStringContext( *this, mxComment->createText() );
+            if( nElement == XLS_TOKEN( commentPr ) ) { mxComment->importCommentPr( rAttribs ); return this; }
+        break;
+    }
+    return 0;
+}
+
+void CommentsFragment::onCharacters( const OUString& rChars )
+{
+    if( isCurrentElement( XLS_TOKEN( author ) ) )
+        getComments().appendAuthor( rChars );
+}
+
+void CommentsFragment::onEndElement()
+{
+    if( isCurrentElement( XLS_TOKEN( comment ) ) )
+        mxComment.reset();
+}
+
+ContextHandlerRef CommentsFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_COMMENTS ) return this;
+        break;
+        case BIFF12_ID_COMMENTS:
+            if( nRecId == BIFF12_ID_COMMENTAUTHORS ) return this;
+            if( nRecId == BIFF12_ID_COMMENTLIST ) return this;
+        break;
+        case BIFF12_ID_COMMENTAUTHORS:
+            if( nRecId == BIFF12_ID_COMMENTAUTHOR ) getComments().appendAuthor( BiffHelper::readString( rStrm ) );
+        break;
+        case BIFF12_ID_COMMENTLIST:
+            if( nRecId == BIFF12_ID_COMMENT ) { importComment( rStrm ); return this; }
+        break;
+        case BIFF12_ID_COMMENT:
+            if( (nRecId == BIFF12_ID_COMMENTTEXT) && mxComment.get() )
+                mxComment->createText()->importString( rStrm, true );
+        break;
+    }
+    return 0;
+}
+
+void CommentsFragment::onEndRecord()
+{
+    if( isCurrentElement( BIFF12_ID_COMMENT ) )
+        mxComment.reset();
+}
+
+const RecordInfo* CommentsFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_COMMENT,        BIFF12_ID_COMMENT + 1           },
+        { BIFF12_ID_COMMENTAUTHORS, BIFF12_ID_COMMENTAUTHORS + 1    },
+        { BIFF12_ID_COMMENTLIST,    BIFF12_ID_COMMENTLIST + 1       },
+        { BIFF12_ID_COMMENTS,       BIFF12_ID_COMMENTS + 1          },
+        { -1,                       -1                              }
+    };
+    return spRecInfos;
+}
+
+// private --------------------------------------------------------------------
+
+void CommentsFragment::importComment( const AttributeList& rAttribs )
+{
+    mxComment = getComments().createComment();
+    mxComment->importComment( rAttribs );
+}
+
+void CommentsFragment::importComment( SequenceInputStream& rStrm )
+{
+    mxComment = getComments().createComment();
+    mxComment->importComment( rStrm );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/condformatbuffer.cxx b/sc/source/filter/oox/condformatbuffer.cxx
new file mode 100644
index 000000000000..b10210fbecfc
--- /dev/null
+++ b/sc/source/filter/oox/condformatbuffer.cxx
@@ -0,0 +1,779 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "condformatbuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "stylesbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 BIFF12_CFRULE_TYPE_CELLIS           = 1;
+const sal_Int32 BIFF12_CFRULE_TYPE_EXPRESSION       = 2;
+const sal_Int32 BIFF12_CFRULE_TYPE_COLORSCALE       = 3;
+const sal_Int32 BIFF12_CFRULE_TYPE_DATABAR          = 4;
+const sal_Int32 BIFF12_CFRULE_TYPE_TOPTEN           = 5;
+const sal_Int32 BIFF12_CFRULE_TYPE_ICONSET          = 6;
+
+const sal_Int32 BIFF12_CFRULE_SUB_CELLIS            = 0;
+const sal_Int32 BIFF12_CFRULE_SUB_EXPRESSION        = 1;
+const sal_Int32 BIFF12_CFRULE_SUB_COLORSCALE        = 2;
+const sal_Int32 BIFF12_CFRULE_SUB_DATABAR           = 3;
+const sal_Int32 BIFF12_CFRULE_SUB_ICONSET           = 4;
+const sal_Int32 BIFF12_CFRULE_SUB_TOPTEN            = 5;
+const sal_Int32 BIFF12_CFRULE_SUB_UNIQUE            = 7;
+const sal_Int32 BIFF12_CFRULE_SUB_TEXT              = 8;
+const sal_Int32 BIFF12_CFRULE_SUB_BLANK             = 9;
+const sal_Int32 BIFF12_CFRULE_SUB_NOTBLANK          = 10;
+const sal_Int32 BIFF12_CFRULE_SUB_ERROR             = 11;
+const sal_Int32 BIFF12_CFRULE_SUB_NOTERROR          = 12;
+const sal_Int32 BIFF12_CFRULE_SUB_TODAY             = 15;
+const sal_Int32 BIFF12_CFRULE_SUB_TOMORROW          = 16;
+const sal_Int32 BIFF12_CFRULE_SUB_YESTERDAY         = 17;
+const sal_Int32 BIFF12_CFRULE_SUB_LAST7DAYS         = 18;
+const sal_Int32 BIFF12_CFRULE_SUB_LASTMONTH         = 19;
+const sal_Int32 BIFF12_CFRULE_SUB_NEXTMONTH         = 20;
+const sal_Int32 BIFF12_CFRULE_SUB_THISWEEK          = 21;
+const sal_Int32 BIFF12_CFRULE_SUB_NEXTWEEK          = 22;
+const sal_Int32 BIFF12_CFRULE_SUB_LASTWEEK          = 23;
+const sal_Int32 BIFF12_CFRULE_SUB_THISMONTH         = 24;
+const sal_Int32 BIFF12_CFRULE_SUB_ABOVEAVERAGE      = 25;
+const sal_Int32 BIFF12_CFRULE_SUB_BELOWAVERAGE      = 26;
+const sal_Int32 BIFF12_CFRULE_SUB_DUPLICATE         = 27;
+const sal_Int32 BIFF12_CFRULE_SUB_EQABOVEAVERAGE    = 29;
+const sal_Int32 BIFF12_CFRULE_SUB_EQBELOWAVERAGE    = 30;
+
+const sal_Int32 BIFF12_CFRULE_TIMEOP_TODAY          = 0;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_YESTERDAY      = 1;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_LAST7DAYS      = 2;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_THISWEEK       = 3;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_LASTWEEK       = 4;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_LASTMONTH      = 5;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_TOMORROW       = 6;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_NEXTWEEK       = 7;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_NEXTMONTH      = 8;
+const sal_Int32 BIFF12_CFRULE_TIMEOP_THISMONTH      = 9;
+
+const sal_uInt16 BIFF12_CFRULE_STOPIFTRUE           = 0x0002;
+const sal_uInt16 BIFF12_CFRULE_ABOVEAVERAGE         = 0x0004;
+const sal_uInt16 BIFF12_CFRULE_BOTTOM               = 0x0008;
+const sal_uInt16 BIFF12_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::setBiffOperator( 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::setBiff12TextType( 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 )
+{
+    CellAddress aBaseAddr = mrCondFormat.getRanges().getBaseAddress();
+    ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, rFormula );
+    maModel.maFormulas.push_back( aTokens );
+}
+
+void CondFormatRule::importCfRule( SequenceInputStream& 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 )
+    {
+        CellAddress aBaseAddr = mrCondFormat.getRanges().getBaseAddress();
+        ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, FORMULATYPE_CONDFORMAT, rStrm );
+        maModel.maFormulas.push_back( aTokens );
+
+        // 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 )
+        {
+            aTokens = getFormulaParser().importFormula( aBaseAddr, FORMULATYPE_CONDFORMAT, rStrm );
+            maModel.maFormulas.push_back( aTokens );
+
+            // third formula
+            OSL_ENSURE( (nFmla3Size > 0) == (rStrm.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
+            if( rStrm.getRemaining() >= 8 )
+            {
+                aTokens = getFormulaParser().importFormula( aBaseAddr, FORMULATYPE_CONDFORMAT, rStrm );
+                maModel.maFormulas.push_back( aTokens );
+            }
+        }
+    }
+
+    // flags
+    maModel.mbStopIfTrue   = getFlag( nFlags, BIFF12_CFRULE_STOPIFTRUE );
+    maModel.mbBottom       = getFlag( nFlags, BIFF12_CFRULE_BOTTOM );
+    maModel.mbPercent      = getFlag( nFlags, BIFF12_CFRULE_PERCENT );
+    maModel.mbAboveAverage = getFlag( nFlags, BIFF12_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 BIFF12_CFRULE_TYPE_CELLIS:
+            OSL_ENSURE( nSubType == BIFF12_CFRULE_SUB_CELLIS, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+            maModel.mnType = XML_cellIs;
+            maModel.setBiffOperator( nOperator );
+            OSL_ENSURE( maModel.mnOperator != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unknown operator" );
+        break;
+        case BIFF12_CFRULE_TYPE_EXPRESSION:
+            // here we have to look at the subtype to find the real type...
+            switch( nSubType )
+            {
+                case BIFF12_CFRULE_SUB_EXPRESSION:
+                    OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+                    maModel.mnType = XML_expression;
+                break;
+                case BIFF12_CFRULE_SUB_UNIQUE:
+                    OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+                    maModel.mnType = XML_uniqueValues;
+                break;
+                case BIFF12_CFRULE_SUB_TEXT:
+                    maModel.setBiff12TextType( nOperator );
+                    OSL_ENSURE( maModel.mnType != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unexpected operator value" );
+                break;
+                case BIFF12_CFRULE_SUB_BLANK:
+                    OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+                    maModel.mnType = XML_containsBlanks;
+                break;
+                case BIFF12_CFRULE_SUB_NOTBLANK:
+                    OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+                    maModel.mnType = XML_notContainsBlanks;
+                break;
+                case BIFF12_CFRULE_SUB_ERROR:
+                    OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+                    maModel.mnType = XML_containsErrors;
+                break;
+                case BIFF12_CFRULE_SUB_NOTERROR:
+                    OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+                    maModel.mnType = XML_notContainsErrors;
+                break;
+                case BIFF12_CFRULE_SUB_TODAY:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_TODAY, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_today;
+                break;
+                case BIFF12_CFRULE_SUB_TOMORROW:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_TOMORROW, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_tomorrow;
+                break;
+                case BIFF12_CFRULE_SUB_YESTERDAY:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_YESTERDAY, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_yesterday;
+                break;
+                case BIFF12_CFRULE_SUB_LAST7DAYS:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_LAST7DAYS, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_last7Days;
+                break;
+                case BIFF12_CFRULE_SUB_LASTMONTH:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_LASTMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_lastMonth;
+                break;
+                case BIFF12_CFRULE_SUB_NEXTMONTH:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_NEXTMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_nextMonth;
+                break;
+                case BIFF12_CFRULE_SUB_THISWEEK:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_THISWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_thisWeek;
+                break;
+                case BIFF12_CFRULE_SUB_NEXTWEEK:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_NEXTWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_nextWeek;
+                break;
+                case BIFF12_CFRULE_SUB_LASTWEEK:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_LASTWEEK, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_lastWeek;
+                break;
+                case BIFF12_CFRULE_SUB_THISMONTH:
+                    OSL_ENSURE( nOperator == BIFF12_CFRULE_TIMEOP_THISMONTH, "CondFormatRule::importCfRule - unexpected time operator value" );
+                    maModel.mnType = XML_timePeriod;
+                    maModel.mnTimePeriod = XML_thisMonth;
+                break;
+                case BIFF12_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 BIFF12_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 BIFF12_CFRULE_SUB_DUPLICATE:
+                    OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+                    maModel.mnType = XML_duplicateValues;
+                break;
+                case BIFF12_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 BIFF12_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 BIFF12_CFRULE_TYPE_COLORSCALE:
+            OSL_ENSURE( nSubType == BIFF12_CFRULE_SUB_COLORSCALE, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+            OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+            maModel.mnType = XML_colorScale;
+        break;
+        case BIFF12_CFRULE_TYPE_DATABAR:
+            OSL_ENSURE( nSubType == BIFF12_CFRULE_SUB_DATABAR, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+            OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
+            maModel.mnType = XML_dataBar;
+        break;
+        case BIFF12_CFRULE_TYPE_TOPTEN:
+            OSL_ENSURE( nSubType == BIFF12_CFRULE_SUB_TOPTEN, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
+            maModel.mnType = XML_top10;
+            maModel.mnRank = nOperator;   // operator field used for rank value
+        break;
+        case BIFF12_CFRULE_TYPE_ICONSET:
+            OSL_ENSURE( nSubType == BIFF12_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_FAIL( "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.setBiffOperator( 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 )
+    {
+        CellAddress aBaseAddr = mrCondFormat.getRanges().getBaseAddress();
+        ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, FORMULATYPE_CONDFORMAT, rStrm, &nFmla1Size );
+        maModel.maFormulas.push_back( aTokens );
+        if( nFmla2Size > 0 )
+        {
+            aTokens = getFormulaParser().importFormula( aBaseAddr, FORMULATYPE_CONDFORMAT, rStrm, &nFmla2Size );
+            maModel.maFormulas.push_back( aTokens );
+        }
+    }
+}
+
+void CondFormatRule::finalizeImport( const Reference< XSheetConditionalEntries >& rxEntries )
+{
+    sal_Int32 eOperator = ::com::sun::star::sheet::ConditionOperator2::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_duplicateValues:
+            eOperator = CondFormatBuffer::convertToApiOperator( XML_duplicateValues );
+            aReplaceFormula = CREATE_OUSTRING( " " );
+        break;
+        case XML_expression:
+            eOperator = ::com::sun::star::sheet::ConditionOperator2::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()-70" );
+        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.isEmpty() )
+    {
+        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.isEmpty() )
+                        aAddress = FormulaProcessorBase::generateAddress2dString( mrCondFormat.getRanges().getBaseAddress(), false );
+                    aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aAddress );
+                break;
+                case 'R':       // range list of conditional formatting
+                    if( aRanges.isEmpty() )
+                        aRanges = FormulaProcessorBase::generateRangeList2dString( mrCondFormat.getRanges(), true, ',', true );
+                    aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aRanges );
+                break;
+                case 'T':       // comparison text
+                    if( aText.isEmpty() )
+                        // 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.isEmpty() )
+                        aComp = maModel.mbAboveAverage ?
+                            (maModel.mbEqualAverage ? CREATE_OUSTRING( ">=" ) : CREATE_OUSTRING( ">" )) :
+                            (maModel.mbEqualAverage ? CREATE_OUSTRING( "<=" ) : CREATE_OUSTRING( "<" ));
+                    aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aComp );
+                break;
+                default:
+                    OSL_FAIL( "CondFormatRule::finalizeImport - unknown placeholder" );
+            }
+        }
+
+        // set the replacement formula
+        maModel.maFormulas.clear();
+        appendFormula( aReplaceFormula );
+        if( eOperator != ::com::sun::star::sheet::ConditionOperator2::DUPLICATE )
+            eOperator = ::com::sun::star::sheet::ConditionOperator2::FORMULA;
+    }
+
+    if( rxEntries.is() && (eOperator != ::com::sun::star::sheet::ConditionOperator2::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 ] );
+        if( maModel.maFormulas.size() >= 2 )
+            lclAppendProperty( aProps, CREATE_OUSTRING( "Formula2" ), maModel.maFormulas[ 1 ] );
+
+        // style name for the formatting attributes
+        OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
+        if( !aStyleName.isEmpty() )
+            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( SequenceInputStream& rStrm )
+{
+    BinRangeList aRanges;
+    rStrm.skip( 8 );
+    rStrm >> aRanges;
+    getAddressConverter().convertToCellRangeList( maModel.maRanges, aRanges, getSheetIndex(), true );
+}
+
+void CondFormat::importCfRule( SequenceInputStream& 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()
+{
+    try
+    {
+        Reference< XSheetCellRanges > xRanges( getCellRangeList( maModel.maRanges ), UNO_SET_THROW );
+        PropertySet aPropSet( xRanges );
+        Reference< XSheetConditionalEntries > xEntries( aPropSet.getAnyProperty( PROP_ConditionalFormat ), UNO_QUERY_THROW );
+        // maRules is sorted by rule priority
+        maRules.forEachMem( &CondFormatRule::finalizeImport, ::boost::cref( xEntries ) );
+        aPropSet.setProperty( PROP_ConditionalFormat, xEntries );
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+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( SequenceInputStream& rStrm )
+{
+    CondFormatRef xCondFmt = createCondFormat();
+    xCondFmt->importCondFormatting( rStrm );
+    return xCondFmt;
+}
+
+void CondFormatBuffer::importCfHeader( BiffInputStream& rStrm )
+{
+    createCondFormat()->importCfHeader( rStrm );
+}
+
+void CondFormatBuffer::finalizeImport()
+{
+    maCondFormats.forEachMem( &CondFormat::finalizeImport );
+}
+
+sal_Int32 CondFormatBuffer::convertToApiOperator( sal_Int32 nToken )
+{
+    switch( nToken )
+    {
+        case XML_between:               return ConditionOperator2::BETWEEN;
+        case XML_equal:                 return ConditionOperator2::EQUAL;
+        case XML_greaterThan:           return ConditionOperator2::GREATER;
+        case XML_greaterThanOrEqual:    return ConditionOperator2::GREATER_EQUAL;
+        case XML_lessThan:              return ConditionOperator2::LESS;
+        case XML_lessThanOrEqual:       return ConditionOperator2::LESS_EQUAL;
+        case XML_notBetween:            return ConditionOperator2::NOT_BETWEEN;
+        case XML_notEqual:              return ConditionOperator2::NOT_EQUAL;
+        case XML_duplicateValues:       return ConditionOperator2::DUPLICATE;
+    }
+    return ConditionOperator2::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/sc/source/filter/oox/condformatcontext.cxx b/sc/source/filter/oox/condformatcontext.cxx
new file mode 100644
index 000000000000..0ca3b7fe431a
--- /dev/null
+++ b/sc/source/filter/oox/condformatcontext.cxx
@@ -0,0 +1,105 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "condformatcontext.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using ::oox::core::ContextHandlerRef;
+using ::rtl::OUString;
+
+// ============================================================================
+
+CondFormatContext::CondFormatContext( WorksheetFragmentBase& rFragment ) :
+    WorksheetContextBase( rFragment )
+{
+}
+
+ContextHandlerRef CondFormatContext::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 CondFormatContext::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 CondFormatContext::onCharacters( const OUString& rChars )
+{
+    if( isCurrentElement( XLS_TOKEN( formula ) ) && mxCondFmt.get() && mxRule.get() )
+        mxRule->appendFormula( rChars );
+}
+
+ContextHandlerRef CondFormatContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_CONDFORMATTING:
+            return (nRecId == BIFF12_ID_CFRULE) ? this : 0;
+    }
+    return 0;
+}
+
+void CondFormatContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_CONDFORMATTING:
+            mxCondFmt = getCondFormats().importCondFormatting( rStrm );
+        break;
+        case BIFF12_ID_CFRULE:
+            if( mxCondFmt.get() ) mxCondFmt->importCfRule( rStrm );
+        break;
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/connectionsbuffer.cxx b/sc/source/filter/oox/connectionsbuffer.cxx
new file mode 100644
index 000000000000..e9946a809ecf
--- /dev/null
+++ b/sc/source/filter/oox/connectionsbuffer.cxx
@@ -0,0 +1,504 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "connectionsbuffer.hxx"
+
+#include "oox/helper/attributelist.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 BIFF12_RECONNECT_AS_REQUIRED            = 1;
+const sal_Int32 BIFF12_RECONNECT_ALWAYS                 = 2;
+const sal_Int32 BIFF12_RECONNECT_NEVER                  = 3;
+
+const sal_uInt8 BIFF12_CONNECTION_SAVEPASSWORD_ON       = 1;
+const sal_uInt8 BIFF12_CONNECTION_SAVEPASSWORD_OFF      = 2;
+
+const sal_uInt16 BIFF12_CONNECTION_KEEPALIVE            = 0x0001;
+const sal_uInt16 BIFF12_CONNECTION_NEW                  = 0x0002;
+const sal_uInt16 BIFF12_CONNECTION_DELETED              = 0x0004;
+const sal_uInt16 BIFF12_CONNECTION_ONLYUSECONNFILE      = 0x0008;
+const sal_uInt16 BIFF12_CONNECTION_BACKGROUND           = 0x0010;
+const sal_uInt16 BIFF12_CONNECTION_REFRESHONLOAD        = 0x0020;
+const sal_uInt16 BIFF12_CONNECTION_SAVEDATA             = 0x0040;
+
+const sal_uInt16 BIFF12_CONNECTION_HAS_SOURCEFILE       = 0x0001;
+const sal_uInt16 BIFF12_CONNECTION_HAS_SOURCECONNFILE   = 0x0002;
+const sal_uInt16 BIFF12_CONNECTION_HAS_DESCRIPTION      = 0x0004;
+const sal_uInt16 BIFF12_CONNECTION_HAS_NAME             = 0x0008;
+const sal_uInt16 BIFF12_CONNECTION_HAS_SSOID            = 0x0010;
+
+const sal_uInt32 BIFF12_WEBPR_XML                       = 0x00000100;
+const sal_uInt32 BIFF12_WEBPR_SOURCEDATA                = 0x00000200;
+const sal_uInt32 BIFF12_WEBPR_PARSEPRE                  = 0x00000400;
+const sal_uInt32 BIFF12_WEBPR_CONSECUTIVE               = 0x00000800;
+const sal_uInt32 BIFF12_WEBPR_FIRSTROW                  = 0x00001000;
+const sal_uInt32 BIFF12_WEBPR_XL97CREATED               = 0x00002000;
+const sal_uInt32 BIFF12_WEBPR_TEXTDATES                 = 0x00004000;
+const sal_uInt32 BIFF12_WEBPR_XL2000REFRESHED           = 0x00008000;
+const sal_uInt32 BIFF12_WEBPR_HTMLTABLES                = 0x00010000;
+
+const sal_uInt8 BIFF12_WEBPR_HAS_POSTMETHOD             = 0x01;
+const sal_uInt8 BIFF12_WEBPR_HAS_EDITPAGE               = 0x02;
+const sal_uInt8 BIFF12_WEBPR_HAS_URL                    = 0x04;
+
+const sal_uInt16 BIFF_DBQUERY_ODBC                      = 0x0008;
+const sal_uInt16 BIFF_DBQUERY_SQLQUERY                  = 0x0010;
+const sal_uInt16 BIFF_DBQUERY_SERVERBASEDSQL            = 0x0020;
+const sal_uInt16 BIFF_DBQUERY_HTML                      = 0x0040;
+const sal_uInt16 BIFF_DBQUERY_SAVEPASSWORD              = 0x0080;
+const sal_uInt16 BIFF_DBQUERY_HTMLTABLES                = 0x0100;
+
+const sal_uInt16 BIFF_QTSETTINGS_KEEPALIVE              = 0x0001;
+const sal_uInt16 BIFF_QTSETTINGS_NEW                    = 0x0002;
+const sal_uInt16 BIFF_QTSETTINGS_SOURCEDATA             = 0x0004;
+const sal_uInt16 BIFF_QTSETTINGS_WEBBASEDPROV           = 0x0008;
+const sal_uInt16 BIFF_QTSETTINGS_REINITLIST             = 0x0010;
+const sal_uInt16 BIFF_QTSETTINGS_XML                    = 0x0080;
+
+const sal_uInt16 BIFF_QTSETTINGS_PARSEPRE               = 0x0001;
+const sal_uInt16 BIFF_QTSETTINGS_CONSECUTIVE            = 0x0002;
+const sal_uInt16 BIFF_QTSETTINGS_FIRSTROW               = 0x0004;
+const sal_uInt16 BIFF_QTSETTINGS_XL97CREATED            = 0x0008;
+const sal_uInt16 BIFF_QTSETTINGS_TEXTDATES              = 0x0010;
+const sal_uInt16 BIFF_QTSETTINGS_XL2000REFRESHED        = 0x0020;
+
+const sal_uInt16 BIFF_QTSETTINGS_TEXTQUERY              = 0x0001;
+const sal_uInt16 BIFF_QTSETTINGS_TABLENAMES             = 0x0002;
+
+// ----------------------------------------------------------------------------
+
+OUString lclReadQueryString( BiffInputStream& rStrm, sal_uInt16 nCount )
+{
+    bool bValidRec = true;
+    OUStringBuffer aBuffer;
+    for( sal_uInt16 nIndex = 0; bValidRec && (nIndex < nCount); ++nIndex )
+    {
+        bValidRec = (rStrm.getNextRecId() == BIFF_ID_PCITEM_STRING) && rStrm.startNextRecord();
+        if( bValidRec )
+            aBuffer.append( rStrm.readUniString() );
+    }
+    OSL_ENSURE( bValidRec, "lclReadQueryString - missing PCITEM_STRING records" );
+    return aBuffer.makeStringAndClear();
+}
+
+void lclParseTables( WebPrModel::TablesVector& rTables, const OUString& rTableNames )
+{
+    rTables.clear();
+    OUString aTableNames = rTableNames.trim();
+    while( !aTableNames.isEmpty() )
+    {
+        sal_Int32 nSep = -1;
+        // table names are enclosed in double quotes
+        if( aTableNames[ 0 ] == '"' )
+        {
+            // search closing quote character
+            sal_Int32 nEndQuote = aTableNames.indexOf( '"', 1 );
+            OSL_ENSURE( nEndQuote >= 1, "lclParseTables - invalid syntax" );
+            if( nEndQuote < 0 )
+                nEndQuote = aTableNames.getLength();
+            else
+                nSep = aTableNames.indexOf( ',', nEndQuote + 1 );
+            // extract text between quote characters
+            OUString aTableName = aTableNames.copy( 1, nEndQuote - 1 ).trim();
+            if( !aTableName.isEmpty() )
+                rTables.push_back( Any( aTableName ) );
+            else
+                rTables.push_back( Any() );
+        }
+        else
+        {
+            nSep = aTableNames.indexOf( ',' );
+            if( nSep < 0 )
+                nSep = aTableNames.getLength();
+            OUString aTableIndex = aTableNames.copy( 0, nSep ).trim();
+            if( !aTableIndex.isEmpty() && (aTableIndex[ 0 ] >= '1') && (aTableIndex[ 0 ] <= '9') )
+                rTables.push_back( Any( aTableIndex.toInt32() ) );
+            else
+                rTables.push_back( Any() );
+        }
+
+        // remove processed item from aTableNames
+        if( (nSep < 0) || (nSep >= aTableNames.getLength()) )
+            aTableNames = OUString();
+        else
+            aTableNames = aTableNames.copy( nSep + 1 ).trim();
+    }
+}
+
+} // namespace
+
+// ============================================================================
+
+WebPrModel::WebPrModel() :
+    mnHtmlFormat( XML_none ),
+    mbXml( false ),
+    mbSourceData( false ),
+    mbParsePre( false ),
+    mbConsecutive( false ),
+    mbFirstRow( false ),
+    mbXl97Created( false ),
+    mbTextDates( false ),
+    mbXl2000Refreshed( false ),
+    mbHtmlTables( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ConnectionModel::ConnectionModel() :
+    mnId( -1 ),
+    mnType( BIFF12_CONNECTION_UNKNOWN ),
+    mnReconnectMethod( BIFF12_RECONNECT_AS_REQUIRED ),
+    mnCredentials( XML_integrated ),
+    mnInterval( 0 ),
+    mbKeepAlive( false ),
+    mbNew( false ),
+    mbDeleted( false ),
+    mbOnlyUseConnFile( false ),
+    mbBackground( false ),
+    mbRefreshOnLoad( false ),
+    mbSaveData( false ),
+    mbSavePassword( false )
+{
+}
+
+WebPrModel& ConnectionModel::createWebPr()
+{
+    OSL_ENSURE( !mxWebPr.get(), "ConnectionModel::createWebPr - multiple call" );
+    mxWebPr.reset( new WebPrModel );
+    return *mxWebPr;
+}
+
+// ----------------------------------------------------------------------------
+
+Connection::Connection( const WorkbookHelper& rHelper, sal_Int32 nConnId ) :
+    WorkbookHelper( rHelper )
+{
+    maModel.mnId = nConnId;
+}
+
+void Connection::importConnection( const AttributeList& rAttribs )
+{
+    maModel.maName            = rAttribs.getXString( XML_name, OUString() );
+    maModel.maDescription     = rAttribs.getXString( XML_description, OUString() );
+    maModel.maSourceFile      = rAttribs.getXString( XML_sourceFile, OUString() );
+    maModel.maSourceConnFile  = rAttribs.getXString( XML_odcFile, OUString() );
+    maModel.maSsoId           = rAttribs.getXString( XML_singleSignOnId, OUString() );
+    maModel.mnId              = rAttribs.getInteger( XML_id, -1 );
+    // type and reconnectionMethod are using the BIFF12 constants instead of XML tokens
+    maModel.mnType            = rAttribs.getInteger( XML_type, BIFF12_CONNECTION_UNKNOWN );
+    maModel.mnReconnectMethod = rAttribs.getInteger( XML_reconnectionMethod, BIFF12_RECONNECT_AS_REQUIRED );
+    maModel.mnCredentials     = rAttribs.getToken( XML_credentials, XML_integrated );
+    maModel.mnInterval        = rAttribs.getInteger( XML_interval, 0 );
+    maModel.mbKeepAlive       = rAttribs.getBool( XML_keepAlive, false );
+    maModel.mbNew             = rAttribs.getBool( XML_new, false );
+    maModel.mbDeleted         = rAttribs.getBool( XML_deleted, false );
+    maModel.mbOnlyUseConnFile = rAttribs.getBool( XML_onlyUseConnectionFile, false );
+    maModel.mbBackground      = rAttribs.getBool( XML_background, false );
+    maModel.mbRefreshOnLoad   = rAttribs.getBool( XML_refreshOnLoad, false );
+    maModel.mbSaveData        = rAttribs.getBool( XML_saveData, false );
+    maModel.mbSavePassword    = rAttribs.getBool( XML_savePassword, false );
+}
+
+void Connection::importWebPr( const AttributeList& rAttribs )
+{
+    WebPrModel& rWebPr = maModel.createWebPr();
+
+    rWebPr.maUrl             = rAttribs.getXString( XML_url, OUString() );
+    rWebPr.maPostMethod      = rAttribs.getXString( XML_post, OUString() );
+    rWebPr.maEditPage        = rAttribs.getXString( XML_editPage, OUString() );
+    rWebPr.mnHtmlFormat      = rAttribs.getToken( XML_htmlFormat, XML_none );
+    rWebPr.mbXml             = rAttribs.getBool( XML_xml, false );
+    rWebPr.mbSourceData      = rAttribs.getBool( XML_sourceData, false );
+    rWebPr.mbParsePre        = rAttribs.getBool( XML_parsePre, false );
+    rWebPr.mbConsecutive     = rAttribs.getBool( XML_consecutive, false );
+    rWebPr.mbFirstRow        = rAttribs.getBool( XML_firstRow, false );
+    rWebPr.mbXl97Created     = rAttribs.getBool( XML_xl97, false );
+    rWebPr.mbTextDates       = rAttribs.getBool( XML_textDates, false );
+    rWebPr.mbXl2000Refreshed = rAttribs.getBool( XML_xl2000, false );
+    rWebPr.mbHtmlTables      = rAttribs.getBool( XML_htmlTables, false );
+}
+
+void Connection::importTables( const AttributeList& /*rAttribs*/ )
+{
+    if( maModel.mxWebPr.get() )
+    {
+        OSL_ENSURE( maModel.mxWebPr->maTables.empty(), "Connection::importTables - multiple calls" );
+        maModel.mxWebPr->maTables.clear();
+    }
+}
+
+void Connection::importTable( const AttributeList& rAttribs, sal_Int32 nElement )
+{
+    if( maModel.mxWebPr.get() )
+    {
+        Any aTableAny;
+        switch( nElement )
+        {
+            case XLS_TOKEN( m ):                                                            break;
+            case XLS_TOKEN( s ):    aTableAny <<= rAttribs.getXString( XML_v, OUString() ); break;
+            case XLS_TOKEN( x ):    aTableAny <<= rAttribs.getInteger( XML_v, -1 );         break;
+            default:
+                OSL_ENSURE( false, "Connection::importTable - unexpected element" );
+                return;
+        }
+        maModel.mxWebPr->maTables.push_back( aTableAny );
+    }
+}
+
+void Connection::importConnection( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFlags, nStrFlags;
+    sal_uInt8 nSavePassword, nCredentials;
+    rStrm.skip( 2 );
+    rStrm >> nSavePassword;
+    rStrm.skip( 1 );
+    maModel.mnInterval = rStrm.readuInt16();
+    rStrm >> nFlags >> nStrFlags >> maModel.mnType >> maModel.mnReconnectMethod >> maModel.mnId >> nCredentials;
+
+    if( getFlag( nStrFlags, BIFF12_CONNECTION_HAS_SOURCEFILE ) )
+        rStrm >> maModel.maSourceFile;
+    if( getFlag( nStrFlags, BIFF12_CONNECTION_HAS_SOURCECONNFILE ) )
+        rStrm >> maModel.maSourceConnFile;
+    if( getFlag( nStrFlags, BIFF12_CONNECTION_HAS_DESCRIPTION ) )
+        rStrm >> maModel.maDescription;
+    if( getFlag( nStrFlags, BIFF12_CONNECTION_HAS_NAME ) )
+        rStrm >> maModel.maName;
+    if( getFlag( nStrFlags, BIFF12_CONNECTION_HAS_SSOID ) )
+        rStrm >> maModel.maSsoId;
+
+    static const sal_Int32 spnCredentials[] = { XML_integrated, XML_none, XML_stored, XML_prompt };
+    maModel.mnCredentials = STATIC_ARRAY_SELECT( spnCredentials, nCredentials, XML_integrated );
+
+    maModel.mbKeepAlive       = getFlag( nFlags, BIFF12_CONNECTION_KEEPALIVE );
+    maModel.mbNew             = getFlag( nFlags, BIFF12_CONNECTION_NEW );
+    maModel.mbDeleted         = getFlag( nFlags, BIFF12_CONNECTION_DELETED );
+    maModel.mbOnlyUseConnFile = getFlag( nFlags, BIFF12_CONNECTION_ONLYUSECONNFILE );
+    maModel.mbBackground      = getFlag( nFlags, BIFF12_CONNECTION_BACKGROUND );
+    maModel.mbRefreshOnLoad   = getFlag( nFlags, BIFF12_CONNECTION_REFRESHONLOAD );
+    maModel.mbSaveData        = getFlag( nFlags, BIFF12_CONNECTION_SAVEDATA );
+    maModel.mbSavePassword    = nSavePassword == BIFF12_CONNECTION_SAVEPASSWORD_ON;
+}
+
+void Connection::importWebPr( SequenceInputStream& rStrm )
+{
+    WebPrModel& rWebPr = maModel.createWebPr();
+
+    sal_uInt32 nFlags;
+    sal_uInt8 nStrFlags;
+    rStrm >> nFlags >> nStrFlags;
+
+    if( getFlag( nStrFlags, BIFF12_WEBPR_HAS_URL ) )
+        rStrm >> rWebPr.maUrl;
+    if( getFlag( nStrFlags, BIFF12_WEBPR_HAS_POSTMETHOD ) )
+        rStrm >> rWebPr.maPostMethod;
+    if( getFlag( nStrFlags, BIFF12_WEBPR_HAS_EDITPAGE ) )
+        rStrm >> rWebPr.maEditPage;
+
+    static const sal_Int32 spnHmlFormats[] = { XML_none, XML_rtf, XML_all };
+    rWebPr.mnHtmlFormat = STATIC_ARRAY_SELECT( spnHmlFormats, extractValue< sal_uInt8 >( nFlags, 0, 8 ), XML_none );
+
+    rWebPr.mbXml             = getFlag( nFlags, BIFF12_WEBPR_XML );
+    rWebPr.mbSourceData      = getFlag( nFlags, BIFF12_WEBPR_SOURCEDATA );
+    rWebPr.mbParsePre        = getFlag( nFlags, BIFF12_WEBPR_PARSEPRE );
+    rWebPr.mbConsecutive     = getFlag( nFlags, BIFF12_WEBPR_CONSECUTIVE );
+    rWebPr.mbFirstRow        = getFlag( nFlags, BIFF12_WEBPR_FIRSTROW );
+    rWebPr.mbXl97Created     = getFlag( nFlags, BIFF12_WEBPR_XL97CREATED );
+    rWebPr.mbTextDates       = getFlag( nFlags, BIFF12_WEBPR_TEXTDATES );
+    rWebPr.mbXl2000Refreshed = getFlag( nFlags, BIFF12_WEBPR_XL2000REFRESHED );
+    rWebPr.mbHtmlTables      = getFlag( nFlags, BIFF12_WEBPR_HTMLTABLES );
+}
+
+void Connection::importWebPrTables( SequenceInputStream& /*rStrm*/ )
+{
+    if( maModel.mxWebPr.get() )
+    {
+        OSL_ENSURE( maModel.mxWebPr->maTables.empty(), "Connection::importWebPrTables - multiple calls" );
+        maModel.mxWebPr->maTables.clear();
+    }
+}
+
+void Connection::importWebPrTable( SequenceInputStream& rStrm, sal_Int32 nRecId )
+{
+    if( maModel.mxWebPr.get() )
+    {
+        Any aTableAny;
+        switch( nRecId )
+        {
+            case BIFF12_ID_PCITEM_MISSING:                                                  break;
+            case BIFF12_ID_PCITEM_STRING:   aTableAny <<= BiffHelper::readString( rStrm );  break;
+            case BIFF12_ID_PCITEM_INDEX:    aTableAny <<= rStrm.readInt32();                break;
+            default:
+                OSL_ENSURE( false, "Connection::importWebPrTable - unexpected record" );
+                return;
+        }
+        maModel.mxWebPr->maTables.push_back( aTableAny );
+    }
+}
+
+void Connection::importDbQuery( BiffInputStream& rStrm )
+{
+    sal_uInt16 nFlags, nSqlParamCount, nCommandCount, nPostMethodCount, nServerSqlCount, nOdbcConnCount;
+    rStrm >> nFlags >> nSqlParamCount >> nCommandCount >> nPostMethodCount >> nServerSqlCount >> nOdbcConnCount;
+
+    // same type constants in all BIFF versions
+    maModel.mnType = extractValue< sal_Int32 >( nFlags, 0, 3 );
+    maModel.mbSavePassword = getFlag( nFlags, BIFF_DBQUERY_SAVEPASSWORD );
+
+    OSL_ENSURE( getFlag( nFlags, BIFF_DBQUERY_ODBC ) == (maModel.mnType == BIFF12_CONNECTION_ODBC), "Connection::importDbQuery - wrong ODBC flag" );
+    OSL_ENSURE( getFlag( nFlags, BIFF_DBQUERY_SQLQUERY ) != (maModel.mnType == BIFF12_CONNECTION_HTML), "Connection::importDbQuery - wrong SQL query flag" );
+    OSL_ENSURE( getFlag( nFlags, BIFF_DBQUERY_HTML ) == (maModel.mnType == BIFF12_CONNECTION_HTML), "Connection::importDbQuery - wrong HTML flag" );
+
+    if( (maModel.mnType == BIFF12_CONNECTION_HTML) && getFlag( nFlags, BIFF_DBQUERY_HTML ) )
+    {
+        WebPrModel& rWebPr = maModel.createWebPr();
+        rWebPr.mbHtmlTables = getFlag( nFlags, BIFF_DBQUERY_HTMLTABLES );
+
+        // read HTML query URL and post method
+        rWebPr.maUrl = lclReadQueryString( rStrm, nCommandCount );
+        rWebPr.maPostMethod = lclReadQueryString( rStrm, nPostMethodCount );
+    }
+}
+
+void Connection::importQueryTableSettings( BiffInputStream& rStrm )
+{
+    rStrm.skip( 4 );
+    // source data type, again
+    sal_uInt16 nType = rStrm.readuInt16();
+    OSL_ENSURE( nType == maModel.mnType, "Connection::importQueryTableSettings - source data type mismatch" );
+    if( nType == maModel.mnType )
+    {
+        sal_uInt16 nFlags1, nFlags2, nFlags3, nHtmlFormat;
+        rStrm >> nFlags1 >> nFlags2 >> nFlags3;
+        rStrm.skip( 10 );
+        maModel.mnInterval = rStrm.readuInt16();
+        rStrm >> nHtmlFormat;
+
+        // first flags field: generic connection flags
+        maModel.mbKeepAlive = getFlag( nFlags1, BIFF_QTSETTINGS_KEEPALIVE );
+        maModel.mbNew       = getFlag( nFlags1, BIFF_QTSETTINGS_NEW );
+
+        // meaning of second flags field is dependent on source data type
+        if( (maModel.mnType == BIFF12_CONNECTION_HTML) && maModel.mxWebPr.get() )
+        {
+            WebPrModel& rWebPr = *maModel.mxWebPr;
+
+            // HTML format is one-based in BIFF8 (but zero-based in BIFF12)
+            static const sal_Int32 spnHmlFormats[] = { XML_none, XML_none, XML_rtf, XML_all };
+            rWebPr.mnHtmlFormat = STATIC_ARRAY_SELECT( spnHmlFormats, nHtmlFormat, XML_none );
+
+            rWebPr.mbXml             = getFlag( nFlags1, BIFF_QTSETTINGS_XML );
+            rWebPr.mbSourceData      = getFlag( nFlags1, BIFF_QTSETTINGS_SOURCEDATA );
+            rWebPr.mbParsePre        = getFlag( nFlags2, BIFF_QTSETTINGS_PARSEPRE );
+            rWebPr.mbConsecutive     = getFlag( nFlags2, BIFF_QTSETTINGS_CONSECUTIVE );
+            rWebPr.mbFirstRow        = getFlag( nFlags2, BIFF_QTSETTINGS_FIRSTROW );
+            rWebPr.mbXl97Created     = getFlag( nFlags2, BIFF_QTSETTINGS_XL97CREATED );
+            rWebPr.mbTextDates       = getFlag( nFlags2, BIFF_QTSETTINGS_TEXTDATES );
+            rWebPr.mbXl2000Refreshed = getFlag( nFlags2, BIFF_QTSETTINGS_XL2000REFRESHED );
+
+            // list of HTML table names or indexes
+            if( getFlag( nFlags3, BIFF_QTSETTINGS_TABLENAMES ) )
+            {
+                // a QUERYTABLESTRING record containing the table names must follow
+                bool bHasQTString = (rStrm.getNextRecId() == BIFF_ID_QUERYTABLESTRING) && rStrm.startNextRecord();
+                OSL_ENSURE( bHasQTString, "Connection::importQueryTableSettings - missing QUERYTABLESTRING record" );
+                if( bHasQTString )
+                {
+                    rStrm.skip( 4 );
+                    lclParseTables( rWebPr.maTables, rStrm.readUniString() );
+                }
+            }
+        }
+    }
+}
+
+// ============================================================================
+
+ConnectionsBuffer::ConnectionsBuffer( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper ),
+    mnUnusedId( 1 )
+{
+}
+
+Connection& ConnectionsBuffer::createConnection()
+{
+    ConnectionRef xConnection( new Connection( *this ) );
+    maConnections.push_back( xConnection );
+    return *xConnection;
+}
+
+Connection& ConnectionsBuffer::createConnectionWithId()
+{
+    ConnectionRef xConnection( new Connection( *this, mnUnusedId ) );
+    maConnections.push_back( xConnection );
+    insertConnectionToMap( xConnection );
+    return *xConnection;
+}
+
+void ConnectionsBuffer::finalizeImport()
+{
+    for( ConnectionVector::iterator aIt = maConnections.begin(), aEnd = maConnections.end(); aIt != aEnd; ++aIt )
+        insertConnectionToMap( *aIt );
+}
+
+ConnectionRef ConnectionsBuffer::getConnection( sal_Int32 nConnId ) const
+{
+    return maConnectionsById.get( nConnId );
+}
+
+void ConnectionsBuffer::insertConnectionToMap( const ConnectionRef& rxConnection )
+{
+    sal_Int32 nConnId = rxConnection->getConnectionId();
+    if( nConnId > 0 )
+    {
+        OSL_ENSURE( !maConnectionsById.has( nConnId ), "ConnectionsBuffer::insertConnectionToMap - multiple connection identifier" );
+        maConnectionsById[ nConnId ] = rxConnection;
+        mnUnusedId = ::std::max< sal_Int32 >( mnUnusedId, nConnId + 1 );
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/connectionsfragment.cxx b/sc/source/filter/oox/connectionsfragment.cxx
new file mode 100644
index 000000000000..23433c7c1ba2
--- /dev/null
+++ b/sc/source/filter/oox/connectionsfragment.cxx
@@ -0,0 +1,182 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "connectionsfragment.hxx"
+
+#include "oox/helper/attributelist.hxx"
+#include "biffhelper.hxx"
+#include "connectionsbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+ConnectionContext::ConnectionContext( WorkbookFragmentBase& rParent, Connection& rConnection ) :
+    WorkbookContextBase( rParent ),
+    mrConnection( rConnection )
+{
+}
+
+ContextHandlerRef ConnectionContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    switch( getCurrentElement() )
+    {
+        case XLS_TOKEN( connection ):
+            if( nElement == XLS_TOKEN( webPr ) )
+            {
+                mrConnection.importWebPr( rAttribs );
+                return this;
+            }
+        break;
+
+        case XLS_TOKEN( webPr ):
+            if( nElement == XLS_TOKEN( tables ) )
+            {
+                mrConnection.importTables( rAttribs );
+                return this;
+            }
+        break;
+
+        case XLS_TOKEN( tables ):
+            mrConnection.importTable( rAttribs, nElement );
+        break;
+    }
+    return 0;
+}
+
+void ConnectionContext::onStartElement( const AttributeList& rAttribs )
+{
+    if( getCurrentElement() == XLS_TOKEN( connection ) )
+        mrConnection.importConnection( rAttribs );
+}
+
+ContextHandlerRef ConnectionContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_CONNECTION:
+            if( nRecId == BIFF12_ID_WEBPR )
+            {
+                mrConnection.importWebPr( rStrm );
+                return this;
+            }
+        break;
+
+        case BIFF12_ID_WEBPR:
+            if( nRecId == BIFF12_ID_WEBPRTABLES )
+            {
+                mrConnection.importWebPrTables( rStrm );
+                return this;
+            }
+        break;
+
+        case BIFF12_ID_WEBPRTABLES:
+            mrConnection.importWebPrTable( rStrm, nRecId );
+        break;
+    }
+    return 0;
+}
+
+void ConnectionContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    if( getCurrentElement() == BIFF12_ID_CONNECTION )
+        mrConnection.importConnection( rStrm );
+}
+
+// ============================================================================
+
+ConnectionsFragment::ConnectionsFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+    WorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+ContextHandlerRef ConnectionsFragment::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 ):
+            if( nElement == XLS_TOKEN( connection ) )
+                return new ConnectionContext( *this, getConnections().createConnection() );
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef ConnectionsFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& /*rStrm*/ )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_CONNECTIONS )
+                return this;
+        break;
+
+        case BIFF12_ID_CONNECTIONS:
+            if( nRecId == BIFF12_ID_CONNECTION )
+                return new ConnectionContext( *this, getConnections().createConnection() );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* ConnectionsFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_CONNECTIONS,    BIFF12_ID_CONNECTIONS + 1   },
+        { BIFF12_ID_CONNECTION,     BIFF12_ID_CONNECTION + 1    },
+        { BIFF12_ID_WEBPR,          BIFF12_ID_WEBPR + 1         },
+        { BIFF12_ID_WEBPRTABLES,    BIFF12_ID_WEBPRTABLES + 1   },
+        { -1,                       -1                          }
+    };
+    return spRecInfos;
+}
+
+void ConnectionsFragment::finalizeImport()
+{
+    getConnections().finalizeImport();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/defnamesbuffer.cxx b/sc/source/filter/oox/defnamesbuffer.cxx
new file mode 100644
index 000000000000..ab0ed199a8f8
--- /dev/null
+++ b/sc/source/filter/oox/defnamesbuffer.cxx
@@ -0,0 +1,696 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "defnamesbuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "externallinkbuffer.hxx"
+#include "formulaparser.hxx"
+#include "worksheetbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt32 BIFF12_DEFNAME_HIDDEN      = 0x00000001;
+const sal_uInt32 BIFF12_DEFNAME_FUNC        = 0x00000002;
+const sal_uInt32 BIFF12_DEFNAME_VBNAME      = 0x00000004;
+const sal_uInt32 BIFF12_DEFNAME_MACRO       = 0x00000008;
+const sal_uInt32 BIFF12_DEFNAME_CALCEXP     = 0x00000010;
+const sal_uInt32 BIFF12_DEFNAME_BUILTIN     = 0x00000020;
+const sal_uInt32 BIFF12_DEFNAME_PUBLISHED   = 0x00008000;
+const sal_uInt32 BIFF12_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_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;
+
+// ----------------------------------------------------------------------------
+
+const sal_Char* const spcLegacyPrefix = "Excel_BuiltIn_";
+const sal_Char* const spcOoxPrefix = "_xlnm.";
+
+const sal_Char* const sppcBaseNames[] =
+{
+    "Consolidate_Area",
+    "Auto_Open",
+    "Auto_Close",
+    "Extract",
+    "Database",
+    "Criteria",
+    "Print_Area",
+    "Print_Titles",
+    "Recorder",
+    "Data_Form",
+    "Auto_Activate",
+    "Auto_Deactivate",
+    "Sheet_Title",
+    "_FilterDatabase"
+};
+
+/** 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 - unsupported built-in identifier" );
+    OUStringBuffer aBuffer;
+    if( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ) )
+        aBuffer.appendAscii( sppcBaseNames[ cBuiltinId ] );
+    else
+        aBuffer.append( static_cast< sal_Int32 >( cBuiltinId ) );
+    return aBuffer.makeStringAndClear();
+}
+
+OUString lclGetPrefixedName( sal_Unicode cBuiltinId )
+{
+    return OUStringBuffer().appendAscii( spcOoxPrefix ).append( lclGetBaseName( cBuiltinId ) ).makeStringAndClear();
+}
+
+/** returns the built-in name identifier from a perfixed built-in name, e.g. '_xlnm.Print_Area'. */
+sal_Unicode lclGetBuiltinIdFromPrefixedName( const OUString& rModelName )
+{
+    OUString aPrefix = OUString::createFromAscii( spcOoxPrefix );
+    sal_Int32 nPrefixLen = aPrefix.getLength();
+    if( rModelName.matchIgnoreAsciiCase( aPrefix ) )
+    {
+        for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId )
+        {
+            OUString aBaseName = lclGetBaseName( cBuiltinId );
+            sal_Int32 nBaseNameLen = aBaseName.getLength();
+            if( (rModelName.getLength() == nPrefixLen + nBaseNameLen) && rModelName.matchIgnoreAsciiCase( aBaseName, nPrefixLen ) )
+                return cBuiltinId;
+        }
+    }
+    return BIFF_DEFNAME_UNKNOWN;
+}
+
+/** returns the built-in name identifier from a built-in base name, e.g. 'Print_Area'. */
+sal_Unicode lclGetBuiltinIdFromBaseName( const OUString& rModelName )
+{
+    for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId )
+        if( rModelName.equalsIgnoreAsciiCaseAscii( sppcBaseNames[ cBuiltinId ] ) )
+            return cBuiltinId;
+    return BIFF_DEFNAME_UNKNOWN;
+}
+
+bool lclIsFilterDatabaseName( const OUString& rModelName )
+{
+    for( const sal_Char* const* ppcName = sppcFilterDbNames; ppcName < STATIC_ARRAY_END( sppcFilterDbNames ); ++ppcName )
+        if( rModelName.equalsIgnoreAsciiCaseAscii( *ppcName ) )
+            return true;
+    return false;
+}
+
+OUString lclGetUpcaseModelName( const OUString& rModelName )
+{
+    // TODO: i18n?
+    return rModelName.toAsciiUpperCase();
+}
+
+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& rBaseAddr, bool bColRel, bool bRowRel )
+{
+    using namespace ::com::sun::star::sheet::ReferenceFlags;
+    lclConvertRefFlags(
+        orApiRef.Flags, orApiRef.Column, orApiRef.RelativeColumn,
+        rBaseAddr.Column, COLUMN_RELATIVE, bColRel );
+    lclConvertRefFlags(
+        orApiRef.Flags, orApiRef.Row, orApiRef.RelativeRow,
+        rBaseAddr.Row, ROW_RELATIVE, bRowRel );
+}
+
+Any lclConvertReference( const Any& rRefAny, const CellAddress& rBaseAddr, sal_uInt16 nRelFlags )
+{
+    if( rRefAny.has< SingleReference >() && !getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ) && !getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) )
+    {
+        SingleReference aApiRef;
+        rRefAny >>= aApiRef;
+        lclConvertSingleRefFlags( aApiRef, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) );
+        return Any( aApiRef );
+    }
+    if( rRefAny.has< ComplexReference >() )
+    {
+        ComplexReference aApiRef;
+        rRefAny >>= aApiRef;
+        lclConvertSingleRefFlags( aApiRef.Reference1, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) );
+        lclConvertSingleRefFlags( aApiRef.Reference2, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) );
+        return Any( aApiRef );
+    }
+    return Any();
+}
+
+} // namespace
+
+// ============================================================================
+
+DefinedNameModel::DefinedNameModel() :
+    mnSheet( -1 ),
+    mnFuncGroupId( -1 ),
+    mbMacro( false ),
+    mbFunction( false ),
+    mbVBName( false ),
+    mbHidden( false )
+{
+}
+
+// ============================================================================
+
+DefinedNameBase::DefinedNameBase( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper )
+{
+}
+
+const OUString& DefinedNameBase::getUpcaseModelName() const
+{
+    if( maUpModelName.isEmpty() )
+        maUpModelName = lclGetUpcaseModelName( maModel.maName );
+    return maUpModelName;
+}
+
+Any DefinedNameBase::getReference( const CellAddress& rBaseAddr ) 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, rBaseAddr, nRelFlags );
+                if( aRefAny.hasValue() )
+                {
+                    aApiExtRef.Reference <<= aRefAny;
+                    return Any( aApiExtRef );
+                }
+            }
+            else
+            {
+                return lclConvertReference( maRefAny, rBaseAddr, nRelFlags );
+            }
+        }
+    }
+    return Any();
+}
+
+ApiTokenSequence DefinedNameBase::importOoxFormula( sal_Int16 nBaseSheet )
+{
+    return (!maModel.maFormula.isEmpty()) ?
+        getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), maModel.maFormula ) :
+        getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME );
+}
+
+ApiTokenSequence DefinedNameBase::importBiff12Formula( sal_Int16 nBaseSheet, SequenceInputStream& rStrm )
+{
+    return getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm );
+}
+
+ApiTokenSequence DefinedNameBase::importBiffFormula( sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
+{
+    return (!pnFmlaSize || (*pnFmlaSize > 0)) ?
+        getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm, pnFmlaSize ) :
+        getFormulaParser().convertErrorToFormula( 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( BIFF_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 );
+    mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1;
+
+    /*  Detect built-in state from name itself, there is no built-in flag.
+        Built-in names are prexixed with '_xlnm.' instead. */
+    mcBuiltinId = lclGetBuiltinIdFromPrefixedName( maModel.maName );
+}
+
+void DefinedName::setFormula( const OUString& rFormula )
+{
+    maModel.maFormula = rFormula;
+}
+
+void DefinedName::importDefinedName( SequenceInputStream& 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, BIFF12_DEFNAME_MACRO );
+    maModel.mbFunction    = getFlag( nFlags, BIFF12_DEFNAME_FUNC );
+    maModel.mbVBName      = getFlag( nFlags, BIFF12_DEFNAME_VBNAME );
+    maModel.mbHidden      = getFlag( nFlags, BIFF12_DEFNAME_HIDDEN );
+
+    // get built-in name index from name
+    if( getFlag( nFlags, BIFF12_DEFNAME_BUILTIN ) )
+        mcBuiltinId = lclGetBuiltinIdFromBaseName( maModel.maName );
+
+    // 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 built-in name index from name
+    if( getFlag( nFlags, BIFF_DEFNAME_BUILTIN ) )
+    {
+        // name may be the built-in identifier or the built-in base name
+        if( maModel.maName.getLength() == 1 )
+            mcBuiltinId = maModel.maName[ 0 ];
+        else
+            mcBuiltinId = lclGetBuiltinIdFromBaseName( maModel.maName );
+    }
+    /*  In BIFF5, '_FilterDatabase' appears as hidden user name without
+        built-in flag, and even worse, localized. */
+    else if( (eBiff == BIFF5) && lclIsFilterDatabaseName( maModel.maName ) )
+    {
+        mcBuiltinId = BIFF_DEFNAME_FILTERDATABASE;
+    }
+
+    // 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. */
+        ApiTokenSequence aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize );
+        extractReference( aTokens );
+    }
+    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 or VBA procedures
+    // #163146# do not ignore hidden names (may be regular names created by VBA scripts)
+    if( /*maModel.mbHidden ||*/ maModel.mbFunction || maModel.mbVBName )
+        return;
+
+    // skip BIFF names without stream position (e.g. BIFF3-BIFF4 internal 3D references)
+    if( (getFilterType() == FILTER_BIFF) && !mxBiffStrm.get() )
+        return;
+
+    // convert original name to final Calc name (TODO: filter invalid characters from model name)
+    maCalcName = isBuiltinName() ? lclGetPrefixedName( mcBuiltinId ) : maModel.maName;
+
+    // #163146# do not rename sheet-local names by default, this breaks VBA scripts
+
+    // special flags for this name
+    sal_Int32 nNameFlags = 0;
+    using namespace ::com::sun::star::sheet::NamedRangeFlag;
+    if( !isGlobalName() ) switch( mcBuiltinId )
+    {
+        case BIFF_DEFNAME_CRITERIA:     nNameFlags = FILTER_CRITERIA;               break;
+        case BIFF_DEFNAME_PRINTAREA:    nNameFlags = PRINT_AREA;                    break;
+        case BIFF_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
+    if (maModel.mnSheet >= 0)
+        mxNamedRange = createLocalNamedRangeObject( maCalcName, nNameFlags, maModel.mnSheet );
+    else
+        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() )
+        return;
+
+    // convert and set formula of the defined name
+    ApiTokenSequence aTokens;
+    switch( getFilterType() )
+    {
+        case FILTER_OOXML:
+        {
+            if( mxFormula.get() )
+            {
+                SequenceInputStream aStrm( *mxFormula );
+                aTokens = importBiff12Formula( mnCalcSheet, aStrm );
+            }
+            else
+                aTokens = importOoxFormula( mnCalcSheet );
+        }
+        break;
+        case FILTER_BIFF:
+        {
+            OSL_ENSURE( mxBiffStrm.get(), "DefinedName::convertFormula - missing BIFF stream" );
+            if( mxBiffStrm.get() )
+            {
+                BiffInputStream& rStrm = mxBiffStrm->getStream();
+                BiffInputStreamPosGuard aStrmGuard( rStrm );
+                if( mxBiffStrm->restorePosition() )
+                    aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize );
+            }
+        }
+        break;
+        case FILTER_UNKNOWN:
+        break;
+    }
+    xTokens->setTokens( aTokens );
+
+    // set built-in names (print ranges, repeated titles, filter ranges)
+    if( !isGlobalName() ) switch( mcBuiltinId )
+    {
+        case BIFF_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 BIFF_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 );
+}
+
+// ============================================================================
+
+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( SequenceInputStream& 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, and insert them into the maps
+    for( DefNameVector::iterator aIt = maDefNames.begin(), aEnd = maDefNames.end(); aIt != aEnd; ++aIt )
+    {
+        DefinedNameRef xDefName = *aIt;
+        xDefName->createNameObject();
+        // map by sheet index and original model name
+        maModelNameMap[ SheetNameKey( xDefName->getLocalCalcSheet(), xDefName->getUpcaseModelName() ) ] = xDefName;
+        // map by sheet index and built-in identifier
+        if( !xDefName->isGlobalName() && xDefName->isBuiltinName() )
+            maBuiltinMap[ BuiltinKey( xDefName->getLocalCalcSheet(), xDefName->getBuiltinId() ) ] = xDefName;
+        // map by API formula token identifier
+        sal_Int32 nTokenIndex = xDefName->getTokenIndex();
+        if( nTokenIndex >= 0 )
+            maTokenIdMap[ 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 maTokenIdMap.get( nIndex );
+}
+
+DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, sal_Int16 nCalcSheet ) const
+{
+    OUString aUpcaseName = lclGetUpcaseModelName( rModelName );
+    DefinedNameRef xDefName = maModelNameMap.get( SheetNameKey( nCalcSheet, aUpcaseName ) );
+    // lookup global name, if no local name exists
+    if( !xDefName && (nCalcSheet >= 0) )
+        xDefName = maModelNameMap.get( SheetNameKey( -1, aUpcaseName ) );
+    return xDefName;
+}
+
+DefinedNameRef DefinedNamesBuffer::getByBuiltinId( sal_Unicode cBuiltinId, sal_Int16 nCalcSheet ) const
+{
+    return maBuiltinMap.get( BuiltinKey( nCalcSheet, cBuiltinId ) );
+}
+
+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/sc/source/filter/oox/drawingbase.cxx b/sc/source/filter/oox/drawingbase.cxx
new file mode 100644
index 000000000000..376476cc7ffe
--- /dev/null
+++ b/sc/source/filter/oox/drawingbase.cxx
@@ -0,0 +1,355 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "drawingbase.hxx"
+
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+#include "unitconverter.hxx"
+#include "oox/helper/propertyset.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::table;
+using namespace ::oox::drawingml;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+namespace {
+
+/** Converts the passed 32-bit integer value from 1/100 mm to EMUs. */
+inline sal_Int64 lclHmmToEmu( sal_Int32 nValue )
+{
+    return (nValue < 0) ? -1 : convertHmmToEmu( nValue );
+}
+
+/** Converts the passed 64-bit integer value from EMUs to 1/100 mm. */
+inline sal_Int32 lclEmuToHmm( sal_Int64 nValue )
+{
+    return (nValue < 0) ? -1 : convertEmuToHmm( nValue );
+}
+
+/** Reads the cell anchor model from a BIFF or DFF stream. */
+BinaryInputStream& operator>>( BinaryInputStream& rStrm, CellAnchorModel& rModel )
+{
+    // all members are given as 16-bit unsigned values
+    rModel.mnCol = rStrm.readuInt16();
+    rModel.mnColOffset = rStrm.readuInt16();
+    rModel.mnRow = rStrm.readuInt16();
+    rModel.mnRowOffset = rStrm.readuInt16();
+    return rStrm;
+}
+
+} // namespace
+
+// ============================================================================
+
+CellAnchorModel::CellAnchorModel() :
+    mnCol( -1 ),
+    mnRow( -1 ),
+    mnColOffset( 0 ),
+    mnRowOffset( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+AnchorClientDataModel::AnchorClientDataModel() :
+    mbLocksWithSheet( true ),
+    mbPrintsWithSheet( true )
+{
+}
+
+// ============================================================================
+
+ShapeAnchor::ShapeAnchor( const WorksheetHelper& rHelper ) :
+    WorksheetHelper( rHelper ),
+    meAnchorType( ANCHOR_INVALID ),
+    meCellAnchorType( CELLANCHOR_EMU ),
+    mnEditAs( XML_twoCell )
+{
+}
+
+void ShapeAnchor::importAnchor( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    switch( nElement )
+    {
+        case XDR_TOKEN( absoluteAnchor ):
+            meAnchorType = ANCHOR_ABSOLUTE;
+        break;
+        case XDR_TOKEN( oneCellAnchor ):
+            meAnchorType = ANCHOR_ONECELL;
+        break;
+        case XDR_TOKEN( twoCellAnchor ):
+            meAnchorType = ANCHOR_TWOCELL;
+            mnEditAs = rAttribs.getToken( XML_editAs, XML_twoCell );
+        break;
+        default:
+            OSL_ENSURE( false, "ShapeAnchor::importAnchor - unexpected element" );
+    }
+    meCellAnchorType = CELLANCHOR_EMU;
+}
+
+void ShapeAnchor::importPos( const AttributeList& rAttribs )
+{
+    OSL_ENSURE( meAnchorType == 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( (meAnchorType == ANCHOR_ABSOLUTE) || (meAnchorType == 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 )
+{
+    CellAnchorModel* pCellAnchor = 0;
+    switch( nParentContext )
+    {
+        case XDR_TOKEN( from ):
+            OSL_ENSURE( (meAnchorType == ANCHOR_ONECELL) || (meAnchorType == ANCHOR_TWOCELL), "ShapeAnchor::setCellPos - unexpected 'xdr:from' element" );
+            pCellAnchor = &maFrom;
+        break;
+        case XDR_TOKEN( to ):
+            OSL_ENSURE( meAnchorType == ANCHOR_TWOCELL, "ShapeAnchor::setCellPos - unexpected 'xdr:to' element" );
+            pCellAnchor = &maTo;
+        break;
+        default:
+            OSL_ENSURE( false, "ShapeAnchor::setCellPos - unexpected parent element" );
+    }
+    if( pCellAnchor ) switch( nElement )
+    {
+        case XDR_TOKEN( col ):      pCellAnchor->mnCol = rValue.toInt32();          break;
+        case XDR_TOKEN( row ):      pCellAnchor->mnRow = rValue.toInt32();          break;
+        case XDR_TOKEN( colOff ):   pCellAnchor->mnColOffset = rValue.toInt64();    break;
+        case XDR_TOKEN( rowOff ):   pCellAnchor->mnRowOffset = rValue.toInt64();    break;
+        default:    OSL_ENSURE( false, "ShapeAnchor::setCellPos - unexpected element" );
+    }
+}
+
+void ShapeAnchor::importVmlAnchor( const OUString& rAnchor )
+{
+    meAnchorType = 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();
+    }
+}
+
+void ShapeAnchor::importBiffAnchor( BinaryInputStream& rStrm )
+{
+    meAnchorType = ANCHOR_TWOCELL;          /// BIFF/DFF use two-cell anchors only
+    meCellAnchorType = CELLANCHOR_COLROW;   /// BIFF/DFF use fraction of column/row for offset values
+    rStrm >> maFrom >> maTo;
+}
+
+EmuRectangle ShapeAnchor::calcAnchorRectEmu( const Size& rPageSizeHmm ) const
+{
+    AddressConverter& rAddrConv = getAddressConverter();
+    EmuSize aPageSize( lclHmmToEmu( rPageSizeHmm.Width ), lclHmmToEmu( rPageSizeHmm.Height ) );
+    EmuRectangle aAnchorRect( -1, -1, -1, -1 );
+
+    // calculate shape position
+    switch( meAnchorType )
+    {
+        case ANCHOR_ABSOLUTE:
+            OSL_ENSURE( maPos.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
+            if( maPos.isValid() && (maPos.X < aPageSize.Width) && (maPos.Y < aPageSize.Height) )
+                aAnchorRect.setPos( maPos );
+        break;
+        case ANCHOR_ONECELL:
+        case ANCHOR_TWOCELL:
+        case ANCHOR_VML:
+            OSL_ENSURE( maFrom.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
+            if( maFrom.isValid() && rAddrConv.checkCol( maFrom.mnCol, true ) && rAddrConv.checkRow( maFrom.mnRow, true ) )
+            {
+                EmuPoint aPoint = calcCellAnchorEmu( maFrom );
+                if( (aPoint.X < aPageSize.Width) && (aPoint.Y < aPageSize.Height) )
+                    aAnchorRect.setPos( aPoint );
+            }
+        break;
+        case ANCHOR_INVALID:
+            OSL_ENSURE( false, "ShapeAnchor::calcAnchorRectEmu - invalid anchor" );
+        break;
+    }
+
+    // calculate shape size
+    if( (aAnchorRect.X >= 0) && (aAnchorRect.Y >= 0) ) switch( meAnchorType )
+    {
+        case ANCHOR_ABSOLUTE:
+        case ANCHOR_ONECELL:
+            OSL_ENSURE( maSize.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid size" );
+            if( maSize.isValid() )
+            {
+                aAnchorRect.Width = ::std::min< sal_Int64 >( maSize.Width, aPageSize.Width - aAnchorRect.X );
+                aAnchorRect.Height = ::std::min< sal_Int64 >( maSize.Height, aPageSize.Height - aAnchorRect.Y );
+            }
+        break;
+        case ANCHOR_TWOCELL:
+        case ANCHOR_VML:
+            OSL_ENSURE( maTo.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
+            if( maTo.isValid() )
+            {
+                /*  Pass a valid cell address to calcCellAnchorEmu(), otherwise
+                    nothing useful is returned, even if either row or column is valid. */
+                CellAddress aToCell = rAddrConv.createValidCellAddress( BinAddress( maTo.mnCol, maTo.mnRow ), getSheetIndex(), true );
+                CellAnchorModel aValidTo = maTo;
+                aValidTo.mnCol = aToCell.Column;
+                aValidTo.mnRow = aToCell.Row;
+                EmuPoint aPoint = calcCellAnchorEmu( aValidTo );
+                // width (if column index is valid, use the calculated offset, otherwise stretch to maximum available X position)
+                aAnchorRect.Width = aPageSize.Width - aAnchorRect.X;
+                if( aToCell.Column == maTo.mnCol )
+                    aAnchorRect.Width = ::std::min< sal_Int64 >( aPoint.X - aAnchorRect.X + 1, aAnchorRect.Width );
+                // height (if row index is valid, use the calculated offset, otherwise stretch to maximum available Y position)
+                aAnchorRect.Height = aPageSize.Height - aAnchorRect.Y;
+                if( aToCell.Row == maTo.mnRow )
+                    aAnchorRect.Height = ::std::min< sal_Int64 >( aPoint.Y - aAnchorRect.Y + 1, aAnchorRect.Height );
+            }
+        break;
+        case ANCHOR_INVALID:
+        break;
+    }
+
+    // add 0.75 mm (27,000 EMUs) in X direction to correct display error
+    if( aAnchorRect.X >= 0 )
+        aAnchorRect.X += 27000;
+    // remove 0.25 mm (9,000 EMUs) in Y direction to correct display error
+    if( aAnchorRect.Y >= 9000 )
+        aAnchorRect.Y -= 9000;
+
+    return aAnchorRect;
+}
+
+Rectangle ShapeAnchor::calcAnchorRectHmm( const Size& rPageSizeHmm ) const
+{
+    EmuRectangle aAnchorRect = calcAnchorRectEmu( rPageSizeHmm );
+    return Rectangle( lclEmuToHmm( aAnchorRect.X ), lclEmuToHmm( aAnchorRect.Y ), lclEmuToHmm( aAnchorRect.Width ), lclEmuToHmm( aAnchorRect.Height ) );
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >
+ShapeAnchor::getFromCell() const
+{
+    CellAddress aAddress;
+    aAddress.Sheet = getSheetIndex();
+    aAddress.Row = maFrom.mnRow;
+    aAddress.Column = maFrom.mnCol;
+    return getCell( aAddress );
+}
+
+void
+ShapeAnchor::applyToXShape( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape>& rxShape )
+{
+    if ( ( meAnchorType == ANCHOR_TWOCELL || meAnchorType ==  ANCHOR_ONECELL ) && getFromCell().is() )
+    {
+        PropertySet aShapeProp( rxShape );
+        aShapeProp.setProperty( PROP_Anchor, getFromCell() );
+        CellAnchorModel offSets;
+        offSets.mnColOffset = maFrom.mnColOffset;
+        offSets.mnRowOffset = maFrom.mnRowOffset;
+        EmuPoint aPos = calcCellAnchorEmu( offSets );
+        aShapeProp.setProperty( PROP_HoriOrientPosition, lclEmuToHmm( aPos.X ) );
+        aShapeProp.setProperty( PROP_VertOrientPosition, lclEmuToHmm( aPos.Y ) );
+    }
+}
+
+// private --------------------------------------------------------------------
+
+EmuPoint ShapeAnchor::calcCellAnchorEmu( const CellAnchorModel& rModel ) const
+{
+    // calculate position of top-left edge of the cell
+    Point aPoint = getCellPosition( rModel.mnCol, rModel.mnRow );
+    EmuPoint aEmuPoint( lclHmmToEmu( aPoint.X ), lclHmmToEmu( aPoint.Y ) );
+
+    // add the offset inside the cell
+    switch( meCellAnchorType )
+    {
+        case CELLANCHOR_EMU:
+            aEmuPoint.X += rModel.mnColOffset;
+            aEmuPoint.Y += rModel.mnRowOffset;
+        break;
+
+        case CELLANCHOR_PIXEL:
+        {
+            const UnitConverter& rUnitConv = getUnitConverter();
+            aEmuPoint.X += static_cast< sal_Int64 >( rUnitConv.scaleValue( static_cast< double >( rModel.mnColOffset ), UNIT_SCREENX, UNIT_EMU ) );
+            aEmuPoint.Y += static_cast< sal_Int64 >( rUnitConv.scaleValue( static_cast< double >( rModel.mnRowOffset ), UNIT_SCREENY, UNIT_EMU ) );
+        }
+        break;
+
+        case CELLANCHOR_COLROW:
+        {
+            Size aCellSize = getCellSize( rModel.mnCol, rModel.mnRow );
+            EmuSize aEmuSize( lclHmmToEmu( aCellSize.Width ), lclHmmToEmu( aCellSize.Height ) );
+            // X offset is given in 1/1024 of column width
+            aEmuPoint.X += static_cast< sal_Int64 >( aEmuSize.Width * getLimitedValue< double >( static_cast< double >( rModel.mnColOffset ) / 1024.0, 0.0, 1.0 ) + 0.5 );
+            // Y offset is given in 1/256 of row height
+            aEmuPoint.Y += static_cast< sal_Int64 >( aEmuSize.Height * getLimitedValue< double >( static_cast< double >( rModel.mnRowOffset ) / 256.0, 0.0, 1.0 ) + 0.5 );
+        }
+        break;
+    }
+
+    return aEmuPoint;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/drawingfragment.cxx b/sc/source/filter/oox/drawingfragment.cxx
new file mode 100644
index 000000000000..f04128762507
--- /dev/null
+++ b/sc/source/filter/oox/drawingfragment.cxx
@@ -0,0 +1,772 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "drawingfragment.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/drawingml/connectorshapecontext.hxx"
+#include "oox/drawingml/graphicshapecontext.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/vml/vmlshape.hxx"
+#include "oox/vml/vmlshapecontainer.hxx"
+#include "formulaparser.hxx"
+#include "stylesbuffer.hxx"
+#include "themebuffer.hxx"
+#include "unitconverter.hxx"
+
+namespace oox {
+namespace xls {
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::oox::core;
+using namespace ::oox::drawingml;
+using namespace ::oox::ole;
+
+using ::rtl::OStringBuffer;
+using ::rtl::OUString;
+using ::rtl::OUStringToOString;
+// no using's for ::oox::vml, that may clash with ::oox::drawingml types
+
+// ============================================================================
+
+ShapeMacroAttacher::ShapeMacroAttacher( const OUString& rMacroName, const Reference< XShape >& rxShape ) :
+    VbaMacroAttacherBase( rMacroName ),
+    mxShape( rxShape )
+{
+}
+
+void ShapeMacroAttacher::attachMacro( const OUString& rMacroUrl )
+{
+    try
+    {
+        Reference< XEventsSupplier > xSupplier( mxShape, UNO_QUERY_THROW );
+        Reference< XNameReplace > xEvents( xSupplier->getEvents(), UNO_SET_THROW );
+        Sequence< PropertyValue > aEventProps( 2 );
+        aEventProps[ 0 ].Name = CREATE_OUSTRING( "EventType" );
+        aEventProps[ 0 ].Value <<= CREATE_OUSTRING( "Script" );
+        aEventProps[ 1 ].Name = CREATE_OUSTRING( "Script" );
+        aEventProps[ 1 ].Value <<= rMacroUrl;
+        xEvents->replaceByName( CREATE_OUSTRING( "OnClick" ), Any( aEventProps ) );
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+// ============================================================================
+
+Shape::Shape( const WorksheetHelper& rHelper, const AttributeList& rAttribs, const sal_Char* pcServiceName ) :
+    ::oox::drawingml::Shape( pcServiceName ),
+    WorksheetHelper( rHelper )
+{
+    OUString aMacro = rAttribs.getXString( XML_macro, OUString() );
+    if( !aMacro.isEmpty() )
+        maMacroName = getFormulaParser().importMacroName( aMacro );
+}
+
+void Shape::finalizeXShape( XmlFilterBase& rFilter, const Reference< XShapes >& rxShapes )
+{
+    if( !maMacroName.isEmpty() && mxShape.is() )
+    {
+        VbaMacroAttacherRef xAttacher( new ShapeMacroAttacher( maMacroName, mxShape ) );
+        getBaseFilter().getVbaProject().registerMacroAttacher( xAttacher );
+    }
+    ::oox::drawingml::Shape::finalizeXShape( rFilter, rxShapes );
+}
+
+// ============================================================================
+
+GroupShapeContext::GroupShapeContext( ContextHandler& rParent,
+        const WorksheetHelper& rHelper, const ShapePtr& rxParentShape, const ShapePtr& rxShape ) :
+    ShapeGroupContext( rParent, rxParentShape, rxShape ),
+    WorksheetHelper( rHelper )
+{
+}
+
+/*static*/ ContextHandlerRef GroupShapeContext::createShapeContext( ContextHandler& rParent,
+        const WorksheetHelper& rHelper, sal_Int32 nElement, const AttributeList& rAttribs,
+        const ShapePtr& rxParentShape, ShapePtr* pxShape )
+{
+    switch( nElement )
+    {
+        case XDR_TOKEN( sp ):
+        {
+            ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.CustomShape" ) );
+            if( pxShape ) *pxShape = xShape;
+            return new ShapeContext( rParent, rxParentShape, xShape );
+        }
+        case XDR_TOKEN( cxnSp ):
+        {
+            ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.ConnectorShape" ) );
+            if( pxShape ) *pxShape = xShape;
+            return new ConnectorShapeContext( rParent, rxParentShape, xShape );
+        }
+        case XDR_TOKEN( pic ):
+        {
+            ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.GraphicObjectShape" ) );
+            if( pxShape ) *pxShape = xShape;
+            return new GraphicShapeContext( rParent, rxParentShape, xShape );
+        }
+        case XDR_TOKEN( graphicFrame ):
+        {
+            ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.GraphicObjectShape" ) );
+            if( pxShape ) *pxShape = xShape;
+            return new GraphicalObjectFrameContext( rParent, rxParentShape, xShape, rHelper.getSheetType() != SHEETTYPE_CHARTSHEET );
+        }
+        case XDR_TOKEN( grpSp ):
+        {
+            ShapePtr xShape( new Shape( rHelper, rAttribs, "com.sun.star.drawing.GroupShape" ) );
+            if( pxShape ) *pxShape = xShape;
+            return new GroupShapeContext( rParent, rHelper, rxParentShape, xShape );
+        }
+    }
+    return 0;
+}
+
+Reference< XFastContextHandler > SAL_CALL GroupShapeContext::createFastChildContext(
+        sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs ) throw (SAXException, RuntimeException)
+{
+    ContextHandlerRef xContext = createShapeContext( *this, *this, nElement, AttributeList( rxAttribs ), mpGroupShapePtr );
+    return xContext.get() ? xContext.get() : ShapeGroupContext::createFastChildContext( nElement, rxAttribs );
+}
+
+// ============================================================================
+
+DrawingFragment::DrawingFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    WorksheetFragmentBase( rHelper, rFragmentPath ),
+    mxDrawPage( rHelper.getDrawPage(), UNO_QUERY )
+{
+    OSL_ENSURE( mxDrawPage.is(), "DrawingFragment::DrawingFragment - missing drawing page" );
+}
+
+ContextHandlerRef DrawingFragment::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( 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;
+
+                default:                        return GroupShapeContext::createShapeContext( *this, *this, nElement, rAttribs, ShapePtr(), &mxShape );
+            }
+        }
+        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 onCharacters()
+            }
+        break;
+    }
+    return 0;
+}
+
+void DrawingFragment::onCharacters( 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(), getParentElement(), rChars );
+        break;
+    }
+}
+
+void DrawingFragment::onEndElement()
+{
+    switch( getCurrentElement() )
+    {
+        case XDR_TOKEN( absoluteAnchor ):
+        case XDR_TOKEN( oneCellAnchor ):
+        case XDR_TOKEN( twoCellAnchor ):
+            if( mxDrawPage.is() && mxShape.get() && mxAnchor.get() )
+            {
+                EmuRectangle aShapeRectEmu = mxAnchor->calcAnchorRectEmu( getDrawPageSize() );
+                if( (aShapeRectEmu.X >= 0) && (aShapeRectEmu.Y >= 0) && (aShapeRectEmu.Width >= 0) && (aShapeRectEmu.Height >= 0) )
+                {
+                    // TODO: DrawingML implementation expects 32-bit coordinates for EMU rectangles (change that to EmuRectangle)
+                    Rectangle aShapeRectEmu32(
+                        getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.X, 0, SAL_MAX_INT32 ),
+                        getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Y, 0, SAL_MAX_INT32 ),
+                        getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Width, 0, SAL_MAX_INT32 ),
+                        getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Height, 0, SAL_MAX_INT32 ) );
+
+                    // Make sure to set the position and size *before* calling addShape().
+                    mxShape->setPosition(Point(aShapeRectEmu.X, aShapeRectEmu.Y));
+                    mxShape->setSize(Size(aShapeRectEmu.Width, aShapeRectEmu.Height));
+
+                    basegfx::B2DHomMatrix aTransformation;
+                    mxShape->addShape( getOoxFilter(), &getTheme(), mxDrawPage, aTransformation, &aShapeRectEmu32 );
+                    // apply Cell anchoring if necessary
+                    mxAnchor->applyToXShape( mxShape->getXShape() );
+                    /*  Collect all shape positions in the WorksheetHelper base
+                        class. But first, scale EMUs to 1/100 mm. */
+                    Rectangle aShapeRectHmm(
+                        convertEmuToHmm( aShapeRectEmu.X ), convertEmuToHmm( aShapeRectEmu.Y ),
+                        convertEmuToHmm( aShapeRectEmu.Width ), convertEmuToHmm( aShapeRectEmu.Height ) );
+                    extendShapeBoundingBox( aShapeRectHmm );
+                }
+            }
+            mxShape.reset();
+            mxAnchor.reset();
+        break;
+    }
+}
+
+// ============================================================================
+// VML
+// ============================================================================
+
+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::ClientData* pClientData = rShape.getClientData();
+    return pClientData && (pClientData->mnCol == mnCol) && (pClientData->mnRow == mnRow);
+}
+
+} // namespace
+
+// ============================================================================
+
+VmlControlMacroAttacher::VmlControlMacroAttacher( const OUString& rMacroName,
+        const Reference< XIndexContainer >& rxCtrlFormIC, sal_Int32 nCtrlIndex, sal_Int32 nCtrlType, sal_Int32 nDropStyle ) :
+    VbaMacroAttacherBase( rMacroName ),
+    mxCtrlFormIC( rxCtrlFormIC ),
+    mnCtrlIndex( nCtrlIndex ),
+    mnCtrlType( nCtrlType ),
+    mnDropStyle( nDropStyle )
+{
+}
+
+void VmlControlMacroAttacher::attachMacro( const OUString& rMacroUrl )
+{
+    ScriptEventDescriptor aEventDesc;
+    aEventDesc.ScriptType = CREATE_OUSTRING( "Script" );
+    aEventDesc.ScriptCode = rMacroUrl;
+
+    // editable drop downs are treated like edit boxes
+    bool bEditDropDown = (mnCtrlType == XML_Drop) && (mnDropStyle == XML_ComboEdit);
+    sal_Int32 nCtrlType = bEditDropDown ? XML_Edit : mnCtrlType;
+
+    switch( nCtrlType )
+    {
+        case XML_Button:
+        case XML_Checkbox:
+        case XML_Radio:
+            aEventDesc.ListenerType = CREATE_OUSTRING( "XActionListener" );
+            aEventDesc.EventMethod = CREATE_OUSTRING( "actionPerformed" );
+        break;
+        case XML_Label:
+        case XML_GBox:
+        case XML_Dialog:
+            aEventDesc.ListenerType = CREATE_OUSTRING( "XMouseListener" );
+            aEventDesc.EventMethod = CREATE_OUSTRING( "mouseReleased" );
+        break;
+        case XML_Edit:
+            aEventDesc.ListenerType = CREATE_OUSTRING( "XTextListener" );
+            aEventDesc.EventMethod = CREATE_OUSTRING( "textChanged" );
+        break;
+        case XML_Spin:
+        case XML_Scroll:
+            aEventDesc.ListenerType = CREATE_OUSTRING( "XAdjustmentListener" );
+            aEventDesc.EventMethod = CREATE_OUSTRING( "adjustmentValueChanged" );
+        break;
+        case XML_List:
+        case XML_Drop:
+            aEventDesc.ListenerType = CREATE_OUSTRING( "XChangeListener" );
+            aEventDesc.EventMethod = CREATE_OUSTRING( "changed" );
+        break;
+        default:
+            OSL_ENSURE( false, "VmlControlMacroAttacher::attachMacro - unexpected object type" );
+            return;
+    }
+
+    try
+    {
+        Reference< XEventAttacherManager > xEventMgr( mxCtrlFormIC, UNO_QUERY_THROW );
+        xEventMgr->registerScriptEvent( mnCtrlIndex, aEventDesc );
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+// ============================================================================
+
+VmlDrawing::VmlDrawing( const WorksheetHelper& rHelper ) :
+    ::oox::vml::Drawing( rHelper.getOoxFilter(), rHelper.getDrawPage(), ::oox::vml::VMLDRAWING_EXCEL ),
+    WorksheetHelper( rHelper ),
+    maControlConv( rHelper.getBaseFilter().getModel(), rHelper.getBaseFilter().getGraphicHelper() )
+{
+    // default font for legacy listboxes and dropdowns: Tahoma, 8pt
+    maListBoxFont.moName = CREATE_OUSTRING( "Tahoma" );
+    maListBoxFont.moColor = CREATE_OUSTRING( "auto" );
+    maListBoxFont.monSize = 160;
+}
+
+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::ClientData* pClientData = rShape.getClientData();
+    return !pClientData || (pClientData->mnObjType != XML_Note);
+}
+
+OUString VmlDrawing::getShapeBaseName( const ::oox::vml::ShapeBase& rShape ) const
+{
+    if( const ::oox::vml::ClientData* pClientData = rShape.getClientData() )
+    {
+        switch( pClientData->mnObjType )
+        {
+            case XML_Button:    return CREATE_OUSTRING( "Button" );
+            case XML_Checkbox:  return CREATE_OUSTRING( "Check Box" );
+            case XML_Dialog:    return CREATE_OUSTRING( "Dialog Frame" );
+            case XML_Drop:      return CREATE_OUSTRING( "Drop Down" );
+            case XML_Edit:      return CREATE_OUSTRING( "Edit Box" );
+            case XML_GBox:      return CREATE_OUSTRING( "Group Box" );
+            case XML_Label:     return CREATE_OUSTRING( "Label" );
+            case XML_List:      return CREATE_OUSTRING( "List Box" );
+            case XML_Note:      return CREATE_OUSTRING( "Comment" );
+            case XML_Pict:      return (pClientData->mbDde || getOleObjectInfo( rShape.getShapeId() )) ? CREATE_OUSTRING( "Object" ) : CREATE_OUSTRING( "Picture" );
+            case XML_Radio:     return CREATE_OUSTRING( "Option Button" );
+            case XML_Scroll:    return CREATE_OUSTRING( "Scroll Bar" );
+            case XML_Spin:      return CREATE_OUSTRING( "Spinner" );
+        }
+    }
+    return ::oox::vml::Drawing::getShapeBaseName( rShape );
+}
+
+bool VmlDrawing::convertClientAnchor( Rectangle& orShapeRect, const OUString& rShapeAnchor ) const
+{
+    if( rShapeAnchor.isEmpty() )
+        return false;
+    ShapeAnchor aAnchor( *this );
+    aAnchor.importVmlAnchor( rShapeAnchor );
+    orShapeRect = aAnchor.calcAnchorRectHmm( getDrawPageSize() );
+    return (orShapeRect.Width >= 0) && (orShapeRect.Height >= 0);
+}
+
+Reference< XShape > VmlDrawing::createAndInsertClientXShape( const ::oox::vml::ShapeBase& rShape,
+        const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
+{
+    // simulate the legacy drawing controls with OLE form controls
+    OUString aShapeName = rShape.getShapeName();
+    const ::oox::vml::ClientData* pClientData = rShape.getClientData();
+    if( !aShapeName.isEmpty() && pClientData )
+    {
+        Rectangle aShapeRect = rShapeRect;
+        const ::oox::vml::TextBox* pTextBox = rShape.getTextBox();
+        EmbeddedControl aControl( aShapeName );
+        switch( pClientData->mnObjType )
+        {
+            case XML_Button:
+            {
+                AxCommandButtonModel& rAxModel = aControl.createModel< AxCommandButtonModel >();
+                convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
+                rAxModel.mnFlags = AX_FLAGS_ENABLED | AX_FLAGS_OPAQUE | AX_FLAGS_WORDWRAP;
+                rAxModel.mnVerticalAlign = pClientData->mnTextVAlign;
+            }
+            break;
+
+            case XML_Label:
+            {
+                AxLabelModel& rAxModel = aControl.createModel< AxLabelModel >();
+                convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
+                rAxModel.mnFlags = AX_FLAGS_ENABLED | AX_FLAGS_WORDWRAP;
+                rAxModel.mnBorderStyle = AX_BORDERSTYLE_NONE;
+                rAxModel.mnSpecialEffect = AX_SPECIALEFFECT_FLAT;
+                rAxModel.mnVerticalAlign = pClientData->mnTextVAlign;
+            }
+            break;
+
+            case XML_Edit:
+            {
+                bool bNumeric = (pClientData->mnVTEdit == ::oox::vml::VML_CLIENTDATA_INTEGER) || (pClientData->mnVTEdit == ::oox::vml::VML_CLIENTDATA_NUMBER);
+                AxMorphDataModelBase& rAxModel = bNumeric ?
+                    static_cast< AxMorphDataModelBase& >( aControl.createModel< AxNumericFieldModel >() ) :
+                    static_cast< AxMorphDataModelBase& >( aControl.createModel< AxTextBoxModel >() );
+                convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maValue, pTextBox, pClientData->mnTextHAlign );
+                setFlag( rAxModel.mnFlags, AX_FLAGS_MULTILINE, pClientData->mbMultiLine );
+                setFlag( rAxModel.mnScrollBars, AX_SCROLLBAR_VERTICAL, pClientData->mbVScroll );
+                if( pClientData->mbSecretEdit )
+                    rAxModel.mnPasswordChar = '*';
+            }
+            break;
+
+            case XML_GBox:
+            {
+                AxFrameModel& rAxModel = aControl.createModel< AxFrameModel >();
+                convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
+                rAxModel.mnBorderStyle = pClientData->mbNo3D ? AX_BORDERSTYLE_SINGLE : AX_BORDERSTYLE_NONE;
+                rAxModel.mnSpecialEffect = pClientData->mbNo3D ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_BUMPED;
+
+                /*  Move top border of groupbox up by half font height, because
+                    Excel specifies Y position of the groupbox border line
+                    instead the top border of the caption text. */
+                if( const ::oox::vml::TextFontModel* pFontModel = pTextBox ? pTextBox->getFirstFont() : 0 )
+                {
+                    sal_Int32 nFontHeightHmm = getUnitConverter().scaleToMm100( pFontModel->monSize.get( 160 ), UNIT_TWIP );
+                    sal_Int32 nYDiff = ::std::min< sal_Int32 >( nFontHeightHmm / 2, aShapeRect.Y );
+                    aShapeRect.Y -= nYDiff;
+                    aShapeRect.Height += nYDiff;
+                }
+            }
+            break;
+
+            case XML_Checkbox:
+            {
+                AxCheckBoxModel& rAxModel = aControl.createModel< AxCheckBoxModel >();
+                convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
+                convertControlBackground( rAxModel, rShape );
+                rAxModel.maValue = OUString::valueOf( pClientData->mnChecked );
+                rAxModel.mnSpecialEffect = pClientData->mbNo3D ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_SUNKEN;
+                rAxModel.mnVerticalAlign = pClientData->mnTextVAlign;
+                bool bTriState = (pClientData->mnChecked != ::oox::vml::VML_CLIENTDATA_UNCHECKED) && (pClientData->mnChecked != ::oox::vml::VML_CLIENTDATA_CHECKED);
+                rAxModel.mnMultiSelect = bTriState ? AX_SELCTION_MULTI : AX_SELCTION_SINGLE;
+            }
+            break;
+
+            case XML_Radio:
+            {
+                AxOptionButtonModel& rAxModel = aControl.createModel< AxOptionButtonModel >();
+                convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, pClientData->mnTextHAlign );
+                convertControlBackground( rAxModel, rShape );
+                rAxModel.maValue = OUString::valueOf( pClientData->mnChecked );
+                rAxModel.mnSpecialEffect = pClientData->mbNo3D ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_SUNKEN;
+                rAxModel.mnVerticalAlign = pClientData->mnTextVAlign;
+            }
+            break;
+
+            case XML_List:
+            {
+                AxListBoxModel& rAxModel = aControl.createModel< AxListBoxModel >();
+                convertControlFontData( rAxModel.maFontData, rAxModel.mnTextColor, maListBoxFont );
+                rAxModel.mnBorderStyle = pClientData->mbNo3D2 ? AX_BORDERSTYLE_SINGLE : AX_BORDERSTYLE_NONE;
+                rAxModel.mnSpecialEffect = pClientData->mbNo3D2 ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_SUNKEN;
+                switch( pClientData->mnSelType )
+                {
+                    case XML_Single:    rAxModel.mnMultiSelect = AX_SELCTION_SINGLE;    break;
+                    case XML_Multi:     rAxModel.mnMultiSelect = AX_SELCTION_MULTI;     break;
+                    case XML_Extend:    rAxModel.mnMultiSelect = AX_SELCTION_EXTENDED;  break;
+                }
+            }
+            break;
+
+            case XML_Drop:
+            {
+                AxComboBoxModel& rAxModel = aControl.createModel< AxComboBoxModel >();
+                convertControlFontData( rAxModel.maFontData, rAxModel.mnTextColor, maListBoxFont );
+                rAxModel.mnDisplayStyle = AX_DISPLAYSTYLE_DROPDOWN;
+                rAxModel.mnShowDropButton = AX_SHOWDROPBUTTON_ALWAYS;
+                rAxModel.mnBorderStyle = pClientData->mbNo3D2 ? AX_BORDERSTYLE_SINGLE : AX_BORDERSTYLE_NONE;
+                rAxModel.mnSpecialEffect = pClientData->mbNo3D2 ? AX_SPECIALEFFECT_FLAT : AX_SPECIALEFFECT_SUNKEN;
+                rAxModel.mnListRows = pClientData->mnDropLines;
+            }
+            break;
+
+            case XML_Spin:
+            {
+                AxSpinButtonModel& rAxModel = aControl.createModel< AxSpinButtonModel >();
+                rAxModel.mnMin = pClientData->mnMin;
+                rAxModel.mnMax = pClientData->mnMax;
+                rAxModel.mnPosition = pClientData->mnVal;
+                rAxModel.mnSmallChange = pClientData->mnInc;
+            }
+            break;
+
+            case XML_Scroll:
+            {
+                AxScrollBarModel& rAxModel = aControl.createModel< AxScrollBarModel >();
+                rAxModel.mnMin = pClientData->mnMin;
+                rAxModel.mnMax = pClientData->mnMax;
+                rAxModel.mnPosition = pClientData->mnVal;
+                rAxModel.mnSmallChange = pClientData->mnInc;
+                rAxModel.mnLargeChange = pClientData->mnPage;
+            }
+            break;
+
+            case XML_Dialog:
+            {
+                // fake with a group box
+                AxFrameModel& rAxModel = aControl.createModel< AxFrameModel >();
+                convertControlText( rAxModel.maFontData, rAxModel.mnTextColor, rAxModel.maCaption, pTextBox, XML_Left );
+                rAxModel.mnBorderStyle = AX_BORDERSTYLE_SINGLE;
+                rAxModel.mnSpecialEffect = AX_SPECIALEFFECT_FLAT;
+            }
+            break;
+        }
+
+        if( ControlModelBase* pAxModel = aControl.getModel() )
+        {
+            // create the control shape
+            pAxModel->maSize.first = aShapeRect.Width;
+            pAxModel->maSize.second = aShapeRect.Height;
+            sal_Int32 nCtrlIndex = -1;
+            Reference< XShape > xShape = createAndInsertXControlShape( aControl, rxShapes, aShapeRect, nCtrlIndex );
+
+            // control shape macro
+            if( xShape.is() && (nCtrlIndex >= 0) && !pClientData->maFmlaMacro.isEmpty() )
+            {
+                OUString aMacroName = getFormulaParser().importMacroName( pClientData->maFmlaMacro );
+                if( !aMacroName.isEmpty() )
+                {
+                    Reference< XIndexContainer > xFormIC = getControlForm().getXForm();
+                    VbaMacroAttacherRef xAttacher( new VmlControlMacroAttacher( aMacroName, xFormIC, nCtrlIndex, pClientData->mnObjType, pClientData->mnDropStyle ) );
+                    getBaseFilter().getVbaProject().registerMacroAttacher( xAttacher );
+                }
+            }
+
+            return xShape;
+        }
+    }
+
+    return Reference< XShape >();
+}
+
+void VmlDrawing::notifyXShapeInserted( const Reference< XShape >& rxShape,
+        const Rectangle& rShapeRect, const ::oox::vml::ShapeBase& rShape, bool bGroupChild )
+{
+    // collect all shape positions in the WorksheetHelper base class (but not children of group shapes)
+    if( !bGroupChild )
+        extendShapeBoundingBox( rShapeRect );
+
+    // convert settings from VML client data
+    if( const ::oox::vml::ClientData* pClientData = rShape.getClientData() )
+    {
+        // specific settings for embedded form controls
+        try
+        {
+            Reference< XControlShape > xCtrlShape( rxShape, UNO_QUERY_THROW );
+            Reference< XControlModel > xCtrlModel( xCtrlShape->getControl(), UNO_SET_THROW );
+            PropertySet aPropSet( xCtrlModel );
+
+            // printable
+            aPropSet.setProperty( PROP_Printable, pClientData->mbPrintObject );
+
+            // control source links
+            if( !pClientData->maFmlaLink.isEmpty() || !pClientData->maFmlaRange.isEmpty() )
+                maControlConv.bindToSources( xCtrlModel, pClientData->maFmlaLink, pClientData->maFmlaRange, getSheetIndex() );
+        }
+        catch( Exception& )
+        {
+        }
+    }
+}
+
+// private --------------------------------------------------------------------
+
+sal_uInt32 VmlDrawing::convertControlTextColor( const OUString& rTextColor ) const
+{
+    // color attribute not present or 'auto' - use passed default color
+    if( rTextColor.isEmpty() || rTextColor.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "auto" ) ) )
+        return AX_SYSCOLOR_WINDOWTEXT;
+
+    if( rTextColor[ 0 ] == '#' )
+    {
+        // RGB colors in the format '#RRGGBB'
+        if( rTextColor.getLength() == 7 )
+            return OleHelper::encodeOleColor( rTextColor.copy( 1 ).toInt32( 16 ) );
+
+        // RGB colors in the format '#RGB'
+        if( rTextColor.getLength() == 4 )
+        {
+            sal_Int32 nR = rTextColor.copy( 1, 1 ).toInt32( 16 ) * 0x11;
+            sal_Int32 nG = rTextColor.copy( 2, 1 ).toInt32( 16 ) * 0x11;
+            sal_Int32 nB = rTextColor.copy( 3, 1 ).toInt32( 16 ) * 0x11;
+            return OleHelper::encodeOleColor( (nR << 16) | (nG << 8) | nB );
+        }
+
+        OSL_ENSURE( false, OStringBuffer( "VmlDrawing::convertControlTextColor - invalid color name '" ).
+            append( OUStringToOString( rTextColor, RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() );
+        return AX_SYSCOLOR_WINDOWTEXT;
+    }
+
+    const GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
+
+    /*  Predefined color names or system color names (resolve to RGB to detect
+        valid color name). */
+    sal_Int32 nColorToken = AttributeConversion::decodeToken( rTextColor );
+    sal_Int32 nRgbValue = Color::getVmlPresetColor( nColorToken, API_RGB_TRANSPARENT );
+    if( nRgbValue == API_RGB_TRANSPARENT )
+        nRgbValue = rGraphicHelper.getSystemColor( nColorToken, API_RGB_TRANSPARENT );
+    if( nRgbValue != API_RGB_TRANSPARENT )
+        return OleHelper::encodeOleColor( nRgbValue );
+
+    // try palette color
+    return OleHelper::encodeOleColor( rGraphicHelper.getPaletteColor( rTextColor.toInt32() ) );
+}
+
+void VmlDrawing::convertControlFontData( AxFontData& rAxFontData, sal_uInt32& rnOleTextColor, const ::oox::vml::TextFontModel& rFontModel ) const
+{
+    if( rFontModel.moName.has() )
+        rAxFontData.maFontName = rFontModel.moName.get();
+
+    // font height: convert from twips to points, then to internal representation of AX controls
+    rAxFontData.setHeightPoints( static_cast< sal_Int16 >( (rFontModel.monSize.get( 200 ) + 10) / 20 ) );
+
+    // font effects
+    rAxFontData.mnFontEffects = 0;
+    setFlag( rAxFontData.mnFontEffects, AX_FONTDATA_BOLD, rFontModel.mobBold.get( false ) );
+    setFlag( rAxFontData.mnFontEffects, AX_FONTDATA_ITALIC, rFontModel.mobItalic.get( false ) );
+    setFlag( rAxFontData.mnFontEffects, AX_FONTDATA_STRIKEOUT, rFontModel.mobStrikeout.get( false ) );
+    sal_Int32 nUnderline = rFontModel.monUnderline.get( XML_none );
+    setFlag( rAxFontData.mnFontEffects, AX_FONTDATA_UNDERLINE, nUnderline != XML_none );
+    rAxFontData.mbDblUnderline = nUnderline == XML_double;
+
+    // font color
+    rnOleTextColor = convertControlTextColor( rFontModel.moColor.get( OUString() ) );
+}
+
+void VmlDrawing::convertControlText( AxFontData& rAxFontData, sal_uInt32& rnOleTextColor,
+        OUString& rCaption, const ::oox::vml::TextBox* pTextBox, sal_Int32 nTextHAlign ) const
+{
+    if( pTextBox )
+    {
+        rCaption = pTextBox->getText();
+        if( const ::oox::vml::TextFontModel* pFontModel = pTextBox->getFirstFont() )
+            convertControlFontData( rAxFontData, rnOleTextColor, *pFontModel );
+    }
+
+    switch( nTextHAlign )
+    {
+        case XML_Left:      rAxFontData.mnHorAlign = AX_FONTDATA_LEFT;      break;
+        case XML_Center:    rAxFontData.mnHorAlign = AX_FONTDATA_CENTER;    break;
+        case XML_Right:     rAxFontData.mnHorAlign = AX_FONTDATA_RIGHT;     break;
+        default:            rAxFontData.mnHorAlign = AX_FONTDATA_LEFT;
+    }
+}
+
+void VmlDrawing::convertControlBackground( AxMorphDataModelBase& rAxModel, const ::oox::vml::ShapeBase& rShape ) const
+{
+    const ::oox::vml::FillModel& rFillModel = rShape.getTypeModel().maFillModel;
+    bool bHasFill = rFillModel.moFilled.get( true );
+    setFlag( rAxModel.mnFlags, AX_FLAGS_OPAQUE, bHasFill );
+    if( bHasFill )
+    {
+        const GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
+        sal_Int32 nSysWindowColor = rGraphicHelper.getSystemColor( XML_window, API_RGB_WHITE );
+        ::oox::drawingml::Color aColor = ::oox::vml::ConversionHelper::decodeColor( rGraphicHelper, rFillModel.moColor, rFillModel.moOpacity, nSysWindowColor );
+        sal_Int32 nRgbValue = aColor.getColor( rGraphicHelper );
+        rAxModel.mnBackColor = OleHelper::encodeOleColor( nRgbValue );
+    }
+}
+
+// ============================================================================
+
+VmlDrawingFragment::VmlDrawingFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    ::oox::vml::DrawingFragment( rHelper.getOoxFilter(), rFragmentPath, rHelper.getVmlDrawing() ),
+    WorksheetHelper( rHelper )
+{
+}
+
+void VmlDrawingFragment::finalizeImport()
+{
+    ::oox::vml::DrawingFragment::finalizeImport();
+    getVmlDrawing().convertAndInsert();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/drawingmanager.cxx b/sc/source/filter/oox/drawingmanager.cxx
new file mode 100644
index 000000000000..5ba29e244488
--- /dev/null
+++ b/sc/source/filter/oox/drawingmanager.cxx
@@ -0,0 +1,1359 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "drawingmanager.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/drawingml/fillproperties.hxx"
+#include "oox/drawingml/lineproperties.hxx"
+#include "oox/drawingml/shapepropertymap.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/token/tokens.hxx"
+#include "biffinputstream.hxx"
+#include "unitconverter.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::oox::drawingml;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+namespace {
+
+// OBJ record -----------------------------------------------------------------
+
+const sal_uInt16 BIFF_OBJTYPE_GROUP         = 0;
+const sal_uInt16 BIFF_OBJTYPE_LINE          = 1;
+const sal_uInt16 BIFF_OBJTYPE_RECTANGLE     = 2;
+const sal_uInt16 BIFF_OBJTYPE_OVAL          = 3;
+const sal_uInt16 BIFF_OBJTYPE_ARC           = 4;
+const sal_uInt16 BIFF_OBJTYPE_CHART         = 5;
+const sal_uInt16 BIFF_OBJTYPE_TEXT          = 6;
+const sal_uInt16 BIFF_OBJTYPE_BUTTON        = 7;
+const sal_uInt16 BIFF_OBJTYPE_PICTURE       = 8;
+const sal_uInt16 BIFF_OBJTYPE_POLYGON       = 9;        // new in BIFF4
+const sal_uInt16 BIFF_OBJTYPE_CHECKBOX      = 11;       // new in BIFF5
+const sal_uInt16 BIFF_OBJTYPE_OPTIONBUTTON  = 12;
+const sal_uInt16 BIFF_OBJTYPE_EDIT          = 13;
+const sal_uInt16 BIFF_OBJTYPE_LABEL         = 14;
+const sal_uInt16 BIFF_OBJTYPE_DIALOG        = 15;
+const sal_uInt16 BIFF_OBJTYPE_SPIN          = 16;
+const sal_uInt16 BIFF_OBJTYPE_SCROLLBAR     = 17;
+const sal_uInt16 BIFF_OBJTYPE_LISTBOX       = 18;
+const sal_uInt16 BIFF_OBJTYPE_GROUPBOX      = 19;
+const sal_uInt16 BIFF_OBJTYPE_DROPDOWN      = 20;
+const sal_uInt16 BIFF_OBJTYPE_NOTE          = 25;       // new in BIFF8
+const sal_uInt16 BIFF_OBJTYPE_DRAWING       = 30;
+const sal_uInt16 BIFF_OBJTYPE_UNKNOWN       = 0xFFFF;   // for internal use only
+
+const sal_uInt16 BIFF_OBJ_HIDDEN            = 0x0100;
+const sal_uInt16 BIFF_OBJ_VISIBLE           = 0x0200;
+const sal_uInt16 BIFF_OBJ_PRINTABLE         = 0x0400;
+
+// line formatting ------------------------------------------------------------
+
+const sal_uInt8 BIFF_OBJ_LINE_AUTOCOLOR     = 64;
+
+const sal_uInt8 BIFF_OBJ_LINE_SOLID         = 0;
+const sal_uInt8 BIFF_OBJ_LINE_DASH          = 1;
+const sal_uInt8 BIFF_OBJ_LINE_DOT           = 2;
+const sal_uInt8 BIFF_OBJ_LINE_DASHDOT       = 3;
+const sal_uInt8 BIFF_OBJ_LINE_DASHDOTDOT    = 4;
+const sal_uInt8 BIFF_OBJ_LINE_MEDTRANS      = 5;
+const sal_uInt8 BIFF_OBJ_LINE_DARKTRANS     = 6;
+const sal_uInt8 BIFF_OBJ_LINE_LIGHTTRANS    = 7;
+const sal_uInt8 BIFF_OBJ_LINE_NONE          = 255;
+
+const sal_uInt8 BIFF_OBJ_LINE_HAIR          = 0;
+const sal_uInt8 BIFF_OBJ_LINE_THIN          = 1;
+const sal_uInt8 BIFF_OBJ_LINE_MEDIUM        = 2;
+const sal_uInt8 BIFF_OBJ_LINE_THICK         = 3;
+
+const sal_uInt8 BIFF_OBJ_LINE_AUTO          = 0x01;
+
+const sal_uInt8 BIFF_OBJ_ARROW_NONE         = 0;
+const sal_uInt8 BIFF_OBJ_ARROW_OPEN         = 1;
+const sal_uInt8 BIFF_OBJ_ARROW_FILLED       = 2;
+const sal_uInt8 BIFF_OBJ_ARROW_OPENBOTH     = 3;
+const sal_uInt8 BIFF_OBJ_ARROW_FILLEDBOTH   = 4;
+
+const sal_uInt8 BIFF_OBJ_ARROW_NARROW       = 0;
+const sal_uInt8 BIFF_OBJ_ARROW_MEDIUM       = 1;
+const sal_uInt8 BIFF_OBJ_ARROW_WIDE         = 2;
+
+const sal_uInt8 BIFF_OBJ_LINE_TL            = 0;
+const sal_uInt8 BIFF_OBJ_LINE_TR            = 1;
+const sal_uInt8 BIFF_OBJ_LINE_BR            = 2;
+const sal_uInt8 BIFF_OBJ_LINE_BL            = 3;
+
+const sal_uInt8 BIFF_OBJ_ARC_TR             = 0;
+const sal_uInt8 BIFF_OBJ_ARC_TL             = 1;
+const sal_uInt8 BIFF_OBJ_ARC_BL             = 2;
+const sal_uInt8 BIFF_OBJ_ARC_BR             = 3;
+
+const sal_uInt16 BIFF_OBJ_POLY_CLOSED       = 0x0100;
+
+// fill formatting ------------------------------------------------------------
+
+const sal_uInt8 BIFF_OBJ_FILL_AUTOCOLOR     = 65;
+
+const sal_uInt8 BIFF_OBJ_PATT_NONE          = 0;
+const sal_uInt8 BIFF_OBJ_PATT_SOLID         = 1;
+
+const sal_uInt8 BIFF_OBJ_FILL_AUTO          = 0x01;
+
+// text formatting ------------------------------------------------------------
+
+const sal_uInt8 BIFF_OBJ_HOR_LEFT           = 1;
+const sal_uInt8 BIFF_OBJ_HOR_CENTER         = 2;
+const sal_uInt8 BIFF_OBJ_HOR_RIGHT          = 3;
+const sal_uInt8 BIFF_OBJ_HOR_JUSTIFY        = 4;
+
+const sal_uInt8 BIFF_OBJ_VER_TOP            = 1;
+const sal_uInt8 BIFF_OBJ_VER_CENTER         = 2;
+const sal_uInt8 BIFF_OBJ_VER_BOTTOM         = 3;
+const sal_uInt8 BIFF_OBJ_VER_JUSTIFY        = 4;
+
+const sal_uInt16 BIFF_OBJ_ORIENT_NONE       = 0;
+const sal_uInt16 BIFF_OBJ_ORIENT_STACKED    = 1;        /// Stacked top to bottom.
+const sal_uInt16 BIFF_OBJ_ORIENT_90CCW      = 2;        /// 90 degr. counterclockwise.
+const sal_uInt16 BIFF_OBJ_ORIENT_90CW       = 3;        /// 90 degr. clockwise.
+
+const sal_uInt16 BIFF_OBJ_TEXT_AUTOSIZE     = 0x0080;
+const sal_uInt16 BIFF_OBJ_TEXT_LOCKED       = 0x0200;
+
+const sal_Int32 BIFF_OBJ_TEXT_MARGIN        = 20000;    /// Automatic text margin (EMUs).
+
+// BIFF8 OBJ sub records ------------------------------------------------------
+
+const sal_uInt16 BIFF_OBJCMO_PRINTABLE      = 0x0010;   /// Object printable.
+const sal_uInt16 BIFF_OBJCMO_AUTOLINE       = 0x2000;   /// Automatic line formatting.
+const sal_uInt16 BIFF_OBJCMO_AUTOFILL       = 0x4000;   /// Automatic fill formatting.
+
+// ----------------------------------------------------------------------------
+
+inline BiffInputStream& operator>>( BiffInputStream& rStrm, ShapeAnchor& rAnchor )
+{
+    rAnchor.importBiffAnchor( rStrm );
+    return rStrm;
+}
+
+} // namespace
+
+// ============================================================================
+// Model structures for BIFF OBJ record data
+// ============================================================================
+
+BiffObjLineModel::BiffObjLineModel() :
+    mnColorIdx( BIFF_OBJ_LINE_AUTOCOLOR ),
+    mnStyle( BIFF_OBJ_LINE_SOLID ),
+    mnWidth( BIFF_OBJ_LINE_HAIR ),
+    mbAuto( true )
+{
+}
+
+BiffInputStream& operator>>( BiffInputStream& rStrm, BiffObjLineModel& rModel )
+{
+    sal_uInt8 nFlags;
+    rStrm >> rModel.mnColorIdx >> rModel.mnStyle >> rModel.mnWidth >> nFlags;
+    rModel.mbAuto = getFlag( nFlags, BIFF_OBJ_LINE_AUTO );
+    return rStrm;
+}
+
+// ============================================================================
+
+BiffObjFillModel::BiffObjFillModel() :
+    mnBackColorIdx( BIFF_OBJ_LINE_AUTOCOLOR ),
+    mnPattColorIdx( BIFF_OBJ_FILL_AUTOCOLOR ),
+    mnPattern( BIFF_OBJ_PATT_SOLID ),
+    mbAuto( true )
+{
+}
+
+bool BiffObjFillModel::isFilled() const
+{
+    return mbAuto || (mnPattern != BIFF_OBJ_PATT_NONE);
+}
+
+BiffInputStream& operator>>( BiffInputStream& rStrm, BiffObjFillModel& rModel )
+{
+    sal_uInt8 nFlags;
+    rStrm >> rModel.mnBackColorIdx >> rModel.mnPattColorIdx >> rModel.mnPattern >> nFlags;
+    rModel.mbAuto = getFlag( nFlags, BIFF_OBJ_FILL_AUTO );
+    return rStrm;
+}
+
+// ============================================================================
+// BIFF drawing objects
+// ============================================================================
+
+BiffDrawingObjectContainer::BiffDrawingObjectContainer()
+{
+}
+
+void BiffDrawingObjectContainer::append( const BiffDrawingObjectRef& rxDrawingObj )
+{
+    maObjects.push_back( rxDrawingObj );
+}
+
+void BiffDrawingObjectContainer::insertGrouped( const BiffDrawingObjectRef& rxDrawingObj )
+{
+    if( !maObjects.empty() )
+        if( BiffGroupObject* pGroupObj = dynamic_cast< BiffGroupObject* >( maObjects.back().get() ) )
+            if( pGroupObj->tryInsert( rxDrawingObj ) )
+                return;
+    maObjects.push_back( rxDrawingObj );
+}
+
+void BiffDrawingObjectContainer::convertAndInsert( BiffDrawingBase& rDrawing, const Reference< XShapes >& rxShapes, const Rectangle* pParentRect ) const
+{
+    maObjects.forEachMem( &BiffDrawingObjectBase::convertAndInsert, ::boost::ref( rDrawing ), ::boost::cref( rxShapes ), pParentRect );
+}
+
+// ============================================================================
+
+BiffDrawingObjectBase::BiffDrawingObjectBase( const WorksheetHelper& rHelper ) :
+    WorksheetHelper( rHelper ),
+    maAnchor( rHelper ),
+    mnDffShapeId( 0 ),
+    mnDffFlags( 0 ),
+    mnObjId( BIFF_OBJ_INVALID_ID ),
+    mnObjType( BIFF_OBJTYPE_UNKNOWN ),
+    mbHasAnchor( false ),
+    mbHidden( false ),
+    mbVisible( true ),
+    mbPrintable( true ),
+    mbAreaObj( false ),
+    mbAutoMargin( true ),
+    mbSimpleMacro( true ),
+    mbProcessShape( true ),
+    mbInsertShape( true ),
+    mbCustomDff( false )
+{
+}
+
+BiffDrawingObjectBase::~BiffDrawingObjectBase()
+{
+}
+
+/*static*/ BiffDrawingObjectRef BiffDrawingObjectBase::importObjBiff3( const WorksheetHelper& rHelper, BiffInputStream& rStrm )
+{
+    BiffDrawingObjectRef xDrawingObj;
+
+    if( rStrm.getRemaining() >= 30 )
+    {
+        sal_uInt16 nObjType;
+        rStrm.skip( 4 );
+        rStrm >> nObjType;
+        switch( nObjType )
+        {
+            case BIFF_OBJTYPE_GROUP:        xDrawingObj.reset( new BiffGroupObject( rHelper ) );    break;
+            case BIFF_OBJTYPE_LINE:         xDrawingObj.reset( new BiffLineObject( rHelper ) );     break;
+            case BIFF_OBJTYPE_RECTANGLE:    xDrawingObj.reset( new BiffRectObject( rHelper ) );     break;
+            case BIFF_OBJTYPE_OVAL:         xDrawingObj.reset( new BiffOvalObject( rHelper ) );     break;
+            case BIFF_OBJTYPE_ARC:          xDrawingObj.reset( new BiffArcObject( rHelper ) );      break;
+#if 0
+            case BIFF_OBJTYPE_CHART:        xDrawingObj.reset( new XclImpChartObj( rHelper ) );     break;
+            case BIFF_OBJTYPE_TEXT:         xDrawingObj.reset( new XclImpTextObj( rHelper ) );      break;
+            case BIFF_OBJTYPE_BUTTON:       xDrawingObj.reset( new XclImpButtonObj( rHelper ) );    break;
+            case BIFF_OBJTYPE_PICTURE:      xDrawingObj.reset( new XclImpPictureObj( rHelper ) );   break;
+#endif
+            default:
+#if 0
+                OSL_ENSURE( false, "BiffDrawingObjectBase::importObjBiff3 - unknown object type" );
+#endif
+                xDrawingObj.reset( new BiffPlaceholderObject( rHelper ) );
+        }
+    }
+
+    xDrawingObj->importObjBiff3( rStrm );
+    return xDrawingObj;
+}
+
+/*static*/ BiffDrawingObjectRef BiffDrawingObjectBase::importObjBiff4( const WorksheetHelper& rHelper, BiffInputStream& rStrm )
+{
+    BiffDrawingObjectRef xDrawingObj;
+
+    if( rStrm.getRemaining() >= 30 )
+    {
+        sal_uInt16 nObjType;
+        rStrm.skip( 4 );
+        rStrm >> nObjType;
+        switch( nObjType )
+        {
+            case BIFF_OBJTYPE_GROUP:        xDrawingObj.reset( new BiffGroupObject( rHelper ) );    break;
+            case BIFF_OBJTYPE_LINE:         xDrawingObj.reset( new BiffLineObject( rHelper ) );     break;
+            case BIFF_OBJTYPE_RECTANGLE:    xDrawingObj.reset( new BiffRectObject( rHelper ) );     break;
+            case BIFF_OBJTYPE_OVAL:         xDrawingObj.reset( new BiffOvalObject( rHelper ) );     break;
+            case BIFF_OBJTYPE_ARC:          xDrawingObj.reset( new BiffArcObject( rHelper ) );      break;
+            case BIFF_OBJTYPE_POLYGON:      xDrawingObj.reset( new BiffPolygonObject( rHelper ) );  break;
+#if 0
+            case BIFF_OBJTYPE_CHART:        xDrawingObj.reset( new XclImpChartObj( rHelper ) );     break;
+            case BIFF_OBJTYPE_TEXT:         xDrawingObj.reset( new XclImpTextObj( rHelper ) );      break;
+            case BIFF_OBJTYPE_BUTTON:       xDrawingObj.reset( new XclImpButtonObj( rHelper ) );    break;
+            case BIFF_OBJTYPE_PICTURE:      xDrawingObj.reset( new XclImpPictureObj( rHelper ) );   break;
+#endif
+            default:
+#if 0
+                OSL_ENSURE( false, "BiffDrawingObjectBase::importObjBiff4 - unknown object type" );
+#endif
+                xDrawingObj.reset( new BiffPlaceholderObject( rHelper ) );
+        }
+    }
+
+    xDrawingObj->importObjBiff4( rStrm );
+    return xDrawingObj;
+}
+
+/*static*/ BiffDrawingObjectRef BiffDrawingObjectBase::importObjBiff5( const WorksheetHelper& rHelper, BiffInputStream& rStrm )
+{
+    BiffDrawingObjectRef xDrawingObj;
+
+    if( rStrm.getRemaining() >= 34 )
+    {
+        sal_uInt16 nObjType;
+        rStrm.skip( 4 );
+        rStrm >> nObjType;
+        switch( nObjType )
+        {
+            case BIFF_OBJTYPE_GROUP:        xDrawingObj.reset( new BiffGroupObject( rHelper ) );        break;
+            case BIFF_OBJTYPE_LINE:         xDrawingObj.reset( new BiffLineObject( rHelper ) );         break;
+            case BIFF_OBJTYPE_RECTANGLE:    xDrawingObj.reset( new BiffRectObject( rHelper ) );         break;
+            case BIFF_OBJTYPE_OVAL:         xDrawingObj.reset( new BiffOvalObject( rHelper ) );         break;
+            case BIFF_OBJTYPE_ARC:          xDrawingObj.reset( new BiffArcObject( rHelper ) );           break;
+            case BIFF_OBJTYPE_POLYGON:      xDrawingObj.reset( new BiffPolygonObject( rHelper ) );      break;
+#if 0
+            case BIFF_OBJTYPE_CHART:        xDrawingObj.reset( new XclImpChartObj( rHelper ) );         break;
+            case BIFF_OBJTYPE_TEXT:         xDrawingObj.reset( new XclImpTextObj( rHelper ) );          break;
+            case BIFF_OBJTYPE_BUTTON:       xDrawingObj.reset( new XclImpButtonObj( rHelper ) );        break;
+            case BIFF_OBJTYPE_PICTURE:      xDrawingObj.reset( new XclImpPictureObj( rHelper ) );       break;
+            case BIFF_OBJTYPE_CHECKBOX:     xDrawingObj.reset( new XclImpCheckBoxObj( rHelper ) );      break;
+            case BIFF_OBJTYPE_OPTIONBUTTON: xDrawingObj.reset( new XclImpOptionButtonObj( rHelper ) );  break;
+            case BIFF_OBJTYPE_EDIT:         xDrawingObj.reset( new XclImpEditObj( rHelper ) );          break;
+            case BIFF_OBJTYPE_LABEL:        xDrawingObj.reset( new XclImpLabelObj( rHelper ) );         break;
+            case BIFF_OBJTYPE_DIALOG:       xDrawingObj.reset( new XclImpDialogObj( rHelper ) );        break;
+            case BIFF_OBJTYPE_SPIN:         xDrawingObj.reset( new XclImpSpinButtonObj( rHelper ) );    break;
+            case BIFF_OBJTYPE_SCROLLBAR:    xDrawingObj.reset( new XclImpScrollBarObj( rHelper ) );     break;
+            case BIFF_OBJTYPE_LISTBOX:      xDrawingObj.reset( new XclImpListBoxObj( rHelper ) );       break;
+            case BIFF_OBJTYPE_GROUPBOX:     xDrawingObj.reset( new XclImpGroupBoxObj( rHelper ) );      break;
+            case BIFF_OBJTYPE_DROPDOWN:     xDrawingObj.reset( new XclImpDropDownObj( rHelper ) );      break;
+#endif
+            default:
+#if 0
+                OSL_ENSURE( false, "BiffDrawingObjectBase::importObjBiff5 - unknown object type" );
+#endif
+                xDrawingObj.reset( new BiffPlaceholderObject( rHelper ) );
+        }
+    }
+
+    xDrawingObj->importObjBiff5( rStrm );
+    return xDrawingObj;
+}
+
+/*static*/ BiffDrawingObjectRef BiffDrawingObjectBase::importObjBiff8( const WorksheetHelper& rHelper, BiffInputStream& rStrm )
+{
+    BiffDrawingObjectRef xDrawingObj;
+
+    if( rStrm.getRemaining() >= 10 )
+    {
+        sal_uInt16 nSubRecId, nSubRecSize, nObjType;
+        rStrm >> nSubRecId >> nSubRecSize >> nObjType;
+        OSL_ENSURE( nSubRecId == BIFF_ID_OBJCMO, "BiffDrawingObjectBase::importObjBiff8 - OBJCMO subrecord expected" );
+        if( (nSubRecId == BIFF_ID_OBJCMO) && (nSubRecSize >= 6) )
+        {
+            switch( nObjType )
+            {
+#if 0
+                // in BIFF8, all simple objects support text
+                case BIFF_OBJTYPE_LINE:
+                case BIFF_OBJTYPE_ARC:
+                    xDrawingObj.reset( new XclImpTextObj( rHelper ) );
+                    // lines and arcs may be 2-dimensional
+                    xDrawingObj->setAreaObj( false );
+                break;
+
+                // in BIFF8, all simple objects support text
+                case BIFF_OBJTYPE_RECTANGLE:
+                case BIFF_OBJTYPE_OVAL:
+                case BIFF_OBJTYPE_POLYGON:
+                case BIFF_OBJTYPE_DRAWING:
+                case BIFF_OBJTYPE_TEXT:
+                    xDrawingObj.reset( new XclImpTextObj( rHelper ) );
+                break;
+#endif
+
+                case BIFF_OBJTYPE_GROUP:        xDrawingObj.reset( new BiffGroupObject( rHelper ) );        break;
+#if 0
+                case BIFF_OBJTYPE_CHART:        xDrawingObj.reset( new XclImpChartObj( rHelper ) );         break;
+                case BIFF_OBJTYPE_BUTTON:       xDrawingObj.reset( new XclImpButtonObj( rHelper ) );        break;
+                case BIFF_OBJTYPE_PICTURE:      xDrawingObj.reset( new XclImpPictureObj( rHelper ) );       break;
+                case BIFF_OBJTYPE_CHECKBOX:     xDrawingObj.reset( new XclImpCheckBoxObj( rHelper ) );      break;
+                case BIFF_OBJTYPE_OPTIONBUTTON: xDrawingObj.reset( new XclImpOptionButtonObj( rHelper ) );  break;
+                case BIFF_OBJTYPE_EDIT:         xDrawingObj.reset( new XclImpEditObj( rHelper ) );          break;
+                case BIFF_OBJTYPE_LABEL:        xDrawingObj.reset( new XclImpLabelObj( rHelper ) );         break;
+                case BIFF_OBJTYPE_DIALOG:       xDrawingObj.reset( new XclImpDialogObj( rHelper ) );        break;
+                case BIFF_OBJTYPE_SPIN:         xDrawingObj.reset( new XclImpSpinButtonObj( rHelper ) );    break;
+                case BIFF_OBJTYPE_SCROLLBAR:    xDrawingObj.reset( new XclImpScrollBarObj( rHelper ) );     break;
+                case BIFF_OBJTYPE_LISTBOX:      xDrawingObj.reset( new XclImpListBoxObj( rHelper ) );       break;
+                case BIFF_OBJTYPE_GROUPBOX:     xDrawingObj.reset( new XclImpGroupBoxObj( rHelper ) );      break;
+                case BIFF_OBJTYPE_DROPDOWN:     xDrawingObj.reset( new XclImpDropDownObj( rHelper ) );      break;
+                case BIFF_OBJTYPE_NOTE:         xDrawingObj.reset( new XclImpNoteObj( rHelper ) );          break;
+#endif
+
+                default:
+#if 0
+                    OSL_ENSURE( false, "BiffDrawingObjectBase::importObjBiff8 - unknown object type" );
+#endif
+                    xDrawingObj.reset( new BiffPlaceholderObject( rHelper ) );
+            }
+        }
+    }
+
+    xDrawingObj->importObjBiff8( rStrm );
+    return xDrawingObj;
+}
+
+Reference< XShape > BiffDrawingObjectBase::convertAndInsert( BiffDrawingBase& rDrawing,
+        const Reference< XShapes >& rxShapes, const Rectangle* pParentRect ) const
+{
+    Reference< XShape > xShape;
+    if( rxShapes.is() && mbProcessShape && !mbHidden )  // TODO: support for hidden objects?
+    {
+        // base class 'ShapeAnchor' calculates the shape rectangle in 1/100 mm
+        // in BIFF3-BIFF5, all shapes have absolute anchor (also children of group shapes)
+        Rectangle aShapeRect = maAnchor.calcAnchorRectHmm( getDrawPageSize() );
+
+        // convert the shape, if the calculated rectangle is not empty
+        bool bHasWidth = aShapeRect.Width > 0;
+        bool bHasHeight = aShapeRect.Height > 0;
+        if( mbAreaObj ? (bHasWidth && bHasHeight) : (bHasWidth || bHasHeight) )
+        {
+            xShape = implConvertAndInsert( rDrawing, rxShapes, aShapeRect );
+            /*  Notify the drawing that a new shape has been inserted (but not
+                for children of group shapes). For convenience, pass the
+                rectangle that contains position and size of the shape. */
+            if( !pParentRect && xShape.is() )
+                rDrawing.notifyShapeInserted( xShape, aShapeRect );
+        }
+    }
+    return xShape;
+}
+
+// protected ------------------------------------------------------------------
+
+void BiffDrawingObjectBase::readNameBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen )
+{
+    maObjName = OUString();
+    if( nNameLen > 0 )
+    {
+        // name length field is repeated before the name
+        maObjName = rStrm.readByteStringUC( false, getTextEncoding() );
+        // skip padding byte for word boundaries
+        rStrm.alignToBlock( 2 );
+    }
+}
+
+void BiffDrawingObjectBase::readMacroBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    maMacroName = OUString();
+    rStrm.skip( nMacroSize );
+    // skip padding byte for word boundaries, not contained in nMacroSize
+    rStrm.alignToBlock( 2 );
+}
+
+void BiffDrawingObjectBase::readMacroBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    maMacroName = OUString();
+    rStrm.skip( nMacroSize );
+}
+
+void BiffDrawingObjectBase::readMacroBiff5( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    maMacroName = OUString();
+    rStrm.skip( nMacroSize );
+}
+
+void BiffDrawingObjectBase::readMacroBiff8( BiffInputStream& rStrm )
+{
+    maMacroName = OUString();
+    if( rStrm.getRemaining() > 6 )
+    {
+        // macro is stored in a tNameXR token containing a link to a defined name
+        sal_uInt16 nFmlaSize;
+        rStrm >> nFmlaSize;
+        rStrm.skip( 4 );
+        OSL_ENSURE( nFmlaSize == 7, "BiffDrawingObjectBase::readMacroBiff8 - unexpected formula size" );
+        if( nFmlaSize == 7 )
+        {
+            sal_uInt8 nTokenId;
+            sal_uInt16 nExtLinkId, nExtNameId;
+            rStrm >> nTokenId >> nExtLinkId >> nExtNameId;
+#if 0
+            OSL_ENSURE( nTokenId == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ),
+                "BiffDrawingObjectBase::readMacroBiff8 - tNameXR token expected" );
+            if( nTokenId == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ) )
+                maMacroName = GetLinkManager().GetMacroName( nExtLinkId, nExtNameId );
+#endif
+        }
+    }
+}
+
+void BiffDrawingObjectBase::convertLineProperties( ShapePropertyMap& rPropMap, const BiffObjLineModel& rLineModel, sal_uInt16 nArrows ) const
+{
+    if( rLineModel.mbAuto )
+    {
+        BiffObjLineModel aAutoModel;
+        aAutoModel.mbAuto = false;
+        convertLineProperties( rPropMap, aAutoModel, nArrows );
+        return;
+    }
+
+    /*  Convert line formatting to DrawingML line formatting and let the
+        DrawingML code do the hard work. */
+    LineProperties aLineProps;
+
+    if( rLineModel.mnStyle == BIFF_OBJ_LINE_NONE )
+    {
+        aLineProps.maLineFill.moFillType = XML_noFill;
+    }
+    else
+    {
+        aLineProps.maLineFill.moFillType = XML_solidFill;
+        aLineProps.maLineFill.maFillColor.setPaletteClr( rLineModel.mnColorIdx );
+        aLineProps.moLineCompound = XML_sng;
+        aLineProps.moLineCap = XML_flat;
+        aLineProps.moLineJoint = XML_round;
+
+        // line width: use 0.35 mm per BIFF line width step
+        sal_Int32 nLineWidth = 0;
+        switch( rLineModel.mnWidth )
+        {
+            default:
+            case BIFF_OBJ_LINE_HAIR:    nLineWidth = 0;     break;
+            case BIFF_OBJ_LINE_THIN:    nLineWidth = 20;    break;
+            case BIFF_OBJ_LINE_MEDIUM:  nLineWidth = 40;    break;
+            case BIFF_OBJ_LINE_THICK:   nLineWidth = 60;    break;
+        }
+        aLineProps.moLineWidth = getLimitedValue< sal_Int32, sal_Int64 >( convertHmmToEmu( nLineWidth ), 0, SAL_MAX_INT32 );
+
+        // dash style and transparency
+        switch( rLineModel.mnStyle )
+        {
+            default:
+            case BIFF_OBJ_LINE_SOLID:
+                aLineProps.moPresetDash = XML_solid;
+            break;
+            case BIFF_OBJ_LINE_DASH:
+                aLineProps.moPresetDash = XML_lgDash;
+            break;
+            case BIFF_OBJ_LINE_DOT:
+                aLineProps.moPresetDash = XML_dot;
+            break;
+            case BIFF_OBJ_LINE_DASHDOT:
+                aLineProps.moPresetDash = XML_lgDashDot;
+            break;
+            case BIFF_OBJ_LINE_DASHDOTDOT:
+                aLineProps.moPresetDash = XML_lgDashDotDot;
+            break;
+            case BIFF_OBJ_LINE_MEDTRANS:
+                aLineProps.moPresetDash = XML_solid;
+                aLineProps.maLineFill.maFillColor.addTransformation( XML_alpha, 50 * PER_PERCENT );
+            break;
+            case BIFF_OBJ_LINE_DARKTRANS:
+                aLineProps.moPresetDash = XML_solid;
+                aLineProps.maLineFill.maFillColor.addTransformation( XML_alpha, 75 * PER_PERCENT );
+            break;
+            case BIFF_OBJ_LINE_LIGHTTRANS:
+                aLineProps.moPresetDash = XML_solid;
+                aLineProps.maLineFill.maFillColor.addTransformation( XML_alpha, 25 * PER_PERCENT );
+            break;
+        }
+
+        // line ends
+        bool bLineStart = false;
+        bool bLineEnd = false;
+        bool bFilled = false;
+        switch( extractValue< sal_uInt8 >( nArrows, 0, 4 ) )
+        {
+            case BIFF_OBJ_ARROW_OPEN:       bLineStart = false; bLineEnd = true;  bFilled = false;  break;
+            case BIFF_OBJ_ARROW_OPENBOTH:   bLineStart = true;  bLineEnd = true;  bFilled = false;  break;
+            case BIFF_OBJ_ARROW_FILLED:     bLineStart = false; bLineEnd = true;  bFilled = true;   break;
+            case BIFF_OBJ_ARROW_FILLEDBOTH: bLineStart = true;  bLineEnd = true;  bFilled = true;   break;
+        }
+        if( bLineStart || bLineEnd )
+        {
+            // arrow type (open or closed)
+            sal_Int32 nArrowType = bFilled ? XML_triangle : XML_arrow;
+            aLineProps.maStartArrow.moArrowType = bLineStart ? nArrowType : XML_none;
+            aLineProps.maEndArrow.moArrowType   = bLineEnd   ? nArrowType : XML_none;
+
+            // arrow width
+            sal_Int32 nArrowWidth = XML_med;
+            switch( extractValue< sal_uInt8 >( nArrows, 4, 4 ) )
+            {
+                case BIFF_OBJ_ARROW_NARROW: nArrowWidth = XML_sm;   break;
+                case BIFF_OBJ_ARROW_MEDIUM: nArrowWidth = XML_med;  break;
+                case BIFF_OBJ_ARROW_WIDE:   nArrowWidth = XML_lg;   break;
+            }
+            aLineProps.maStartArrow.moArrowWidth = aLineProps.maEndArrow.moArrowWidth = nArrowWidth;
+
+            // arrow length
+            sal_Int32 nArrowLength = XML_med;
+            switch( extractValue< sal_uInt8 >( nArrows, 8, 4 ) )
+            {
+                case BIFF_OBJ_ARROW_NARROW: nArrowLength = XML_sm;  break;
+                case BIFF_OBJ_ARROW_MEDIUM: nArrowLength = XML_med; break;
+                case BIFF_OBJ_ARROW_WIDE:   nArrowLength = XML_lg;  break;
+            }
+            aLineProps.maStartArrow.moArrowLength = aLineProps.maEndArrow.moArrowLength = nArrowLength;
+        }
+    }
+
+    aLineProps.pushToPropMap( rPropMap, getBaseFilter().getGraphicHelper() );
+}
+
+void BiffDrawingObjectBase::convertFillProperties( ShapePropertyMap& rPropMap, const BiffObjFillModel& rFillModel ) const
+{
+    if( rFillModel.mbAuto )
+    {
+        BiffObjFillModel aAutoModel;
+        aAutoModel.mbAuto = false;
+        convertFillProperties( rPropMap, aAutoModel );
+        return;
+    }
+
+    /*  Convert fill formatting to DrawingML fill formatting and let the
+        DrawingML code do the hard work. */
+    FillProperties aFillProps;
+
+    if( rFillModel.mnPattern == BIFF_OBJ_PATT_NONE )
+    {
+        aFillProps.moFillType = XML_noFill;
+    }
+    else
+    {
+        const sal_Int32 spnPatternPresets[] = {
+            XML_TOKEN_INVALID, XML_TOKEN_INVALID, XML_pct50, XML_pct50, XML_pct25,
+            XML_dkHorz, XML_dkVert, XML_dkDnDiag, XML_dkUpDiag, XML_smCheck, XML_trellis,
+            XML_ltHorz, XML_ltVert, XML_ltDnDiag, XML_ltUpDiag, XML_smGrid, XML_diagCross,
+            XML_pct20, XML_pct10 };
+        sal_Int32 nPatternPreset = STATIC_ARRAY_SELECT( spnPatternPresets, rFillModel.mnPattern, XML_TOKEN_INVALID );
+        if( nPatternPreset == XML_TOKEN_INVALID )
+        {
+            aFillProps.moFillType = XML_solidFill;
+            aFillProps.maFillColor.setPaletteClr( rFillModel.mnPattColorIdx );
+        }
+        else
+        {
+            aFillProps.moFillType = XML_pattFill;
+            aFillProps.maPatternProps.maPattFgColor.setPaletteClr( rFillModel.mnPattColorIdx );
+            aFillProps.maPatternProps.maPattBgColor.setPaletteClr( rFillModel.mnBackColorIdx );
+            aFillProps.maPatternProps.moPattPreset = nPatternPreset;
+        }
+#if 0
+        static const sal_uInt8 sppnPatterns[][ 8 ] =
+        {
+            { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 },
+            { 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD },
+            { 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 },
+            { 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00 },
+            { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC },
+            { 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99 },
+            { 0xCC, 0x66, 0x33, 0x99, 0xCC, 0x66, 0x33, 0x99 },
+            { 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33 },
+            { 0xCC, 0xFF, 0x33, 0xFF, 0xCC, 0xFF, 0x33, 0xFF },
+            { 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 },
+            { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 },
+            { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 },
+            { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 },
+            { 0xFF, 0x11, 0x11, 0x11, 0xFF, 0x11, 0x11, 0x11 },
+            { 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11 },
+            { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
+            { 0x80, 0x00, 0x08, 0x00, 0x80, 0x00, 0x08, 0x00 }
+        };
+        const sal_uInt8* const pnPattern = sppnPatterns[ ::std::min< size_t >( rFillData.mnPattern - 2, STATIC_ARRAY_SIZE( sppnPatterns ) ) ];
+        // create 2-colored 8x8 DIB
+        SvMemoryStream aMemStrm;
+//      { 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00 }
+        aMemStrm << sal_uInt32( 12 ) << sal_Int16( 8 ) << sal_Int16( 8 ) << sal_uInt16( 1 ) << sal_uInt16( 1 );
+        aMemStrm << sal_uInt8( 0xFF ) << sal_uInt8( 0xFF ) << sal_uInt8( 0xFF );
+        aMemStrm << sal_uInt8( 0x00 ) << sal_uInt8( 0x00 ) << sal_uInt8( 0x00 );
+        for( size_t nIdx = 0; nIdx < 8; ++nIdx )
+            aMemStrm << sal_uInt32( pnPattern[ nIdx ] ); // 32-bit little-endian
+        aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
+        Bitmap aBitmap;
+        aBitmap.Read( aMemStrm, FALSE );
+        XOBitmap aXOBitmap( aBitmap );
+        aXOBitmap.Bitmap2Array();
+        aXOBitmap.SetBitmapType( XBITMAP_8X8 );
+        if( aXOBitmap.GetBackgroundColor().GetColor() == COL_BLACK )
+            ::std::swap( aPattColor, aBackColor );
+        aXOBitmap.SetPixelColor( aPattColor );
+        aXOBitmap.SetBackgroundColor( aBackColor );
+        rSdrObj.SetMergedItem( XFillStyleItem( XFILL_BITMAP ) );
+        rSdrObj.SetMergedItem( XFillBitmapItem( EMPTY_STRING, aXOBitmap ) );
+#endif
+    }
+
+    aFillProps.pushToPropMap( rPropMap, getBaseFilter().getGraphicHelper() );
+}
+
+void BiffDrawingObjectBase::convertFrameProperties( ShapePropertyMap& /*rPropMap*/, sal_uInt16 /*nFrameFlags*/ ) const
+{
+}
+
+void BiffDrawingObjectBase::implReadObjBiff3( BiffInputStream& /*rStrm*/, sal_uInt16 /*nMacroSize*/ )
+{
+}
+
+void BiffDrawingObjectBase::implReadObjBiff4( BiffInputStream& /*rStrm*/, sal_uInt16 /*nMacroSize*/ )
+{
+}
+
+void BiffDrawingObjectBase::implReadObjBiff5( BiffInputStream& /*rStrm*/, sal_uInt16 /*nNameLen*/, sal_uInt16 /*nMacroSize*/ )
+{
+}
+
+void BiffDrawingObjectBase::implReadObjBiff8SubRec( BiffInputStream& /*rStrm*/, sal_uInt16 /*nSubRecId*/, sal_uInt16 /*nSubRecSize*/ )
+{
+}
+
+// private --------------------------------------------------------------------
+
+void BiffDrawingObjectBase::importObjBiff3( BiffInputStream& rStrm )
+{
+    // back to offset 4 (ignore object count field)
+    rStrm.seek( 4 );
+
+    sal_uInt16 nObjFlags, nMacroSize;
+    rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
+    rStrm.skip( 2 );
+
+    mbHasAnchor = true;
+    mbHidden = getFlag( nObjFlags, BIFF_OBJ_HIDDEN );
+    mbVisible = getFlag( nObjFlags, BIFF_OBJ_VISIBLE );
+    implReadObjBiff3( rStrm, nMacroSize );
+}
+
+void BiffDrawingObjectBase::importObjBiff4( BiffInputStream& rStrm )
+{
+    // back to offset 4 (ignore object count field)
+    rStrm.seek( 4 );
+
+    sal_uInt16 nObjFlags, nMacroSize;
+    rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
+    rStrm.skip( 2 );
+
+    mbHasAnchor = true;
+    mbHidden = getFlag( nObjFlags, BIFF_OBJ_HIDDEN );
+    mbVisible = getFlag( nObjFlags, BIFF_OBJ_VISIBLE );
+    mbPrintable = getFlag( nObjFlags, BIFF_OBJ_PRINTABLE );
+    implReadObjBiff4( rStrm, nMacroSize );
+}
+
+void BiffDrawingObjectBase::importObjBiff5( BiffInputStream& rStrm )
+{
+    // back to offset 4 (ignore object count field)
+    rStrm.seek( 4 );
+
+    sal_uInt16 nObjFlags, nMacroSize, nNameLen;
+    rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
+    rStrm.skip( 2 );
+    rStrm >> nNameLen;
+    rStrm.skip( 2 );
+
+    mbHasAnchor = true;
+    mbHidden = getFlag( nObjFlags, BIFF_OBJ_HIDDEN );
+    mbVisible = getFlag( nObjFlags, BIFF_OBJ_VISIBLE );
+    mbPrintable = getFlag( nObjFlags, BIFF_OBJ_PRINTABLE );
+    implReadObjBiff5( rStrm, nNameLen, nMacroSize );
+}
+
+void BiffDrawingObjectBase::importObjBiff8( BiffInputStream& rStrm )
+{
+    // back to beginning
+    rStrm.seekToStart();
+
+    bool bLoop = true;
+    while( bLoop && (rStrm.getRemaining() >= 4) )
+    {
+        sal_uInt16 nSubRecId, nSubRecSize;
+        rStrm >> nSubRecId >> nSubRecSize;
+        sal_Int64 nStrmPos = rStrm.tell();
+        // sometimes the last subrecord has an invalid length (OBJLBSDATA) -> min()
+        nSubRecSize = static_cast< sal_uInt16 >( ::std::min< sal_Int64 >( nSubRecSize, rStrm.getRemaining() ) );
+
+        switch( nSubRecId )
+        {
+            case BIFF_ID_OBJCMO:
+                OSL_ENSURE( rStrm.tell() == 4, "BiffDrawingObjectBase::importObjBiff8 - unexpected OBJCMO subrecord" );
+                if( (rStrm.tell() == 4) && (nSubRecSize >= 6) )
+                {
+                    sal_uInt16 nObjFlags;
+                    rStrm >> mnObjType >> mnObjId >> nObjFlags;
+                    mbPrintable = getFlag( nObjFlags, BIFF_OBJCMO_PRINTABLE );
+                }
+            break;
+            case BIFF_ID_OBJMACRO:
+                readMacroBiff8( rStrm );
+            break;
+            case BIFF_ID_OBJEND:
+                bLoop = false;
+            break;
+            default:
+                implReadObjBiff8SubRec( rStrm, nSubRecId, nSubRecSize );
+        }
+
+        // seek to end of subrecord
+        rStrm.seek( nStrmPos + nSubRecSize );
+    }
+
+    /*  Call doReadObj8SubRec() with BIFF_ID_OBJEND for further stream
+        processing (e.g. charts), even if the OBJEND subrecord is missing. */
+    implReadObjBiff8SubRec( rStrm, BIFF_ID_OBJEND, 0 );
+
+    /*  Pictures that Excel reads from BIFF5 and writes to BIFF8 still have the
+        IMGDATA record following the OBJ record (but they use the image data
+        stored in DFF). The IMGDATA record may be continued by several CONTINUE
+        records. But the last CONTINUE record may be in fact an MSODRAWING
+        record that contains the DFF data of the next drawing object! So we
+        have to skip just enough CONTINUE records to look at the next
+        MSODRAWING/CONTINUE record. */
+    if( (rStrm.getNextRecId() == BIFF3_ID_IMGDATA) && rStrm.startNextRecord() )
+    {
+        rStrm.skip( 4 );
+        sal_Int64 nDataSize = rStrm.readuInt32();
+        nDataSize -= rStrm.getRemaining();
+        // skip following CONTINUE records until IMGDATA ends
+        while( (nDataSize > 0) && (rStrm.getNextRecId() == BIFF_ID_CONT) && rStrm.startNextRecord() )
+        {
+            OSL_ENSURE( nDataSize >= rStrm.getRemaining(), "BiffDrawingObjectBase::importObjBiff8 - CONTINUE too long" );
+            nDataSize -= ::std::min( rStrm.getRemaining(), nDataSize );
+        }
+        OSL_ENSURE( nDataSize == 0, "BiffDrawingObjectBase::importObjBiff8 - missing CONTINUE records" );
+        // next record may be MSODRAWING or CONTINUE or anything else
+    }
+}
+
+// ============================================================================
+
+BiffPlaceholderObject::BiffPlaceholderObject( const WorksheetHelper& rHelper ) :
+    BiffDrawingObjectBase( rHelper )
+{
+    setProcessShape( false );
+}
+
+Reference< XShape > BiffPlaceholderObject::implConvertAndInsert( BiffDrawingBase& /*rDrawing*/,
+        const Reference< XShapes >& /*rxShapes*/, const Rectangle& /*rShapeRect*/ ) const
+{
+    return Reference< XShape >();
+}
+
+// ============================================================================
+
+BiffGroupObject::BiffGroupObject( const WorksheetHelper& rHelper ) :
+    BiffDrawingObjectBase( rHelper ),
+    mnFirstUngrouped( BIFF_OBJ_INVALID_ID )
+{
+}
+
+bool BiffGroupObject::tryInsert( const BiffDrawingObjectRef& rxDrawingObj )
+{
+    if( rxDrawingObj->getObjId() == mnFirstUngrouped )
+        return false;
+    // insert into own list or into nested group
+    maChildren.insertGrouped( rxDrawingObj );
+    return true;
+}
+
+void BiffGroupObject::implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    rStrm.skip( 4 );
+    rStrm >> mnFirstUngrouped;
+    rStrm.skip( 16 );
+    readMacroBiff3( rStrm, nMacroSize );
+}
+
+void BiffGroupObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    rStrm.skip( 4 );
+    rStrm >> mnFirstUngrouped;
+    rStrm.skip( 16 );
+    readMacroBiff4( rStrm, nMacroSize );
+}
+
+void BiffGroupObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+    rStrm.skip( 4 );
+    rStrm >> mnFirstUngrouped;
+    rStrm.skip( 16 );
+    readNameBiff5( rStrm, nNameLen );
+    readMacroBiff5( rStrm, nMacroSize );
+}
+
+Reference< XShape > BiffGroupObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
+        const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
+{
+    Reference< XShape > xGroupShape;
+    if( !maChildren.empty() ) try
+    {
+        xGroupShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rxShapes, rShapeRect );
+        Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
+        maChildren.convertAndInsert( rDrawing, xChildShapes, &rShapeRect );
+        // no child shape has been created - delete the group shape
+        if( !xChildShapes->hasElements() )
+        {
+            rxShapes->remove( xGroupShape );
+            xGroupShape.clear();
+        }
+    }
+    catch( Exception& )
+    {
+    }
+    return xGroupShape;
+}
+
+// ============================================================================
+
+BiffLineObject::BiffLineObject( const WorksheetHelper& rHelper ) :
+    BiffDrawingObjectBase( rHelper ),
+    mnArrows( 0 ),
+    mnStartPoint( BIFF_OBJ_LINE_TL )
+{
+    setAreaObj( false );
+}
+
+void BiffLineObject::implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    rStrm >> maLineModel >> mnArrows >> mnStartPoint;
+    rStrm.skip( 1 );
+    readMacroBiff3( rStrm, nMacroSize );
+}
+
+void BiffLineObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    rStrm >> maLineModel >> mnArrows >> mnStartPoint;
+    rStrm.skip( 1 );
+    readMacroBiff4( rStrm, nMacroSize );
+}
+
+void BiffLineObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+    rStrm >> maLineModel >> mnArrows >> mnStartPoint;
+    rStrm.skip( 1 );
+    readNameBiff5( rStrm, nNameLen );
+    readMacroBiff5( rStrm, nMacroSize );
+}
+
+Reference< XShape > BiffLineObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
+        const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
+{
+    ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
+    convertLineProperties( aPropMap, maLineModel, mnArrows );
+
+    // create the line polygon
+    PointSequenceSequence aPoints( 1 );
+    aPoints[ 0 ].realloc( 2 );
+    Point& rBeg = aPoints[ 0 ][ 0 ];
+    Point& rEnd = aPoints[ 0 ][ 1 ];
+    sal_Int32 nL = rShapeRect.X;
+    sal_Int32 nT = rShapeRect.Y;
+    sal_Int32 nR = rShapeRect.X + ::std::max< sal_Int32 >( rShapeRect.Width - 1, 0 );
+    sal_Int32 nB = rShapeRect.Y + ::std::max< sal_Int32 >( rShapeRect.Height - 1, 0 );
+    switch( mnStartPoint )
+    {
+        default:
+        case BIFF_OBJ_LINE_TL: rBeg.X = nL; rBeg.Y = nT; rEnd.X = nR; rEnd.Y = nB; break;
+        case BIFF_OBJ_LINE_TR: rBeg.X = nR; rBeg.Y = nT; rEnd.X = nL; rEnd.Y = nB; break;
+        case BIFF_OBJ_LINE_BR: rBeg.X = nR; rBeg.Y = nB; rEnd.X = nL; rEnd.Y = nT; break;
+        case BIFF_OBJ_LINE_BL: rBeg.X = nL; rBeg.Y = nB; rEnd.X = nR; rEnd.Y = nT; break;
+    }
+    aPropMap.setProperty( PROP_PolyPolygon, aPoints );
+    aPropMap.setProperty( PROP_PolygonKind, PolygonKind_LINE );
+
+    // create the shape
+    Reference< XShape > xShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.LineShape" ), rxShapes, rShapeRect );
+    PropertySet( xShape ).setProperties( aPropMap );
+    return xShape;
+}
+
+// ============================================================================
+
+BiffRectObject::BiffRectObject( const WorksheetHelper& rHelper ) :
+    BiffDrawingObjectBase( rHelper ),
+    mnFrameFlags( 0 )
+{
+    setAreaObj( true );
+}
+
+void BiffRectObject::readFrameData( BiffInputStream& rStrm )
+{
+    rStrm >> maFillModel >> maLineModel >> mnFrameFlags;
+}
+
+void BiffRectObject::convertRectProperties( ShapePropertyMap& rPropMap ) const
+{
+    convertLineProperties( rPropMap, maLineModel );
+    convertFillProperties( rPropMap, maFillModel );
+    convertFrameProperties( rPropMap, mnFrameFlags );
+}
+
+void BiffRectObject::implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    readFrameData( rStrm );
+    readMacroBiff3( rStrm, nMacroSize );
+}
+
+void BiffRectObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    readFrameData( rStrm );
+    readMacroBiff4( rStrm, nMacroSize );
+}
+
+void BiffRectObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+    readFrameData( rStrm );
+    readNameBiff5( rStrm, nNameLen );
+    readMacroBiff5( rStrm, nMacroSize );
+}
+
+Reference< XShape > BiffRectObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
+        const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
+{
+    ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
+    convertRectProperties( aPropMap );
+
+    Reference< XShape > xShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.RectangleShape" ), rxShapes, rShapeRect );
+    PropertySet( xShape ).setProperties( aPropMap );
+    return xShape;
+}
+
+// ============================================================================
+
+BiffOvalObject::BiffOvalObject( const WorksheetHelper& rHelper ) :
+    BiffRectObject( rHelper )
+{
+}
+
+Reference< XShape > BiffOvalObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
+        const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
+{
+    ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
+    convertRectProperties( aPropMap );
+
+    Reference< XShape > xShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ), rxShapes, rShapeRect );
+    PropertySet( xShape ).setProperties( aPropMap );
+    return xShape;
+}
+
+// ============================================================================
+
+BiffArcObject::BiffArcObject( const WorksheetHelper& rHelper ) :
+    BiffDrawingObjectBase( rHelper ),
+    mnQuadrant( BIFF_OBJ_ARC_TR )
+{
+    setAreaObj( false );    // arc may be 2-dimensional
+}
+
+void BiffArcObject::implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    rStrm >> maFillModel >> maLineModel >> mnQuadrant;
+    rStrm.skip( 1 );
+    readMacroBiff3( rStrm, nMacroSize );
+}
+
+void BiffArcObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    rStrm >> maFillModel >> maLineModel >> mnQuadrant;
+    rStrm.skip( 1 );
+    readMacroBiff4( rStrm, nMacroSize );
+}
+
+void BiffArcObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+    rStrm >> maFillModel >> maLineModel >> mnQuadrant;
+    rStrm.skip( 1 );
+    readNameBiff5( rStrm, nNameLen );
+    readMacroBiff5( rStrm, nMacroSize );
+}
+
+Reference< XShape > BiffArcObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
+        const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
+{
+    ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
+    convertLineProperties( aPropMap, maLineModel );
+    convertFillProperties( aPropMap, maFillModel );
+
+    /*  Simulate arc objects with ellipse sections. While the original arc
+        object uses the entire object rectangle, only one quarter of the
+        ellipse shape will be visible. Thus, the size of the ellipse shape
+        needs to be extended and its position adjusted according to the visible
+        quadrant. */
+    Rectangle aNewRect( rShapeRect.X, rShapeRect.Y, rShapeRect.Width * 2, rShapeRect.Height * 2 );
+    long nStartAngle = 0;
+    switch( mnQuadrant )
+    {
+        default:
+        case BIFF_OBJ_ARC_TR: nStartAngle =     0; aNewRect.X -= rShapeRect.Width;                                  break;
+        case BIFF_OBJ_ARC_TL: nStartAngle =  9000;                                                                  break;
+        case BIFF_OBJ_ARC_BL: nStartAngle = 18000;                                 aNewRect.Y -= rShapeRect.Height; break;
+        case BIFF_OBJ_ARC_BR: nStartAngle = 27000; aNewRect.X -= rShapeRect.Width; aNewRect.Y -= rShapeRect.Height; break;
+    }
+    long nEndAngle = (nStartAngle + 9000) % 36000;
+    aPropMap.setProperty( PROP_CircleKind, maFillModel.isFilled() ? CircleKind_SECTION : CircleKind_ARC );
+    aPropMap.setProperty( PROP_CircleStartAngle, nStartAngle );
+    aPropMap.setProperty( PROP_CircleEndAngle, nEndAngle );
+
+    // create the shape
+    Reference< XShape > xShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ), rxShapes, aNewRect );
+    PropertySet( xShape ).setProperties( aPropMap );
+    return xShape;
+}
+
+// ============================================================================
+
+BiffPolygonObject::BiffPolygonObject( const WorksheetHelper& rHelper ) :
+    BiffRectObject( rHelper ),
+    mnPolyFlags( 0 ),
+    mnPointCount( 0 )
+{
+    setAreaObj( false );    // polygon may be 2-dimensional
+}
+
+void BiffPolygonObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
+{
+    readFrameData( rStrm );
+    rStrm >> mnPolyFlags;
+    rStrm.skip( 10 );
+    rStrm >> mnPointCount;
+    rStrm.skip( 8 );
+    readMacroBiff4( rStrm, nMacroSize );
+    importCoordList( rStrm );
+}
+
+void BiffPolygonObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+    readFrameData( rStrm );
+    rStrm >> mnPolyFlags;
+    rStrm.skip( 10 );
+    rStrm >> mnPointCount;
+    rStrm.skip( 8 );
+    readNameBiff5( rStrm, nNameLen );
+    readMacroBiff5( rStrm, nMacroSize );
+    importCoordList( rStrm );
+}
+
+namespace {
+
+Point lclGetPolyPoint( const Rectangle& rAnchorRect, const Point& rPoint )
+{
+    // polygon coordinates are given in 1/16384 of shape size
+    return Point(
+        rAnchorRect.X + static_cast< sal_Int32 >( rAnchorRect.Width * getLimitedValue< double >( static_cast< double >( rPoint.X ) / 16384.0, 0.0, 1.0 ) + 0.5 ),
+        rAnchorRect.Y + static_cast< sal_Int32 >( rAnchorRect.Height * getLimitedValue< double >( static_cast< double >( rPoint.Y ) / 16384.0, 0.0, 1.0 ) + 0.5 ) );
+}
+
+} // namespace
+
+Reference< XShape > BiffPolygonObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
+        const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
+{
+    Reference< XShape > xShape;
+    if( maCoords.size() >= 2 )
+    {
+        ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
+        convertRectProperties( aPropMap );
+
+        // create the polygon
+        PointVector aPolygon;
+        for( PointVector::const_iterator aIt = maCoords.begin(), aEnd = maCoords.end(); aIt != aEnd; ++aIt )
+            aPolygon.push_back( lclGetPolyPoint( rShapeRect, *aIt ) );
+        // close polygon if specified
+        if( getFlag( mnPolyFlags, BIFF_OBJ_POLY_CLOSED ) && ((maCoords.front().X != maCoords.back().X) || (maCoords.front().Y != maCoords.back().Y)) )
+            aPolygon.push_back( aPolygon.front() );
+        PointSequenceSequence aPoints( 1 );
+        aPoints[ 0 ] = ContainerHelper::vectorToSequence( aPolygon );
+        aPropMap.setProperty( PROP_PolyPolygon, aPoints );
+
+        // create the shape
+        OUString aService = maFillModel.isFilled() ?
+            CREATE_OUSTRING( "com.sun.star.drawing.PolyPolygonShape" ) :
+            CREATE_OUSTRING( "com.sun.star.drawing.PolyLineShape" );
+        xShape = rDrawing.createAndInsertXShape( aService, rxShapes, rShapeRect );
+        PropertySet( xShape ).setProperties( aPropMap );
+    }
+    return xShape;
+}
+
+void BiffPolygonObject::importCoordList( BiffInputStream& rStrm )
+{
+    if( (rStrm.getNextRecId() == BIFF_ID_COORDLIST) && rStrm.startNextRecord() )
+    {
+        OSL_ENSURE( rStrm.getRemaining() / 4 == mnPointCount, "BiffPolygonObject::importCoordList - wrong polygon point count" );
+        while( rStrm.getRemaining() >= 4 )
+        {
+            sal_uInt16 nX, nY;
+            rStrm >> nX >> nY;
+            maCoords.push_back( Point( nX, nY ) );
+        }
+    }
+}
+
+// ============================================================================
+// BIFF drawing page
+// ============================================================================
+
+BiffDrawingBase::BiffDrawingBase( const WorksheetHelper& rHelper, const Reference< XDrawPage >& rxDrawPage ) :
+    WorksheetHelper( rHelper ),
+    mxDrawPage( rxDrawPage )
+{
+}
+
+void BiffDrawingBase::importObj( BiffInputStream& rStrm )
+{
+    BiffDrawingObjectRef xDrawingObj;
+
+#if 0
+    /*  #i61786# In BIFF8 streams, OBJ records may occur without MSODRAWING
+        records. In this case, the OBJ records are in BIFF5 format. Do a sanity
+        check here that there is no DFF data loaded before. */
+    DBG_ASSERT( maDffStrm.Tell() == 0, "BiffDrawingBase::importObj - unexpected DFF stream data, OBJ will be ignored" );
+    if( maDffStrm.Tell() == 0 ) switch( GetBiff() )
+#else
+    switch( getBiff() )
+#endif
+    {
+        case BIFF3:
+            xDrawingObj = BiffDrawingObjectBase::importObjBiff3( *this, rStrm );
+        break;
+        case BIFF4:
+            xDrawingObj = BiffDrawingObjectBase::importObjBiff4( *this, rStrm );
+        break;
+        case BIFF5:
+// TODO: add BIFF8 when DFF is supported
+//        case BIFF8:
+            xDrawingObj = BiffDrawingObjectBase::importObjBiff5( *this, rStrm );
+        break;
+        default:;
+    }
+
+    if( xDrawingObj.get() )
+    {
+        // insert into maRawObjs or into the last open group object
+        maRawObjs.insertGrouped( xDrawingObj );
+        // to be able to find objects by ID
+        maObjMapId[ xDrawingObj->getObjId() ] = xDrawingObj;
+    }
+}
+
+void BiffDrawingBase::setSkipObj( sal_uInt16 nObjId )
+{
+    /*  Store identifiers of objects to be skipped in a separate list (the OBJ
+        record may not be read yet). In the finalization phase, all objects
+        registered here will be skipped. */
+    maSkipObjs.push_back( nObjId );
+}
+
+void BiffDrawingBase::finalizeImport()
+{
+    Reference< XShapes > xShapes( mxDrawPage, UNO_QUERY );
+    OSL_ENSURE( xShapes.is(), "BiffDrawingBase::finalizeImport - no shapes container" );
+    if( !xShapes.is() )
+        return;
+
+    // process list of objects to be skipped
+    for( BiffObjIdVector::const_iterator aIt = maSkipObjs.begin(), aEnd = maSkipObjs.end(); aIt != aEnd; ++aIt )
+        if( BiffDrawingObjectBase* pDrawingObj = maObjMapId.get( *aIt ).get() )
+            pDrawingObj->setProcessShape( false );
+
+    // process drawing objects without DFF data
+    maRawObjs.convertAndInsert( *this, xShapes );
+}
+
+Reference< XShape > BiffDrawingBase::createAndInsertXShape( const OUString& rService,
+        const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
+{
+    OSL_ENSURE( !rService.isEmpty(), "BiffDrawingBase::createAndInsertXShape - missing UNO shape service name" );
+    OSL_ENSURE( rxShapes.is(), "BiffDrawingBase::createAndInsertXShape - missing XShapes container" );
+    Reference< XShape > xShape;
+    if( !rService.isEmpty() && rxShapes.is() ) try
+    {
+        xShape.set( getBaseFilter().getModelFactory()->createInstance( rService ), UNO_QUERY_THROW );
+        // insert shape into passed shape collection (maybe drawpage or group shape)
+        rxShapes->add( xShape );
+        xShape->setPosition( Point( rShapeRect.X, rShapeRect.Y ) );
+        xShape->setSize( Size( rShapeRect.Width, rShapeRect.Height ) );
+    }
+    catch( Exception& )
+    {
+    }
+    OSL_ENSURE( xShape.is(), "BiffDrawingBase::createAndInsertXShape - cannot instanciate shape object" );
+    return xShape;
+}
+
+// protected ------------------------------------------------------------------
+
+void BiffDrawingBase::appendRawObject( const BiffDrawingObjectRef& rxDrawingObj )
+{
+    OSL_ENSURE( rxDrawingObj.get(), "BiffDrawingBase::appendRawObject - unexpected empty object reference" );
+    maRawObjs.append( rxDrawingObj );
+}
+
+// ============================================================================
+
+BiffSheetDrawing::BiffSheetDrawing( const WorksheetHelper& rHelper ) :
+    BiffDrawingBase( rHelper, rHelper.getDrawPage() )
+{
+}
+
+void BiffSheetDrawing::notifyShapeInserted( const Reference< XShape >& /*rxShape*/, const Rectangle& rShapeRect )
+{
+    // collect all shape positions in the WorksheetHelper base class
+    extendShapeBoundingBox( rShapeRect );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/excelchartconverter.cxx b/sc/source/filter/oox/excelchartconverter.cxx
new file mode 100644
index 000000000000..a6303b0362ea
--- /dev/null
+++ b/sc/source/filter/oox/excelchartconverter.cxx
@@ -0,0 +1,139 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "excelchartconverter.hxx"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "oox/core/filterbase.hxx"
+#include "oox/drawingml/chart/datasourcemodel.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "formulaparser.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::chart2;
+using namespace ::com::sun::star::chart2::data;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::oox::drawingml::chart::DataSequenceModel;
+using ::rtl::OUString;
+
+// ============================================================================
+
+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< XDataProvider > xDataProv( getBaseFilter().getModelFactory()->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())
+        return xDataSeq;
+
+    Reference xSheetProvider(rxDataProvider, UNO_QUERY);
+    if (!xSheetProvider.is())
+        return xDataSeq;
+
+    if (!rDataSeq.maFormula.isEmpty())
+    {
+        // parse the formula string, create a token sequence
+        FormulaParser& rParser = getFormulaParser();
+        CellAddress aBaseAddr( getCurrentSheetIndex(), 0, 0 );
+        ApiTokenSequence aTokens = rParser.importFormula( aBaseAddr, rDataSeq.maFormula );
+
+        try
+        {
+            // create the data sequence
+            xDataSeq = xSheetProvider->createDataSequenceByFormulaTokens(aTokens);
+        }
+        catch (Exception&)
+        {
+            OSL_FAIL( "ExcelChartConverter::createDataSequence - cannot create data sequence" );
+        }
+    }
+    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;
+        OUString aRangeRep = FormulaProcessorBase::generateApiArray( aMatrix );
+
+        if (!aRangeRep.isEmpty())
+        {
+            try
+            {
+                // create the data sequence
+                xDataSeq = rxDataProvider->createDataSequenceByRangeRepresentation( aRangeRep );
+            }
+            catch (Exception&)
+            {
+                OSL_FAIL( "ExcelChartConverter::createDataSequence - cannot create data sequence" );
+            }
+        }
+    }
+    return xDataSeq;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/excelfilter.cxx b/sc/source/filter/oox/excelfilter.cxx
new file mode 100644
index 000000000000..57c9749e7f96
--- /dev/null
+++ b/sc/source/filter/oox/excelfilter.cxx
@@ -0,0 +1,360 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "excelfilter.hxx"
+
+#include 
+//#include "oox/dump/biffdumper.hxx"
+//#include "oox/dump/xlsbdumper.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+#include "biffdetector.hxx"
+#include "biffinputstream.hxx"
+#include "excelchartconverter.hxx"
+#include "excelvbaproject.hxx"
+#include "stylesbuffer.hxx"
+#include "themebuffer.hxx"
+#include "workbookfragment.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+using ::oox::drawingml::table::TableStyleListPtr;
+
+// ============================================================================
+
+ExcelFilterBase::ExcelFilterBase() :
+    mpBookGlob( 0 )
+{
+}
+
+ExcelFilterBase::~ExcelFilterBase()
+{
+    OSL_ENSURE( !mpBookGlob, "ExcelFilterBase::~ExcelFilterBase - workbook data not cleared" );
+}
+
+void ExcelFilterBase::registerWorkbookGlobals( WorkbookGlobals& rBookGlob )
+{
+    mpBookGlob = &rBookGlob;
+}
+
+WorkbookGlobals& ExcelFilterBase::getWorkbookGlobals() const
+{
+    OSL_ENSURE( mpBookGlob, "ExcelFilterBase::getWorkbookGlobals - missing workbook data" );
+    return *mpBookGlob;
+}
+
+void ExcelFilterBase::unregisterWorkbookGlobals()
+{
+    mpBookGlob = 0;
+}
+
+// ============================================================================
+
+OUString SAL_CALL ExcelFilter_getImplementationName() throw()
+{
+    return CREATE_OUSTRING( "com.sun.star.comp.oox.xls.ExcelFilter" );
+}
+
+Sequence< OUString > SAL_CALL ExcelFilter_getSupportedServiceNames() throw()
+{
+    Sequence< OUString > aSeq( 2 );
+    aSeq[ 0 ] = CREATE_OUSTRING( "com.sun.star.document.ImportFilter" );
+    aSeq[ 1 ] = CREATE_OUSTRING( "com.sun.star.document.ExportFilter" );
+    return aSeq;
+}
+
+Reference< XInterface > SAL_CALL ExcelFilter_createInstance(
+        const Reference< XComponentContext >& rxContext ) throw( Exception )
+{
+    return static_cast< ::cppu::OWeakObject* >( new ExcelFilter( rxContext ) );
+}
+
+// ----------------------------------------------------------------------------
+
+ExcelFilter::ExcelFilter( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
+    XmlFilterBase( rxContext )
+{
+}
+
+ExcelFilter::~ExcelFilter()
+{
+}
+
+bool ExcelFilter::importDocument() throw()
+{
+    /*  To activate the XLSX/XLSB dumper, insert the full path to the file
+        file:////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_RELATION_TYPE( "officeDocument" ) );
+    if( aWorkbookPath.isEmpty() )
+        return false;
+
+    /*  Construct the WorkbookGlobals object referred to by every instance of
+        the class WorkbookHelper, and execute the import filter by constructing
+        an instance of WorkbookFragment and loading the file. */
+    WorkbookGlobalsRef xBookGlob = WorkbookHelper::constructGlobals( *this );
+    if ( xBookGlob.get() && importFragment( new WorkbookFragment( *xBookGlob, aWorkbookPath ) ) )
+    {
+        importDocumentProperties();
+        return true;
+    }
+    return false;
+}
+
+bool ExcelFilter::exportDocument() throw()
+{
+    return false;
+}
+
+const ::oox::drawingml::Theme* ExcelFilter::getCurrentTheme() const
+{
+    return &WorkbookHelper( getWorkbookGlobals() ).getTheme();
+}
+
+::oox::vml::Drawing* ExcelFilter::getVmlDrawing()
+{
+    return 0;
+}
+
+const TableStyleListPtr ExcelFilter::getTableStyles()
+{
+    return TableStyleListPtr();
+}
+
+::oox::drawingml::chart::ChartConverter* ExcelFilter::getChartConverter()
+{
+    return WorkbookHelper( getWorkbookGlobals() ).getChartConverter();
+}
+
+GraphicHelper* ExcelFilter::implCreateGraphicHelper() const
+{
+    return new ExcelGraphicHelper( getWorkbookGlobals() );
+}
+
+::oox::ole::VbaProject* ExcelFilter::implCreateVbaProject() const
+{
+    return new ExcelVbaProject( getComponentContext(), Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
+}
+
+
+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( getServiceFactory()->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.xls.ExcelBiffFilter" );
+}
+
+Sequence< OUString > SAL_CALL ExcelBiffFilter_getSupportedServiceNames() throw()
+{
+    Sequence< OUString > aSeq( 2 );
+    aSeq[ 0 ] = CREATE_OUSTRING( "com.sun.star.document.ImportFilter" );
+    aSeq[ 1 ] = CREATE_OUSTRING( "com.sun.star.document.ExportFilter" );
+    return aSeq;
+}
+
+Reference< XInterface > SAL_CALL ExcelBiffFilter_createInstance(
+        const Reference< XComponentContext >& rxContext ) throw( Exception )
+{
+    return static_cast< ::cppu::OWeakObject* >( new ExcelBiffFilter( rxContext ) );
+}
+
+// ----------------------------------------------------------------------------
+
+ExcelBiffFilter::ExcelBiffFilter( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
+    BinaryFilterBase( rxContext )
+{
+}
+
+ExcelBiffFilter::~ExcelBiffFilter()
+{
+}
+
+bool ExcelBiffFilter::importDocument() throw()
+{
+    /*  To activate the BIFF dumper, insert the full path to the file
+        file:////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;
+
+    /*  Construct the WorkbookGlobals object referred to by every instance of
+        the class WorkbookHelper, and execute the import filter by constructing
+        an instance of BiffWorkbookFragment and loading the file. */
+    WorkbookGlobalsRef xBookGlob = WorkbookHelper::constructGlobals( *this, eBiff );
+    return xBookGlob.get() && BiffWorkbookFragment( *xBookGlob, aWorkbookName ).importFragment();
+}
+
+bool ExcelBiffFilter::exportDocument() throw()
+{
+    return false;
+}
+
+GraphicHelper* ExcelBiffFilter::implCreateGraphicHelper() const
+{
+    return new ExcelGraphicHelper( getWorkbookGlobals() );
+}
+
+::oox::ole::VbaProject* ExcelBiffFilter::implCreateVbaProject() const
+{
+    return new ExcelVbaProject( getComponentContext(), Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
+}
+
+OUString ExcelBiffFilter::implGetImplementationName() const
+{
+    return ExcelBiffFilter_getImplementationName();
+}
+
+// ============================================================================
+
+OUString SAL_CALL ExcelVbaProjectFilter_getImplementationName() throw()
+{
+    return CREATE_OUSTRING( "com.sun.star.comp.oox.xls.ExcelVbaProjectFilter" );
+}
+
+Sequence< OUString > SAL_CALL ExcelVbaProjectFilter_getSupportedServiceNames() throw()
+{
+    Sequence< OUString > aSeq( 1 );
+    aSeq[ 0 ] = CREATE_OUSTRING( "com.sun.star.document.ImportFilter" );
+    return aSeq;
+}
+
+Reference< XInterface > SAL_CALL ExcelVbaProjectFilter_createInstance(
+        const Reference< XComponentContext >& rxContext ) throw( Exception )
+{
+    return static_cast< ::cppu::OWeakObject* >( new ExcelVbaProjectFilter( rxContext ) );
+}
+
+// ----------------------------------------------------------------------------
+
+ExcelVbaProjectFilter::ExcelVbaProjectFilter( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
+    ExcelBiffFilter( rxContext )
+{
+}
+
+bool ExcelVbaProjectFilter::importDocument() throw()
+{
+    // detect BIFF version and workbook stream name
+    OUString aWorkbookName;
+    BiffType eBiff = BiffDetector::detectStorageBiffVersion( aWorkbookName, getStorage() );
+    OSL_ENSURE( eBiff == BIFF8, "ExcelVbaProjectFilter::ExcelVbaProjectFilter - invalid file format" );
+    if( eBiff != BIFF8 )
+        return false;
+
+    StorageRef xVbaPrjStrg = openSubStorage( CREATE_OUSTRING( "_VBA_PROJECT_CUR" ), false );
+    if( !xVbaPrjStrg || !xVbaPrjStrg->isStorage() )
+        return false;
+
+    /*  Construct the WorkbookGlobals object referred to by every instance of
+        the class WorkbookHelper. */
+    WorkbookGlobalsRef xBookGlob = WorkbookHelper::constructGlobals( *this, eBiff );
+    if( !xBookGlob.get() )
+        return false;
+
+    // set palette colors passed in service constructor
+    Any aPalette = getArgument( CREATE_OUSTRING( "ColorPalette" ) );
+    WorkbookHelper( *xBookGlob ).getStyles().importPalette( aPalette );
+    // import the VBA project (getVbaProject() implemented in base class)
+    getVbaProject().importVbaProject( *xVbaPrjStrg, getGraphicHelper() );
+    return true;
+}
+
+bool ExcelVbaProjectFilter::exportDocument() throw()
+{
+    return false;
+}
+
+OUString ExcelVbaProjectFilter::implGetImplementationName() const
+{
+    return ExcelVbaProjectFilter_getImplementationName();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/excelhandlers.cxx b/sc/source/filter/oox/excelhandlers.cxx
new file mode 100644
index 000000000000..a3d0b518d6e8
--- /dev/null
+++ b/sc/source/filter/oox/excelhandlers.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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "excelhandlers.hxx"
+
+#include "oox/core/filterbase.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using ::oox::core::FilterBase;
+using ::oox::core::FragmentHandler2;
+using ::rtl::OUString;
+
+// ============================================================================
+// ============================================================================
+
+WorkbookFragmentBase::WorkbookFragmentBase(
+        const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+    FragmentHandler2( rHelper.getOoxFilter(), rFragmentPath ),
+    WorkbookHelper( rHelper )
+{
+}
+
+// ============================================================================
+
+WorksheetFragmentBase::WorksheetFragmentBase(
+        const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    FragmentHandler2( rHelper.getOoxFilter(), rFragmentPath ),
+    WorksheetHelper( rHelper )
+{
+}
+
+// ============================================================================
+// ============================================================================
+
+BiffContextHandler::~BiffContextHandler()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+BiffWorkbookContextBase::BiffWorkbookContextBase( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+BiffWorksheetContextBase::BiffWorksheetContextBase( const WorksheetHelper& rHelper ) :
+    WorksheetHelper( 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
+
+// ----------------------------------------------------------------------------
+
+BiffFragmentHandler::BiffFragmentHandler( const FilterBase& rFilter, const OUString& rStrmName )
+{
+    // do not automatically close the root stream (indicated by empty stream name)
+    bool bRootStrm = rStrmName.isEmpty();
+    mxXInStrm.reset( new BinaryXInputStream( rFilter.openInputStream( rStrmName ), !bRootStrm ) );
+    mxBiffStrm.reset( new BiffInputStream( *mxXInStrm ) );
+}
+
+BiffFragmentHandler::~BiffFragmentHandler()
+{
+}
+
+BiffFragmentType BiffFragmentHandler::startFragment( 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( mxBiffStrm->startNextRecord() && BiffHelper::isBofRecord( *mxBiffStrm ) )
+    {
+        // BOF is always written unencrypted
+        mxBiffStrm->enableDecoder( false );
+        mxBiffStrm->skip( 2 );
+        sal_uInt16 nType = mxBiffStrm->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;
+}
+
+bool BiffFragmentHandler::skipFragment()
+{
+    while( mxBiffStrm->startNextRecord() && (mxBiffStrm->getRecId() != BIFF_ID_EOF) )
+        if( BiffHelper::isBofRecord( *mxBiffStrm ) )
+            skipFragment();
+    return !mxBiffStrm->isEof() && (mxBiffStrm->getRecId() == BIFF_ID_EOF);
+}
+
+// ============================================================================
+
+BiffWorkbookFragmentBase::BiffWorkbookFragmentBase( const WorkbookHelper& rHelper, const OUString& rStrmName, bool bCloneDecoder ) :
+    BiffFragmentHandler( rHelper.getBaseFilter(), rStrmName ),
+    WorkbookHelper( rHelper )
+{
+    if( bCloneDecoder )
+        getCodecHelper().cloneDecoder( getInputStream() );
+}
+
+// ----------------------------------------------------------------------------
+
+BiffWorksheetFragmentBase::BiffWorksheetFragmentBase( const WorksheetHelper& rHelper, const BiffWorkbookFragmentBase& rParent ) :
+    BiffFragmentHandler( rParent ),
+    WorksheetHelper( rHelper )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+BiffSkipWorksheetFragment::BiffSkipWorksheetFragment( const WorksheetHelper& rHelper, const BiffWorkbookFragmentBase& rParent ) :
+    BiffWorksheetFragmentBase( rHelper, rParent )
+{
+}
+
+bool BiffSkipWorksheetFragment::importFragment()
+{
+    return skipFragment();
+}
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/excelvbaproject.cxx b/sc/source/filter/oox/excelvbaproject.cxx
new file mode 100644
index 000000000000..148f27a58b47
--- /dev/null
+++ b/sc/source/filter/oox/excelvbaproject.cxx
@@ -0,0 +1,150 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "excelvbaproject.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/helper.hxx"
+#include "oox/helper/propertyset.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+ExcelVbaProject::ExcelVbaProject( const Reference< XComponentContext >& rxContext, const Reference< XSpreadsheetDocument >& rxDocument ) :
+    ::oox::ole::VbaProject( rxContext, Reference< XModel >( rxDocument, UNO_QUERY ), CREATE_OUSTRING( "Calc" ) ),
+    mxDocument( rxDocument )
+{
+}
+
+// protected ------------------------------------------------------------------
+
+namespace {
+
+struct SheetCodeNameInfo
+{
+    PropertySet         maSheetProps;       /// Property set of the sheet without codename.
+    OUString            maPrefix;           /// Prefix for the codename to be generated.
+
+    inline explicit     SheetCodeNameInfo( PropertySet& rSheetProps, const OUString& rPrefix ) :
+                            maSheetProps( rSheetProps ), maPrefix( rPrefix ) {}
+};
+
+typedef ::std::set< OUString >              CodeNameSet;
+typedef ::std::list< SheetCodeNameInfo >    SheetCodeNameInfoList;
+
+} // namespace
+
+void ExcelVbaProject::prepareImport()
+{
+    /*  Check if the sheets have imported codenames. Generate new unused
+        codenames if not. */
+    if( mxDocument.is() ) try
+    {
+        // collect existing codenames (do not use them when creating new codenames)
+        CodeNameSet aUsedCodeNames;
+
+        // collect sheets without codenames
+        SheetCodeNameInfoList aCodeNameInfos;
+
+        // iterate over all imported sheets
+        Reference< XEnumerationAccess > xSheetsEA( mxDocument->getSheets(), UNO_QUERY_THROW );
+        Reference< XEnumeration > xSheetsEnum( xSheetsEA->createEnumeration(), UNO_SET_THROW );
+        // own try/catch for every sheet
+        while( xSheetsEnum->hasMoreElements() ) try
+        {
+            PropertySet aSheetProp( xSheetsEnum->nextElement() );
+            OUString aCodeName;
+            aSheetProp.getProperty( aCodeName, PROP_CodeName );
+            if( !aCodeName.isEmpty() )
+            {
+                aUsedCodeNames.insert( aCodeName );
+            }
+            else
+            {
+                // TODO: once we have chart sheets we need a switch/case on sheet type ('SheetNNN' vs. 'ChartNNN')
+                aCodeNameInfos.push_back( SheetCodeNameInfo( aSheetProp, CREATE_OUSTRING( "Sheet" ) ) );
+            }
+        }
+        catch( Exception& )
+        {
+        }
+
+        // create new codenames if sheets do not have one
+        for( SheetCodeNameInfoList::iterator aIt = aCodeNameInfos.begin(), aEnd = aCodeNameInfos.end(); aIt != aEnd; ++aIt )
+        {
+            // search for an unused codename
+            sal_Int32 nCounter = 1;
+            OUString aCodeName;
+            do
+            {
+                aCodeName = OUStringBuffer( aIt->maPrefix ).append( nCounter++ ).makeStringAndClear();
+            }
+            while( aUsedCodeNames.count( aCodeName ) > 0 );
+            aUsedCodeNames.insert( aCodeName );
+
+            // set codename at sheet
+            aIt->maSheetProps.setProperty( PROP_CodeName, aCodeName );
+
+            // tell base class to create a dummy module
+            addDummyModule( aCodeName, ModuleType::DOCUMENT );
+        }
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/externallinkbuffer.cxx b/sc/source/filter/oox/externallinkbuffer.cxx
new file mode 100644
index 000000000000..2a6faca1455e
--- /dev/null
+++ b/sc/source/filter/oox/externallinkbuffer.cxx
@@ -0,0 +1,1136 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "externallinkbuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "excelhandlers.hxx"
+#include "formulaparser.hxx"
+#include "worksheetbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::Relation;
+using ::oox::core::Relations;
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OStringToOUString;
+using ::rtl::OUString;
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF12_EXTERNALBOOK_BOOK   = 0;
+const sal_uInt16 BIFF12_EXTERNALBOOK_DDE    = 1;
+const sal_uInt16 BIFF12_EXTERNALBOOK_OLE    = 2;
+
+const sal_uInt16 BIFF12_EXTNAME_AUTOMATIC   = 0x0002;
+const sal_uInt16 BIFF12_EXTNAME_PREFERPIC   = 0x0004;
+const sal_uInt16 BIFF12_EXTNAME_STDDOCNAME  = 0x0008;
+const sal_uInt16 BIFF12_EXTNAME_OLEOBJECT   = 0x0010;
+const sal_uInt16 BIFF12_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.isEmpty(), "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.isEmpty(), "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.isEmpty(), "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( SequenceInputStream& rStrm )
+{
+    rStrm >> maModel.maName;
+    OSL_ENSURE( !maModel.maName.isEmpty(), "ExternalName::importExternalName - empty name" );
+}
+
+void ExternalName::importExternalNameFlags( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    sal_Int32 nSheetId;
+    rStrm >> nFlags >> nSheetId;
+    // index into sheet list of EXTSHEETNAMES (one-based in BIFF12)
+    maModel.mnSheet = nSheetId - 1;
+    // no flag for built-in names, as in OOXML...
+    maExtNameModel.mbNotify     = getFlag( nFlags, BIFF12_EXTNAME_AUTOMATIC );
+    maExtNameModel.mbPreferPic  = getFlag( nFlags, BIFF12_EXTNAME_PREFERPIC );
+    maExtNameModel.mbStdDocName = getFlag( nFlags, BIFF12_EXTNAME_STDDOCNAME );
+    maExtNameModel.mbOleObj     = getFlag( nFlags, BIFF12_EXTNAME_OLEOBJECT );
+    maExtNameModel.mbIconified  = getFlag( nFlags, BIFF12_EXTNAME_ICONIFIED );
+    OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_OLE) == maExtNameModel.mbOleObj,
+        "ExternalName::importExternalNameFlags - wrong OLE flag in external name" );
+}
+
+void ExternalName::importDdeItemValues( SequenceInputStream& rStrm )
+{
+    sal_Int32 nRows, nCols;
+    rStrm >> nRows >> nCols;
+    setResultSize( nCols, nRows );
+}
+
+void ExternalName::importDdeItemBool( SequenceInputStream& rStrm )
+{
+    appendResultValue< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
+}
+
+void ExternalName::importDdeItemDouble( SequenceInputStream& rStrm )
+{
+    appendResultValue( rStrm.readDouble() );
+}
+
+void ExternalName::importDdeItemError( SequenceInputStream& rStrm )
+{
+    appendResultValue( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) );
+}
+
+void ExternalName::importDdeItemString( SequenceInputStream& rStrm )
+{
+    appendResultValue( BiffHelper::readString( rStrm ) );
+}
+
+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.isEmpty(), "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() )
+            {
+                ApiTokenSequence aTokens = importBiffFormula( mrParentLink.getCalcSheetIndex(), rStrm );
+                extractReference( aTokens );
+            }
+        break;
+
+        case LINKTYPE_EXTERNAL:
+            // cell references to other documents are stored in hidden external names
+            if( bHiddenRef )
+            {
+                ApiTokenSequence aTokens = importBiffFormula( 0, rStrm );
+                extractExternalReference( aTokens );
+            }
+        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_OOXML:
+            // OOXML/BIFF12: 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.isEmpty() )
+    {
+        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.isEmpty() )
+    {
+        // try to create a DDE link and to set the imported link results
+        if( !mbDdeLinkCreated ) try
+        {
+            PropertySet aDocProps( getDocument() );
+            Reference< XDDELinks > xDdeLinks( aDocProps.getAnyProperty( PROP_DDELinks ), UNO_QUERY_THROW );
+            mxDdeLink = xDdeLinks->addDDELink( mrParentLink.getClassName(), mrParentLink.getTargetUrl(), maModel.maName, ::com::sun::star::sheet::DDELinkMode_DEFAULT );
+            mbDdeLinkCreated = true;    // ignore if setting results fails
+            if( !maResults.empty() )
+            {
+                Reference< XDDELinkResults > xResults( mxDdeLink, UNO_QUERY_THROW );
+                xResults->setResults( ContainerHelper::matrixToSequenceSequence( maResults ) );
+            }
+        }
+        catch( Exception& )
+        {
+            OSL_FAIL( "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( SequenceInputStream& rStrm )
+{
+    rStrm >> maRelId;
+}
+
+void ExternalLink::importExternalSelf( SequenceInputStream& )
+{
+    meLinkType = LINKTYPE_SELF;
+}
+
+void ExternalLink::importExternalSame( SequenceInputStream& )
+{
+    meLinkType = LINKTYPE_SAME;
+}
+
+void ExternalLink::importExternalAddin( SequenceInputStream& )
+{
+    meLinkType = LINKTYPE_UNKNOWN;
+}
+
+void ExternalLink::importExternalBook( const Relations& rRelations, SequenceInputStream& rStrm )
+{
+    switch( rStrm.readuInt16() )
+    {
+        case BIFF12_EXTERNALBOOK_BOOK:
+            parseExternalReference( rRelations, BiffHelper::readString( rStrm ) );
+        break;
+        case BIFF12_EXTERNALBOOK_DDE:
+        {
+            OUString aDdeService, aDdeTopic;
+            rStrm >> aDdeService >> aDdeTopic;
+            setDdeOleTargetUrl( aDdeService, aDdeTopic, LINKTYPE_DDE );
+        }
+        break;
+        case BIFF12_EXTERNALBOOK_OLE:
+        {
+            OUString aTargetUrl = rRelations.getExternalTargetFromRelId( BiffHelper::readString( rStrm ) );
+            OUString aProgId = BiffHelper::readString( rStrm );
+            setDdeOleTargetUrl( aProgId, aTargetUrl, LINKTYPE_OLE );
+        }
+        break;
+        default:
+            OSL_FAIL( "ExternalLink::importExternalBook - unknown link type" );
+    }
+}
+
+void ExternalLink::importExtSheetNames( SequenceInputStream& 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( BiffHelper::readString( rStrm ) );
+}
+
+ExternalNameRef ExternalLink::importExternalName( SequenceInputStream& 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.isEmpty() ? WorksheetBuffer::getBaseFileName( maTargetUrl ) : aSheetName);
+        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.isEmpty(), "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_OOXML) || (getBiff() == BIFF8),
+        "ExternalLink::getCalcSheetIndex - invalid sheet index" );
+    return ContainerHelper::getVectorElement( 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_OOXML) || (getBiff() == BIFF8),
+        "ExternalLink::getSheetCacheIndex - invalid sheet index" );
+    return ContainerHelper::getVectorElement( 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_OOXML:
+                    // BIFF12: 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_RELATION_TYPE( "externalLinkPath" )
+#define OOX_TARGETTYPE_LIBRARY      CREATE_MSOFFICE_RELATION_TYPE( "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.isEmpty() )
+            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 ) try
+    {
+        PropertySet aDocProps( getDocument() );
+        Reference< XExternalDocLinks > xDocLinks( aDocProps.getAnyProperty( PROP_ExternalDocLinks ), UNO_QUERY_THROW );
+        mxDocLink = xDocLinks->addDocLink( maTargetUrl );
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+void ExternalLink::setDdeOleTargetUrl( const OUString& rClassName, const OUString& rTargetUrl, ExternalLinkType eLinkType )
+{
+    maClassName = rClassName;
+    maTargetUrl = rTargetUrl;
+    meLinkType = (maClassName.isEmpty() || maTargetUrl.isEmpty()) ?  LINKTYPE_UNKNOWN : eLinkType;
+    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.isEmpty() )
+            {
+                meLinkType = aSheetName.isEmpty() ? LINKTYPE_SELF : LINKTYPE_INTERNAL;
+            }
+            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.isEmpty() && aSheetName.isEmpty(), "ExternalLink::parseBiffTargetUrl - unexpected target or sheet name" );
+            meLinkType = LINKTYPE_SAME;
+        break;
+
+        case BIFF_TARGETTYPE_LIBRARY:
+            OSL_ENSURE( aSheetName.isEmpty(), "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.isEmpty(), "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::readBiff12Data( SequenceInputStream& 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 ),
+    mxSelfRef( new ExternalLink( rHelper ) ),
+    mbUseRefSheets( false )
+{
+    mxSelfRef->setSelfLinkType();
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternalReference( const AttributeList& rAttribs )
+{
+    ExternalLinkRef xExtLink = createExternalLink();
+    xExtLink->importExternalReference( rAttribs );
+    maExtLinks.push_back( xExtLink );
+    return xExtLink;
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternalRef( SequenceInputStream& rStrm )
+{
+    mbUseRefSheets = true;
+    ExternalLinkRef xExtLink = createExternalLink();
+    xExtLink->importExternalRef( rStrm );
+    maExtLinks.push_back( xExtLink );
+    return xExtLink;
+}
+
+void ExternalLinkBuffer::importExternalSelf( SequenceInputStream& rStrm )
+{
+    mbUseRefSheets = true;
+    createExternalLink()->importExternalSelf( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalSame( SequenceInputStream& rStrm )
+{
+    mbUseRefSheets = true;
+    createExternalLink()->importExternalSame( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalAddin( SequenceInputStream& rStrm )
+{
+    mbUseRefSheets = true;
+    createExternalLink()->importExternalAddin( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalSheets( SequenceInputStream& 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.readBiff12Data( 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::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(), aEnd = aIt + nRefCount; !rStrm.isEof() && (aIt != aEnd); ++aIt )
+        aIt->readBiff8Data( rStrm );
+}
+
+Sequence< ExternalLinkInfo > ExternalLinkBuffer::getLinkInfos() const
+{
+    ::std::vector< ExternalLinkInfo > aLinkInfos;
+    // should not be used for BIFF12 documents
+    OSL_ENSURE( (getFilterType() == FILTER_OOXML) && !mbUseRefSheets, "ExternalLinkBuffer::getLinkInfos - unexpected file format" );
+    // add entry for implicit index 0 (self reference to this document)
+    aLinkInfos.push_back( mxSelfRef->getLinkInfo() );
+    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, bool bUseRefSheets ) const
+{
+    ExternalLinkRef xExtLink;
+    switch( getFilterType() )
+    {
+        case FILTER_OOXML:
+            // OOXML: 0 = this document, otherwise one-based index into link list
+            if( !bUseRefSheets || !mbUseRefSheets )
+                xExtLink = (nRefId == 0) ? mxSelfRef : maLinks.get( nRefId - 1 );
+            // BIFF12: 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_OOXML) && 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/sc/source/filter/oox/externallinkfragment.cxx b/sc/source/filter/oox/externallinkfragment.cxx
new file mode 100644
index 000000000000..0b7c3794e57a
--- /dev/null
+++ b/sc/source/filter/oox/externallinkfragment.cxx
@@ -0,0 +1,551 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "externallinkfragment.hxx"
+
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "biffinputstream.hxx"
+#include "defnamesbuffer.hxx"
+#include "sheetdatacontext.hxx"
+#include "unitconverter.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+// ============================================================================
+
+ExternalSheetDataContext::ExternalSheetDataContext(
+        WorkbookFragmentBase& rFragment, const Reference< XExternalSheetCache >& rxSheetCache ) :
+    WorkbookContextBase( rFragment ),
+    mxSheetCache( rxSheetCache )
+{
+    OSL_ENSURE( mxSheetCache.is(), "ExternalSheetDataContext::ExternalSheetDataContext - missing sheet cache" );
+}
+
+ContextHandlerRef ExternalSheetDataContext::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 onCharacters()
+        break;
+    }
+    return 0;
+}
+
+void ExternalSheetDataContext::onCharacters( const OUString& rChars )
+{
+    if( isCurrentElement( 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;
+    }
+}
+
+ContextHandlerRef ExternalSheetDataContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_EXTSHEETDATA:
+            if( nRecId == BIFF12_ID_EXTROW ) { maCurrPos.Row = rStrm.readInt32(); return this; }
+        break;
+        case BIFF12_ID_EXTROW:
+            switch( nRecId )
+            {
+                case BIFF12_ID_EXTCELL_BLANK:   importExtCellBlank( rStrm );    break;
+                case BIFF12_ID_EXTCELL_BOOL:    importExtCellBool( rStrm );     break;
+                case BIFF12_ID_EXTCELL_DOUBLE:  importExtCellDouble( rStrm );   break;
+                case BIFF12_ID_EXTCELL_ERROR:   importExtCellError( rStrm );    break;
+                case BIFF12_ID_EXTCELL_STRING:  importExtCellString( rStrm );   break;
+            }
+        break;
+    }
+    return 0;
+}
+
+// private --------------------------------------------------------------------
+
+void ExternalSheetDataContext::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 ExternalSheetDataContext::importExtCellBlank( SequenceInputStream& rStrm )
+{
+    maCurrPos.Column = rStrm.readInt32();
+    setCellValue( Any( OUString() ) );
+}
+
+void ExternalSheetDataContext::importExtCellBool( SequenceInputStream& rStrm )
+{
+    maCurrPos.Column = rStrm.readInt32();
+    double fValue = (rStrm.readuInt8() == 0) ? 0.0 : 1.0;
+    setCellValue( Any( fValue ) );
+}
+
+void ExternalSheetDataContext::importExtCellDouble( SequenceInputStream& rStrm )
+{
+    maCurrPos.Column = rStrm.readInt32();
+    setCellValue( Any( rStrm.readDouble() ) );
+}
+
+void ExternalSheetDataContext::importExtCellError( SequenceInputStream& rStrm )
+{
+    maCurrPos.Column = rStrm.readInt32();
+    setCellValue( Any( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) ) );
+}
+
+void ExternalSheetDataContext::importExtCellString( SequenceInputStream& rStrm )
+{
+    maCurrPos.Column = rStrm.readInt32();
+    setCellValue( Any( BiffHelper::readString( rStrm ) ) );
+}
+
+void ExternalSheetDataContext::setCellValue( const Any& rValue )
+{
+    if( mxSheetCache.is() && getAddressConverter().checkCellAddress( maCurrPos, false ) ) try
+    {
+        mxSheetCache->setCellValue( maCurrPos.Column, maCurrPos.Row, rValue );
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+// ============================================================================
+
+ExternalLinkFragment::ExternalLinkFragment( const WorkbookHelper& rHelper,
+        const OUString& rFragmentPath, ExternalLink& rExtLink ) :
+    WorkbookFragmentBase( rHelper, rFragmentPath ),
+    mrExtLink( rExtLink ),
+    mnResultType( XML_TOKEN_INVALID )
+{
+}
+
+ContextHandlerRef ExternalLinkFragment::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 onCharacters()
+        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 ExternalLinkFragment::onCharacters( const OUString& rChars )
+{
+    if( isCurrentElement( XLS_TOKEN( val ) ) )
+        maResultValue = rChars;
+}
+
+void ExternalLinkFragment::onEndElement()
+{
+    if( isCurrentElement( XLS_TOKEN( value ) ) && 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 ) );
+    }
+}
+
+ContextHandlerRef ExternalLinkFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_EXTERNALBOOK )
+            {
+                mrExtLink.importExternalBook( getRelations(), rStrm );
+                return this;
+            }
+        break;
+
+        case BIFF12_ID_EXTERNALBOOK:
+            switch( nRecId )
+            {
+                case BIFF12_ID_EXTSHEETDATA:
+                    if( mrExtLink.getLinkType() == LINKTYPE_EXTERNAL )
+                        return createSheetDataContext( rStrm.readInt32() );
+                break;
+
+                case BIFF12_ID_EXTSHEETNAMES:       mrExtLink.importExtSheetNames( rStrm );                             break;
+                case BIFF12_ID_EXTERNALNAME:        mxExtName = mrExtLink.importExternalName( rStrm );                  return this;
+            }
+        break;
+
+        case BIFF12_ID_EXTERNALNAME:
+            switch( nRecId )
+            {
+                case BIFF12_ID_EXTERNALNAMEFLAGS:   if( mxExtName.get() ) mxExtName->importExternalNameFlags( rStrm );  break;
+                case BIFF12_ID_DDEITEMVALUES:       if( mxExtName.get() ) mxExtName->importDdeItemValues( rStrm );      return this;
+            }
+        break;
+
+        case BIFF12_ID_DDEITEMVALUES:
+            switch( nRecId )
+            {
+                case BIFF12_ID_DDEITEM_BOOL:        if( mxExtName.get() ) mxExtName->importDdeItemBool( rStrm );        break;
+                case BIFF12_ID_DDEITEM_DOUBLE:      if( mxExtName.get() ) mxExtName->importDdeItemDouble( rStrm );      break;
+                case BIFF12_ID_DDEITEM_ERROR:       if( mxExtName.get() ) mxExtName->importDdeItemError( rStrm );       break;
+                case BIFF12_ID_DDEITEM_STRING:      if( mxExtName.get() ) mxExtName->importDdeItemString( rStrm );      break;
+            }
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef ExternalLinkFragment::createSheetDataContext( sal_Int32 nSheetId )
+{
+    return new ExternalSheetDataContext( *this, mrExtLink.getSheetCache( nSheetId ) );
+}
+
+const RecordInfo* ExternalLinkFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_DDEITEMVALUES,  BIFF12_ID_DDEITEMVALUES + 1     },
+        { BIFF12_ID_EXTERNALBOOK,   BIFF12_ID_EXTERNALBOOK + 228    },
+        { BIFF12_ID_EXTERNALNAME,   BIFF12_ID_EXTERNALNAME + 10     },
+        { BIFF12_ID_EXTROW,         -1                              },
+        { BIFF12_ID_EXTSHEETDATA,   BIFF12_ID_EXTSHEETDATA + 1      },
+        { -1,                       -1                              }
+    };
+    return spRecInfos;
+}
+
+// ============================================================================
+// ============================================================================
+
+BiffExternalSheetDataContext::BiffExternalSheetDataContext( const WorkbookHelper& rHelper, bool bImportDefNames ) :
+    BiffWorkbookContextBase( rHelper ),
+    mbImportDefNames( bImportDefNames )
+{
+}
+
+BiffExternalSheetDataContext::~BiffExternalSheetDataContext()
+{
+}
+
+void BiffExternalSheetDataContext::importRecord( BiffInputStream& rStrm )
+{
+    sal_uInt16 nRecId = rStrm.getRecId();
+    switch( getBiff() )
+    {
+        case BIFF2: switch( nRecId )
+        {
+            case BIFF2_ID_EXTERNALNAME: importExternalName( rStrm );    break;
+            case BIFF_ID_EXTERNSHEET:   importExternSheet( rStrm );     break;
+            case BIFF2_ID_DEFINEDNAME:  importDefinedName( rStrm );     break;
+        }
+        break;
+        case BIFF3: switch( nRecId )
+        {
+            case BIFF_ID_CRN:           importCrn( rStrm );             break;
+            case BIFF3_ID_EXTERNALNAME: importExternalName( rStrm );    break;
+            case BIFF_ID_EXTERNSHEET:   importExternSheet( rStrm );     break;
+            case BIFF3_ID_DEFINEDNAME:  importDefinedName( rStrm );     break;
+            case BIFF_ID_XCT:           importXct( rStrm );             break;
+        }
+        break;
+        case BIFF4: switch( nRecId )
+        {
+            case BIFF_ID_CRN:           importCrn( rStrm );             break;
+            case BIFF3_ID_EXTERNALNAME: importExternalName( rStrm );    break;
+            case BIFF_ID_EXTERNSHEET:   importExternSheet( rStrm );     break;
+            case BIFF3_ID_DEFINEDNAME:  importDefinedName( rStrm );     break;
+            case BIFF_ID_XCT:           importXct( rStrm );             break;
+        }
+        break;
+        case BIFF5: switch( nRecId )
+        {
+            case BIFF_ID_CRN:           importCrn( rStrm );             break;
+            case BIFF5_ID_EXTERNALNAME: importExternalName( rStrm );    break;
+            case BIFF_ID_EXTERNSHEET:   importExternSheet( rStrm );     break;
+            case BIFF5_ID_DEFINEDNAME:  importDefinedName( rStrm );     break;
+            case BIFF_ID_XCT:           importXct( rStrm );             break;
+        }
+        break;
+        case BIFF8: switch( nRecId )
+        {
+            case BIFF_ID_CRN:           importCrn( rStrm );             break;
+            case BIFF_ID_EXTERNALBOOK:  importExternalBook( rStrm );    break;
+            case BIFF5_ID_EXTERNALNAME: importExternalName( rStrm );    break;
+            case BIFF_ID_EXTERNSHEET:   importExternSheet( rStrm );     break;
+            case BIFF5_ID_DEFINEDNAME:  importDefinedName( rStrm );     break;
+            case BIFF_ID_XCT:           importXct( rStrm );             break;
+        }
+        break;
+        case BIFF_UNKNOWN: break;
+    }
+}
+
+// private --------------------------------------------------------------------
+
+void BiffExternalSheetDataContext::importExternSheet( BiffInputStream& rStrm )
+{
+    mxSheetCache.clear();
+    if( getBiff() == BIFF8 )
+        getExternalLinks().importExternSheet8( rStrm );
+    else
+        mxExtLink = getExternalLinks().importExternSheet( rStrm );
+}
+
+void BiffExternalSheetDataContext::importExternalBook( BiffInputStream& rStrm )
+{
+    mxSheetCache.clear();
+    mxExtLink = getExternalLinks().importExternalBook( rStrm );
+}
+
+void BiffExternalSheetDataContext::importExternalName( BiffInputStream& rStrm )
+{
+    if( mxExtLink.get() )
+        mxExtLink->importExternalName( rStrm );
+}
+
+void BiffExternalSheetDataContext::importXct( BiffInputStream& rStrm )
+{
+    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:
+                rStrm.skip( 2 );
+                mxSheetCache = mxExtLink->getSheetCache( rStrm.readInt16() );
+            break;
+            case BIFF_UNKNOWN:
+            break;
+        }
+    }
+}
+
+void BiffExternalSheetDataContext::importCrn( BiffInputStream& rStrm )
+{
+    if( !mxSheetCache.is() ) return;
+
+    sal_uInt8 nCol2, nCol1;
+    sal_uInt16 nRow;
+    rStrm >> nCol2 >> nCol1 >> nRow;
+    bool bLoop = true;
+    for( BinAddress aBinAddr( nCol1, nRow ); bLoop && !rStrm.isEof() && (aBinAddr.mnCol <= nCol2); ++aBinAddr.mnCol )
+    {
+        switch( rStrm.readuInt8() )
+        {
+            case BIFF_DATATYPE_EMPTY:
+                rStrm.skip( 8 );
+                setCellValue( aBinAddr, Any( OUString() ) );
+            break;
+            case BIFF_DATATYPE_DOUBLE:
+                setCellValue( aBinAddr, Any( rStrm.readDouble() ) );
+            break;
+            case BIFF_DATATYPE_STRING:
+            {
+                OUString aText = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
+                setCellValue( aBinAddr, Any( aText ) );
+            }
+            break;
+            case BIFF_DATATYPE_BOOL:
+            {
+                double fValue = (rStrm.readuInt8() == 0) ? 0.0 : 1.0;
+                setCellValue( aBinAddr, Any( fValue ) );
+                rStrm.skip( 7 );
+            }
+            break;
+            case BIFF_DATATYPE_ERROR:
+                setCellValue( aBinAddr, Any( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) ) );
+                rStrm.skip( 7 );
+            break;
+            default:
+                OSL_FAIL( "BiffExternalLinkFragment::importCrn - unknown data type" );
+                bLoop = false;
+        }
+    }
+}
+
+void BiffExternalSheetDataContext::importDefinedName( BiffInputStream& rStrm )
+{
+    if( mbImportDefNames )
+        getDefinedNames().importDefinedName( rStrm );
+}
+
+void BiffExternalSheetDataContext::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& )
+    {
+    }
+}
+
+// ============================================================================
+
+BiffExternalLinkFragment::BiffExternalLinkFragment( const BiffWorkbookFragmentBase& rParent ) :
+    BiffWorkbookFragmentBase( rParent )
+{
+}
+
+bool BiffExternalLinkFragment::importFragment()
+{
+    // process all record in this sheet fragment
+    BiffExternalSheetDataContext aSheetContext( *this, false );
+    BiffInputStream& rStrm = getInputStream();
+    while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+    {
+        if( BiffHelper::isBofRecord( rStrm ) )
+            skipFragment();  // skip unknown embedded fragments
+        else
+            aSheetContext.importRecord( rStrm );
+    }
+    return !rStrm.isEof() && (rStrm.getRecId() == BIFF_ID_EOF);
+}
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/formulabase.cxx b/sc/source/filter/oox/formulabase.cxx
new file mode 100644
index 000000000000..276564eeaa11
--- /dev/null
+++ b/sc/source/filter/oox/formulabase.cxx
@@ -0,0 +1,1639 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "formulabase.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OStringToOUString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OUStringToOString;
+
+// reference helpers ==========================================================
+
+BinSingleRef2d::BinSingleRef2d() :
+    mnCol( 0 ),
+    mnRow( 0 ),
+    mbColRel( false ),
+    mbRowRel( false )
+{
+}
+
+void BinSingleRef2d::setBiff12Data( sal_uInt16 nCol, sal_Int32 nRow, bool bRelativeAsOffset )
+{
+    mnCol = nCol & BIFF12_TOK_REF_COLMASK;
+    mnRow = nRow & BIFF12_TOK_REF_ROWMASK;
+    mbColRel = getFlag( nCol, BIFF12_TOK_REF_COLREL );
+    mbRowRel = getFlag( nCol, BIFF12_TOK_REF_ROWREL );
+    if( bRelativeAsOffset && mbColRel && (mnCol > (BIFF12_TOK_REF_COLMASK >> 1)) )
+        mnCol -= (BIFF12_TOK_REF_COLMASK + 1);
+    if( bRelativeAsOffset && mbRowRel && (mnRow > (BIFF12_TOK_REF_ROWMASK >> 1)) )
+        mnRow -= (BIFF12_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::readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset )
+{
+    sal_Int32 nRow;
+    sal_uInt16 nCol;
+    rStrm >> nRow >> nCol;
+    setBiff12Data( 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::readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset )
+{
+    sal_Int32 nRow1, nRow2;
+    sal_uInt16 nCol1, nCol2;
+    rStrm >> nRow1 >> nRow2 >> nCol1 >> nCol2;
+    maRef1.setBiff12Data( nCol1, nRow1, bRelativeAsOffset );
+    maRef2.setBiff12Data( 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.
+
+/// Converts a function library index (value of enum FunctionLibraryType) to function flags.
+#define FUNCLIB_TO_FUNCFLAGS( funclib_index ) static_cast< sal_uInt16 >( static_cast< sal_uInt8 >( funclib_index ) << 12 )
+/// Extracts a function library index (value of enum FunctionLibraryType) from function flags.
+#define FUNCFLAGS_TO_FUNCLIB( func_flags ) extractValue< FunctionLibraryType >( func_flags, 12, 4 )
+
+typedef ::boost::shared_ptr< FunctionInfo > FunctionInfoRef;
+
+struct FunctionData
+{
+    const sal_Char*     mpcOdfFuncName;     /// ODF function name.
+    const sal_Char*     mpcOoxFuncName;     /// OOXML function name.
+    sal_uInt16          mnBiff12FuncId;     /// BIFF12 function identifier.
+    sal_uInt16          mnBiffFuncId;       /// BIFF2-BIFF8 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 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 },
+    { "CSC",                    "SIN",                  15,     15,     1,  1,  V, { VR }, FUNCFLAG_EXPORTONLY },
+    { "COS",                    "COS",                  16,     16,     1,  1,  V, { VR }, 0 },
+    { "SEC",                    "COS",                  16,     16,     1,  1,  V, { VR }, FUNCFLAG_EXPORTONLY },
+    { "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 },
+    { "CSCH",                   "SINH",                 229,    229,    1,  1,  V, { VR }, FUNCFLAG_EXPORTONLY },
+    { "COSH",                   "COSH",                 230,    230,    1,  1,  V, { VR }, 0 },
+    { "SECH",                   "COSH",                 230,    230,    1,  1,  V, { VR }, FUNCFLAG_EXPORTONLY },
+    { "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 OOXML spec
+    { 0,                        "NUMBERSTRING",         353,    353,    2,  2,  V, { VR }, FUNCFLAG_IMPORTONLY },   // not supported in Calc, missing in OOXML spec
+    { "ROMAN",                  "ROMAN",                354,    354,    1,  2,  V, { VR }, 0 },
+
+    // *** EuroTool add-in ***
+
+    { "EUROCONVERT",            "EUROCONVERT",          NOID,   NOID,   3,  5,  V, { VR }, FUNCLIB_TO_FUNCFLAGS( FUNCLIB_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 OOXML. */
+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,   0,  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" );
+}
+
+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         maOoxFuncs;         /// Maps OOXML function names to function data.
+    FuncIdMap           maBiff12Funcs;      /// Maps BIFF12 function indexes to function data.
+    FuncIdMap           maBiffFuncs;        /// Maps BIFF2-BIFF8 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_OOXML:
+            nMaxParam = OOX_MAX_PARAMCOUNT;
+            eBiff = BIFF8;  // insert all BIFF function tables, then the OOXML table
+        break;
+        case FILTER_BIFF:
+            nMaxParam = BIFF_MAX_PARAMCOUNT;
+        break;
+        case FILTER_UNKNOWN:
+            OSL_FAIL( "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_OOXML )
+        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.isEmpty(), "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.isEmpty(), "FunctionProviderImpl::initFunc - missing ODF function name" );
+        xFuncInfo->maBiffMacroName = CREATE_OUSTRING( "_xlfnodf." ) + xFuncInfo->maOdfFuncName;
+    }
+
+    xFuncInfo->meFuncLibType = FUNCFLAGS_TO_FUNCLIB( rFuncData.mnFlags );
+    xFuncInfo->mnApiOpCode = -1;
+    xFuncInfo->mnBiff12FuncId = rFuncData.mnBiff12FuncId;
+    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->mnBiff12FuncId, 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->maOoxFuncName.isEmpty() )
+        maOoxFuncs[ xFuncInfo->maOoxFuncName ] = xFuncInfo;
+    if( xFuncInfo->mnBiff12FuncId != NOID )
+        maBiff12Funcs[ xFuncInfo->mnBiff12FuncId ] = xFuncInfo;
+    if( xFuncInfo->mnBiffFuncId != NOID )
+        maBiffFuncs[ xFuncInfo->mnBiffFuncId ] = xFuncInfo;
+    if( !xFuncInfo->maBiffMacroName.isEmpty() )
+        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::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
+{
+    return mxFuncImpl->maOoxFuncs.get( rFuncName ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromBiff12FuncId( sal_uInt16 nFuncId ) const
+{
+    return mxFuncImpl->maBiff12Funcs.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 >& rxModelFactory );
+
+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 >& rxModelFactory )
+{
+    if( rxModelFactory.is() ) try
+    {
+        Reference< XFormulaOpCodeMapper > xMapper( rxModelFactory->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_FAIL( "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_FAIL( 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.isEmpty() )
+        {
+            FormulaOpCodeMapEntry aEntry;
+            aEntry.Name = rOoxName;
+            aEntry.Token.OpCode = ornOpCode;
+            maParserMap.push_back( aEntry );
+        }
+        return true;
+    }
+    OSL_FAIL( 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.isEmpty() )
+    {
+        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.isEmpty();
+                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 OOXML function name exists
+            if( bIsValid && !orFuncInfo.maOoxFuncName.isEmpty() )
+            {
+                // 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.isEmpty();
+        }
+    }
+    else if( orFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
+    {
+        orFuncInfo.mnApiOpCode = OPCODE_EXTERNAL;
+        bIsValid = true;
+    }
+    else if( !orFuncInfo.maOoxFuncName.isEmpty() )
+    {
+        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.isEmpty() )
+                maExtProgFuncs[ xFuncInfo->maExtProgName ] = xFuncInfo;
+            else
+                maOpCodeFuncs[ xFuncInfo->mnApiOpCode ] = xFuncInfo;
+        }
+    }
+    return bIsValid;
+}
+
+// ----------------------------------------------------------------------------
+
+OpCodeProvider::OpCodeProvider( const Reference< XMultiServiceFactory >& rxModelFactory,
+        FilterType eFilter, BiffType eBiff, bool bImportFilter ) :
+    FunctionProvider( eFilter, eBiff, bImportFilter ),
+    mxOpCodeImpl( new OpCodeProviderImpl( getFuncs(), rxModelFactory ) )
+{
+}
+
+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 >& rxModelFactory, const OpCodeProvider& rOpCodeProv ) :
+    OpCodeProvider( rOpCodeProv )
+{
+    if( rxModelFactory.is() ) try
+    {
+        mxParser.set( rxModelFactory->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 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.getBaseFilter().getModelFactory(), 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::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::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();
+}
+
+bool FormulaProcessorBase::extractSpecialTokenInfo( ApiSpecialTokenInfo& orTokenInfo, const ApiTokenSequence& rTokens ) const
+{
+    ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES, true );
+    return aTokenIt.is() && (aTokenIt->OpCode == OPCODE_BAD) && (aTokenIt->Data >>= orTokenInfo);
+}
+
+void FormulaProcessorBase::convertStringToStringList(
+        ApiTokenSequence& orTokens, sal_Unicode cStringSep, bool bTrimLeadingSpaces ) const
+{
+    OUString aString;
+    if( extractString( aString, orTokens ) && !aString.isEmpty() )
+    {
+        ::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/sc/source/filter/oox/formulaparser.cxx b/sc/source/filter/oox/formulaparser.cxx
new file mode 100644
index 000000000000..eeb683f85ab0
--- /dev/null
+++ b/sc/source/filter/oox/formulaparser.cxx
@@ -0,0 +1,2930 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "formulaparser.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "defnamesbuffer.hxx"
+#include "externallinkbuffer.hxx"
+#include "tablebuffer.hxx"
+#include "worksheethelper.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::sheet::ReferenceFlags;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+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.isEmpty()) )
+                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.isEmpty() )
+            orFuncToken.Data <<= pFuncInfo->maExtProgName;
+        // name of unsupported function, convert to OPCODE_BAD to preserve the name
+        else if( (pFuncInfo->mnApiOpCode == OPCODE_BAD) && !pFuncInfo->maOoxFuncName.isEmpty() )
+            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.isEmpty() )
+        {
+            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() )
+                {
+                    // handle empty parameters
+                    if( bIsEmpty )
+                    {
+                        // append leading space tokens from original token array
+                        while( (pParamBegin < pParamEnd) && (pParamBegin->OpCode == OPCODE_SPACES) )
+                            maTokens.push_back( *pParamBegin++ );
+                        // add default values for some empty parameters, or the OPCODE_MISSING token
+                        appendEmptyParameter( *pRealFuncInfo, nParam );
+                        // reset bIsEmpty flag, if something has been appended in appendEmptyParameter()
+                        bIsEmpty = maTokens.back().OpCode == OPCODE_MISSING;
+                        // skip OPCODE_MISSING token in the original token array
+                        OSL_ENSURE( (pParamBegin == pParamEnd) || (pParamBegin->OpCode == OPCODE_MISSING), "FormulaFinalizer::processParameters - OPCODE_MISSING expected" );
+                        if( pParamBegin < pParamEnd ) ++pParamBegin;
+                        // append trailing space tokens from original token array
+                        while( (pParamBegin < pParamEnd) && (pParamBegin->OpCode == OPCODE_SPACES) )
+                            maTokens.push_back( *pParamBegin++ );
+                    }
+                    else
+                    {
+                        // if parameter is not empty, 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::appendEmptyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
+{
+    // remember old size of the token array
+    size_t nTokenArraySize = maTokens.size();
+
+    switch( rFuncInfo.mnBiff12FuncId )
+    {
+        case BIFF_FUNC_IF:
+            if( (nParam == 1) || (nParam == 2) )
+                maTokens.append< double >( OPCODE_PUSH, 0.0 );
+        break;
+        default:;
+    }
+
+    // if no token has been added, append a OPCODE_MISSING token
+    if( nTokenArraySize == maTokens.size() )
+        maTokens.append( OPCODE_MISSING );
+}
+
+void FormulaFinalizer::appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
+{
+    (void)nParam;   // prevent 'unused' warning
+    switch( rFuncInfo.mnBiff12FuncId )
+    {
+        case BIFF_FUNC_FLOOR:
+        case BIFF_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.mnBiff12FuncId )
+    {
+        case BIFF_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 OOXML formula string. */
+    virtual ApiTokenSequence importOoxFormula(
+                            const CellAddress& rBaseAddress,
+                            const OUString& rFormulaString );
+
+    /** Imports and converts a BIFF12 token array from the passed stream. */
+    virtual ApiTokenSequence importBiff12Formula(
+                            const CellAddress& rBaseAddress,
+                            FormulaType eType,
+                            SequenceInputStream& rStrm );
+
+    /** Imports and converts a BIFF2-BIFF8 token array from the passed stream. */
+    virtual ApiTokenSequence importBiffFormula(
+                            const CellAddress& rBaseAddress,
+                            FormulaType eType,
+                            BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize );
+
+    /** Tries to resolve the passed ref-id to an OLE target URL. */
+    OUString            resolveOleTarget( sal_Int32 nRefId, bool bUseRefSheets ) const;
+
+protected:
+    typedef ::std::pair< sal_Int32, bool >  WhiteSpace;
+    typedef ::std::vector< WhiteSpace >     WhiteSpaceVec;
+
+    /** Initializes the formula parser before importing a formula. */
+    void                initializeImport( const CellAddress& rBaseAddress, FormulaType eType );
+    /** Finalizes the internal token storage after import. */
+    ApiTokenSequence    finalizeImport();
+
+    // 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 );
+
+    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                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                pushSpecialTokenOperand( const BinAddress& rBaseAddr, bool bTable );
+
+    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.
+
+    CellAddress         maBaseAddr;                 /// Base address for relative references.
+    bool                mbRelativeAsOffset;         /// True = relative row/column index is (signed) offset, false = explicit index.
+    bool                mb2dRefsAs3dRefs;           /// True = convert all 2D references to 3D references in sheet specified by base address.
+    bool                mbSpecialTokens;            /// True = special handling for tExp and tTbl tokens, false = exit with error.
+    bool                mbAllowNulChars;            /// True = keep NUL characters in string tokens.
+
+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.
+};
+
+// ----------------------------------------------------------------------------
+
+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 ),
+    mbRelativeAsOffset( false ),
+    mb2dRefsAs3dRefs( false ),
+    mbSpecialTokens( false ),
+    mbAllowNulChars( false )
+{
+    // 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 );
+}
+
+ApiTokenSequence FormulaParserImpl::importOoxFormula( const CellAddress&, const OUString& )
+{
+    OSL_FAIL( "FormulaParserImpl::importOoxFormula - not implemented" );
+    return ApiTokenSequence();
+}
+
+ApiTokenSequence FormulaParserImpl::importBiff12Formula( const CellAddress&, FormulaType, SequenceInputStream& )
+{
+    OSL_FAIL( "FormulaParserImpl::importBiff12Formula - not implemented" );
+    return ApiTokenSequence();
+}
+
+ApiTokenSequence FormulaParserImpl::importBiffFormula( const CellAddress&, FormulaType, BiffInputStream&, const sal_uInt16* )
+{
+    OSL_FAIL( "FormulaParserImpl::importBiffFormula - not implemented" );
+    return ApiTokenSequence();
+}
+
+OUString FormulaParserImpl::resolveOleTarget( sal_Int32 nRefId, bool bUseRefSheets ) const
+{
+    const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId, bUseRefSheets ).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( const CellAddress& rBaseAddr, FormulaType eType )
+{
+    maBaseAddr = rBaseAddr;
+    mbRelativeAsOffset = mb2dRefsAs3dRefs = mbSpecialTokens = mbAllowNulChars = false;
+    switch( eType )
+    {
+        case FORMULATYPE_CELL:
+            mbSpecialTokens = true;
+        break;
+        case FORMULATYPE_ARRAY:
+        break;
+        case FORMULATYPE_SHAREDFORMULA:
+            mbRelativeAsOffset = true;
+        break;
+        case FORMULATYPE_CONDFORMAT:
+            mbRelativeAsOffset = true;
+        break;
+        case FORMULATYPE_VALIDATION:
+            mbRelativeAsOffset = true;
+            // enable NUL characters in BIFF import, string list is single tStr token with NUL separators
+            mbAllowNulChars = getFilterType() == FILTER_BIFF;
+        break;
+        case FORMULATYPE_DEFINEDNAME:
+            mbRelativeAsOffset = true;
+            // BIFF2-BIFF4: convert 2D referebces to absolute 3D references
+            mb2dRefsAs3dRefs = (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4);
+        break;
+    }
+
+    maTokenStorage.clear();
+    maTokenIndexes.clear();
+    maOperandSizeStack.clear();
+}
+
+ApiTokenSequence 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 ];
+    }
+    return finalizeTokenArray( aTokens );
+}
+
+// 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) ];
+}
+
+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.isEmpty() )
+            getOperandToken( 1, 0, 0 ).Data <<= rFuncInfo.maExtProgName;
+        // create a bad token with unsupported function name
+        else if( (rFuncInfo.mnApiOpCode == OPCODE_BAD) && !rFuncInfo.maOoxFuncName.isEmpty() )
+            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 = getFuncInfoFromBiff12FuncId( bValue ? BIFF_FUNC_TRUE : BIFF_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::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( maBaseAddr );
+    if( aRefAny.hasValue() )
+        return pushAnyOperand( aRefAny, OPCODE_PUSH );
+    if( bPushBadToken && !rName.getModelName().isEmpty() && (rName.getModelName()[ 0 ] >= ' ') )
+        return pushValueOperand( rName.getModelName(), OPCODE_BAD );
+    return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool FormulaParserImpl::pushDefinedNameOperand( const DefinedNameRef& rxDefName )
+{
+    if( !rxDefName || rxDefName->getModelName().isEmpty() )
+        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::pushSpecialTokenOperand( const BinAddress& rBaseAddr, bool bTable )
+{
+    CellAddress aBaseAddr( maBaseAddr.Sheet, rBaseAddr.mnCol, rBaseAddr.mnRow );
+    ApiSpecialTokenInfo aTokenInfo( aBaseAddr, bTable );
+    return mbSpecialTokens && (getFormulaSize() == 0) && pushValueOperand( aTokenInfo, OPCODE_BAD );
+}
+
+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( mb2dRefsAs3dRefs )
+    {
+        initReference3d( orApiRef, maBaseAddr.Sheet, false );
+    }
+    else
+    {
+        orApiRef.Flags = SHEET_RELATIVE;
+        // #i10184# absolute sheet index needed for relative references in shared formulas
+        orApiRef.Sheet = maBaseAddr.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 -= maBaseAddr.Column;
+            if( rRef.mbRowRel )
+                orApiRef.RelativeRow -= maBaseAddr.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();
+}
+
+// OOXML/BIFF12 parser implementation =========================================
+
+class OoxFormulaParserImpl : public FormulaParserImpl
+{
+public:
+    explicit            OoxFormulaParserImpl( const FormulaParser& rParent );
+
+    virtual ApiTokenSequence importOoxFormula(
+                            const CellAddress& rBaseAddr,
+                            const OUString& rFormulaString );
+
+    virtual ApiTokenSequence importBiff12Formula(
+                            const CellAddress& rBaseAddr,
+                            FormulaType eType,
+                            SequenceInputStream& rStrm );
+
+private:
+    // import token contents and create API formula token ---------------------
+
+    bool                importAttrToken( SequenceInputStream& rStrm );
+    bool                importSpaceToken( SequenceInputStream& rStrm );
+    bool                importTableToken( SequenceInputStream& rStrm );
+    bool                importArrayToken( SequenceInputStream& rStrm );
+    bool                importRefToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+    bool                importAreaToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+    bool                importRef3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+    bool                importArea3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
+    bool                importMemAreaToken( SequenceInputStream& rStrm, bool bAddData );
+    bool                importMemFuncToken( SequenceInputStream& rStrm );
+    bool                importNameToken( SequenceInputStream& rStrm );
+    bool                importNameXToken( SequenceInputStream& rStrm );
+    bool                importFuncToken( SequenceInputStream& rStrm );
+    bool                importFuncVarToken( SequenceInputStream& rStrm );
+    bool                importExpToken( SequenceInputStream& rStrm );
+
+    LinkSheetRange      readSheetRange( SequenceInputStream& rStrm );
+
+    void                swapStreamPosition( SequenceInputStream& rStrm );
+    void                skipMemAreaAddData( SequenceInputStream& rStrm );
+
+    // convert BIN token and push API operand or operator ---------------------
+
+    bool                pushBiff12Name( sal_Int32 nNameId );
+    bool                pushBiff12ExtName( sal_Int32 nRefId, sal_Int32 nNameId );
+    bool                pushBiff12Function( sal_uInt16 nFuncId );
+    bool                pushBiff12Function( 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.getBaseFilter().getModelFactory(), rParent ),
+    mnAddDataPos( 0 ),
+    mbNeedExtRefs( true )
+{
+}
+
+ApiTokenSequence OoxFormulaParserImpl::importOoxFormula( const CellAddress& rBaseAddr, const OUString& rFormulaString )
+{
+    if( mbNeedExtRefs )
+    {
+        maApiParser.getParserProperties().setProperty( PROP_ExternalLinks, getExternalLinks().getLinkInfos() );
+        mbNeedExtRefs = false;
+    }
+    return finalizeTokenArray( maApiParser.parseFormula( rFormulaString, rBaseAddr ) );
+}
+
+ApiTokenSequence OoxFormulaParserImpl::importBiff12Formula( const CellAddress& rBaseAddr, FormulaType eType, SequenceInputStream& rStrm )
+{
+    initializeImport( rBaseAddr, eType );
+
+    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 = mbRelativeAsOffset;
+
+    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( BiffHelper::readString( rStrm, 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
+    ApiTokenSequence aFinalTokens;
+    if( bOk && (rStrm.tell() == nFmlaEndPos) && (mnAddDataPos == nAddDataEndPos) )
+        aFinalTokens = finalizeImport();
+
+    // seek behind token array
+    if( (nFmlaSize >= 0) && (nAddDataSize >= 0) )
+        rStrm.seek( nAddDataEndPos );
+
+    // return the final token sequence
+    return aFinalTokens;
+}
+
+// import token contents and create API formula token -------------------------
+
+bool OoxFormulaParserImpl::importAttrToken( SequenceInputStream& rStrm )
+{
+    bool bOk = true;
+    sal_uInt8 nType;
+    rStrm >> nType;
+    // equal flags in all BIFFs
+    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:
+        case BIFF_TOK_ATTR_IFERROR:
+            rStrm.skip( 2 );
+        break;
+        case BIFF_TOK_ATTR_CHOOSE:
+            rStrm.skip( 2 * rStrm.readuInt16() + 2 );
+        break;
+        case BIFF_TOK_ATTR_SUM:
+            rStrm.skip( 2 );
+            bOk = pushBiff12Function( BIFF_FUNC_SUM, 1 );
+        break;
+        case BIFF_TOK_ATTR_SPACE:
+        case BIFF_TOK_ATTR_SPACE_VOLATILE:
+            bOk = importSpaceToken( rStrm );
+        break;
+        default:
+            bOk = false;
+    }
+    return bOk;
+}
+
+bool OoxFormulaParserImpl::importSpaceToken( SequenceInputStream& 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( SequenceInputStream& 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, BIFF12_TOK_TABLE_COLUMN );
+        bool bColRange = getFlag( nFlags, BIFF12_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, BIFF12_TOK_TABLE_ALL );
+            bool bHeaderRows = getFlag( nFlags, BIFF12_TOK_TABLE_HEADERS );
+            bool bDataRows   = getFlag( nFlags, BIFF12_TOK_TABLE_DATA );
+            bool bTotalsRows = getFlag( nFlags, BIFF12_TOK_TABLE_TOTALS );
+            bool bThisRow    = getFlag( nFlags, BIFF12_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 = maBaseAddr.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 = getFuncInfoFromBiff12FuncId( BIFF_FUNC_ROWS );
+            const FunctionInfo* pColumnsInfo = getFuncInfoFromBiff12FuncId( BIFF_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 )) &&
+                pushBiff12Function( BIFF_FUNC_OFFSET, 5 );
+        }
+    }
+    return pushBiffErrorOperand( BIFF_ERR_REF );
+}
+
+bool OoxFormulaParserImpl::importArrayToken( SequenceInputStream& 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 BIFF_TOK_ARRAY_DOUBLE:
+                    appendRawToken( OPCODE_PUSH ) <<= rStrm.readDouble();
+                break;
+                case BIFF_TOK_ARRAY_STRING:
+                    appendRawToken( OPCODE_PUSH ) <<= BiffHelper::readString( rStrm, false );
+                break;
+                case BIFF_TOK_ARRAY_BOOL:
+                    appendRawToken( OPCODE_PUSH ) <<= (static_cast< double >( (rStrm.readuInt8() == BIFF_TOK_BOOL_FALSE) ? 0.0 : 1.0 ));
+                break;
+                case BIFF_TOK_ARRAY_ERROR:
+                    appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
+                    rStrm.skip( 3 );
+                break;
+                default:
+                    OSL_FAIL( "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( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+    BinSingleRef2d aRef;
+    aRef.readBiff12Data( rStrm, bRelativeAsOffset );
+    return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool OoxFormulaParserImpl::importAreaToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+    BinComplexRef2d aRef;
+    aRef.readBiff12Data( rStrm, bRelativeAsOffset );
+    return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool OoxFormulaParserImpl::importRef3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+    LinkSheetRange aSheetRange = readSheetRange( rStrm );
+    BinSingleRef2d aRef;
+    aRef.readBiff12Data( rStrm, bRelativeAsOffset );
+    return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool OoxFormulaParserImpl::importArea3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
+{
+    LinkSheetRange aSheetRange = readSheetRange( rStrm );
+    BinComplexRef2d aRef;
+    aRef.readBiff12Data( rStrm, bRelativeAsOffset );
+    return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
+}
+
+bool OoxFormulaParserImpl::importMemAreaToken( SequenceInputStream& rStrm, bool bAddData )
+{
+    rStrm.skip( 6 );
+    if( bAddData )
+        skipMemAreaAddData( rStrm );
+    return true;
+}
+
+bool OoxFormulaParserImpl::importMemFuncToken( SequenceInputStream& rStrm )
+{
+    rStrm.skip( 2 );
+    return true;
+}
+
+bool OoxFormulaParserImpl::importNameToken( SequenceInputStream& rStrm )
+{
+    return pushBiff12Name( rStrm.readInt32() );
+}
+
+bool OoxFormulaParserImpl::importNameXToken( SequenceInputStream& rStrm )
+{
+    sal_Int32 nRefId = rStrm.readInt16();
+    sal_Int32 nNameId = rStrm.readInt32();
+    return pushBiff12ExtName( nRefId, nNameId );
+}
+
+bool OoxFormulaParserImpl::importFuncToken( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFuncId;
+    rStrm >> nFuncId;
+    return pushBiff12Function( nFuncId );
+}
+
+bool OoxFormulaParserImpl::importFuncVarToken( SequenceInputStream& rStrm )
+{
+    sal_uInt8 nParamCount;
+    sal_uInt16 nFuncId;
+    rStrm >> nParamCount >> nFuncId;
+    return pushBiff12Function( nFuncId, nParamCount );
+}
+
+bool OoxFormulaParserImpl::importExpToken( SequenceInputStream& rStrm )
+{
+    BinAddress aBaseAddr;
+    rStrm >> aBaseAddr.mnRow;
+    swapStreamPosition( rStrm );
+    rStrm >> aBaseAddr.mnCol;
+    swapStreamPosition( rStrm );
+    return pushSpecialTokenOperand( aBaseAddr, false );
+}
+
+LinkSheetRange OoxFormulaParserImpl::readSheetRange( SequenceInputStream& rStrm )
+{
+    return getExternalLinks().getSheetRange( rStrm.readInt16() );
+}
+
+void OoxFormulaParserImpl::swapStreamPosition( SequenceInputStream& rStrm )
+{
+    sal_Int64 nRecPos = rStrm.tell();
+    rStrm.seek( mnAddDataPos );
+    mnAddDataPos = nRecPos;
+}
+
+void OoxFormulaParserImpl::skipMemAreaAddData( SequenceInputStream& rStrm )
+{
+    swapStreamPosition( rStrm );
+    rStrm.skip( 16 * rStrm.readInt32() );
+    swapStreamPosition( rStrm );
+}
+
+// convert BIN token and push API operand or operator -------------------------
+
+bool OoxFormulaParserImpl::pushBiff12Name( sal_Int32 nNameId )
+{
+    // one-based in BIFF12 formulas
+    return pushDefinedNameOperand( getDefinedNames().getByIndex( nNameId - 1 ) );
+}
+
+bool OoxFormulaParserImpl::pushBiff12ExtName( sal_Int32 nRefId, sal_Int32 nNameId )
+{
+    if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
+    {
+        if( pExtLink->getLinkType() == LINKTYPE_SELF )
+            return pushBiff12Name( nNameId );
+        // external name indexes are one-based in BIFF12
+        ExternalNameRef xExtName = pExtLink->getNameByIndex( nNameId - 1 );
+        return pushExternalNameOperand( xExtName, *pExtLink );
+    }
+    return pushBiffErrorOperand( BIFF_ERR_NAME );
+}
+
+bool OoxFormulaParserImpl::pushBiff12Function( sal_uInt16 nFuncId )
+{
+    if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiff12FuncId( nFuncId ) )
+        if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
+            return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
+    return pushFunctionOperator( OPCODE_NONAME, 0 );
+}
+
+bool OoxFormulaParserImpl::pushBiff12Function( sal_uInt16 nFuncId, sal_uInt8 nParamCount )
+{
+    if( getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD ) )
+        nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
+    if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiff12FuncId( 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 ApiTokenSequence importBiffFormula(
+                            const CellAddress& rBaseAddr,
+                            FormulaType eType,
+                            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                importExpToken( BiffInputStream& rStrm );
+    bool                importTblToken( 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).
+    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;
+            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;
+            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;
+            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;
+            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;
+            mnAttrDataSize = 2;
+            mnArraySize = 7;
+            mnNameSize = 2;
+            mnMemAreaSize = 6;
+            mnMemFuncSize = 2;
+            mnRefIdSize = 0;
+        break;
+        case BIFF_UNKNOWN: break;
+    }
+}
+
+ApiTokenSequence BiffFormulaParserImpl::importBiffFormula( const CellAddress& rBaseAddr,
+        FormulaType eType, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
+{
+    initializeImport( rBaseAddr, eType );
+    mnCurrRefId = 0;
+
+    sal_uInt16 nFmlaSize = lclReadFmlaSize( rStrm, getBiff(), pnFmlaSize );
+    sal_Int64 nEndPos = mnAddDataPos = rStrm.tell() + nFmlaSize;
+
+    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 = importExpToken( rStrm );                          break;
+                    case BIFF_TOKID_TBL:        bOk = importTblToken( 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 = (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, mbRelativeAsOffset );  break;
+                    case BIFF_TOKID_AREA3D:     bOk = (this->*mpImportArea3dToken)( rStrm, false, mbRelativeAsOffset ); break;
+                    case BIFF_TOKID_REFERR3D:   bOk = (this->*mpImportRef3dToken)( rStrm, true, mbRelativeAsOffset );   break;
+                    case BIFF_TOKID_AREAERR3D:  bOk = (this->*mpImportArea3dToken)( rStrm, true, mbRelativeAsOffset );  break;
+                    default:                    bOk = false;
+                }
+            }
+        }
+    }
+
+    // build and finalize the token sequence
+    ApiTokenSequence aFinalTokens;
+    if( bOk && (rStrm.tell() == nEndPos) )
+        aFinalTokens = finalizeImport();
+
+    // seek behind additional token data of tArray, tMemArea, tNlr tokens
+    rStrm.seek( mnAddDataPos );
+
+    // return the final token sequence
+    return aFinalTokens;
+}
+
+// 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(), mbAllowNulChars ) );
+}
+
+bool BiffFormulaParserImpl::importStrToken8( BiffInputStream& rStrm )
+{
+    // read flags field for empty strings also
+    return pushValueOperand( rStrm.readUniStringBody( rStrm.readuInt8(), mbAllowNulChars ) );
+}
+
+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;
+
+    // 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( mbAllowNulChars ) :
+                        rStrm.readByteStringUC( false, getTextEncoding(), mbAllowNulChars );
+                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_FAIL( "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::importExpToken( BiffInputStream& rStrm )
+{
+    BinAddress aBaseAddr;
+    aBaseAddr.read( rStrm );
+    return pushSpecialTokenOperand( aBaseAddr, false );
+}
+
+bool BiffFormulaParserImpl::importTblToken( BiffInputStream& rStrm )
+{
+    BinAddress aBaseAddr;
+    aBaseAddr.read( rStrm );
+    return pushSpecialTokenOperand( aBaseAddr, true );
+}
+
+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 );
+}
+
+// ============================================================================
+
+namespace {
+
+/** Extracts the reference identifier and the remaining data from a formula in
+    the format '[RefID]Remaining'. */
+bool lclExtractRefId( sal_Int32& rnRefId, OUString& rRemainder, const OUString& rFormulaString )
+{
+    if( (rFormulaString.getLength() >= 4) && (rFormulaString[ 0 ] == '[') )
+    {
+        sal_Int32 nBracketClose = rFormulaString.indexOf( ']', 1 );
+        if( nBracketClose >= 2 )
+        {
+            rnRefId = rFormulaString.copy( 1, nBracketClose - 1 ).toInt32();
+            rRemainder = rFormulaString.copy( nBracketClose + 1 );
+            return !rRemainder.isEmpty();
+        }
+    }
+    return false;
+}
+
+}
+
+// ----------------------------------------------------------------------------
+
+FormulaParser::FormulaParser( const WorkbookHelper& rHelper ) :
+    FormulaProcessorBase( rHelper )
+{
+    switch( getFilterType() )
+    {
+        case FILTER_OOXML:  mxImpl.reset( new OoxFormulaParserImpl( *this ) );  break;
+        case FILTER_BIFF:   mxImpl.reset( new BiffFormulaParserImpl( *this ) ); break;
+        case FILTER_UNKNOWN: break;
+    }
+}
+
+FormulaParser::~FormulaParser()
+{
+}
+
+ApiTokenSequence FormulaParser::importFormula( const CellAddress& rBaseAddress, const OUString& rFormulaString ) const
+{
+    return mxImpl->importOoxFormula( rBaseAddress, rFormulaString );
+}
+
+ApiTokenSequence FormulaParser::importFormula( const CellAddress& rBaseAddress, FormulaType eType, SequenceInputStream& rStrm ) const
+{
+    return mxImpl->importBiff12Formula( rBaseAddress, eType, rStrm );
+}
+
+ApiTokenSequence FormulaParser::importFormula( const CellAddress& rBaseAddress, FormulaType eType, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) const
+{
+    return mxImpl->importBiffFormula( rBaseAddress, eType, rStrm, pnFmlaSize );
+}
+
+ApiTokenSequence FormulaParser::convertBoolToFormula( bool bValue ) const
+{
+    if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiffFuncId( bValue ? BIFF_FUNC_TRUE : BIFF_FUNC_FALSE ) )
+    {
+        ApiTokenSequence aTokens( 3 );
+        aTokens[ 0 ].OpCode = pFuncInfo->mnApiOpCode;
+        aTokens[ 1 ].OpCode = OPCODE_OPEN;
+        aTokens[ 2 ].OpCode = OPCODE_CLOSE;
+        return aTokens;
+    }
+    return ApiTokenSequence();
+}
+
+ApiTokenSequence FormulaParser::convertErrorToFormula( 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;
+    return aTokens;
+}
+
+ApiTokenSequence FormulaParser::convertNameToFormula( sal_Int32 nTokenIndex ) const
+{
+    if( nTokenIndex < 0 )
+        return convertErrorToFormula( BIFF_ERR_REF );
+
+    ApiTokenSequence aTokens( 1 );
+    aTokens[ 0 ].OpCode = OPCODE_NAME;
+    NameToken aNameTokenData;
+    aNameTokenData.Global = sal_True;
+    aNameTokenData.Index = nTokenIndex;
+    aTokens[ 0 ].Data <<= aNameTokenData;
+    return aTokens;
+}
+
+OUString FormulaParser::importOleTargetLink( const OUString& rFormulaString )
+{
+    sal_Int32 nRefId = -1;
+    OUString aRemainder;
+    if( lclExtractRefId( nRefId, aRemainder, rFormulaString ) && (aRemainder.getLength() >= 3) &&
+            (aRemainder[ 0 ] == '!') && (aRemainder[ 1 ] == '\'') && (aRemainder[ aRemainder.getLength() - 1 ] == '\'') )
+        return mxImpl->resolveOleTarget( nRefId, false );
+    return OUString();
+}
+
+OUString FormulaParser::importOleTargetLink( SequenceInputStream& 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, true );
+    }
+    rStrm.seek( nFmlaEndPos );
+    return aTargetLink;
+}
+
+OUString FormulaParser::importMacroName( const OUString& rFormulaString )
+{
+    /*  Valid macros are either sheet macros or VBA macros. OOXML and all BIFF
+        documents store defined names for sheet macros, but OOXML documents do
+        not store any defined name for VBA macros (while BIFF documents do).
+        Sheet macros may be defined locally to a sheet, or globally to the
+        document. As a result, all of the following macro specifiers are valid:
+
+        1) Macros located in the own document:
+            [0]!MySheetMacro    (global sheet macro 'MySheetMacro')
+            Macro1!MyMacro      (sheet-local sheet macro 'MyMacro')
+            [0]!MyVBAProc       (VBA macro 'MyVBAProc')
+            [0]!Mod1.MyVBAProc  (VBA macro 'MyVBAProc' from code module 'Mod1')
+
+        2) Macros from an external document:
+            [2]!MySheetMacro    (global external sheet macro 'MySheetMacro')
+            [2]Macro1!MyMacro   (sheet-local external sheet macro 'MyMacro')
+            [2]!MyVBAProc       (external VBA macro 'MyVBAProc')
+            [2]!Mod1.MyVBAProc  (external VBA macro from code module 'Mod1')
+
+        This implementation is only interested in VBA macros from the own
+        document, ignoring the valid syntax 'Macro1!MyMacro' for sheet-local
+        sheet macros.
+     */
+    sal_Int32 nRefId = -1;
+    OUString aRemainder;
+    if( lclExtractRefId( nRefId, aRemainder, rFormulaString ) && (aRemainder.getLength() > 1) && (aRemainder[ 0 ] == '!') )
+    {
+        /*  In BIFF12 documents, the reference identifier is always the
+            one-based index of the external link as it is in OOXML documents
+            (it is not an index into the list of reference sheets as used in
+            cell formulas). Index 0 is an implicit placeholder for the own
+            document. In BIFF12 documents, the reference to the own document is
+            stored explicitly, mostly at the top of the list, so index 1 may
+            resolve to the own document too.
+            Passing 'false' to getExternalLink() specifies to ignore the
+            reference sheets list (if existing) and to access the list of
+            external links directly. */
+        const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId, false ).get();
+        OSL_ENSURE( pExtLink, "FormulaParser::importMacroName - missing link" );
+        // do not accept macros in external documents (not supported)
+        if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_SELF) )
+        {
+            // ignore sheet macros (defined name for VBA macros may not exist, see above)
+            OUString aMacroName = aRemainder.copy( 1 );
+            const DefinedName* pDefName = getDefinedNames().getByModelName( aMacroName ).get();
+            if( !pDefName || pDefName->isVBName() )
+                return aMacroName;
+        }
+    }
+    return OUString();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/numberformatsbuffer.cxx b/sc/source/filter/oox/numberformatsbuffer.cxx
new file mode 100644
index 000000000000..e8a9ca55796d
--- /dev/null
+++ b/sc/source/filter/oox/numberformatsbuffer.cxx
@@ -0,0 +1,2117 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "numberformatsbuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertymap.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OStringToOUString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+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_FAIL( 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_FAIL( 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.isEmpty() )
+        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( getBaseFilter().getServiceFactory()->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.isEmpty() )
+        {
+            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_FAIL( "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( SequenceInputStream& rStrm )
+{
+    sal_Int32 nNumFmtId = rStrm.readuInt16();
+    OUString aFmtCode = BiffHelper::readString( rStrm );
+    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/sc/source/filter/oox/ooxformulaparser.cxx b/sc/source/filter/oox/ooxformulaparser.cxx
new file mode 100644
index 000000000000..ebb5175f4eee
--- /dev/null
+++ b/sc/source/filter/oox/ooxformulaparser.cxx
@@ -0,0 +1,205 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "ooxformulaparser.hxx"
+
+#include 
+#include "formulaparser.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+class OOXMLFormulaParserImpl : private FormulaFinalizer
+{
+public:
+    explicit            OOXMLFormulaParserImpl( const Reference< XMultiServiceFactory >& rxModelFactory );
+
+    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 >& rxModelFactory ) :
+    FormulaFinalizer( OpCodeProvider( rxModelFactory, FILTER_OOXML, BIFF_UNKNOWN, true ) ),
+    maApiParser( rxModelFactory, *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
+            "'\Library\'!". */
+
+    // 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;
+}
+
+// ============================================================================
+
+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.xls.FormulaParser" );
+}
+
+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 > xModelFactory( mxComponent, UNO_QUERY_THROW );
+        mxParserImpl.reset( new OOXMLFormulaParserImpl( xModelFactory ) );
+    }
+    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/sc/source/filter/oox/pagesettings.cxx b/sc/source/filter/oox/pagesettings.cxx
new file mode 100644
index 000000000000..6f140b16518e
--- /dev/null
+++ b/sc/source/filter/oox/pagesettings.cxx
@@ -0,0 +1,1285 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "pagesettings.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/xmlfilterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/graphichelper.hxx"
+#include "oox/helper/propertymap.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "biffinputstream.hxx"
+#include "excelhandlers.hxx"
+#include "stylesbuffer.hxx"
+#include "unitconverter.hxx"
+#include 
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::Relations;
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+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 BIFF12_PRINTOPT_HORCENTER          = 0x0001;
+const sal_uInt16 BIFF12_PRINTOPT_VERCENTER          = 0x0002;
+const sal_uInt16 BIFF12_PRINTOPT_PRINTHEADING       = 0x0004;
+const sal_uInt16 BIFF12_PRINTOPT_PRINTGRID          = 0x0008;
+
+const sal_uInt16 BIFF12_HEADERFOOTER_DIFFEVEN       = 0x0001;
+const sal_uInt16 BIFF12_HEADERFOOTER_DIFFFIRST      = 0x0002;
+const sal_uInt16 BIFF12_HEADERFOOTER_SCALEDOC       = 0x0004;
+const sal_uInt16 BIFF12_HEADERFOOTER_ALIGNMARGIN    = 0x0008;
+
+const sal_uInt16 BIFF12_PAGESETUP_INROWS            = 0x0001;
+const sal_uInt16 BIFF12_PAGESETUP_LANDSCAPE         = 0x0002;
+const sal_uInt16 BIFF12_PAGESETUP_INVALID           = 0x0004;
+const sal_uInt16 BIFF12_PAGESETUP_BLACKWHITE        = 0x0008;
+const sal_uInt16 BIFF12_PAGESETUP_DRAFTQUALITY      = 0x0010;
+const sal_uInt16 BIFF12_PAGESETUP_PRINTNOTES        = 0x0020;
+const sal_uInt16 BIFF12_PAGESETUP_DEFAULTORIENT     = 0x0040;
+const sal_uInt16 BIFF12_PAGESETUP_USEFIRSTPAGE      = 0x0080;
+const sal_uInt16 BIFF12_PAGESETUP_NOTES_END         = 0x0100;   // different to BIFF flag
+
+const sal_uInt16 BIFF12_CHARTPAGESETUP_LANDSCAPE    = 0x0001;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_INVALID      = 0x0002;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_BLACKWHITE   = 0x0004;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_DEFAULTORIENT= 0x0008;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_USEFIRSTPAGE = 0x0010;
+const sal_uInt16 BIFF12_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::setBiffPrintErrors( 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() );
+    ::sax::Converter::convertMeasure(
+            maModel.mnPaperWidth, aStr, util::MeasureUnit::MM_100TH);
+    aStr                    = rAttribs.getString ( XML_paperHeight, OUString() );
+    ::sax::Converter::convertMeasure(
+            maModel.mnPaperHeight, aStr, util::MeasureUnit::MM_100TH );
+    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() );
+    ::sax::Converter::convertMeasure(
+            maModel.mnPaperWidth, aStr, util::MeasureUnit::MM_100TH );
+    aStr                    = rAttribs.getString ( XML_paperHeight, OUString() );
+    ::sax::Converter::convertMeasure(
+            maModel.mnPaperHeight, aStr, util::MeasureUnit::MM_100TH );
+    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( SequenceInputStream& rStrm )
+{
+    rStrm   >> maModel.mfLeftMargin   >> maModel.mfRightMargin
+            >> maModel.mfTopMargin    >> maModel.mfBottomMargin
+            >> maModel.mfHeaderMargin >> maModel.mfFooterMargin;
+}
+
+void PageSettings::importPrintOptions( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    rStrm >> nFlags;
+    maModel.mbHorCenter     = getFlag( nFlags, BIFF12_PRINTOPT_HORCENTER );
+    maModel.mbVerCenter     = getFlag( nFlags, BIFF12_PRINTOPT_VERCENTER );
+    maModel.mbPrintGrid     = getFlag( nFlags, BIFF12_PRINTOPT_PRINTGRID );
+    maModel.mbPrintHeadings = getFlag( nFlags, BIFF12_PRINTOPT_PRINTHEADING );
+}
+
+void PageSettings::importPageSetup( const Relations& rRelations, SequenceInputStream& 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.setBiffPrintErrors( extractValue< sal_uInt8 >( nFlags, 9, 2 ) );
+    maModel.maBinSettPath   = rRelations.getFragmentPathFromRelId( aRelId );
+    maModel.mnOrientation   = getFlagValue( nFlags, BIFF12_PAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, BIFF12_PAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
+    maModel.mnPageOrder     = getFlagValue( nFlags, BIFF12_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
+    maModel.mnCellComments  = getFlagValue( nFlags, BIFF12_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, BIFF12_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
+    maModel.mbValidSettings = !getFlag( nFlags, BIFF12_PAGESETUP_INVALID );
+    maModel.mbUseFirstPage  = getFlag( nFlags, BIFF12_PAGESETUP_USEFIRSTPAGE );
+    maModel.mbBlackWhite    = getFlag( nFlags, BIFF12_PAGESETUP_BLACKWHITE );
+    maModel.mbDraftQuality  = getFlag( nFlags, BIFF12_PAGESETUP_DRAFTQUALITY );
+}
+
+void PageSettings::importChartPageSetup( const Relations& rRelations, SequenceInputStream& 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, BIFF12_CHARTPAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, BIFF12_CHARTPAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
+    maModel.mbValidSettings = !getFlag( nFlags, BIFF12_CHARTPAGESETUP_INVALID );
+    maModel.mbUseFirstPage  = getFlag( nFlags, BIFF12_CHARTPAGESETUP_USEFIRSTPAGE );
+    maModel.mbBlackWhite    = getFlag( nFlags, BIFF12_CHARTPAGESETUP_BLACKWHITE );
+    maModel.mbDraftQuality  = getFlag( nFlags, BIFF12_CHARTPAGESETUP_DRAFTQUALITY );
+}
+
+void PageSettings::importHeaderFooter( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    rStrm   >> nFlags
+            >> maModel.maOddHeader   >> maModel.maOddFooter
+            >> maModel.maEvenHeader  >> maModel.maEvenFooter
+            >> maModel.maFirstHeader >> maModel.maFirstFooter;
+    maModel.mbUseEvenHF  = getFlag( nFlags, BIFF12_HEADERFOOTER_DIFFEVEN );
+    maModel.mbUseFirstHF = getFlag( nFlags, BIFF12_HEADERFOOTER_DIFFFIRST );
+}
+
+void PageSettings::importPicture( const Relations& rRelations, SequenceInputStream& rStrm )
+{
+    importPictureData( rRelations, BiffHelper::readString( rStrm ) );
+}
+
+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.setBiffPrintErrors( 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.isEmpty() )
+        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.isEmpty() ||
+            !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), OOXML, BIFF12, and BIFF8 only
+                        if( (getFilterType() == FILTER_OOXML) || ((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_OOXML) && (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
+    {
+        xContent.set( getBaseFilter().getModelFactory()->createInstance( rServiceName ), UNO_QUERY_THROW );
+    }
+    catch( Exception& )
+    {
+        OSL_FAIL( 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.isEmpty() )
+    {
+        // 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.isEmpty() )
+        {
+            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.isEmpty() )
+    {
+        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.isEmpty();
+    bool bHasEvenContent = bUseEvenContent && !rEvenContent.isEmpty();
+
+    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.isEmpty(), "PageSettingsConverter::writeHeaderFooter - empty h/f string found" );
+    sal_Int32 nHeight = 0;
+    if( !rContent.isEmpty() )
+    {
+        Reference< XHeaderFooterContent > xHFContent( rPropSet.getAnyProperty( nPropId ), UNO_QUERY );
+        if( 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/sc/source/filter/oox/pivotcachebuffer.cxx b/sc/source/filter/oox/pivotcachebuffer.cxx
new file mode 100644
index 000000000000..4a5c32170a3c
--- /dev/null
+++ b/sc/source/filter/oox/pivotcachebuffer.cxx
@@ -0,0 +1,1607 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "pivotcachebuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "biffinputstream.hxx"
+#include "defnamesbuffer.hxx"
+#include "excelhandlers.hxx"
+#include "pivotcachefragment.hxx"
+#include "sheetdatabuffer.hxx"
+#include "tablebuffer.hxx"
+#include "unitconverter.hxx"
+#include "worksheetbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+using ::oox::core::Relations;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF12_PCDFIELD_SERVERFIELD        = 0x0001;
+const sal_uInt16 BIFF12_PCDFIELD_NOUNIQUEITEMS      = 0x0002;
+const sal_uInt16 BIFF12_PCDFIELD_DATABASEFIELD      = 0x0004;
+const sal_uInt16 BIFF12_PCDFIELD_HASCAPTION         = 0x0008;
+const sal_uInt16 BIFF12_PCDFIELD_MEMBERPROPFIELD    = 0x0010;
+const sal_uInt16 BIFF12_PCDFIELD_HASFORMULA         = 0x0100;
+const sal_uInt16 BIFF12_PCDFIELD_HASPROPERTYNAME    = 0x0200;
+
+const sal_uInt16 BIFF12_PCDFSITEMS_HASSEMIMIXED     = 0x0001;
+const sal_uInt16 BIFF12_PCDFSITEMS_HASNONDATE       = 0x0002;
+const sal_uInt16 BIFF12_PCDFSITEMS_HASDATE          = 0x0004;
+const sal_uInt16 BIFF12_PCDFSITEMS_HASSTRING        = 0x0008;
+const sal_uInt16 BIFF12_PCDFSITEMS_HASBLANK         = 0x0010;
+const sal_uInt16 BIFF12_PCDFSITEMS_HASMIXED         = 0x0020;
+const sal_uInt16 BIFF12_PCDFSITEMS_ISNUMERIC        = 0x0040;
+const sal_uInt16 BIFF12_PCDFSITEMS_ISINTEGER        = 0x0080;
+const sal_uInt16 BIFF12_PCDFSITEMS_HASMINMAX        = 0x0100;
+const sal_uInt16 BIFF12_PCDFSITEMS_HASLONGTEXT      = 0x0200;
+
+const sal_uInt16 BIFF12_PCITEM_ARRAY_DOUBLE         = 0x0001;
+const sal_uInt16 BIFF12_PCITEM_ARRAY_STRING         = 0x0002;
+const sal_uInt16 BIFF12_PCITEM_ARRAY_ERROR          = 0x0010;
+const sal_uInt16 BIFF12_PCITEM_ARRAY_DATE           = 0x0020;
+
+const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOSTART        = 0x01;
+const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOEND          = 0x02;
+const sal_uInt8 BIFF12_PCDFRANGEPR_DATEGROUP        = 0x04;
+
+const sal_uInt8 BIFF12_PCDEFINITION_SAVEDATA        = 0x01;
+const sal_uInt8 BIFF12_PCDEFINITION_INVALID         = 0x02;
+const sal_uInt8 BIFF12_PCDEFINITION_REFRESHONLOAD   = 0x04;
+const sal_uInt8 BIFF12_PCDEFINITION_OPTIMIZEMEMORY  = 0x08;
+const sal_uInt8 BIFF12_PCDEFINITION_ENABLEREFRESH   = 0x10;
+const sal_uInt8 BIFF12_PCDEFINITION_BACKGROUNDQUERY = 0x20;
+const sal_uInt8 BIFF12_PCDEFINITION_UPGRADEONREFR   = 0x40;
+const sal_uInt8 BIFF12_PCDEFINITION_TUPELCACHE      = 0x80;
+
+const sal_uInt8 BIFF12_PCDEFINITION_HASUSERNAME     = 0x01;
+const sal_uInt8 BIFF12_PCDEFINITION_HASRELID        = 0x02;
+const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTSUBQUERY = 0x04;
+const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTDRILL    = 0x08;
+
+const sal_uInt8 BIFF12_PCDWBSOURCE_HASRELID         = 0x01;
+const sal_uInt8 BIFF12_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 ), mbUnused( false )
+{
+}
+
+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;
+    mbUnused = rAttribs.getBool( XML_u, false );
+}
+
+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( SequenceInputStream& rStrm )
+{
+    maValue <<= BiffHelper::readString( rStrm );
+    mnType = XML_s;
+}
+
+void PivotCacheItem::readDouble( SequenceInputStream& rStrm )
+{
+    maValue <<= rStrm.readDouble();
+    mnType = XML_n;
+}
+
+void PivotCacheItem::readDate( SequenceInputStream& 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( SequenceInputStream& rStrm )
+{
+    maValue <<= (rStrm.readuInt8() != 0);
+    mnType = XML_b;
+}
+
+void PivotCacheItem::readError( SequenceInputStream& rStrm )
+{
+    maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
+    mnType = XML_e;
+}
+
+void PivotCacheItem::readIndex( SequenceInputStream& 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;
+}
+
+void PivotCacheItem::setStringValue( const OUString& sString )
+{
+    mnType = XML_s;
+    maValue <<= sString;
+}
+
+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_FAIL( "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_FAIL( "PivotCacheItemList::importItem - unknown element type" );
+    }
+}
+
+void PivotCacheItemList::importItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    if( nRecId == BIFF12_ID_PCITEM_ARRAY )
+    {
+        importArray( rStrm );
+        return;
+    }
+
+    PivotCacheItem& rItem = createItem();
+    switch( nRecId )
+    {
+        case BIFF12_ID_PCITEM_MISSING:
+        case BIFF12_ID_PCITEMA_MISSING:                             break;
+        case BIFF12_ID_PCITEM_STRING:
+        case BIFF12_ID_PCITEMA_STRING:  rItem.readString( rStrm );  break;
+        case BIFF12_ID_PCITEM_DOUBLE:
+        case BIFF12_ID_PCITEMA_DOUBLE:  rItem.readDouble( rStrm );  break;
+        case BIFF12_ID_PCITEM_DATE:
+        case BIFF12_ID_PCITEMA_DATE:    rItem.readDate( rStrm );    break;
+        case BIFF12_ID_PCITEM_BOOL:
+        case BIFF12_ID_PCITEMA_BOOL:    rItem.readBool( rStrm );    break;
+        case BIFF12_ID_PCITEM_ERROR:
+        case BIFF12_ID_PCITEMA_ERROR:   rItem.readError( rStrm );   break;
+        default:    OSL_FAIL( "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::applyItemCaptions( const IdCaptionPairList& vCaptions )
+{
+    for( IdCaptionPairList::const_iterator aIt = vCaptions.begin(), aEnd = vCaptions.end(); aIt != aEnd; ++aIt )
+    {
+        if ( static_cast( aIt->first ) < maItems.size() )
+            maItems[ aIt->first ].setStringValue( aIt->second );
+    }
+}
+
+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( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nType = rStrm.readuInt16();
+    sal_Int32 nCount = rStrm.readInt32();
+    for( sal_Int32 nIdx = 0; !rStrm.isEof() && (nIdx < nCount); ++nIdx )
+    {
+        switch( nType )
+        {
+            case BIFF12_PCITEM_ARRAY_DOUBLE: createItem().readDouble( rStrm );   break;
+            case BIFF12_PCITEM_ARRAY_STRING: createItem().readString( rStrm );   break;
+            case BIFF12_PCITEM_ARRAY_ERROR:  createItem().readError( rStrm );    break;
+            case BIFF12_PCITEM_ARRAY_DATE:   createItem().readDate( rStrm );     break;
+            default:
+                OSL_FAIL( "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::setBiffGroupBy( 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( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    rStrm >> nFlags >> maFieldModel.mnNumFmtId;
+    maFieldModel.mnSqlType = rStrm.readInt16();
+    rStrm >> maFieldModel.mnHierarchy >> maFieldModel.mnLevel >> maFieldModel.mnMappingCount >> maFieldModel.maName;
+    if( getFlag( nFlags, BIFF12_PCDFIELD_HASCAPTION ) )
+        rStrm >> maFieldModel.maCaption;
+    if( getFlag( nFlags, BIFF12_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, BIFF12_PCDFIELD_HASPROPERTYNAME ) )
+        rStrm >> maFieldModel.maPropertyName;
+
+    maFieldModel.mbDatabaseField   = getFlag( nFlags, BIFF12_PCDFIELD_DATABASEFIELD );
+    maFieldModel.mbServerField     = getFlag( nFlags, BIFF12_PCDFIELD_SERVERFIELD );
+    maFieldModel.mbUniqueList      = !getFlag( nFlags, BIFF12_PCDFIELD_NOUNIQUEITEMS );
+    maFieldModel.mbMemberPropField = getFlag( nFlags, BIFF12_PCDFIELD_MEMBERPROPFIELD );
+}
+
+void PivotCacheField::importPCDFSharedItems( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    rStrm >> nFlags;
+    maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSEMIMIXED );
+    maSharedItemsModel.mbHasNonDate   = getFlag( nFlags, BIFF12_PCDFSITEMS_HASNONDATE );
+    maSharedItemsModel.mbHasDate      = getFlag( nFlags, BIFF12_PCDFSITEMS_HASDATE );
+    maSharedItemsModel.mbHasString    = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSTRING );
+    maSharedItemsModel.mbHasBlank     = getFlag( nFlags, BIFF12_PCDFSITEMS_HASBLANK );
+    maSharedItemsModel.mbHasMixed     = getFlag( nFlags, BIFF12_PCDFSITEMS_HASMIXED );
+    maSharedItemsModel.mbIsNumeric    = getFlag( nFlags, BIFF12_PCDFSITEMS_ISNUMERIC );
+    maSharedItemsModel.mbIsInteger    = getFlag( nFlags, BIFF12_PCDFSITEMS_ISINTEGER );
+    maSharedItemsModel.mbHasLongText  = getFlag( nFlags, BIFF12_PCDFSITEMS_HASLONGTEXT );
+}
+
+void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    maSharedItems.importItem( nRecId, rStrm );
+}
+
+void PivotCacheField::importPCDFieldGroup( SequenceInputStream& rStrm )
+{
+    rStrm >> maFieldGroupModel.mnParentField >> maFieldGroupModel.mnBaseField;
+}
+
+void PivotCacheField::importPCDFRangePr( SequenceInputStream& rStrm )
+{
+    sal_uInt8 nGroupBy, nFlags;
+    rStrm >> nGroupBy >> nFlags >> maFieldGroupModel.mfStartValue >> maFieldGroupModel.mfEndValue >> maFieldGroupModel.mfInterval;
+
+    maFieldGroupModel.setBiffGroupBy( nGroupBy );
+    maFieldGroupModel.mbRangeGroup   = true;
+    maFieldGroupModel.mbDateGroup    = getFlag( nFlags, BIFF12_PCDFRANGEPR_DATEGROUP );
+    maFieldGroupModel.mbAutoStart    = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOSTART );
+    maFieldGroupModel.mbAutoEnd      = getFlag( nFlags, BIFF12_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, SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( nRecId == BIFF12_ID_PCITEM_INDEX, "PivotCacheField::importPCDFDiscretePrItem - unexpected record" );
+    if( nRecId == BIFF12_ID_PCITEM_INDEX )
+        maDiscreteItems.push_back( rStrm.readInt32() );
+}
+
+void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& 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.setBiffGroupBy( 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.size() / 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::applyItemCaptions( const IdCaptionPairList& vCaptions )
+{
+    if( hasGroupItems() )
+        maGroupItems.applyItemCaptions( vCaptions );
+    if( hasSharedItems() )
+        maSharedItems.applyItemCaptions( vCaptions );
+}
+
+void PivotCacheField::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
+{
+    if( hasGroupItems() )
+        maGroupItems.getCacheItemNames( orItemNames );
+    else if( hasSharedItems() )
+        maSharedItems.getCacheItemNames( orItemNames );
+}
+
+PivotCacheItemList PivotCacheField::getCacheItems() const
+{
+    if( hasGroupItems() )
+        return maGroupItems;
+    return maSharedItems;
+}
+
+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_FAIL( "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, const PivotCacheField& rBaseCacheField, 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::getVectorElementAccess( aItemMap, *aIt ) )
+        {
+            if ( const PivotCacheItem* pItem = rBaseCacheField.getCacheItems().getCacheItem( aIt - aBeg ) )
+            {
+                // Skip unspecified or ununsed entries or errors
+                if ( pItem->isUnused() || ( pItem->getType() == XML_m ) ||  ( pItem->getType() == XML_e ) )
+                    continue;
+            }
+            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( !aIt->empty() )
+        {
+            /*  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.empty() ) 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.isEmpty()); ++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.isEmpty(), "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.isEmpty(), "PivotCacheField::createParentGroupField - cannot find group name" );
+                if( aGroupName.isEmpty() )
+                    aGroupName = aAutoName;
+
+                if( xGroupName.is() && !aGroupName.isEmpty() )
+                {
+                    // 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::getVectorElementAccess( 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
+{
+    CellModel aModel;
+    aModel.maCellAddr = CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow );
+    rSheetHelper.getSheetData().setStringCell( aModel, 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( SequenceInputStream& 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 )
+    {
+        CellModel aModel;
+        aModel.maCellAddr = CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow );
+        SheetDataBuffer& rSheetData = rSheetHelper.getSheetData();
+        switch( rItem.getType() )
+        {
+            case XML_s: rSheetData.setStringCell( aModel, rItem.getValue().get< OUString >() );                             break;
+            case XML_n: rSheetData.setValueCell( aModel, rItem.getValue().get< double >() );                                break;
+            case XML_i: rSheetData.setValueCell( aModel, rItem.getValue().get< sal_Int16 >() );                             break;
+            case XML_d: rSheetData.setDateTimeCell( aModel, rItem.getValue().get< DateTime >() );                           break;
+            case XML_b: rSheetData.setBooleanCell( aModel, rItem.getValue().get< bool >() );                                break;
+            case XML_e: rSheetData.setErrorCell( aModel, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break;
+            default:    OSL_FAIL( "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 ),
+    mnCurrRow( -1 ),
+    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( SequenceInputStream& 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, BIFF12_PCDEFINITION_HASUSERNAME ) )
+        rStrm >> maDefModel.maRefreshedBy;
+    if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASRELID ) )
+        rStrm >> maDefModel.maRelId;
+
+    maDefModel.mbInvalid          = getFlag( nFlags1, BIFF12_PCDEFINITION_INVALID );
+    maDefModel.mbSaveData         = getFlag( nFlags1, BIFF12_PCDEFINITION_SAVEDATA );
+    maDefModel.mbRefreshOnLoad    = getFlag( nFlags1, BIFF12_PCDEFINITION_REFRESHONLOAD );
+    maDefModel.mbOptimizeMemory   = getFlag( nFlags1, BIFF12_PCDEFINITION_OPTIMIZEMEMORY );
+    maDefModel.mbEnableRefresh    = getFlag( nFlags1, BIFF12_PCDEFINITION_ENABLEREFRESH );
+    maDefModel.mbBackgroundQuery  = getFlag( nFlags1, BIFF12_PCDEFINITION_BACKGROUNDQUERY );
+    maDefModel.mbUpgradeOnRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_UPGRADEONREFR );
+    maDefModel.mbTupleCache       = getFlag( nFlags1, BIFF12_PCDEFINITION_TUPELCACHE );
+    maDefModel.mbSupportSubquery  = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTSUBQUERY );
+    maDefModel.mbSupportDrill     = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTDRILL );
+}
+
+void PivotCache::importPCDSource( SequenceInputStream& 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( SequenceInputStream& rStrm, const Relations& rRelations )
+{
+    sal_uInt8 nIsDefName, nIsBuiltinName, nFlags;
+    rStrm >> nIsDefName >> nIsBuiltinName >> nFlags;
+    if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASSHEET ) )
+        rStrm >> maSheetSrcModel.maSheet;
+    if( getFlag( nFlags, BIFF12_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.isEmpty() && maSheetSrcModel.maRelId.isEmpty();
+            bool bExternal = !maTargetUrl.isEmpty();   // 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( 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;
+    mnCurrRow = -1;
+    updateSourceDataRow( rSheetHelper, nRow );
+    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 nColIdx, sal_Int32 nRowIdx, const PivotCacheItem& rItem ) const
+{
+    sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn + nColIdx;
+    OSL_ENSURE( (maSheetSrcModel.maRange.StartColumn <= nCol) && (nCol <= maSheetSrcModel.maRange.EndColumn), "PivotCache::writeSourceDataCell - invalid column index" );
+    sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
+    OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::writeSourceDataCell - invalid row index" );
+    updateSourceDataRow( rSheetHelper, nRow );
+    if( const PivotCacheField* pCacheField = maDatabaseFields.get( nColIdx ).get() )
+        pCacheField->writeSourceDataCell( rSheetHelper, nCol, nRow, rItem );
+}
+
+void PivotCache::importPCRecord( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
+{
+    sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
+    OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCRecord - invalid row index" );
+    sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
+    sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
+    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 nRowIdx ) const
+{
+    sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
+    OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCItemIndexList - invalid row index" );
+    sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
+    sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
+    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.isEmpty(), "PivotCache::importDConRef - missing sheet name" );
+}
+
+void PivotCache::importDConName( BiffInputStream& rStrm )
+{
+    maSheetSrcModel.maDefName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
+    OSL_ENSURE( !maSheetSrcModel.maDefName.isEmpty(), "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.isEmpty() )
+    {
+        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.isEmpty() )
+    {
+        // 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.isEmpty() )
+    {
+        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 (OOXML only) are required. */
+    bool bHasRelation = (getFilterType() == FILTER_BIFF) || !maDefModel.maRelId.isEmpty();
+    if( bHasRelation && maSheetSrcModel.maDefName.isEmpty() && !maSheetSrcModel.maSheet.isEmpty() )
+        prepareSourceDataSheet();
+}
+
+void PivotCache::prepareSourceDataSheet()
+{
+    CellRangeAddress& rRange = maSheetSrcModel.maRange;
+    // data will be inserted in top-left cell, sheet index is still set to 0 (will be set below)
+    rRange.EndColumn -= rRange.StartColumn;
+    rRange.StartColumn = 0;
+    rRange.EndRow -= rRange.StartRow;
+    rRange.StartRow = 0;
+    // check range location, do not allow ranges that overflow the sheet partly
+    if( getAddressConverter().checkCellRange( rRange, false, true ) )
+    {
+        maColSpans.insert( ValueRange( rRange.StartColumn, rRange.EndColumn ) );
+        OUString aSheetName = CREATE_OUSTRING( "DPCache_" ) + maSheetSrcModel.maSheet;
+        rRange.Sheet = getWorksheets().insertEmptySheet( aSheetName, false );
+        mbValidSource = mbDummySheet = rRange.Sheet >= 0;
+    }
+}
+
+void PivotCache::updateSourceDataRow( WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const
+{
+    if( mnCurrRow != nRow )
+    {
+        rSheetHelper.getSheetData().setColSpans( nRow, maColSpans );
+        mnCurrRow = nRow;
+    }
+}
+
+// ============================================================================
+
+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.isEmpty() )
+        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() )
+    {
+        /*  OOXML/BIFF12 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_OOXML:
+        {
+            // 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 PivotCacheDefinitionFragment( *this, aIt->second, rCache ) );
+            return &rCache;
+        }
+
+        /*  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( 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;
+        }
+
+        case FILTER_UNKNOWN:
+            OSL_FAIL( "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/sc/source/filter/oox/pivotcachefragment.cxx b/sc/source/filter/oox/pivotcachefragment.cxx
new file mode 100644
index 000000000000..3671f52066bb
--- /dev/null
+++ b/sc/source/filter/oox/pivotcachefragment.cxx
@@ -0,0 +1,478 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "pivotcachefragment.hxx"
+
+#include "oox/helper/attributelist.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "pivotcachebuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::uno;
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+PivotCacheFieldContext::PivotCacheFieldContext( WorkbookFragmentBase& rFragment, PivotCacheField& rCacheField ) :
+    WorkbookContextBase( rFragment ),
+    mrCacheField( rCacheField )
+{
+}
+
+ContextHandlerRef PivotCacheFieldContext::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 PivotCacheFieldContext::onStartElement( const AttributeList& rAttribs )
+{
+    if( isRootElement() )
+        mrCacheField.importCacheField( rAttribs );
+}
+
+ContextHandlerRef PivotCacheFieldContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_PCDFIELD:
+            switch( nRecId )
+            {
+                case BIFF12_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItems( rStrm );  return this;
+                case BIFF12_ID_PCDFIELDGROUP:   mrCacheField.importPCDFieldGroup( rStrm );    return this;
+            }
+        break;
+
+        case BIFF12_ID_PCDFIELDGROUP:
+            switch( nRecId )
+            {
+                case BIFF12_ID_PCDFRANGEPR:     mrCacheField.importPCDFRangePr( rStrm );    break;
+                case BIFF12_ID_PCDFDISCRETEPR:  return this;
+                case BIFF12_ID_PCDFGROUPITEMS:  return this;
+            }
+        break;
+
+        case BIFF12_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItem( nRecId, rStrm );     break;
+        case BIFF12_ID_PCDFDISCRETEPR:  mrCacheField.importPCDFDiscretePrItem( nRecId, rStrm ); break;
+        case BIFF12_ID_PCDFGROUPITEMS:  mrCacheField.importPCDFGroupItem( nRecId, rStrm );      break;
+    }
+    return 0;
+}
+
+void PivotCacheFieldContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    if( isRootElement() )
+        mrCacheField.importPCDField( rStrm );
+}
+
+// ============================================================================
+
+PivotCacheDefinitionFragment::PivotCacheDefinitionFragment(
+        const WorkbookHelper& rHelper, const OUString& rFragmentPath, PivotCache& rPivotCache ) :
+    WorkbookFragmentBase( rHelper, rFragmentPath ),
+    mrPivotCache( rPivotCache )
+{
+}
+
+ContextHandlerRef PivotCacheDefinitionFragment::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 PivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef PivotCacheDefinitionFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_PCDEFINITION ) { mrPivotCache.importPCDefinition( rStrm ); return this; }
+        break;
+
+        case BIFF12_ID_PCDEFINITION:
+            switch( nRecId )
+            {
+                case BIFF12_ID_PCDSOURCE: mrPivotCache.importPCDSource( rStrm ); return this;
+                case BIFF12_ID_PCDFIELDS: return this;
+            }
+        break;
+
+        case BIFF12_ID_PCDSOURCE:
+            if( nRecId == BIFF12_ID_PCDSHEETSOURCE ) mrPivotCache.importPCDSheetSource( rStrm, getRelations() );
+        break;
+
+        case BIFF12_ID_PCDFIELDS:
+            if( nRecId == BIFF12_ID_PCDFIELD ) return new PivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* PivotCacheDefinitionFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_PCDEFINITION,       BIFF12_ID_PCDEFINITION + 1      },
+        { BIFF12_ID_PCDFDISCRETEPR,     BIFF12_ID_PCDFDISCRETEPR + 1    },
+        { BIFF12_ID_PCDFGROUPITEMS,     BIFF12_ID_PCDFGROUPITEMS + 1    },
+        { BIFF12_ID_PCDFIELD,           BIFF12_ID_PCDFIELD + 1          },
+        { BIFF12_ID_PCDFIELDGROUP,      BIFF12_ID_PCDFIELDGROUP + 1     },
+        { BIFF12_ID_PCDFIELDS,          BIFF12_ID_PCDFIELDS + 1         },
+        { BIFF12_ID_PCDFRANGEPR,        BIFF12_ID_PCDFRANGEPR + 1       },
+        { BIFF12_ID_PCDFSHAREDITEMS,    BIFF12_ID_PCDFSHAREDITEMS + 1   },
+        { BIFF12_ID_PCITEM_ARRAY,       BIFF12_ID_PCITEM_ARRAY + 1      },
+        { BIFF12_ID_PCDSHEETSOURCE,     BIFF12_ID_PCDSHEETSOURCE + 1    },
+        { BIFF12_ID_PCDSOURCE,          BIFF12_ID_PCDSOURCE + 1         },
+        { -1,                           -1                              }
+    };
+    return spRecInfos;
+}
+
+void PivotCacheDefinitionFragment::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.isEmpty() )
+        {
+            sal_Int16 nSheet = mrPivotCache.getSourceRange().Sheet;
+            WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, ISegmentProgressBarRef(), SHEETTYPE_WORKSHEET, nSheet );
+            if( xSheetGlob.get() )
+                importOoxFragment( new PivotCacheRecordsFragment( *xSheetGlob, aRecFragmentPath, mrPivotCache ) );
+        }
+    }
+}
+
+// ============================================================================
+
+PivotCacheRecordsFragment::PivotCacheRecordsFragment( const WorksheetHelper& rHelper,
+        const OUString& rFragmentPath, const PivotCache& rPivotCache ) :
+    WorksheetFragmentBase( rHelper, rFragmentPath ),
+    mrPivotCache( rPivotCache ),
+    mnColIdx( 0 ),
+    mnRowIdx( 0 ),
+    mbInRecord( false )
+{
+    // prepare sheet: insert column header names into top row
+    rPivotCache.writeSourceHeaderCells( *this );
+}
+
+ContextHandlerRef PivotCacheRecordsFragment::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_FAIL( "OoxPivotCacheRecordsFragment::onCreateContext - unexpected element" );
+            }
+            mrPivotCache.writeSourceDataCell( *this, mnColIdx, mnRowIdx, aItem );
+            ++mnColIdx;
+        }
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef PivotCacheRecordsFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_PCRECORDS ) return this;
+        break;
+
+        case BIFF12_ID_PCRECORDS:
+            switch( nRecId )
+            {
+                case BIFF12_ID_PCRECORD:    importPCRecord( rStrm );                break;
+                case BIFF12_ID_PCRECORDDT:  startCacheRecord();                     break;
+                default:                    importPCRecordItem( nRecId, rStrm );    break;
+            }
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* PivotCacheRecordsFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_PCRECORDS,  BIFF12_ID_PCRECORDS + 1 },
+        { -1,                   -1                      }
+    };
+    return spRecInfos;
+}
+
+// private --------------------------------------------------------------------
+
+void PivotCacheRecordsFragment::startCacheRecord()
+{
+    mnColIdx = 0;
+    ++mnRowIdx;
+    mbInRecord = true;
+}
+
+void PivotCacheRecordsFragment::importPCRecord( SequenceInputStream& rStrm )
+{
+    startCacheRecord();
+    mrPivotCache.importPCRecord( rStrm, *this, mnRowIdx );
+    mbInRecord = false;
+}
+
+void PivotCacheRecordsFragment::importPCRecordItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    if( mbInRecord )
+    {
+        PivotCacheItem aItem;
+        switch( nRecId )
+        {
+            case BIFF12_ID_PCITEM_MISSING:                              break;
+            case BIFF12_ID_PCITEM_STRING:   aItem.readString( rStrm );  break;
+            case BIFF12_ID_PCITEM_DOUBLE:   aItem.readDouble( rStrm );  break;
+            case BIFF12_ID_PCITEM_DATE:     aItem.readDate( rStrm );    break;
+            case BIFF12_ID_PCITEM_BOOL:     aItem.readBool( rStrm );    break;
+            case BIFF12_ID_PCITEM_ERROR:    aItem.readError( rStrm );   break;
+            case BIFF12_ID_PCITEM_INDEX:    aItem.readIndex( rStrm );   break;
+            default:    OSL_FAIL( "OoxPivotCacheRecordsFragment::importPCRecordItem - unexpected record" );
+        }
+        mrPivotCache.writeSourceDataCell( *this, mnColIdx, mnRowIdx, aItem );
+        ++mnColIdx;
+    }
+}
+
+// ============================================================================
+// ============================================================================
+
+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 OUString& rStrmName, PivotCache& rPivotCache ) :
+    BiffWorkbookFragmentBase( rHelper, rStrmName, true ),
+    mrPivotCache( rPivotCache )
+{
+}
+
+bool BiffPivotCacheFragment::importFragment()
+{
+    BiffInputStream& rStrm = getInputStream();
+    if( rStrm.startNextRecord() && (rStrm.getRecId() == BIFF_ID_PCDEFINITION) )
+    {
+        // read PCDEFINITION and optional PCDEFINITION2 records
+        mrPivotCache.importPCDefinition( rStrm );
+
+        // read cache fields as long as another PCDFIELD record can be found
+        while( lclSeekToPCDField( rStrm ) )
+            mrPivotCache.createCacheField( true ).importPCDField( rStrm );
+
+        // 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. */
+            sal_Int16 nSheet = mrPivotCache.getSourceRange().Sheet;
+            WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, ISegmentProgressBarRef(), SHEETTYPE_WORKSHEET, nSheet );
+            if( xSheetGlob.get() )
+            {
+                BiffPivotCacheRecordsContext aContext( *xSheetGlob, mrPivotCache );
+                while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+                    aContext.importRecord( rStrm );
+            }
+        }
+    }
+
+    return rStrm.getRecId() == BIFF_ID_EOF;
+}
+
+// ============================================================================
+
+BiffPivotCacheRecordsContext::BiffPivotCacheRecordsContext( const WorksheetHelper& rHelper, const PivotCache& rPivotCache ) :
+    BiffWorksheetContextBase( rHelper ),
+    mrPivotCache( rPivotCache ),
+    mnColIdx( 0 ),
+    mnRowIdx( 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( BiffInputStream& rStrm )
+{
+    if( rStrm.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( rStrm, *this, mnRowIdx );
+        mbInRow = !maUnsharedCols.empty();  // mbInRow remains true, if unshared items are expected
+        return;
+    }
+
+    PivotCacheItem aItem;
+    switch( rStrm.getRecId() )
+    {
+        case BIFF_ID_PCITEM_MISSING:                                        break;
+        case BIFF_ID_PCITEM_STRING:     aItem.readString( rStrm, *this );   break;
+        case BIFF_ID_PCITEM_DOUBLE:     aItem.readDouble( rStrm );          break;
+        case BIFF_ID_PCITEM_INTEGER:    aItem.readInteger( rStrm );         break;
+        case BIFF_ID_PCITEM_DATE:       aItem.readDate( rStrm );            break;
+        case BIFF_ID_PCITEM_BOOL:       aItem.readBool( rStrm );            break;
+        case BIFF_ID_PCITEM_ERROR:      aItem.readError( rStrm );           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 ], mnRowIdx, aItem );
+    ++mnColIdx;
+}
+
+void BiffPivotCacheRecordsContext::startNextRow()
+{
+    mnColIdx = 0;
+    ++mnRowIdx;
+    mbInRow = true;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/pivottablebuffer.cxx b/sc/source/filter/oox/pivottablebuffer.cxx
new file mode 100644
index 000000000000..0a5dc7388f81
--- /dev/null
+++ b/sc/source/filter/oox/pivottablebuffer.cxx
@@ -0,0 +1,1590 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "pivottablebuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+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 BIFF12_PTFIELD_DATAFIELD           = 0x00000008;
+const sal_uInt32 BIFF12_PTFIELD_DEFAULT             = 0x00000100;
+const sal_uInt32 BIFF12_PTFIELD_SUM                 = 0x00000200;
+const sal_uInt32 BIFF12_PTFIELD_COUNTA              = 0x00000400;
+const sal_uInt32 BIFF12_PTFIELD_AVERAGE             = 0x00000800;
+const sal_uInt32 BIFF12_PTFIELD_MAX                 = 0x00001000;
+const sal_uInt32 BIFF12_PTFIELD_MIN                 = 0x00002000;
+const sal_uInt32 BIFF12_PTFIELD_PRODUCT             = 0x00004000;
+const sal_uInt32 BIFF12_PTFIELD_COUNT               = 0x00008000;
+const sal_uInt32 BIFF12_PTFIELD_STDDEV              = 0x00010000;
+const sal_uInt32 BIFF12_PTFIELD_STDDEVP             = 0x00020000;
+const sal_uInt32 BIFF12_PTFIELD_VAR                 = 0x00040000;
+const sal_uInt32 BIFF12_PTFIELD_VARP                = 0x00080000;
+
+const sal_uInt32 BIFF12_PTFIELD_SHOWALL             = 0x00000020;
+const sal_uInt32 BIFF12_PTFIELD_OUTLINE             = 0x00000040;
+const sal_uInt32 BIFF12_PTFIELD_INSERTBLANKROW      = 0x00000080;
+const sal_uInt32 BIFF12_PTFIELD_SUBTOTALTOP         = 0x00000100;
+const sal_uInt32 BIFF12_PTFIELD_INSERTPAGEBREAK     = 0x00000800;
+const sal_uInt32 BIFF12_PTFIELD_AUTOSORT            = 0x00001000;
+const sal_uInt32 BIFF12_PTFIELD_SORTASCENDING       = 0x00002000;
+const sal_uInt32 BIFF12_PTFIELD_AUTOSHOW            = 0x00004000;
+const sal_uInt32 BIFF12_PTFIELD_AUTOSHOWTOP         = 0x00008000;
+const sal_uInt32 BIFF12_PTFIELD_MULTIPAGEITEMS      = 0x00080000;
+
+const sal_uInt16 BIFF12_PTFITEM_HIDDEN              = 0x0001;
+const sal_uInt16 BIFF12_PTFITEM_HIDEDETAILS         = 0x0002;
+
+const sal_uInt8 BIFF12_PTPAGEFIELD_HASNAME          = 0x01;
+const sal_uInt8 BIFF12_PTPAGEFIELD_HASOLAPCAPTION   = 0x02;
+const sal_Int32 BIFF12_PTPAGEFIELD_MULTIITEMS       = 0x001000FE;
+
+const sal_uInt16 BIFF12_PTFILTER_HASNAME            = 0x0001;
+const sal_uInt16 BIFF12_PTFILTER_HASDESCRIPTION     = 0x0002;
+const sal_uInt16 BIFF12_PTFILTER_HASSTRVALUE1       = 0x0004;
+const sal_uInt16 BIFF12_PTFILTER_HASSTRVALUE2       = 0x0008;
+
+const sal_uInt8 BIFF12_TOP10FILTER_TOP              = 0x01;
+const sal_uInt8 BIFF12_TOP10FILTER_PERCENT          = 0x02;
+
+const sal_uInt32 BIFF12_PTDEF_SHOWITEMS             = 0x00000100;
+const sal_uInt32 BIFF12_PTDEF_DISABLEFIELDLIST      = 0x00000400;
+const sal_uInt32 BIFF12_PTDEF_HIDECALCMEMBERS       = 0x00001000;
+const sal_uInt32 BIFF12_PTDEF_WITHHIDDENTOTALS      = 0x00002000;
+const sal_uInt32 BIFF12_PTDEF_HIDEDRILL             = 0x00100000;
+const sal_uInt32 BIFF12_PTDEF_PRINTDRILL            = 0x00200000;
+const sal_uInt32 BIFF12_PTDEF_HIDEHEADERS           = 0x80000000;
+
+const sal_uInt32 BIFF12_PTDEF_SHOWEMPTYROW          = 0x00000004;
+const sal_uInt32 BIFF12_PTDEF_SHOWEMPTYCOL          = 0x00000008;
+const sal_uInt32 BIFF12_PTDEF_ENABLEDRILL           = 0x00000020;
+const sal_uInt32 BIFF12_PTDEF_PRESERVEFORMATTING    = 0x00000080;
+const sal_uInt32 BIFF12_PTDEF_USEAUTOFORMAT         = 0x00000100;
+const sal_uInt32 BIFF12_PTDEF_SHOWERROR             = 0x00000200;
+const sal_uInt32 BIFF12_PTDEF_SHOWMISSING           = 0x00000400;
+const sal_uInt32 BIFF12_PTDEF_PAGEOVERTHENDOWN      = 0x00000800;
+const sal_uInt32 BIFF12_PTDEF_SUBTOTALHIDDENITEMS   = 0x00001000;
+const sal_uInt32 BIFF12_PTDEF_ROWGRANDTOTALS        = 0x00002000;
+const sal_uInt32 BIFF12_PTDEF_COLGRANDTOTALS        = 0x00004000;
+const sal_uInt32 BIFF12_PTDEF_FIELDPRINTTITLES      = 0x00008000;
+const sal_uInt32 BIFF12_PTDEF_ITEMPRINTTITLES       = 0x00020000;
+const sal_uInt32 BIFF12_PTDEF_MERGEITEM             = 0x00040000;
+const sal_uInt32 BIFF12_PTDEF_HASDATACAPTION        = 0x00080000;
+const sal_uInt32 BIFF12_PTDEF_HASGRANDTOTALCAPTION  = 0x00100000;
+const sal_uInt32 BIFF12_PTDEF_HASPAGESTYLE          = 0x00200000;
+const sal_uInt32 BIFF12_PTDEF_HASPIVOTTABLESTYLE    = 0x00400000;
+const sal_uInt32 BIFF12_PTDEF_HASVACATEDSTYLE       = 0x00800000;
+const sal_uInt32 BIFF12_PTDEF_APPLYNUMFMT           = 0x01000000;
+const sal_uInt32 BIFF12_PTDEF_APPLYFONT             = 0x02000000;
+const sal_uInt32 BIFF12_PTDEF_APPLYALIGNMENT        = 0x04000000;
+const sal_uInt32 BIFF12_PTDEF_APPLYBORDER           = 0x08000000;
+const sal_uInt32 BIFF12_PTDEF_APPLYFILL             = 0x10000000;
+const sal_uInt32 BIFF12_PTDEF_APPLYPROTECTION       = 0x20000000;
+const sal_uInt32 BIFF12_PTDEF_HASTAG                = 0x40000000;
+
+const sal_uInt32 BIFF12_PTDEF_NOERRORCAPTION        = 0x00000040;
+const sal_uInt32 BIFF12_PTDEF_NOMISSINGCAPTION      = 0x00000080;
+const sal_uInt32 BIFF12_PTDEF_HASROWHEADERCAPTION   = 0x00000400;
+const sal_uInt32 BIFF12_PTDEF_HASCOLHEADERCAPTION   = 0x00000800;
+const sal_uInt32 BIFF12_PTDEF_FIELDLISTSORTASC      = 0x00001000;
+const sal_uInt32 BIFF12_PTDEF_NOCUSTOMLISTSORT      = 0x00004000;
+
+const sal_uInt8 BIFF12_PTDEF_ROWAXIS                = 1;
+const sal_uInt8 BIFF12_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::setBiffType( 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::setBiffAxis( 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( BIFF12_PTPAGEFIELD_MULTIITEMS )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+PTDataFieldModel::PTDataFieldModel() :
+    mnField( -1 ),
+    mnSubtotal( XML_sum ),
+    mnShowDataAs( XML_normal ),
+    mnBaseField( -1 ),
+    mnBaseItem( -1 ),
+    mnNumFmtId( 0 )
+{
+}
+
+void PTDataFieldModel::setBiffSubtotal( 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::setBiffShowDataAs( 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 );
+    aModel.msCaption     = rAttribs.getXString( XML_n, OUString() );
+    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( SequenceInputStream& rStrm )
+{
+    sal_uInt32 nFlags1, nFlags2;
+    rStrm >> nFlags1 >> maModel.mnNumFmtId >> nFlags2 >> maModel.mnAutoShowItems >> maModel.mnAutoShowRankBy;
+
+    maModel.setBiffAxis( extractValue< sal_uInt8 >( nFlags1, 0, 3 ) );
+    maModel.mbDataField       = getFlag( nFlags1, BIFF12_PTFIELD_DATAFIELD );
+    maModel.mbDefaultSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_DEFAULT );
+    maModel.mbSumSubtotal     = getFlag( nFlags1, BIFF12_PTFIELD_SUM );
+    maModel.mbCountASubtotal  = getFlag( nFlags1, BIFF12_PTFIELD_COUNTA );
+    maModel.mbAverageSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_AVERAGE );
+    maModel.mbMaxSubtotal     = getFlag( nFlags1, BIFF12_PTFIELD_MAX );
+    maModel.mbMinSubtotal     = getFlag( nFlags1, BIFF12_PTFIELD_MIN );
+    maModel.mbProductSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_PRODUCT );
+    maModel.mbCountSubtotal   = getFlag( nFlags1, BIFF12_PTFIELD_COUNT );
+    maModel.mbStdDevSubtotal  = getFlag( nFlags1, BIFF12_PTFIELD_STDDEV );
+    maModel.mbStdDevPSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_STDDEVP );
+    maModel.mbVarSubtotal     = getFlag( nFlags1, BIFF12_PTFIELD_VAR );
+    maModel.mbVarPSubtotal    = getFlag( nFlags1, BIFF12_PTFIELD_VARP );
+
+    maModel.mbShowAll         = getFlag( nFlags2, BIFF12_PTFIELD_SHOWALL );
+    maModel.mbOutline         = getFlag( nFlags2, BIFF12_PTFIELD_OUTLINE );
+    maModel.mbSubtotalTop     = getFlag( nFlags2, BIFF12_PTFIELD_SUBTOTALTOP );
+    maModel.mbInsertBlankRow  = getFlag( nFlags2, BIFF12_PTFIELD_INSERTBLANKROW );
+    maModel.mbInsertPageBreak = getFlag( nFlags2, BIFF12_PTFIELD_INSERTPAGEBREAK );
+    maModel.mbAutoShow        = getFlag( nFlags2, BIFF12_PTFIELD_AUTOSHOW );
+    maModel.mbTopAutoShow     = getFlag( nFlags2, BIFF12_PTFIELD_AUTOSHOWTOP );
+    maModel.mbMultiPageItems  = getFlag( nFlags2, BIFF12_PTFIELD_MULTIPAGEITEMS );
+
+    bool bAutoSort = getFlag( nFlags2, BIFF12_PTFIELD_AUTOSORT );
+    bool bAscending = getFlag( nFlags2, BIFF12_PTFIELD_SORTASCENDING );
+    maModel.mnSortType = bAutoSort ? (bAscending ? XML_ascending : XML_descending) : XML_manual;
+}
+
+void PivotTableField::importPTFItem( SequenceInputStream& rStrm )
+{
+    PTFieldItemModel aModel;
+    sal_uInt8 nType;
+    sal_uInt16 nFlags;
+    rStrm >> nType >> nFlags >> aModel.mnCacheItem;
+
+    aModel.setBiffType( nType );
+    aModel.mbShowDetails = !getFlag( nFlags, BIFF12_PTFITEM_HIDEDETAILS );
+    aModel.mbHidden      = getFlag( nFlags, BIFF12_PTFITEM_HIDDEN );
+
+    maItems.push_back( aModel );
+}
+
+void PivotTableField::importPTReference( SequenceInputStream& rStrm )
+{
+    rStrm >> maModel.mnSortRefField;
+}
+
+void PivotTableField::importPTReferenceItem( SequenceInputStream& rStrm )
+{
+    rStrm >> maModel.mnSortRefItem;
+}
+
+void PivotTableField::importPTField( BiffInputStream& rStrm )
+{
+    sal_uInt16 nAxis, nSubtCount, nSubtotals;
+    rStrm >> nAxis >> nSubtCount >> nSubtotals;
+    rStrm.skip( 2 );    // item count
+
+    maModel.setBiffAxis( 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.setBiffType( 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.isEmpty(), "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.isEmpty() )    // 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.isEmpty(), "PivotTableField::finalizeDateGroupingImport - cannot create date group field" );
+            }
+        }
+    }
+}
+
+void PivotTableField::finalizeParentGroupingImport( const Reference< XDataPilotField >& rxBaseDPField,  const PivotCacheField& rBaseCacheField, PivotCacheGroupItemVector& orItemNames )
+{
+    if( maDPFieldName.isEmpty() )    // prevent endless loops if file format is broken
+    {
+        if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
+        {
+            // data field can have user defined groupname captions, apply them
+            // if they do
+            IdCaptionPairList captionList;
+            for( ItemModelVector::iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
+            {
+                if ( aIt->mnType == XML_data  && aIt->msCaption.getLength() )
+                    captionList.push_back( IdCaptionPair( aIt->mnCacheItem, aIt->msCaption ) );
+            }
+            // #FIXME find another way out of this const nightmare prison
+            if ( !captionList.empty() )
+                const_cast( pCacheField )->applyItemCaptions( captionList );
+            maDPFieldName = pCacheField->createParentGroupField( rxBaseDPField, rBaseCacheField, 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 == BIFF12_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.isEmpty() )
+                        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_FAIL( "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 (OOXML/BIFF12 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( SequenceInputStream& 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, BIFF12_PTFILTER_HASNAME ) )
+        rStrm >> maModel.maName;
+    if( getFlag( nFlags, BIFF12_PTFILTER_HASDESCRIPTION ) )
+        rStrm >> maModel.maDescription;
+    if( getFlag( nFlags, BIFF12_PTFILTER_HASSTRVALUE1 ) )
+        rStrm >> maModel.maStrValue1;
+    if( getFlag( nFlags, BIFF12_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( SequenceInputStream& rStrm )
+{
+    sal_uInt8 nFlags;
+    rStrm >> nFlags >> maModel.mfValue;
+
+    OSL_ENSURE( getFlag( nFlags, BIFF12_TOP10FILTER_PERCENT ) == (maModel.mnType == XML_percent),
+        "PivotTableFilter::importTop10 - unexpected value of percent attribute" );
+    maModel.mbTopFilter = getFlag( nFlags, BIFF12_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 ),
+    mbUseAutoFormat( false ),
+    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.mnAutoFormatId        = rAttribs.getInteger( XML_autoFormatId, 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.mbUseAutoFormat       = rAttribs.getBool( XML_useAutoFormatting, false );
+    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 );
+    maDefModel.mbApplyNumFmt         = rAttribs.getBool( XML_applyNumberFormats, false );
+    maDefModel.mbApplyFont           = rAttribs.getBool( XML_applyFontFormats, false );
+    maDefModel.mbApplyAlignment      = rAttribs.getBool( XML_applyAlignmentFormats, false );
+    maDefModel.mbApplyBorder         = rAttribs.getBool( XML_applyBorderFormats, false );
+    maDefModel.mbApplyFill           = rAttribs.getBool( XML_applyPatternFormats, false );
+    // OOXML and BIFF12 documentation differ: OOXML mentions width/height, BIFF12 mentions protection
+    maDefModel.mbApplyProtection     = rAttribs.getBool( XML_applyWidthHeightFormats, false );
+}
+
+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, BIFF12_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( SequenceInputStream& 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;
+    maDefModel.mnAutoFormatId = rStrm.readuInt16();
+    rStrm.skip( 2 );    // unused
+    rStrm >> maDefModel.mnChartFormat >> maDefModel.mnCacheId >> maDefModel.maName;
+    if( getFlag( nFlags2, BIFF12_PTDEF_HASDATACAPTION ) )
+        rStrm >> maDefModel.maDataCaption;
+    if( getFlag( nFlags2, BIFF12_PTDEF_HASGRANDTOTALCAPTION ) )
+        rStrm >> maDefModel.maGrandTotalCaption;
+    if( !getFlag( nFlags3, BIFF12_PTDEF_NOERRORCAPTION ) )   // missing flag indicates existing string
+        rStrm >> maDefModel.maErrorCaption;
+    if( !getFlag( nFlags3, BIFF12_PTDEF_NOMISSINGCAPTION ) ) // missing flag indicates existing string
+        rStrm >> maDefModel.maMissingCaption;
+    if( getFlag( nFlags2, BIFF12_PTDEF_HASPAGESTYLE ) )
+        rStrm >> maDefModel.maPageStyle;
+    if( getFlag( nFlags2, BIFF12_PTDEF_HASPIVOTTABLESTYLE ) )
+        rStrm >> maDefModel.maPivotTableStyle;
+    if( getFlag( nFlags2, BIFF12_PTDEF_HASVACATEDSTYLE ) )
+        rStrm >> maDefModel.maVacatedStyle;
+    if( getFlag( nFlags2, BIFF12_PTDEF_HASTAG ) )
+        rStrm >> maDefModel.maTag;
+    if( getFlag( nFlags3, BIFF12_PTDEF_HASCOLHEADERCAPTION ) )   // TODO: right order (col/row)? spec is unclear
+        rStrm >> maDefModel.maColHeaderCaption;
+    if( getFlag( nFlags3, BIFF12_PTDEF_HASROWHEADERCAPTION ) )
+        rStrm >> maDefModel.maRowHeaderCaption;
+
+    OSL_ENSURE( (nDataAxis == BIFF12_PTDEF_ROWAXIS) || (nDataAxis == BIFF12_PTDEF_COLAXIS),
+        "PivotTable::importPTDefinition - unexpected axis position for data field" );
+
+    maDefModel.mnIndent              = extractValue< sal_uInt8 >( nFlags1, 24, 7 );
+    maDefModel.mbDataOnRows          = nDataAxis == BIFF12_PTDEF_ROWAXIS;
+    maDefModel.mbShowError           = getFlag( nFlags2, BIFF12_PTDEF_SHOWERROR );
+    maDefModel.mbShowMissing         = getFlag( nFlags2, BIFF12_PTDEF_SHOWMISSING );
+    maDefModel.mbShowItems           = getFlag( nFlags1, BIFF12_PTDEF_SHOWITEMS );
+    maDefModel.mbDisableFieldList    = getFlag( nFlags1, BIFF12_PTDEF_DISABLEFIELDLIST );
+    maDefModel.mbShowCalcMembers     = !getFlag( nFlags1, BIFF12_PTDEF_HIDECALCMEMBERS );
+    maDefModel.mbVisualTotals        = !getFlag( nFlags1, BIFF12_PTDEF_WITHHIDDENTOTALS );
+    maDefModel.mbShowDrill           = !getFlag( nFlags1, BIFF12_PTDEF_HIDEDRILL );
+    maDefModel.mbPrintDrill          = getFlag( nFlags1, BIFF12_PTDEF_PRINTDRILL );
+    maDefModel.mbEnableDrill         = getFlag( nFlags2, BIFF12_PTDEF_ENABLEDRILL );
+    maDefModel.mbPreserveFormatting  = getFlag( nFlags2, BIFF12_PTDEF_PRESERVEFORMATTING );
+    maDefModel.mbUseAutoFormat       = getFlag( nFlags2, BIFF12_PTDEF_USEAUTOFORMAT );
+    maDefModel.mbPageOverThenDown    = getFlag( nFlags2, BIFF12_PTDEF_PAGEOVERTHENDOWN );
+    maDefModel.mbSubtotalHiddenItems = getFlag( nFlags2, BIFF12_PTDEF_SUBTOTALHIDDENITEMS );
+    maDefModel.mbRowGrandTotals      = getFlag( nFlags2, BIFF12_PTDEF_ROWGRANDTOTALS );
+    maDefModel.mbColGrandTotals      = getFlag( nFlags2, BIFF12_PTDEF_COLGRANDTOTALS );
+    maDefModel.mbFieldPrintTitles    = getFlag( nFlags2, BIFF12_PTDEF_FIELDPRINTTITLES );
+    maDefModel.mbItemPrintTitles     = getFlag( nFlags2, BIFF12_PTDEF_ITEMPRINTTITLES );
+    maDefModel.mbMergeItem           = getFlag( nFlags2, BIFF12_PTDEF_MERGEITEM );
+    maDefModel.mbApplyNumFmt         = getFlag( nFlags2, BIFF12_PTDEF_APPLYNUMFMT );
+    maDefModel.mbApplyFont           = getFlag( nFlags2, BIFF12_PTDEF_APPLYFONT );
+    maDefModel.mbApplyAlignment      = getFlag( nFlags2, BIFF12_PTDEF_APPLYALIGNMENT );
+    maDefModel.mbApplyBorder         = getFlag( nFlags2, BIFF12_PTDEF_APPLYBORDER );
+    maDefModel.mbApplyFill           = getFlag( nFlags2, BIFF12_PTDEF_APPLYFILL );
+    maDefModel.mbApplyProtection     = getFlag( nFlags2, BIFF12_PTDEF_APPLYPROTECTION );
+    maDefModel.mbShowEmptyRow        = getFlag( nFlags2, BIFF12_PTDEF_SHOWEMPTYROW );
+    maDefModel.mbShowEmptyCol        = getFlag( nFlags2, BIFF12_PTDEF_SHOWEMPTYCOL );
+    maDefModel.mbShowHeaders         = !getFlag( nFlags1, BIFF12_PTDEF_HIDEHEADERS );
+    maDefModel.mbFieldListSortAsc    = getFlag( nFlags3, BIFF12_PTDEF_FIELDLISTSORTASC );
+    maDefModel.mbCustomListSort      = !getFlag( nFlags3, BIFF12_PTDEF_NOCUSTOMLISTSORT );
+}
+
+void PivotTable::importPTLocation( SequenceInputStream& 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( SequenceInputStream& rStrm )
+{
+    importFields( maRowFields, rStrm );
+}
+
+void PivotTable::importPTColFields( SequenceInputStream& rStrm )
+{
+    importFields( maColFields, rStrm );
+}
+
+void PivotTable::importPTPageField( SequenceInputStream& rStrm )
+{
+    PTPageFieldModel aModel;
+    sal_uInt8 nFlags;
+    rStrm >> aModel.mnField >> aModel.mnItem;
+    rStrm.skip( 4 );    // hierarchy
+    rStrm >> nFlags;
+    if( getFlag( nFlags, BIFF12_PTPAGEFIELD_HASNAME ) )
+        rStrm >> aModel.maName;
+    maPageFields.push_back( aModel );
+}
+
+void PivotTable::importPTDataField( SequenceInputStream& 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.setBiffSubtotal( nSubtotal );
+    aModel.setBiffShowDataAs( 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) ? BIFF12_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.setBiffSubtotal( nSubtotal );
+    aModel.setBiffShowDataAs( 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.isEmpty() )
+        {
+            // 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( const PivotCacheField* pCacheField = getCacheField( aIt->mnField  ) )
+                    {
+                        if ( pCacheField-> getGroupBaseField() != -1 )
+                            aIt->mnField = pCacheField-> getGroupBaseField();
+                    }
+                    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_FAIL( "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, rBaseCacheField, orItemNames );
+}
+
+Reference< XDataPilotField > PivotTable::getDataPilotField( const OUString& rFieldName ) const
+{
+    Reference< XDataPilotField > xDPField;
+    if( !rFieldName.isEmpty() && 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, SequenceInputStream& 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/sc/source/filter/oox/pivottablefragment.cxx b/sc/source/filter/oox/pivottablefragment.cxx
new file mode 100644
index 000000000000..76310bfb2a3d
--- /dev/null
+++ b/sc/source/filter/oox/pivottablefragment.cxx
@@ -0,0 +1,322 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "pivottablefragment.hxx"
+
+#include "biffinputstream.hxx"
+#include "pivottablebuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+PivotTableFieldContext::PivotTableFieldContext( WorksheetFragmentBase& rFragment, PivotTableField& rTableField ) :
+    WorksheetContextBase( rFragment ),
+    mrTableField( rTableField )
+{
+}
+
+ContextHandlerRef PivotTableFieldContext::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 PivotTableFieldContext::onStartElement( const AttributeList& rAttribs )
+{
+    if( isRootElement() )
+        mrTableField.importPivotField( rAttribs );
+}
+
+ContextHandlerRef PivotTableFieldContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_PTFIELD:
+            switch( nRecId )
+            {
+                case BIFF12_ID_PTFITEMS:        return this;
+                case BIFF12_ID_AUTOSORTSCOPE:   return this;
+            }
+        break;
+        case BIFF12_ID_PTFITEMS:
+            if( nRecId == BIFF12_ID_PTFITEM ) mrTableField.importPTFItem( rStrm );
+        break;
+        case BIFF12_ID_AUTOSORTSCOPE:
+            if( nRecId == BIFF12_ID_PIVOTAREA ) return this;
+        break;
+        case BIFF12_ID_PIVOTAREA:
+            if( nRecId == BIFF12_ID_PTREFERENCES ) return this;
+        break;
+        case BIFF12_ID_PTREFERENCES:
+            if( nRecId == BIFF12_ID_PTREFERENCE ) { mrTableField.importPTReference( rStrm ); return this; }
+        break;
+        case BIFF12_ID_PTREFERENCE:
+            if( nRecId == BIFF12_ID_PTREFERENCEITEM ) mrTableField.importPTReferenceItem( rStrm );
+        break;
+    }
+    return 0;
+}
+
+void PivotTableFieldContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    if( isRootElement() )
+        mrTableField.importPTField( rStrm );
+}
+
+// ============================================================================
+
+PivotTableFilterContext::PivotTableFilterContext( WorksheetFragmentBase& rFragment, PivotTableFilter& rTableFilter ) :
+    WorksheetContextBase( rFragment ),
+    mrTableFilter( rTableFilter )
+{
+}
+
+ContextHandlerRef PivotTableFilterContext::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 PivotTableFilterContext::onStartElement( const AttributeList& rAttribs )
+{
+    if( isRootElement() )
+        mrTableFilter.importFilter( rAttribs );
+}
+
+ContextHandlerRef PivotTableFilterContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_PTFILTER:
+            if( nRecId == BIFF12_ID_AUTOFILTER ) return this;
+        break;
+        case BIFF12_ID_AUTOFILTER:
+            if( nRecId == BIFF12_ID_FILTERCOLUMN ) return this;
+        break;
+        case BIFF12_ID_FILTERCOLUMN:
+            if( nRecId == BIFF12_ID_TOP10FILTER ) mrTableFilter.importTop10Filter( rStrm );
+        break;
+    }
+    return 0;
+}
+
+void PivotTableFilterContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    if( isRootElement() )
+        mrTableFilter.importPTFilter( rStrm );
+}
+
+// ============================================================================
+
+PivotTableFragment::PivotTableFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    WorksheetFragmentBase( rHelper, rFragmentPath ),
+    mrPivotTable( getPivotTables().createPivotTable() )
+{
+}
+
+ContextHandlerRef PivotTableFragment::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 PivotTableFieldContext( *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 PivotTableFilterContext( *this, mrPivotTable.createTableFilter() );
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef PivotTableFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_PTDEFINITION ) { mrPivotTable.importPTDefinition( rStrm ); return this; }
+        break;
+
+        case BIFF12_ID_PTDEFINITION:
+            switch( nRecId )
+            {
+                case BIFF12_ID_PTLOCATION:      mrPivotTable.importPTLocation( rStrm, getSheetIndex() );    break;
+                case BIFF12_ID_PTFIELDS:        return this;
+                case BIFF12_ID_PTROWFIELDS:     mrPivotTable.importPTRowFields( rStrm );                    break;
+                case BIFF12_ID_PTCOLFIELDS:     mrPivotTable.importPTColFields( rStrm );                    break;
+                case BIFF12_ID_PTPAGEFIELDS:    return this;
+                case BIFF12_ID_PTDATAFIELDS:    return this;
+                case BIFF12_ID_PTFILTERS:       return this;
+            }
+        break;
+
+        case BIFF12_ID_PTFIELDS:
+            if( nRecId == BIFF12_ID_PTFIELD ) return new PivotTableFieldContext( *this, mrPivotTable.createTableField() );
+        break;
+        case BIFF12_ID_PTPAGEFIELDS:
+            if( nRecId == BIFF12_ID_PTPAGEFIELD ) mrPivotTable.importPTPageField( rStrm );
+        break;
+        case BIFF12_ID_PTDATAFIELDS:
+            if( nRecId == BIFF12_ID_PTDATAFIELD ) mrPivotTable.importPTDataField( rStrm );
+        break;
+        case BIFF12_ID_PTFILTERS:
+            if( nRecId == BIFF12_ID_PTFILTER ) return new PivotTableFilterContext( *this, mrPivotTable.createTableFilter() );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* PivotTableFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_AUTOFILTER,         BIFF12_ID_AUTOFILTER + 1        },
+        { BIFF12_ID_AUTOSORTSCOPE,      BIFF12_ID_AUTOSORTSCOPE + 1     },
+        { BIFF12_ID_FILTERCOLUMN,       BIFF12_ID_FILTERCOLUMN + 1      },
+        { BIFF12_ID_PIVOTAREA,          BIFF12_ID_PIVOTAREA + 1         },
+        { BIFF12_ID_PTCOLFIELDS,        BIFF12_ID_PTCOLFIELDS + 1       },
+        { BIFF12_ID_PTDATAFIELD,        BIFF12_ID_PTDATAFIELD + 1       },
+        { BIFF12_ID_PTDATAFIELDS,       BIFF12_ID_PTDATAFIELDS + 1      },
+        { BIFF12_ID_PTDEFINITION,       BIFF12_ID_PTDEFINITION + 35     },
+        { BIFF12_ID_PTFIELD,            BIFF12_ID_PTFIELD + 1           },
+        { BIFF12_ID_PTFIELDS,           BIFF12_ID_PTFIELDS + 1          },
+        { BIFF12_ID_PTFILTER,           BIFF12_ID_PTFILTER + 1          },
+        { BIFF12_ID_PTFILTERS,          BIFF12_ID_PTFILTERS + 1         },
+        { BIFF12_ID_PTFITEM,            BIFF12_ID_PTFITEM - 1           },
+        { BIFF12_ID_PTFITEMS,           BIFF12_ID_PTFITEMS + 1          },
+        { BIFF12_ID_PTLOCATION,         BIFF12_ID_PTLOCATION - 1        },
+        { BIFF12_ID_PTPAGEFIELD,        BIFF12_ID_PTPAGEFIELD + 1       },
+        { BIFF12_ID_PTPAGEFIELDS,       BIFF12_ID_PTPAGEFIELDS + 1      },
+        { BIFF12_ID_PTREFERENCE,        BIFF12_ID_PTREFERENCE + 1       },
+        { BIFF12_ID_PTREFERENCEITEM,    BIFF12_ID_PTREFERENCEITEM + 1   },
+        { BIFF12_ID_PTREFERENCES,       BIFF12_ID_PTREFERENCES + 1      },
+        { BIFF12_ID_PTROWFIELDS,        BIFF12_ID_PTROWFIELDS + 1       },
+        { -1,                           -1                              }
+    };
+    return spRecInfos;
+}
+
+// ============================================================================
+// ============================================================================
+
+BiffPivotTableContext::BiffPivotTableContext( const WorksheetHelper& rHelper ) :
+    BiffWorksheetContextBase( rHelper ),
+    mrPivotTable( getPivotTables().createPivotTable() )
+{
+}
+
+void BiffPivotTableContext::importRecord( BiffInputStream& rStrm )
+{
+    switch( rStrm.getRecId() )
+    {
+        case BIFF_ID_PTDEFINITION:      mrPivotTable.importPTDefinition( rStrm, getSheetIndex() );  break;
+        case BIFF_ID_PTDEFINITION2:     mrPivotTable.importPTDefinition2( rStrm );                  break;
+        case BIFF_ID_PTFIELD:           mrPivotTable.createTableField().importPTField( rStrm );     break;
+        case BIFF_ID_PTROWCOLFIELDS:    mrPivotTable.importPTRowColFields( rStrm );                 break;
+        case BIFF_ID_PTPAGEFIELDS:      mrPivotTable.importPTPageFields( rStrm );                   break;
+        case BIFF_ID_PTDATAFIELD:       mrPivotTable.importPTDataField( rStrm );                    break;
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/querytablebuffer.cxx b/sc/source/filter/oox/querytablebuffer.cxx
new file mode 100644
index 000000000000..63d2ea8f6119
--- /dev/null
+++ b/sc/source/filter/oox/querytablebuffer.cxx
@@ -0,0 +1,393 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "querytablebuffer.hxx"
+
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "connectionsbuffer.hxx"
+#include "defnamesbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt32 BIFF12_QUERYTABLE_HEADERS          = 0x00000001;
+const sal_uInt32 BIFF12_QUERYTABLE_ROWNUMBERS       = 0x00000002;
+const sal_uInt32 BIFF12_QUERYTABLE_DISABLEREFRESH   = 0x00000004;
+const sal_uInt32 BIFF12_QUERYTABLE_BACKGROUND       = 0x00000008;
+const sal_uInt32 BIFF12_QUERYTABLE_FIRSTBACKGROUND  = 0x00000010;
+const sal_uInt32 BIFF12_QUERYTABLE_REFRESHONLOAD    = 0x00000020;
+const sal_uInt32 BIFF12_QUERYTABLE_FILLFORMULAS     = 0x00000100;
+const sal_uInt32 BIFF12_QUERYTABLE_SAVEDATA         = 0x00000200;
+const sal_uInt32 BIFF12_QUERYTABLE_DISABLEEDIT      = 0x00000400;
+const sal_uInt32 BIFF12_QUERYTABLE_PRESERVEFORMAT   = 0x00000800;
+const sal_uInt32 BIFF12_QUERYTABLE_ADJUSTCOLWIDTH   = 0x00001000;
+const sal_uInt32 BIFF12_QUERYTABLE_INTERMEDIATE     = 0x00002000;
+const sal_uInt32 BIFF12_QUERYTABLE_APPLYNUMFMT      = 0x00004000;
+const sal_uInt32 BIFF12_QUERYTABLE_APPLYFONT        = 0x00008000;
+const sal_uInt32 BIFF12_QUERYTABLE_APPLYALIGNMENT   = 0x00010000;
+const sal_uInt32 BIFF12_QUERYTABLE_APPLYBORDER      = 0x00020000;
+const sal_uInt32 BIFF12_QUERYTABLE_APPLYFILL        = 0x00040000;
+const sal_uInt32 BIFF12_QUERYTABLE_APPLYPROTECTION  = 0x00080000;
+
+const sal_uInt16 BIFF_QUERYTABLE_HEADERS            = 0x0001;
+const sal_uInt16 BIFF_QUERYTABLE_ROWNUMBERS         = 0x0002;
+const sal_uInt16 BIFF_QUERYTABLE_DISABLEREFRESH     = 0x0004;
+const sal_uInt16 BIFF_QUERYTABLE_BACKGROUND         = 0x0008;
+const sal_uInt16 BIFF_QUERYTABLE_FIRSTBACKGROUND    = 0x0010;
+const sal_uInt16 BIFF_QUERYTABLE_REFRESHONLOAD      = 0x0020;
+const sal_uInt16 BIFF_QUERYTABLE_DELETEUNUSED       = 0x0040;
+const sal_uInt16 BIFF_QUERYTABLE_FILLFORMULAS       = 0x0080;
+const sal_uInt16 BIFF_QUERYTABLE_ADJUSTCOLWIDTH     = 0x0100;
+const sal_uInt16 BIFF_QUERYTABLE_SAVEDATA           = 0x0200;
+const sal_uInt16 BIFF_QUERYTABLE_DISABLEEDIT        = 0x0400;
+const sal_uInt16 BIFF_QUERYTABLE_OVERWRITEEXISTING  = 0x2000;
+
+const sal_uInt16 BIFF_QUERYTABLE_APPLYNUMFMT        = 0x0001;
+const sal_uInt16 BIFF_QUERYTABLE_APPLYFONT          = 0x0002;
+const sal_uInt16 BIFF_QUERYTABLE_APPLYALIGNMENT     = 0x0004;
+const sal_uInt16 BIFF_QUERYTABLE_APPLYBORDER        = 0x0008;
+const sal_uInt16 BIFF_QUERYTABLE_APPLYFILL          = 0x0010;
+const sal_uInt16 BIFF_QUERYTABLE_APPLYPROTECTION    = 0x0020;
+
+const sal_uInt32 BIFF_QTREFRESH_PRESERVEFORMAT      = 0x00000001;
+const sal_uInt32 BIFF_QTREFRESH_ADJUSTCOLWIDTH      = 0x00000002;
+
+// ----------------------------------------------------------------------------
+
+void lclAppendWebQueryTableName( OUStringBuffer& rTables, const OUString& rTableName )
+{
+    if( !rTableName.isEmpty() )
+    {
+        if( rTables.getLength() > 0 )
+            rTables.append( sal_Unicode( ';' ) );
+        rTables.appendAscii( RTL_CONSTASCII_STRINGPARAM( "HTML__" ) ).append( rTableName );
+    }
+}
+
+void lclAppendWebQueryTableIndex( OUStringBuffer& rTables, sal_Int32 nTableIndex )
+{
+    if( nTableIndex > 0 )
+    {
+        if( rTables.getLength() > 0 )
+            rTables.append( sal_Unicode( ';' ) );
+        rTables.appendAscii( RTL_CONSTASCII_STRINGPARAM( "HTML_" ) ).append( nTableIndex );
+    }
+}
+
+OUString lclBuildWebQueryTables( const WebPrModel::TablesVector& rTables )
+{
+    if( rTables.empty() )
+        return CREATE_OUSTRING( "HTML_tables" );
+
+    OUStringBuffer aTables;
+    for( WebPrModel::TablesVector::const_iterator aIt = rTables.begin(), aEnd = rTables.end(); aIt != aEnd; ++aIt )
+    {
+        if( aIt->has< OUString >() )
+            lclAppendWebQueryTableName( aTables, aIt->get< OUString >() );
+        else if( aIt->has< sal_Int32 >() )
+            lclAppendWebQueryTableIndex( aTables, aIt->get< sal_Int32 >() );
+    }
+    return aTables.makeStringAndClear();
+}
+
+Reference< XAreaLink > lclFindAreaLink(
+        const Reference< XAreaLinks >& rxAreaLinks, const CellAddress& rDestPos,
+        const OUString& rFileUrl, const OUString& rTables, const OUString& rFilterName, const OUString& rFilterOptions )
+{
+    try
+    {
+        Reference< XEnumerationAccess > xAreaLinksEA( rxAreaLinks, UNO_QUERY_THROW );
+        Reference< XEnumeration > xAreaLinksEnum( xAreaLinksEA->createEnumeration(), UNO_SET_THROW );
+        while( xAreaLinksEnum->hasMoreElements() )
+        {
+            Reference< XAreaLink > xAreaLink( xAreaLinksEnum->nextElement(), UNO_QUERY_THROW );
+            PropertySet aPropSet( xAreaLink );
+            CellRangeAddress aDestArea = xAreaLink->getDestArea();
+            OUString aString;
+            if( (rDestPos.Sheet == aDestArea.Sheet) && (rDestPos.Column == aDestArea.StartColumn) && (rDestPos.Row == aDestArea.StartRow) &&
+                    (rTables == xAreaLink->getSourceArea()) &&
+                    aPropSet.getProperty( aString, PROP_Url ) && (rFileUrl == aString) &&
+                    aPropSet.getProperty( aString, PROP_Filter ) && (rFilterName == aString) &&
+                    aPropSet.getProperty( aString, PROP_FilterOptions ) && (rFilterOptions == aString) )
+                return xAreaLink;
+        }
+    }
+    catch( Exception& )
+    {
+    }
+    return Reference< XAreaLink >();
+}
+
+} // namespace
+
+// ============================================================================
+
+QueryTableModel::QueryTableModel() :
+    mnConnId( -1 ),
+    mnGrowShrinkType( XML_insertDelete ),
+    mbHeaders( true ),
+    mbRowNumbers( false ),
+    mbDisableRefresh( false ),
+    mbBackground( true ),
+    mbFirstBackground( false ),
+    mbRefreshOnLoad( false ),
+    mbFillFormulas( false ),
+    mbRemoveDataOnSave( false ),
+    mbDisableEdit( false ),
+    mbPreserveFormat( true ),
+    mbAdjustColWidth( true ),
+    mbIntermediate( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+QueryTable::QueryTable( const WorksheetHelper& rHelper ) :
+    WorksheetHelper( rHelper )
+{
+}
+
+void QueryTable::importQueryTable( const AttributeList& rAttribs )
+{
+    maModel.maDefName          = rAttribs.getXString( XML_name, OUString() );
+    maModel.mnConnId           = rAttribs.getInteger( XML_connectionId, -1 );
+    maModel.mnGrowShrinkType   = rAttribs.getToken( XML_growShrinkType, XML_insertDelete );
+    maModel.mnAutoFormatId     = rAttribs.getInteger( XML_autoFormatId, 0 );
+    maModel.mbHeaders          = rAttribs.getBool( XML_headers, true );
+    maModel.mbRowNumbers       = rAttribs.getBool( XML_rowNumbers, false );
+    maModel.mbDisableRefresh   = rAttribs.getBool( XML_disableRefresh, false );
+    maModel.mbBackground       = rAttribs.getBool( XML_backgroundRefresh, true );
+    maModel.mbFirstBackground  = rAttribs.getBool( XML_firstBackgroundRefresh, false );
+    maModel.mbRefreshOnLoad    = rAttribs.getBool( XML_refreshOnLoad, false );
+    maModel.mbFillFormulas     = rAttribs.getBool( XML_fillFormulas, false );
+    maModel.mbRemoveDataOnSave = rAttribs.getBool( XML_removeDataOnSave, false );
+    maModel.mbDisableEdit      = rAttribs.getBool( XML_disableEdit, false );
+    maModel.mbPreserveFormat   = rAttribs.getBool( XML_preserveFormatting, true );
+    maModel.mbAdjustColWidth   = rAttribs.getBool( XML_adjustColumnWidth, true );
+    maModel.mbIntermediate     = rAttribs.getBool( XML_intermediate, false );
+    maModel.mbApplyNumFmt      = rAttribs.getBool( XML_applyNumberFormats, false );
+    maModel.mbApplyFont        = rAttribs.getBool( XML_applyFontFormats, false );
+    maModel.mbApplyAlignment   = rAttribs.getBool( XML_applyAlignmentFormats, false );
+    maModel.mbApplyBorder      = rAttribs.getBool( XML_applyBorderFormats, false );
+    maModel.mbApplyFill        = rAttribs.getBool( XML_applyPatternFormats, false );
+    // OOXML and BIFF12 documentation differ: OOXML mentions width/height, BIFF12 mentions protection
+    maModel.mbApplyProtection  = rAttribs.getBool( XML_applyWidthHeightFormats, false );
+}
+
+void QueryTable::importQueryTable( SequenceInputStream& rStrm )
+{
+    sal_uInt32 nFlags;
+    rStrm >> nFlags;
+    maModel.mnAutoFormatId = rStrm.readuInt16();
+    rStrm >> maModel.mnConnId >> maModel.maDefName;
+
+    static const sal_Int32 spnGrowShrinkTypes[] = { XML_insertClear, XML_insertDelete, XML_overwriteClear };
+    maModel.mnGrowShrinkType = STATIC_ARRAY_SELECT( spnGrowShrinkTypes, extractValue< sal_uInt8 >( nFlags, 6, 2 ), XML_insertDelete );
+
+    maModel.mbHeaders           = getFlag( nFlags, BIFF12_QUERYTABLE_HEADERS );
+    maModel.mbRowNumbers        = getFlag( nFlags, BIFF12_QUERYTABLE_ROWNUMBERS );
+    maModel.mbDisableRefresh    = getFlag( nFlags, BIFF12_QUERYTABLE_DISABLEREFRESH );
+    maModel.mbBackground        = getFlag( nFlags, BIFF12_QUERYTABLE_BACKGROUND );
+    maModel.mbFirstBackground   = getFlag( nFlags, BIFF12_QUERYTABLE_FIRSTBACKGROUND );
+    maModel.mbRefreshOnLoad     = getFlag( nFlags, BIFF12_QUERYTABLE_REFRESHONLOAD );
+    maModel.mbFillFormulas      = getFlag( nFlags, BIFF12_QUERYTABLE_FILLFORMULAS );
+    maModel.mbRemoveDataOnSave  = !getFlag( nFlags, BIFF12_QUERYTABLE_SAVEDATA ); // flag negated in BIFF12
+    maModel.mbDisableEdit       = getFlag( nFlags, BIFF12_QUERYTABLE_DISABLEEDIT );
+    maModel.mbPreserveFormat    = getFlag( nFlags, BIFF12_QUERYTABLE_PRESERVEFORMAT );
+    maModel.mbAdjustColWidth    = getFlag( nFlags, BIFF12_QUERYTABLE_ADJUSTCOLWIDTH );
+    maModel.mbIntermediate      = getFlag( nFlags, BIFF12_QUERYTABLE_INTERMEDIATE );
+    maModel.mbApplyNumFmt       = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYNUMFMT );
+    maModel.mbApplyFont         = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYFONT );
+    maModel.mbApplyAlignment    = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYALIGNMENT );
+    maModel.mbApplyBorder       = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYBORDER );
+    maModel.mbApplyFill         = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYFILL );
+    maModel.mbApplyProtection   = getFlag( nFlags, BIFF12_QUERYTABLE_APPLYPROTECTION );
+}
+
+void QueryTable::importQueryTable( BiffInputStream& rStrm )
+{
+    sal_uInt16 nFlags, nAutoFormatFlags;
+    rStrm >> nFlags;
+    maModel.mnAutoFormatId = rStrm.readuInt16();
+    rStrm >> nAutoFormatFlags;
+    rStrm.skip( 4 );
+    maModel.maDefName = rStrm.readUniString();
+
+    bool bDeleteUnused = getFlag( nFlags, BIFF_QUERYTABLE_DELETEUNUSED );
+    bool bOverwriteExisting = getFlag( nFlags, BIFF_QUERYTABLE_OVERWRITEEXISTING );
+    OSL_ENSURE( !bDeleteUnused || !bOverwriteExisting, "QueryTable::importQueryTable - invalid flags" );
+    maModel.mnGrowShrinkType = bDeleteUnused ? XML_insertDelete : (bOverwriteExisting ? XML_overwriteClear : XML_insertClear);
+
+    maModel.mbHeaders           = getFlag( nFlags, BIFF_QUERYTABLE_HEADERS );
+    maModel.mbRowNumbers        = getFlag( nFlags, BIFF_QUERYTABLE_ROWNUMBERS );
+    maModel.mbDisableRefresh    = getFlag( nFlags, BIFF_QUERYTABLE_DISABLEREFRESH );
+    maModel.mbBackground        = getFlag( nFlags, BIFF_QUERYTABLE_BACKGROUND );
+    maModel.mbFirstBackground   = getFlag( nFlags, BIFF_QUERYTABLE_FIRSTBACKGROUND );
+    maModel.mbRefreshOnLoad     = getFlag( nFlags, BIFF_QUERYTABLE_REFRESHONLOAD );
+    maModel.mbFillFormulas      = getFlag( nFlags, BIFF_QUERYTABLE_FILLFORMULAS );
+    maModel.mbRemoveDataOnSave  = !getFlag( nFlags, BIFF_QUERYTABLE_SAVEDATA ); // flag negated in BIFF
+    maModel.mbDisableEdit       = getFlag( nFlags, BIFF_QUERYTABLE_DISABLEEDIT );
+    maModel.mbAdjustColWidth    = getFlag( nFlags, BIFF_QUERYTABLE_ADJUSTCOLWIDTH );
+    maModel.mbApplyNumFmt       = getFlag( nAutoFormatFlags, BIFF_QUERYTABLE_APPLYNUMFMT );
+    maModel.mbApplyFont         = getFlag( nAutoFormatFlags, BIFF_QUERYTABLE_APPLYFONT );
+    maModel.mbApplyAlignment    = getFlag( nAutoFormatFlags, BIFF_QUERYTABLE_APPLYALIGNMENT );
+    maModel.mbApplyBorder       = getFlag( nAutoFormatFlags, BIFF_QUERYTABLE_APPLYBORDER );
+    maModel.mbApplyFill         = getFlag( nAutoFormatFlags, BIFF_QUERYTABLE_APPLYFILL );
+    maModel.mbApplyProtection   = getFlag( nAutoFormatFlags, BIFF_QUERYTABLE_APPLYPROTECTION );
+
+    // create a new connection object that will store settings from following records
+    OSL_ENSURE( maModel.mnConnId == -1, "QueryTable::importQueryTable - multiple call" );
+    Connection& rConnection = getConnections().createConnectionWithId();
+    maModel.mnConnId = rConnection.getConnectionId();
+
+    // a DBQUERY record with some PCITEM_STRING records must follow
+    bool bHasDbQuery = (rStrm.getNextRecId() == BIFF_ID_DBQUERY) && rStrm.startNextRecord();
+    OSL_ENSURE( bHasDbQuery, "QueryTable::importQueryTable - missing DBQUERY record" );
+    if( bHasDbQuery )
+        rConnection.importDbQuery( rStrm );
+}
+
+void QueryTable::importQueryTableRefresh( BiffInputStream& rStrm )
+{
+    rStrm.skip( 4 );
+    bool bPivot = rStrm.readuInt16() != 0;
+    OSL_ENSURE( !bPivot, "QueryTable::importQueryTableRefresh - unexpected pivot flag" );
+    if( !bPivot )
+    {
+        rStrm.skip( 2 );
+        sal_uInt32 nFlags = rStrm.readuInt32();
+        maModel.mbPreserveFormat = getFlag( nFlags, BIFF_QTREFRESH_PRESERVEFORMAT );
+        maModel.mbAdjustColWidth = getFlag( nFlags, BIFF_QTREFRESH_ADJUSTCOLWIDTH );
+    }
+}
+
+void QueryTable::importQueryTableSettings( BiffInputStream& rStrm )
+{
+    ConnectionRef xConnection = getConnections().getConnection( maModel.mnConnId );
+    OSL_ENSURE( xConnection.get(), "QueryTable::importQueryTableSettings - missing connection object" );
+    if( xConnection.get() )
+        xConnection->importQueryTableSettings( rStrm );
+}
+
+void QueryTable::finalizeImport()
+{
+    ConnectionRef xConnection = getConnections().getConnection( maModel.mnConnId );
+    OSL_ENSURE( xConnection.get(), "QueryTable::finalizeImport - missing connection object" );
+    if( xConnection.get() && (xConnection->getConnectionType() == BIFF12_CONNECTION_HTML) )
+    {
+        // check that valid web query properties exist
+        const WebPrModel* pWebPr = xConnection->getModel().mxWebPr.get();
+        if( pWebPr && !pWebPr->mbXml )
+        {
+            OUString aFileUrl = getBaseFilter().getAbsoluteUrl( pWebPr->maUrl );
+            if( !aFileUrl.isEmpty() )
+            {
+                // resolve destination cell range (stored as defined name containing the range)
+                OUString aDefName = maModel.maDefName.replace( ' ', '_' ).replace( '-', '_' );
+                DefinedNameRef xDefName = getDefinedNames().getByModelName( aDefName, getSheetIndex() );
+                OSL_ENSURE( xDefName.get(), "QueryTable::finalizeImport - missing defined name" );
+                if( xDefName.get() )
+                {
+                    CellRangeAddress aDestRange;
+                    bool bIsRange = xDefName->getAbsoluteRange( aDestRange ) && (aDestRange.Sheet == getSheetIndex());
+                    OSL_ENSURE( bIsRange, "QueryTable::finalizeImport - defined name does not contain valid cell range" );
+                    if( bIsRange && getAddressConverter().checkCellRange( aDestRange, false, true ) )
+                    {
+                        CellAddress aDestPos( aDestRange.Sheet, aDestRange.StartColumn, aDestRange.StartRow );
+                        // find tables mode: entire document, all tables, or specific tables
+                        OUString aTables = pWebPr->mbHtmlTables ? lclBuildWebQueryTables( pWebPr->maTables ) : CREATE_OUSTRING( "HTML_all" );
+                        if( !aTables.isEmpty() ) try
+                        {
+                            PropertySet aDocProps( getDocument() );
+                            Reference< XAreaLinks > xAreaLinks( aDocProps.getAnyProperty( PROP_AreaLinks ), UNO_QUERY_THROW );
+                            OUString aFilterName = CREATE_OUSTRING( "calc_HTML_WebQuery" );
+                            OUString aFilterOptions;
+                            xAreaLinks->insertAtPosition( aDestPos, aFileUrl, aTables, aFilterName, aFilterOptions );
+                            // set refresh interval (convert minutes to seconds)
+                            sal_Int32 nRefreshPeriod = xConnection->getModel().mnInterval * 60;
+                            if( nRefreshPeriod > 0 )
+                            {
+                                PropertySet aPropSet( lclFindAreaLink( xAreaLinks, aDestPos, aFileUrl, aTables, aFilterName, aFilterOptions ) );
+                                aPropSet.setProperty( PROP_RefreshPeriod, nRefreshPeriod );
+                            }
+                        }
+                        catch( Exception& )
+                        {
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+// ============================================================================
+
+QueryTableBuffer::QueryTableBuffer( const WorksheetHelper& rHelper ) :
+    WorksheetHelper( rHelper )
+{
+}
+
+QueryTable& QueryTableBuffer::createQueryTable()
+{
+    QueryTableVector::value_type xQueryTable( new QueryTable( *this ) );
+    maQueryTables.push_back( xQueryTable );
+    return *xQueryTable;
+}
+
+void QueryTableBuffer::finalizeImport()
+{
+    maQueryTables.forEachMem( &QueryTable::finalizeImport );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/querytablefragment.cxx b/sc/source/filter/oox/querytablefragment.cxx
new file mode 100644
index 000000000000..ad4ca130f062
--- /dev/null
+++ b/sc/source/filter/oox/querytablefragment.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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "querytablefragment.hxx"
+
+#include "biffinputstream.hxx"
+#include "querytablebuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+QueryTableFragment::QueryTableFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    WorksheetFragmentBase( rHelper, rFragmentPath ),
+    mrQueryTable( getQueryTables().createQueryTable() )
+{
+}
+
+ContextHandlerRef QueryTableFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nElement == XLS_TOKEN( queryTable ) )
+                mrQueryTable.importQueryTable( rAttribs );
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef QueryTableFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_QUERYTABLE )
+                mrQueryTable.importQueryTable( rStrm );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* QueryTableFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_QUERYTABLE,         BIFF12_ID_QUERYTABLE + 1        },
+        { BIFF12_ID_QUERYTABLEREFRESH,  BIFF12_ID_QUERYTABLEREFRESH + 1 },
+        { -1,                           -1                              }
+    };
+    return spRecInfos;
+}
+
+// ============================================================================
+
+BiffQueryTableContext::BiffQueryTableContext( const WorksheetHelper& rHelper ) :
+    BiffWorksheetContextBase( rHelper ),
+    mrQueryTable( getQueryTables().createQueryTable() )
+{
+}
+
+void BiffQueryTableContext::importRecord( BiffInputStream& rStrm )
+{
+    switch( rStrm.getRecId() )
+    {
+        case BIFF_ID_QUERYTABLE:            mrQueryTable.importQueryTable( rStrm );         break;
+        case BIFF_ID_QUERYTABLEREFRESH:     mrQueryTable.importQueryTableRefresh( rStrm );  break;
+        case BIFF_ID_QUERYTABLESETTINGS:    mrQueryTable.importQueryTableSettings( rStrm ); break;
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/richstring.cxx b/sc/source/filter/oox/richstring.cxx
new file mode 100644
index 000000000000..28c0d0cb1827
--- /dev/null
+++ b/sc/source/filter/oox/richstring.cxx
@@ -0,0 +1,668 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "richstring.hxx"
+
+#include 
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt8 BIFF12_STRINGFLAG_FONTS         = 0x01;
+const sal_uInt8 BIFF12_STRINGFLAG_PHONETICS     = 0x02;
+
+inline bool lclNeedsRichTextFormat( const Font* pFont )
+{
+    return pFont && pFont->needsRichTextFormat();
+}
+
+} // 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, const Font* pFont, bool bReplace )
+{
+    Reference< XTextRange > xRange;
+    if( bReplace )
+        xRange.set( rxText, UNO_QUERY );
+    else
+        xRange = rxText->getEnd();
+    OSL_ENSURE( xRange.is(), "RichStringPortion::convert - cannot get text range interface" );
+
+    if( xRange.is() )
+    {
+        xRange->setString( maText );
+        if( mxFont.get() )
+        {
+            PropertySet aPropSet( xRange );
+            mxFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
+        }
+
+        /*  Some font attributes cannot be set to cell formatting in Calc but
+            require to use rich formatting, e.g. font escapement. But do not
+            use the passed font if this portion has its own font. */
+        else if( lclNeedsRichTextFormat( pFont ) )
+        {
+            PropertySet aPropSet( xRange );
+            pFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
+        }
+    }
+}
+
+void RichStringPortion::writeFontProperties( const Reference& rxText, const Font* pFont ) const
+{
+    PropertySet aPropSet(rxText);
+
+    if (mxFont.get())
+        mxFont->writeToPropertySet(aPropSet, FONT_PROPTYPE_TEXT);
+
+    if (lclNeedsRichTextFormat(pFont))
+        pFont->writeToPropertySet(aPropSet, FONT_PROPTYPE_TEXT);
+}
+
+// ----------------------------------------------------------------------------
+
+void FontPortionModel::read( SequenceInputStream& 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( SequenceInputStream& 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::setBiffData( 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( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFontId;
+    sal_Int32 nType, nAlignment;
+    rStrm >> nFontId >> nType >> nAlignment;
+    maModel.mnFontId = nFontId;
+    maModel.setBiffData( nType, nAlignment );
+}
+
+void PhoneticSettings::importPhoneticPr( BiffInputStream& rStrm )
+{
+    sal_uInt16 nFontId, nFlags;
+    rStrm >> nFontId >> nFlags;
+    maModel.mnFontId = nFontId;
+    maModel.setBiffData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) );
+    // following: range list with cells showing phonetic text
+}
+
+void PhoneticSettings::importStringData( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFontId, nFlags;
+    rStrm >> nFontId >> nFlags;
+    maModel.mnFontId = nFontId;
+    maModel.setBiffData( 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.setBiffData( 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( SequenceInputStream& 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( SequenceInputStream& 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( SequenceInputStream& rStrm, bool bRich )
+{
+    sal_uInt8 nFlags = bRich ? rStrm.readuInt8() : 0;
+    OUString aBaseText = BiffHelper::readString( rStrm );
+
+    if( !rStrm.isEof() && getFlag( nFlags, BIFF12_STRINGFLAG_FONTS ) )
+    {
+        FontPortionModelList aPortions;
+        aPortions.importPortions( rStrm );
+        createTextPortions( aBaseText, aPortions );
+    }
+    else
+    {
+        createPortion()->setText( aBaseText );
+    }
+
+    if( !rStrm.isEof() && getFlag( nFlags, BIFF12_STRINGFLAG_PHONETICS ) )
+    {
+        OUString aPhoneticText = BiffHelper::readString( rStrm );
+        PhoneticPortionModelList aPortions;
+        aPortions.importPortions( rStrm );
+        maPhonSettings.importStringData( rStrm );
+        createPhoneticPortions( aPhoneticText, aPortions, aBaseText.getLength() );
+    }
+}
+
+void RichString::importCharArray( BiffInputStream& rStrm, sal_uInt16 nChars, rtl_TextEncoding eTextEnc )
+{
+    createPortion()->setText( rStrm.readCharArrayUC( nChars, eTextEnc ) );
+}
+
+void RichString::importByteString( BiffInputStream& rStrm, rtl_TextEncoding eTextEnc, 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 );
+        createTextPortions( aBaseText, eTextEnc, aPortions );
+    }
+    else
+    {
+        createPortion()->setText( OStringToOUString( aBaseText, eTextEnc ) );
+    }
+}
+
+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 );
+        createTextPortions( 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()
+{
+    maTextPortions.forEachMem( &RichStringPortion::finalizeImport );
+}
+
+bool RichString::extractPlainString( OUString& orString, const Font* pFirstPortionFont ) const
+{
+    if( !maPhonPortions.empty() )
+        return false;
+    if( maTextPortions.empty() )
+    {
+        orString = OUString();
+        return true;
+    }
+    if( (maTextPortions.size() == 1) && !maTextPortions.front()->hasFont() && !lclNeedsRichTextFormat( pFirstPortionFont ) )
+    {
+        orString = maTextPortions.front()->getText();
+        return orString.indexOf( '\x0A' ) < 0;
+    }
+    return false;
+}
+
+void RichString::convert( const Reference< XText >& rxText, bool bReplaceOld, const Font* pFirstPortionFont ) const
+{
+    if (maTextPortions.size() == 1)
+    {
+        // Set text directly to the cell when the string has only one portion.
+        // It's much faster this way.
+        RichStringPortion& rPtn = *maTextPortions.front();
+        rxText->setString(rPtn.getText());
+        rPtn.writeFontProperties(rxText, pFirstPortionFont);
+        return;
+    }
+
+    for( PortionVector::const_iterator aIt = maTextPortions.begin(), aEnd = maTextPortions.end(); aIt != aEnd; ++aIt )
+    {
+        (*aIt)->convert( rxText, pFirstPortionFont, bReplaceOld );
+        pFirstPortionFont = 0;  // use passed font for first portion only
+        bReplaceOld = false;    // do not replace first portion text with following portions
+    }
+}
+
+// private --------------------------------------------------------------------
+
+RichStringPortionRef RichString::createPortion()
+{
+    RichStringPortionRef xPortion( new RichStringPortion( *this ) );
+    maTextPortions.push_back( xPortion );
+    return xPortion;
+}
+
+RichStringPhoneticRef RichString::createPhonetic()
+{
+    RichStringPhoneticRef xPhonetic( new RichStringPhonetic( *this ) );
+    maPhonPortions.push_back( xPhonetic );
+    return xPhonetic;
+}
+
+void RichString::createTextPortions( const OString& rText, rtl_TextEncoding eTextEnc, FontPortionModelList& rPortions )
+{
+    maTextPortions.clear();
+    if( !rText.isEmpty())
+    {
+        sal_Int32 nStrLen = rText.getLength();
+        // 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 eFontEnc = xFont.get() ? xFont->getFontEncoding() : eTextEnc;
+                OUString aUniStr = OStringToOUString( rText.copy( aIt->mnPos, nPortionLen ), eFontEnc );
+                // create string portion
+                RichStringPortionRef xPortion = createPortion();
+                xPortion->setText( aUniStr );
+                xPortion->setFontId( aIt->mnFontId );
+            }
+        }
+    }
+}
+
+void RichString::createTextPortions( const OUString& rText, FontPortionModelList& rPortions )
+{
+    maTextPortions.clear();
+    if( !rText.isEmpty() )
+    {
+         sal_Int32 nStrLen = rText.getLength();
+        // 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();
+    if( !rText.isEmpty())
+    {
+        sal_Int32 nStrLen = rText.getLength();
+        // 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/sc/source/filter/oox/richstringcontext.cxx b/sc/source/filter/oox/richstringcontext.cxx
new file mode 100644
index 000000000000..0443ff1fc5c3
--- /dev/null
+++ b/sc/source/filter/oox/richstringcontext.cxx
@@ -0,0 +1,108 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "richstringcontext.hxx"
+
+#include "stylesfragment.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using ::oox::core::ContextHandlerRef;
+using ::rtl::OUString;
+
+// ============================================================================
+
+ContextHandlerRef RichStringContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    if( isRootElement() )
+    {
+        switch( nElement )
+        {
+            case XLS_TOKEN( t ):
+                mxPortion = mxString->importText( rAttribs );
+                return this;    // collect text in onCharacters()
+            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 FontContext( *this, mxPortion->createFont() );
+                break;
+
+                case XLS_TOKEN( t ):
+                    return this;    // collect portion text in onCharacters()
+            }
+        break;
+
+        case XLS_TOKEN( rPh ):
+            switch( nElement )
+            {
+                case XLS_TOKEN( t ):
+                    return this;    // collect phonetic text in onCharacters()
+            }
+        break;
+    }
+    return 0;
+}
+
+void RichStringContext::onCharacters( const OUString& rChars )
+{
+    if( isCurrentElement( XLS_TOKEN( t ) ) ) switch( getParentElement() )
+    {
+        case XLS_TOKEN( rPh ):
+            if( mxPhonetic.get() )
+                mxPhonetic->setText( rChars );
+        break;
+        default:
+            if( mxPortion.get() )
+                mxPortion->setText( rChars );
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/scenariobuffer.cxx b/sc/source/filter/oox/scenariobuffer.cxx
new file mode 100644
index 000000000000..0309bb6460e9
--- /dev/null
+++ b/sc/source/filter/oox/scenariobuffer.cxx
@@ -0,0 +1,302 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "scenariobuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+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( SequenceInputStream& 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( SequenceInputStream& 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.isEmpty() ) 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( SequenceInputStream& 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/sc/source/filter/oox/scenariocontext.cxx b/sc/source/filter/oox/scenariocontext.cxx
new file mode 100644
index 000000000000..5c1c76d967eb
--- /dev/null
+++ b/sc/source/filter/oox/scenariocontext.cxx
@@ -0,0 +1,129 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "scenariocontext.hxx"
+
+#include "scenariobuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using ::oox::core::ContextHandlerRef;
+
+// ============================================================================
+
+ScenarioContext::ScenarioContext( WorksheetContextBase& rParent, SheetScenarios& rSheetScenarios ) :
+    WorksheetContextBase( rParent ),
+    mrScenario( rSheetScenarios.createScenario() )
+{
+}
+
+ContextHandlerRef ScenarioContext::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 ScenarioContext::onStartElement( const AttributeList& rAttribs )
+{
+    if( isRootElement() )
+        mrScenario.importScenario( rAttribs );
+}
+
+ContextHandlerRef ScenarioContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_SCENARIO:
+            if( nRecId == BIFF12_ID_INPUTCELLS ) mrScenario.importInputCells( rStrm );
+        break;
+    }
+    return 0;
+}
+
+void ScenarioContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    if( isRootElement() )
+        mrScenario.importScenario( rStrm );
+}
+
+// ============================================================================
+
+ScenariosContext::ScenariosContext( WorksheetFragmentBase& rFragment ) :
+    WorksheetContextBase( rFragment ),
+    mrSheetScenarios( getScenarios().createSheetScenarios( getSheetIndex() ) )
+{
+}
+
+ContextHandlerRef ScenariosContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
+{
+    switch( getCurrentElement() )
+    {
+        case XLS_TOKEN( scenarios ):
+            if( nElement == XLS_TOKEN( scenario ) ) return new ScenarioContext( *this, mrSheetScenarios );
+        break;
+    }
+    return 0;
+}
+
+void ScenariosContext::onStartElement( const AttributeList& rAttribs )
+{
+    if( isRootElement() )
+        mrSheetScenarios.importScenarios( rAttribs );
+}
+
+ContextHandlerRef ScenariosContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_SCENARIOS:
+            if( nRecId == BIFF12_ID_SCENARIO ) return new ScenarioContext( *this, mrSheetScenarios );
+        break;
+    }
+    return 0;
+}
+
+void ScenariosContext::onStartRecord( SequenceInputStream& rStrm )
+{
+    if( isRootElement() )
+        mrSheetScenarios.importScenarios( rStrm );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/sharedformulabuffer.cxx b/sc/source/filter/oox/sharedformulabuffer.cxx
new file mode 100644
index 000000000000..9646534ac207
--- /dev/null
+++ b/sc/source/filter/oox/sharedformulabuffer.cxx
@@ -0,0 +1,213 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include 
+#include 
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "formulaparser.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+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( SequenceInputStream& 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/sc/source/filter/oox/sharedstringsbuffer.cxx b/sc/source/filter/oox/sharedstringsbuffer.cxx
new file mode 100644
index 000000000000..c71172f4a9a9
--- /dev/null
+++ b/sc/source/filter/oox/sharedstringsbuffer.cxx
@@ -0,0 +1,87 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "sharedstringsbuffer.hxx"
+
+#include "biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+
+// ============================================================================
+
+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 );
+}
+
+RichStringRef SharedStringsBuffer::getString( sal_Int32 nStringId ) const
+{
+    return maStrings.get( nStringId );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/sharedstringsfragment.cxx b/sc/source/filter/oox/sharedstringsfragment.cxx
new file mode 100644
index 000000000000..0be8837935bc
--- /dev/null
+++ b/sc/source/filter/oox/sharedstringsfragment.cxx
@@ -0,0 +1,105 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "sharedstringsfragment.hxx"
+
+#include "richstringcontext.hxx"
+#include "sharedstringsbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+SharedStringsFragment::SharedStringsFragment(
+        const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+    WorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+ContextHandlerRef SharedStringsFragment::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 RichStringContext( *this, getSharedStrings().createRichString() );
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef SharedStringsFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_SST )
+                return this;
+        break;
+
+        case BIFF12_ID_SST:
+            if( nRecId == BIFF12_ID_SI )
+                getSharedStrings().createRichString()->importString( rStrm, true );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* SharedStringsFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_SST,    BIFF12_ID_SST + 1   },
+        { -1,               -1                  }
+    };
+    return spRecInfos;
+}
+
+void SharedStringsFragment::finalizeImport()
+{
+    getSharedStrings().finalizeImport();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/sheetdatabuffer.cxx b/sc/source/filter/oox/sheetdatabuffer.cxx
new file mode 100644
index 000000000000..fbae5b15aa97
--- /dev/null
+++ b/sc/source/filter/oox/sheetdatabuffer.cxx
@@ -0,0 +1,897 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "sheetdatabuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertymap.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/token/tokens.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "formulaparser.hxx"
+#include "sharedstringsbuffer.hxx"
+#include "unitconverter.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+CellModel::CellModel() :
+    mnCellType( XML_TOKEN_INVALID ),
+    mnXfId( -1 ),
+    mbShowPhonetic( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+CellFormulaModel::CellFormulaModel() :
+    mnFormulaType( XML_TOKEN_INVALID ),
+    mnSharedId( -1 )
+{
+}
+
+bool CellFormulaModel::isValidArrayRef( const CellAddress& rCellAddr )
+{
+    return
+        (maFormulaRef.Sheet == rCellAddr.Sheet) &&
+        (maFormulaRef.StartColumn == rCellAddr.Column) &&
+        (maFormulaRef.StartRow == rCellAddr.Row);
+}
+
+bool CellFormulaModel::isValidSharedRef( const CellAddress& rCellAddr )
+{
+    return
+        (maFormulaRef.Sheet == rCellAddr.Sheet) &&
+        (maFormulaRef.StartColumn <= rCellAddr.Column) && (rCellAddr.Column <= maFormulaRef.EndColumn) &&
+        (maFormulaRef.StartRow <= rCellAddr.Row) && (rCellAddr.Row <= maFormulaRef.EndRow);
+}
+
+// ----------------------------------------------------------------------------
+
+DataTableModel::DataTableModel() :
+    mb2dTable( false ),
+    mbRowTable( false ),
+    mbRef1Deleted( false ),
+    mbRef2Deleted( false )
+{
+}
+
+// ============================================================================
+
+namespace {
+
+const sal_Int32 CELLBLOCK_MAXROWS  = 16;    /// Number of rows in a cell block.
+
+} // namespace
+
+CellBlock::CellBlock( const WorksheetHelper& rHelper, const ValueRange& rColSpan, sal_Int32 nRow ) :
+    WorksheetHelper( rHelper ),
+    maRange( rHelper.getSheetIndex(), rColSpan.mnFirst, nRow, rColSpan.mnLast, nRow ),
+    mnRowLength( rColSpan.mnLast - rColSpan.mnFirst + 1 ),
+    mnFirstFreeIndex( 0 )
+{
+    maCellArray.realloc( 1 );
+    maCellArray[ 0 ].realloc( mnRowLength );
+    mpCurrCellRow = maCellArray[ 0 ].getArray();
+}
+
+bool CellBlock::isExpandable( const ValueRange& rColSpan ) const
+{
+    return (maRange.StartColumn == rColSpan.mnFirst) && (maRange.EndColumn == rColSpan.mnLast);
+}
+
+bool CellBlock::isBefore( const ValueRange& rColSpan ) const
+{
+    return (maRange.EndColumn < rColSpan.mnLast) ||
+        ((maRange.EndColumn == rColSpan.mnLast) && (maRange.StartColumn != rColSpan.mnFirst));
+}
+
+bool CellBlock::contains( sal_Int32 nCol ) const
+{
+    return (maRange.StartColumn <= nCol) && (nCol <= maRange.EndColumn);
+}
+
+void CellBlock::insertRichString( const CellAddress& rAddress, const RichStringRef& rxString, const Font* pFirstPortionFont )
+{
+    maRichStrings.push_back( RichStringCell( rAddress, rxString, pFirstPortionFont ) );
+}
+
+void CellBlock::startNextRow()
+{
+    // fill last cells in current row with empty strings (placeholder for empty cells)
+    fillUnusedCells( mnRowLength );
+    // flush if the cell block reaches maximum size
+    if( maCellArray.getLength() == CELLBLOCK_MAXROWS )
+    {
+        finalizeImport();
+        maRange.StartRow = ++maRange.EndRow;
+        maCellArray.realloc( 1 );
+        mpCurrCellRow = maCellArray[ 0 ].getArray();
+    }
+    else
+    {
+        // prepare next row
+        ++maRange.EndRow;
+        sal_Int32 nRowCount = maCellArray.getLength();
+        maCellArray.realloc( nRowCount + 1 );
+        maCellArray[ nRowCount ].realloc( mnRowLength );
+        mpCurrCellRow = maCellArray[ nRowCount ].getArray();
+    }
+    mnFirstFreeIndex = 0;
+}
+
+Any& CellBlock::getCellAny( sal_Int32 nCol )
+{
+    OSL_ENSURE( contains( nCol ), "CellBlock::getCellAny - invalid column" );
+    // fill cells before passed column with empty strings (the placeholder for empty cells)
+    sal_Int32 nIndex = nCol - maRange.StartColumn;
+    fillUnusedCells( nIndex );
+    mnFirstFreeIndex = nIndex + 1;
+    return mpCurrCellRow[ nIndex ];
+}
+
+void CellBlock::finalizeImport()
+{
+    // fill last cells in last row with empty strings (placeholder for empty cells)
+    fillUnusedCells( mnRowLength );
+    // insert all buffered cells into the Calc sheet
+    try
+    {
+        Reference< XCellRangeData > xRangeData( getCellRange( maRange ), UNO_QUERY_THROW );
+        xRangeData->setDataArray( maCellArray );
+    }
+    catch( Exception& )
+    {
+    }
+    // insert uncacheable cells separately
+    for( RichStringCellList::const_iterator aIt = maRichStrings.begin(), aEnd = maRichStrings.end(); aIt != aEnd; ++aIt )
+        putRichString( aIt->maCellAddr, *aIt->mxString, aIt->mpFirstPortionFont );
+}
+
+// private --------------------------------------------------------------------
+
+CellBlock::RichStringCell::RichStringCell( const CellAddress& rCellAddr, const RichStringRef& rxString, const Font* pFirstPortionFont ) :
+    maCellAddr( rCellAddr ),
+    mxString( rxString ),
+    mpFirstPortionFont( pFirstPortionFont )
+{
+}
+
+void CellBlock::fillUnusedCells( sal_Int32 nIndex )
+{
+    if( mnFirstFreeIndex < nIndex )
+    {
+        Any* pCellEnd = mpCurrCellRow + nIndex;
+        for( Any* pCell = mpCurrCellRow + mnFirstFreeIndex; pCell < pCellEnd; ++pCell )
+            *pCell <<= OUString();
+    }
+}
+
+// ============================================================================
+
+CellBlockBuffer::CellBlockBuffer( const WorksheetHelper& rHelper ) :
+    WorksheetHelper( rHelper ),
+    mnCurrRow( -1 )
+{
+    maCellBlockIt = maCellBlocks.end();
+}
+
+void CellBlockBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
+{
+    OSL_ENSURE( maColSpans.count( nRow ) == 0, "CellBlockBuffer::setColSpans - multiple column spans for the same row" );
+    OSL_ENSURE( (mnCurrRow < nRow) && (maColSpans.empty() || (maColSpans.rbegin()->first < nRow)), "CellBlockBuffer::setColSpans - rows are unsorted" );
+    if( (mnCurrRow < nRow) && (maColSpans.count( nRow ) == 0) )
+        maColSpans[ nRow ] = rColSpans.getRanges();
+}
+
+CellBlock* CellBlockBuffer::getCellBlock( const CellAddress& rCellAddr )
+{
+    (void) rCellAddr; // Avoid WaE: unreferenced formal parameter, drop this line
+                      // if the below "temporarily disabled" early return is removed
+
+    // Temporarily disabled. TODO: Fix this.
+    return NULL;
+
+#if 0 // Avoid WaE: unreachable code. Don't remove this ifdeffed out block, see above
+    OSL_ENSURE( rCellAddr.Row >= mnCurrRow, "CellBlockBuffer::getCellBlock - passed row out of order" );
+    // prepare cell blocks, if row changes
+    if( rCellAddr.Row != mnCurrRow )
+    {
+        // find colspans for the new row
+        ColSpanVectorMap::iterator aIt = maColSpans.find( rCellAddr.Row );
+
+        /*  Gap between rows, or rows out of order, or no colspan
+            information for the new row found: flush all open cell blocks. */
+        if( (aIt == maColSpans.end()) || (rCellAddr.Row != mnCurrRow + 1) )
+        {
+            finalizeImport();
+            maCellBlocks.clear();
+            maCellBlockIt = maCellBlocks.end();
+        }
+
+        /*  Prepare matching cell blocks, create new cell blocks, finalize
+            unmatching cell blocks, if colspan information is available. */
+        if( aIt != maColSpans.end() )
+        {
+            /*  The colspan vector aIt points to is sorted by columns, as well
+                as the cell block map. In the folloing, this vector and the
+                list of cell blocks can be iterated simultanously. */
+            CellBlockMap::iterator aMIt = maCellBlocks.begin();
+            const ValueRangeVector& rColRanges = aIt->second;
+            for( ValueRangeVector::const_iterator aVIt = rColRanges.begin(), aVEnd = rColRanges.end(); aVIt != aVEnd; ++aVIt, ++aMIt )
+            {
+                const ValueRange& rColSpan = *aVIt;
+                /*  Finalize and remove all cell blocks up to end of the column
+                    range (cell blocks are keyed by end column index).
+                    CellBlock::isBefore() returns true, if the end index of the
+                    passed colspan is greater than the column end index of the
+                    cell block, or if the passed range has the same end index
+                    but the start indexes do not match. */
+                while( (aMIt != maCellBlocks.end()) && aMIt->second->isBefore( rColSpan ) )
+                {
+                    aMIt->second->finalizeImport();
+                    maCellBlocks.erase( aMIt++ );
+                }
+                /*  If the current cell block (aMIt) fits to the colspan, start
+                    a new row there, otherwise create and insert a new cell block. */
+                if( (aMIt != maCellBlocks.end()) && aMIt->second->isExpandable( rColSpan ) )
+                    aMIt->second->startNextRow();
+                else
+                    aMIt = maCellBlocks.insert( aMIt, CellBlockMap::value_type( rColSpan.mnLast,
+                        CellBlockMap::mapped_type( new CellBlock( *this, rColSpan, rCellAddr.Row ) ) ) );
+            }
+            // finalize and remove all remaining cell blocks
+            CellBlockMap::iterator aMEnd = maCellBlocks.end();
+            for( CellBlockMap::iterator aMIt2 = aMIt; aMIt2 != aMEnd; ++aMIt2 )
+                aMIt2->second->finalizeImport();
+            maCellBlocks.erase( aMIt, aMEnd );
+
+            // remove cached colspan information (including current one aIt points to)
+            maColSpans.erase( maColSpans.begin(), ++aIt );
+        }
+        maCellBlockIt = maCellBlocks.begin();
+        mnCurrRow = rCellAddr.Row;
+    }
+
+    // try to find a valid cell block (update maCellBlockIt)
+    if( ((maCellBlockIt != maCellBlocks.end()) && maCellBlockIt->second->contains( rCellAddr.Column )) ||
+        (((maCellBlockIt = maCellBlocks.lower_bound( rCellAddr.Column )) != maCellBlocks.end()) && maCellBlockIt->second->contains( rCellAddr.Column )) )
+    {
+        // maCellBlockIt points to valid cell block
+        return maCellBlockIt->second.get();
+    }
+
+    // no valid cell block found
+    return 0;
+#endif // See start of method
+}
+
+void CellBlockBuffer::finalizeImport()
+{
+    maCellBlocks.forEachMem( &CellBlock::finalizeImport );
+}
+
+// ============================================================================
+
+SheetDataBuffer::SheetDataBuffer( const WorksheetHelper& rHelper ) :
+    WorksheetHelper( rHelper ),
+    maCellBlocks( rHelper ),
+    mbPendingSharedFmla( false )
+{
+}
+
+void SheetDataBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
+{
+    maCellBlocks.setColSpans( nRow, rColSpans );
+}
+
+void SheetDataBuffer::setBlankCell( const CellModel& rModel )
+{
+    setCellFormat( rModel );
+}
+
+void SheetDataBuffer::setValueCell( const CellModel& rModel, double fValue )
+{
+    if( CellBlock* pCellBlock = maCellBlocks.getCellBlock( rModel.maCellAddr ) )
+        pCellBlock->getCellAny( rModel.maCellAddr.Column ) <<= fValue;
+    else
+        putValue( rModel.maCellAddr, fValue );
+    setCellFormat( rModel );
+}
+
+void SheetDataBuffer::setStringCell( const CellModel& rModel, const OUString& rText )
+{
+    if( CellBlock* pCellBlock = maCellBlocks.getCellBlock( rModel.maCellAddr ) )
+        pCellBlock->getCellAny( rModel.maCellAddr.Column ) <<= rText;
+    else
+        putString( rModel.maCellAddr, rText );
+    setCellFormat( rModel );
+}
+
+void SheetDataBuffer::setStringCell( const CellModel& rModel, const RichStringRef& rxString )
+{
+    OSL_ENSURE( rxString.get(), "SheetDataBuffer::setStringCell - missing rich string object" );
+    const Font* pFirstPortionFont = getStyles().getFontFromCellXf( rModel.mnXfId ).get();
+    OUString aText;
+    if( rxString->extractPlainString( aText, pFirstPortionFont ) )
+    {
+        setStringCell( rModel, aText );
+    }
+    else
+    {
+        if( CellBlock* pCellBlock = maCellBlocks.getCellBlock( rModel.maCellAddr ) )
+            pCellBlock->insertRichString( rModel.maCellAddr, rxString, pFirstPortionFont );
+        else
+            putRichString( rModel.maCellAddr, *rxString, pFirstPortionFont );
+        setCellFormat( rModel );
+    }
+}
+
+void SheetDataBuffer::setStringCell( const CellModel& rModel, sal_Int32 nStringId )
+{
+    RichStringRef xString = getSharedStrings().getString( nStringId );
+    if( xString.get() )
+        setStringCell( rModel, xString );
+    else
+        setBlankCell( rModel );
+}
+
+void SheetDataBuffer::setDateTimeCell( const CellModel& rModel, const DateTime& rDateTime )
+{
+    // write serial date/time value into the cell
+    double fSerial = getUnitConverter().calcSerialFromDateTime( rDateTime );
+    setValueCell( rModel, 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( rModel.maCellAddr, nStdFmt );
+}
+
+void SheetDataBuffer::setBooleanCell( const CellModel& rModel, bool bValue )
+{
+    setCellFormula( rModel.maCellAddr, getFormulaParser().convertBoolToFormula( bValue ) );
+    // #108770# set 'Standard' number format for all Boolean cells
+    setCellFormat( rModel, 0 );
+}
+
+void SheetDataBuffer::setErrorCell( const CellModel& rModel, const OUString& rErrorCode )
+{
+    setErrorCell( rModel, getUnitConverter().calcBiffErrorCode( rErrorCode ) );
+}
+
+void SheetDataBuffer::setErrorCell( const CellModel& rModel, sal_uInt8 nErrorCode )
+{
+    setCellFormula( rModel.maCellAddr, getFormulaParser().convertErrorToFormula( nErrorCode ) );
+    setCellFormat( rModel );
+}
+
+void SheetDataBuffer::setFormulaCell( const CellModel& rModel, const ApiTokenSequence& rTokens )
+{
+    mbPendingSharedFmla = false;
+    ApiTokenSequence aTokens;
+
+    /*  Detect special token passed as placeholder for array formulas, shared
+        formulas, and table operations. In BIFF, these formulas are represented
+        by a single tExp resp. tTbl token. If the formula parser finds these
+        tokens, it puts a single OPCODE_BAD token with the base address and
+        formula type into the token sequence. This information will be
+        extracted here, and in case of a shared formula, the shared formula
+        buffer will generate the resulting formula token array. */
+    ApiSpecialTokenInfo aTokenInfo;
+    if( rTokens.hasElements() && getFormulaParser().extractSpecialTokenInfo( aTokenInfo, rTokens ) )
+    {
+        /*  The second member of the token info is set to true, if the formula
+            represents a table operation, which will be skipped. In BIFF12 it
+            is not possible to distinguish array and shared formulas
+            (BIFF5/BIFF8 provide this information with a special flag in the
+            FORMULA record). */
+        if( !aTokenInfo.Second )
+        {
+            /*  Construct the token array representing the shared formula. If
+                the returned sequence is empty, the definition of the shared
+                formula has not been loaded yet, or the cell is part of an
+                array formula. In this case, the cell will be remembered. After
+                reading the formula definition it will be retried to insert the
+                formula via retryPendingSharedFormulaCell(). */
+            BinAddress aBaseAddr( aTokenInfo.First );
+            aTokens = resolveSharedFormula( aBaseAddr );
+            if( !aTokens.hasElements() )
+            {
+                maSharedFmlaAddr = rModel.maCellAddr;
+                maSharedBaseAddr = aBaseAddr;
+                mbPendingSharedFmla = true;
+            }
+        }
+    }
+    else
+    {
+        // simple formula, use the passed token array
+        aTokens = rTokens;
+    }
+
+    setCellFormula( rModel.maCellAddr, aTokens );
+    setCellFormat( rModel );
+}
+
+void SheetDataBuffer::setFormulaCell( const CellModel& rModel, sal_Int32 nSharedId )
+{
+    setCellFormula( rModel.maCellAddr, resolveSharedFormula( BinAddress( nSharedId, 0 ) ) );
+    setCellFormat( rModel );
+}
+
+void SheetDataBuffer::createArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens )
+{
+    /*  Array formulas will be inserted later in finalizeImport(). This is
+        needed to not disturb collecting all the cells, which will be put into
+        the sheet in large blocks to increase performance. */
+    maArrayFormulas.push_back( ArrayFormula( rRange, rTokens ) );
+}
+
+void SheetDataBuffer::createTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel )
+{
+    /*  Table operations will be inserted later in finalizeImport(). This is
+        needed to not disturb collecting all the cells, which will be put into
+        the sheet in large blocks to increase performance. */
+    maTableOperations.push_back( TableOperation( rRange, rModel ) );
+}
+
+void SheetDataBuffer::createSharedFormula( sal_Int32 nSharedId, const ApiTokenSequence& rTokens )
+{
+    createSharedFormula( BinAddress( nSharedId, 0 ), rTokens );
+}
+
+void SheetDataBuffer::createSharedFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens )
+{
+    createSharedFormula( BinAddress( rCellAddr ), rTokens );
+}
+
+void SheetDataBuffer::setRowFormat( sal_Int32 nRow, sal_Int32 nXfId, bool bCustomFormat )
+{
+    // set row formatting
+    if( bCustomFormat )
+    {
+        // try to expand cached row range, if formatting is equal
+        if( (maXfIdRowRange.maRowRange.mnLast < 0) || !maXfIdRowRange.tryExpand( nRow, nXfId ) )
+        {
+            writeXfIdRowRangeProperties( maXfIdRowRange );
+            maXfIdRowRange.set( nRow, nXfId );
+        }
+    }
+    else if( maXfIdRowRange.maRowRange.mnLast >= 0 )
+    {
+        // finish last cached row range
+        writeXfIdRowRangeProperties( maXfIdRowRange );
+        maXfIdRowRange.set( -1, -1 );
+    }
+}
+
+void SheetDataBuffer::setMergedRange( const CellRangeAddress& rRange )
+{
+    maMergedRanges.push_back( MergedRange( rRange ) );
+}
+
+void SheetDataBuffer::setStandardNumFmt( const CellAddress& rCellAddr, sal_Int16 nStdNumFmt )
+{
+    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( getCell( rCellAddr ) );
+        aPropSet.setProperty( PROP_NumberFormat, nIndex );
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+void SheetDataBuffer::finalizeImport()
+{
+    // insert all cells of all open cell blocks
+    maCellBlocks.finalizeImport();
+
+    // create all array formulas
+    for( ArrayFormulaList::iterator aIt = maArrayFormulas.begin(), aEnd = maArrayFormulas.end(); aIt != aEnd; ++aIt )
+        finalizeArrayFormula( aIt->first, aIt->second );
+
+    // create all table operations
+    for( TableOperationList::iterator aIt = maTableOperations.begin(), aEnd = maTableOperations.end(); aIt != aEnd; ++aIt )
+        finalizeTableOperation( aIt->first, aIt->second );
+
+    // write default formatting of remaining row range
+    writeXfIdRowRangeProperties( maXfIdRowRange );
+
+    for( XfIdRangeListMap::const_iterator aIt = maXfIdRangeLists.begin(), aEnd = maXfIdRangeLists.end(); aIt != aEnd; ++aIt )
+        writeXfIdRangeListProperties( aIt->first.first, aIt->first.second, aIt->second );
+
+    // merge all cached merged ranges and update right/bottom cell borders
+    for( MergedRangeList::iterator aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt )
+        finalizeMergedRange( aIt->maRange );
+    for( MergedRangeList::iterator aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt )
+        finalizeMergedRange( aIt->maRange );
+}
+
+// private --------------------------------------------------------------------
+
+SheetDataBuffer::XfIdRowRange::XfIdRowRange() :
+    maRowRange( -1 ),
+    mnXfId( -1 )
+{
+}
+
+void SheetDataBuffer::XfIdRowRange::set( sal_Int32 nRow, sal_Int32 nXfId )
+{
+    maRowRange = ValueRange( nRow );
+    mnXfId = nXfId;
+}
+
+bool SheetDataBuffer::XfIdRowRange::tryExpand( sal_Int32 nRow, sal_Int32 nXfId )
+{
+    if( mnXfId == nXfId )
+    {
+        if( maRowRange.mnLast + 1 == nRow )
+        {
+            ++maRowRange.mnLast;
+            return true;
+        }
+        if( maRowRange.mnFirst == nRow + 1 )
+        {
+            --maRowRange.mnFirst;
+            return true;
+        }
+    }
+    return false;
+}
+
+
+SheetDataBuffer::MergedRange::MergedRange( const CellRangeAddress& rRange ) :
+    maRange( rRange ),
+    mnHorAlign( XML_TOKEN_INVALID )
+{
+}
+
+SheetDataBuffer::MergedRange::MergedRange( const CellAddress& rAddress, sal_Int32 nHorAlign ) :
+    maRange( rAddress.Sheet, rAddress.Column, rAddress.Row, rAddress.Column, rAddress.Row ),
+    mnHorAlign( nHorAlign )
+{
+}
+
+bool SheetDataBuffer::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 SheetDataBuffer::setCellFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens )
+{
+    if( rTokens.hasElements() )
+    {
+        if( CellBlock* pCellBlock = maCellBlocks.getCellBlock( rCellAddr ) )
+            pCellBlock->getCellAny( rCellAddr.Column ) <<= rTokens;
+        else
+            putFormulaTokens( rCellAddr, rTokens );
+    }
+}
+
+void SheetDataBuffer::createSharedFormula( const BinAddress& rMapKey, const ApiTokenSequence& rTokens )
+{
+    // create the defined name that will represent the shared formula
+    OUString aName = OUStringBuffer().appendAscii( RTL_CONSTASCII_STRINGPARAM( "__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 );
+    OSL_ENSURE( xNamedRange.is(), "SheetDataBuffer::createSharedFormula - cannot create shared formula" );
+    PropertySet aNameProps( xNamedRange );
+    aNameProps.setProperty( PROP_IsSharedFormula, true );
+
+    // get and store the token index of the defined name
+    OSL_ENSURE( maSharedFormulas.count( rMapKey ) == 0, "SheetDataBuffer::createSharedFormula - shared formula exists already" );
+    sal_Int32 nTokenIndex = 0;
+    if( aNameProps.getProperty( nTokenIndex, PROP_TokenIndex ) && (nTokenIndex >= 0) ) try
+    {
+        // store the token index in the map
+        maSharedFormulas[ rMapKey ] = nTokenIndex;
+        // set the formula definition
+        Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY_THROW );
+        xTokens->setTokens( rTokens );
+        // retry to insert a pending shared formula cell
+        if( mbPendingSharedFmla )
+            setCellFormula( maSharedFmlaAddr, resolveSharedFormula( maSharedBaseAddr ) );
+    }
+    catch( Exception& )
+    {
+    }
+    mbPendingSharedFmla = false;
+}
+
+ApiTokenSequence SheetDataBuffer::resolveSharedFormula( const BinAddress& rMapKey ) const
+{
+    sal_Int32 nTokenIndex = ContainerHelper::getMapElement( maSharedFormulas, rMapKey, -1 );
+    return (nTokenIndex >= 0) ? getFormulaParser().convertNameToFormula( nTokenIndex ) : ApiTokenSequence();
+}
+
+void SheetDataBuffer::finalizeArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) const
+{
+    Reference< XArrayFormulaTokens > xTokens( getCellRange( rRange ), UNO_QUERY );
+    OSL_ENSURE( xTokens.is(), "SheetDataBuffer::finalizeArrayFormula - missing formula token interface" );
+    if( xTokens.is() )
+        xTokens->setArrayTokens( rTokens );
+}
+
+void SheetDataBuffer::finalizeTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) const
+{
+    sal_Int16 nSheet = getSheetIndex();
+    bool bOk = false;
+    if( !rModel.mbRef1Deleted && !rModel.maRef1.isEmpty() && (rRange.StartColumn > 0) && (rRange.StartRow > 0) )
+    {
+        CellRangeAddress aOpRange = rRange;
+        CellAddress aRef1;
+        if( getAddressConverter().convertToCellAddress( aRef1, rModel.maRef1, nSheet, true ) ) try
+        {
+            if( rModel.mb2dTable )
+            {
+                CellAddress aRef2;
+                if( !rModel.mbRef2Deleted && getAddressConverter().convertToCellAddress( aRef2, rModel.maRef2, nSheet, true ) )
+                {
+                    // API call expects input values inside operation range
+                    --aOpRange.StartColumn;
+                    --aOpRange.StartRow;
+                    // formula range is top-left cell of operation range
+                    CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow, aOpRange.StartColumn, aOpRange.StartRow );
+                    // set multiple operation
+                    Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW );
+                    xMultOp->setTableOperation( aFormulaRange, TableOperationMode_BOTH, aRef2, aRef1 );
+                    bOk = true;
+                }
+            }
+            else if( rModel.mbRowTable )
+            {
+                // formula range is column to the left of operation range
+                CellRangeAddress aFormulaRange( nSheet, 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( getCellRange( aOpRange ), UNO_QUERY_THROW );
+                xMultOp->setTableOperation( aFormulaRange, TableOperationMode_ROW, aRef1, aRef1 );
+                bOk = true;
+            }
+            else
+            {
+                // formula range is row above operation range
+                CellRangeAddress aFormulaRange( nSheet, 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( getCellRange( aOpRange ), UNO_QUERY_THROW );
+                xMultOp->setTableOperation( aFormulaRange, TableOperationMode_COLUMN, aRef1, aRef1 );
+                bOk = true;
+            }
+        }
+        catch( Exception& )
+        {
+        }
+    }
+
+    // on error: fill cell range with #REF! error codes
+    if( !bOk ) try
+    {
+        Reference< XCellRangeData > xCellRangeData( getCellRange( rRange ), UNO_QUERY_THROW );
+        size_t nWidth = static_cast< size_t >( rRange.EndColumn - rRange.StartColumn + 1 );
+        size_t nHeight = static_cast< size_t >( rRange.EndRow - rRange.StartRow + 1 );
+        Matrix< Any > aErrorCells( nWidth, nHeight, Any( getFormulaParser().convertErrorToFormula( BIFF_ERR_REF ) ) );
+        xCellRangeData->setDataArray( ContainerHelper::matrixToSequenceSequence( aErrorCells ) );
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+void SheetDataBuffer::setCellFormat( const CellModel& rModel, sal_Int32 nNumFmtId )
+{
+    if( (rModel.mnXfId >= 0) || (nNumFmtId >= 0) )
+    {
+        ApiCellRangeList::reverse_iterator aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rbegin();
+        ApiCellRangeList::reverse_iterator aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rend();
+        /* The xlsx sheet data contains row wise information.
+         * It is sufficient to check if the row range size is one
+         */
+        if(     aIt                 != aItEnd &&
+                aIt->Sheet          == rModel.maCellAddr.Sheet &&
+                aIt->StartRow       == aIt->EndRow &&
+                aIt->StartRow       == rModel.maCellAddr.Row &&
+                (aIt->EndColumn+1)  == rModel.maCellAddr.Column )
+        {
+            aIt->EndColumn++;       // Expand Column
+        }
+        else
+        {
+            maXfIdRangeLists[ XfIdNumFmtKey (rModel.mnXfId, nNumFmtId ) ].push_back(
+                              CellRangeAddress( rModel.maCellAddr.Sheet, rModel.maCellAddr.Column, rModel.maCellAddr.Row,
+                              rModel.maCellAddr.Column, rModel.maCellAddr.Row ) );
+        }
+
+        aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rbegin();
+        aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rend();
+        ApiCellRangeList::reverse_iterator aItM = aIt+1;
+        while( aItM != aItEnd )
+        {
+            if( aIt->Sheet == aItM->Sheet )
+            {
+                /* Try to merge this with the previous range */
+                if( aIt->StartRow == (aItM->EndRow + 1) &&
+                        aIt->StartColumn == aItM->StartColumn &&
+                        aIt->EndColumn == aItM->EndColumn)
+                {
+                    aItM->EndRow = aIt->EndRow;
+                    maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].pop_back();
+                    break;
+                }
+                else if( aIt->StartRow > aItM->EndRow + 1 )
+                    break; // Un-necessary to check with any other rows
+            }
+            else
+                break;
+            ++aItM;
+        }
+
+        // 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.maCellAddr, nHorAlign ) );
+                else if( !maCenterFillRanges.empty() )
+                    maCenterFillRanges.rbegin()->tryExpand( rModel.maCellAddr, nHorAlign );
+            }
+        }
+    }
+}
+
+void SheetDataBuffer::writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowRange ) const
+{
+    if( (rXfIdRowRange.maRowRange.mnLast >= 0) && (rXfIdRowRange.mnXfId >= 0) )
+    {
+        AddressConverter& rAddrConv = getAddressConverter();
+        CellRangeAddress aRange( getSheetIndex(), 0, rXfIdRowRange.maRowRange.mnFirst, rAddrConv.getMaxApiAddress().Column, rXfIdRowRange.maRowRange.mnLast );
+        if( rAddrConv.validateCellRange( aRange, true, false ) )
+        {
+            PropertySet aPropSet( getCellRange( aRange ) );
+            getStyles().writeCellXfToPropertySet( aPropSet, rXfIdRowRange.mnXfId );
+        }
+    }
+}
+
+void SheetDataBuffer::writeXfIdRangeListProperties( sal_Int32 nXfId, sal_Int32 nNumFmtId, const ApiCellRangeList& rRanges ) const
+{
+    StylesBuffer& rStyles = getStyles();
+    PropertyMap aPropMap;
+    if( nXfId >= 0 )
+        rStyles.writeCellXfToPropertyMap( aPropMap, nXfId );
+    if( nNumFmtId >= 0 )
+        rStyles.writeNumFmtToPropertyMap( aPropMap, nNumFmtId );
+    PropertySet aPropSet( getCellRangeList( rRanges ) );
+    aPropSet.setProperties( aPropMap );
+}
+
+void SheetDataBuffer::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() == CellContentType_TEXT) )
+            {
+                Reference< XText > xText( xTopLeft, UNO_QUERY );
+                bTextWrap = xText.is() && (xText->getString().indexOf( '\x0A' ) >= 0);
+            }
+            if( bTextWrap )
+                setManualRowHeight( rRange.StartRow );
+        }
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/sheetdatacontext.cxx b/sc/source/filter/oox/sheetdatacontext.cxx
new file mode 100644
index 000000000000..c087418c7371
--- /dev/null
+++ b/sc/source/filter/oox/sheetdatacontext.cxx
@@ -0,0 +1,1009 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "sheetdatacontext.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "formulaparser.hxx"
+#include "richstringcontext.hxx"
+#include "unitconverter.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::ContextHandlerRef;
+using ::rtl::OUString;
+
+// ============================================================================
+
+namespace {
+
+// record constants -----------------------------------------------------------
+
+const sal_uInt32 BIFF12_CELL_SHOWPHONETIC   = 0x01000000;
+
+const sal_uInt8 BIFF12_DATATABLE_ROW        = 0x01;
+const sal_uInt8 BIFF12_DATATABLE_2D         = 0x02;
+const sal_uInt8 BIFF12_DATATABLE_REF1DEL    = 0x04;
+const sal_uInt8 BIFF12_DATATABLE_REF2DEL    = 0x08;
+
+const sal_uInt16 BIFF12_ROW_THICKTOP        = 0x0001;
+const sal_uInt16 BIFF12_ROW_THICKBOTTOM     = 0x0002;
+const sal_uInt16 BIFF12_ROW_COLLAPSED       = 0x0800;
+const sal_uInt16 BIFF12_ROW_HIDDEN          = 0x1000;
+const sal_uInt16 BIFF12_ROW_CUSTOMHEIGHT    = 0x2000;
+const sal_uInt16 BIFF12_ROW_CUSTOMFORMAT    = 0x4000;
+const sal_uInt8 BIFF12_ROW_SHOWPHONETIC     = 0x01;
+
+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_CELL_USEIXFE          = 63;
+
+} // namespace
+
+// ============================================================================
+
+SheetDataContextBase::SheetDataContextBase( const WorksheetHelper& rHelper ) :
+    mrAddressConv( rHelper.getAddressConverter() ),
+    mrFormulaParser( rHelper.getFormulaParser() ),
+    mrSheetData( rHelper.getSheetData() ),
+    mnSheet( rHelper.getSheetIndex() )
+{
+}
+
+SheetDataContextBase::~SheetDataContextBase()
+{
+}
+
+// ============================================================================
+
+SheetDataContext::SheetDataContext( WorksheetFragmentBase& rFragment ) :
+    WorksheetContextBase( rFragment ),
+    SheetDataContextBase( rFragment ),
+    mbHasFormula( false ),
+    mbValidRange( false )
+{
+}
+
+ContextHandlerRef SheetDataContext::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 ):
+            // do not process cell elements with invalid (out-of-range) address
+            if( nElement == XLS_TOKEN( c ) && importCell( rAttribs ) )
+                return this;
+        break;
+
+        case XLS_TOKEN( c ):
+            switch( nElement )
+            {
+                case XLS_TOKEN( is ):
+                    mxInlineStr.reset( new RichString( *this ) );
+                    return new RichStringContext( *this, mxInlineStr );
+                case XLS_TOKEN( v ):
+                    return this;    // characters contain cell value
+                case XLS_TOKEN( f ):
+                    importFormula( rAttribs );
+                    return this;    // characters contain formula string
+            }
+        break;
+    }
+    return 0;
+}
+
+void SheetDataContext::onCharacters( const OUString& rChars )
+{
+    switch( getCurrentElement() )
+    {
+        case XLS_TOKEN( v ):
+            maCellValue = rChars;
+        break;
+        case XLS_TOKEN( f ):
+            if( maFmlaData.mnFormulaType != XML_TOKEN_INVALID )
+            {
+                maTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, rChars );
+            }
+        break;
+    }
+}
+
+void SheetDataContext::onEndElement()
+{
+    if( getCurrentElement() == XLS_TOKEN( c ) )
+    {
+        // try to create a formula cell
+        if( mbHasFormula ) switch( maFmlaData.mnFormulaType )
+        {
+            case XML_normal:
+                mrSheetData.setFormulaCell( maCellData, maTokens );
+                break;
+            case XML_shared:
+                if( maFmlaData.mnSharedId >= 0 )
+                {
+                    if( mbValidRange && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) )
+                        mrSheetData.createSharedFormula( maFmlaData.mnSharedId, maTokens );
+                    mrSheetData.setFormulaCell( maCellData, maFmlaData.mnSharedId );
+                }
+                else
+                    // no success, set plain cell value and formatting below
+                    mbHasFormula = false;
+            break;
+            case XML_array:
+                if( mbValidRange && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) )
+                    mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, maTokens );
+                // set cell formatting, but do not set result as cell value
+                mrSheetData.setBlankCell( maCellData );
+            break;
+            case XML_dataTable:
+                if( mbValidRange )
+                    mrSheetData.createTableOperation( maFmlaData.maFormulaRef, maTableData );
+                // set cell formatting, but do not set result as cell value
+                mrSheetData.setBlankCell( maCellData );
+            break;
+            default:
+                OSL_ENSURE( maFmlaData.mnFormulaType == XML_TOKEN_INVALID, "SheetDataContext::onEndElement - unknown formula type" );
+                mbHasFormula = false;
+        }
+
+        if( !mbHasFormula )
+        {
+            // no formula created: try to set the cell value
+            if( !maCellValue.isEmpty() ) switch( maCellData.mnCellType )
+            {
+                case XML_n:
+                    mrSheetData.setValueCell( maCellData, maCellValue.toDouble() );
+                break;
+                case XML_b:
+                    mrSheetData.setBooleanCell( maCellData, maCellValue.toDouble() != 0.0 );
+                break;
+                case XML_e:
+                    mrSheetData.setErrorCell( maCellData, maCellValue );
+                break;
+                case XML_str:
+                    mrSheetData.setStringCell( maCellData, maCellValue );
+                break;
+                case XML_s:
+                    mrSheetData.setStringCell( maCellData, maCellValue.toInt32() );
+                break;
+            }
+            else if( (maCellData.mnCellType == XML_inlineStr) && mxInlineStr.get() )
+            {
+                mxInlineStr->finalizeImport();
+                mrSheetData.setStringCell( maCellData, mxInlineStr );
+            }
+            else
+            {
+                // empty cell, update cell type
+                maCellData.mnCellType = XML_TOKEN_INVALID;
+                mrSheetData.setBlankCell( maCellData );
+            }
+        }
+        else if( !maCellValue.isEmpty() ) switch( maCellData.mnCellType )
+        {
+            case XML_n:
+                /* Set the pre-loaded value */
+                mrSheetData.putFormulaResult( maCellData.maCellAddr, maCellValue.toDouble() );
+                break;
+        }
+    }
+}
+
+ContextHandlerRef SheetDataContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_SHEETDATA:
+            if( nRecId == BIFF12_ID_ROW ) { importRow( rStrm ); return this; }
+        break;
+
+        case BIFF12_ID_ROW:
+            switch( nRecId )
+            {
+                case BIFF12_ID_ARRAY:           importArray( rStrm );                           break;
+                case BIFF12_ID_CELL_BOOL:       importCellBool( rStrm, CELLTYPE_VALUE );        break;
+                case BIFF12_ID_CELL_BLANK:      importCellBlank( rStrm, CELLTYPE_VALUE );       break;
+                case BIFF12_ID_CELL_DOUBLE:     importCellDouble( rStrm, CELLTYPE_VALUE );      break;
+                case BIFF12_ID_CELL_ERROR:      importCellError( rStrm, CELLTYPE_VALUE );       break;
+                case BIFF12_ID_CELL_RK:         importCellRk( rStrm, CELLTYPE_VALUE );          break;
+                case BIFF12_ID_CELL_RSTRING:    importCellRString( rStrm, CELLTYPE_VALUE );     break;
+                case BIFF12_ID_CELL_SI:         importCellSi( rStrm, CELLTYPE_VALUE );          break;
+                case BIFF12_ID_CELL_STRING:     importCellString( rStrm, CELLTYPE_VALUE );      break;
+                case BIFF12_ID_DATATABLE:       importDataTable( rStrm );                       break;
+                case BIFF12_ID_FORMULA_BOOL:    importCellBool( rStrm, CELLTYPE_FORMULA );      break;
+                case BIFF12_ID_FORMULA_DOUBLE:  importCellDouble( rStrm, CELLTYPE_FORMULA );    break;
+                case BIFF12_ID_FORMULA_ERROR:   importCellError( rStrm, CELLTYPE_FORMULA );     break;
+                case BIFF12_ID_FORMULA_STRING:  importCellString( rStrm, CELLTYPE_FORMULA );    break;
+                case BIFF12_ID_MULTCELL_BOOL:   importCellBool( rStrm, CELLTYPE_MULTI );        break;
+                case BIFF12_ID_MULTCELL_BLANK:  importCellBlank( rStrm, CELLTYPE_MULTI );       break;
+                case BIFF12_ID_MULTCELL_DOUBLE: importCellDouble( rStrm, CELLTYPE_MULTI );      break;
+                case BIFF12_ID_MULTCELL_ERROR:  importCellError( rStrm, CELLTYPE_MULTI );       break;
+                case BIFF12_ID_MULTCELL_RK:     importCellRk( rStrm, CELLTYPE_MULTI );          break;
+                case BIFF12_ID_MULTCELL_RSTRING:importCellRString( rStrm, CELLTYPE_MULTI );     break;
+                case BIFF12_ID_MULTCELL_SI:     importCellSi( rStrm, CELLTYPE_MULTI );          break;
+                case BIFF12_ID_MULTCELL_STRING: importCellString( rStrm, CELLTYPE_MULTI );      break;
+                case BIFF12_ID_SHAREDFMLA:      importSharedFmla( rStrm );                      break;
+            }
+        break;
+    }
+    return 0;
+}
+
+// private --------------------------------------------------------------------
+
+void SheetDataContext::importRow( const AttributeList& rAttribs )
+{
+    RowModel aModel;
+    aModel.mnRow          = 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 );
+
+    // decode the column spans (space-separated list of colon-separated integer pairs)
+    OUString aColSpansText = rAttribs.getString( XML_spans, OUString() );
+    sal_Int32 nMaxCol = mrAddressConv.getMaxApiAddress().Column;
+    sal_Int32 nIndex = 0;
+    while( nIndex >= 0 )
+    {
+        OUString aColSpanToken = aColSpansText.getToken( 0, ' ', nIndex );
+        sal_Int32 nSepPos = aColSpanToken.indexOf( ':' );
+        if( (0 < nSepPos) && (nSepPos + 1 < aColSpanToken.getLength()) )
+        {
+            // OOXML uses 1-based integer column indexes, row model expects 0-based colspans
+            sal_Int32 nLastCol = ::std::min( aColSpanToken.copy( nSepPos + 1 ).toInt32() - 1, nMaxCol );
+            aModel.insertColSpan( ValueRange( aColSpanToken.copy( 0, nSepPos ).toInt32() - 1, nLastCol ) );
+        }
+    }
+
+    // set row properties in the current sheet
+    setRowModel( aModel );
+}
+
+bool SheetDataContext::importCell( const AttributeList& rAttribs )
+{
+    bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, rAttribs.getString( XML_r, OUString() ), mnSheet, true );
+    if( bValidAddr )
+    {
+        maCellData.mnCellType     = rAttribs.getToken( XML_t, XML_n );
+        maCellData.mnXfId         = rAttribs.getInteger( XML_s, -1 );
+        maCellData.mbShowPhonetic = rAttribs.getBool( XML_ph, false );
+
+        // reset cell value, formula settings, and inline string
+        maCellValue = OUString();
+        mxInlineStr.reset();
+        mbHasFormula = false;
+
+        // update used area of the sheet
+        extendUsedArea( maCellData.maCellAddr );
+    }
+    return bValidAddr;
+}
+
+void SheetDataContext::importFormula( const AttributeList& rAttribs )
+{
+    mbHasFormula = true;
+    mbValidRange = mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, rAttribs.getString( XML_ref, OUString() ), mnSheet, true, true );
+
+    maFmlaData.mnFormulaType = rAttribs.getToken( XML_t, XML_normal );
+    maFmlaData.mnSharedId    = rAttribs.getInteger( XML_si, -1 );
+
+    if( maFmlaData.mnFormulaType == XML_dataTable )
+    {
+        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 );
+    }
+
+    // clear token array, will be regenerated from element text
+    maTokens = ApiTokenSequence();
+}
+
+void SheetDataContext::importRow( SequenceInputStream& rStrm )
+{
+    RowModel aModel;
+    sal_Int32 nSpanCount;
+    sal_uInt16 nHeight, nFlags1;
+    sal_uInt8 nFlags2;
+    rStrm >> maCurrPos.mnRow >> aModel.mnXfId >> nHeight >> nFlags1 >> nFlags2 >> nSpanCount;
+    maCurrPos.mnCol = 0;
+
+    // row index is 0-based in BIFF12, but RowModel expects 1-based
+    aModel.mnRow          = maCurrPos.mnRow + 1;
+    // row height is in twips in BIFF12, convert to points
+    aModel.mfHeight       = nHeight / 20.0;
+    aModel.mnLevel        = extractValue< sal_Int32 >( nFlags1, 8, 3 );
+    aModel.mbCustomHeight = getFlag( nFlags1, BIFF12_ROW_CUSTOMHEIGHT );
+    aModel.mbCustomFormat = getFlag( nFlags1, BIFF12_ROW_CUSTOMFORMAT );
+    aModel.mbShowPhonetic = getFlag( nFlags2, BIFF12_ROW_SHOWPHONETIC );
+    aModel.mbHidden       = getFlag( nFlags1, BIFF12_ROW_HIDDEN );
+    aModel.mbCollapsed    = getFlag( nFlags1, BIFF12_ROW_COLLAPSED );
+    aModel.mbThickTop     = getFlag( nFlags1, BIFF12_ROW_THICKTOP );
+    aModel.mbThickBottom  = getFlag( nFlags1, BIFF12_ROW_THICKBOTTOM );
+
+    // read the column spans
+    sal_Int32 nMaxCol = mrAddressConv.getMaxApiAddress().Column;
+    for( sal_Int32 nSpanIdx = 0; (nSpanIdx < nSpanCount) && !rStrm.isEof(); ++nSpanIdx )
+    {
+        sal_Int32 nFirstCol, nLastCol;
+        rStrm >> nFirstCol >> nLastCol;
+        aModel.insertColSpan( ValueRange( nFirstCol, ::std::min( nLastCol, nMaxCol ) ) );
+    }
+
+    // set row properties in the current sheet
+    setRowModel( aModel );
+}
+
+bool SheetDataContext::readCellHeader( SequenceInputStream& rStrm, CellType eCellType )
+{
+    switch( eCellType )
+    {
+        case CELLTYPE_VALUE:
+        case CELLTYPE_FORMULA:  rStrm >> maCurrPos.mnCol;   break;
+        case CELLTYPE_MULTI:    ++maCurrPos.mnCol;          break;
+    }
+
+    sal_uInt32 nXfId;
+    rStrm >> nXfId;
+
+    bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, maCurrPos, mnSheet, true );
+    maCellData.mnXfId = extractValue< sal_Int32 >( nXfId, 0, 24 );
+    maCellData.mbShowPhonetic = getFlag( nXfId, BIFF12_CELL_SHOWPHONETIC );
+
+    // update used area of the sheet
+    if( bValidAddr )
+        extendUsedArea( maCellData.maCellAddr );
+    return bValidAddr;
+}
+
+ApiTokenSequence SheetDataContext::readCellFormula( SequenceInputStream& rStrm )
+{
+    rStrm.skip( 2 );
+    return mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm );
+}
+
+bool SheetDataContext::readFormulaRef( SequenceInputStream& rStrm )
+{
+    BinRange aRange;
+    rStrm >> aRange;
+    return mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, aRange, mnSheet, true, true );
+}
+
+void SheetDataContext::importCellBool( SequenceInputStream& rStrm, CellType eCellType )
+{
+    if( readCellHeader( rStrm, eCellType ) )
+    {
+        maCellData.mnCellType = XML_b;
+        bool bValue = rStrm.readuInt8() != 0;
+        if( eCellType == CELLTYPE_FORMULA )
+            mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) );
+        else
+            mrSheetData.setBooleanCell( maCellData, bValue );
+    }
+}
+
+void SheetDataContext::importCellBlank( SequenceInputStream& rStrm, CellType eCellType )
+{
+    OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellBlank - no formula cells supported" );
+    if( readCellHeader( rStrm, eCellType ) )
+        mrSheetData.setBlankCell( maCellData );
+}
+
+void SheetDataContext::importCellDouble( SequenceInputStream& rStrm, CellType eCellType )
+{
+    if( readCellHeader( rStrm, eCellType ) )
+    {
+        maCellData.mnCellType = XML_n;
+        double fValue = rStrm.readDouble();
+        if( eCellType == CELLTYPE_FORMULA )
+            mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) );
+        else
+            mrSheetData.setValueCell( maCellData, fValue );
+    }
+}
+
+void SheetDataContext::importCellError( SequenceInputStream& rStrm, CellType eCellType )
+{
+    if( readCellHeader( rStrm, eCellType ) )
+    {
+        maCellData.mnCellType = XML_e;
+        sal_uInt8 nErrorCode = rStrm.readuInt8();
+        if( eCellType == CELLTYPE_FORMULA )
+            mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) );
+        else
+            mrSheetData.setErrorCell( maCellData, nErrorCode );
+    }
+}
+
+void SheetDataContext::importCellRk( SequenceInputStream& rStrm, CellType eCellType )
+{
+    OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellRk - no formula cells supported" );
+    if( readCellHeader( rStrm, eCellType ) )
+    {
+        maCellData.mnCellType = XML_n;
+        mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) );
+    }
+}
+
+void SheetDataContext::importCellRString( SequenceInputStream& rStrm, CellType eCellType )
+{
+    OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellRString - no formula cells supported" );
+    if( readCellHeader( rStrm, eCellType ) )
+    {
+        maCellData.mnCellType = XML_inlineStr;
+        RichStringRef xString( new RichString( *this ) );
+        xString->importString( rStrm, true );
+        xString->finalizeImport();
+        mrSheetData.setStringCell( maCellData, xString );
+    }
+}
+
+void SheetDataContext::importCellSi( SequenceInputStream& rStrm, CellType eCellType )
+{
+    OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellSi - no formula cells supported" );
+    if( readCellHeader( rStrm, eCellType ) )
+    {
+        maCellData.mnCellType = XML_s;
+        mrSheetData.setStringCell( maCellData, rStrm.readInt32() );
+    }
+}
+
+void SheetDataContext::importCellString( SequenceInputStream& rStrm, CellType eCellType )
+{
+    if( readCellHeader( rStrm, eCellType ) )
+    {
+        maCellData.mnCellType = XML_inlineStr;
+        // always import the string, stream will point to formula afterwards, if existing
+        RichStringRef xString( new RichString( *this ) );
+        xString->importString( rStrm, false );
+        xString->finalizeImport();
+        if( eCellType == CELLTYPE_FORMULA )
+            mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) );
+        else
+            mrSheetData.setStringCell( maCellData, xString );
+    }
+}
+
+void SheetDataContext::importArray( SequenceInputStream& rStrm )
+{
+    if( readFormulaRef( rStrm ) && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) )
+    {
+        rStrm.skip( 1 );
+        ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_ARRAY, rStrm );
+        mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, aTokens );
+    }
+}
+
+void SheetDataContext::importDataTable( SequenceInputStream& rStrm )
+{
+    if( readFormulaRef( rStrm ) )
+    {
+        BinAddress aRef1, aRef2;
+        sal_uInt8 nFlags;
+        rStrm >> aRef1 >> aRef2 >> nFlags;
+        maTableData.maRef1        = FormulaProcessorBase::generateAddress2dString( aRef1, false );
+        maTableData.maRef2        = FormulaProcessorBase::generateAddress2dString( aRef2, false );
+        maTableData.mbRowTable    = getFlag( nFlags, BIFF12_DATATABLE_ROW );
+        maTableData.mb2dTable     = getFlag( nFlags, BIFF12_DATATABLE_2D );
+        maTableData.mbRef1Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF1DEL );
+        maTableData.mbRef2Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF2DEL );
+        mrSheetData.createTableOperation( maFmlaData.maFormulaRef, maTableData );
+    }
+}
+
+void SheetDataContext::importSharedFmla( SequenceInputStream& rStrm )
+{
+    if( readFormulaRef( rStrm ) && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) )
+    {
+        ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_SHAREDFORMULA, rStrm );
+        mrSheetData.createSharedFormula( maCellData.maCellAddr, aTokens );
+    }
+}
+
+// ============================================================================
+
+BiffSheetDataContext::BiffSheetDataContext( const WorksheetHelper& rHelper ) :
+    BiffWorksheetContextBase( rHelper ),
+    SheetDataContextBase( rHelper ),
+    mnBiff2XfId( 0 )
+{
+    switch( getBiff() )
+    {
+        case BIFF2:
+            mnFormulaSkipSize = 9;  // double formula result, 1 byte flags
+            mnArraySkipSize = 1;    // recalc-always flag
+        break;
+        case BIFF3:
+        case BIFF4:
+            mnFormulaSkipSize = 10; // double formula result, 2 byte flags
+            mnArraySkipSize = 2;    // 2 byte flags
+        break;
+        case BIFF5:
+        case BIFF8:
+            mnFormulaSkipSize = 14; // double formula result, 2 byte flags, 4 bytes nothing
+            mnArraySkipSize = 6;    // 2 byte flags, 4 bytes nothing
+        break;
+        case BIFF_UNKNOWN:
+        break;
+    }
+}
+
+void BiffSheetDataContext::importRecord( BiffInputStream& rStrm )
+{
+    sal_uInt16 nRecId = rStrm.getRecId();
+    switch( nRecId )
+    {
+        // records in all BIFF versions
+        case BIFF2_ID_ARRAY:        // #i72713#
+        case BIFF3_ID_ARRAY:        importArray( rStrm );   break;
+        case BIFF2_ID_BLANK:
+        case BIFF3_ID_BLANK:        importBlank( rStrm );   break;
+        case BIFF2_ID_BOOLERR:
+        case BIFF3_ID_BOOLERR:      importBoolErr( rStrm ); break;
+        case BIFF2_ID_INTEGER:      importInteger( rStrm ); break;
+        case BIFF_ID_IXFE:          rStrm >> mnBiff2XfId;   break;
+        case BIFF2_ID_LABEL:
+        case BIFF3_ID_LABEL:        importLabel( rStrm );   break;
+        case BIFF2_ID_NUMBER:
+        case BIFF3_ID_NUMBER:       importNumber( rStrm );  break;
+        case BIFF_ID_RK:            importRk( rStrm );      break;
+
+        // BIFF specific records
+        default: switch( getBiff() )
+        {
+            case BIFF2: switch( nRecId )
+            {
+                case BIFF2_ID_DATATABLE:    importDataTable( rStrm );   break;
+                case BIFF2_ID_DATATABLE2:   importDataTable( rStrm );   break;
+                case BIFF2_ID_FORMULA:      importFormula( rStrm );     break;
+                case BIFF2_ID_ROW:          importRow( rStrm );         break;
+            }
+            break;
+
+            case BIFF3: switch( nRecId )
+            {
+                case BIFF3_ID_DATATABLE:    importDataTable( rStrm );   break;
+                case BIFF3_ID_FORMULA:      importFormula( rStrm );     break;
+                case BIFF3_ID_ROW:          importRow( rStrm );         break;
+            }
+            break;
+
+            case BIFF4: switch( nRecId )
+            {
+                case BIFF3_ID_DATATABLE:    importDataTable( rStrm );   break;
+                case BIFF4_ID_FORMULA:      importFormula( rStrm );     break;
+                case BIFF3_ID_ROW:          importRow( rStrm );         break;
+            }
+            break;
+
+            case BIFF5: switch( nRecId )
+            {
+                case BIFF3_ID_DATATABLE:    importDataTable( rStrm );   break;
+                case BIFF3_ID_FORMULA:
+                case BIFF4_ID_FORMULA:
+                case BIFF5_ID_FORMULA:      importFormula( rStrm );     break;
+                case BIFF_ID_MULTBLANK:     importMultBlank( rStrm );   break;
+                case BIFF_ID_MULTRK:        importMultRk( rStrm );      break;
+                case BIFF3_ID_ROW:          importRow( rStrm );         break;
+                case BIFF_ID_RSTRING:       importLabel( rStrm );       break;
+                case BIFF_ID_SHAREDFMLA:    importSharedFmla( rStrm );  break;
+            }
+            break;
+
+            case BIFF8: switch( nRecId )
+            {
+                case BIFF3_ID_DATATABLE:    importDataTable( rStrm );   break;
+                case BIFF3_ID_FORMULA:
+                case BIFF4_ID_FORMULA:
+                case BIFF5_ID_FORMULA:      importFormula( rStrm );     break;
+                case BIFF_ID_LABELSST:      importLabelSst( rStrm );    break;
+                case BIFF_ID_MULTBLANK:     importMultBlank( rStrm );   break;
+                case BIFF_ID_MULTRK:        importMultRk( rStrm );      break;
+                case BIFF3_ID_ROW:          importRow( rStrm );         break;
+                case BIFF_ID_RSTRING:       importLabel( rStrm );       break;
+                case BIFF_ID_SHAREDFMLA:    importSharedFmla( rStrm );  break;
+            }
+            break;
+
+            case BIFF_UNKNOWN:
+            break;
+        }
+    }
+}
+
+// private --------------------------------------------------------------------
+
+void BiffSheetDataContext::importRow( BiffInputStream& rStrm )
+{
+    RowModel aModel;
+    sal_uInt16 nRow, nFirstUsedCol, nFirstFreeCol, nHeight;
+    rStrm >> nRow >> nFirstUsedCol >> nFirstFreeCol >> nHeight;
+    if( getBiff() == BIFF2 )
+    {
+        rStrm.skip( 2 );
+        aModel.mbCustomFormat = rStrm.readuInt8() == BIFF2_ROW_CUSTOMFORMAT;
+        if( aModel.mbCustomFormat )
+        {
+            rStrm.skip( 5 );
+            aModel.mnXfId = rStrm.readuInt16();
+        }
+    }
+    else
+    {
+        rStrm.skip( 4 );
+        sal_uInt32 nFlags = rStrm.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.mnRow = static_cast< sal_Int32 >( nRow ) + 1;
+    // row height is in twips in BIFF, convert to points
+    aModel.mfHeight = (nHeight & BIFF_ROW_HEIGHTMASK) / 20.0;
+    // set column spans
+    if( nFirstUsedCol < nFirstFreeCol )
+    {
+        sal_Int32 nLastCol = ::std::min< sal_Int32 >( nFirstFreeCol - 1, mrAddressConv.getMaxApiAddress().Column );
+        aModel.insertColSpan( ValueRange( nFirstUsedCol, nLastCol ) );
+    }
+
+    // set row properties in the current sheet
+    setRowModel( aModel );
+}
+
+bool BiffSheetDataContext::readCellXfId( BiffInputStream& rStrm, const BinAddress& rAddr, bool bBiff2 )
+{
+    bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, rAddr, mnSheet, true );
+    if( bValidAddr )
+    {
+        // update used area of the sheet
+        extendUsedArea( maCellData.maCellAddr );
+
+        // load the XF identifier according to current BIFF version
+        if( bBiff2 )
+        {
+            /*  #i71453# On first call, check if the file contains XF records
+                (by trying to access the first XF with index 0). If there are
+                no XFs, the explicit formatting information contained in each
+                cell record will be used instead. */
+            if( !mobBiff2HasXfs )
+                mobBiff2HasXfs = getStyles().getCellXf( 0 ).get() != 0;
+            // read formatting information (includes the XF identifier)
+            sal_uInt8 nFlags1, nFlags2, nFlags3;
+            rStrm >> nFlags1 >> nFlags2 >> nFlags3;
+            /*  If the file contains XFs, extract and set the XF identifier,
+                otherwise get the explicit formatting. */
+            if( mobBiff2HasXfs.get() )
+            {
+                maCellData.mnXfId = extractValue< sal_Int32 >( nFlags1, 0, 6 );
+                /*  If the identifier is equal to 63, then the real identifier
+                    is contained in the preceding IXFE record (stored in the
+                    class member mnBiff2XfId). */
+                if( maCellData.mnXfId == BIFF2_CELL_USEIXFE )
+                    maCellData.mnXfId = mnBiff2XfId;
+            }
+            else
+            {
+                /*  Let the Xf class do the API conversion. Keeping the member
+                    maCellData.mnXfId untouched will prevent to trigger the
+                    usual XF formatting conversion later on. */
+                PropertySet aPropSet( getCell( maCellData.maCellAddr ) );
+                Xf::writeBiff2CellFormatToPropertySet( *this, aPropSet, nFlags1, nFlags2, nFlags3 );
+            }
+        }
+        else
+        {
+            // BIFF3-BIFF8: 16-bit XF identifier
+            maCellData.mnXfId = rStrm.readuInt16();
+        }
+    }
+    return bValidAddr;
+}
+
+bool BiffSheetDataContext::readCellHeader( BiffInputStream& rStrm, bool bBiff2 )
+{
+    BinAddress aAddr;
+    rStrm >> aAddr;
+    return readCellXfId( rStrm, aAddr, bBiff2 );
+}
+
+bool BiffSheetDataContext::readFormulaRef( BiffInputStream& rStrm )
+{
+    BinRange aRange;
+    aRange.read( rStrm, false );    // columns always 8-bit
+    return mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, aRange, mnSheet, true, true );
+}
+
+void BiffSheetDataContext::importBlank( BiffInputStream& rStrm )
+{
+    if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BLANK ) )
+        mrSheetData.setBlankCell( maCellData );
+}
+
+void BiffSheetDataContext::importBoolErr( BiffInputStream& rStrm )
+{
+    if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BOOLERR ) )
+    {
+        sal_uInt8 nValue, nType;
+        rStrm >> nValue >> nType;
+        switch( nType )
+        {
+            case BIFF_BOOLERR_BOOL:
+                maCellData.mnCellType = XML_b;
+                mrSheetData.setBooleanCell( maCellData, nValue != 0 );
+            break;
+            case BIFF_BOOLERR_ERROR:
+                maCellData.mnCellType = XML_e;
+                mrSheetData.setErrorCell( maCellData, nValue );
+            break;
+            default:
+                OSL_FAIL( "BiffSheetDataContext::importBoolErr - unknown cell type" );
+                maCellData.mnCellType = XML_TOKEN_INVALID;
+                mrSheetData.setBlankCell( maCellData );
+            break;
+        }
+    }
+}
+
+void BiffSheetDataContext::importFormula( BiffInputStream& rStrm )
+{
+    if( readCellHeader( rStrm, getBiff() == BIFF2 ) )
+    {
+        maCellData.mnCellType = XML_n;
+        rStrm.skip( mnFormulaSkipSize );
+        ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm );
+        mrSheetData.setFormulaCell( maCellData, aTokens );
+    }
+}
+
+void BiffSheetDataContext::importInteger( BiffInputStream& rStrm )
+{
+    if( readCellHeader( rStrm, true ) )
+    {
+        maCellData.mnCellType = XML_n;
+        mrSheetData.setValueCell( maCellData, rStrm.readuInt16() );
+    }
+}
+
+void BiffSheetDataContext::importLabel( BiffInputStream& rStrm )
+{
+    /*  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
+     */
+    bool bBiff2Xf = rStrm.getRecId() == BIFF2_ID_LABEL;
+    if( readCellHeader( rStrm, bBiff2Xf ) )
+    {
+        maCellData.mnCellType = XML_inlineStr;
+        if( getBiff() == BIFF8 )
+        {
+            // string may contain rich-text formatting
+            RichStringRef xString( new RichString( *this ) );
+            xString->importUniString( rStrm );
+            xString->finalizeImport();
+            mrSheetData.setStringCell( maCellData, xString );
+        }
+        else
+        {
+            // #i63105# use text encoding from FONT record
+            rtl_TextEncoding eTextEnc = getTextEncoding();
+            if( const Font* pFont = getStyles().getFontFromCellXf( maCellData.mnXfId ).get() )
+                eTextEnc = pFont->getFontEncoding();
+            // RSTRING record contains rich-text formatting
+            if( rStrm.getRecId() == BIFF_ID_RSTRING )
+            {
+                BiffStringFlags nFlags = BIFF_STR_EXTRAFONTS;
+                // BIFF2 record identifier: 8-bit string length (see above)
+                setFlag( nFlags, BIFF_STR_8BITLENGTH, bBiff2Xf );
+                RichStringRef xString( new RichString( *this ) );
+                xString->importByteString( rStrm, eTextEnc, nFlags );
+                xString->finalizeImport();
+                mrSheetData.setStringCell( maCellData, xString );
+            }
+            else
+            {
+                // BIFF2 record identifier: 8-bit string length (see above)
+                OUString aText = rStrm.readByteStringUC( !bBiff2Xf, eTextEnc );
+                mrSheetData.setStringCell( maCellData, aText );
+            }
+        }
+    }
+}
+
+void BiffSheetDataContext::importLabelSst( BiffInputStream& rStrm )
+{
+    if( readCellHeader( rStrm, false ) )
+    {
+        maCellData.mnCellType = XML_s;
+        mrSheetData.setStringCell( maCellData, rStrm.readInt32() );
+    }
+}
+
+void BiffSheetDataContext::importMultBlank( BiffInputStream& rStrm )
+{
+    BinAddress aAddr;
+    bool bValidAddr = true;
+    for( rStrm >> aAddr; bValidAddr && (rStrm.getRemaining() > 2); ++aAddr.mnCol )
+        if( (bValidAddr = readCellXfId( rStrm, aAddr, false )) == true )
+            mrSheetData.setBlankCell( maCellData );
+}
+
+void BiffSheetDataContext::importMultRk( BiffInputStream& rStrm )
+{
+    BinAddress aAddr;
+    bool bValidAddr = true;
+    for( rStrm >> aAddr; bValidAddr && (rStrm.getRemaining() > 2); ++aAddr.mnCol )
+    {
+        if( (bValidAddr = readCellXfId( rStrm, aAddr, false )) == true )
+        {
+            maCellData.mnCellType = XML_n;
+            sal_Int32 nRkValue = rStrm.readInt32();
+            mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( nRkValue ) );
+        }
+    }
+}
+
+void BiffSheetDataContext::importNumber( BiffInputStream& rStrm )
+{
+    if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_NUMBER ) )
+    {
+        maCellData.mnCellType = XML_n;
+        mrSheetData.setValueCell( maCellData, rStrm.readDouble() );
+    }
+}
+
+void BiffSheetDataContext::importRk( BiffInputStream& rStrm )
+{
+    if( readCellHeader( rStrm, false ) )
+    {
+        maCellData.mnCellType = XML_n;
+        mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) );
+    }
+}
+
+void BiffSheetDataContext::importArray( BiffInputStream& rStrm )
+{
+    if( readFormulaRef( rStrm ) && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) )
+    {
+        rStrm.skip( mnArraySkipSize );
+        ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_ARRAY, rStrm );
+        mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, aTokens );
+    }
+}
+
+void BiffSheetDataContext::importDataTable( BiffInputStream& rStrm )
+{
+    if( readFormulaRef( rStrm ) )
+    {
+        DataTableModel aModel;
+        BinAddress aRef1, aRef2;
+        switch( rStrm.getRecId() )
+        {
+            case BIFF2_ID_DATATABLE:
+                rStrm.skip( 1 );
+                aModel.mbRowTable = rStrm.readuInt8() != 0;
+                aModel.mb2dTable = false;
+                rStrm >> aRef1;
+            break;
+            case BIFF2_ID_DATATABLE2:
+                rStrm.skip( 2 );
+                aModel.mb2dTable = true;
+                rStrm >> aRef1 >> aRef2;
+            break;
+            case BIFF3_ID_DATATABLE:
+            {
+                sal_uInt16 nFlags;
+                rStrm >> 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_FAIL( "BiffSheetDataContext::importDataTable - unknown record id" );
+        }
+        aModel.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false );
+        aModel.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false );
+        mrSheetData.createTableOperation( maFmlaData.maFormulaRef, aModel );
+    }
+}
+
+void BiffSheetDataContext::importSharedFmla( BiffInputStream& rStrm )
+{
+    if( readFormulaRef( rStrm ) && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) )
+    {
+        rStrm.skip( 2 );    // flags
+        ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_SHAREDFORMULA, rStrm );
+        mrSheetData.createSharedFormula( maCellData.maCellAddr, aTokens );
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/stylesbuffer.cxx b/sc/source/filter/oox/stylesbuffer.cxx
new file mode 100644
index 000000000000..ffcd6f05cbe7
--- /dev/null
+++ b/sc/source/filter/oox/stylesbuffer.cxx
@@ -0,0 +1,3443 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "stylesbuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertymap.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "biffinputstream.hxx"
+#include "condformatbuffer.hxx"
+#include "excelhandlers.hxx"
+#include "themebuffer.hxx"
+#include "unitconverter.hxx"
+
+using ::com::sun::star::table::BorderLine2;
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::FilterBase;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+// OOXML constants ------------------------------------------------------------
+
+// OOXML predefined color indexes (also used in BIFF3-BIFF8)
+const sal_Int32 OOX_COLOR_USEROFFSET        = 0;        /// First user defined color in palette (OOXML/BIFF12).
+const sal_Int32 BIFF_COLOR_USEROFFSET       = 8;        /// First user defined color in palette (BIFF3-BIFF8).
+
+// OOXML 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;
+
+// OOXML 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;
+
+// OOXML 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;
+
+// OOXML cell indentation
+const sal_Int32 OOX_XF_INDENT_NONE          = 0;
+
+// OOXML 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.
+
+// BIFF12 constants -----------------------------------------------------------
+
+// BIFF12 color types
+const sal_uInt8 BIFF12_COLOR_AUTO           = 0;
+const sal_uInt8 BIFF12_COLOR_INDEXED        = 1;
+const sal_uInt8 BIFF12_COLOR_RGB            = 2;
+const sal_uInt8 BIFF12_COLOR_THEME          = 3;
+
+// BIFF12 diagonal borders
+const sal_uInt8 BIFF12_BORDER_DIAG_TLBR     = 0x01;     /// Top-left to bottom-right.
+const sal_uInt8 BIFF12_BORDER_DIAG_BLTR     = 0x02;     /// Bottom-left to top-right.
+
+// BIFF12 gradient fill
+const sal_Int32 BIFF12_FILL_GRADIENT        = 40;
+
+// BIFF12 XF flags
+const sal_uInt32 BIFF12_XF_WRAPTEXT         = 0x00400000;
+const sal_uInt32 BIFF12_XF_JUSTLASTLINE     = 0x00800000;
+const sal_uInt32 BIFF12_XF_SHRINK           = 0x01000000;
+const sal_uInt32 BIFF12_XF_LOCKED           = 0x10000000;
+const sal_uInt32 BIFF12_XF_HIDDEN           = 0x20000000;
+
+// BIFF12 XF attribute used flags
+const sal_uInt16 BIFF12_XF_NUMFMT_USED      = 0x0001;
+const sal_uInt16 BIFF12_XF_FONT_USED        = 0x0002;
+const sal_uInt16 BIFF12_XF_ALIGN_USED       = 0x0004;
+const sal_uInt16 BIFF12_XF_BORDER_USED      = 0x0008;
+const sal_uInt16 BIFF12_XF_AREA_USED        = 0x0010;
+const sal_uInt16 BIFF12_XF_PROT_USED        = 0x0020;
+
+// BIFF12 DXF constants
+const sal_uInt16 BIFF12_DXF_FILL_PATTERN    = 0;
+const sal_uInt16 BIFF12_DXF_FILL_FGCOLOR    = 1;
+const sal_uInt16 BIFF12_DXF_FILL_BGCOLOR    = 2;
+const sal_uInt16 BIFF12_DXF_FILL_GRADIENT   = 3;
+const sal_uInt16 BIFF12_DXF_FILL_STOP       = 4;
+const sal_uInt16 BIFF12_DXF_FONT_COLOR      = 5;
+const sal_uInt16 BIFF12_DXF_BORDER_TOP      = 6;
+const sal_uInt16 BIFF12_DXF_BORDER_BOTTOM   = 7;
+const sal_uInt16 BIFF12_DXF_BORDER_LEFT     = 8;
+const sal_uInt16 BIFF12_DXF_BORDER_RIGHT    = 9;
+const sal_uInt16 BIFF12_DXF_BORDER_DIAG     = 10;
+const sal_uInt16 BIFF12_DXF_BORDER_VERT     = 11;
+const sal_uInt16 BIFF12_DXF_BORDER_HOR      = 12;
+const sal_uInt16 BIFF12_DXF_BORDER_DIAGUP   = 13;
+const sal_uInt16 BIFF12_DXF_BORDER_DIAGDOWN = 14;
+const sal_uInt16 BIFF12_DXF_FONT_NAME       = 24;
+const sal_uInt16 BIFF12_DXF_FONT_WEIGHT     = 25;
+const sal_uInt16 BIFF12_DXF_FONT_UNDERLINE  = 26;
+const sal_uInt16 BIFF12_DXF_FONT_ESCAPEMENT = 27;
+const sal_uInt16 BIFF12_DXF_FONT_ITALIC     = 28;
+const sal_uInt16 BIFF12_DXF_FONT_STRIKE     = 29;
+const sal_uInt16 BIFF12_DXF_FONT_OUTLINE    = 30;
+const sal_uInt16 BIFF12_DXF_FONT_SHADOW     = 31;
+const sal_uInt16 BIFF12_DXF_FONT_CONDENSE   = 32;
+const sal_uInt16 BIFF12_DXF_FONT_EXTEND     = 33;
+const sal_uInt16 BIFF12_DXF_FONT_CHARSET    = 34;
+const sal_uInt16 BIFF12_DXF_FONT_FAMILY     = 35;
+const sal_uInt16 BIFF12_DXF_FONT_HEIGHT     = 36;
+const sal_uInt16 BIFF12_DXF_FONT_SCHEME     = 37;
+const sal_uInt16 BIFF12_DXF_NUMFMT_CODE     = 38;
+const sal_uInt16 BIFF12_DXF_NUMFMT_ID       = 41;
+
+// BIFF12 CELLSTYLE flags
+const sal_uInt16 BIFF12_CELLSTYLE_BUILTIN   = 0x0001;
+const sal_uInt16 BIFF12_CELLSTYLE_HIDDEN    = 0x0002;
+const sal_uInt16 BIFF12_CELLSTYLE_CUSTOM    = 0x0004;
+
+// 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 BIFF12
+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 BIFF12
+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;   /// Styles 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.getBaseFilter().getComponentContext(), rHelper.getBaseFilter().getTargetFrame(), rHelper.getBaseFilter().getStorage() ),
+    WorkbookHelper( rHelper )
+{
+}
+
+sal_Int32 ExcelGraphicHelper::getSchemeColor( sal_Int32 nToken ) const
+{
+    if( getFilterType() == FILTER_OOXML )
+        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_FAIL( "Color::importColor - unknown color type" );
+        setAuto();
+    }
+}
+
+void Color::importColor( SequenceInputStream& 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 BIFF12_COLOR_AUTO:
+            setAuto();
+            rStrm.skip( 4 );
+        break;
+        case BIFF12_COLOR_INDEXED:
+            setIndexed( nIndex, fTint );
+            rStrm.skip( 4 );
+        break;
+        case BIFF12_COLOR_RGB:
+            setRgb( lclReadRgbColor( rStrm ), fTint );
+        break;
+        case BIFF12_COLOR_THEME:
+            setTheme( nIndex, fTint );
+            rStrm.skip( 4 );
+        break;
+        default:
+            OSL_FAIL( "Color::importColor - unknown color type" );
+            setAuto();
+            rStrm.skip( 4 );
+    }
+}
+
+void Color::importColorId( SequenceInputStream& rStrm )
+{
+    setIndexed( rStrm.readInt32() );
+}
+
+void Color::importColorId( BiffInputStream& rStrm, bool b16Bit )
+{
+    setIndexed( b16Bit ? rStrm.readuInt16() : rStrm.readuInt8() );
+}
+
+void Color::importColorRgb( BiffInputStream& rStrm )
+{
+    setRgb( lclReadRgbColor( rStrm ) );
+}
+
+SequenceInputStream& operator>>( SequenceInputStream& 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/BIFF12/OOXML. */
+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_OOXML:
+            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( SequenceInputStream& 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 );
+    }
+}
+
+void ColorPalette::importPalette( const Any& rPalette )
+{
+    Sequence< sal_Int32 > rColorSeq;
+    if( (rPalette >>= rColorSeq) && rColorSeq.hasElements() )
+    {
+        const sal_Int32* pnColor = rColorSeq.getConstArray();
+        const sal_Int32* pnColorEnd = pnColor + rColorSeq.getLength();
+        for( ; pnColor < pnColorEnd; ++pnColor )
+            appendColor( *pnColor & 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_FAIL( "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::setBiff12Scheme( 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  element
+        case XLS_TOKEN( rFont ):    // when in  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( SequenceInputStream& 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 all BIFFs for weight, underline, and escapement
+    maModel.setBiff12Scheme( nScheme );
+    maModel.setBiffHeight( nHeight );
+    maModel.setBiffWeight( nWeight );
+    maModel.setBiffUnderline( nUnderline );
+    maModel.setBiffEscapement( nEscapement );
+    maModel.mnFamily    = nFamily;
+    maModel.mnCharSet   = nCharSet;
+    // equal flags in all BIFFs
+    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( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Font::importDxfName - missing conditional formatting flag" );
+    maModel.maName = BiffHelper::readString( rStrm, false );
+    maUsedFlags.mbColorUsed = true;
+}
+
+void Font::importDxfColor( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Font::importDxfColor - missing conditional formatting flag" );
+    rStrm >> maModel.maColor;
+    maUsedFlags.mbColorUsed = true;
+}
+
+void Font::importDxfScheme( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Font::importDxfScheme - missing conditional formatting flag" );
+    maModel.setBiff12Scheme( rStrm.readuInt8() );
+    maUsedFlags.mbSchemeUsed = true;
+}
+
+void Font::importDxfHeight( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Font::importDxfHeight - missing conditional formatting flag" );
+    maModel.setBiffHeight( rStrm.readuInt16() );
+    maUsedFlags.mbHeightUsed = true;
+}
+
+void Font::importDxfWeight( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Font::importDxfWeight - missing conditional formatting flag" );
+    maModel.setBiffWeight( rStrm.readuInt16() );
+    maUsedFlags.mbWeightUsed = true;
+}
+
+void Font::importDxfUnderline( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Font::importDxfUnderline - missing conditional formatting flag" );
+    maModel.setBiffUnderline( rStrm.readuInt16() );
+    maUsedFlags.mbUnderlineUsed = true;
+}
+
+void Font::importDxfEscapement( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Font::importDxfEscapement - missing conditional formatting flag" );
+    maModel.setBiffEscapement( rStrm.readuInt16() );
+    maUsedFlags.mbEscapementUsed = true;
+}
+
+void Font::importDxfFlag( sal_Int32 nElement, SequenceInputStream& 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_FAIL( "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.isEmpty();
+    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 )
+    {
+        PropertySet aDocProps( getDocument() );
+        Reference< XDevice > xDevice( aDocProps.getAnyProperty( PROP_ReferenceDevice ), UNO_QUERY );
+        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.isEmpty() )
+        {
+            rPropMap[ PROP_CharFontName ]    <<= maApiData.maLatinFont.maName;
+            rPropMap[ PROP_CharFontFamily ]  <<= maApiData.maLatinFont.mnFamily;
+            rPropMap[ PROP_CharFontCharSet ] <<= maApiData.maLatinFont.mnTextEnc;
+        }
+        if( !maApiData.maAsianFont.maName.isEmpty() )
+        {
+            rPropMap[ PROP_CharFontNameAsian ]    <<= maApiData.maAsianFont.maName;
+            rPropMap[ PROP_CharFontFamilyAsian ]  <<= maApiData.maAsianFont.mnFamily;
+            rPropMap[ PROP_CharFontCharSetAsian ] <<= maApiData.maAsianFont.mnTextEnc;
+        }
+        if( !maApiData.maCmplxFont.maName.isEmpty() )
+        {
+            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 )
+    {
+        rPropMap[ PROP_CharEscapement ] <<= maApiData.mnEscapement;
+        if( ePropType == FONT_PROPTYPE_TEXT )
+            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::setBiffHorAlign( 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::setBiffVerAlign( 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::setBiffTextOrient( 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::setBiff12Data( sal_uInt32 nFlags )
+{
+    maModel.setBiffHorAlign( extractValue< sal_uInt8 >( nFlags, 16, 3 ) );
+    maModel.setBiffVerAlign( 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, BIFF12_XF_WRAPTEXT );
+    maModel.mbShrink       = getFlag( nFlags, BIFF12_XF_SHRINK );
+    maModel.mbJustLastLine = getFlag( nFlags, BIFF12_XF_JUSTLASTLINE );
+}
+
+void Alignment::setBiff2Data( sal_uInt8 nFlags )
+{
+    maModel.setBiffHorAlign( extractValue< sal_uInt8 >( nFlags, 0, 3 ) );
+}
+
+void Alignment::setBiff3Data( sal_uInt16 nAlign )
+{
+    maModel.setBiffHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+    maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT ); // new in BIFF3
+}
+
+void Alignment::setBiff4Data( sal_uInt16 nAlign )
+{
+    maModel.setBiffHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+    maModel.setBiffVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 2 ) ); // new in BIFF4
+    maModel.setBiffTextOrient( extractValue< sal_uInt8 >( nAlign, 6, 2 ) ); // new in BIFF4
+    maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT );
+}
+
+void Alignment::setBiff5Data( sal_uInt16 nAlign )
+{
+    maModel.setBiffHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+    maModel.setBiffVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 3 ) );
+    maModel.setBiffTextOrient( extractValue< sal_uInt8 >( nAlign, 8, 2 ) );
+    maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT );
+}
+
+void Alignment::setBiff8Data( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
+{
+    maModel.setBiffHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) );
+    maModel.setBiffVerAlign( 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
+        OOXML/BIFF12, and as multiple of 10 points in BIFF8. */
+    sal_Int32 nIndent = 0;
+    switch( getFilterType() )
+    {
+        case FILTER_OOXML:  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::setBiff12Data( sal_uInt32 nFlags )
+{
+    maModel.mbLocked = getFlag( nFlags, BIFF12_XF_LOCKED );
+    maModel.mbHidden = getFlag( nFlags, BIFF12_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);
+}
+
+} // 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;
+}
+
+} // 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( SequenceInputStream& rStrm )
+{
+    sal_uInt8 nFlags = rStrm.readuInt8();
+    maModel.mbDiagTLtoBR = getFlag( nFlags, BIFF12_BORDER_DIAG_TLBR );
+    maModel.mbDiagBLtoTR = getFlag( nFlags, BIFF12_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, SequenceInputStream& 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::setBiffPattern( 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 all BIFFs
+    setBiffPattern( nPattern );
+}
+
+// ----------------------------------------------------------------------------
+
+GradientFillModel::GradientFillModel() :
+    mnType( XML_linear ),
+    mfAngle( 0.0 ),
+    mfLeft( 0.0 ),
+    mfRight( 0.0 ),
+    mfTop( 0.0 ),
+    mfBottom( 0.0 )
+{
+}
+
+void GradientFillModel::readGradient( SequenceInputStream& 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( SequenceInputStream& 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( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( !mbDxf, "Fill::importFill - unexpected conditional formatting flag" );
+    sal_Int32 nPattern = rStrm.readInt32();
+    if( nPattern == BIFF12_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->setBiffPattern( nPattern );
+        rStrm >> mxPatternModel->maPatternColor >> mxPatternModel->maFillColor;
+    }
+}
+
+void Fill::importDxfPattern( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Fill::importDxfPattern - missing conditional formatting flag" );
+    if( !mxPatternModel )
+        mxPatternModel.reset( new PatternFillModel( mbDxf ) );
+    mxPatternModel->setBiffPattern( rStrm.readuInt8() );
+    mxPatternModel->mbPatternUsed = true;
+}
+
+void Fill::importDxfFgColor( SequenceInputStream& 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( SequenceInputStream& 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( SequenceInputStream& rStrm )
+{
+    OSL_ENSURE( mbDxf, "Fill::importDxfGradient - missing conditional formatting flag" );
+    if( !mxGradientModel )
+        mxGradientModel.reset( new GradientFillModel );
+    mxGradientModel->readGradient( rStrm );
+}
+
+void Fill::importDxfStop( SequenceInputStream& 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 OOXML 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::CellVertJustify2::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( SequenceInputStream& 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.setBiff12Data( nFlags );
+    maProtection.setBiff12Data( nFlags );
+    // used flags, see comments in Xf::setBiffUsedFlags()
+    sal_uInt16 nUsedFlags = rStrm.readuInt16();
+    maModel.mbFontUsed   = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_FONT_USED );
+    maModel.mbNumFmtUsed = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_NUMFMT_USED );
+    maModel.mbAlignUsed  = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_ALIGN_USED );
+    maModel.mbProtUsed   = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_PROT_USED );
+    maModel.mbBorderUsed = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_BORDER_USED );
+    maModel.mbAreaUsed   = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_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::CellVertJustify2::BOTTOM;
+    }
+}
+
+FontRef Xf::getFont() const
+{
+    return getStyles().getFont( maModel.mnFontId );
+}
+
+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;
+
+    sal_Int32 eRotRef = ::com::sun::star::table::CellVertJustify2::STANDARD;
+    if (maModel.mbBorderUsed && rStyles.hasBorder(maModel.mnBorderId) && maAlignment.getApiData().mnRotation)
+        eRotRef = ::com::sun::star::table::CellVertJustify2::BOTTOM;
+    rPropMap[ PROP_RotateReference ] <<= eRotRef;
+}
+
+void Xf::writeToPropertySet( PropertySet& rPropSet ) const
+{
+    PropertyMap aPropMap;
+    writeToPropertyMap( aPropMap );
+    rPropSet.setProperties( aPropMap );
+}
+
+/*static*/ void Xf::writeBiff2CellFormatToPropertySet( const WorkbookHelper& rHelper,
+        PropertySet& rPropSet, sal_uInt8 nFlags1, sal_uInt8 nFlags2, sal_uInt8 nFlags3 )
+{
+    /*  Create an XF object and let it do the work. We will have access to its
+        private members here. Also, create temporary border and fill objects,
+        this prevents polluting the border and fill buffers with new temporary
+        objects per imported cell. */
+    Xf aXf( rHelper );
+    Border aBorder( rHelper, false );
+    Fill aFill( rHelper, false );
+
+    // no used flags available in BIFF2 (always true)
+    aXf.setAllUsedFlags( true );
+
+    // set the attributes
+    aXf.maModel.mnFontId = extractValue< sal_Int32 >( nFlags2, 6, 2 );
+    aXf.maModel.mnNumFmtId = extractValue< sal_Int32 >( nFlags2, 0, 6 );
+    aXf.maAlignment.setBiff2Data( nFlags3 );
+    aXf.maProtection.setBiff2Data( nFlags1 );
+    aBorder.setBiff2Data( nFlags3 );
+    aFill.setBiff2Data( nFlags3 );
+
+    // finalize the objects (convert model to API attributes)
+    aXf.finalizeImport();
+    aBorder.finalizeImport();
+    aFill.finalizeImport();
+
+    // write the properties to the property set
+    PropertyMap aPropMap;
+    aXf.writeToPropertyMap( aPropMap );
+    aBorder.writeToPropertyMap( aPropMap );
+    aFill.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::importDxf( SequenceInputStream& 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 BIFF12_DXF_FILL_PATTERN:       createFill( false )->importDxfPattern( rStrm );                         break;
+            case BIFF12_DXF_FILL_FGCOLOR:       createFill( false )->importDxfFgColor( rStrm );                         break;
+            case BIFF12_DXF_FILL_BGCOLOR:       createFill( false )->importDxfBgColor( rStrm );                         break;
+            case BIFF12_DXF_FILL_GRADIENT:      createFill( false )->importDxfGradient( rStrm );                        break;
+            case BIFF12_DXF_FILL_STOP:          createFill( false )->importDxfStop( rStrm );                            break;
+            case BIFF12_DXF_FONT_COLOR:         createFont( false )->importDxfColor( rStrm );                           break;
+            case BIFF12_DXF_BORDER_TOP:         createBorder( false )->importDxfBorder( XLS_TOKEN( top ), rStrm );      break;
+            case BIFF12_DXF_BORDER_BOTTOM:      createBorder( false )->importDxfBorder( XLS_TOKEN( bottom ), rStrm );   break;
+            case BIFF12_DXF_BORDER_LEFT:        createBorder( false )->importDxfBorder( XLS_TOKEN( left ), rStrm );     break;
+            case BIFF12_DXF_BORDER_RIGHT:       createBorder( false )->importDxfBorder( XLS_TOKEN( right ), rStrm );    break;
+            case BIFF12_DXF_FONT_NAME:          createFont( false )->importDxfName( rStrm );                            break;
+            case BIFF12_DXF_FONT_WEIGHT:        createFont( false )->importDxfWeight( rStrm );                          break;
+            case BIFF12_DXF_FONT_UNDERLINE:     createFont( false )->importDxfUnderline( rStrm );                       break;
+            case BIFF12_DXF_FONT_ESCAPEMENT:    createFont( false )->importDxfEscapement( rStrm );                      break;
+            case BIFF12_DXF_FONT_ITALIC:        createFont( false )->importDxfFlag( XML_i, rStrm );                     break;
+            case BIFF12_DXF_FONT_STRIKE:        createFont( false )->importDxfFlag( XML_strike, rStrm );                break;
+            case BIFF12_DXF_FONT_OUTLINE:       createFont( false )->importDxfFlag( XML_outline, rStrm );               break;
+            case BIFF12_DXF_FONT_SHADOW:        createFont( false )->importDxfFlag( XML_shadow, rStrm );                break;
+            case BIFF12_DXF_FONT_HEIGHT:        createFont( false )->importDxfHeight( rStrm );                          break;
+            case BIFF12_DXF_FONT_SCHEME:        createFont( false )->importDxfScheme( rStrm );                          break;
+            case BIFF12_DXF_NUMFMT_CODE:        aFmtCode = BiffHelper::readString( rStrm, false );                      break;
+            case BIFF12_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.isEmpty() )
+        aStyleName.append( rName );
+    else
+        aStyleName.append( nBuiltinId );
+    if( (nBuiltinId == OOX_STYLE_ROWLEVEL) || (nBuiltinId == OOX_STYLE_COLLEVEL) )
+        aStyleName.append( nLevel );
+    return aStyleName.makeStringAndClear();
+}
+
+} // 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( SequenceInputStream& rStrm )
+{
+    sal_uInt16 nFlags;
+    rStrm >> maModel.mnXfId >> nFlags;
+    maModel.mnBuiltinId = rStrm.readInt8();
+    maModel.mnLevel = rStrm.readInt8();
+    rStrm >> maModel.maName;
+    maModel.mbBuiltin = getFlag( nFlags, BIFF12_CELLSTYLE_BUILTIN );
+    maModel.mbCustom = getFlag( nFlags, BIFF12_CELLSTYLE_CUSTOM );
+    maModel.mbHidden = getFlag( nFlags, BIFF12_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.isEmpty();
+
+    /*  #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( SequenceInputStream& 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.isEmpty() )
+        {
+            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 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.isEmpty() )
+            return rStyleName;
+    }
+    // on error: fallback to default style
+    return lclGetBuiltinStyleName( OOX_STYLE_NORMAL, OUString() );
+}
+
+// ============================================================================
+
+AutoFormatModel::AutoFormatModel() :
+    mnAutoFormatId( 0 ),
+    mbApplyNumFmt( false ),
+    mbApplyFont( false ),
+    mbApplyAlignment( false ),
+    mbApplyBorder( false ),
+    mbApplyFill( false ),
+    mbApplyProtection( false )
+{
+}
+
+// ============================================================================
+
+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( SequenceInputStream& rStrm )
+{
+    maPalette.importPaletteColor( rStrm );
+}
+
+void StylesBuffer::importNumFmt( SequenceInputStream& rStrm )
+{
+    maNumFmts.importNumFmt( rStrm );
+}
+
+void StylesBuffer::importCellStyle( SequenceInputStream& 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::importPalette( const Any& rPalette )
+{
+    maPalette.importPalette( rPalette );
+}
+
+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 );
+}
+
+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_OOXML:
+            // 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_OOXML:
+            // 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.isEmpty() )
+    {
+        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.isEmpty() )
+            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::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/sc/source/filter/oox/stylesfragment.cxx b/sc/source/filter/oox/stylesfragment.cxx
new file mode 100644
index 000000000000..d301135d905b
--- /dev/null
+++ b/sc/source/filter/oox/stylesfragment.cxx
@@ -0,0 +1,332 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "stylesfragment.hxx"
+
+#include "oox/helper/attributelist.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+IndexedColorsContext::IndexedColorsContext( WorkbookFragmentBase& rFragment ) :
+    WorkbookContextBase( rFragment )
+{
+}
+
+ContextHandlerRef IndexedColorsContext::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 IndexedColorsContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case BIFF12_ID_INDEXEDCOLORS:
+            if( nRecId == BIFF12_ID_RGBCOLOR ) getStyles().importPaletteColor( rStrm );
+        break;
+    }
+    return 0;
+}
+
+// ============================================================================
+
+ContextHandlerRef FontContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    if( mxFont.get() )
+        mxFont->importAttribs( nElement, rAttribs );
+    return 0;
+}
+
+// ============================================================================
+
+void BorderContext::onStartElement( const AttributeList& rAttribs )
+{
+    if( mxBorder.get() && (getCurrentElement() == XLS_TOKEN( border )) )
+        mxBorder->importBorder( rAttribs );
+}
+
+ContextHandlerRef BorderContext::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 FillContext::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 XfContext::onStartElement( const AttributeList& rAttribs )
+{
+    if( mxXf.get() && (getCurrentElement() == XLS_TOKEN( xf )) )
+        mxXf->importXf( rAttribs, mbCellXf );
+}
+
+ContextHandlerRef XfContext::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 DxfContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    if( mxDxf.get() ) switch( getCurrentElement() )
+    {
+        case XLS_TOKEN( dxf ):
+            switch( nElement )
+            {
+                case XLS_TOKEN( font ):         return new FontContext( *this, mxDxf->createFont() );
+                case XLS_TOKEN( border ):       return new BorderContext( *this, mxDxf->createBorder() );
+                case XLS_TOKEN( fill ):         return new FillContext( *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;
+}
+
+// ============================================================================
+
+StylesFragment::StylesFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+    WorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+ContextHandlerRef StylesFragment::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 IndexedColorsContext( *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 FontContext( *this, getStyles().createFont() );
+        break;
+        case XLS_TOKEN( borders ):
+            if( nElement == XLS_TOKEN( border ) ) return new BorderContext( *this, getStyles().createBorder() );
+        break;
+        case XLS_TOKEN( fills ):
+            if( nElement == XLS_TOKEN( fill ) ) return new FillContext( *this, getStyles().createFill() );
+        break;
+        case XLS_TOKEN( cellXfs ):
+            if( nElement == XLS_TOKEN( xf ) ) return new XfContext( *this, getStyles().createCellXf(), true );
+        break;
+        case XLS_TOKEN( cellStyleXfs ):
+            if( nElement == XLS_TOKEN( xf ) ) return new XfContext( *this, getStyles().createStyleXf(), false );
+        break;
+        case XLS_TOKEN( dxfs ):
+            if( nElement == XLS_TOKEN( dxf ) ) return new DxfContext( *this, getStyles().createDxf() );
+        break;
+        case XLS_TOKEN( cellStyles ):
+            if( nElement == XLS_TOKEN( cellStyle ) ) getStyles().importCellStyle( rAttribs );
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef StylesFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_STYLESHEET ) return this;
+        break;
+
+        case BIFF12_ID_STYLESHEET:
+            switch( nRecId )
+            {
+                case BIFF12_ID_COLORS:
+                case BIFF12_ID_NUMFMTS:
+                case BIFF12_ID_FONTS:
+                case BIFF12_ID_BORDERS:
+                case BIFF12_ID_FILLS:
+                case BIFF12_ID_CELLXFS:
+                case BIFF12_ID_CELLSTYLEXFS:
+                case BIFF12_ID_DXFS:
+                case BIFF12_ID_CELLSTYLES:      return this;
+            }
+        break;
+
+        case BIFF12_ID_COLORS:
+            if( nRecId == BIFF12_ID_INDEXEDCOLORS ) return new IndexedColorsContext( *this );
+        break;
+        case BIFF12_ID_NUMFMTS:
+            if( nRecId == BIFF12_ID_NUMFMT ) getStyles().importNumFmt( rStrm );
+        break;
+        case BIFF12_ID_FONTS:
+            if( nRecId == BIFF12_ID_FONT ) getStyles().createFont()->importFont( rStrm );
+        break;
+        case BIFF12_ID_BORDERS:
+            if( nRecId == BIFF12_ID_BORDER ) getStyles().createBorder()->importBorder( rStrm );
+        break;
+        case BIFF12_ID_FILLS:
+            if( nRecId == BIFF12_ID_FILL ) getStyles().createFill()->importFill( rStrm );
+        break;
+        case BIFF12_ID_CELLXFS:
+            if( nRecId == BIFF12_ID_XF ) getStyles().createCellXf()->importXf( rStrm, true );
+        break;
+        case BIFF12_ID_CELLSTYLEXFS:
+            if( nRecId == BIFF12_ID_XF ) getStyles().createStyleXf()->importXf( rStrm, false );
+        break;
+        case BIFF12_ID_DXFS:
+            if( nRecId == BIFF12_ID_DXF ) getStyles().createDxf()->importDxf( rStrm );
+        break;
+        case BIFF12_ID_CELLSTYLES:
+            if( nRecId == BIFF12_ID_CELLSTYLE ) getStyles().importCellStyle( rStrm );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* StylesFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_BORDERS,        BIFF12_ID_BORDERS + 1       },
+        { BIFF12_ID_CELLSTYLES,     BIFF12_ID_CELLSTYLES + 1    },
+        { BIFF12_ID_CELLSTYLEXFS,   BIFF12_ID_CELLSTYLEXFS + 1  },
+        { BIFF12_ID_CELLXFS,        BIFF12_ID_CELLXFS + 1       },
+        { BIFF12_ID_COLORS,         BIFF12_ID_COLORS + 1        },
+        { BIFF12_ID_DXFS,           BIFF12_ID_DXFS + 1          },
+        { BIFF12_ID_FILLS,          BIFF12_ID_FILLS + 1         },
+        { BIFF12_ID_FONTS,          BIFF12_ID_FONTS + 1         },
+        { BIFF12_ID_INDEXEDCOLORS,  BIFF12_ID_INDEXEDCOLORS + 1 },
+        { BIFF12_ID_MRUCOLORS,      BIFF12_ID_MRUCOLORS + 1     },
+        { BIFF12_ID_NUMFMTS,        BIFF12_ID_NUMFMTS + 1       },
+        { BIFF12_ID_STYLESHEET,     BIFF12_ID_STYLESHEET + 1    },
+        { BIFF12_ID_TABLESTYLES,    BIFF12_ID_TABLESTYLES + 1   },
+        { -1,                       -1                          }
+    };
+    return spRecInfos;
+}
+
+void StylesFragment::finalizeImport()
+{
+    getStyles().finalizeImport();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/tablebuffer.cxx b/sc/source/filter/oox/tablebuffer.cxx
new file mode 100644
index 000000000000..a2c98220afcd
--- /dev/null
+++ b/sc/source/filter/oox/tablebuffer.cxx
@@ -0,0 +1,171 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "tablebuffer.hxx"
+
+#include 
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+TableModel::TableModel() :
+    mnId( -1 ),
+    mnType( XML_worksheet ),
+    mnHeaderRows( 1 ),
+    mnTotalsRows( 0 )
+{
+}
+
+// ============================================================================
+
+Table::Table( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper ),
+    maAutoFilters( 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( SequenceInputStream& 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()
+{
+    // Create database range.  Note that Excel 2007 and later names database
+    // ranges (or tables in their terminology) as Table1, Table2 etc.  We need
+    // to import them as named db ranges because they may be referenced by
+    // name in formula expressions.
+    if( (maModel.mnId > 0) && !maModel.maDisplayName.isEmpty() ) try
+    {
+        maDBRangeName = maModel.maDisplayName;
+        Reference< XDatabaseRange > xDatabaseRange(
+            createDatabaseRangeObject( maDBRangeName, maModel.maRange ), UNO_SET_THROW);
+        maDestRange = xDatabaseRange->getDataArea();
+
+        // get formula token index of the database range
+        PropertySet aPropSet( xDatabaseRange );
+        if( !aPropSet.getProperty( mnTokenIndex, PROP_TokenIndex ) )
+            mnTokenIndex = -1;
+
+        // filter settings
+        maAutoFilters.finalizeImport( xDatabaseRange );
+    }
+    catch( Exception& )
+    {
+        OSL_FAIL( "Table::finalizeImport - cannot create database range" );
+    }
+}
+
+// ============================================================================
+
+TableBuffer::TableBuffer( const WorkbookHelper& rHelper ) :
+    WorkbookHelper( rHelper )
+{
+}
+
+Table& TableBuffer::createTable()
+{
+    TableVector::value_type xTable( new Table( *this ) );
+    maTables.push_back( xTable );
+    return *xTable;
+}
+
+void TableBuffer::finalizeImport()
+{
+    // map all tables by identifier and display name
+    for( TableVector::iterator aIt = maTables.begin(), aEnd = maTables.end(); aIt != aEnd; ++aIt )
+        insertTableToMaps( *aIt );
+    // finalize all valid tables
+    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::insertTableToMaps( const TableRef& rxTable )
+{
+    sal_Int32 nTableId = rxTable->getTableId();
+    const OUString& rDispName = rxTable->getDisplayName();
+    if( (nTableId > 0) && !rDispName.isEmpty() )
+    {
+        OSL_ENSURE( !maIdTables.has( nTableId ), "TableBuffer::insertTableToMaps - multiple table identifier" );
+        maIdTables[ nTableId ] = rxTable;
+        OSL_ENSURE( !maNameTables.has( rDispName ), "TableBuffer::insertTableToMaps - multiple table name" );
+        maNameTables[ rDispName ] = rxTable;
+    }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/tablefragment.cxx b/sc/source/filter/oox/tablefragment.cxx
new file mode 100644
index 000000000000..28953f366f7e
--- /dev/null
+++ b/sc/source/filter/oox/tablefragment.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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "tablefragment.hxx"
+
+#include "autofilterbuffer.hxx"
+#include "autofiltercontext.hxx"
+#include "tablebuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+TableFragment::TableFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    WorksheetFragmentBase( rHelper, rFragmentPath ),
+    mrTable( getTables().createTable() )
+{
+}
+
+ContextHandlerRef TableFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nElement == XLS_TOKEN( table ) )
+            {
+                mrTable.importTable( rAttribs, getSheetIndex() );
+                return this;
+            }
+        break;
+        case XLS_TOKEN( table ):
+            if( nElement == XLS_TOKEN( autoFilter ) )
+                return new AutoFilterContext( *this, mrTable.createAutoFilter() );
+        break;
+    }
+    return 0;
+}
+
+ContextHandlerRef TableFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_TABLE )
+            {
+                mrTable.importTable( rStrm, getSheetIndex() );
+                return this;
+            }
+        break;
+        case BIFF12_ID_TABLE:
+            if( nRecId == BIFF12_ID_AUTOFILTER )
+                return new AutoFilterContext( *this, mrTable.createAutoFilter() );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* TableFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_AUTOFILTER,         BIFF12_ID_AUTOFILTER + 1        },
+        { BIFF12_ID_CUSTOMFILTERS,      BIFF12_ID_CUSTOMFILTERS + 1     },
+        { BIFF12_ID_DISCRETEFILTERS,    BIFF12_ID_DISCRETEFILTERS + 1   },
+        { BIFF12_ID_FILTERCOLUMN,       BIFF12_ID_FILTERCOLUMN + 1      },
+        { BIFF12_ID_TABLE,              BIFF12_ID_TABLE + 1             },
+        { -1,                           -1                              }
+    };
+    return spRecInfos;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/themebuffer.cxx b/sc/source/filter/oox/themebuffer.cxx
new file mode 100644
index 000000000000..2d3682e4c1a5
--- /dev/null
+++ b/sc/source/filter/oox/themebuffer.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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "themebuffer.hxx"
+
+#include "stylesbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using ::oox::drawingml::ClrScheme;
+
+// ============================================================================
+
+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_OOXML:
+            //! 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/sc/source/filter/oox/unitconverter.cxx b/sc/source/filter/oox/unitconverter.cxx
new file mode 100644
index 000000000000..86112043370f
--- /dev/null
+++ b/sc/source/filter/oox/unitconverter.cxx
@@ -0,0 +1,255 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "unitconverter.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "stylesbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+using ::rtl::OUString;
+
+// ============================================================================
+
+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()
+{
+    PropertySet aDocProps( getDocument() );
+    Reference< XDevice > xDevice( aDocProps.getAnyProperty( PROP_ReferenceDevice ), UNO_QUERY );
+    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;
+}
+
+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;
+}
+
+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/sc/source/filter/oox/viewsettings.cxx b/sc/source/filter/oox/viewsettings.cxx
new file mode 100644
index 000000000000..ec954fce0f78
--- /dev/null
+++ b/sc/source/filter/oox/viewsettings.cxx
@@ -0,0 +1,832 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "viewsettings.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertymap.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "unitconverter.hxx"
+#include "workbooksettings.hxx"
+#include "worksheetbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::FilterBase;
+using ::rtl::OUString;
+
+// ============================================================================
+
+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 BIFF12_PANE_FROZEN                  = 0x01;
+const sal_uInt8 BIFF12_PANE_FROZENNOSPLIT           = 0x02;
+
+const sal_uInt16 BIFF12_SHEETVIEW_WINPROTECTED      = 0x0001;
+const sal_uInt16 BIFF12_SHEETVIEW_SHOWFORMULAS      = 0x0002;
+const sal_uInt16 BIFF12_SHEETVIEW_SHOWGRID          = 0x0004;
+const sal_uInt16 BIFF12_SHEETVIEW_SHOWHEADINGS      = 0x0008;
+const sal_uInt16 BIFF12_SHEETVIEW_SHOWZEROS         = 0x0010;
+const sal_uInt16 BIFF12_SHEETVIEW_RIGHTTOLEFT       = 0x0020;
+const sal_uInt16 BIFF12_SHEETVIEW_SELECTED          = 0x0040;
+const sal_uInt16 BIFF12_SHEETVIEW_SHOWRULER         = 0x0080;
+const sal_uInt16 BIFF12_SHEETVIEW_SHOWOUTLINE       = 0x0100;
+const sal_uInt16 BIFF12_SHEETVIEW_DEFGRIDCOLOR      = 0x0200;
+const sal_uInt16 BIFF12_SHEETVIEW_SHOWWHITESPACE    = 0x0400;
+
+const sal_uInt16 BIFF12_CHARTSHEETVIEW_SELECTED     = 0x0001;
+const sal_uInt16 BIFF12_CHARTSHEETVIEW_ZOOMTOFIT    = 0x0002;
+
+const sal_uInt8 BIFF12_WBVIEW_HIDDEN                = 0x01;
+const sal_uInt8 BIFF12_WBVIEW_MINIMIZED             = 0x02;
+const sal_uInt8 BIFF12_WBVIEW_SHOWHORSCROLL         = 0x08;
+const sal_uInt8 BIFF12_WBVIEW_SHOWVERSCROLL         = 0x10;
+const sal_uInt8 BIFF12_WBVIEW_SHOWTABBAR            = 0x20;
+const sal_uInt8 BIFF12_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 BIFF pane id. */
+sal_Int32 lclGetOoxPaneId( sal_Int32 nBiffPaneId, sal_Int32 nDefaultPaneId )
+{
+    static const sal_Int32 spnPaneIds[] = { XML_bottomRight, XML_topRight, XML_bottomLeft, XML_topLeft };
+    return STATIC_ARRAY_SELECT( spnPaneIds, nBiffPaneId, 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( SequenceInputStream& 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, BIFF12_SHEETVIEW_SELECTED );
+    rModel.mbRightToLeft  = getFlag( nFlags, BIFF12_SHEETVIEW_RIGHTTOLEFT );
+    rModel.mbDefGridColor = getFlag( nFlags, BIFF12_SHEETVIEW_DEFGRIDCOLOR );
+    rModel.mbShowFormulas = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWFORMULAS );
+    rModel.mbShowGrid     = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWGRID );
+    rModel.mbShowHeadings = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWHEADINGS );
+    rModel.mbShowZeros    = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWZEROS );
+    rModel.mbShowOutline  = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWOUTLINE );
+}
+
+void SheetViewSettings::importPane( SequenceInputStream& 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, BIFF12_PANE_FROZEN, getFlagValue( nFlags, BIFF12_PANE_FROZENNOSPLIT, XML_frozen, XML_frozenSplit ), XML_split );
+    }
+}
+
+void SheetViewSettings::importSelection( SequenceInputStream& 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( SequenceInputStream& rStrm )
+{
+    SheetViewModel& rModel = *createSheetView();
+    sal_uInt16 nFlags;
+    rStrm >> nFlags >> rModel.mnCurrentZoom >> rModel.mnWorkbookViewId;
+
+    rModel.mbSelected  = getFlag( nFlags, BIFF12_CHARTSHEETVIEW_SELECTED );
+    rModel.mbZoomToFit = getFlag( nFlags, BIFF12_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;
+    }
+
+    // sheet selected (active sheet must be selected)
+    bool bSelected = xModel->mbSelected || (getSheetIndex() == getViewSettings().getActiveCalcSheet());
+    if ( bSelected )
+    {
+        // active tab/sheet cannot be hidden
+        // always force it to be displayed
+        PropertySet aPropSet( getSheet() );
+        aPropSet.setProperty( PROP_IsVisible, sal_True );
+    }
+    // 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() ) );
+}
+
+bool SheetViewSettings::isSheetRightToLeft() const
+{
+    return !maSheetViews.empty() && maSheetViews.front()->mbRightToLeft;
+}
+
+// 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( SequenceInputStream& 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, BIFF12_WBVIEW_HIDDEN, XML_hidden, XML_visible );
+    rModel.mbShowTabBar    = getFlag( nFlags, BIFF12_WBVIEW_SHOWTABBAR );
+    rModel.mbShowHorScroll = getFlag( nFlags, BIFF12_WBVIEW_SHOWHORSCROLL );
+    rModel.mbShowVerScroll = getFlag( nFlags, BIFF12_WBVIEW_SHOWVERSCROLL );
+    rModel.mbMinimized     = getFlag( nFlags, BIFF12_WBVIEW_MINIMIZED );
+}
+
+void ViewSettings::importOleSize( SequenceInputStream& 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( getBaseFilter().getComponentContext() );
+    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( getBaseFilter().getComponentContext() );
+    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_FAIL( "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/sc/source/filter/oox/workbookfragment.cxx b/sc/source/filter/oox/workbookfragment.cxx
new file mode 100644
index 000000000000..4d079e0cfce3
--- /dev/null
+++ b/sc/source/filter/oox/workbookfragment.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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "workbookfragment.hxx"
+
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/drawingml/themefragmenthandler.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/progressbar.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/ole/olestorage.hxx"
+#include "biffinputstream.hxx"
+#include "chartsheetfragment.hxx"
+#include "connectionsfragment.hxx"
+#include "externallinkbuffer.hxx"
+#include "externallinkfragment.hxx"
+#include "pivotcachebuffer.hxx"
+#include "sharedstringsbuffer.hxx"
+#include "sharedstringsfragment.hxx"
+#include "stylesfragment.hxx"
+#include "tablebuffer.hxx"
+#include "themebuffer.hxx"
+#include "viewsettings.hxx"
+#include "workbooksettings.hxx"
+#include "worksheetbuffer.hxx"
+#include "worksheetfragment.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sheet;
+using namespace ::oox::core;
+
+using ::oox::drawingml::ThemeFragmentHandler;
+using ::rtl::OUString;
+
+// ============================================================================
+
+namespace {
+
+const double PROGRESS_LENGTH_GLOBALS        = 0.1;      /// 10% of progress bar for globals import.
+
+} // namespace
+
+// ============================================================================
+
+WorkbookFragment::WorkbookFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
+    WorkbookFragmentBase( rHelper, rFragmentPath )
+{
+}
+
+ContextHandlerRef WorkbookFragment::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 WorkbookFragment::onCharacters( const OUString& rChars )
+{
+    if( isCurrentElement( XLS_TOKEN( definedName ) ) && mxCurrName.get() )
+        mxCurrName->setFormula( rChars );
+}
+
+ContextHandlerRef WorkbookFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_WORKBOOK ) return this;
+        break;
+
+        case BIFF12_ID_WORKBOOK:
+            switch( nRecId )
+            {
+                case BIFF12_ID_SHEETS:
+                case BIFF12_ID_BOOKVIEWS:
+                case BIFF12_ID_EXTERNALREFS:
+                case BIFF12_ID_PIVOTCACHES:     return this;
+
+                case BIFF12_ID_FILESHARING:     getWorkbookSettings().importFileSharing( rStrm );   break;
+                case BIFF12_ID_WORKBOOKPR:      getWorkbookSettings().importWorkbookPr( rStrm );    break;
+                case BIFF12_ID_CALCPR:          getWorkbookSettings().importCalcPr( rStrm );        break;
+                case BIFF12_ID_OLESIZE:         getViewSettings().importOleSize( rStrm );           break;
+                case BIFF12_ID_DEFINEDNAME:     getDefinedNames().importDefinedName( rStrm );       break;
+            }
+        break;
+
+        case BIFF12_ID_SHEETS:
+            if( nRecId == BIFF12_ID_SHEET ) getWorksheets().importSheet( rStrm );
+        break;
+        case BIFF12_ID_BOOKVIEWS:
+            if( nRecId == BIFF12_ID_WORKBOOKVIEW ) getViewSettings().importWorkbookView( rStrm );
+        break;
+
+        case BIFF12_ID_EXTERNALREFS:
+            switch( nRecId )
+            {
+                case BIFF12_ID_EXTERNALREF:     importExternalRef( rStrm );                         break;
+                case BIFF12_ID_EXTERNALSELF:    getExternalLinks().importExternalSelf( rStrm );     break;
+                case BIFF12_ID_EXTERNALSAME:    getExternalLinks().importExternalSame( rStrm );     break;
+                case BIFF12_ID_EXTERNALADDIN:   getExternalLinks().importExternalAddin( rStrm );    break;
+                case BIFF12_ID_EXTERNALSHEETS:  getExternalLinks().importExternalSheets( rStrm );   break;
+            }
+        break;
+
+        case BIFF12_ID_PIVOTCACHES:
+            if( nRecId == BIFF12_ID_PIVOTCACHE ) importPivotCache( rStrm );
+    }
+    return 0;
+}
+
+const RecordInfo* WorkbookFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_BOOKVIEWS,      BIFF12_ID_BOOKVIEWS + 1         },
+        { BIFF12_ID_EXTERNALREFS,   BIFF12_ID_EXTERNALREFS + 1      },
+        { BIFF12_ID_FUNCTIONGROUPS, BIFF12_ID_FUNCTIONGROUPS + 2    },
+        { BIFF12_ID_PIVOTCACHE,     BIFF12_ID_PIVOTCACHE + 1        },
+        { BIFF12_ID_PIVOTCACHES,    BIFF12_ID_PIVOTCACHES + 1       },
+        { BIFF12_ID_SHEETS,         BIFF12_ID_SHEETS + 1            },
+        { BIFF12_ID_WORKBOOK,       BIFF12_ID_WORKBOOK + 1          },
+        { -1,                       -1                              }
+    };
+    return spRecInfos;
+}
+
+void WorkbookFragment::finalizeImport()
+{
+    ISegmentProgressBarRef xGlobalSegment = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
+
+    // read the theme substream
+    OUString aThemeFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "theme" ) );
+    if( !aThemeFragmentPath.isEmpty() )
+        importOoxFragment( new ThemeFragmentHandler( getFilter(), aThemeFragmentPath, getTheme() ) );
+    xGlobalSegment->setPosition( 0.25 );
+
+    // read the styles substream (requires finalized theme buffer)
+    OUString aStylesFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "styles" ) );
+    if( !aStylesFragmentPath.isEmpty() )
+        importOoxFragment( new StylesFragment( *this, aStylesFragmentPath ) );
+    xGlobalSegment->setPosition( 0.5 );
+
+    // read the shared string table substream (requires finalized styles buffer)
+    OUString aSstFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "sharedStrings" ) );
+    if( !aSstFragmentPath.isEmpty() )
+        importOoxFragment( new SharedStringsFragment( *this, aSstFragmentPath ) );
+    xGlobalSegment->setPosition( 0.75 );
+
+    // read the connections substream
+    OUString aConnFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "connections" ) );
+    if( !aConnFragmentPath.isEmpty() )
+        importOoxFragment( new ConnectionsFragment( *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. Additionally, the instances of the WorkbookGlobals structures
+        have to be stored for every sheet. */
+    typedef ::std::pair< WorksheetGlobalsRef, FragmentHandlerRef > SheetFragmentHandler;
+    typedef ::std::vector< SheetFragmentHandler > 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.isEmpty(), "WorkbookFragment::finalizeImport - cannot access sheet fragment" );
+            if( !aFragmentPath.isEmpty() )
+            {
+                double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
+                ISegmentProgressBarRef xSheetSegment = getProgressBar().createSegment( fSegmentLength );
+
+                // get the sheet type according to the relations type
+                WorksheetType eSheetType = SHEETTYPE_EMPTYSHEET;
+                if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "worksheet" ) )
+                    eSheetType = SHEETTYPE_WORKSHEET;
+                else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "chartsheet" ) )
+                    eSheetType = SHEETTYPE_CHARTSHEET;
+                else if( (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlMacrosheet" )) ||
+                         (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlIntlMacrosheet" )) )
+                    eSheetType = SHEETTYPE_MACROSHEET;
+                else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "dialogsheet" ) )
+                    eSheetType = SHEETTYPE_DIALOGSHEET;
+                OSL_ENSURE( eSheetType != SHEETTYPE_EMPTYSHEET, "WorkbookFragment::finalizeImport - unknown sheet type" );
+                if( eSheetType != SHEETTYPE_EMPTYSHEET )
+                {
+                    // create the WorksheetGlobals object
+                    WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, xSheetSegment, eSheetType, nCalcSheet );
+                    OSL_ENSURE( xSheetGlob.get(), "WorkbookFragment::finalizeImport - missing sheet in document" );
+                    if( xSheetGlob.get() )
+                    {
+                        // create the sheet fragment handler
+                        ::rtl::Reference< WorksheetFragmentBase > xFragment;
+                        switch( eSheetType )
+                        {
+                            case SHEETTYPE_WORKSHEET:
+                            case SHEETTYPE_MACROSHEET:
+                            case SHEETTYPE_DIALOGSHEET:
+                                xFragment.set( new WorksheetFragment( *xSheetGlob, aFragmentPath ) );
+                            break;
+                            case SHEETTYPE_CHARTSHEET:
+                                xFragment.set( new ChartsheetFragment( *xSheetGlob, aFragmentPath ) );
+                            break;
+                            default:
+                                OSL_ENSURE( false, "WorkbookFragment::finalizeImport - unexpected sheet type" );
+                        }
+
+                        // insert the fragment into the map
+                        if( xFragment.is() )
+                            aSheetFragments.push_back( SheetFragmentHandler( xSheetGlob, 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->second );
+        // delete fragment object and WorkbookGlobals object, will free all allocated sheet buffers
+        aIt->second.clear();
+        aIt->first.reset();
+    }
+
+    // open the VBA project storage
+    OUString aVbaFragmentPath = getFragmentPathFromFirstType( CREATE_MSOFFICE_RELATION_TYPE( "vbaProject" ) );
+    if( !aVbaFragmentPath.isEmpty() )
+    {
+        Reference< XInputStream > xInStrm = getBaseFilter().openInputStream( aVbaFragmentPath );
+        if( xInStrm.is() )
+            setVbaProjectStorage( StorageRef( new ::oox::ole::OleStorage( getBaseFilter().getComponentContext(), xInStrm, false ) ) );
+    }
+
+    // final conversions, e.g. calculation settings and view settings
+    finalizeWorkbookImport();
+
+    // Recalculate (only changed ones)
+    Reference< XCalculatable > xCalculatable( getDocument(), UNO_QUERY );
+    if( xCalculatable.is() )
+        xCalculatable->calculate();
+}
+
+// private --------------------------------------------------------------------
+
+void WorkbookFragment::importExternalReference( const AttributeList& rAttribs )
+{
+    if( ExternalLink* pExtLink = getExternalLinks().importExternalReference( rAttribs ).get() )
+        importExternalLinkFragment( *pExtLink );
+}
+
+void WorkbookFragment::importDefinedName( const AttributeList& rAttribs )
+{
+    mxCurrName = getDefinedNames().importDefinedName( rAttribs );
+}
+
+void WorkbookFragment::importPivotCache( const AttributeList& rAttribs )
+{
+    sal_Int32 nCacheId = rAttribs.getInteger( XML_cacheId, -1 );
+    OUString aRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
+    importPivotCacheDefFragment( aRelId, nCacheId );
+}
+
+void WorkbookFragment::importExternalRef( SequenceInputStream& rStrm )
+{
+    if( ExternalLink* pExtLink = getExternalLinks().importExternalRef( rStrm ).get() )
+        importExternalLinkFragment( *pExtLink );
+}
+
+void WorkbookFragment::importPivotCache( SequenceInputStream& rStrm )
+{
+    sal_Int32 nCacheId = rStrm.readInt32();
+    OUString aRelId = BiffHelper::readString( rStrm );
+    importPivotCacheDefFragment( aRelId, nCacheId );
+}
+
+void WorkbookFragment::importExternalLinkFragment( ExternalLink& rExtLink )
+{
+    OUString aFragmentPath = getFragmentPathFromRelId( rExtLink.getRelId() );
+    if( !aFragmentPath.isEmpty() )
+        importOoxFragment( new ExternalLinkFragment( *this, aFragmentPath, rExtLink ) );
+}
+
+void WorkbookFragment::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:
+        {
+            BiffInputStream& rStrm = getInputStream();
+            // 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 )
+            {
+                // calculate progress size for the sheet
+                double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
+                ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength );
+                /*  Try to start a new sheet fragment. The SHEET records point to the
+                    first record of the sheet fragment which is usually a BOF record. */
+                BiffFragmentType eSheetFragment = BIFF_FRAGMENT_UNKNOWN;
+                sal_Int64 nRecHandle = rWorksheets.getBiffRecordHandle( nWorksheet );
+                if( rStrm.startRecordByHandle( nRecHandle ) )
+                {
+                    /*  #i109800# Stream may point to any record of the sheet fragment.
+                        Check the record identifier before calling startFragment(). */
+                    bool bIsBofRec = BiffHelper::isBofRecord( rStrm );
+                    /*  Rewind the record. If it is the BOF record, it will be read in
+                        startFragment(). In every case, stream will point before the
+                        first available non-BOF record. */
+                    rStrm.rewindRecord();
+                    // if the BOF record is missing, a regular worksheet will be assumed
+                    eSheetFragment = bIsBofRec ? startFragment( getBiff() ) : BIFF_FRAGMENT_WORKSHEET;
+                }
+                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;
+    BiffInputStream& rStrm = getInputStream();
+    while( bRet && bLoop && rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+    {
+        switch( rStrm.getRecId() )
+        {
+            case BIFF_ID_SHEET:         rWorksheets.importSheet( rStrm );                   break;
+            case BIFF_ID_CODEPAGE:      setCodePage( rStrm.readuInt16() );                  break;
+            case BIFF_ID_FILEPASS:      bRet = getCodecHelper().importFilePass( rStrm );    break;
+            case BIFF_ID_SHEETHEADER:   rStrm.rewindRecord(); bLoop = false;                break;
+        }
+    }
+    xGlobalsProgress->setPosition( 1.0 );
+
+    // load sheet fragments (do not return false in bRet on missing/broken sheets)
+    bool bNextSheet = bRet;
+    for( sal_Int32 nWorksheet = 0, nWorksheetCount = rWorksheets.getWorksheetCount(); bNextSheet && (nWorksheet < nWorksheetCount); ++nWorksheet )
+    {
+        // try to start a new sheet fragment (with leading SHEETHEADER record)
+        bNextSheet = rStrm.startNextRecord() && (rStrm.getRecId() == BIFF_ID_SHEETHEADER);
+        if( bNextSheet )
+        {
+            double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
+            ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength );
+            /*  Read current sheet name (sheet substreams may not be in the
+                same order as SHEET records are). */
+            rStrm.skip( 4 );
+            OUString aSheetName = rStrm.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;
+    BiffInputStream& rStrm = getInputStream();
+    while( bRet && bLoop && rStrm.startNextRecord() )
+    {
+        sal_uInt16 nRecId = rStrm.getRecId();
+        bool bExtLinkRec = false;
+
+        /*  #i56376# BIFF5-BIFF8: If an EOF record for globals is missing,
+            simulate it. The issue is about a document where the sheet fragment
+            starts directly after the EXTSST record, without terminating the
+            globals fragment with an EOF record. */
+        if( BiffHelper::isBofRecord( rStrm ) || (nRecId == BIFF_ID_EOF) )
+        {
+            bLoop = false;
+        }
+        else switch( nRecId )
+        {
+            // records in all BIFF versions
+            case BIFF_ID_CODEPAGE:      setCodePage( rStrm.readuInt16() );                  break;
+            case BIFF_ID_DATEMODE:      rWorkbookSett.importDateMode( rStrm );              break;
+            case BIFF_ID_FILEPASS:      bRet = getCodecHelper().importFilePass( rStrm );    break;
+            case BIFF_ID_PRECISION:     rWorkbookSett.importPrecision( rStrm );             break;
+            case BIFF_ID_WINDOW1:       rViewSett.importWindow1( rStrm );                   break;
+
+            // BIFF specific records
+            default: switch( getBiff() )
+            {
+                case BIFF2: switch( nRecId )
+                {
+                    case BIFF2_ID_DEFINEDNAME:  bExtLinkRec = true;                 break;
+                    case BIFF2_ID_EXTERNALNAME: bExtLinkRec = true;                 break;
+                    case BIFF_ID_EXTERNSHEET:   bExtLinkRec = true;                 break;
+                    case BIFF2_ID_FONT:         rStyles.importFont( rStrm );        break;
+                    case BIFF_ID_FONTCOLOR:     rStyles.importFontColor( rStrm );   break;
+                    case BIFF2_ID_FORMAT:       rStyles.importFormat( rStrm );      break;
+                    case BIFF2_ID_XF:           rStyles.importXf( rStrm );          break;
+                }
+                break;
+
+                case BIFF3: switch( nRecId )
+                {
+                    case BIFF_ID_CRN:           bExtLinkRec = true;                         break;
+                    case BIFF3_ID_DEFINEDNAME:  bExtLinkRec = true;                         break;
+                    case BIFF3_ID_EXTERNALNAME: bExtLinkRec = true;                         break;
+                    case BIFF_ID_EXTERNSHEET:   bExtLinkRec = true;                         break;
+                    case BIFF_ID_FILESHARING:   rWorkbookSett.importFileSharing( rStrm );   break;
+                    case BIFF3_ID_FONT:         rStyles.importFont( rStrm );                break;
+                    case BIFF2_ID_FORMAT:       rStyles.importFormat( rStrm );              break;
+                    case BIFF_ID_HIDEOBJ:       rWorkbookSett.importHideObj( rStrm );       break;
+                    case BIFF_ID_PALETTE:       rStyles.importPalette( rStrm );             break;
+                    case BIFF_ID_STYLE:         rStyles.importStyle( rStrm );               break;
+                    case BIFF_ID_XCT:           bExtLinkRec = true;                         break;
+                    case BIFF3_ID_XF:           rStyles.importXf( rStrm );                  break;
+                }
+                break;
+
+                case BIFF4: switch( nRecId )
+                {
+                    case BIFF_ID_CRN:           bExtLinkRec = true;                         break;
+                    case BIFF3_ID_DEFINEDNAME:  bExtLinkRec = true;                         break;
+                    case BIFF3_ID_EXTERNALNAME: bExtLinkRec = true;                         break;
+                    case BIFF_ID_EXTERNSHEET:   bExtLinkRec = true;                         break;
+                    case BIFF_ID_FILESHARING:   rWorkbookSett.importFileSharing( rStrm );   break;
+                    case BIFF3_ID_FONT:         rStyles.importFont( rStrm );                break;
+                    case BIFF4_ID_FORMAT:       rStyles.importFormat( rStrm );              break;
+                    case BIFF_ID_HIDEOBJ:       rWorkbookSett.importHideObj( rStrm );       break;
+                    case BIFF_ID_PALETTE:       rStyles.importPalette( rStrm );             break;
+                    case BIFF_ID_STYLE:         rStyles.importStyle( rStrm );               break;
+                    case BIFF_ID_XCT:           bExtLinkRec = true;                         break;
+                    case BIFF4_ID_XF:           rStyles.importXf( rStrm );                  break;
+                }
+                break;
+
+                case BIFF5: switch( nRecId )
+                {
+                    case BIFF_ID_BOOKBOOL:      rWorkbookSett.importBookBool( rStrm );      break;
+                    case BIFF_ID_CRN:           bExtLinkRec = true;                         break;
+                    case BIFF5_ID_DEFINEDNAME:  bExtLinkRec = true;                         break;
+                    case BIFF5_ID_EXTERNALNAME: bExtLinkRec = true;                         break;
+                    case BIFF_ID_EXTERNSHEET:   bExtLinkRec = true;                         break;
+                    case BIFF_ID_FILESHARING:   rWorkbookSett.importFileSharing( rStrm );   break;
+                    case BIFF5_ID_FONT:         rStyles.importFont( rStrm );                break;
+                    case BIFF4_ID_FORMAT:       rStyles.importFormat( rStrm );              break;
+                    case BIFF_ID_HIDEOBJ:       rWorkbookSett.importHideObj( rStrm );       break;
+                    case BIFF_ID_OLESIZE:       rViewSett.importOleSize( rStrm );           break;
+                    case BIFF_ID_PALETTE:       rStyles.importPalette( rStrm );             break;
+                    case BIFF_ID_PIVOTCACHE:    rPivotCaches.importPivotCacheRef( rStrm );  break;
+                    case BIFF_ID_SHEET:         rWorksheets.importSheet( rStrm );           break;
+                    case BIFF_ID_STYLE:         rStyles.importStyle( rStrm );               break;
+                    case BIFF_ID_XCT:           bExtLinkRec = true;                         break;
+                    case BIFF5_ID_XF:           rStyles.importXf( rStrm );                  break;
+                }
+                break;
+
+                case BIFF8: switch( nRecId )
+                {
+                    case BIFF_ID_BOOKBOOL:          rWorkbookSett.importBookBool( rStrm );      break;
+                    case BIFF_ID_CODENAME:          rWorkbookSett.importCodeName( rStrm );      break;
+                    case BIFF_ID_CRN:               bExtLinkRec = true;                         break;
+                    case BIFF5_ID_DEFINEDNAME:      bExtLinkRec = true;                         break;
+                    case BIFF_ID_EXTERNALBOOK:      bExtLinkRec = true;                         break;
+                    case BIFF5_ID_EXTERNALNAME:     bExtLinkRec = true;                         break;
+                    case BIFF_ID_EXTERNSHEET:       bExtLinkRec = true;                         break;
+                    case BIFF_ID_FILESHARING:       rWorkbookSett.importFileSharing( rStrm );   break;
+                    case BIFF5_ID_FONT:             rStyles.importFont( rStrm );                break;
+                    case BIFF4_ID_FORMAT:           rStyles.importFormat( rStrm );              break;
+                    case BIFF_ID_HIDEOBJ:           rWorkbookSett.importHideObj( rStrm );       break;
+                    case BIFF_ID_OLESIZE:           rViewSett.importOleSize( rStrm );           break;
+                    case BIFF_ID_PALETTE:           rStyles.importPalette( rStrm );             break;
+                    case BIFF_ID_PIVOTCACHE:        rPivotCaches.importPivotCacheRef( rStrm );  break;
+                    case BIFF_ID_SHEET:             rWorksheets.importSheet( rStrm );           break;
+                    case BIFF_ID_SST:               rSharedStrings.importSst( rStrm );          break;
+                    case BIFF_ID_STYLE:             rStyles.importStyle( rStrm );               break;
+                    case BIFF_ID_USESELFS:          rWorkbookSett.importUsesElfs( rStrm );      break;
+                    case BIFF_ID_VBAPROJECT:        bHasVbaProject = true;                      break;
+                    case BIFF_ID_VBAPROJECTEMPTY:   bEmptyVbaProject = true;                    break;
+                    case BIFF_ID_XCT:               bExtLinkRec = true;                         break;
+                    case BIFF5_ID_XF:               rStyles.importXf( rStrm );                  break;
+                }
+                break;
+
+                case BIFF_UNKNOWN: break;
+            }
+        }
+
+        if( bExtLinkRec )
+            aExtLinkRecs.push_back( rStrm.getRecHandle() );
+    }
+
+    // finalize global buffers
+    rProgressBar.setPosition( 0.5 );
+    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 = rStrm.getRecHandle();
+        // context handler implementing import of external link records
+        BiffExternalSheetDataContext aSheetContext( *this, true );
+        // import all records by using their cached record handle
+        for( RecordHandleVec::const_iterator aIt = aExtLinkRecs.begin(), aEnd = aExtLinkRecs.end(); (aIt != aEnd) && rStrm.startRecordByHandle( *aIt ); ++aIt )
+            aSheetContext.importRecord( rStrm );
+        // finalize global buffers
+        getDefinedNames().finalizeImport();
+        // seek back to the EOF record of the workbook globals fragment
+        bRet = rStrm.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 && BiffHelper::isBofRecord( rStrm ) )
+        rStrm.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
+    BiffInputStream& rStrm = getInputStream();
+    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 = rStrm.getRecHandle();
+            // import the global records
+            ISegmentProgressBarRef xGlobalsProgress = rProgressBar.createSegment( PROGRESS_LENGTH_GLOBALS );
+            importGlobalsFragment( *xGlobalsProgress );
+            // rewind stream to fragment BOF record
+            rStrm.startRecordByHandle( nRecHandle );
+        }
+        break;
+
+        // load the external link records for this sheet in BIFF5
+        case BIFF5:
+        {
+            // remember current record to seek back below
+            sal_Int64 nRecHandle = rStrm.getRecHandle();
+            // fragment implementing import of external link records
+            BiffExternalLinkFragment( *this ).importFragment();
+            // rewind stream to fragment BOF record
+            rStrm.startRecordByHandle( nRecHandle );
+        }
+        break;
+
+        case BIFF8:
+        break;
+
+        case BIFF_UNKNOWN:
+        break;
+    }
+
+    // create the WorksheetGlobals object
+    ISegmentProgressBarRef xSheetProgress = rProgressBar.createSegment( rProgressBar.getFreeLength() );
+    WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, xSheetProgress, eSheetType, nCalcSheet );
+    OSL_ENSURE( xSheetGlob.get(), "BiffWorkbookFragment::importSheetFragment - missing sheet in document" );
+    if( !xSheetGlob.get() )
+        return false;
+
+    // create the worksheet fragment
+    ::boost::shared_ptr< BiffWorksheetFragmentBase > xFragment;
+    switch( eSheetType )
+    {
+        case SHEETTYPE_WORKSHEET:
+        case SHEETTYPE_MACROSHEET:
+        case SHEETTYPE_DIALOGSHEET:
+            xFragment.reset( new BiffWorksheetFragment( *xSheetGlob, *this ) );
+        break;
+        case SHEETTYPE_CHARTSHEET:
+            xFragment.reset( new BiffChartsheetFragment( *xSheetGlob, *this ) );
+        break;
+        case SHEETTYPE_MODULESHEET:
+        case SHEETTYPE_EMPTYSHEET:
+            xFragment.reset( new BiffSkipWorksheetFragment( *xSheetGlob, *this ) );
+        break;
+    }
+    // load the sheet fragment records
+    return xFragment.get() && xFragment->importFragment();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/workbookhelper.cxx b/sc/source/filter/oox/workbookhelper.cxx
new file mode 100644
index 000000000000..f6ea218a7c87
--- /dev/null
+++ b/sc/source/filter/oox/workbookhelper.cxx
@@ -0,0 +1,960 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "workbookhelper.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/drawingml/theme.hxx"
+#include "oox/helper/progressbar.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/ole/vbaproject.hxx"
+#include "addressconverter.hxx"
+#include "biffinputstream.hxx"
+#include "biffcodec.hxx"
+#include "connectionsbuffer.hxx"
+#include "defnamesbuffer.hxx"
+#include "excelchartconverter.hxx"
+#include "excelfilter.hxx"
+#include "externallinkbuffer.hxx"
+#include "formulaparser.hxx"
+#include "pagesettings.hxx"
+#include "pivotcachebuffer.hxx"
+#include "pivottablebuffer.hxx"
+#include "scenariobuffer.hxx"
+#include "sharedstringsbuffer.hxx"
+#include "stylesbuffer.hxx"
+#include "tablebuffer.hxx"
+#include "themebuffer.hxx"
+#include "unitconverter.hxx"
+#include "viewsettings.hxx"
+#include "workbooksettings.hxx"
+#include "worksheetbuffer.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::BinaryFilterBase;
+using ::oox::core::FilterBase;
+using ::oox::core::FragmentHandler;
+using ::oox::core::XmlFilterBase;
+using ::oox::drawingml::Theme;
+using ::rtl::OUString;
+
+// ============================================================================
+
+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 WorkbookGlobals
+{
+public:
+    explicit            WorkbookGlobals( ExcelFilter& rFilter );
+    explicit            WorkbookGlobals( ExcelBiffFilter& rFilter, BiffType eBiff );
+                        ~WorkbookGlobals();
+
+    /** 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 VBA project storage. */
+    inline StorageRef   getVbaProjectStorage() const { return mxVbaPrjStrg; }
+    /** Returns the index of the current Calc sheet, if filter currently processes a sheet. */
+    inline sal_Int16    getCurrentSheetIndex() const { return mnCurrSheet; }
+
+    /** Sets the VBA project storage used to import VBA source code and forms. */
+    inline void         setVbaProjectStorage( const StorageRef& rxVbaPrjStrg ) { mxVbaPrjStrg = rxVbaPrjStrg; }
+    /** Sets the index of the current Calc sheet, if filter currently processes a sheet. */
+    inline void         setCurrentSheetIndex( sal_Int16 nSheet ) { mnCurrSheet = nSheet; }
+
+    // document model ---------------------------------------------------------
+
+    /** Returns a reference to the source/target spreadsheet document model. */
+    inline Reference< XSpreadsheetDocument > getDocument() const { return mxDoc; }
+    /** 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 defined name on the-fly in the correct Calc sheet. */
+    Reference< XNamedRange > createLocalNamedRangeObject( OUString& orName, sal_Int32 nNameFlags, sal_Int32 nTab ) const;
+    /** Creates and returns a database range on-the-fly in the Calc document. */
+    Reference< XDatabaseRange > createDatabaseRangeObject( OUString& orName, const CellRangeAddress& rRangeAddr ) const;
+    /** Creates and returns an unnamed database range on-the-fly in the Calc document. */
+    Reference< XDatabaseRange > createUnnamedDatabaseRangeObject( const CellRangeAddress& rRangeAddr ) 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 collection of external data connections. */
+    inline ConnectionsBuffer&  getConnections() const { return *mxConnections; }
+    /** 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.get(); }
+    /** Returns the page/print settings converter. */
+    inline PageSettingsConverter& getPageSettingsConverter() const { return *mxPageSettConverter; }
+
+    // OOXML/BIFF12 specific --------------------------------------------------
+
+    /** Returns the base OOXML/BIFF12 filter object. */
+    inline XmlFilterBase& getOoxFilter() const { return *mpOoxFilter; }
+
+    // BIFF2-BIFF8 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< ConnectionsBuffer >        ConnectionsBfrPtr;
+    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 document.
+    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.
+    ConnectionsBfrPtr   mxConnections;          /// All external data connections.
+    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.
+
+    // OOXML/BIFF12 specific
+    XmlFilterBase*      mpOoxFilter;            /// Base OOXML/BIFF12 filter object.
+
+    // BIFF2-BIFF8 specific
+    BinaryFilterBase*   mpBiffFilter;           /// Base BIFF2-BIFF8 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.
+};
+
+// ----------------------------------------------------------------------------
+
+WorkbookGlobals::WorkbookGlobals( ExcelFilter& rFilter ) :
+    mrBaseFilter( rFilter ),
+    mrExcelBase( rFilter ),
+    meFilterType( FILTER_OOXML ),
+    mpOoxFilter( &rFilter ),
+    mpBiffFilter( 0 ),
+    meBiff( BIFF_UNKNOWN )
+{
+    // register at the filter, needed for virtual callbacks (even during construction)
+    mrExcelBase.registerWorkbookGlobals( *this );
+    initialize( true );
+}
+
+WorkbookGlobals::WorkbookGlobals( 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.registerWorkbookGlobals( *this );
+    initialize( eBiff >= BIFF5 );
+}
+
+WorkbookGlobals::~WorkbookGlobals()
+{
+    finalize();
+    mrExcelBase.unregisterWorkbookGlobals();
+}
+
+// document model -------------------------------------------------------------
+
+Reference< XNameContainer > WorkbookGlobals::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(), "WorkbookGlobals::getStyleFamily - cannot access style family" );
+    return xStylesNC;
+}
+
+Reference< XStyle > WorkbookGlobals::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(), "WorkbookGlobals::getStyleObject - cannot access style object" );
+    return xStyle;
+}
+
+Reference< XNamedRange > WorkbookGlobals::createNamedRangeObject( OUString& orName, sal_Int32 nNameFlags ) const
+{
+    // create the name and insert it into the Calc document
+    Reference< XNamedRange > xNamedRange;
+    if( !orName.isEmpty() ) try
+    {
+        // find an unused name
+        PropertySet aDocProps( mxDoc );
+        Reference< XNamedRanges > xNamedRanges( aDocProps.getAnyProperty( PROP_NamedRanges ), UNO_QUERY_THROW );
+        Reference< XNameAccess > xNameAccess( xNamedRanges, UNO_QUERY_THROW );
+        orName = ContainerHelper::getUnusedName( xNameAccess, orName, '_' );
+        // create the named range
+        xNamedRanges->addNewByName( orName, OUString(), CellAddress( 0, 0, 0 ), nNameFlags );
+        xNamedRange.set( xNamedRanges->getByName( orName ), UNO_QUERY );
+    }
+    catch( Exception& )
+    {
+    }
+    OSL_ENSURE( xNamedRange.is(), "WorkbookGlobals::createNamedRangeObject - cannot create defined name" );
+    return xNamedRange;
+}
+
+Reference< XNamedRange > WorkbookGlobals::createLocalNamedRangeObject( OUString& orName, sal_Int32 nNameFlags, sal_Int32 nTab ) const
+{
+    // create the name and insert it into the Calc document
+    Reference< XNamedRange > xNamedRange;
+    if( !orName.isEmpty() ) try
+    {
+        // find an unused name
+        Reference< XIndexAccess > xSheets(mxDoc->getSheets(), UNO_QUERY_THROW);
+        Reference< XSpreadsheet > xSheet (xSheets->getByIndex(nTab), UNO_QUERY_THROW);
+        Reference< com::sun::star::container::XNamed > xNamed(xSheet, UNO_QUERY_THROW);
+        rtl::OUString aName = xNamed->getName();
+        PropertySet aSheetProps( xSheet );
+        Reference< XNamedRanges > xNamedRanges( aSheetProps.getAnyProperty( PROP_NamedRanges ), UNO_QUERY_THROW );
+        Reference< XNameAccess > xNameAccess( xNamedRanges, UNO_QUERY_THROW );
+        orName = ContainerHelper::getUnusedName( xNameAccess, orName, '_' );
+        // create the named range
+        xNamedRanges->addNewByName( orName, OUString(), CellAddress( 0, 0, 0 ), nNameFlags );
+        xNamedRange.set( xNamedRanges->getByName( orName ), UNO_QUERY );
+    }
+    catch( Exception& )
+    {
+    }
+    OSL_ENSURE( xNamedRange.is(), "WorkbookGlobals::createLocalNamedRangeObject - cannot create defined name" );
+    return xNamedRange;
+}
+
+Reference< XDatabaseRange > WorkbookGlobals::createDatabaseRangeObject( OUString& orName, const CellRangeAddress& rRangeAddr ) const
+{
+    // validate cell range
+    CellRangeAddress aDestRange = rRangeAddr;
+    bool bValidRange = getAddressConverter().validateCellRange( aDestRange, true, true );
+
+    // create database range and insert it into the Calc document
+    Reference< XDatabaseRange > xDatabaseRange;
+    if( bValidRange && !orName.isEmpty() ) try
+    {
+        // find an unused name
+        PropertySet aDocProps( mxDoc );
+        Reference< XDatabaseRanges > xDatabaseRanges( aDocProps.getAnyProperty( PROP_DatabaseRanges ), UNO_QUERY_THROW );
+        Reference< XNameAccess > xNameAccess( xDatabaseRanges, UNO_QUERY_THROW );
+        orName = ContainerHelper::getUnusedName( xNameAccess, orName, '_' );
+        // create the database range
+        xDatabaseRanges->addNewByName( orName, aDestRange );
+        xDatabaseRange.set( xDatabaseRanges->getByName( orName ), UNO_QUERY );
+    }
+    catch( Exception& )
+    {
+    }
+    OSL_ENSURE( xDatabaseRange.is(), "WorkbookGlobals::createDatabaseRangeObject - cannot create database range" );
+    return xDatabaseRange;
+}
+
+Reference< XDatabaseRange > WorkbookGlobals::createUnnamedDatabaseRangeObject( const CellRangeAddress& rRangeAddr ) const
+{
+    // validate cell range
+    CellRangeAddress aDestRange = rRangeAddr;
+    bool bValidRange = getAddressConverter().validateCellRange( aDestRange, true, true );
+
+    // create database range and insert it into the Calc document
+    Reference< XDatabaseRange > xDatabaseRange;
+    PropertySet aDocProps( mxDoc );
+    Reference< XUnnamedDatabaseRanges > xDatabaseRanges( aDocProps.getAnyProperty( PROP_UnnamedDatabaseRanges ), UNO_QUERY_THROW );
+    if( bValidRange ) try
+    {
+        xDatabaseRanges->setByTable( aDestRange );
+        xDatabaseRange.set( xDatabaseRanges->getByTable( aDestRange.Sheet ), UNO_QUERY );
+    }
+    catch( Exception& )
+    {
+    }
+    OSL_ENSURE( xDatabaseRange.is(), "WorkbookData::createDatabaseRangeObject - cannot create database range" );
+    return xDatabaseRange;
+}
+
+Reference< XStyle > WorkbookGlobals::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(), "WorkbookGlobals::createStyleObject - cannot create style" );
+    return xStyle;
+}
+
+// BIFF specific --------------------------------------------------------------
+
+void WorkbookGlobals::setTextEncoding( rtl_TextEncoding eTextEnc )
+{
+    if( eTextEnc != RTL_TEXTENCODING_DONTKNOW )
+        meTextEnc = eTextEnc;
+}
+
+void WorkbookGlobals::setCodePage( sal_uInt16 nCodePage )
+{
+    setTextEncoding( BiffHelper::calcTextEncodingFromCodePage( nCodePage ) );
+    mbHasCodePage = true;
+}
+
+void WorkbookGlobals::setAppFontEncoding( rtl_TextEncoding eAppFontEnc )
+{
+    if( !mbHasCodePage )
+        setTextEncoding( eAppFontEnc );
+}
+
+void WorkbookGlobals::setIsWorkbookFile()
+{
+    OSL_ENSURE( meBiff == BIFF4, "WorkbookGlobals::setIsWorkbookFile - invalid call" );
+    mbWorkbook = true;
+}
+
+void WorkbookGlobals::createBuffersPerSheet( sal_Int16 nSheet )
+{
+    switch( meBiff )
+    {
+        case BIFF2:
+        case BIFF3:
+            OSL_ENSURE( nSheet == 0, "WorkbookGlobals::createBuffersPerSheet - unexpected sheet index" );
+            mxDefNames->setLocalCalcSheet( nSheet );
+        break;
+
+        case BIFF4:
+            OSL_ENSURE( mbWorkbook || (nSheet == 0), "WorkbookGlobals::createBuffersPerSheet - unexpected sheet index" );
+            // #i11183# sheets in BIFF4W files have own styles and names
+            if( nSheet > 0 )
+            {
+                mxStyles.reset( new StylesBuffer( *this ) );
+                mxDefNames.reset( new DefinedNamesBuffer( *this ) );
+                mxExtLinks.reset( new ExternalLinkBuffer( *this ) );
+            }
+            mxDefNames->setLocalCalcSheet( nSheet );
+        break;
+
+        case BIFF5:
+            // BIFF5 stores external references per sheet
+            if( nSheet > 0 )
+                mxExtLinks.reset( new ExternalLinkBuffer( *this ) );
+        break;
+
+        case BIFF8:
+        break;
+
+        case BIFF_UNKNOWN:
+        break;
+    }
+}
+
+// private --------------------------------------------------------------------
+
+void WorkbookGlobals::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(), "WorkbookGlobals::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 ) );
+    mxConnections.reset( new ConnectionsBuffer( *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( aPropSet.getAnyProperty( PROP_NamedRanges ), 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_OOXML:
+        break;
+
+        case FILTER_UNKNOWN:
+        break;
+    }
+}
+
+void WorkbookGlobals::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( aPropSet.getAnyProperty( PROP_NamedRanges ), 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 );
+        // #111099# open forms in alive mode (has no effect, if no controls in document)
+        aPropSet.setProperty( PROP_ApplyFormDesignMode, false );
+    }
+}
+
+// ============================================================================
+
+WorkbookHelper::~WorkbookHelper()
+{
+}
+
+/*static*/ WorkbookGlobalsRef WorkbookHelper::constructGlobals( ExcelFilter& rFilter )
+{
+    WorkbookGlobalsRef xBookGlob( new WorkbookGlobals( rFilter ) );
+    if( !xBookGlob->isValid() )
+        xBookGlob.reset();
+    return xBookGlob;
+}
+
+/*static*/ WorkbookGlobalsRef WorkbookHelper::constructGlobals( ExcelBiffFilter& rFilter, BiffType eBiff )
+{
+    WorkbookGlobalsRef xBookGlob( new WorkbookGlobals( rFilter, eBiff ) );
+    if( !xBookGlob->isValid() )
+        xBookGlob.reset();
+    return xBookGlob;
+}
+
+// filter ---------------------------------------------------------------------
+
+FilterBase& WorkbookHelper::getBaseFilter() const
+{
+    return mrBookGlob.getBaseFilter();
+}
+
+FilterType WorkbookHelper::getFilterType() const
+{
+    return mrBookGlob.getFilterType();
+}
+
+SegmentProgressBar& WorkbookHelper::getProgressBar() const
+{
+    return mrBookGlob.getProgressBar();
+}
+
+bool WorkbookHelper::isWorkbookFile() const
+{
+    return mrBookGlob.isWorkbookFile();
+}
+
+sal_Int16 WorkbookHelper::getCurrentSheetIndex() const
+{
+    return mrBookGlob.getCurrentSheetIndex();
+}
+
+void WorkbookHelper::setVbaProjectStorage( const StorageRef& rxVbaPrjStrg )
+{
+    mrBookGlob.setVbaProjectStorage( rxVbaPrjStrg );
+}
+
+void WorkbookHelper::setCurrentSheetIndex( sal_Int16 nSheet )
+{
+    mrBookGlob.setCurrentSheetIndex( nSheet );
+}
+
+void WorkbookHelper::finalizeWorkbookImport()
+{
+    // workbook settings, document and sheet view settings
+    mrBookGlob.getWorkbookSettings().finalizeImport();
+    mrBookGlob.getViewSettings().finalizeImport();
+
+    /*  Insert all pivot tables. Must be done after loading all sheets, because
+        data pilots expect existing source data on creation. */
+    mrBookGlob.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. */
+    mrBookGlob.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 = mrBookGlob.getVbaProjectStorage();
+    if( xVbaPrjStrg.get() && xVbaPrjStrg->isStorage() )
+        getBaseFilter().getVbaProject().importVbaProject( *xVbaPrjStrg, getBaseFilter().getGraphicHelper() );
+}
+
+// document model -------------------------------------------------------------
+
+Reference< XSpreadsheetDocument > WorkbookHelper::getDocument() const
+{
+    return mrBookGlob.getDocument();
+}
+
+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< 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 mrBookGlob.getStyleFamily( bPageStyles );
+}
+
+Reference< XStyle > WorkbookHelper::getStyleObject( const OUString& rStyleName, bool bPageStyle ) const
+{
+    return mrBookGlob.getStyleObject( rStyleName, bPageStyle );
+}
+
+Reference< XNamedRange > WorkbookHelper::createNamedRangeObject( OUString& orName, sal_Int32 nNameFlags ) const
+{
+    return mrBookGlob.createNamedRangeObject( orName, nNameFlags );
+}
+
+Reference< XNamedRange > WorkbookHelper::createLocalNamedRangeObject( OUString& orName, sal_Int32 nNameFlags, sal_Int32 nTab ) const
+{
+    return mrBookGlob.createLocalNamedRangeObject( orName, nNameFlags, nTab );
+}
+
+Reference< XDatabaseRange > WorkbookHelper::createDatabaseRangeObject( OUString& orName, const CellRangeAddress& rRangeAddr ) const
+{
+    return mrBookGlob.createDatabaseRangeObject( orName, rRangeAddr );
+}
+
+Reference< XDatabaseRange > WorkbookHelper::createUnnamedDatabaseRangeObject( const CellRangeAddress& rRangeAddr ) const
+{
+    return mrBookGlob.createUnnamedDatabaseRangeObject( rRangeAddr );
+}
+
+Reference< XStyle > WorkbookHelper::createStyleObject( OUString& orStyleName, bool bPageStyle ) const
+{
+    return mrBookGlob.createStyleObject( orStyleName, bPageStyle );
+}
+
+// buffers --------------------------------------------------------------------
+
+WorkbookSettings& WorkbookHelper::getWorkbookSettings() const
+{
+    return mrBookGlob.getWorkbookSettings();
+}
+
+ViewSettings& WorkbookHelper::getViewSettings() const
+{
+    return mrBookGlob.getViewSettings();
+}
+
+WorksheetBuffer& WorkbookHelper::getWorksheets() const
+{
+    return mrBookGlob.getWorksheets();
+}
+
+ThemeBuffer& WorkbookHelper::getTheme() const
+{
+    return mrBookGlob.getTheme();
+}
+
+StylesBuffer& WorkbookHelper::getStyles() const
+{
+    return mrBookGlob.getStyles();
+}
+
+SharedStringsBuffer& WorkbookHelper::getSharedStrings() const
+{
+    return mrBookGlob.getSharedStrings();
+}
+
+ExternalLinkBuffer& WorkbookHelper::getExternalLinks() const
+{
+    return mrBookGlob.getExternalLinks();
+}
+
+DefinedNamesBuffer& WorkbookHelper::getDefinedNames() const
+{
+    return mrBookGlob.getDefinedNames();
+}
+
+TableBuffer& WorkbookHelper::getTables() const
+{
+    return mrBookGlob.getTables();
+}
+
+ScenarioBuffer& WorkbookHelper::getScenarios() const
+{
+    return mrBookGlob.getScenarios();
+}
+
+ConnectionsBuffer& WorkbookHelper::getConnections() const
+{
+    return mrBookGlob.getConnections();
+}
+
+PivotCacheBuffer& WorkbookHelper::getPivotCaches() const
+{
+    return mrBookGlob.getPivotCaches();
+}
+
+PivotTableBuffer& WorkbookHelper::getPivotTables() const
+{
+    return mrBookGlob.getPivotTables();
+}
+
+// converters -----------------------------------------------------------------
+
+FormulaParser& WorkbookHelper::getFormulaParser() const
+{
+    return mrBookGlob.getFormulaParser();
+}
+
+UnitConverter& WorkbookHelper::getUnitConverter() const
+{
+    return mrBookGlob.getUnitConverter();
+}
+
+AddressConverter& WorkbookHelper::getAddressConverter() const
+{
+    return mrBookGlob.getAddressConverter();
+}
+
+ExcelChartConverter* WorkbookHelper::getChartConverter() const
+{
+    return mrBookGlob.getChartConverter();
+}
+
+PageSettingsConverter& WorkbookHelper::getPageSettingsConverter() const
+{
+    return mrBookGlob.getPageSettingsConverter();
+}
+
+// OOXML/BIFF12 specific ------------------------------------------------------
+
+XmlFilterBase& WorkbookHelper::getOoxFilter() const
+{
+    OSL_ENSURE( mrBookGlob.getFilterType() == FILTER_OOXML, "WorkbookHelper::getOoxFilter - invalid call" );
+    return mrBookGlob.getOoxFilter();
+}
+
+bool WorkbookHelper::importOoxFragment( const ::rtl::Reference< FragmentHandler >& rxHandler )
+{
+    return getOoxFilter().importFragment( rxHandler );
+}
+
+// BIFF specific --------------------------------------------------------------
+
+BiffType WorkbookHelper::getBiff() const
+{
+    return mrBookGlob.getBiff();
+}
+
+rtl_TextEncoding WorkbookHelper::getTextEncoding() const
+{
+    return mrBookGlob.getTextEncoding();
+}
+
+void WorkbookHelper::setCodePage( sal_uInt16 nCodePage )
+{
+    mrBookGlob.setCodePage( nCodePage );
+}
+
+void WorkbookHelper::setAppFontEncoding( rtl_TextEncoding eAppFontEnc )
+{
+    mrBookGlob.setAppFontEncoding( eAppFontEnc );
+}
+
+void WorkbookHelper::setIsWorkbookFile()
+{
+    mrBookGlob.setIsWorkbookFile();
+}
+
+void WorkbookHelper::createBuffersPerSheet( sal_Int16 nSheet )
+{
+    mrBookGlob.createBuffersPerSheet( nSheet );
+}
+
+BiffCodecHelper& WorkbookHelper::getCodecHelper() const
+{
+    return mrBookGlob.getCodecHelper();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/workbooksettings.cxx b/sc/source/filter/oox/workbooksettings.cxx
new file mode 100644
index 000000000000..b07fa83baf6b
--- /dev/null
+++ b/sc/source/filter/oox/workbooksettings.cxx
@@ -0,0 +1,384 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "workbooksettings.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/core/xmlfilterbase.hxx"
+#include "biffinputstream.hxx"
+#include "unitconverter.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+using ::comphelper::MediaDescriptor;
+using ::oox::core::CodecHelper;
+using ::rtl::OUString;
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt32 BIFF12_WORKBOOKPR_DATE1904     = 0x00000001;
+const sal_uInt32 BIFF12_WORKBOOKPR_STRIPEXT     = 0x00000080;
+
+const sal_uInt16 BIFF12_CALCPR_A1               = 0x0002;
+const sal_uInt16 BIFF12_CALCPR_ITERATE          = 0x0004;
+const sal_uInt16 BIFF12_CALCPR_FULLPRECISION    = 0x0008;
+const sal_uInt16 BIFF12_CALCPR_CALCCOMPLETED    = 0x0010;
+const sal_uInt16 BIFF12_CALCPR_CALCONSAVE       = 0x0020;
+const sal_uInt16 BIFF12_CALCPR_CONCURRENT       = 0x0040;
+const sal_uInt16 BIFF12_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::setBiffObjectMode( 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( SequenceInputStream& rStrm )
+{
+    maFileSharing.mbRecommendReadOnly = rStrm.readuInt16() != 0;
+    rStrm >> maFileSharing.mnPasswordHash >> maFileSharing.maUserName;
+}
+
+void WorkbookSettings::importWorkbookPr( SequenceInputStream& rStrm )
+{
+    sal_uInt32 nFlags;
+    rStrm >> nFlags >> maBookSettings.mnDefaultThemeVer >> maBookSettings.maCodeName;
+    maBookSettings.setBiffObjectMode( extractValue< sal_uInt16 >( nFlags, 13, 2 ) );
+    // set flag means: strip external link values
+    maBookSettings.mbSaveExtLinkValues = !getFlag( nFlags, BIFF12_WORKBOOKPR_STRIPEXT );
+    setDateMode( getFlag( nFlags, BIFF12_WORKBOOKPR_DATE1904 ) );
+}
+
+void WorkbookSettings::importCalcPr( SequenceInputStream& 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, BIFF12_CALCPR_A1, XML_A1, XML_R1C1 );
+    maCalcSettings.mnCalcMode      = STATIC_ARRAY_SELECT( spnCalcModes, nCalcMode, XML_auto );
+    maCalcSettings.mnProcCount     = getFlagValue< sal_Int32 >( nFlags, BIFF12_CALCPR_MANUALPROC, nProcCount, -1 );
+    maCalcSettings.mbCalcOnSave    = getFlag( nFlags, BIFF12_CALCPR_CALCONSAVE );
+    maCalcSettings.mbCalcCompleted = getFlag( nFlags, BIFF12_CALCPR_CALCCOMPLETED );
+    maCalcSettings.mbFullPrecision = getFlag( nFlags, BIFF12_CALCPR_FULLPRECISION );
+    maCalcSettings.mbIterate       = getFlag( nFlags, BIFF12_CALCPR_ITERATE );
+    maCalcSettings.mbConcurrent    = getFlag( nFlags, BIFF12_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.setBiffObjectMode( 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_OOXML:
+        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( getBaseFilter().getModelFactory()->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/sc/source/filter/oox/worksheetbuffer.cxx b/sc/source/filter/oox/worksheetbuffer.cxx
new file mode 100644
index 000000000000..5178143cb9b3
--- /dev/null
+++ b/sc/source/filter/oox/worksheetbuffer.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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "worksheetbuffer.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "biffinputstream.hxx"
+#include "excelhandlers.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+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( SequenceInputStream& 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[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.isEmpty() ? 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_FAIL( "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/sc/source/filter/oox/worksheetfragment.cxx b/sc/source/filter/oox/worksheetfragment.cxx
new file mode 100644
index 000000000000..b4484bdd1621
--- /dev/null
+++ b/sc/source/filter/oox/worksheetfragment.cxx
@@ -0,0 +1,1223 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "worksheetfragment.hxx"
+
+#include "oox/core/filterbase.hxx"
+#include "oox/core/relations.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "addressconverter.hxx"
+#include "autofilterbuffer.hxx"
+#include "autofiltercontext.hxx"
+#include "biffinputstream.hxx"
+#include "commentsfragment.hxx"
+#include "condformatcontext.hxx"
+#include "drawingfragment.hxx"
+#include "drawingmanager.hxx"
+#include "externallinkbuffer.hxx"
+#include "pagesettings.hxx"
+#include "pivottablefragment.hxx"
+#include "querytablefragment.hxx"
+#include "scenariobuffer.hxx"
+#include "scenariocontext.hxx"
+#include "sheetdatabuffer.hxx"
+#include "sheetdatacontext.hxx"
+#include "tablefragment.hxx"
+#include "viewsettings.hxx"
+#include "workbooksettings.hxx"
+#include "worksheetsettings.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::uno;
+using namespace ::oox::core;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+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 BIFF12_OLEOBJECT_CONTENT    = 1;
+const sal_Int32 BIFF12_OLEOBJECT_ICON       = 4;
+const sal_Int32 BIFF12_OLEOBJECT_ALWAYS     = 1;
+const sal_Int32 BIFF12_OLEOBJECT_ONCALL     = 3;
+const sal_uInt16 BIFF12_OLEOBJECT_LINKED    = 0x0001;
+const sal_uInt16 BIFF12_OLEOBJECT_AUTOLOAD  = 0x0002;
+
+} // namespace
+
+// ============================================================================
+
+DataValidationsContext::DataValidationsContext( WorksheetFragmentBase& rFragment ) :
+    WorksheetContextBase( rFragment )
+{
+}
+
+ContextHandlerRef DataValidationsContext::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 onCharacters()
+            }
+        break;
+    }
+    return 0;
+}
+
+void DataValidationsContext::onCharacters( const OUString& rChars )
+{
+    if( mxValModel.get() ) switch( getCurrentElement() )
+    {
+        case XLS_TOKEN( formula1 ):
+            mxValModel->maTokens1 = getFormulaParser().importFormula( mxValModel->maRanges.getBaseAddress(), rChars );
+            // 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 = getFormulaParser().importFormula( mxValModel->maRanges.getBaseAddress(), rChars );
+        break;
+    }
+}
+
+void DataValidationsContext::onEndElement()
+{
+    if( isCurrentElement( XLS_TOKEN( dataValidation ) ) && mxValModel.get() )
+    {
+        setValidation( *mxValModel );
+        mxValModel.reset();
+    }
+}
+
+
+ContextHandlerRef DataValidationsContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    if( nRecId == BIFF12_ID_DATAVALIDATION )
+        importDataValidation( rStrm );
+    return 0;
+}
+
+void DataValidationsContext::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 DataValidationsContext::importDataValidation( SequenceInputStream& rStrm )
+{
+    ValidationModel aModel;
+
+    sal_uInt32 nFlags;
+    BinRangeList aRanges;
+    rStrm >> nFlags >> aRanges >> aModel.maErrorTitle >> aModel.maErrorMessage >> aModel.maInputTitle >> aModel.maInputMessage;
+
+    // equal flags in all BIFFs
+    aModel.setBiffType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
+    aModel.setBiffOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
+    aModel.setBiffErrorStyle( 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();
+    CellAddress aBaseAddr = aModel.maRanges.getBaseAddress();
+    aModel.maTokens1 = rParser.importFormula( aBaseAddr, FORMULATYPE_VALIDATION, rStrm );
+    aModel.maTokens2 = rParser.importFormula( aBaseAddr, FORMULATYPE_VALIDATION, rStrm );
+    // 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 );
+}
+
+// ============================================================================
+
+WorksheetFragment::WorksheetFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
+    WorksheetFragmentBase( rHelper, rFragmentPath )
+{
+    // import data tables related to this worksheet
+    RelationsRef xTableRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "table" ) );
+    for( Relations::const_iterator aIt = xTableRels->begin(), aEnd = xTableRels->end(); aIt != aEnd; ++aIt )
+        importOoxFragment( new TableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
+
+    // import comments related to this worksheet
+    OUString aCommentsFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "comments" ) );
+    if( !aCommentsFragmentPath.isEmpty() )
+        importOoxFragment( new CommentsFragment( *this, aCommentsFragmentPath ) );
+}
+
+ContextHandlerRef WorksheetFragment::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 == XLS_TOKEN( dialogsheet )) ? this : 0;
+            case SHEETTYPE_MODULESHEET: return 0;
+            case SHEETTYPE_EMPTYSHEET:  return 0;
+        }
+        break;
+
+        case XLS_TOKEN( worksheet ):
+        case XM_TOKEN( macrosheet ):
+        case XLS_TOKEN( dialogsheet ):
+            switch( nElement )
+            {
+                case XLS_TOKEN( sheetData ):                return new SheetDataContext( *this );
+                case XLS_TOKEN( conditionalFormatting ):    return new CondFormatContext( *this );
+                case XLS_TOKEN( dataValidations ):          return new DataValidationsContext( *this );
+                case XLS_TOKEN( autoFilter ):               return new AutoFilterContext( *this, getAutoFilters().createAutoFilter() );
+                case XLS_TOKEN( scenarios ):                return new ScenariosContext( *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;
+            }
+        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 onCharacters()
+            }
+        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 WorksheetFragment::onCharacters( 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 WorksheetFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
+{
+    switch( getCurrentElement() )
+    {
+        case XML_ROOT_CONTEXT:
+            if( nRecId == BIFF12_ID_WORKSHEET ) return this;
+        break;
+
+        case BIFF12_ID_WORKSHEET:
+            switch( nRecId )
+            {
+                case BIFF12_ID_SHEETDATA:       return new SheetDataContext( *this );
+                case BIFF12_ID_CONDFORMATTING:  return new CondFormatContext( *this );
+                case BIFF12_ID_DATAVALIDATIONS: return new DataValidationsContext( *this );
+                case BIFF12_ID_AUTOFILTER:      return new AutoFilterContext( *this, getAutoFilters().createAutoFilter() );
+                case BIFF12_ID_SCENARIOS:       return new ScenariosContext( *this );
+
+                case BIFF12_ID_SHEETVIEWS:
+                case BIFF12_ID_COLS:
+                case BIFF12_ID_MERGECELLS:
+                case BIFF12_ID_ROWBREAKS:
+                case BIFF12_ID_COLBREAKS:
+                case BIFF12_ID_OLEOBJECTS:
+                case BIFF12_ID_CONTROLS:        return this;
+
+                case BIFF12_ID_SHEETPR:         getWorksheetSettings().importSheetPr( rStrm );              break;
+                case BIFF12_ID_DIMENSION:       importDimension( rStrm );                                   break;
+                case BIFF12_ID_SHEETFORMATPR:   importSheetFormatPr( rStrm );                               break;
+                case BIFF12_ID_HYPERLINK:       importHyperlink( rStrm );                                   break;
+                case BIFF12_ID_PAGEMARGINS:     getPageSettings().importPageMargins( rStrm );               break;
+                case BIFF12_ID_PAGESETUP:       getPageSettings().importPageSetup( getRelations(), rStrm ); break;
+                case BIFF12_ID_PRINTOPTIONS:    getPageSettings().importPrintOptions( rStrm );              break;
+                case BIFF12_ID_HEADERFOOTER:    getPageSettings().importHeaderFooter( rStrm );              break;
+                case BIFF12_ID_PICTURE:         getPageSettings().importPicture( getRelations(), rStrm );   break;
+                case BIFF12_ID_SHEETPROTECTION: getWorksheetSettings().importSheetProtection( rStrm );      break;
+                case BIFF12_ID_PHONETICPR:      getWorksheetSettings().importPhoneticPr( rStrm );           break;
+                case BIFF12_ID_DRAWING:         importDrawing( rStrm );                                     break;
+                case BIFF12_ID_LEGACYDRAWING:   importLegacyDrawing( rStrm );                               break;
+            }
+        break;
+
+        case BIFF12_ID_SHEETVIEWS:
+            switch( nRecId )
+            {
+                case BIFF12_ID_SHEETVIEW:       getSheetViewSettings().importSheetView( rStrm );            return this;
+            }
+        break;
+        case BIFF12_ID_SHEETVIEW:
+            switch( nRecId )
+            {
+                case BIFF12_ID_PANE:            getSheetViewSettings().importPane( rStrm );                 break;
+                case BIFF12_ID_SELECTION:       getSheetViewSettings().importSelection( rStrm );            break;
+            }
+        break;
+
+        case BIFF12_ID_COLS:
+            if( nRecId == BIFF12_ID_COL ) importCol( rStrm );
+        break;
+        case BIFF12_ID_MERGECELLS:
+            if( nRecId == BIFF12_ID_MERGECELL ) importMergeCell( rStrm );
+        break;
+        case BIFF12_ID_ROWBREAKS:
+            if( nRecId == BIFF12_ID_BRK ) importBrk( rStrm, true );
+        break;
+        case BIFF12_ID_COLBREAKS:
+            if( nRecId == BIFF12_ID_BRK ) importBrk( rStrm, false );
+        break;
+        case BIFF12_ID_OLEOBJECTS:
+            if( nRecId == BIFF12_ID_OLEOBJECT ) importOleObject( rStrm );
+        break;
+        case BIFF12_ID_CONTROLS:
+            if( nRecId == BIFF12_ID_CONTROL ) importControl( rStrm );
+        break;
+    }
+    return 0;
+}
+
+const RecordInfo* WorksheetFragment::getRecordInfos() const
+{
+    static const RecordInfo spRecInfos[] =
+    {
+        { BIFF12_ID_AUTOFILTER,         BIFF12_ID_AUTOFILTER + 1        },
+        { BIFF12_ID_CFRULE,             BIFF12_ID_CFRULE + 1            },
+        { BIFF12_ID_COLBREAKS,          BIFF12_ID_COLBREAKS + 1         },
+        { BIFF12_ID_COLORSCALE,         BIFF12_ID_COLORSCALE + 1        },
+        { BIFF12_ID_COLS,               BIFF12_ID_COLS + 1              },
+        { BIFF12_ID_CONDFORMATTING,     BIFF12_ID_CONDFORMATTING + 1    },
+        { BIFF12_ID_CONTROLS,           BIFF12_ID_CONTROLS + 2          },
+        { BIFF12_ID_CUSTOMFILTERS,      BIFF12_ID_CUSTOMFILTERS + 1     },
+        { BIFF12_ID_CUSTOMSHEETVIEW,    BIFF12_ID_CUSTOMSHEETVIEW + 1   },
+        { BIFF12_ID_CUSTOMSHEETVIEWS,   BIFF12_ID_CUSTOMSHEETVIEWS + 3  },
+        { BIFF12_ID_DATABAR,            BIFF12_ID_DATABAR + 1           },
+        { BIFF12_ID_DATAVALIDATIONS,    BIFF12_ID_DATAVALIDATIONS + 1   },
+        { BIFF12_ID_DISCRETEFILTERS,    BIFF12_ID_DISCRETEFILTERS + 1   },
+        { BIFF12_ID_FILTERCOLUMN,       BIFF12_ID_FILTERCOLUMN + 1      },
+        { BIFF12_ID_HEADERFOOTER,       BIFF12_ID_HEADERFOOTER + 1      },
+        { BIFF12_ID_ICONSET,            BIFF12_ID_ICONSET + 1           },
+        { BIFF12_ID_MERGECELLS,         BIFF12_ID_MERGECELLS + 1        },
+        { BIFF12_ID_OLEOBJECTS,         BIFF12_ID_OLEOBJECTS + 2        },
+        { BIFF12_ID_ROW,                -1                              },
+        { BIFF12_ID_ROWBREAKS,          BIFF12_ID_ROWBREAKS + 1         },
+        { BIFF12_ID_SCENARIO,           BIFF12_ID_SCENARIO + 1          },
+        { BIFF12_ID_SCENARIOS,          BIFF12_ID_SCENARIOS + 1         },
+        { BIFF12_ID_SHEETDATA,          BIFF12_ID_SHEETDATA + 1         },
+        { BIFF12_ID_SHEETVIEW,          BIFF12_ID_SHEETVIEW + 1         },
+        { BIFF12_ID_SHEETVIEWS,         BIFF12_ID_SHEETVIEWS + 1        },
+        { BIFF12_ID_TABLEPARTS,         BIFF12_ID_TABLEPARTS + 2        },
+        { BIFF12_ID_WORKSHEET,          BIFF12_ID_WORKSHEET + 1         },
+        { -1,                           -1                              }
+    };
+    return spRecInfos;
+}
+
+void WorksheetFragment::initializeImport()
+{
+    // initial processing in base class WorksheetHelper
+    initializeWorksheetImport();
+
+    // import query table fragments related to this worksheet
+    RelationsRef xQueryRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "queryTable" ) );
+    for( Relations::const_iterator aIt = xQueryRels->begin(), aEnd = xQueryRels->end(); aIt != aEnd; ++aIt )
+        importOoxFragment( new QueryTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
+
+    // import pivot table fragments related to this worksheet
+    RelationsRef xPivotRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "pivotTable" ) );
+    for( Relations::const_iterator aIt = xPivotRels->begin(), aEnd = xPivotRels->end(); aIt != aEnd; ++aIt )
+        importOoxFragment( new PivotTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
+}
+
+void WorksheetFragment::finalizeImport()
+{
+    // final processing in base class WorksheetHelper
+    finalizeWorksheetImport();
+}
+
+// private --------------------------------------------------------------------
+
+void WorksheetFragment::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 WorksheetFragment::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 WorksheetFragment::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 WorksheetFragment::importCol( const AttributeList& rAttribs )
+{
+    ColumnModel aModel;
+    aModel.maRange.mnFirst = rAttribs.getInteger( XML_min, -1 );
+    aModel.maRange.mnLast  = 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 WorksheetFragment::importMergeCell( const AttributeList& rAttribs )
+{
+    CellRangeAddress aRange;
+    if( getAddressConverter().convertToCellRange( aRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex(), true, true ) )
+        getSheetData().setMergedRange( aRange );
+}
+
+void WorksheetFragment::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 WorksheetFragment::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 WorksheetFragment::importDrawing( const AttributeList& rAttribs )
+{
+    setDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
+}
+
+void WorksheetFragment::importLegacyDrawing( const AttributeList& rAttribs )
+{
+    setVmlDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
+}
+
+void WorksheetFragment::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 ) ),
+        "WorksheetFragment::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 WorksheetFragment::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 WorksheetFragment::importDimension( SequenceInputStream& 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 WorksheetFragment::importSheetFormatPr( SequenceInputStream& 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 BIFF12, convert to entire character
+    setDefaultColumnWidth( static_cast< double >( nDefaultWidth ) / 256.0 );
+    // row height is in twips in BIFF12, convert to points; equal flags in all BIFFs
+    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 WorksheetFragment::importCol( SequenceInputStream& rStrm )
+{
+    ColumnModel aModel;
+
+    sal_Int32 nWidth;
+    sal_uInt16 nFlags;
+    rStrm >> aModel.maRange.mnFirst >> aModel.maRange.mnLast >> nWidth >> aModel.mnXfId >> nFlags;
+
+    // column indexes are 0-based in BIFF12, but ColumnModel expects 1-based
+    ++aModel.maRange.mnFirst;
+    ++aModel.maRange.mnLast;
+    // width is stored as 1/256th of a character in BIFF12, convert to entire character
+    aModel.mfWidth        = static_cast< double >( nWidth ) / 256.0;
+    // equal flags in all BIFFs
+    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 WorksheetFragment::importMergeCell( SequenceInputStream& rStrm )
+{
+    BinRange aBinRange;
+    rStrm >> aBinRange;
+    CellRangeAddress aRange;
+    if( getAddressConverter().convertToCellRange( aRange, aBinRange, getSheetIndex(), true, true ) )
+        getSheetData().setMergedRange( aRange );
+}
+
+void WorksheetFragment::importHyperlink( SequenceInputStream& rStrm )
+{
+    BinRange aBinRange;
+    rStrm >> aBinRange;
+    HyperlinkModel aModel;
+    if( getAddressConverter().convertToCellRange( aModel.maRange, aBinRange, getSheetIndex(), true, true ) )
+    {
+        aModel.maTarget = getRelations().getExternalTargetFromRelId( BiffHelper::readString( rStrm ) );
+        rStrm >> aModel.maLocation >> aModel.maTooltip >> aModel.maDisplay;
+        setHyperlink( aModel );
+    }
+}
+
+void WorksheetFragment::importBrk( SequenceInputStream& rStrm, bool bRowBreak )
+{
+    PageBreakModel aModel;
+    sal_Int32 nManual;
+    rStrm >> aModel.mnColRow >> aModel.mnMin >> aModel.mnMax >> nManual;
+    aModel.mbManual = nManual != 0;
+    setPageBreak( aModel, bRowBreak );
+}
+
+void WorksheetFragment::importDrawing( SequenceInputStream& rStrm )
+{
+    setDrawingPath( getFragmentPathFromRelId( BiffHelper::readString( rStrm ) ) );
+}
+
+void WorksheetFragment::importLegacyDrawing( SequenceInputStream& rStrm )
+{
+    setVmlDrawingPath( getFragmentPathFromRelId( BiffHelper::readString( rStrm ) ) );
+}
+
+void WorksheetFragment::importOleObject( SequenceInputStream& rStrm )
+{
+    ::oox::vml::OleObjectInfo aInfo;
+    sal_Int32 nAspect, nUpdateMode, nShapeId;
+    sal_uInt16 nFlags;
+    rStrm >> nAspect >> nUpdateMode >> nShapeId >> nFlags >> aInfo.maProgId;
+    aInfo.mbLinked = getFlag( nFlags, BIFF12_OLEOBJECT_LINKED );
+    if( aInfo.mbLinked )
+        aInfo.maTargetLink = getFormulaParser().importOleTargetLink( rStrm );
+    else
+        importEmbeddedOleData( aInfo.maEmbeddedData, BiffHelper::readString( rStrm ) );
+    aInfo.setShapeId( nShapeId );
+    aInfo.mbShowAsIcon = nAspect == BIFF12_OLEOBJECT_ICON;
+    aInfo.mbAutoUpdate = nUpdateMode == BIFF12_OLEOBJECT_ALWAYS;
+    aInfo.mbAutoLoad = getFlag( nFlags, BIFF12_OLEOBJECT_AUTOLOAD );
+    getVmlDrawing().registerOleObject( aInfo );
+}
+
+void WorksheetFragment::importControl( SequenceInputStream& rStrm )
+{
+    ::oox::vml::ControlInfo aInfo;
+    aInfo.setShapeId( rStrm.readInt32() );
+    aInfo.maFragmentPath = getFragmentPathFromRelId( BiffHelper::readString( rStrm ) );
+    rStrm >> aInfo.maName;
+    getVmlDrawing().registerControl( aInfo );
+}
+
+void WorksheetFragment::importEmbeddedOleData( StreamDataSequence& orEmbeddedData, const OUString& rRelId )
+{
+    OUString aFragmentPath = getFragmentPathFromRelId( rRelId );
+    if( !aFragmentPath.isEmpty() )
+        getBaseFilter().importBinaryData( orEmbeddedData, aFragmentPath );
+}
+
+// ============================================================================
+
+BiffWorksheetFragment::BiffWorksheetFragment( const WorksheetHelper& rHelper, const BiffWorkbookFragmentBase& rParent ) :
+    BiffWorksheetFragmentBase( rHelper, rParent )
+{
+}
+
+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();
+    BiffSheetDrawing& rDrawing        = getBiffDrawing();
+
+    // process all record in this sheet fragment
+    BiffInputStream& rStrm = getInputStream();
+    while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
+    {
+        if( BiffHelper::isBofRecord( rStrm ) )
+        {
+            // skip unknown embedded fragments (BOF/EOF blocks)
+            skipFragment();
+        }
+        else
+        {
+            // cache base stream position to detect if record is already processed
+            sal_Int64 nStrmPos = rStrm.tellBase();
+            sal_uInt16 nRecId = rStrm.getRecId();
+
+            switch( nRecId )
+            {
+                // records in all BIFF versions
+                case BIFF_ID_BOTTOMMARGIN:      rPageSett.importBottomMargin( rStrm );      break;
+                case BIFF_ID_CALCCOUNT:         rWorkbookSett.importCalcCount( rStrm );     break;
+                case BIFF_ID_CALCMODE:          rWorkbookSett.importCalcMode( rStrm );      break;
+                case BIFF_ID_DEFCOLWIDTH:       importDefColWidth( rStrm );                 break;
+                case BIFF_ID_DELTA:             rWorkbookSett.importDelta( rStrm );         break;
+                case BIFF2_ID_DIMENSION:        importDimension( rStrm );                   break;
+                case BIFF3_ID_DIMENSION:        importDimension( rStrm );                   break;
+                case BIFF_ID_FOOTER:            rPageSett.importFooter( rStrm );            break;
+                case BIFF_ID_HEADER:            rPageSett.importHeader( rStrm );            break;
+                case BIFF_ID_HORPAGEBREAKS:     importPageBreaks( rStrm, true );            break;
+                case BIFF_ID_ITERATION:         rWorkbookSett.importIteration( rStrm );     break;
+                case BIFF_ID_LEFTMARGIN:        rPageSett.importLeftMargin( rStrm );        break;
+                case BIFF_ID_NOTE:              importNote( rStrm );                        break;
+                case BIFF_ID_PANE:              rSheetViewSett.importPane( rStrm );         break;
+                case BIFF_ID_PASSWORD:          rWorksheetSett.importPassword( rStrm );     break;
+                case BIFF_ID_PRINTGRIDLINES:    rPageSett.importPrintGridLines( rStrm );    break;
+                case BIFF_ID_PRINTHEADERS:      rPageSett.importPrintHeaders( rStrm );      break;
+                case BIFF_ID_PROTECT:           rWorksheetSett.importProtect( rStrm );      break;
+                case BIFF_ID_REFMODE:           rWorkbookSett.importRefMode( rStrm );       break;
+                case BIFF_ID_RIGHTMARGIN:       rPageSett.importRightMargin( rStrm );       break;
+                case BIFF_ID_SELECTION:         rSheetViewSett.importSelection( rStrm );    break;
+                case BIFF_ID_TOPMARGIN:         rPageSett.importTopMargin( rStrm );         break;
+                case BIFF_ID_VERPAGEBREAKS:     importPageBreaks( rStrm, false );           break;
+
+                // BIFF specific records
+                default: switch( getBiff() )
+                {
+                    case BIFF2: switch( nRecId )
+                    {
+                        case BIFF_ID_COLUMNDEFAULT: importColumnDefault( rStrm );           break;
+                        case BIFF_ID_COLWIDTH:      importColWidth( rStrm );                break;
+                        case BIFF2_ID_DEFROWHEIGHT: importDefRowHeight( rStrm );            break;
+                        case BIFF2_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );  break;
+                    }
+                    break;
+
+                    case BIFF3: switch( nRecId )
+                    {
+                        case BIFF_ID_COLINFO:       importColInfo( rStrm );                         break;
+                        case BIFF_ID_DEFCOLWIDTH:   importDefColWidth( rStrm );                     break;
+                        case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm );                    break;
+                        case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
+                        case BIFF_ID_OBJ:           rDrawing.importObj( rStrm );                    break;
+                        case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
+                        case BIFF_ID_SAVERECALC:    rWorkbookSett.importSaveRecalc( rStrm );        break;
+                        case BIFF_ID_SHEETPR:       rWorksheetSett.importSheetPr( rStrm );          break;
+                        case BIFF_ID_UNCALCED:      rWorkbookSett.importUncalced( rStrm );          break;
+                        case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
+                        case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
+                    }
+                    break;
+
+                    case BIFF4: switch( nRecId )
+                    {
+                        case BIFF_ID_COLINFO:       importColInfo( rStrm );                         break;
+                        case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm );                    break;
+                        case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
+                        case BIFF_ID_OBJ:           rDrawing.importObj( rStrm );                    break;
+                        case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
+                        case BIFF_ID_PAGESETUP:     rPageSett.importPageSetup( rStrm );             break;
+                        case BIFF_ID_SAVERECALC:    rWorkbookSett.importSaveRecalc( rStrm );        break;
+                        case BIFF_ID_SHEETPR:       rWorksheetSett.importSheetPr( rStrm );          break;
+                        case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm );                   break;
+                        case BIFF_ID_UNCALCED:      rWorkbookSett.importUncalced( rStrm );          break;
+                        case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
+                        case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
+                    }
+                    break;
+
+                    case BIFF5: switch( nRecId )
+                    {
+                        case BIFF_ID_AUTOFILTER:    importAutoFilter( rStrm );                      break;
+                        case BIFF_ID_COLINFO:       importColInfo( rStrm );                         break;
+                        case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm );                    break;
+                        case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
+                        case BIFF_ID_MERGEDCELLS:   importMergedCells( rStrm );                     break;  // #i62300# also in BIFF5
+                        case BIFF_ID_OBJ:           rDrawing.importObj( rStrm );                    break;
+                        case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
+                        case BIFF_ID_PAGESETUP:     rPageSett.importPageSetup( rStrm );             break;
+                        case BIFF_ID_PTDEFINITION:  importPTDefinition( rStrm );                    break;
+                        case BIFF_ID_SAVERECALC:    rWorkbookSett.importSaveRecalc( rStrm );        break;
+                        case BIFF_ID_SCENPROTECT:   rWorksheetSett.importScenProtect( rStrm );      break;
+                        case BIFF_ID_SCL:           rSheetViewSett.importScl( rStrm );              break;
+                        case BIFF_ID_SHEETPR:       rWorksheetSett.importSheetPr( rStrm );          break;
+                        case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm );                   break;
+                        case BIFF_ID_UNCALCED:      rWorkbookSett.importUncalced( rStrm );          break;
+                        case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
+                        case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
+                    }
+                    break;
+
+                    case BIFF8: switch( nRecId )
+                    {
+                        case BIFF_ID_AUTOFILTER:        importAutoFilter( rStrm );                      break;
+                        case BIFF_ID_CFHEADER:          rCondFormats.importCfHeader( rStrm );           break;
+                        case BIFF_ID_CODENAME:          rWorksheetSett.importCodeName( rStrm );         break;
+                        case BIFF_ID_COLINFO:           importColInfo( rStrm );                         break;
+                        case BIFF_ID_DATAVALIDATION:    importDataValidation( rStrm );                  break;
+                        case BIFF_ID_DATAVALIDATIONS:   importDataValidations( rStrm );                 break;
+                        case BIFF3_ID_DEFROWHEIGHT:     importDefRowHeight( rStrm );                    break;
+                        case BIFF_ID_HCENTER:           rPageSett.importHorCenter( rStrm );             break;
+                        case BIFF_ID_HYPERLINK:         importHyperlink( rStrm );                       break;
+                        case BIFF_ID_LABELRANGES:       importLabelRanges( rStrm );                     break;
+                        case BIFF_ID_MERGEDCELLS:       importMergedCells( rStrm );                     break;
+                        case BIFF_ID_OBJ:               rDrawing.importObj( rStrm );                    break;
+                        case BIFF_ID_OBJECTPROTECT:     rWorksheetSett.importObjectProtect( rStrm );    break;
+                        case BIFF_ID_PAGESETUP:         rPageSett.importPageSetup( rStrm );             break;
+                        case BIFF_ID_PHONETICPR:        rWorksheetSett.importPhoneticPr( rStrm );       break;
+                        case BIFF_ID_PICTURE:           rPageSett.importPicture( rStrm );               break;
+                        case BIFF_ID_PTDEFINITION:      importPTDefinition( rStrm );                    break;
+                        case BIFF_ID_QUERYTABLE:        importQueryTable( rStrm );                      break;
+                        case BIFF_ID_SAVERECALC:        rWorkbookSett.importSaveRecalc( rStrm );        break;
+                        case BIFF_ID_SCENARIOS:         importScenarios( rStrm );                       break;
+                        case BIFF_ID_SCENPROTECT:       rWorksheetSett.importScenProtect( rStrm );      break;
+                        case BIFF_ID_SCL:               rSheetViewSett.importScl( rStrm );              break;
+                        case BIFF_ID_SHEETEXT:          rWorksheetSett.importSheetExt( rStrm );         break;
+                        case BIFF_ID_SHEETPR:           rWorksheetSett.importSheetPr( rStrm );          break;
+                        case BIFF_ID_SHAREDFEATHEAD:    importSharedFeatHead( rStrm );                  break;
+                        case BIFF_ID_STANDARDWIDTH:     importStandardWidth( rStrm );                   break;
+                        case BIFF_ID_UNCALCED:          rWorkbookSett.importUncalced( rStrm );          break;
+                        case BIFF_ID_VCENTER:           rPageSett.importVerCenter( rStrm );             break;
+                        case BIFF3_ID_WINDOW2:          rSheetViewSett.importWindow2( rStrm );          break;
+                    }
+                    break;
+
+                    case BIFF_UNKNOWN: break;
+                }
+            }
+
+            // record not processed, try record context objects
+            if( rStrm.tellBase() == nStrmPos )
+            {
+                // first, try cell table records
+                aSheetData.importRecord( rStrm );
+                // handle another open record context
+                if( mxContext.get() )
+                {
+                    // if it was a cell table record, forget the other record context
+                    if( rStrm.tellBase() == nStrmPos )
+                        mxContext->importRecord( rStrm );
+                    else
+                        mxContext.reset();
+                }
+            }
+        }
+    }
+
+    // final processing in base class WorksheetHelper
+    finalizeWorksheetImport();
+    return rStrm.getRecId() == BIFF_ID_EOF;
+}
+
+// private --------------------------------------------------------------------
+
+void BiffWorksheetFragment::importAutoFilter( BiffInputStream& rStrm )
+{
+    mxContext.reset( new BiffAutoFilterContext( *this, getAutoFilters().createAutoFilter() ) );
+    mxContext->importRecord( rStrm );
+}
+
+void BiffWorksheetFragment::importColInfo( BiffInputStream& rStrm )
+{
+    sal_uInt16 nFirstCol, nLastCol, nWidth, nXfId, nFlags;
+    rStrm >> nFirstCol >> nLastCol >> nWidth >> nXfId >> nFlags;
+
+    ColumnModel aModel;
+    // column indexes are 0-based in BIFF, but ColumnModel expects 1-based
+    aModel.maRange.mnFirst = static_cast< sal_Int32 >( nFirstCol ) + 1;
+    aModel.maRange.mnLast  = 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( BiffInputStream& rStrm )
+{
+    sal_uInt16 nFirstCol, nLastCol, nXfId;
+    rStrm >> nFirstCol >> nLastCol >> nXfId;
+    setDefaultColumnFormat( nFirstCol, nLastCol, nXfId );
+}
+
+void BiffWorksheetFragment::importColWidth( BiffInputStream& rStrm )
+{
+    sal_uInt8 nFirstCol, nLastCol;
+    sal_uInt16 nWidth;
+    rStrm >> nFirstCol >> nLastCol >> nWidth;
+
+    ColumnModel aModel;
+    // column indexes are 0-based in BIFF, but ColumnModel expects 1-based
+    aModel.maRange.mnFirst = static_cast< sal_Int32 >( nFirstCol ) + 1;
+    aModel.maRange.mnLast = 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( BiffInputStream& rStrm )
+{
+    /*  Stored as entire number of characters without padding pixels, which
+        will be added in setBaseColumnWidth(). Call has no effect, if a
+        width has already been set from the STANDARDWIDTH record. */
+    setBaseColumnWidth( rStrm.readuInt16() );
+}
+
+void BiffWorksheetFragment::importDefRowHeight( BiffInputStream& rStrm )
+{
+    sal_uInt16 nFlags = BIFF_DEFROW_CUSTOMHEIGHT, nHeight;
+    if( getBiff() != BIFF2 )
+        rStrm >> nFlags;
+    rStrm >> nHeight;
+    if( getBiff() == BIFF2 )
+        nHeight &= BIFF2_DEFROW_MASK;
+    // row height is in twips in BIFF, convert to points
+    setDefaultRowSettings(
+        nHeight / 20.0,
+        getFlag( nFlags, BIFF_DEFROW_CUSTOMHEIGHT ),
+        getFlag( nFlags, BIFF_DEFROW_HIDDEN ),
+        getFlag( nFlags, BIFF_DEFROW_THICKTOP ),
+        getFlag( nFlags, BIFF_DEFROW_THICKBOTTOM ) );
+}
+
+void BiffWorksheetFragment::importDataValidations( BiffInputStream& rStrm )
+{
+    sal_Int32 nObjId;
+    rStrm.skip( 10 );
+    rStrm >> nObjId;
+    //! TODO: invalidate object id in drawing object manager
+}
+
+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 );
+    return rParser.importFormula( CellAddress(), FORMULATYPE_VALIDATION, rStrm, &nFmlaSize );
+}
+
+} // namespace
+
+void BiffWorksheetFragment::importDataValidation( BiffInputStream& rStrm )
+{
+    ValidationModel aModel;
+
+    // flags
+    sal_uInt32 nFlags;
+    rStrm >> nFlags;
+    aModel.setBiffType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
+    aModel.setBiffOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
+    aModel.setBiffErrorStyle( 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( rStrm );
+    aModel.maErrorTitle   = lclReadDataValMessage( rStrm );
+    aModel.maInputMessage = lclReadDataValMessage( rStrm );
+    aModel.maErrorMessage = lclReadDataValMessage( rStrm );
+
+    // condition formula(s)
+    FormulaParser& rParser = getFormulaParser();
+    aModel.maTokens1 = lclReadDataValFormula( rStrm, rParser );
+    aModel.maTokens2 = lclReadDataValFormula( rStrm, 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;
+    rStrm >> aRanges;
+    getAddressConverter().convertToCellRangeList( aModel.maRanges, aRanges, getSheetIndex(), true );
+
+    // set validation data
+    setValidation( aModel );
+}
+
+void BiffWorksheetFragment::importDimension( BiffInputStream& rStrm )
+{
+    // 32-bit row indexes in BIFF8
+    bool bInt32Rows = (rStrm.getRecId() == BIFF3_ID_DIMENSION) && (getBiff() == BIFF8);
+    BinRange aBinRange;
+    aBinRange.read( rStrm, 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( BiffInputStream& rStrm )
+{
+    HyperlinkModel aModel;
+
+    // read cell range for the hyperlink
+    BinRange aBiffRange;
+    rStrm >> aBiffRange;
+    // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
+    aBiffRange.maFirst.mnCol &= 0xFF;
+    aBiffRange.maLast.mnCol &= 0xFF;
+    if( !getAddressConverter().convertToCellRange( aModel.maRange, aBiffRange, getSheetIndex(), true, true ) )
+        return;
+
+    // try to read the StdHlink data
+    if( !::oox::ole::OleHelper::importStdHlink( aModel, rStrm, true ) )
+        return;
+
+    // try to read the optional following SCREENTIP record
+    if( (rStrm.getNextRecId() == BIFF_ID_SCREENTIP) && rStrm.startNextRecord() )
+    {
+        rStrm.skip( 2 );      // repeated record id
+        // the cell range, again
+        rStrm >> aBiffRange;
+        CellRangeAddress aRange;
+        if( getAddressConverter().convertToCellRange( aRange, aBiffRange, getSheetIndex(), true, 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 = rStrm.readNulUnicodeArray();
+        }
+    }
+
+    // store the hyperlink settings
+    setHyperlink( aModel );
+}
+
+void BiffWorksheetFragment::importLabelRanges( BiffInputStream& rStrm )
+{
+    BinRangeList aBiffRowRanges, aBiffColRanges;
+    rStrm >> aBiffRowRanges >> aBiffColRanges;
+    ApiCellRangeList aColRanges, aRowRanges;
+    getAddressConverter().convertToCellRangeList( aColRanges, aBiffColRanges, getSheetIndex(), true );
+    getAddressConverter().convertToCellRangeList( aRowRanges, aBiffRowRanges, getSheetIndex(), true );
+    setLabelRanges( aColRanges, aRowRanges );
+}
+
+void BiffWorksheetFragment::importMergedCells( BiffInputStream& rStrm )
+{
+    BinRangeList aBiffRanges;
+    rStrm >> aBiffRanges;
+    ApiCellRangeList aRanges;
+    getAddressConverter().convertToCellRangeList( aRanges, aBiffRanges, getSheetIndex(), true );
+    for( ApiCellRangeList::const_iterator aIt = aRanges.begin(), aEnd = aRanges.end(); aIt != aEnd; ++aIt )
+        getSheetData().setMergedRange( *aIt );
+}
+
+void BiffWorksheetFragment::importNote( BiffInputStream& rStrm )
+{
+    getComments().createComment()->importNote( rStrm );
+}
+
+void BiffWorksheetFragment::importPageBreaks( BiffInputStream& rStrm, 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;
+    rStrm >> nCount;
+    for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
+    {
+        aModel.mnColRow = rStrm.readuInt16();
+        setPageBreak( aModel, bRowBreak );
+        if( bBiff8 )
+            rStrm.skip( 4 );
+    }
+}
+
+void BiffWorksheetFragment::importPTDefinition( BiffInputStream& rStrm )
+{
+    mxContext.reset( new BiffPivotTableContext( *this ) );
+    mxContext->importRecord( rStrm );
+}
+
+void BiffWorksheetFragment::importQueryTable( BiffInputStream& rStrm )
+{
+    mxContext.reset( new BiffQueryTableContext( *this ) );
+    mxContext->importRecord( rStrm );
+}
+
+void BiffWorksheetFragment::importScenarios( BiffInputStream& rStrm )
+{
+    getScenarios().createSheetScenarios( getSheetIndex() ).importScenarios( rStrm );
+}
+
+void BiffWorksheetFragment::importSharedFeatHead( BiffInputStream& rStrm )
+{
+    rStrm.skip( 12 );
+    sal_uInt16 nType = rStrm.readuInt16();
+    rStrm.skip( 5 );
+    switch( nType )
+    {
+        case BIFF_SHRFEATHEAD_SHEETPROT:
+            if( rStrm.getRemaining() >= 4 )
+                getWorksheetSettings().importSheetProtection( rStrm );
+        break;
+    }
+}
+
+void BiffWorksheetFragment::importStandardWidth( BiffInputStream& rStrm )
+{
+    sal_uInt16 nWidth;
+    rStrm >> nWidth;
+    // width is stored as 1/256th of a character in BIFF, convert to entire character
+    double fWidth = static_cast< double >( nWidth ) / 256.0;
+    // set as default width, will override the width from DEFCOLWIDTH record
+    setDefaultColumnWidth( fWidth );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/worksheethelper.cxx b/sc/source/filter/oox/worksheethelper.cxx
new file mode 100644
index 000000000000..27e8eab76878
--- /dev/null
+++ b/sc/source/filter/oox/worksheethelper.cxx
@@ -0,0 +1,1667 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "worksheethelper.hxx"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "addressconverter.hxx"
+#include "autofilterbuffer.hxx"
+#include "commentsbuffer.hxx"
+#include "condformatbuffer.hxx"
+#include "drawingfragment.hxx"
+#include "drawingmanager.hxx"
+#include "formulaparser.hxx"
+#include "pagesettings.hxx"
+#include "querytablebuffer.hxx"
+#include "sharedstringsbuffer.hxx"
+#include "sheetdatabuffer.hxx"
+#include "stylesbuffer.hxx"
+#include "unitconverter.hxx"
+#include "viewsettings.hxx"
+#include "workbooksettings.hxx"
+#include "worksheetbuffer.hxx"
+#include "worksheetsettings.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, const CellRangeAddress& rUsedArea, sal_Int32 nRow )
+{
+    if( rxProgressBar.get() && (rUsedArea.StartRow <= nRow) && (nRow <= rUsedArea.EndRow) )
+    {
+        double fPosition = static_cast< double >( nRow - rUsedArea.StartRow + 1 ) / (rUsedArea.EndRow - rUsedArea.StartRow + 1);
+        if( rxProgressBar->getPosition() < fPosition )
+            rxProgressBar->setPosition( fPosition );
+    }
+}
+
+void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, double fPosition )
+{
+    if( rxProgressBar.get() )
+        rxProgressBar->setPosition( fPosition );
+}
+
+} // namespace
+
+// ============================================================================
+// ============================================================================
+
+ColumnModel::ColumnModel() :
+    maRange( -1 ),
+    mfWidth( 0.0 ),
+    mnXfId( -1 ),
+    mnLevel( 0 ),
+    mbShowPhonetic( false ),
+    mbHidden( false ),
+    mbCollapsed( false )
+{
+}
+
+bool ColumnModel::isMergeable( const ColumnModel& rModel ) const
+{
+    return
+        (maRange.mnFirst        <= rModel.maRange.mnFirst) &&
+        (rModel.maRange.mnFirst <= maRange.mnLast + 1) &&
+        (mfWidth                == rModel.mfWidth) &&
+        // ignore mnXfId, cell formatting is always set directly
+        (mnLevel                == rModel.mnLevel) &&
+        (mbHidden               == rModel.mbHidden) &&
+        (mbCollapsed            == rModel.mbCollapsed);
+}
+
+// ----------------------------------------------------------------------------
+
+RowModel::RowModel() :
+    mnRow( -1 ),
+    mfHeight( 0.0 ),
+    mnXfId( -1 ),
+    mnLevel( 0 ),
+    mbCustomHeight( false ),
+    mbCustomFormat( false ),
+    mbShowPhonetic( false ),
+    mbHidden( false ),
+    mbCollapsed( false ),
+    mbThickTop( false ),
+    mbThickBottom( false )
+{
+}
+
+void RowModel::insertColSpan( const ValueRange& rColSpan )
+{
+    if( (0 <= rColSpan.mnFirst) && (rColSpan.mnFirst <= rColSpan.mnLast) )
+        maColSpans.insert( rColSpan );
+}
+
+bool RowModel::isMergeable( const RowModel& rModel ) const
+{
+    return
+        // ignore maColSpans - is handled separately in SheetDataBuffer class
+        (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);
+}
+
+// ----------------------------------------------------------------------------
+
+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::setBiffType( 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::setBiffOperator( 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::setBiffErrorStyle( sal_uInt8 nErrorStyle )
+{
+    static const sal_Int32 spnErrorStyles[] = { XML_stop, XML_warning, XML_information };
+    mnErrorStyle = STATIC_ARRAY_SELECT( spnErrorStyles, nErrorStyle, XML_stop );
+}
+
+// ============================================================================
+// ============================================================================
+
+class WorksheetGlobals : public WorkbookHelper
+{
+public:
+    explicit            WorksheetGlobals(
+                            const WorkbookHelper& rHelper,
+                            const ISegmentProgressBarRef& rxProgressBar,
+                            WorksheetType eSheetType,
+                            sal_Int16 nSheet );
+
+    /** Returns true, if this helper refers to an existing Calc sheet. */
+    inline bool         isValidSheet() const { return mxSheet.is(); }
+
+    /** 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 Reference< 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( const ValueRange& rColRange ) const;
+    /** Returns the XTableRows interface for a range of rows. */
+    Reference< XTableRows > getRows( const ValueRange& rRowRange ) 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. */
+    const 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;
+    /** Returns the cell range address that contains the passed rectangle in 1/100 mm. */
+    CellRangeAddress    getCellRangeFromRectangle( const Rectangle& rRect ) const;
+
+    /** Returns the buffer for cell contents and cell formatting. */
+    inline SheetDataBuffer& getSheetData() { return maSheetData; }
+    /** Returns the conditional formatting 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 auto filters for the sheet. */
+    inline AutoFilterBuffer& getAutoFilters() { return maAutoFilters; }
+    /** Returns the buffer for all web query tables in this sheet. */
+    inline QueryTableBuffer& getQueryTables() { return maQueryTables; }
+    /** Returns the worksheet settings object. */
+    inline WorksheetSettings& getWorksheetSettings() { return maSheetSett; }
+    /** 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 (OOXML/BIFF12 only). */
+    inline VmlDrawing&  getVmlDrawing() { return *mxVmlDrawing; }
+    /** Returns the BIFF drawing page for this sheet (BIFF2-BIFF8 only). */
+    inline BiffSheetDrawing& getBiffDrawing() const { return *mxBiffDrawing; }
+
+    /** Changes the current sheet type. */
+    inline void         setSheetType( WorksheetType eSheetType ) { meSheetType = eSheetType; }
+    /** 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 );
+    /** Converts column default cell formatting. */
+    void                convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ) const;
+
+    /** 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 );
+    /** Specifies that the passed row needs to set its height manually. */
+    void                setManualRowHeight( sal_Int32 nRow );
+
+    /** 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::pair< ColumnModel, sal_Int32 >       ColumnModelRange;
+    typedef ::std::map< sal_Int32, ColumnModelRange >   ColumnModelRangeMap;
+    typedef ::std::pair< RowModel, sal_Int32 >          RowModelRange;
+    typedef ::std::map< sal_Int32, RowModelRange >      RowModelRangeMap;
+    typedef ::std::list< HyperlinkModel >               HyperlinkModelList;
+    typedef ::std::list< ValidationModel >              ValidationModelList;
+
+    /** 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;
+
+    /** Converts column properties for all columns in the sheet. */
+    void                convertColumns();
+    /** Converts column properties. */
+    void                convertColumns( OutlineLevelVec& orColLevels, const ValueRange& rColRange, const ColumnModel& rModel );
+
+    /** Converts row properties for all rows in the sheet. */
+    void                convertRows();
+    /** Converts row properties. */
+    void                convertRows( OutlineLevelVec& orRowLevels, const ValueRange& rRowRange, 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 );
+
+    /** Imports the drawings of the sheet (DML, VML, DFF) and updates the used area. */
+    void                finalizeDrawings();
+
+private:
+    typedef ::std::auto_ptr< VmlDrawing >       VmlDrawingPtr;
+    typedef ::std::auto_ptr< BiffSheetDrawing > BiffSheetDrawingPtr;
+
+    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.
+    ColumnModelRangeMap maColModels;        /// Ranges of columns sorted by first column index.
+    RowModel            maDefRowModel;      /// Default row formatting.
+    RowModelRangeMap    maRowModels;        /// Ranges of rows sorted by first row index.
+    HyperlinkModelList  maHyperlinks;       /// Cell ranges containing hyperlinks.
+    ValidationModelList maValidations;      /// Cell ranges containing data validation settings.
+    ValueRangeSet       maManualRowHeights; /// Rows that need manual height independent from own settings.
+    SheetDataBuffer     maSheetData;        /// Buffer for cell contents and cell formatting.
+    CondFormatBuffer    maCondFormats;      /// Buffer for conditional formatting.
+    CommentsBuffer      maComments;         /// Buffer for all cell comments in this sheet.
+    AutoFilterBuffer    maAutoFilters;      /// Sheet auto filters (not associated to a table).
+    QueryTableBuffer    maQueryTables;      /// Buffer for all web query tables in this sheet.
+    WorksheetSettings   maSheetSett;        /// Global settings for this sheet.
+    PageSettings        maPageSett;         /// Page/print settings for this sheet.
+    SheetViewSettings   maSheetViewSett;    /// View settings for this sheet.
+    VmlDrawingPtr       mxVmlDrawing;       /// Collection of all VML shapes.
+    BiffSheetDrawingPtr mxBiffDrawing;      /// Collection of all BIFF/DFF shapes.
+    OUString            maDrawingPath;      /// Path to DrawingML fragment.
+    OUString            maVmlDrawingPath;   /// Path to legacy VML drawing fragment.
+    Size                maDrawPageSize;     /// Current size of the drawing page in 1/100 mm.
+    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.
+};
+
+// ----------------------------------------------------------------------------
+
+WorksheetGlobals::WorksheetGlobals( const WorkbookHelper& rHelper, const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
+    WorkbookHelper( rHelper ),
+    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 ),
+    maSheetData( *this ),
+    maCondFormats( *this ),
+    maComments( *this ),
+    maAutoFilters( *this ),
+    maQueryTables( *this ),
+    maSheetSett( *this ),
+    maPageSett( *this ),
+    maSheetViewSett( *this ),
+    mxProgressBar( rxProgressBar ),
+    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
+    switch( getFilterType() )
+    {
+        case FILTER_OOXML:
+            mxVmlDrawing.reset( new VmlDrawing( *this ) );
+        break;
+        case FILTER_BIFF:
+            mxBiffDrawing.reset( new BiffSheetDrawing( *this ) );
+        break;
+        case FILTER_UNKNOWN:
+        break;
+    }
+
+    // prepare progress bars
+    if( mxProgressBar.get() )
+    {
+        mxRowProgress = mxProgressBar->createSegment( 0.5 );
+        mxFinalProgress = mxProgressBar->createSegment( 0.5 );
+    }
+}
+
+Reference< XCell > WorksheetGlobals::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 > WorksheetGlobals::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 > WorksheetGlobals::getCellRangeList( const ApiCellRangeList& rRanges ) const
+{
+    Reference< XSheetCellRanges > xRanges;
+    if( mxSheet.is() && !rRanges.empty() ) try
+    {
+        xRanges.set( getBaseFilter().getModelFactory()->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 > WorksheetGlobals::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 > WorksheetGlobals::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 > WorksheetGlobals::getColumns( const ValueRange& rColRange ) const
+{
+    Reference< XTableColumns > xColumns;
+    sal_Int32 nLastCol = ::std::min( rColRange.mnLast, mrMaxApiPos.Column );
+    if( (0 <= rColRange.mnFirst) && (rColRange.mnFirst <= nLastCol) )
+    {
+        Reference< XColumnRowRange > xRange( getCellRange( CellRangeAddress( getSheetIndex(), rColRange.mnFirst, 0, nLastCol, 0 ) ), UNO_QUERY );
+        if( xRange.is() )
+            xColumns = xRange->getColumns();
+    }
+    return xColumns;
+}
+
+Reference< XTableRows > WorksheetGlobals::getRows( const ValueRange& rRowRange ) const
+{
+    Reference< XTableRows > xRows;
+    sal_Int32 nLastRow = ::std::min( rRowRange.mnLast, mrMaxApiPos.Row );
+    if( (0 <= rRowRange.mnFirst) && (rRowRange.mnFirst <= nLastRow) )
+    {
+        Reference< XColumnRowRange > xRange( getCellRange( CellRangeAddress( getSheetIndex(), 0, rRowRange.mnFirst, 0, nLastRow ) ), UNO_QUERY );
+        if( xRange.is() )
+            xRows = xRange->getRows();
+    }
+    return xRows;
+}
+
+Reference< XDrawPage > WorksheetGlobals::getDrawPage() const
+{
+    Reference< XDrawPage > xDrawPage;
+    try
+    {
+        xDrawPage = Reference< XDrawPageSupplier >( mxSheet, UNO_QUERY_THROW )->getDrawPage();
+    }
+    catch( Exception& )
+    {
+    }
+    return xDrawPage;
+}
+
+const Size& WorksheetGlobals::getDrawPageSize() const
+{
+    OSL_ENSURE( (maDrawPageSize.Width > 0) && (maDrawPageSize.Height > 0), "WorksheetGlobals::getDrawPageSize - called too early, size invalid" );
+    return maDrawPageSize;
+}
+
+Point WorksheetGlobals::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 WorksheetGlobals::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 WorksheetGlobals::getCellAddressFromPosition( const Point& rPosition ) 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( maDrawPageSize.Width, maDrawPageSize.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 WorksheetGlobals::getCellRangeFromRectangle( const Rectangle& rRect ) const
+{
+    CellAddress aStartAddr = getCellAddressFromPosition( Point( rRect.X, rRect.Y ) );
+    Point aBotRight( rRect.X + rRect.Width, rRect.Y + rRect.Height );
+    CellAddress aEndAddr = getCellAddressFromPosition( aBotRight );
+    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 WorksheetGlobals::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 WorksheetGlobals::setHyperlink( const HyperlinkModel& rModel )
+{
+    maHyperlinks.push_back( rModel );
+}
+
+void WorksheetGlobals::setValidation( const ValidationModel& rModel )
+{
+    maValidations.push_back( rModel );
+}
+
+void WorksheetGlobals::setDrawingPath( const OUString& rDrawingPath )
+{
+    maDrawingPath = rDrawingPath;
+}
+
+void WorksheetGlobals::setVmlDrawingPath( const OUString& rVmlDrawingPath )
+{
+    maVmlDrawingPath = rVmlDrawingPath;
+}
+
+void WorksheetGlobals::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 WorksheetGlobals::extendUsedArea( const CellRangeAddress& rRange )
+{
+    extendUsedArea( CellAddress( rRange.Sheet, rRange.StartColumn, rRange.StartRow ) );
+    extendUsedArea( CellAddress( rRange.Sheet, rRange.EndColumn, rRange.EndRow ) );
+}
+
+void WorksheetGlobals::extendShapeBoundingBox( const Rectangle& rShapeRect )
+{
+    if( (maShapeBoundingBox.Width == 0) && (maShapeBoundingBox.Height == 0) )
+    {
+        // width and height of maShapeBoundingBox are assumed to be zero on first cell
+        maShapeBoundingBox = rShapeRect;
+    }
+    else
+    {
+        sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, rShapeRect.X + rShapeRect.Width );
+        sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, rShapeRect.Y + rShapeRect.Height );
+        maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, rShapeRect.X );
+        maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, rShapeRect.Y );
+        maShapeBoundingBox.Width = nEndX - maShapeBoundingBox.X;
+        maShapeBoundingBox.Height = nEndY - maShapeBoundingBox.Y;
+    }
+}
+
+void WorksheetGlobals::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 WorksheetGlobals::setDefaultColumnWidth( double fWidth )
+{
+    // overrides a width set with setBaseColumnWidth()
+    if( fWidth > 0.0 )
+    {
+        maDefColModel.mfWidth = fWidth;
+        mbHasDefWidth = true;
+    }
+}
+
+void WorksheetGlobals::setColumnModel( const ColumnModel& rModel )
+{
+    // convert 1-based OOXML column indexes to 0-based API column indexes
+    sal_Int32 nFirstCol = rModel.maRange.mnFirst - 1;
+    sal_Int32 nLastCol = rModel.maRange.mnLast - 1;
+    if( getAddressConverter().checkCol( nFirstCol, true ) && (nFirstCol <= nLastCol) )
+    {
+        // validate last column index
+        if( !getAddressConverter().checkCol( nLastCol, true ) )
+            nLastCol = mrMaxApiPos.Column;
+        // try to find entry in column model map that is able to merge with the passed model
+        bool bInsertModel = true;
+        if( !maColModels.empty() )
+        {
+            // find first column model range following nFirstCol (nFirstCol < aIt->first), or end of map
+            ColumnModelRangeMap::iterator aIt = maColModels.upper_bound( nFirstCol );
+            OSL_ENSURE( aIt == maColModels.end(), "WorksheetGlobals::setColModel - columns are unsorted" );
+            // if inserting before another column model, get last free column
+            OSL_ENSURE( (aIt == maColModels.end()) || (nLastCol < aIt->first), "WorksheetGlobals::setColModel - multiple models of the same column" );
+            if( aIt != maColModels.end() )
+                nLastCol = ::std::min( nLastCol, aIt->first - 1 );
+            if( aIt != maColModels.begin() )
+            {
+                // go to previous map element (which may be able to merge with the passed model)
+                --aIt;
+                // the usage of upper_bound() above ensures that aIt->first is less than or equal to nFirstCol now
+                sal_Int32& rnLastMapCol = aIt->second.second;
+                OSL_ENSURE( rnLastMapCol < nFirstCol, "WorksheetGlobals::setColModel - multiple models of the same column" );
+                nFirstCol = ::std::max( rnLastMapCol + 1, nFirstCol );
+                if( (rnLastMapCol + 1 == nFirstCol) && (nFirstCol <= nLastCol) && aIt->second.first.isMergeable( rModel ) )
+                {
+                    // can merge with existing model, update last column index
+                    rnLastMapCol = nLastCol;
+                    bInsertModel = false;
+                }
+            }
+        }
+        if( nFirstCol <= nLastCol )
+        {
+            // insert the column model, if it has not been merged with another
+            if( bInsertModel )
+                maColModels[ nFirstCol ] = ColumnModelRange( rModel, nLastCol );
+            // set column formatting directly
+            convertColumnFormat( nFirstCol, nLastCol, rModel.mnXfId );
+        }
+    }
+}
+
+void WorksheetGlobals::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 WorksheetGlobals::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 WorksheetGlobals::setRowModel( const RowModel& rModel )
+{
+    // convert 1-based OOXML row index to 0-based API row index
+    sal_Int32 nRow = rModel.mnRow - 1;
+    if( getAddressConverter().checkRow( nRow, true ) )
+    {
+        // try to find entry in row model map that is able to merge with the passed model
+        bool bInsertModel = true;
+        bool bUnusedRow = true;
+        if( !maRowModels.empty() )
+        {
+            // find first row model range following nRow (nRow < aIt->first), or end of map
+            RowModelRangeMap::iterator aIt = maRowModels.upper_bound( nRow );
+            OSL_ENSURE( aIt == maRowModels.end(), "WorksheetGlobals::setRowModel - rows are unsorted" );
+            if( aIt != maRowModels.begin() )
+            {
+                // go to previous map element (which may be able to merge with the passed model)
+                --aIt;
+                // the usage of upper_bound() above ensures that aIt->first is less than or equal to nRow now
+                sal_Int32& rnLastMapRow = aIt->second.second;
+                bUnusedRow = rnLastMapRow < nRow;
+                OSL_ENSURE( bUnusedRow, "WorksheetGlobals::setRowModel - multiple models of the same row" );
+                if( (rnLastMapRow + 1 == nRow) && aIt->second.first.isMergeable( rModel ) )
+                {
+                    // can merge with existing model, update last row index
+                    ++rnLastMapRow;
+                    bInsertModel = false;
+                }
+            }
+        }
+        if( bUnusedRow )
+        {
+            // insert the row model, if it has not been merged with another
+            if( bInsertModel )
+                maRowModels[ nRow ] = RowModelRange( rModel, nRow );
+            // set row formatting
+            maSheetData.setRowFormat( nRow, rModel.mnXfId, rModel.mbCustomFormat );
+            // set column spans
+            maSheetData.setColSpans( nRow, rModel.maColSpans );
+        }
+    }
+    lclUpdateProgressBar( mxRowProgress, maUsedArea, nRow );
+}
+
+void WorksheetGlobals::setManualRowHeight( sal_Int32 nRow )
+{
+    maManualRowHeights.insert( nRow );
+}
+
+void WorksheetGlobals::initializeWorksheetImport()
+{
+    // set default cell style for unused cells
+    PropertySet aPropSet( mxSheet );
+    aPropSet.setProperty( PROP_CellStyle, getStyles().getDefaultStyleName() );
+
+    /*  Remember the current sheet index in global data, needed by global
+        objects, e.g. the chart converter. */
+    setCurrentSheetIndex( getSheetIndex() );
+}
+
+void WorksheetGlobals::finalizeWorksheetImport()
+{
+    lclUpdateProgressBar( mxRowProgress, 1.0 );
+    maSheetData.finalizeImport();
+    lclUpdateProgressBar( mxFinalProgress, 0.25 );
+    finalizeHyperlinkRanges();
+    finalizeValidationRanges();
+    maAutoFilters.finalizeImport( getSheetIndex() );
+    maCondFormats.finalizeImport();
+    maQueryTables.finalizeImport();
+    maSheetSett.finalizeImport();
+    maPageSett.finalizeImport();
+    maSheetViewSett.finalizeImport();
+
+    lclUpdateProgressBar( mxFinalProgress, 0.5 );
+    convertColumns();
+    convertRows();
+    lclUpdateProgressBar( mxFinalProgress, 0.75 );
+    finalizeDrawings();
+    lclUpdateProgressBar( mxFinalProgress, 1.0 );
+
+    // forget current sheet index in global data
+    setCurrentSheetIndex( -1 );
+}
+
+// private --------------------------------------------------------------------
+
+void WorksheetGlobals::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.isEmpty() )
+            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 WorksheetGlobals::getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const
+{
+    OUStringBuffer aUrlBuffer;
+    if( !rHyperlink.maTarget.isEmpty() )
+        aUrlBuffer.append( getBaseFilter().getAbsoluteUrl( rHyperlink.maTarget ) );
+    if( !rHyperlink.maLocation.isEmpty() )
+        aUrlBuffer.append( sal_Unicode( '#' ) ).append( rHyperlink.maLocation );
+    OUString aUrl = aUrlBuffer.makeStringAndClear();
+
+    // convert '#SheetName!A1' to '#SheetName.A1'
+    if( !aUrl.isEmpty() && (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.isEmpty() )
+                aUrl = aUrl.replaceAt( 1, nSepPos - 1, aCalcName );
+        }
+    }
+
+    return aUrl;
+}
+
+void WorksheetGlobals::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 CellContentType_TEXT:
+        {
+            Reference< XText > xText( xCell, UNO_QUERY );
+            if( xText.is() )
+            {
+                // create a URL field object and set its properties
+                Reference< XTextContent > xUrlField( getBaseFilter().getModelFactory()->createInstance( maUrlTextField ), UNO_QUERY );
+                OSL_ENSURE( xUrlField.is(), "WorksheetGlobals::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_FAIL( "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 CellContentType_VALUE:
+        {
+            Reference< XFormulaTokens > xTokens( xCell, UNO_QUERY );
+            ApiTokenSequence aTokens = getFormulaParser().convertNumberToHyperlink( rUrl, xCell->getValue() );
+            OSL_ENSURE( xTokens.is(), "WorksheetHelper::insertHyperlink - missing formula token interface" );
+            if( xTokens.is() && aTokens.hasElements() )
+                xTokens->setTokens( aTokens );
+        }
+        break;
+#endif
+
+        default:;
+    }
+}
+
+void WorksheetGlobals::finalizeValidationRanges() const
+{
+    for( ValidationModelList::const_iterator aIt = maValidations.begin(), aEnd = maValidations.end(); aIt != aEnd; ++aIt )
+    {
+        PropertySet aPropSet( getCellRangeList( aIt->maRanges ) );
+
+        Reference< XPropertySet > xValidation( aPropSet.getAnyProperty( PROP_Validation ), UNO_QUERY );
+        if( xValidation.is() )
+        {
+            PropertySet aValProps( xValidation );
+
+            // convert validation type to API enum
+            ValidationType eType = ValidationType_ANY;
+            switch( aIt->mnType )
+            {
+                case XML_custom:        eType = ValidationType_CUSTOM;      break;
+                case XML_date:          eType = ValidationType_DATE;        break;
+                case XML_decimal:       eType = ValidationType_DECIMAL;     break;
+                case XML_list:          eType = ValidationType_LIST;        break;
+                case XML_none:          eType = ValidationType_ANY;         break;
+                case XML_textLength:    eType = ValidationType_TEXT_LEN;    break;
+                case XML_time:          eType = ValidationType_TIME;        break;
+                case XML_whole:         eType = ValidationType_WHOLE;       break;
+                default:    OSL_FAIL( "WorksheetData::finalizeValidationRanges - unknown validation type" );
+            }
+            aValProps.setProperty( PROP_Type, eType );
+
+            // convert error alert style to API enum
+            ValidationAlertStyle eAlertStyle = ValidationAlertStyle_STOP;
+            switch( aIt->mnErrorStyle )
+            {
+                case XML_information:   eAlertStyle = ValidationAlertStyle_INFO;    break;
+                case XML_stop:          eAlertStyle = ValidationAlertStyle_STOP;    break;
+                case XML_warning:       eAlertStyle = ValidationAlertStyle_WARNING; break;
+                default:    OSL_FAIL( "WorksheetData::finalizeValidationRanges - unknown error style" );
+            }
+            aValProps.setProperty( PROP_ErrorAlertStyle, eAlertStyle );
+
+            // convert dropdown style to API visibility constants
+            sal_Int16 nVisibility = aIt->mbNoDropDown ? TableValidationVisibility::INVISIBLE : 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< XSheetCondition2 > xSheetCond( xValidation, UNO_QUERY_THROW );
+                xSheetCond->setConditionOperator( 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 WorksheetGlobals::convertColumns()
+{
+    sal_Int32 nNextCol = 0;
+    sal_Int32 nMaxCol = mrMaxApiPos.Column;
+    // stores first grouped column index for each level
+    OutlineLevelVec aColLevels;
+
+    for( ColumnModelRangeMap::iterator aIt = maColModels.begin(), aEnd = maColModels.end(); aIt != aEnd; ++aIt )
+    {
+        // column indexes are stored 0-based in maColModels
+        ValueRange aColRange( ::std::max( aIt->first, nNextCol ), ::std::min( aIt->second.second, nMaxCol ) );
+        // process gap between two column models, use default column model
+        if( nNextCol < aColRange.mnFirst )
+            convertColumns( aColLevels, ValueRange( nNextCol, aColRange.mnFirst - 1 ), maDefColModel );
+        // process the column model
+        convertColumns( aColLevels, aColRange, aIt->second.first );
+        // cache next column to be processed
+        nNextCol = aColRange.mnLast + 1;
+    }
+
+    // remaining default columns to end of sheet
+    convertColumns( aColLevels, ValueRange( nNextCol, nMaxCol ), maDefColModel );
+    // close remaining column outlines spanning to end of sheet
+    convertOutlines( aColLevels, nMaxCol + 1, 0, false, false );
+}
+
+void WorksheetGlobals::convertColumns( OutlineLevelVec& orColLevels,
+        const ValueRange& rColRange, const ColumnModel& rModel )
+{
+    PropertySet aPropSet( getColumns( rColRange ) );
+
+    // 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, rColRange.mnFirst, rModel.mnLevel, rModel.mbCollapsed, false );
+}
+
+void WorksheetGlobals::convertRows()
+{
+    sal_Int32 nNextRow = 0;
+    sal_Int32 nMaxRow = mrMaxApiPos.Row;
+    // stores first grouped row index for each level
+    OutlineLevelVec aRowLevels;
+
+    for( RowModelRangeMap::iterator aIt = maRowModels.begin(), aEnd = maRowModels.end(); aIt != aEnd; ++aIt )
+    {
+        // row indexes are stored 0-based in maRowModels
+        ValueRange aRowRange( ::std::max( aIt->first, nNextRow ), ::std::min( aIt->second.second, nMaxRow ) );
+        // process gap between two row models, use default row model
+        if( nNextRow < aRowRange.mnFirst )
+            convertRows( aRowLevels, ValueRange( nNextRow, aRowRange.mnFirst - 1 ), maDefRowModel );
+        // process the row model
+        convertRows( aRowLevels, aRowRange, aIt->second.first, maDefRowModel.mfHeight );
+        // cache next row to be processed
+        nNextRow = aRowRange.mnLast + 1;
+    }
+
+    // remaining default rows to end of sheet
+    convertRows( aRowLevels, ValueRange( nNextRow, nMaxRow ), maDefRowModel );
+    // close remaining row outlines spanning to end of sheet
+    convertOutlines( aRowLevels, nMaxRow + 1, 0, false, true );
+}
+
+void WorksheetGlobals::convertRows( OutlineLevelVec& orRowLevels,
+        const ValueRange& rRowRange, 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 )
+    {
+        /*  Get all rows that have custom height inside the passed row model.
+            If the model has the custom height flag set, all its rows have
+            custom height, otherwise get all rows specified in the class member
+            maManualRowHeights that are inside the passed row model. */
+        ValueRangeVector aManualRows;
+        if( rModel.mbCustomHeight )
+            aManualRows.push_back( rRowRange );
+        else
+            aManualRows = maManualRowHeights.getIntersection( rRowRange );
+        for( ValueRangeVector::const_iterator aIt = aManualRows.begin(), aEnd = aManualRows.end(); aIt != aEnd; ++aIt )
+        {
+            PropertySet aPropSet( getRows( *aIt ) );
+            aPropSet.setProperty( PROP_Height, nHeight );
+        }
+    }
+
+    // hidden rows: TODO: #108683# hide rows later?
+    if( rModel.mbHidden )
+    {
+        PropertySet aPropSet( getRows( rRowRange ) );
+        // #i116460# Use VisibleFlag instead of IsVisible: directly set the flag,
+        // without drawing layer update etc. (only possible before shapes are inserted)
+        aPropSet.setProperty( PROP_VisibleFlag, false );
+    }
+
+    // outline settings for this row range
+    convertOutlines( orRowLevels, rRowRange.mnFirst, rModel.mnLevel, rModel.mbCollapsed, true );
+}
+
+void WorksheetGlobals::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, "WorksheetGlobals::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 WorksheetGlobals::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, TableOrientation_ROWS );
+            if( bCollapse )
+                xOutline->hideDetail( aRange );
+        }
+        else
+        {
+            CellRangeAddress aRange( getSheetIndex(), nFirstColRow, 0, nLastColRow, 0 );
+            xOutline->group( aRange, TableOrientation_COLUMNS );
+            if( bCollapse )
+                xOutline->hideDetail( aRange );
+        }
+    }
+    catch( Exception& )
+    {
+    }
+}
+
+void WorksheetGlobals::finalizeDrawings()
+{
+    // calculate the current drawing page size (after rows/columns are imported)
+    PropertySet aRangeProp( getCellRange( CellRangeAddress( getSheetIndex(), 0, 0, mrMaxApiPos.Column, mrMaxApiPos.Row ) ) );
+    aRangeProp.getProperty( maDrawPageSize, PROP_Size );
+
+    switch( getFilterType() )
+    {
+        case FILTER_OOXML:
+            // import DML and VML
+            if( !maDrawingPath.isEmpty() )
+                importOoxFragment( new DrawingFragment( *this, maDrawingPath ) );
+            if( !maVmlDrawingPath.isEmpty() )
+                importOoxFragment( new VmlDrawingFragment( *this, maVmlDrawingPath ) );
+        break;
+
+        case FILTER_BIFF:
+            // convert BIFF3-BIFF5 drawing objects, or import and convert DFF stream
+            getBiffDrawing().finalizeImport();
+        break;
+
+        case FILTER_UNKNOWN:
+        break;
+    }
+
+    // comments (after callout shapes have been imported from VML/DFF)
+    maComments.finalizeImport();
+
+    /*  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 );
+
+    /*  #i103686# Set right-to-left sheet layout. Must be done after all
+        drawing shapes to simplify calculation of shape coordinates. */
+    if( maSheetViewSett.isSheetRightToLeft() )
+    {
+        PropertySet aPropSet( mxSheet );
+        aPropSet.setProperty( PROP_TableLayout, WritingMode2::RL_TB );
+    }
+}
+
+// ============================================================================
+// ============================================================================
+
+WorksheetHelper::WorksheetHelper( WorksheetGlobals& rSheetGlob ) :
+    WorkbookHelper( rSheetGlob ),
+    mrSheetGlob( rSheetGlob )
+{
+}
+
+/*static*/ WorksheetGlobalsRef WorksheetHelper::constructGlobals( const WorkbookHelper& rHelper,
+        const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, sal_Int16 nSheet )
+{
+    WorksheetGlobalsRef xSheetGlob( new WorksheetGlobals( rHelper, rxProgressBar, eSheetType, nSheet ) );
+    if( !xSheetGlob->isValidSheet() )
+        xSheetGlob.reset();
+    return xSheetGlob;
+}
+
+WorksheetType WorksheetHelper::getSheetType() const
+{
+    return mrSheetGlob.getSheetType();
+}
+
+sal_Int16 WorksheetHelper::getSheetIndex() const
+{
+    return mrSheetGlob.getSheetIndex();
+}
+
+const Reference< XSpreadsheet >& WorksheetHelper::getSheet() const
+{
+    return mrSheetGlob.getSheet();
+}
+
+Reference< XCell > WorksheetHelper::getCell( const CellAddress& rAddress ) const
+{
+    return mrSheetGlob.getCell( rAddress );
+}
+
+Reference< XCellRange > WorksheetHelper::getCellRange( const CellRangeAddress& rRange ) const
+{
+    return mrSheetGlob.getCellRange( rRange );
+}
+
+Reference< XSheetCellRanges > WorksheetHelper::getCellRangeList( const ApiCellRangeList& rRanges ) const
+{
+    return mrSheetGlob.getCellRangeList( rRanges );
+}
+
+Reference< XDrawPage > WorksheetHelper::getDrawPage() const
+{
+    return mrSheetGlob.getDrawPage();
+}
+
+Point WorksheetHelper::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+    return mrSheetGlob.getCellPosition( nCol, nRow );
+}
+
+Size WorksheetHelper::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+    return mrSheetGlob.getCellSize( nCol, nRow );
+}
+
+Size WorksheetHelper::getDrawPageSize() const
+{
+    return mrSheetGlob.getDrawPageSize();
+}
+
+SheetDataBuffer& WorksheetHelper::getSheetData() const
+{
+    return mrSheetGlob.getSheetData();
+}
+
+CondFormatBuffer& WorksheetHelper::getCondFormats() const
+{
+    return mrSheetGlob.getCondFormats();
+}
+
+CommentsBuffer& WorksheetHelper::getComments() const
+{
+    return mrSheetGlob.getComments();
+}
+
+AutoFilterBuffer& WorksheetHelper::getAutoFilters() const
+{
+    return mrSheetGlob.getAutoFilters();
+}
+
+QueryTableBuffer& WorksheetHelper::getQueryTables() const
+{
+    return mrSheetGlob.getQueryTables();
+}
+
+WorksheetSettings& WorksheetHelper::getWorksheetSettings() const
+{
+    return mrSheetGlob.getWorksheetSettings();
+}
+
+PageSettings& WorksheetHelper::getPageSettings() const
+{
+    return mrSheetGlob.getPageSettings();
+}
+
+SheetViewSettings& WorksheetHelper::getSheetViewSettings() const
+{
+    return mrSheetGlob.getSheetViewSettings();
+}
+
+VmlDrawing& WorksheetHelper::getVmlDrawing() const
+{
+    return mrSheetGlob.getVmlDrawing();
+}
+
+BiffSheetDrawing& WorksheetHelper::getBiffDrawing() const
+{
+    return mrSheetGlob.getBiffDrawing();
+}
+
+void WorksheetHelper::setSheetType( WorksheetType eSheetType )
+{
+    mrSheetGlob.setSheetType( eSheetType );
+}
+
+void WorksheetHelper::setPageBreak( const PageBreakModel& rModel, bool bRowBreak )
+{
+    mrSheetGlob.setPageBreak( rModel, bRowBreak );
+}
+
+void WorksheetHelper::setHyperlink( const HyperlinkModel& rModel )
+{
+    mrSheetGlob.setHyperlink( rModel );
+}
+
+void WorksheetHelper::setValidation( const ValidationModel& rModel )
+{
+    mrSheetGlob.setValidation( rModel );
+}
+
+void WorksheetHelper::setLabelRanges( const ApiCellRangeList& rColRanges, const ApiCellRangeList& rRowRanges )
+{
+    const CellAddress& rMaxPos = getAddressConverter().getMaxApiAddress();
+    PropertySet aPropSet( getSheet() );
+
+    if( !rColRanges.empty() )
+    {
+        Reference< XLabelRanges > xLabelRanges( aPropSet.getAnyProperty( PROP_ColumnLabelRanges ), UNO_QUERY );
+        if( 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() )
+    {
+        Reference< XLabelRanges > xLabelRanges( aPropSet.getAnyProperty( PROP_RowLabelRanges ), UNO_QUERY );
+        if( 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 )
+{
+    mrSheetGlob.setDrawingPath( rDrawingPath );
+}
+
+void WorksheetHelper::setVmlDrawingPath( const OUString& rVmlDrawingPath )
+{
+    mrSheetGlob.setVmlDrawingPath( rVmlDrawingPath );
+}
+
+void WorksheetHelper::extendUsedArea( const CellAddress& rAddress )
+{
+    mrSheetGlob.extendUsedArea( rAddress );
+}
+
+void WorksheetHelper::extendUsedArea( const CellRangeAddress& rRange )
+{
+    mrSheetGlob.extendUsedArea( rRange );
+}
+
+void WorksheetHelper::extendShapeBoundingBox( const Rectangle& rShapeRect )
+{
+    mrSheetGlob.extendShapeBoundingBox( rShapeRect );
+}
+
+void WorksheetHelper::setBaseColumnWidth( sal_Int32 nWidth )
+{
+    mrSheetGlob.setBaseColumnWidth( nWidth );
+}
+
+void WorksheetHelper::setDefaultColumnWidth( double fWidth )
+{
+    mrSheetGlob.setDefaultColumnWidth( fWidth );
+}
+
+void WorksheetHelper::setDefaultColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId )
+{
+    mrSheetGlob.convertColumnFormat( nFirstCol, nLastCol, nXfId );
+}
+
+void WorksheetHelper::setColumnModel( const ColumnModel& rModel )
+{
+    mrSheetGlob.setColumnModel( rModel );
+}
+
+void WorksheetHelper::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
+{
+    mrSheetGlob.setDefaultRowSettings( fHeight, bCustomHeight, bHidden, bThickTop, bThickBottom );
+}
+
+void WorksheetHelper::setRowModel( const RowModel& rModel )
+{
+    mrSheetGlob.setRowModel( rModel );
+}
+
+void WorksheetHelper::setManualRowHeight( sal_Int32 nRow )
+{
+    mrSheetGlob.setManualRowHeight( nRow );
+}
+
+void WorksheetHelper::putValue( const CellAddress& rAddress, double fValue ) const
+{
+    Reference< XCell > xCell = getCell( rAddress );
+    OSL_ENSURE( xCell.is(), "WorksheetHelper::putValue - missing cell interface" );
+    if( xCell.is() ) xCell->setValue( fValue );
+}
+
+void WorksheetHelper::putFormulaResult( const CellAddress& rAddress, double fValue ) const
+{
+    Reference< XCell2 > xCell( getCell( rAddress ), UNO_QUERY );
+    OSL_ENSURE( xCell.is(), "WorksheetHelper::putFormulaResult - missing cell interface" );
+    if( xCell.is() ) xCell->setFormulaResult( fValue );
+}
+
+void WorksheetHelper::putString( const CellAddress& rAddress, const OUString& rText ) const
+{
+    Reference< XText > xText( getCell( rAddress ), UNO_QUERY );
+    OSL_ENSURE( xText.is(), "WorksheetHelper::putString - missing text interface" );
+    if( xText.is() ) xText->setString( rText );
+}
+
+void WorksheetHelper::putRichString( const CellAddress& rAddress, const RichString& rString, const Font* pFirstPortionFont ) const
+{
+    Reference< XText > xText( getCell( rAddress ), UNO_QUERY );
+    OSL_ENSURE( xText.is(), "WorksheetHelper::putRichString - missing text interface" );
+    /*  Passing false will always append the portions to the XText. This is
+        essential for special rich formatting attributes at the leading text
+        portion supported by edit cells only, e.g. font escapement. */
+    rString.convert( xText, false, pFirstPortionFont );
+}
+
+void WorksheetHelper::putFormulaTokens( const CellAddress& rAddress, const ApiTokenSequence& rTokens ) const
+{
+    Reference< XFormulaTokens > xTokens( getCell( rAddress ), UNO_QUERY );
+    OSL_ENSURE( xTokens.is(), "WorksheetHelper::putFormulaTokens - missing token interface" );
+    if( xTokens.is() ) xTokens->setTokens( rTokens );
+}
+
+void WorksheetHelper::initializeWorksheetImport()
+{
+    mrSheetGlob.initializeWorksheetImport();
+}
+
+void WorksheetHelper::finalizeWorksheetImport()
+{
+    mrSheetGlob.finalizeWorksheetImport();
+}
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/oox/worksheetsettings.cxx b/sc/source/filter/oox/worksheetsettings.cxx
new file mode 100644
index 000000000000..768041b23834
--- /dev/null
+++ b/sc/source/filter/oox/worksheetsettings.cxx
@@ -0,0 +1,351 @@
+/* -*- 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
+ * 
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "worksheetsettings.hxx"
+
+#include 
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/attributelist.hxx"
+#include "biffinputstream.hxx"
+#include "pagesettings.hxx"
+#include "workbooksettings.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+using ::oox::core::CodecHelper;
+using ::rtl::OUString;
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt8 BIFF12_SHEETPR_FILTERMODE       = 0x01;
+const sal_uInt8 BIFF12_SHEETPR_EVAL_CF          = 0x02;
+
+const sal_uInt32 BIFF_SHEETEXT_NOTABCOLOR       = 0x7F;
+
+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( SequenceInputStream& 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, BIFF12_SHEETPR_FILTERMODE );
+    // outline settings, equal flags in all BIFFs
+    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( SequenceInputStream& rStrm )
+{
+    rStrm.skip( 2 );    // flags, contains only the 'published' flag
+    rStrm >> maSheetSettings.maTabColor >> maSheetSettings.maCodeName;
+}
+
+void WorksheetSettings::importSheetProtection( SequenceInputStream& 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( SequenceInputStream& 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( SequenceInputStream& rStrm )
+{
+    maPhoneticSett.importPhoneticPr( rStrm );
+}
+
+void WorksheetSettings::importSheetExt( BiffInputStream& rStrm )
+{
+    rStrm.skip( 16 );
+    sal_uInt32 nFlags;
+    rStrm >> nFlags;
+    sal_uInt8 nColorIdx = extractValue< sal_uInt8 >( nFlags, 0, 7 );
+    if( nColorIdx != BIFF_SHEETEXT_NOTABCOLOR )
+        maSheetSettings.maTabColor.setPaletteClr( nColorIdx );
+}
+
+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 );
+
+    // sheet tab color
+    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: */
diff --git a/sc/util/scfilt.component b/sc/util/scfilt.component
index 91ae96d910ce..1b72dcd017ec 100644
--- a/sc/util/scfilt.component
+++ b/sc/util/scfilt.component
@@ -31,4 +31,11 @@
   
     
   
+  
+    
+    
+  
+  
+    
+  
 
-- 
cgit