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