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/sheetdatacontext.hxx"
25 
26 #include <com/sun/star/table/CellContentType.hpp>
27 #include <com/sun/star/table/XCell.hpp>
28 #include <com/sun/star/table/XCellRange.hpp>
29 #include <com/sun/star/text/XText.hpp>
30 #include <com/sun/star/util/DateTime.hpp>
31 #include "oox/helper/attributelist.hxx"
32 #include "oox/helper/datetimehelper.hxx"
33 #include "oox/helper/propertyset.hxx"
34 #include "oox/xls/addressconverter.hxx"
35 #include "oox/xls/biffinputstream.hxx"
36 #include "oox/xls/formulaparser.hxx"
37 #include "oox/xls/richstringcontext.hxx"
38 #include "oox/xls/unitconverter.hxx"
39 
40 namespace oox {
41 namespace xls {
42 
43 // ============================================================================
44 
45 using namespace ::com::sun::star::sheet;
46 using namespace ::com::sun::star::table;
47 using namespace ::com::sun::star::text;
48 using namespace ::com::sun::star::uno;
49 using namespace ::com::sun::star::util;
50 
51 using ::oox::core::ContextHandlerRef;
52 using ::rtl::OUString;
53 
54 // ============================================================================
55 
56 namespace {
57 
58 // record constants -----------------------------------------------------------
59 
60 const sal_uInt32 BIFF12_CELL_SHOWPHONETIC   = 0x01000000;
61 
62 const sal_uInt8 BIFF12_DATATABLE_ROW        = 0x01;
63 const sal_uInt8 BIFF12_DATATABLE_2D         = 0x02;
64 const sal_uInt8 BIFF12_DATATABLE_REF1DEL    = 0x04;
65 const sal_uInt8 BIFF12_DATATABLE_REF2DEL    = 0x08;
66 
67 const sal_uInt16 BIFF12_ROW_THICKTOP        = 0x0001;
68 const sal_uInt16 BIFF12_ROW_THICKBOTTOM     = 0x0002;
69 const sal_uInt16 BIFF12_ROW_COLLAPSED       = 0x0800;
70 const sal_uInt16 BIFF12_ROW_HIDDEN          = 0x1000;
71 const sal_uInt16 BIFF12_ROW_CUSTOMHEIGHT    = 0x2000;
72 const sal_uInt16 BIFF12_ROW_CUSTOMFORMAT    = 0x4000;
73 const sal_uInt8 BIFF12_ROW_SHOWPHONETIC     = 0x01;
74 
75 const sal_uInt16 BIFF_DATATABLE_ROW         = 0x0004;
76 const sal_uInt16 BIFF_DATATABLE_2D          = 0x0008;
77 const sal_uInt16 BIFF_DATATABLE_REF1DEL     = 0x0010;
78 const sal_uInt16 BIFF_DATATABLE_REF2DEL     = 0x0020;
79 
80 const sal_uInt8 BIFF_FORMULA_RES_STRING     = 0;        /// Result is a string.
81 const sal_uInt8 BIFF_FORMULA_RES_BOOL       = 1;        /// Result is Boolean value.
82 const sal_uInt8 BIFF_FORMULA_RES_ERROR      = 2;        /// Result is error code.
83 const sal_uInt8 BIFF_FORMULA_RES_EMPTY      = 3;        /// Result is empty cell (BIFF8 only).
84 const sal_uInt16 BIFF_FORMULA_SHARED        = 0x0008;   /// Shared formula cell.
85 
86 const sal_uInt8 BIFF2_ROW_CUSTOMFORMAT      = 0x01;
87 const sal_uInt16 BIFF_ROW_DEFAULTHEIGHT     = 0x8000;
88 const sal_uInt16 BIFF_ROW_HEIGHTMASK        = 0x7FFF;
89 const sal_uInt32 BIFF_ROW_COLLAPSED         = 0x00000010;
90 const sal_uInt32 BIFF_ROW_HIDDEN            = 0x00000020;
91 const sal_uInt32 BIFF_ROW_CUSTOMHEIGHT      = 0x00000040;
92 const sal_uInt32 BIFF_ROW_CUSTOMFORMAT      = 0x00000080;
93 const sal_uInt32 BIFF_ROW_THICKTOP          = 0x10000000;
94 const sal_uInt32 BIFF_ROW_THICKBOTTOM       = 0x20000000;
95 const sal_uInt32 BIFF_ROW_SHOWPHONETIC      = 0x40000000;
96 
97 const sal_Int32 BIFF2_CELL_USEIXFE          = 63;
98 
99 } // namespace
100 
101 // ============================================================================
102 
SheetDataContextBase(const WorksheetHelper & rHelper)103 SheetDataContextBase::SheetDataContextBase( const WorksheetHelper& rHelper ) :
104     mrAddressConv( rHelper.getAddressConverter() ),
105     mrFormulaParser( rHelper.getFormulaParser() ),
106     mrSheetData( rHelper.getSheetData() ),
107     mnSheet( rHelper.getSheetIndex() )
108 {
109     maLastCellAddress.Sheet = rHelper.getSheetIndex();
110     maLastCellAddress.Row = SAL_MAX_UINT32; // wraps around to 0 when incremented
111 }
112 
~SheetDataContextBase()113 SheetDataContextBase::~SheetDataContextBase()
114 {
115 }
116 
117 // ============================================================================
118 
SheetDataContext(WorksheetFragmentBase & rFragment)119 SheetDataContext::SheetDataContext( WorksheetFragmentBase& rFragment ) :
120     WorksheetContextBase( rFragment ),
121     SheetDataContextBase( rFragment ),
122     mbHasFormula( false ),
123     mbValidRange( false )
124 {
125 }
126 
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)127 ContextHandlerRef SheetDataContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
128 {
129     switch( getCurrentElement() )
130     {
131         case XLS_TOKEN( sheetData ):
132             if( nElement == XLS_TOKEN( row ) ) { importRow( rAttribs ); return this; }
133         break;
134 
135         case XLS_TOKEN( row ):
136             // do not process cell elements with invalid (out-of-range) address
137             if( nElement == XLS_TOKEN( c ) && importCell( rAttribs ) )
138                 return this;
139         break;
140 
141         case XLS_TOKEN( c ):
142             switch( nElement )
143             {
144                 case XLS_TOKEN( is ):
145                     mxInlineStr.reset( new RichString( *this ) );
146                     return new RichStringContext( *this, mxInlineStr );
147                 case XLS_TOKEN( v ):
148                     return this;    // characters contain cell value
149                 case XLS_TOKEN( f ):
150                     importFormula( rAttribs );
151                     return this;    // characters contain formula string
152             }
153         break;
154     }
155     return 0;
156 }
157 
onCharacters(const OUString & rChars)158 void SheetDataContext::onCharacters( const OUString& rChars )
159 {
160     switch( getCurrentElement() )
161     {
162         case XLS_TOKEN( v ):
163             maCellValue = rChars;
164         break;
165         case XLS_TOKEN( f ):
166             if( maFmlaData.mnFormulaType != XML_TOKEN_INVALID )
167                 maTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, rChars );
168         break;
169     }
170 }
171 
onEndElement()172 void SheetDataContext::onEndElement()
173 {
174     if( getCurrentElement() == XLS_TOKEN( c ) )
175     {
176         // try to create a formula cell
177         if( mbHasFormula ) switch( maFmlaData.mnFormulaType )
178         {
179             case XML_normal:
180                 mrSheetData.setFormulaCell( maCellData, maTokens );
181             break;
182             case XML_shared:
183                 if( maFmlaData.mnSharedId >= 0 )
184                 {
185                     if( mbValidRange && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) )
186                         mrSheetData.createSharedFormula( maFmlaData.mnSharedId, maTokens );
187                     mrSheetData.setFormulaCell( maCellData, maFmlaData.mnSharedId );
188                 }
189                 else
190                     // no success, set plain cell value and formatting below
191                     mbHasFormula = false;
192             break;
193             case XML_array:
194                 if( mbValidRange && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) )
195                     mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, maTokens );
196                 // set cell formatting, but do not set result as cell value
197                 mrSheetData.setBlankCell( maCellData );
198             break;
199             case XML_dataTable:
200                 if( mbValidRange )
201                     mrSheetData.createTableOperation( maFmlaData.maFormulaRef, maTableData );
202                 // set cell formatting, but do not set result as cell value
203                 mrSheetData.setBlankCell( maCellData );
204             break;
205             default:
206                 OSL_ENSURE( maFmlaData.mnFormulaType == XML_TOKEN_INVALID, "SheetDataContext::onEndElement - unknown formula type" );
207                 mbHasFormula = false;
208         }
209 
210         if( !mbHasFormula )
211         {
212             // no formula created: try to set the cell value
213             if( maCellValue.getLength() > 0 ) switch( maCellData.mnCellType )
214             {
215                 case XML_n:
216                     mrSheetData.setValueCell( maCellData, maCellValue.toDouble() );
217                 break;
218                 case XML_d:
219                 {
220                     DateTime dateTime;
221                     if ( parseISO8601DateTime( maCellValue, dateTime ) )
222                         mrSheetData.setDateTimeCell( maCellData, dateTime );
223                     else
224                         mrSheetData.setErrorCell( maCellData, maCellValue );
225                 }
226                 break;
227                 case XML_b:
228                     mrSheetData.setBooleanCell( maCellData, maCellValue.toDouble() != 0.0 );
229                 break;
230                 case XML_e:
231                     mrSheetData.setErrorCell( maCellData, maCellValue );
232                 break;
233                 case XML_str:
234                     mrSheetData.setStringCell( maCellData, maCellValue );
235                 break;
236                 case XML_s:
237                     mrSheetData.setStringCell( maCellData, maCellValue.toInt32() );
238                 break;
239             }
240             else if( (maCellData.mnCellType == XML_inlineStr) && mxInlineStr.get() )
241             {
242                 mxInlineStr->finalizeImport();
243                 mrSheetData.setStringCell( maCellData, mxInlineStr );
244             }
245             else
246             {
247                 // empty cell, update cell type
248                 maCellData.mnCellType = XML_TOKEN_INVALID;
249                 mrSheetData.setBlankCell( maCellData );
250             }
251         }
252     }
253 }
254 
onCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)255 ContextHandlerRef SheetDataContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
256 {
257     switch( getCurrentElement() )
258     {
259         case BIFF12_ID_SHEETDATA:
260             if( nRecId == BIFF12_ID_ROW ) { importRow( rStrm ); return this; }
261         break;
262 
263         case BIFF12_ID_ROW:
264             switch( nRecId )
265             {
266                 case BIFF12_ID_ARRAY:           importArray( rStrm );                           break;
267                 case BIFF12_ID_CELL_BOOL:       importCellBool( rStrm, CELLTYPE_VALUE );        break;
268                 case BIFF12_ID_CELL_BLANK:      importCellBlank( rStrm, CELLTYPE_VALUE );       break;
269                 case BIFF12_ID_CELL_DOUBLE:     importCellDouble( rStrm, CELLTYPE_VALUE );      break;
270                 case BIFF12_ID_CELL_ERROR:      importCellError( rStrm, CELLTYPE_VALUE );       break;
271                 case BIFF12_ID_CELL_RK:         importCellRk( rStrm, CELLTYPE_VALUE );          break;
272                 case BIFF12_ID_CELL_RSTRING:    importCellRString( rStrm, CELLTYPE_VALUE );     break;
273                 case BIFF12_ID_CELL_SI:         importCellSi( rStrm, CELLTYPE_VALUE );          break;
274                 case BIFF12_ID_CELL_STRING:     importCellString( rStrm, CELLTYPE_VALUE );      break;
275                 case BIFF12_ID_DATATABLE:       importDataTable( rStrm );                       break;
276                 case BIFF12_ID_FORMULA_BOOL:    importCellBool( rStrm, CELLTYPE_FORMULA );      break;
277                 case BIFF12_ID_FORMULA_DOUBLE:  importCellDouble( rStrm, CELLTYPE_FORMULA );    break;
278                 case BIFF12_ID_FORMULA_ERROR:   importCellError( rStrm, CELLTYPE_FORMULA );     break;
279                 case BIFF12_ID_FORMULA_STRING:  importCellString( rStrm, CELLTYPE_FORMULA );    break;
280                 case BIFF12_ID_MULTCELL_BOOL:   importCellBool( rStrm, CELLTYPE_MULTI );        break;
281                 case BIFF12_ID_MULTCELL_BLANK:  importCellBlank( rStrm, CELLTYPE_MULTI );       break;
282                 case BIFF12_ID_MULTCELL_DOUBLE: importCellDouble( rStrm, CELLTYPE_MULTI );      break;
283                 case BIFF12_ID_MULTCELL_ERROR:  importCellError( rStrm, CELLTYPE_MULTI );       break;
284                 case BIFF12_ID_MULTCELL_RK:     importCellRk( rStrm, CELLTYPE_MULTI );          break;
285                 case BIFF12_ID_MULTCELL_RSTRING:importCellRString( rStrm, CELLTYPE_MULTI );     break;
286                 case BIFF12_ID_MULTCELL_SI:     importCellSi( rStrm, CELLTYPE_MULTI );          break;
287                 case BIFF12_ID_MULTCELL_STRING: importCellString( rStrm, CELLTYPE_MULTI );      break;
288                 case BIFF12_ID_SHAREDFMLA:      importSharedFmla( rStrm );                      break;
289             }
290         break;
291     }
292     return 0;
293 }
294 
295 // private --------------------------------------------------------------------
296 
importRow(const AttributeList & rAttribs)297 void SheetDataContext::importRow( const AttributeList& rAttribs )
298 {
299     RowModel aModel;
300     aModel.mnRow          = rAttribs.getInteger( XML_r, -1 );
301     if ( aModel.mnRow == -1 )
302         aModel.mnRow = ++maLastCellAddress.Row;
303     else
304         maLastCellAddress.Row = aModel.mnRow - 1;
305     maLastCellAddress.Column = SAL_MAX_UINT32; // wraps around to 0 when incremented
306     aModel.mfHeight       = rAttribs.getDouble( XML_ht, -1.0 );
307     aModel.mnXfId         = rAttribs.getInteger( XML_s, -1 );
308     aModel.mnLevel        = rAttribs.getInteger( XML_outlineLevel, 0 );
309     aModel.mbCustomHeight = rAttribs.getBool( XML_customHeight, false );
310     aModel.mbCustomFormat = rAttribs.getBool( XML_customFormat, false );
311     aModel.mbShowPhonetic = rAttribs.getBool( XML_ph, false );
312     aModel.mbHidden       = rAttribs.getBool( XML_hidden, false );
313     aModel.mbCollapsed    = rAttribs.getBool( XML_collapsed, false );
314     aModel.mbThickTop     = rAttribs.getBool( XML_thickTop, false );
315     aModel.mbThickBottom  = rAttribs.getBool( XML_thickBot, false );
316 
317     // decode the column spans (space-separated list of colon-separated integer pairs)
318     OUString aColSpansText = rAttribs.getString( XML_spans, OUString() );
319     sal_Int32 nMaxCol = mrAddressConv.getMaxApiAddress().Column;
320     sal_Int32 nIndex = 0;
321     while( nIndex >= 0 )
322     {
323         OUString aColSpanToken = aColSpansText.getToken( 0, ' ', nIndex );
324         sal_Int32 nSepPos = aColSpanToken.indexOf( ':' );
325         if( (0 < nSepPos) && (nSepPos + 1 < aColSpanToken.getLength()) )
326         {
327             // OOXML uses 1-based integer column indexes, row model expects 0-based colspans
328             sal_Int32 nLastCol = ::std::min( aColSpanToken.copy( nSepPos + 1 ).toInt32() - 1, nMaxCol );
329             aModel.insertColSpan( ValueRange( aColSpanToken.copy( 0, nSepPos ).toInt32() - 1, nLastCol ) );
330         }
331     }
332 
333     // set row properties in the current sheet
334     setRowModel( aModel );
335 }
336 
importCell(const AttributeList & rAttribs)337 bool SheetDataContext::importCell( const AttributeList& rAttribs )
338 {
339     OUString r = rAttribs.getString( XML_r, OUString() );
340     bool bValidAddr;
341     if ( r.getLength() > 0 )
342         bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, rAttribs.getString( XML_r, OUString() ), mnSheet, true );
343     else
344     {
345         maCellData.maCellAddr.Column = ++maLastCellAddress.Column;
346         maCellData.maCellAddr.Row = maLastCellAddress.Row;
347         maCellData.maCellAddr.Sheet = maLastCellAddress.Sheet;
348         bValidAddr = true;
349     }
350     if( bValidAddr )
351     {
352         maLastCellAddress.Column  = maCellData.maCellAddr.Column;
353         maLastCellAddress.Row     = maCellData.maCellAddr.Row;
354         maLastCellAddress.Sheet   = maCellData.maCellAddr.Sheet;
355         maCellData.mnCellType     = rAttribs.getToken( XML_t, XML_n );
356         maCellData.mnXfId         = rAttribs.getInteger( XML_s, -1 );
357         maCellData.mbShowPhonetic = rAttribs.getBool( XML_ph, false );
358 
359         // reset cell value, formula settings, and inline string
360         maCellValue = OUString();
361         mxInlineStr.reset();
362         mbHasFormula = false;
363 
364         // update used area of the sheet
365         extendUsedArea( maCellData.maCellAddr );
366     }
367     return bValidAddr;
368 }
369 
importFormula(const AttributeList & rAttribs)370 void SheetDataContext::importFormula( const AttributeList& rAttribs )
371 {
372     mbHasFormula = true;
373     mbValidRange = mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, rAttribs.getString( XML_ref, OUString() ), mnSheet, true, true );
374 
375     maFmlaData.mnFormulaType = rAttribs.getToken( XML_t, XML_normal );
376     maFmlaData.mnSharedId    = rAttribs.getInteger( XML_si, -1 );
377 
378     if( maFmlaData.mnFormulaType == XML_dataTable )
379     {
380         maTableData.maRef1        = rAttribs.getString( XML_r1, OUString() );
381         maTableData.maRef2        = rAttribs.getString( XML_r2, OUString() );
382         maTableData.mb2dTable     = rAttribs.getBool( XML_dt2D, false );
383         maTableData.mbRowTable    = rAttribs.getBool( XML_dtr, false );
384         maTableData.mbRef1Deleted = rAttribs.getBool( XML_del1, false );
385         maTableData.mbRef2Deleted = rAttribs.getBool( XML_del2, false );
386     }
387 
388     // clear token array, will be regenerated from element text
389     maTokens = ApiTokenSequence();
390 }
391 
importRow(SequenceInputStream & rStrm)392 void SheetDataContext::importRow( SequenceInputStream& rStrm )
393 {
394     RowModel aModel;
395     sal_Int32 nSpanCount;
396     sal_uInt16 nHeight, nFlags1;
397     sal_uInt8 nFlags2;
398     rStrm >> maCurrPos.mnRow >> aModel.mnXfId >> nHeight >> nFlags1 >> nFlags2 >> nSpanCount;
399     maCurrPos.mnCol = 0;
400 
401     // row index is 0-based in BIFF12, but RowModel expects 1-based
402     aModel.mnRow          = maCurrPos.mnRow + 1;
403     // row height is in twips in BIFF12, convert to points
404     aModel.mfHeight       = nHeight / 20.0;
405     aModel.mnLevel        = extractValue< sal_Int32 >( nFlags1, 8, 3 );
406     aModel.mbCustomHeight = getFlag( nFlags1, BIFF12_ROW_CUSTOMHEIGHT );
407     aModel.mbCustomFormat = getFlag( nFlags1, BIFF12_ROW_CUSTOMFORMAT );
408     aModel.mbShowPhonetic = getFlag( nFlags2, BIFF12_ROW_SHOWPHONETIC );
409     aModel.mbHidden       = getFlag( nFlags1, BIFF12_ROW_HIDDEN );
410     aModel.mbCollapsed    = getFlag( nFlags1, BIFF12_ROW_COLLAPSED );
411     aModel.mbThickTop     = getFlag( nFlags1, BIFF12_ROW_THICKTOP );
412     aModel.mbThickBottom  = getFlag( nFlags1, BIFF12_ROW_THICKBOTTOM );
413 
414     // read the column spans
415     sal_Int32 nMaxCol = mrAddressConv.getMaxApiAddress().Column;
416     for( sal_Int32 nSpanIdx = 0; (nSpanIdx < nSpanCount) && !rStrm.isEof(); ++nSpanIdx )
417     {
418         sal_Int32 nFirstCol, nLastCol;
419         rStrm >> nFirstCol >> nLastCol;
420         aModel.insertColSpan( ValueRange( nFirstCol, ::std::min( nLastCol, nMaxCol ) ) );
421     }
422 
423     // set row properties in the current sheet
424     setRowModel( aModel );
425 }
426 
readCellHeader(SequenceInputStream & rStrm,CellType eCellType)427 bool SheetDataContext::readCellHeader( SequenceInputStream& rStrm, CellType eCellType )
428 {
429     switch( eCellType )
430     {
431         case CELLTYPE_VALUE:
432         case CELLTYPE_FORMULA:  rStrm >> maCurrPos.mnCol;   break;
433         case CELLTYPE_MULTI:    ++maCurrPos.mnCol;          break;
434     }
435 
436     sal_uInt32 nXfId;
437     rStrm >> nXfId;
438 
439     bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, maCurrPos, mnSheet, true );
440     maCellData.mnXfId = extractValue< sal_Int32 >( nXfId, 0, 24 );
441     maCellData.mbShowPhonetic = getFlag( nXfId, BIFF12_CELL_SHOWPHONETIC );
442 
443     // update used area of the sheet
444     if( bValidAddr )
445         extendUsedArea( maCellData.maCellAddr );
446     return bValidAddr;
447 }
448 
readCellFormula(SequenceInputStream & rStrm)449 ApiTokenSequence SheetDataContext::readCellFormula( SequenceInputStream& rStrm )
450 {
451     rStrm.skip( 2 );
452     return mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm );
453 }
454 
readFormulaRef(SequenceInputStream & rStrm)455 bool SheetDataContext::readFormulaRef( SequenceInputStream& rStrm )
456 {
457     BinRange aRange;
458     rStrm >> aRange;
459     return mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, aRange, mnSheet, true, true );
460 }
461 
importCellBool(SequenceInputStream & rStrm,CellType eCellType)462 void SheetDataContext::importCellBool( SequenceInputStream& rStrm, CellType eCellType )
463 {
464     if( readCellHeader( rStrm, eCellType ) )
465     {
466         maCellData.mnCellType = XML_b;
467         bool bValue = rStrm.readuInt8() != 0;
468         if( eCellType == CELLTYPE_FORMULA )
469             mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) );
470         else
471             mrSheetData.setBooleanCell( maCellData, bValue );
472     }
473 }
474 
importCellBlank(SequenceInputStream & rStrm,CellType eCellType)475 void SheetDataContext::importCellBlank( SequenceInputStream& rStrm, CellType eCellType )
476 {
477     OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellBlank - no formula cells supported" );
478     if( readCellHeader( rStrm, eCellType ) )
479         mrSheetData.setBlankCell( maCellData );
480 }
481 
importCellDouble(SequenceInputStream & rStrm,CellType eCellType)482 void SheetDataContext::importCellDouble( SequenceInputStream& rStrm, CellType eCellType )
483 {
484     if( readCellHeader( rStrm, eCellType ) )
485     {
486         maCellData.mnCellType = XML_n;
487         double fValue = rStrm.readDouble();
488         if( eCellType == CELLTYPE_FORMULA )
489             mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) );
490         else
491             mrSheetData.setValueCell( maCellData, fValue );
492     }
493 }
494 
importCellError(SequenceInputStream & rStrm,CellType eCellType)495 void SheetDataContext::importCellError( SequenceInputStream& rStrm, CellType eCellType )
496 {
497     if( readCellHeader( rStrm, eCellType ) )
498     {
499         maCellData.mnCellType = XML_e;
500         sal_uInt8 nErrorCode = rStrm.readuInt8();
501         if( eCellType == CELLTYPE_FORMULA )
502             mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) );
503         else
504             mrSheetData.setErrorCell( maCellData, nErrorCode );
505     }
506 }
507 
importCellRk(SequenceInputStream & rStrm,CellType eCellType)508 void SheetDataContext::importCellRk( SequenceInputStream& rStrm, CellType eCellType )
509 {
510     OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellRk - no formula cells supported" );
511     if( readCellHeader( rStrm, eCellType ) )
512     {
513         maCellData.mnCellType = XML_n;
514         mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) );
515     }
516 }
517 
importCellRString(SequenceInputStream & rStrm,CellType eCellType)518 void SheetDataContext::importCellRString( SequenceInputStream& rStrm, CellType eCellType )
519 {
520     OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellRString - no formula cells supported" );
521     if( readCellHeader( rStrm, eCellType ) )
522     {
523         maCellData.mnCellType = XML_inlineStr;
524         RichStringRef xString( new RichString( *this ) );
525         xString->importString( rStrm, true );
526         xString->finalizeImport();
527         mrSheetData.setStringCell( maCellData, xString );
528     }
529 }
530 
importCellSi(SequenceInputStream & rStrm,CellType eCellType)531 void SheetDataContext::importCellSi( SequenceInputStream& rStrm, CellType eCellType )
532 {
533     OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellSi - no formula cells supported" );
534     if( readCellHeader( rStrm, eCellType ) )
535     {
536         maCellData.mnCellType = XML_s;
537         mrSheetData.setStringCell( maCellData, rStrm.readInt32() );
538     }
539 }
540 
importCellString(SequenceInputStream & rStrm,CellType eCellType)541 void SheetDataContext::importCellString( SequenceInputStream& rStrm, CellType eCellType )
542 {
543     if( readCellHeader( rStrm, eCellType ) )
544     {
545         maCellData.mnCellType = XML_inlineStr;
546         // always import the string, stream will point to formula afterwards, if existing
547         RichStringRef xString( new RichString( *this ) );
548         xString->importString( rStrm, false );
549         xString->finalizeImport();
550         if( eCellType == CELLTYPE_FORMULA )
551             mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) );
552         else
553             mrSheetData.setStringCell( maCellData, xString );
554     }
555 }
556 
importArray(SequenceInputStream & rStrm)557 void SheetDataContext::importArray( SequenceInputStream& rStrm )
558 {
559     if( readFormulaRef( rStrm ) && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) )
560     {
561         rStrm.skip( 1 );
562         ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_ARRAY, rStrm );
563         mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, aTokens );
564     }
565 }
566 
importDataTable(SequenceInputStream & rStrm)567 void SheetDataContext::importDataTable( SequenceInputStream& rStrm )
568 {
569     if( readFormulaRef( rStrm ) )
570     {
571         BinAddress aRef1, aRef2;
572         sal_uInt8 nFlags;
573         rStrm >> aRef1 >> aRef2 >> nFlags;
574         maTableData.maRef1        = FormulaProcessorBase::generateAddress2dString( aRef1, false );
575         maTableData.maRef2        = FormulaProcessorBase::generateAddress2dString( aRef2, false );
576         maTableData.mbRowTable    = getFlag( nFlags, BIFF12_DATATABLE_ROW );
577         maTableData.mb2dTable     = getFlag( nFlags, BIFF12_DATATABLE_2D );
578         maTableData.mbRef1Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF1DEL );
579         maTableData.mbRef2Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF2DEL );
580         mrSheetData.createTableOperation( maFmlaData.maFormulaRef, maTableData );
581     }
582 }
583 
importSharedFmla(SequenceInputStream & rStrm)584 void SheetDataContext::importSharedFmla( SequenceInputStream& rStrm )
585 {
586     if( readFormulaRef( rStrm ) && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) )
587     {
588         ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_SHAREDFORMULA, rStrm );
589         mrSheetData.createSharedFormula( maCellData.maCellAddr, aTokens );
590     }
591 }
592 
593 // ============================================================================
594 
BiffSheetDataContext(const WorksheetHelper & rHelper)595 BiffSheetDataContext::BiffSheetDataContext( const WorksheetHelper& rHelper ) :
596     BiffWorksheetContextBase( rHelper ),
597     SheetDataContextBase( rHelper ),
598     mnBiff2XfId( 0 )
599 {
600     switch( getBiff() )
601     {
602         case BIFF2:
603             mnFormulaSkipSize = 9;  // double formula result, 1 byte flags
604             mnArraySkipSize = 1;    // recalc-always flag
605         break;
606         case BIFF3:
607         case BIFF4:
608             mnFormulaSkipSize = 10; // double formula result, 2 byte flags
609             mnArraySkipSize = 2;    // 2 byte flags
610         break;
611         case BIFF5:
612         case BIFF8:
613             mnFormulaSkipSize = 14; // double formula result, 2 byte flags, 4 bytes nothing
614             mnArraySkipSize = 6;    // 2 byte flags, 4 bytes nothing
615         break;
616         case BIFF_UNKNOWN:
617         break;
618     }
619 }
620 
importRecord(BiffInputStream & rStrm)621 void BiffSheetDataContext::importRecord( BiffInputStream& rStrm )
622 {
623     sal_uInt16 nRecId = rStrm.getRecId();
624     switch( nRecId )
625     {
626         // records in all BIFF versions
627         case BIFF2_ID_ARRAY:        // #i72713#
628         case BIFF3_ID_ARRAY:        importArray( rStrm );   break;
629         case BIFF2_ID_BLANK:
630         case BIFF3_ID_BLANK:        importBlank( rStrm );   break;
631         case BIFF2_ID_BOOLERR:
632         case BIFF3_ID_BOOLERR:      importBoolErr( rStrm ); break;
633         case BIFF2_ID_INTEGER:      importInteger( rStrm ); break;
634         case BIFF_ID_IXFE:          rStrm >> mnBiff2XfId;   break;
635         case BIFF2_ID_LABEL:
636         case BIFF3_ID_LABEL:        importLabel( rStrm );   break;
637         case BIFF2_ID_NUMBER:
638         case BIFF3_ID_NUMBER:       importNumber( rStrm );  break;
639         case BIFF_ID_RK:            importRk( rStrm );      break;
640 
641         // BIFF specific records
642         default: switch( getBiff() )
643         {
644             case BIFF2: switch( nRecId )
645             {
646                 case BIFF2_ID_DATATABLE:    importDataTable( rStrm );   break;
647                 case BIFF2_ID_DATATABLE2:   importDataTable( rStrm );   break;
648                 case BIFF2_ID_FORMULA:      importFormula( rStrm );     break;
649                 case BIFF2_ID_ROW:          importRow( rStrm );         break;
650             }
651             break;
652 
653             case BIFF3: switch( nRecId )
654             {
655                 case BIFF3_ID_DATATABLE:    importDataTable( rStrm );   break;
656                 case BIFF3_ID_FORMULA:      importFormula( rStrm );     break;
657                 case BIFF3_ID_ROW:          importRow( rStrm );         break;
658             }
659             break;
660 
661             case BIFF4: switch( nRecId )
662             {
663                 case BIFF3_ID_DATATABLE:    importDataTable( rStrm );   break;
664                 case BIFF4_ID_FORMULA:      importFormula( rStrm );     break;
665                 case BIFF3_ID_ROW:          importRow( rStrm );         break;
666             }
667             break;
668 
669             case BIFF5: switch( nRecId )
670             {
671                 case BIFF3_ID_DATATABLE:    importDataTable( rStrm );   break;
672                 case BIFF3_ID_FORMULA:
673                 case BIFF4_ID_FORMULA:
674                 case BIFF5_ID_FORMULA:      importFormula( rStrm );     break;
675                 case BIFF_ID_MULTBLANK:     importMultBlank( rStrm );   break;
676                 case BIFF_ID_MULTRK:        importMultRk( rStrm );      break;
677                 case BIFF3_ID_ROW:          importRow( rStrm );         break;
678                 case BIFF_ID_RSTRING:       importLabel( rStrm );       break;
679                 case BIFF_ID_SHAREDFMLA:    importSharedFmla( rStrm );  break;
680             }
681             break;
682 
683             case BIFF8: switch( nRecId )
684             {
685                 case BIFF3_ID_DATATABLE:    importDataTable( rStrm );   break;
686                 case BIFF3_ID_FORMULA:
687                 case BIFF4_ID_FORMULA:
688                 case BIFF5_ID_FORMULA:      importFormula( rStrm );     break;
689                 case BIFF_ID_LABELSST:      importLabelSst( rStrm );    break;
690                 case BIFF_ID_MULTBLANK:     importMultBlank( rStrm );   break;
691                 case BIFF_ID_MULTRK:        importMultRk( rStrm );      break;
692                 case BIFF3_ID_ROW:          importRow( rStrm );         break;
693                 case BIFF_ID_RSTRING:       importLabel( rStrm );       break;
694                 case BIFF_ID_SHAREDFMLA:    importSharedFmla( rStrm );  break;
695             }
696             break;
697 
698             case BIFF_UNKNOWN:
699             break;
700         }
701     }
702 }
703 
704 // private --------------------------------------------------------------------
705 
importRow(BiffInputStream & rStrm)706 void BiffSheetDataContext::importRow( BiffInputStream& rStrm )
707 {
708     RowModel aModel;
709     sal_uInt16 nRow, nFirstUsedCol, nFirstFreeCol, nHeight;
710     rStrm >> nRow >> nFirstUsedCol >> nFirstFreeCol >> nHeight;
711     if( getBiff() == BIFF2 )
712     {
713         rStrm.skip( 2 );
714         aModel.mbCustomFormat = rStrm.readuInt8() == BIFF2_ROW_CUSTOMFORMAT;
715         if( aModel.mbCustomFormat )
716         {
717             rStrm.skip( 5 );
718             aModel.mnXfId = rStrm.readuInt16();
719         }
720     }
721     else
722     {
723         rStrm.skip( 4 );
724         sal_uInt32 nFlags = rStrm.readuInt32();
725         aModel.mnXfId         = extractValue< sal_Int32 >( nFlags, 16, 12 );
726         aModel.mnLevel        = extractValue< sal_Int32 >( nFlags, 0, 3 );
727         aModel.mbCustomFormat = getFlag( nFlags, BIFF_ROW_CUSTOMFORMAT );
728         aModel.mbCustomHeight = getFlag( nFlags, BIFF_ROW_CUSTOMHEIGHT );
729         aModel.mbShowPhonetic = getFlag( nFlags, BIFF_ROW_SHOWPHONETIC );
730         aModel.mbHidden       = getFlag( nFlags, BIFF_ROW_HIDDEN );
731         aModel.mbCollapsed    = getFlag( nFlags, BIFF_ROW_COLLAPSED );
732         aModel.mbThickTop     = getFlag( nFlags, BIFF_ROW_THICKTOP );
733         aModel.mbThickBottom  = getFlag( nFlags, BIFF_ROW_THICKBOTTOM );
734     }
735 
736     // row index is 0-based in BIFF, but RowModel expects 1-based
737     aModel.mnRow = static_cast< sal_Int32 >( nRow ) + 1;
738     // row height is in twips in BIFF, convert to points
739     aModel.mfHeight = (nHeight & BIFF_ROW_HEIGHTMASK) / 20.0;
740     // set column spans
741     if( nFirstUsedCol < nFirstFreeCol )
742     {
743         sal_Int32 nLastCol = ::std::min< sal_Int32 >( nFirstFreeCol - 1, mrAddressConv.getMaxApiAddress().Column );
744         aModel.insertColSpan( ValueRange( nFirstUsedCol, nLastCol ) );
745     }
746 
747     // set row properties in the current sheet
748     setRowModel( aModel );
749 }
750 
readCellXfId(BiffInputStream & rStrm,const BinAddress & rAddr,bool bBiff2)751 bool BiffSheetDataContext::readCellXfId( BiffInputStream& rStrm, const BinAddress& rAddr, bool bBiff2 )
752 {
753     bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, rAddr, mnSheet, true );
754     if( bValidAddr )
755     {
756         // update used area of the sheet
757         extendUsedArea( maCellData.maCellAddr );
758 
759         // load the XF identifier according to current BIFF version
760         if( bBiff2 )
761         {
762             /*  #i71453# On first call, check if the file contains XF records
763                 (by trying to access the first XF with index 0). If there are
764                 no XFs, the explicit formatting information contained in each
765                 cell record will be used instead. */
766             if( !mobBiff2HasXfs )
767                 mobBiff2HasXfs = getStyles().getCellXf( 0 ).get() != 0;
768             // read formatting information (includes the XF identifier)
769             sal_uInt8 nFlags1, nFlags2, nFlags3;
770             rStrm >> nFlags1 >> nFlags2 >> nFlags3;
771             /*  If the file contains XFs, extract and set the XF identifier,
772                 otherwise get the explicit formatting. */
773             if( mobBiff2HasXfs.get() )
774             {
775                 maCellData.mnXfId = extractValue< sal_Int32 >( nFlags1, 0, 6 );
776                 /*  If the identifier is equal to 63, then the real identifier
777                     is contained in the preceding IXFE record (stored in the
778                     class member mnBiff2XfId). */
779                 if( maCellData.mnXfId == BIFF2_CELL_USEIXFE )
780                     maCellData.mnXfId = mnBiff2XfId;
781             }
782             else
783             {
784                 /*  Let the Xf class do the API conversion. Keeping the member
785                     maCellData.mnXfId untouched will prevent to trigger the
786                     usual XF formatting conversion later on. */
787                 PropertySet aPropSet( getCell( maCellData.maCellAddr ) );
788                 Xf::writeBiff2CellFormatToPropertySet( *this, aPropSet, nFlags1, nFlags2, nFlags3 );
789             }
790         }
791         else
792         {
793             // BIFF3-BIFF8: 16-bit XF identifier
794             maCellData.mnXfId = rStrm.readuInt16();
795         }
796     }
797     return bValidAddr;
798 }
799 
readCellHeader(BiffInputStream & rStrm,bool bBiff2)800 bool BiffSheetDataContext::readCellHeader( BiffInputStream& rStrm, bool bBiff2 )
801 {
802     BinAddress aAddr;
803     rStrm >> aAddr;
804     return readCellXfId( rStrm, aAddr, bBiff2 );
805 }
806 
readFormulaRef(BiffInputStream & rStrm)807 bool BiffSheetDataContext::readFormulaRef( BiffInputStream& rStrm )
808 {
809     BinRange aRange;
810     aRange.read( rStrm, false );    // columns always 8-bit
811     return mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, aRange, mnSheet, true, true );
812 }
813 
importBlank(BiffInputStream & rStrm)814 void BiffSheetDataContext::importBlank( BiffInputStream& rStrm )
815 {
816     if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BLANK ) )
817         mrSheetData.setBlankCell( maCellData );
818 }
819 
importBoolErr(BiffInputStream & rStrm)820 void BiffSheetDataContext::importBoolErr( BiffInputStream& rStrm )
821 {
822     if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BOOLERR ) )
823     {
824         sal_uInt8 nValue, nType;
825         rStrm >> nValue >> nType;
826         switch( nType )
827         {
828             case BIFF_BOOLERR_BOOL:
829                 maCellData.mnCellType = XML_b;
830                 mrSheetData.setBooleanCell( maCellData, nValue != 0 );
831             break;
832             case BIFF_BOOLERR_ERROR:
833                 maCellData.mnCellType = XML_e;
834                 mrSheetData.setErrorCell( maCellData, nValue );
835             break;
836             default:
837                 OSL_ENSURE( false, "BiffSheetDataContext::importBoolErr - unknown cell type" );
838                 maCellData.mnCellType = XML_TOKEN_INVALID;
839                 mrSheetData.setBlankCell( maCellData );
840         }
841     }
842 }
843 
importFormula(BiffInputStream & rStrm)844 void BiffSheetDataContext::importFormula( BiffInputStream& rStrm )
845 {
846     if( readCellHeader( rStrm, getBiff() == BIFF2 ) )
847     {
848         maCellData.mnCellType = XML_n;
849         rStrm.skip( mnFormulaSkipSize );
850         ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm );
851         mrSheetData.setFormulaCell( maCellData, aTokens );
852     }
853 }
854 
importInteger(BiffInputStream & rStrm)855 void BiffSheetDataContext::importInteger( BiffInputStream& rStrm )
856 {
857     if( readCellHeader( rStrm, true ) )
858     {
859         maCellData.mnCellType = XML_n;
860         mrSheetData.setValueCell( maCellData, rStrm.readuInt16() );
861     }
862 }
863 
importLabel(BiffInputStream & rStrm)864 void BiffSheetDataContext::importLabel( BiffInputStream& rStrm )
865 {
866     /*  the deep secrets of BIFF type and record identifier...
867         record id   BIFF    ->  XF type     String type
868         0x0004      2-7     ->  3 byte      8-bit length, byte string
869         0x0004      8       ->  3 byte      16-bit length, unicode string
870         0x0204      2-7     ->  2 byte      16-bit length, byte string
871         0x0204      8       ->  2 byte      16-bit length, unicode string
872      */
873     bool bBiff2Xf = rStrm.getRecId() == BIFF2_ID_LABEL;
874     if( readCellHeader( rStrm, bBiff2Xf ) )
875     {
876         maCellData.mnCellType = XML_inlineStr;
877         if( getBiff() == BIFF8 )
878         {
879             // string may contain rich-text formatting
880             RichStringRef xString( new RichString( *this ) );
881             xString->importUniString( rStrm );
882             xString->finalizeImport();
883             mrSheetData.setStringCell( maCellData, xString );
884         }
885         else
886         {
887             // #i63105# use text encoding from FONT record
888             rtl_TextEncoding eTextEnc = getTextEncoding();
889             if( const Font* pFont = getStyles().getFontFromCellXf( maCellData.mnXfId ).get() )
890                 eTextEnc = pFont->getFontEncoding();
891             // RSTRING record contains rich-text formatting
892             if( rStrm.getRecId() == BIFF_ID_RSTRING )
893             {
894                 BiffStringFlags nFlags = BIFF_STR_EXTRAFONTS;
895                 // BIFF2 record identifier: 8-bit string length (see above)
896                 setFlag( nFlags, BIFF_STR_8BITLENGTH, bBiff2Xf );
897                 RichStringRef xString( new RichString( *this ) );
898                 xString->importByteString( rStrm, eTextEnc, nFlags );
899                 xString->finalizeImport();
900                 mrSheetData.setStringCell( maCellData, xString );
901             }
902             else
903             {
904                 // BIFF2 record identifier: 8-bit string length (see above)
905                 OUString aText = rStrm.readByteStringUC( !bBiff2Xf, eTextEnc );
906                 mrSheetData.setStringCell( maCellData, aText );
907             }
908         }
909     }
910 }
911 
importLabelSst(BiffInputStream & rStrm)912 void BiffSheetDataContext::importLabelSst( BiffInputStream& rStrm )
913 {
914     if( readCellHeader( rStrm, false ) )
915     {
916         maCellData.mnCellType = XML_s;
917         mrSheetData.setStringCell( maCellData, rStrm.readInt32() );
918     }
919 }
920 
importMultBlank(BiffInputStream & rStrm)921 void BiffSheetDataContext::importMultBlank( BiffInputStream& rStrm )
922 {
923     BinAddress aAddr;
924     bool bValidAddr = true;
925     for( rStrm >> aAddr; bValidAddr && (rStrm.getRemaining() > 2); ++aAddr.mnCol )
926         if( (bValidAddr = readCellXfId( rStrm, aAddr, false )) == true )
927             mrSheetData.setBlankCell( maCellData );
928 }
929 
importMultRk(BiffInputStream & rStrm)930 void BiffSheetDataContext::importMultRk( BiffInputStream& rStrm )
931 {
932     BinAddress aAddr;
933     bool bValidAddr = true;
934     for( rStrm >> aAddr; bValidAddr && (rStrm.getRemaining() > 2); ++aAddr.mnCol )
935     {
936         if( (bValidAddr = readCellXfId( rStrm, aAddr, false )) == true )
937         {
938             maCellData.mnCellType = XML_n;
939             sal_Int32 nRkValue = rStrm.readInt32();
940             mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( nRkValue ) );
941         }
942     }
943 }
944 
importNumber(BiffInputStream & rStrm)945 void BiffSheetDataContext::importNumber( BiffInputStream& rStrm )
946 {
947     if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_NUMBER ) )
948     {
949         maCellData.mnCellType = XML_n;
950         mrSheetData.setValueCell( maCellData, rStrm.readDouble() );
951     }
952 }
953 
importRk(BiffInputStream & rStrm)954 void BiffSheetDataContext::importRk( BiffInputStream& rStrm )
955 {
956     if( readCellHeader( rStrm, false ) )
957     {
958         maCellData.mnCellType = XML_n;
959         mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) );
960     }
961 }
962 
importArray(BiffInputStream & rStrm)963 void BiffSheetDataContext::importArray( BiffInputStream& rStrm )
964 {
965     if( readFormulaRef( rStrm ) && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) )
966     {
967         rStrm.skip( mnArraySkipSize );
968         ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_ARRAY, rStrm );
969         mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, aTokens );
970     }
971 }
972 
importDataTable(BiffInputStream & rStrm)973 void BiffSheetDataContext::importDataTable( BiffInputStream& rStrm )
974 {
975     if( readFormulaRef( rStrm ) )
976     {
977         DataTableModel aModel;
978         BinAddress aRef1, aRef2;
979         switch( rStrm.getRecId() )
980         {
981             case BIFF2_ID_DATATABLE:
982                 rStrm.skip( 1 );
983                 aModel.mbRowTable = rStrm.readuInt8() != 0;
984                 aModel.mb2dTable = false;
985                 rStrm >> aRef1;
986             break;
987             case BIFF2_ID_DATATABLE2:
988                 rStrm.skip( 2 );
989                 aModel.mb2dTable = true;
990                 rStrm >> aRef1 >> aRef2;
991             break;
992             case BIFF3_ID_DATATABLE:
993             {
994                 sal_uInt16 nFlags;
995                 rStrm >> nFlags >> aRef1 >> aRef2;
996                 aModel.mbRowTable = getFlag( nFlags, BIFF_DATATABLE_ROW );
997                 aModel.mb2dTable = getFlag( nFlags, BIFF_DATATABLE_2D );
998                 aModel.mbRef1Deleted = getFlag( nFlags, BIFF_DATATABLE_REF1DEL );
999                 aModel.mbRef2Deleted = getFlag( nFlags, BIFF_DATATABLE_REF2DEL );
1000             }
1001             break;
1002             default:
1003                 OSL_ENSURE( false, "BiffSheetDataContext::importDataTable - unknown record id" );
1004         }
1005         aModel.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false );
1006         aModel.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false );
1007         mrSheetData.createTableOperation( maFmlaData.maFormulaRef, aModel );
1008     }
1009 }
1010 
importSharedFmla(BiffInputStream & rStrm)1011 void BiffSheetDataContext::importSharedFmla( BiffInputStream& rStrm )
1012 {
1013     if( readFormulaRef( rStrm ) && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) )
1014     {
1015         rStrm.skip( 2 );    // flags
1016         ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_SHAREDFORMULA, rStrm );
1017         mrSheetData.createSharedFormula( maCellData.maCellAddr, aTokens );
1018     }
1019 }
1020 
1021 // ============================================================================
1022 
1023 } // namespace xls
1024 } // namespace oox
1025