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