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