1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/xls/worksheetfragment.hxx"
29 
30 #include "oox/core/filterbase.hxx"
31 #include "oox/core/relations.hxx"
32 #include "oox/helper/attributelist.hxx"
33 #include "oox/xls/addressconverter.hxx"
34 #include "oox/xls/autofilterbuffer.hxx"
35 #include "oox/xls/autofiltercontext.hxx"
36 #include "oox/xls/biffinputstream.hxx"
37 #include "oox/xls/commentsfragment.hxx"
38 #include "oox/xls/condformatcontext.hxx"
39 #include "oox/xls/drawingfragment.hxx"
40 #include "oox/xls/drawingmanager.hxx"
41 #include "oox/xls/externallinkbuffer.hxx"
42 #include "oox/xls/pagesettings.hxx"
43 #include "oox/xls/pivottablefragment.hxx"
44 #include "oox/xls/querytablefragment.hxx"
45 #include "oox/xls/scenariobuffer.hxx"
46 #include "oox/xls/scenariocontext.hxx"
47 #include "oox/xls/sheetdatabuffer.hxx"
48 #include "oox/xls/sheetdatacontext.hxx"
49 #include "oox/xls/tablefragment.hxx"
50 #include "oox/xls/viewsettings.hxx"
51 #include "oox/xls/workbooksettings.hxx"
52 #include "oox/xls/worksheetsettings.hxx"
53 
54 namespace oox {
55 namespace xls {
56 
57 // ============================================================================
58 
59 using namespace ::com::sun::star::table;
60 using namespace ::com::sun::star::uno;
61 using namespace ::oox::core;
62 
63 using ::rtl::OUString;
64 using ::rtl::OUStringBuffer;
65 
66 // ============================================================================
67 
68 namespace {
69 
70 const sal_uInt16 BIFF_COLINFO_HIDDEN        = 0x0001;
71 const sal_uInt16 BIFF_COLINFO_SHOWPHONETIC  = 0x0008;
72 const sal_uInt16 BIFF_COLINFO_COLLAPSED     = 0x1000;
73 
74 const sal_uInt16 BIFF_DEFROW_CUSTOMHEIGHT   = 0x0001;
75 const sal_uInt16 BIFF_DEFROW_HIDDEN         = 0x0002;
76 const sal_uInt16 BIFF_DEFROW_THICKTOP       = 0x0004;
77 const sal_uInt16 BIFF_DEFROW_THICKBOTTOM    = 0x0008;
78 const sal_uInt16 BIFF2_DEFROW_DEFHEIGHT     = 0x8000;
79 const sal_uInt16 BIFF2_DEFROW_MASK          = 0x7FFF;
80 
81 const sal_uInt32 BIFF_DATAVAL_STRINGLIST    = 0x00000080;
82 const sal_uInt32 BIFF_DATAVAL_ALLOWBLANK    = 0x00000100;
83 const sal_uInt32 BIFF_DATAVAL_NODROPDOWN    = 0x00000200;
84 const sal_uInt32 BIFF_DATAVAL_SHOWINPUT     = 0x00040000;
85 const sal_uInt32 BIFF_DATAVAL_SHOWERROR     = 0x00080000;
86 
87 const sal_uInt32 BIFF_SHRFEATHEAD_SHEETPROT = 2;
88 
89 const sal_Int32 BIFF12_OLEOBJECT_CONTENT    = 1;
90 const sal_Int32 BIFF12_OLEOBJECT_ICON       = 4;
91 const sal_Int32 BIFF12_OLEOBJECT_ALWAYS     = 1;
92 const sal_Int32 BIFF12_OLEOBJECT_ONCALL     = 3;
93 const sal_uInt16 BIFF12_OLEOBJECT_LINKED    = 0x0001;
94 const sal_uInt16 BIFF12_OLEOBJECT_AUTOLOAD  = 0x0002;
95 
96 } // namespace
97 
98 // ============================================================================
99 
100 DataValidationsContext::DataValidationsContext( WorksheetFragmentBase& rFragment ) :
101     WorksheetContextBase( rFragment )
102 {
103 }
104 
105 ContextHandlerRef DataValidationsContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
106 {
107     switch( getCurrentElement() )
108     {
109         case XLS_TOKEN( dataValidations ):
110             if( nElement == XLS_TOKEN( dataValidation ) )
111             {
112                 importDataValidation( rAttribs );
113                 return this;
114             }
115         break;
116         case XLS_TOKEN( dataValidation ):
117             switch( nElement )
118             {
119                 case XLS_TOKEN( formula1 ):
120                 case XLS_TOKEN( formula2 ):
121                     return this;    // collect formulas in onCharacters()
122             }
123         break;
124     }
125     return 0;
126 }
127 
128 void DataValidationsContext::onCharacters( const OUString& rChars )
129 {
130     if( mxValModel.get() ) switch( getCurrentElement() )
131     {
132         case XLS_TOKEN( formula1 ):
133             mxValModel->maTokens1 = getFormulaParser().importFormula( mxValModel->maRanges.getBaseAddress(), rChars );
134             // process string list of a list validation (convert to list of string tokens)
135             if( mxValModel->mnType == XML_list )
136                 getFormulaParser().convertStringToStringList( mxValModel->maTokens1, ',', true );
137         break;
138         case XLS_TOKEN( formula2 ):
139             mxValModel->maTokens2 = getFormulaParser().importFormula( mxValModel->maRanges.getBaseAddress(), rChars );
140         break;
141     }
142 }
143 
144 void DataValidationsContext::onEndElement()
145 {
146     if( isCurrentElement( XLS_TOKEN( dataValidation ) ) && mxValModel.get() )
147     {
148         setValidation( *mxValModel );
149         mxValModel.reset();
150     }
151 }
152 
153 
154 ContextHandlerRef DataValidationsContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
155 {
156     if( nRecId == BIFF12_ID_DATAVALIDATION )
157         importDataValidation( rStrm );
158     return 0;
159 }
160 
161 void DataValidationsContext::importDataValidation( const AttributeList& rAttribs )
162 {
163     mxValModel.reset( new ValidationModel );
164     getAddressConverter().convertToCellRangeList( mxValModel->maRanges, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), true );
165     mxValModel->maInputTitle   = rAttribs.getXString( XML_promptTitle, OUString() );
166     mxValModel->maInputMessage = rAttribs.getXString( XML_prompt, OUString() );
167     mxValModel->maErrorTitle   = rAttribs.getXString( XML_errorTitle, OUString() );
168     mxValModel->maErrorMessage = rAttribs.getXString( XML_error, OUString() );
169     mxValModel->mnType         = rAttribs.getToken( XML_type, XML_none );
170     mxValModel->mnOperator     = rAttribs.getToken( XML_operator, XML_between );
171     mxValModel->mnErrorStyle   = rAttribs.getToken( XML_errorStyle, XML_stop );
172     mxValModel->mbShowInputMsg = rAttribs.getBool( XML_showInputMessage, false );
173     mxValModel->mbShowErrorMsg = rAttribs.getBool( XML_showErrorMessage, false );
174     /*  The attribute showDropDown@dataValidation is in fact a "suppress
175         dropdown" flag, as it was in the BIFF format! ECMA specification
176         and attribute name are plain wrong! */
177     mxValModel->mbNoDropDown   = rAttribs.getBool( XML_showDropDown, false );
178     mxValModel->mbAllowBlank   = rAttribs.getBool( XML_allowBlank, false );
179 }
180 
181 void DataValidationsContext::importDataValidation( SequenceInputStream& rStrm )
182 {
183     ValidationModel aModel;
184 
185     sal_uInt32 nFlags;
186     BinRangeList aRanges;
187     rStrm >> nFlags >> aRanges >> aModel.maErrorTitle >> aModel.maErrorMessage >> aModel.maInputTitle >> aModel.maInputMessage;
188 
189     // equal flags in all BIFFs
190     aModel.setBiffType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
191     aModel.setBiffOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
192     aModel.setBiffErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
193     aModel.mbAllowBlank   = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
194     aModel.mbNoDropDown   = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
195     aModel.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
196     aModel.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
197 
198     // cell range list
199     getAddressConverter().convertToCellRangeList( aModel.maRanges, aRanges, getSheetIndex(), true );
200 
201     // condition formula(s)
202     FormulaParser& rParser = getFormulaParser();
203     CellAddress aBaseAddr = aModel.maRanges.getBaseAddress();
204     aModel.maTokens1 = rParser.importFormula( aBaseAddr, FORMULATYPE_VALIDATION, rStrm );
205     aModel.maTokens2 = rParser.importFormula( aBaseAddr, FORMULATYPE_VALIDATION, rStrm );
206     // process string list of a list validation (convert to list of string tokens)
207     if( (aModel.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
208         rParser.convertStringToStringList( aModel.maTokens1, ',', true );
209 
210     // set validation data
211     setValidation( aModel );
212 }
213 
214 // ============================================================================
215 
216 WorksheetFragment::WorksheetFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
217     WorksheetFragmentBase( rHelper, rFragmentPath )
218 {
219     // import data tables related to this worksheet
220     RelationsRef xTableRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "table" ) );
221     for( Relations::const_iterator aIt = xTableRels->begin(), aEnd = xTableRels->end(); aIt != aEnd; ++aIt )
222         importOoxFragment( new TableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
223 
224     // import comments related to this worksheet
225     OUString aCommentsFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "comments" ) );
226     if( aCommentsFragmentPath.getLength() > 0 )
227         importOoxFragment( new CommentsFragment( *this, aCommentsFragmentPath ) );
228 }
229 
230 ContextHandlerRef WorksheetFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
231 {
232     switch( getCurrentElement() )
233     {
234         case XML_ROOT_CONTEXT: switch( getSheetType() )
235         {
236             case SHEETTYPE_WORKSHEET:   return (nElement == XLS_TOKEN( worksheet )) ? this : 0;
237             case SHEETTYPE_CHARTSHEET:  return 0;
238             case SHEETTYPE_MACROSHEET:  return (nElement == XM_TOKEN( macrosheet )) ? this : 0;
239             case SHEETTYPE_DIALOGSHEET: return (nElement == XLS_TOKEN( dialogsheet )) ? this : 0;
240             case SHEETTYPE_MODULESHEET: return 0;
241             case SHEETTYPE_EMPTYSHEET:  return 0;
242         }
243         break;
244 
245         case XLS_TOKEN( worksheet ):
246         case XM_TOKEN( macrosheet ):
247         case XLS_TOKEN( dialogsheet ):
248             switch( nElement )
249             {
250                 case XLS_TOKEN( sheetData ):                return new SheetDataContext( *this );
251                 case XLS_TOKEN( conditionalFormatting ):    return new CondFormatContext( *this );
252                 case XLS_TOKEN( dataValidations ):          return new DataValidationsContext( *this );
253                 case XLS_TOKEN( autoFilter ):               return new AutoFilterContext( *this, getAutoFilters().createAutoFilter() );
254                 case XLS_TOKEN( scenarios ):                return new ScenariosContext( *this );
255 
256                 case XLS_TOKEN( sheetViews ):
257                 case XLS_TOKEN( cols ):
258                 case XLS_TOKEN( mergeCells ):
259                 case XLS_TOKEN( hyperlinks ):
260                 case XLS_TOKEN( rowBreaks ):
261                 case XLS_TOKEN( colBreaks ):
262                 case XLS_TOKEN( oleObjects ):
263                 case XLS_TOKEN( controls ):         return this;
264 
265                 case XLS_TOKEN( sheetPr ):          getWorksheetSettings().importSheetPr( rAttribs );               return this;
266                 case XLS_TOKEN( dimension ):        importDimension( rAttribs );                                    break;
267                 case XLS_TOKEN( sheetFormatPr ):    importSheetFormatPr( rAttribs );                                break;
268                 case XLS_TOKEN( sheetProtection ):  getWorksheetSettings().importSheetProtection( rAttribs );       break;
269                 case XLS_TOKEN( phoneticPr ):       getWorksheetSettings().importPhoneticPr( rAttribs );            break;
270                 case XLS_TOKEN( printOptions ):     getPageSettings().importPrintOptions( rAttribs );               break;
271                 case XLS_TOKEN( pageMargins ):      getPageSettings().importPageMargins( rAttribs );                break;
272                 case XLS_TOKEN( pageSetup ):        getPageSettings().importPageSetup( getRelations(), rAttribs );  break;
273                 case XLS_TOKEN( headerFooter ):     getPageSettings().importHeaderFooter( rAttribs );               return this;
274                 case XLS_TOKEN( picture ):          getPageSettings().importPicture( getRelations(), rAttribs );    break;
275                 case XLS_TOKEN( drawing ):          importDrawing( rAttribs );                                      break;
276                 case XLS_TOKEN( legacyDrawing ):    importLegacyDrawing( rAttribs );                                break;
277             }
278         break;
279 
280         case XLS_TOKEN( sheetPr ):
281             switch( nElement )
282             {
283                 case XLS_TOKEN( tabColor ):         getWorksheetSettings().importTabColor( rAttribs );              break;
284                 case XLS_TOKEN( outlinePr ):        getWorksheetSettings().importOutlinePr( rAttribs );             break;
285                 case XLS_TOKEN( pageSetUpPr ):      importPageSetUpPr( rAttribs );                                  break;
286             }
287         break;
288 
289         case XLS_TOKEN( sheetViews ):
290             switch( nElement )
291             {
292                 case XLS_TOKEN( sheetView ):        getSheetViewSettings().importSheetView( rAttribs );             return this;
293             }
294         break;
295         case XLS_TOKEN( sheetView ):
296             switch( nElement )
297             {
298                 case XLS_TOKEN( pane ):             getSheetViewSettings().importPane( rAttribs );                  break;
299                 case XLS_TOKEN( selection ):        getSheetViewSettings().importSelection( rAttribs );             break;
300             }
301         break;
302 
303         case XLS_TOKEN( cols ):
304             if( nElement == XLS_TOKEN( col ) ) importCol( rAttribs );
305         break;
306         case XLS_TOKEN( mergeCells ):
307             if( nElement == XLS_TOKEN( mergeCell ) ) importMergeCell( rAttribs );
308         break;
309         case XLS_TOKEN( hyperlinks ):
310             if( nElement == XLS_TOKEN( hyperlink ) ) importHyperlink( rAttribs );
311         break;
312         case XLS_TOKEN( rowBreaks ):
313             if( nElement == XLS_TOKEN( brk ) ) importBrk( rAttribs, true );
314         break;
315         case XLS_TOKEN( colBreaks ):
316             if( nElement == XLS_TOKEN( brk ) ) importBrk( rAttribs, false );
317         break;
318 
319         case XLS_TOKEN( headerFooter ):
320             switch( nElement )
321             {
322                 case XLS_TOKEN( firstHeader ):
323                 case XLS_TOKEN( firstFooter ):
324                 case XLS_TOKEN( oddHeader ):
325                 case XLS_TOKEN( oddFooter ):
326                 case XLS_TOKEN( evenHeader ):
327                 case XLS_TOKEN( evenFooter ):       return this;    // collect h/f contents in onCharacters()
328             }
329         break;
330 
331         case XLS_TOKEN( oleObjects ):
332             if( nElement == XLS_TOKEN( oleObject ) ) importOleObject( rAttribs );
333         break;
334         case XLS_TOKEN( controls ):
335             if( nElement == XLS_TOKEN( control ) ) importControl( rAttribs );
336         break;
337     }
338     return 0;
339 }
340 
341 void WorksheetFragment::onCharacters( const OUString& rChars )
342 {
343     switch( getCurrentElement() )
344     {
345         case XLS_TOKEN( firstHeader ):
346         case XLS_TOKEN( firstFooter ):
347         case XLS_TOKEN( oddHeader ):
348         case XLS_TOKEN( oddFooter ):
349         case XLS_TOKEN( evenHeader ):
350         case XLS_TOKEN( evenFooter ):
351             getPageSettings().importHeaderFooterCharacters( rChars, getCurrentElement() );
352         break;
353     }
354 }
355 
356 ContextHandlerRef WorksheetFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
357 {
358     switch( getCurrentElement() )
359     {
360         case XML_ROOT_CONTEXT:
361             if( nRecId == BIFF12_ID_WORKSHEET ) return this;
362         break;
363 
364         case BIFF12_ID_WORKSHEET:
365             switch( nRecId )
366             {
367                 case BIFF12_ID_SHEETDATA:       return new SheetDataContext( *this );
368                 case BIFF12_ID_CONDFORMATTING:  return new CondFormatContext( *this );
369                 case BIFF12_ID_DATAVALIDATIONS: return new DataValidationsContext( *this );
370                 case BIFF12_ID_AUTOFILTER:      return new AutoFilterContext( *this, getAutoFilters().createAutoFilter() );
371                 case BIFF12_ID_SCENARIOS:       return new ScenariosContext( *this );
372 
373                 case BIFF12_ID_SHEETVIEWS:
374                 case BIFF12_ID_COLS:
375                 case BIFF12_ID_MERGECELLS:
376                 case BIFF12_ID_ROWBREAKS:
377                 case BIFF12_ID_COLBREAKS:
378                 case BIFF12_ID_OLEOBJECTS:
379                 case BIFF12_ID_CONTROLS:        return this;
380 
381                 case BIFF12_ID_SHEETPR:         getWorksheetSettings().importSheetPr( rStrm );              break;
382                 case BIFF12_ID_DIMENSION:       importDimension( rStrm );                                   break;
383                 case BIFF12_ID_SHEETFORMATPR:   importSheetFormatPr( rStrm );                               break;
384                 case BIFF12_ID_HYPERLINK:       importHyperlink( rStrm );                                   break;
385                 case BIFF12_ID_PAGEMARGINS:     getPageSettings().importPageMargins( rStrm );               break;
386                 case BIFF12_ID_PAGESETUP:       getPageSettings().importPageSetup( getRelations(), rStrm ); break;
387                 case BIFF12_ID_PRINTOPTIONS:    getPageSettings().importPrintOptions( rStrm );              break;
388                 case BIFF12_ID_HEADERFOOTER:    getPageSettings().importHeaderFooter( rStrm );              break;
389                 case BIFF12_ID_PICTURE:         getPageSettings().importPicture( getRelations(), rStrm );   break;
390                 case BIFF12_ID_SHEETPROTECTION: getWorksheetSettings().importSheetProtection( rStrm );      break;
391                 case BIFF12_ID_PHONETICPR:      getWorksheetSettings().importPhoneticPr( rStrm );           break;
392                 case BIFF12_ID_DRAWING:         importDrawing( rStrm );                                     break;
393                 case BIFF12_ID_LEGACYDRAWING:   importLegacyDrawing( rStrm );                               break;
394             }
395         break;
396 
397         case BIFF12_ID_SHEETVIEWS:
398             switch( nRecId )
399             {
400                 case BIFF12_ID_SHEETVIEW:       getSheetViewSettings().importSheetView( rStrm );            return this;
401             }
402         break;
403         case BIFF12_ID_SHEETVIEW:
404             switch( nRecId )
405             {
406                 case BIFF12_ID_PANE:            getSheetViewSettings().importPane( rStrm );                 break;
407                 case BIFF12_ID_SELECTION:       getSheetViewSettings().importSelection( rStrm );            break;
408             }
409         break;
410 
411         case BIFF12_ID_COLS:
412             if( nRecId == BIFF12_ID_COL ) importCol( rStrm );
413         break;
414         case BIFF12_ID_MERGECELLS:
415             if( nRecId == BIFF12_ID_MERGECELL ) importMergeCell( rStrm );
416         break;
417         case BIFF12_ID_ROWBREAKS:
418             if( nRecId == BIFF12_ID_BRK ) importBrk( rStrm, true );
419         break;
420         case BIFF12_ID_COLBREAKS:
421             if( nRecId == BIFF12_ID_BRK ) importBrk( rStrm, false );
422         break;
423         case BIFF12_ID_OLEOBJECTS:
424             if( nRecId == BIFF12_ID_OLEOBJECT ) importOleObject( rStrm );
425         break;
426         case BIFF12_ID_CONTROLS:
427             if( nRecId == BIFF12_ID_CONTROL ) importControl( rStrm );
428         break;
429     }
430     return 0;
431 }
432 
433 const RecordInfo* WorksheetFragment::getRecordInfos() const
434 {
435     static const RecordInfo spRecInfos[] =
436     {
437         { BIFF12_ID_AUTOFILTER,         BIFF12_ID_AUTOFILTER + 1        },
438         { BIFF12_ID_CFRULE,             BIFF12_ID_CFRULE + 1            },
439         { BIFF12_ID_COLBREAKS,          BIFF12_ID_COLBREAKS + 1         },
440         { BIFF12_ID_COLORSCALE,         BIFF12_ID_COLORSCALE + 1        },
441         { BIFF12_ID_COLS,               BIFF12_ID_COLS + 1              },
442         { BIFF12_ID_CONDFORMATTING,     BIFF12_ID_CONDFORMATTING + 1    },
443         { BIFF12_ID_CONTROLS,           BIFF12_ID_CONTROLS + 2          },
444         { BIFF12_ID_CUSTOMFILTERS,      BIFF12_ID_CUSTOMFILTERS + 1     },
445         { BIFF12_ID_CUSTOMSHEETVIEW,    BIFF12_ID_CUSTOMSHEETVIEW + 1   },
446         { BIFF12_ID_CUSTOMSHEETVIEWS,   BIFF12_ID_CUSTOMSHEETVIEWS + 3  },
447         { BIFF12_ID_DATABAR,            BIFF12_ID_DATABAR + 1           },
448         { BIFF12_ID_DATAVALIDATIONS,    BIFF12_ID_DATAVALIDATIONS + 1   },
449         { BIFF12_ID_DISCRETEFILTERS,    BIFF12_ID_DISCRETEFILTERS + 1   },
450         { BIFF12_ID_FILTERCOLUMN,       BIFF12_ID_FILTERCOLUMN + 1      },
451         { BIFF12_ID_HEADERFOOTER,       BIFF12_ID_HEADERFOOTER + 1      },
452         { BIFF12_ID_ICONSET,            BIFF12_ID_ICONSET + 1           },
453         { BIFF12_ID_MERGECELLS,         BIFF12_ID_MERGECELLS + 1        },
454         { BIFF12_ID_OLEOBJECTS,         BIFF12_ID_OLEOBJECTS + 2        },
455         { BIFF12_ID_ROW,                -1                              },
456         { BIFF12_ID_ROWBREAKS,          BIFF12_ID_ROWBREAKS + 1         },
457         { BIFF12_ID_SCENARIO,           BIFF12_ID_SCENARIO + 1          },
458         { BIFF12_ID_SCENARIOS,          BIFF12_ID_SCENARIOS + 1         },
459         { BIFF12_ID_SHEETDATA,          BIFF12_ID_SHEETDATA + 1         },
460         { BIFF12_ID_SHEETVIEW,          BIFF12_ID_SHEETVIEW + 1         },
461         { BIFF12_ID_SHEETVIEWS,         BIFF12_ID_SHEETVIEWS + 1        },
462         { BIFF12_ID_TABLEPARTS,         BIFF12_ID_TABLEPARTS + 2        },
463         { BIFF12_ID_WORKSHEET,          BIFF12_ID_WORKSHEET + 1         },
464         { -1,                           -1                              }
465     };
466     return spRecInfos;
467 }
468 
469 void WorksheetFragment::initializeImport()
470 {
471     // initial processing in base class WorksheetHelper
472     initializeWorksheetImport();
473 
474     // import query table fragments related to this worksheet
475     RelationsRef xQueryRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "queryTable" ) );
476     for( Relations::const_iterator aIt = xQueryRels->begin(), aEnd = xQueryRels->end(); aIt != aEnd; ++aIt )
477         importOoxFragment( new QueryTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
478 
479     // import pivot table fragments related to this worksheet
480     RelationsRef xPivotRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "pivotTable" ) );
481     for( Relations::const_iterator aIt = xPivotRels->begin(), aEnd = xPivotRels->end(); aIt != aEnd; ++aIt )
482         importOoxFragment( new PivotTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
483 }
484 
485 void WorksheetFragment::finalizeImport()
486 {
487     // final processing in base class WorksheetHelper
488     finalizeWorksheetImport();
489 }
490 
491 // private --------------------------------------------------------------------
492 
493 void WorksheetFragment::importPageSetUpPr( const AttributeList& rAttribs )
494 {
495     // for whatever reason, this flag is still stored separated from the page settings
496     getPageSettings().setFitToPagesMode( rAttribs.getBool( XML_fitToPage, false ) );
497 }
498 
499 void WorksheetFragment::importDimension( const AttributeList& rAttribs )
500 {
501     CellRangeAddress aRange;
502     getAddressConverter().convertToCellRangeUnchecked( aRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex() );
503     /*  OOXML stores the used area, if existing, or "A1" if the sheet is empty.
504         In case of "A1", the dimension at the WorksheetHelper object will not
505         be set. If the cell A1 exists, the used area will be updated while
506         importing the cell. */
507     if( (aRange.EndColumn > 0) || (aRange.EndRow > 0) )
508         extendUsedArea( aRange );
509 }
510 
511 void WorksheetFragment::importSheetFormatPr( const AttributeList& rAttribs )
512 {
513     // default column settings
514     setBaseColumnWidth( rAttribs.getInteger( XML_baseColWidth, 8 ) );
515     setDefaultColumnWidth( rAttribs.getDouble( XML_defaultColWidth, 0.0 ) );
516     // default row settings
517     setDefaultRowSettings(
518         rAttribs.getDouble( XML_defaultRowHeight, 0.0 ),
519         rAttribs.getBool( XML_customHeight, false ),
520         rAttribs.getBool( XML_zeroHeight, false ),
521         rAttribs.getBool( XML_thickTop, false ),
522         rAttribs.getBool( XML_thickBottom, false ) );
523 }
524 
525 void WorksheetFragment::importCol( const AttributeList& rAttribs )
526 {
527     ColumnModel aModel;
528     aModel.maRange.mnFirst = rAttribs.getInteger( XML_min, -1 );
529     aModel.maRange.mnLast  = rAttribs.getInteger( XML_max, -1 );
530     aModel.mfWidth         = rAttribs.getDouble( XML_width, 0.0 );
531     aModel.mnXfId          = rAttribs.getInteger( XML_style, -1 );
532     aModel.mnLevel         = rAttribs.getInteger( XML_outlineLevel, 0 );
533     aModel.mbShowPhonetic  = rAttribs.getBool( XML_phonetic, false );
534     aModel.mbHidden        = rAttribs.getBool( XML_hidden, false );
535     aModel.mbCollapsed     = rAttribs.getBool( XML_collapsed, false );
536     // set column properties in the current sheet
537     setColumnModel( aModel );
538 }
539 
540 void WorksheetFragment::importMergeCell( const AttributeList& rAttribs )
541 {
542     CellRangeAddress aRange;
543     if( getAddressConverter().convertToCellRange( aRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex(), true, true ) )
544         getSheetData().setMergedRange( aRange );
545 }
546 
547 void WorksheetFragment::importHyperlink( const AttributeList& rAttribs )
548 {
549     HyperlinkModel aModel;
550     if( getAddressConverter().convertToCellRange( aModel.maRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex(), true, true ) )
551     {
552         aModel.maTarget   = getRelations().getExternalTargetFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
553         aModel.maLocation = rAttribs.getXString( XML_location, OUString() );
554         aModel.maDisplay  = rAttribs.getXString( XML_display, OUString() );
555         aModel.maTooltip  = rAttribs.getXString( XML_tooltip, OUString() );
556         setHyperlink( aModel );
557     }
558 }
559 
560 void WorksheetFragment::importBrk( const AttributeList& rAttribs, bool bRowBreak )
561 {
562     PageBreakModel aModel;
563     aModel.mnColRow = rAttribs.getInteger( XML_id, 0 );
564     aModel.mnMin    = rAttribs.getInteger( XML_id, 0 );
565     aModel.mnMax    = rAttribs.getInteger( XML_id, 0 );
566     aModel.mbManual = rAttribs.getBool( XML_man, false );
567     setPageBreak( aModel, bRowBreak );
568 }
569 
570 void WorksheetFragment::importDrawing( const AttributeList& rAttribs )
571 {
572     setDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
573 }
574 
575 void WorksheetFragment::importLegacyDrawing( const AttributeList& rAttribs )
576 {
577     setVmlDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
578 }
579 
580 void WorksheetFragment::importOleObject( const AttributeList& rAttribs )
581 {
582     ::oox::vml::OleObjectInfo aInfo;
583     aInfo.setShapeId( rAttribs.getInteger( XML_shapeId, 0 ) );
584     OSL_ENSURE( rAttribs.hasAttribute( XML_link ) != rAttribs.hasAttribute( R_TOKEN( id ) ),
585         "WorksheetFragment::importOleObject - OLE object must be either linked or embedded" );
586     aInfo.mbLinked = rAttribs.hasAttribute( XML_link );
587     if( aInfo.mbLinked )
588         aInfo.maTargetLink = getFormulaParser().importOleTargetLink( rAttribs.getString( XML_link, OUString() ) );
589     else if( rAttribs.hasAttribute( R_TOKEN( id ) ) )
590         importEmbeddedOleData( aInfo.maEmbeddedData, rAttribs.getString( R_TOKEN( id ), OUString() ) );
591     aInfo.maProgId = rAttribs.getString( XML_progId, OUString() );
592     aInfo.mbShowAsIcon = rAttribs.getToken( XML_dvAspect, XML_DVASPECT_CONTENT ) == XML_DVASPECT_ICON;
593     aInfo.mbAutoUpdate = rAttribs.getToken( XML_oleUpdate, XML_OLEUPDATE_ONCALL ) == XML_OLEUPDATE_ALWAYS;
594     aInfo.mbAutoLoad = rAttribs.getBool( XML_autoLoad, false );
595     getVmlDrawing().registerOleObject( aInfo );
596 }
597 
598 void WorksheetFragment::importControl( const AttributeList& rAttribs )
599 {
600     ::oox::vml::ControlInfo aInfo;
601     aInfo.setShapeId( rAttribs.getInteger( XML_shapeId, 0 ) );
602     aInfo.maFragmentPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
603     aInfo.maName = rAttribs.getString( XML_name, OUString() );
604     getVmlDrawing().registerControl( aInfo );
605 }
606 
607 void WorksheetFragment::importDimension( SequenceInputStream& rStrm )
608 {
609     BinRange aBinRange;
610     aBinRange.read( rStrm );
611     CellRangeAddress aRange;
612     getAddressConverter().convertToCellRangeUnchecked( aRange, aBinRange, getSheetIndex() );
613     /*  BIFF12 stores the used area, if existing, or "A1" if the sheet is
614         empty. In case of "A1", the dimension at the WorksheetHelper object
615         will not be set. If the cell A1 exists, the used area will be updated
616         while importing the cell. */
617     if( (aRange.EndColumn > 0) || (aRange.EndRow > 0) )
618         extendUsedArea( aRange );
619 }
620 
621 void WorksheetFragment::importSheetFormatPr( SequenceInputStream& rStrm )
622 {
623     sal_Int32 nDefaultWidth;
624     sal_uInt16 nBaseWidth, nDefaultHeight, nFlags;
625     rStrm >> nDefaultWidth >> nBaseWidth >> nDefaultHeight >> nFlags;
626 
627     // base column with
628     setBaseColumnWidth( nBaseWidth );
629     // default width is stored as 1/256th of a character in BIFF12, convert to entire character
630     setDefaultColumnWidth( static_cast< double >( nDefaultWidth ) / 256.0 );
631     // row height is in twips in BIFF12, convert to points; equal flags in all BIFFs
632     setDefaultRowSettings(
633         nDefaultHeight / 20.0,
634         getFlag( nFlags, BIFF_DEFROW_CUSTOMHEIGHT ),
635         getFlag( nFlags, BIFF_DEFROW_HIDDEN ),
636         getFlag( nFlags, BIFF_DEFROW_THICKTOP ),
637         getFlag( nFlags, BIFF_DEFROW_THICKBOTTOM ) );
638 }
639 
640 void WorksheetFragment::importCol( SequenceInputStream& rStrm )
641 {
642     ColumnModel aModel;
643 
644     sal_Int32 nWidth;
645     sal_uInt16 nFlags;
646     rStrm >> aModel.maRange.mnFirst >> aModel.maRange.mnLast >> nWidth >> aModel.mnXfId >> nFlags;
647 
648     // column indexes are 0-based in BIFF12, but ColumnModel expects 1-based
649     ++aModel.maRange.mnFirst;
650     ++aModel.maRange.mnLast;
651     // width is stored as 1/256th of a character in BIFF12, convert to entire character
652     aModel.mfWidth        = static_cast< double >( nWidth ) / 256.0;
653     // equal flags in all BIFFs
654     aModel.mnLevel        = extractValue< sal_Int32 >( nFlags, 8, 3 );
655     aModel.mbShowPhonetic = getFlag( nFlags, BIFF_COLINFO_SHOWPHONETIC );
656     aModel.mbHidden       = getFlag( nFlags, BIFF_COLINFO_HIDDEN );
657     aModel.mbCollapsed    = getFlag( nFlags, BIFF_COLINFO_COLLAPSED );
658     // set column properties in the current sheet
659     setColumnModel( aModel );
660 }
661 
662 void WorksheetFragment::importMergeCell( SequenceInputStream& rStrm )
663 {
664     BinRange aBinRange;
665     rStrm >> aBinRange;
666     CellRangeAddress aRange;
667     if( getAddressConverter().convertToCellRange( aRange, aBinRange, getSheetIndex(), true, true ) )
668         getSheetData().setMergedRange( aRange );
669 }
670 
671 void WorksheetFragment::importHyperlink( SequenceInputStream& rStrm )
672 {
673     BinRange aBinRange;
674     rStrm >> aBinRange;
675     HyperlinkModel aModel;
676     if( getAddressConverter().convertToCellRange( aModel.maRange, aBinRange, getSheetIndex(), true, true ) )
677     {
678         aModel.maTarget = getRelations().getExternalTargetFromRelId( BiffHelper::readString( rStrm ) );
679         rStrm >> aModel.maLocation >> aModel.maTooltip >> aModel.maDisplay;
680         setHyperlink( aModel );
681     }
682 }
683 
684 void WorksheetFragment::importBrk( SequenceInputStream& rStrm, bool bRowBreak )
685 {
686     PageBreakModel aModel;
687     sal_Int32 nManual;
688     rStrm >> aModel.mnColRow >> aModel.mnMin >> aModel.mnMax >> nManual;
689     aModel.mbManual = nManual != 0;
690     setPageBreak( aModel, bRowBreak );
691 }
692 
693 void WorksheetFragment::importDrawing( SequenceInputStream& rStrm )
694 {
695     setDrawingPath( getFragmentPathFromRelId( BiffHelper::readString( rStrm ) ) );
696 }
697 
698 void WorksheetFragment::importLegacyDrawing( SequenceInputStream& rStrm )
699 {
700     setVmlDrawingPath( getFragmentPathFromRelId( BiffHelper::readString( rStrm ) ) );
701 }
702 
703 void WorksheetFragment::importOleObject( SequenceInputStream& rStrm )
704 {
705     ::oox::vml::OleObjectInfo aInfo;
706     sal_Int32 nAspect, nUpdateMode, nShapeId;
707     sal_uInt16 nFlags;
708     rStrm >> nAspect >> nUpdateMode >> nShapeId >> nFlags >> aInfo.maProgId;
709     aInfo.mbLinked = getFlag( nFlags, BIFF12_OLEOBJECT_LINKED );
710     if( aInfo.mbLinked )
711         aInfo.maTargetLink = getFormulaParser().importOleTargetLink( rStrm );
712     else
713         importEmbeddedOleData( aInfo.maEmbeddedData, BiffHelper::readString( rStrm ) );
714     aInfo.setShapeId( nShapeId );
715     aInfo.mbShowAsIcon = nAspect == BIFF12_OLEOBJECT_ICON;
716     aInfo.mbAutoUpdate = nUpdateMode == BIFF12_OLEOBJECT_ALWAYS;
717     aInfo.mbAutoLoad = getFlag( nFlags, BIFF12_OLEOBJECT_AUTOLOAD );
718     getVmlDrawing().registerOleObject( aInfo );
719 }
720 
721 void WorksheetFragment::importControl( SequenceInputStream& rStrm )
722 {
723     ::oox::vml::ControlInfo aInfo;
724     aInfo.setShapeId( rStrm.readInt32() );
725     aInfo.maFragmentPath = getFragmentPathFromRelId( BiffHelper::readString( rStrm ) );
726     rStrm >> aInfo.maName;
727     getVmlDrawing().registerControl( aInfo );
728 }
729 
730 void WorksheetFragment::importEmbeddedOleData( StreamDataSequence& orEmbeddedData, const OUString& rRelId )
731 {
732     OUString aFragmentPath = getFragmentPathFromRelId( rRelId );
733     if( aFragmentPath.getLength() > 0 )
734         getBaseFilter().importBinaryData( orEmbeddedData, aFragmentPath );
735 }
736 
737 // ============================================================================
738 
739 BiffWorksheetFragment::BiffWorksheetFragment( const WorksheetHelper& rHelper, const BiffWorkbookFragmentBase& rParent ) :
740     BiffWorksheetFragmentBase( rHelper, rParent )
741 {
742 }
743 
744 BiffWorksheetFragment::~BiffWorksheetFragment()
745 {
746 }
747 
748 bool BiffWorksheetFragment::importFragment()
749 {
750     // initial processing in base class WorksheetHelper
751     initializeWorksheetImport();
752 
753     // create a SheetDataContext object that implements cell import
754     BiffSheetDataContext aSheetData( *this );
755 
756     WorkbookSettings& rWorkbookSett   = getWorkbookSettings();
757     WorksheetSettings& rWorksheetSett = getWorksheetSettings();
758     SheetViewSettings& rSheetViewSett = getSheetViewSettings();
759     CondFormatBuffer& rCondFormats    = getCondFormats();
760     PageSettings& rPageSett           = getPageSettings();
761     BiffSheetDrawing& rDrawing        = getBiffDrawing();
762 
763     // process all record in this sheet fragment
764     BiffInputStream& rStrm = getInputStream();
765     while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
766     {
767         if( BiffHelper::isBofRecord( rStrm ) )
768         {
769             // skip unknown embedded fragments (BOF/EOF blocks)
770             skipFragment();
771         }
772         else
773         {
774             // cache base stream position to detect if record is already processed
775             sal_Int64 nStrmPos = rStrm.tellBase();
776             sal_uInt16 nRecId = rStrm.getRecId();
777 
778             switch( nRecId )
779             {
780                 // records in all BIFF versions
781                 case BIFF_ID_BOTTOMMARGIN:      rPageSett.importBottomMargin( rStrm );      break;
782                 case BIFF_ID_CALCCOUNT:         rWorkbookSett.importCalcCount( rStrm );     break;
783                 case BIFF_ID_CALCMODE:          rWorkbookSett.importCalcMode( rStrm );      break;
784                 case BIFF_ID_DEFCOLWIDTH:       importDefColWidth( rStrm );                 break;
785                 case BIFF_ID_DELTA:             rWorkbookSett.importDelta( rStrm );         break;
786                 case BIFF2_ID_DIMENSION:        importDimension( rStrm );                   break;
787                 case BIFF3_ID_DIMENSION:        importDimension( rStrm );                   break;
788                 case BIFF_ID_FOOTER:            rPageSett.importFooter( rStrm );            break;
789                 case BIFF_ID_HEADER:            rPageSett.importHeader( rStrm );            break;
790                 case BIFF_ID_HORPAGEBREAKS:     importPageBreaks( rStrm, true );            break;
791                 case BIFF_ID_ITERATION:         rWorkbookSett.importIteration( rStrm );     break;
792                 case BIFF_ID_LEFTMARGIN:        rPageSett.importLeftMargin( rStrm );        break;
793                 case BIFF_ID_NOTE:              importNote( rStrm );                        break;
794                 case BIFF_ID_PANE:              rSheetViewSett.importPane( rStrm );         break;
795                 case BIFF_ID_PASSWORD:          rWorksheetSett.importPassword( rStrm );     break;
796                 case BIFF_ID_PRINTGRIDLINES:    rPageSett.importPrintGridLines( rStrm );    break;
797                 case BIFF_ID_PRINTHEADERS:      rPageSett.importPrintHeaders( rStrm );      break;
798                 case BIFF_ID_PROTECT:           rWorksheetSett.importProtect( rStrm );      break;
799                 case BIFF_ID_REFMODE:           rWorkbookSett.importRefMode( rStrm );       break;
800                 case BIFF_ID_RIGHTMARGIN:       rPageSett.importRightMargin( rStrm );       break;
801                 case BIFF_ID_SELECTION:         rSheetViewSett.importSelection( rStrm );    break;
802                 case BIFF_ID_TOPMARGIN:         rPageSett.importTopMargin( rStrm );         break;
803                 case BIFF_ID_VERPAGEBREAKS:     importPageBreaks( rStrm, false );           break;
804 
805                 // BIFF specific records
806                 default: switch( getBiff() )
807                 {
808                     case BIFF2: switch( nRecId )
809                     {
810                         case BIFF_ID_COLUMNDEFAULT: importColumnDefault( rStrm );           break;
811                         case BIFF_ID_COLWIDTH:      importColWidth( rStrm );                break;
812                         case BIFF2_ID_DEFROWHEIGHT: importDefRowHeight( rStrm );            break;
813                         case BIFF2_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );  break;
814                     }
815                     break;
816 
817                     case BIFF3: switch( nRecId )
818                     {
819                         case BIFF_ID_COLINFO:       importColInfo( rStrm );                         break;
820                         case BIFF_ID_DEFCOLWIDTH:   importDefColWidth( rStrm );                     break;
821                         case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm );                    break;
822                         case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
823                         case BIFF_ID_OBJ:           rDrawing.importObj( rStrm );                    break;
824                         case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
825                         case BIFF_ID_SAVERECALC:    rWorkbookSett.importSaveRecalc( rStrm );        break;
826                         case BIFF_ID_SHEETPR:       rWorksheetSett.importSheetPr( rStrm );          break;
827                         case BIFF_ID_UNCALCED:      rWorkbookSett.importUncalced( rStrm );          break;
828                         case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
829                         case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
830                     }
831                     break;
832 
833                     case BIFF4: switch( nRecId )
834                     {
835                         case BIFF_ID_COLINFO:       importColInfo( rStrm );                         break;
836                         case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm );                    break;
837                         case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
838                         case BIFF_ID_OBJ:           rDrawing.importObj( rStrm );                    break;
839                         case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
840                         case BIFF_ID_PAGESETUP:     rPageSett.importPageSetup( rStrm );             break;
841                         case BIFF_ID_SAVERECALC:    rWorkbookSett.importSaveRecalc( rStrm );        break;
842                         case BIFF_ID_SHEETPR:       rWorksheetSett.importSheetPr( rStrm );          break;
843                         case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm );                   break;
844                         case BIFF_ID_UNCALCED:      rWorkbookSett.importUncalced( rStrm );          break;
845                         case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
846                         case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
847                     }
848                     break;
849 
850                     case BIFF5: switch( nRecId )
851                     {
852                         case BIFF_ID_AUTOFILTER:    importAutoFilter( rStrm );                      break;
853                         case BIFF_ID_COLINFO:       importColInfo( rStrm );                         break;
854                         case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm );                    break;
855                         case BIFF_ID_HCENTER:       rPageSett.importHorCenter( rStrm );             break;
856                         case BIFF_ID_MERGEDCELLS:   importMergedCells( rStrm );                     break;  // #i62300# also in BIFF5
857                         case BIFF_ID_OBJ:           rDrawing.importObj( rStrm );                    break;
858                         case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm );    break;
859                         case BIFF_ID_PAGESETUP:     rPageSett.importPageSetup( rStrm );             break;
860                         case BIFF_ID_PTDEFINITION:  importPTDefinition( rStrm );                    break;
861                         case BIFF_ID_SAVERECALC:    rWorkbookSett.importSaveRecalc( rStrm );        break;
862                         case BIFF_ID_SCENPROTECT:   rWorksheetSett.importScenProtect( rStrm );      break;
863                         case BIFF_ID_SCL:           rSheetViewSett.importScl( rStrm );              break;
864                         case BIFF_ID_SHEETPR:       rWorksheetSett.importSheetPr( rStrm );          break;
865                         case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm );                   break;
866                         case BIFF_ID_UNCALCED:      rWorkbookSett.importUncalced( rStrm );          break;
867                         case BIFF_ID_VCENTER:       rPageSett.importVerCenter( rStrm );             break;
868                         case BIFF3_ID_WINDOW2:      rSheetViewSett.importWindow2( rStrm );          break;
869                     }
870                     break;
871 
872                     case BIFF8: switch( nRecId )
873                     {
874                         case BIFF_ID_AUTOFILTER:        importAutoFilter( rStrm );                      break;
875                         case BIFF_ID_CFHEADER:          rCondFormats.importCfHeader( rStrm );           break;
876                         case BIFF_ID_CODENAME:          rWorksheetSett.importCodeName( rStrm );         break;
877                         case BIFF_ID_COLINFO:           importColInfo( rStrm );                         break;
878                         case BIFF_ID_DATAVALIDATION:    importDataValidation( rStrm );                  break;
879                         case BIFF_ID_DATAVALIDATIONS:   importDataValidations( rStrm );                 break;
880                         case BIFF3_ID_DEFROWHEIGHT:     importDefRowHeight( rStrm );                    break;
881                         case BIFF_ID_HCENTER:           rPageSett.importHorCenter( rStrm );             break;
882                         case BIFF_ID_HYPERLINK:         importHyperlink( rStrm );                       break;
883                         case BIFF_ID_LABELRANGES:       importLabelRanges( rStrm );                     break;
884                         case BIFF_ID_MERGEDCELLS:       importMergedCells( rStrm );                     break;
885                         case BIFF_ID_OBJ:               rDrawing.importObj( rStrm );                    break;
886                         case BIFF_ID_OBJECTPROTECT:     rWorksheetSett.importObjectProtect( rStrm );    break;
887                         case BIFF_ID_PAGESETUP:         rPageSett.importPageSetup( rStrm );             break;
888                         case BIFF_ID_PHONETICPR:        rWorksheetSett.importPhoneticPr( rStrm );       break;
889                         case BIFF_ID_PICTURE:           rPageSett.importPicture( rStrm );               break;
890                         case BIFF_ID_PTDEFINITION:      importPTDefinition( rStrm );                    break;
891                         case BIFF_ID_QUERYTABLE:        importQueryTable( rStrm );                      break;
892                         case BIFF_ID_SAVERECALC:        rWorkbookSett.importSaveRecalc( rStrm );        break;
893                         case BIFF_ID_SCENARIOS:         importScenarios( rStrm );                       break;
894                         case BIFF_ID_SCENPROTECT:       rWorksheetSett.importScenProtect( rStrm );      break;
895                         case BIFF_ID_SCL:               rSheetViewSett.importScl( rStrm );              break;
896                         case BIFF_ID_SHEETEXT:          rWorksheetSett.importSheetExt( rStrm );         break;
897                         case BIFF_ID_SHEETPR:           rWorksheetSett.importSheetPr( rStrm );          break;
898                         case BIFF_ID_SHAREDFEATHEAD:    importSharedFeatHead( rStrm );                  break;
899                         case BIFF_ID_STANDARDWIDTH:     importStandardWidth( rStrm );                   break;
900                         case BIFF_ID_UNCALCED:          rWorkbookSett.importUncalced( rStrm );          break;
901                         case BIFF_ID_VCENTER:           rPageSett.importVerCenter( rStrm );             break;
902                         case BIFF3_ID_WINDOW2:          rSheetViewSett.importWindow2( rStrm );          break;
903                     }
904                     break;
905 
906                     case BIFF_UNKNOWN: break;
907                 }
908             }
909 
910             // record not processed, try record context objects
911             if( rStrm.tellBase() == nStrmPos )
912             {
913                 // first, try cell table records
914                 aSheetData.importRecord( rStrm );
915                 // handle another open record context
916                 if( mxContext.get() )
917                 {
918                     // if it was a cell table record, forget the other record context
919                     if( rStrm.tellBase() == nStrmPos )
920                         mxContext->importRecord( rStrm );
921                     else
922                         mxContext.reset();
923                 }
924             }
925         }
926     }
927 
928     // final processing in base class WorksheetHelper
929     finalizeWorksheetImport();
930     return rStrm.getRecId() == BIFF_ID_EOF;
931 }
932 
933 // private --------------------------------------------------------------------
934 
935 void BiffWorksheetFragment::importAutoFilter( BiffInputStream& rStrm )
936 {
937     mxContext.reset( new BiffAutoFilterContext( *this, getAutoFilters().createAutoFilter() ) );
938     mxContext->importRecord( rStrm );
939 }
940 
941 void BiffWorksheetFragment::importColInfo( BiffInputStream& rStrm )
942 {
943     sal_uInt16 nFirstCol, nLastCol, nWidth, nXfId, nFlags;
944     rStrm >> nFirstCol >> nLastCol >> nWidth >> nXfId >> nFlags;
945 
946     ColumnModel aModel;
947     // column indexes are 0-based in BIFF, but ColumnModel expects 1-based
948     aModel.maRange.mnFirst = static_cast< sal_Int32 >( nFirstCol ) + 1;
949     aModel.maRange.mnLast  = static_cast< sal_Int32 >( nLastCol ) + 1;
950     // width is stored as 1/256th of a character in BIFF, convert to entire character
951     aModel.mfWidth         = static_cast< double >( nWidth ) / 256.0;
952     aModel.mnXfId          = nXfId;
953     aModel.mnLevel         = extractValue< sal_Int32 >( nFlags, 8, 3 );
954     aModel.mbShowPhonetic  = getFlag( nFlags, BIFF_COLINFO_SHOWPHONETIC );
955     aModel.mbHidden        = getFlag( nFlags, BIFF_COLINFO_HIDDEN );
956     aModel.mbCollapsed     = getFlag( nFlags, BIFF_COLINFO_COLLAPSED );
957     // set column properties in the current sheet
958     setColumnModel( aModel );
959 }
960 
961 void BiffWorksheetFragment::importColumnDefault( BiffInputStream& rStrm )
962 {
963     sal_uInt16 nFirstCol, nLastCol, nXfId;
964     rStrm >> nFirstCol >> nLastCol >> nXfId;
965     setDefaultColumnFormat( nFirstCol, nLastCol, nXfId );
966 }
967 
968 void BiffWorksheetFragment::importColWidth( BiffInputStream& rStrm )
969 {
970     sal_uInt8 nFirstCol, nLastCol;
971     sal_uInt16 nWidth;
972     rStrm >> nFirstCol >> nLastCol >> nWidth;
973 
974     ColumnModel aModel;
975     // column indexes are 0-based in BIFF, but ColumnModel expects 1-based
976     aModel.maRange.mnFirst = static_cast< sal_Int32 >( nFirstCol ) + 1;
977     aModel.maRange.mnLast = static_cast< sal_Int32 >( nLastCol ) + 1;
978     // width is stored as 1/256th of a character in BIFF, convert to entire character
979     aModel.mfWidth = static_cast< double >( nWidth ) / 256.0;
980     // set column properties in the current sheet
981     setColumnModel( aModel );
982 }
983 
984 void BiffWorksheetFragment::importDefColWidth( BiffInputStream& rStrm )
985 {
986     /*  Stored as entire number of characters without padding pixels, which
987         will be added in setBaseColumnWidth(). Call has no effect, if a
988         width has already been set from the STANDARDWIDTH record. */
989     setBaseColumnWidth( rStrm.readuInt16() );
990 }
991 
992 void BiffWorksheetFragment::importDefRowHeight( BiffInputStream& rStrm )
993 {
994     sal_uInt16 nFlags = BIFF_DEFROW_CUSTOMHEIGHT, nHeight;
995     if( getBiff() != BIFF2 )
996         rStrm >> nFlags;
997     rStrm >> nHeight;
998     if( getBiff() == BIFF2 )
999         nHeight &= BIFF2_DEFROW_MASK;
1000     // row height is in twips in BIFF, convert to points
1001     setDefaultRowSettings(
1002         nHeight / 20.0,
1003         getFlag( nFlags, BIFF_DEFROW_CUSTOMHEIGHT ),
1004         getFlag( nFlags, BIFF_DEFROW_HIDDEN ),
1005         getFlag( nFlags, BIFF_DEFROW_THICKTOP ),
1006         getFlag( nFlags, BIFF_DEFROW_THICKBOTTOM ) );
1007 }
1008 
1009 void BiffWorksheetFragment::importDataValidations( BiffInputStream& rStrm )
1010 {
1011     sal_Int32 nObjId;
1012     rStrm.skip( 10 );
1013     rStrm >> nObjId;
1014     //! TODO: invalidate object id in drawing object manager
1015 }
1016 
1017 namespace {
1018 
1019 OUString lclReadDataValMessage( BiffInputStream& rStrm )
1020 {
1021     // empty strings are single NUL characters (string length is 1)
1022     OUString aMessage = rStrm.readUniString( true );
1023     if( (aMessage.getLength() == 1) && (aMessage[ 0 ] == 0) )
1024         aMessage = OUString();
1025     return aMessage;
1026 }
1027 
1028 ApiTokenSequence lclReadDataValFormula( BiffInputStream& rStrm, FormulaParser& rParser )
1029 {
1030     sal_uInt16 nFmlaSize = rStrm.readuInt16();
1031     rStrm.skip( 2 );
1032     return rParser.importFormula( CellAddress(), FORMULATYPE_VALIDATION, rStrm, &nFmlaSize );
1033 }
1034 
1035 } // namespace
1036 
1037 void BiffWorksheetFragment::importDataValidation( BiffInputStream& rStrm )
1038 {
1039     ValidationModel aModel;
1040 
1041     // flags
1042     sal_uInt32 nFlags;
1043     rStrm >> nFlags;
1044     aModel.setBiffType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
1045     aModel.setBiffOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
1046     aModel.setBiffErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
1047     aModel.mbAllowBlank   = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
1048     aModel.mbNoDropDown   = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
1049     aModel.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
1050     aModel.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
1051 
1052     // message strings
1053     aModel.maInputTitle   = lclReadDataValMessage( rStrm );
1054     aModel.maErrorTitle   = lclReadDataValMessage( rStrm );
1055     aModel.maInputMessage = lclReadDataValMessage( rStrm );
1056     aModel.maErrorMessage = lclReadDataValMessage( rStrm );
1057 
1058     // condition formula(s)
1059     FormulaParser& rParser = getFormulaParser();
1060     aModel.maTokens1 = lclReadDataValFormula( rStrm, rParser );
1061     aModel.maTokens2 = lclReadDataValFormula( rStrm, rParser );
1062     // process string list of a list validation (convert to list of string tokens)
1063     if( (aModel.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
1064         rParser.convertStringToStringList( aModel.maTokens1, '\0', true );
1065 
1066     // cell range list
1067     BinRangeList aRanges;
1068     rStrm >> aRanges;
1069     getAddressConverter().convertToCellRangeList( aModel.maRanges, aRanges, getSheetIndex(), true );
1070 
1071     // set validation data
1072     setValidation( aModel );
1073 }
1074 
1075 void BiffWorksheetFragment::importDimension( BiffInputStream& rStrm )
1076 {
1077     // 32-bit row indexes in BIFF8
1078     bool bInt32Rows = (rStrm.getRecId() == BIFF3_ID_DIMENSION) && (getBiff() == BIFF8);
1079     BinRange aBinRange;
1080     aBinRange.read( rStrm, true, bInt32Rows );
1081     /*  BIFF stores the used area with end column and end row increased by 1
1082         (first unused column and row). */
1083     if( (aBinRange.maFirst.mnCol < aBinRange.maLast.mnCol) && (aBinRange.maFirst.mnRow < aBinRange.maLast.mnRow) )
1084     {
1085         // reduce range to used area
1086         --aBinRange.maLast.mnCol;
1087         --aBinRange.maLast.mnRow;
1088         CellRangeAddress aRange;
1089         getAddressConverter().convertToCellRangeUnchecked( aRange, aBinRange, getSheetIndex() );
1090         extendUsedArea( aRange );
1091     }
1092 }
1093 
1094 void BiffWorksheetFragment::importHyperlink( BiffInputStream& rStrm )
1095 {
1096     HyperlinkModel aModel;
1097 
1098     // read cell range for the hyperlink
1099     BinRange aBiffRange;
1100     rStrm >> aBiffRange;
1101     // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
1102     aBiffRange.maFirst.mnCol &= 0xFF;
1103     aBiffRange.maLast.mnCol &= 0xFF;
1104     if( !getAddressConverter().convertToCellRange( aModel.maRange, aBiffRange, getSheetIndex(), true, true ) )
1105         return;
1106 
1107     // try to read the StdHlink data
1108     if( !::oox::ole::OleHelper::importStdHlink( aModel, rStrm, true ) )
1109         return;
1110 
1111     // try to read the optional following SCREENTIP record
1112     if( (rStrm.getNextRecId() == BIFF_ID_SCREENTIP) && rStrm.startNextRecord() )
1113     {
1114         rStrm.skip( 2 );      // repeated record id
1115         // the cell range, again
1116         rStrm >> aBiffRange;
1117         CellRangeAddress aRange;
1118         if( getAddressConverter().convertToCellRange( aRange, aBiffRange, getSheetIndex(), true, true ) &&
1119             (aRange.StartColumn == aModel.maRange.StartColumn) &&
1120             (aRange.StartRow == aModel.maRange.StartRow) &&
1121             (aRange.EndColumn == aModel.maRange.EndColumn) &&
1122             (aRange.EndRow == aModel.maRange.EndRow) )
1123         {
1124             /*  This time, we have no string length, no flag field, and a
1125                 null-terminated 16-bit character array. */
1126             aModel.maTooltip = rStrm.readNulUnicodeArray();
1127         }
1128     }
1129 
1130     // store the hyperlink settings
1131     setHyperlink( aModel );
1132 }
1133 
1134 void BiffWorksheetFragment::importLabelRanges( BiffInputStream& rStrm )
1135 {
1136     BinRangeList aBiffRowRanges, aBiffColRanges;
1137     rStrm >> aBiffRowRanges >> aBiffColRanges;
1138     ApiCellRangeList aColRanges, aRowRanges;
1139     getAddressConverter().convertToCellRangeList( aColRanges, aBiffColRanges, getSheetIndex(), true );
1140     getAddressConverter().convertToCellRangeList( aRowRanges, aBiffRowRanges, getSheetIndex(), true );
1141     setLabelRanges( aColRanges, aRowRanges );
1142 }
1143 
1144 void BiffWorksheetFragment::importMergedCells( BiffInputStream& rStrm )
1145 {
1146     BinRangeList aBiffRanges;
1147     rStrm >> aBiffRanges;
1148     ApiCellRangeList aRanges;
1149     getAddressConverter().convertToCellRangeList( aRanges, aBiffRanges, getSheetIndex(), true );
1150     for( ApiCellRangeList::const_iterator aIt = aRanges.begin(), aEnd = aRanges.end(); aIt != aEnd; ++aIt )
1151         getSheetData().setMergedRange( *aIt );
1152 }
1153 
1154 void BiffWorksheetFragment::importNote( BiffInputStream& rStrm )
1155 {
1156     getComments().createComment()->importNote( rStrm );
1157 }
1158 
1159 void BiffWorksheetFragment::importPageBreaks( BiffInputStream& rStrm, bool bRowBreak )
1160 {
1161     PageBreakModel aModel;
1162     aModel.mbManual = true;             // only manual breaks stored in BIFF
1163     bool bBiff8 = getBiff() == BIFF8;   // skip start/end columns or rows in BIFF8
1164 
1165     sal_uInt16 nCount;
1166     rStrm >> nCount;
1167     for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
1168     {
1169         aModel.mnColRow = rStrm.readuInt16();
1170         setPageBreak( aModel, bRowBreak );
1171         if( bBiff8 )
1172             rStrm.skip( 4 );
1173     }
1174 }
1175 
1176 void BiffWorksheetFragment::importPTDefinition( BiffInputStream& rStrm )
1177 {
1178     mxContext.reset( new BiffPivotTableContext( *this ) );
1179     mxContext->importRecord( rStrm );
1180 }
1181 
1182 void BiffWorksheetFragment::importQueryTable( BiffInputStream& rStrm )
1183 {
1184     mxContext.reset( new BiffQueryTableContext( *this ) );
1185     mxContext->importRecord( rStrm );
1186 }
1187 
1188 void BiffWorksheetFragment::importScenarios( BiffInputStream& rStrm )
1189 {
1190     getScenarios().createSheetScenarios( getSheetIndex() ).importScenarios( rStrm );
1191 }
1192 
1193 void BiffWorksheetFragment::importSharedFeatHead( BiffInputStream& rStrm )
1194 {
1195     rStrm.skip( 12 );
1196     sal_uInt16 nType = rStrm.readuInt16();
1197     rStrm.skip( 5 );
1198     switch( nType )
1199     {
1200         case BIFF_SHRFEATHEAD_SHEETPROT:
1201             if( rStrm.getRemaining() >= 4 )
1202                 getWorksheetSettings().importSheetProtection( rStrm );
1203         break;
1204     }
1205 }
1206 
1207 void BiffWorksheetFragment::importStandardWidth( BiffInputStream& rStrm )
1208 {
1209     sal_uInt16 nWidth;
1210     rStrm >> nWidth;
1211     // width is stored as 1/256th of a character in BIFF, convert to entire character
1212     double fWidth = static_cast< double >( nWidth ) / 256.0;
1213     // set as default width, will override the width from DEFCOLWIDTH record
1214     setDefaultColumnWidth( fWidth );
1215 }
1216 
1217 // ============================================================================
1218 
1219 } // namespace xls
1220 } // namespace oox
1221