1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sheetdatacontext.hxx>
22 #include <oox/core/xmlfilterbase.hxx>
23 #include <oox/helper/attributelist.hxx>
24 #include <oox/helper/binaryinputstream.hxx>
25 #include <oox/token/namespaces.hxx>
26 #include <oox/token/tokens.hxx>
27 #include <addressconverter.hxx>
28 #include <biffhelper.hxx>
29 #include <formulaparser.hxx>
30 #include <richstringcontext.hxx>
31 #include <sal/log.hxx>
32 #include <o3tl/string_view.hxx>
36 using ::oox::core::ContextHandlerRef
;
40 // record constants -----------------------------------------------------------
42 const sal_uInt32 BIFF12_CELL_SHOWPHONETIC
= 0x01000000;
44 const sal_uInt8 BIFF12_DATATABLE_ROW
= 0x01;
45 const sal_uInt8 BIFF12_DATATABLE_2D
= 0x02;
46 const sal_uInt8 BIFF12_DATATABLE_REF1DEL
= 0x04;
47 const sal_uInt8 BIFF12_DATATABLE_REF2DEL
= 0x08;
49 const sal_uInt16 BIFF12_ROW_THICKTOP
= 0x0001;
50 const sal_uInt16 BIFF12_ROW_THICKBOTTOM
= 0x0002;
51 const sal_uInt16 BIFF12_ROW_COLLAPSED
= 0x0800;
52 const sal_uInt16 BIFF12_ROW_HIDDEN
= 0x1000;
53 const sal_uInt16 BIFF12_ROW_CUSTOMHEIGHT
= 0x2000;
54 const sal_uInt16 BIFF12_ROW_CUSTOMFORMAT
= 0x4000;
55 const sal_uInt8 BIFF12_ROW_SHOWPHONETIC
= 0x01;
59 SheetDataContext::SheetDataContext( WorksheetFragmentBase
& rFragment
) :
60 WorksheetContextBase( rFragment
),
61 mrAddressConv( rFragment
.getAddressConverter() ),
62 mrSheetData( rFragment
.getSheetData() ),
63 mnSheet( rFragment
.getSheetIndex() ),
64 mbHasFormula( false ),
65 mbValidRange( false ),
69 SAL_INFO( "sc.filter", "start safe sheet data context - unlock" );
70 mxFormulaParser
.reset(rFragment
.createFormulaParser());
73 SheetDataContext::~SheetDataContext()
75 SAL_INFO( "sc.filter", "end safe sheet data context - relock" );
78 ContextHandlerRef
SheetDataContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
80 switch( getCurrentElement() )
82 case XLS_TOKEN( sheetData
):
83 if( nElement
== XLS_TOKEN( row
) ) { importRow( rAttribs
); return this; }
86 case XLS_TOKEN( row
):
87 // do not process cell elements with invalid (out-of-range) address
88 if( nElement
== XLS_TOKEN( c
) && importCell( rAttribs
) )
96 mxInlineStr
= std::make_shared
<RichString
>();
97 return new RichStringContext( *this, mxInlineStr
);
99 return this; // characters contain cell value
101 importFormula( rAttribs
);
102 return this; // characters contain formula string
109 void SheetDataContext::onCharacters( const OUString
& rChars
)
111 switch( getCurrentElement() )
114 maCellValue
= rChars
;
117 if( maFmlaData
.mnFormulaType
!= XML_TOKEN_INVALID
)
119 maFormulaStr
= rChars
;
125 void SheetDataContext::onEndElement()
127 if( getCurrentElement() != XLS_TOKEN( c
) )
130 // try to create a formula cell
131 if( mbHasFormula
) switch( maFmlaData
.mnFormulaType
)
133 // will buffer formulas but need to
134 // a) need to set format first
137 setCellFormula( maCellData
.maCellAddr
, maFormulaStr
);
138 mrSheetData
.setCellFormat( maCellData
);
140 // If a number cell has some preloaded value, stick it into the buffer
141 // but do this only for real cell formulas (not array, shared etc.)
142 if (!maCellValue
.isEmpty())
143 setCellFormulaValue(maCellData
.maCellAddr
, maCellValue
, maCellData
.mnCellType
);
147 if( maFmlaData
.mnSharedId
>= 0 )
149 if( mbValidRange
&& maFmlaData
.isValidSharedRef( maCellData
.maCellAddr
) )
150 createSharedFormulaMapEntry(maCellData
.maCellAddr
, maFmlaData
.mnSharedId
, maFormulaStr
);
152 setCellFormula(maCellData
.maCellAddr
, maFmlaData
.mnSharedId
, maCellValue
, maCellData
.mnCellType
);
153 mrSheetData
.setCellFormat( maCellData
);
156 // no success, set plain cell value and formatting below
157 mbHasFormula
= false;
160 if( mbValidRange
&& maFmlaData
.isValidArrayRef( maCellData
.maCellAddr
) )
162 setCellArrayFormula( maFmlaData
.maFormulaRef
, maCellData
.maCellAddr
, maFormulaStr
);
164 // set cell formatting, but do not set result as cell value
165 mrSheetData
.setBlankCell( maCellData
);
169 mrSheetData
.createTableOperation( maFmlaData
.maFormulaRef
, maTableData
);
170 // set cell formatting, but do not set result as cell value
171 mrSheetData
.setBlankCell( maCellData
);
174 OSL_ENSURE( maFmlaData
.mnFormulaType
== XML_TOKEN_INVALID
, "SheetDataContext::onEndElement - unknown formula type" );
175 mbHasFormula
= false;
181 // no formula created: try to set the cell value
182 if( !maCellValue
.isEmpty() ) switch( maCellData
.mnCellType
)
185 mrSheetData
.setValueCell( maCellData
, maCellValue
.toDouble() );
188 mrSheetData
.setBooleanCell( maCellData
, maCellValue
.toDouble() != 0.0 );
191 mrSheetData
.setErrorCell( maCellData
, maCellValue
);
194 mrSheetData
.setStringCell( maCellData
, maCellValue
);
197 mrSheetData
.setStringCell( maCellData
, maCellValue
.toInt32() );
200 mrSheetData
.setDateCell( maCellData
, maCellValue
);
203 else if( (maCellData
.mnCellType
== XML_inlineStr
) && mxInlineStr
)
205 mxInlineStr
->finalizeImport(*this);
206 mrSheetData
.setStringCell( maCellData
, mxInlineStr
);
210 // empty cell, update cell type
211 maCellData
.mnCellType
= XML_TOKEN_INVALID
;
212 mrSheetData
.setBlankCell( maCellData
);
216 ContextHandlerRef
SheetDataContext::onCreateRecordContext( sal_Int32 nRecId
, SequenceInputStream
& rStrm
)
218 switch( getCurrentElement() )
220 case BIFF12_ID_SHEETDATA
:
221 if( nRecId
== BIFF12_ID_ROW
) { importRow( rStrm
); return this; }
227 case BIFF12_ID_ARRAY
: importArray( rStrm
); break;
228 case BIFF12_ID_CELL_BOOL
: importCellBool( rStrm
, CELLTYPE_VALUE
); break;
229 case BIFF12_ID_CELL_BLANK
: importCellBlank( rStrm
, CELLTYPE_VALUE
); break;
230 case BIFF12_ID_CELL_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_VALUE
); break;
231 case BIFF12_ID_CELL_ERROR
: importCellError( rStrm
, CELLTYPE_VALUE
); break;
232 case BIFF12_ID_CELL_RK
: importCellRk( rStrm
, CELLTYPE_VALUE
); break;
233 case BIFF12_ID_CELL_RSTRING
: importCellRString( rStrm
, CELLTYPE_VALUE
); break;
234 case BIFF12_ID_CELL_SI
: importCellSi( rStrm
, CELLTYPE_VALUE
); break;
235 case BIFF12_ID_CELL_STRING
: importCellString( rStrm
, CELLTYPE_VALUE
); break;
236 case BIFF12_ID_DATATABLE
: importDataTable( rStrm
); break;
237 case BIFF12_ID_FORMULA_BOOL
: importCellBool( rStrm
, CELLTYPE_FORMULA
); break;
238 case BIFF12_ID_FORMULA_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_FORMULA
); break;
239 case BIFF12_ID_FORMULA_ERROR
: importCellError( rStrm
, CELLTYPE_FORMULA
); break;
240 case BIFF12_ID_FORMULA_STRING
: importCellString( rStrm
, CELLTYPE_FORMULA
); break;
241 case BIFF12_ID_MULTCELL_BOOL
: importCellBool( rStrm
, CELLTYPE_MULTI
); break;
242 case BIFF12_ID_MULTCELL_BLANK
: importCellBlank( rStrm
, CELLTYPE_MULTI
); break;
243 case BIFF12_ID_MULTCELL_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_MULTI
); break;
244 case BIFF12_ID_MULTCELL_ERROR
: importCellError( rStrm
, CELLTYPE_MULTI
); break;
245 case BIFF12_ID_MULTCELL_RK
: importCellRk( rStrm
, CELLTYPE_MULTI
); break;
246 case BIFF12_ID_MULTCELL_RSTRING
:importCellRString( rStrm
, CELLTYPE_MULTI
); break;
247 case BIFF12_ID_MULTCELL_SI
: importCellSi( rStrm
, CELLTYPE_MULTI
); break;
248 case BIFF12_ID_MULTCELL_STRING
: importCellString( rStrm
, CELLTYPE_MULTI
); break;
249 case BIFF12_ID_SHAREDFMLA
: importSharedFmla( rStrm
); break;
256 // private --------------------------------------------------------------------
258 void SheetDataContext::importRow( const AttributeList
& rAttribs
)
261 sal_Int32 nRow
= rAttribs
.getInteger( XML_r
, -1 ); // 1-based row index
265 mnRow
= nRow
-1; // to 0-based row index.
268 aModel
.mnRow
= (++mnRow
+ 1); // increment 0-based row index, to 1-based model row
269 mrAddressConv
.checkRow( mnRow
, true);
272 aModel
.mfHeight
= rAttribs
.getDouble( XML_ht
, -1.0 );
273 aModel
.mnXfId
= rAttribs
.getInteger( XML_s
, -1 );
274 aModel
.mnLevel
= rAttribs
.getInteger( XML_outlineLevel
, 0 );
275 aModel
.mbCustomHeight
= rAttribs
.getBool( XML_customHeight
, false );
276 aModel
.mbCustomFormat
= rAttribs
.getBool( XML_customFormat
, false );
277 aModel
.mbShowPhonetic
= rAttribs
.getBool( XML_ph
, false );
278 aModel
.mbHidden
= rAttribs
.getBool( XML_hidden
, false );
279 aModel
.mbCollapsed
= rAttribs
.getBool( XML_collapsed
, false );
280 aModel
.mbThickTop
= rAttribs
.getBool( XML_thickTop
, false );
281 aModel
.mbThickBottom
= rAttribs
.getBool( XML_thickBot
, false );
283 if (aModel
.mfHeight
> 0 && getFilter().isMSODocument())
285 aModel
.mfHeight
-= fmod(aModel
.mfHeight
, 0.75); //round down to 0.75pt
288 // decode the column spans (space-separated list of colon-separated integer pairs)
289 OUString aColSpansText
= rAttribs
.getString( XML_spans
, OUString() );
290 sal_Int32 nIndex
= 0;
293 std::u16string_view aColSpanToken
= o3tl::getToken(aColSpansText
, 0, ' ', nIndex
);
294 size_t nSepPos
= aColSpanToken
.find( ':' );
295 if( (0 < nSepPos
) && (nSepPos
+ 1 < aColSpanToken
.size()) )
297 // OOXML uses 1-based integer column indexes, row model expects 0-based colspans
298 const sal_Int32 nCol1
= o3tl::toInt32(aColSpanToken
.substr( 0, nSepPos
)) - 1;
299 const bool bValid1
= mrAddressConv
.checkCol( nCol1
, true);
302 const sal_Int32 nCol2
= o3tl::toInt32(aColSpanToken
.substr( nSepPos
+ 1 )) - 1;
303 mrAddressConv
.checkCol( nCol2
, true);
308 // set row properties in the current sheet
309 setRowModel( aModel
);
312 bool SheetDataContext::importCell( const AttributeList
& rAttribs
)
315 std::string_view p
= rAttribs
.getView(XML_r
);
320 ScAddress
aAddress( mnCol
, mnRow
, mnSheet
);
321 bValid
= mrAddressConv
.checkCellAddress( aAddress
, true );
322 maCellData
.maCellAddr
= aAddress
;
326 bValid
= mrAddressConv
.convertToCellAddress(maCellData
.maCellAddr
, p
, mnSheet
, true);
327 mnCol
= maCellData
.maCellAddr
.Col();
332 maCellData
.mnCellType
= rAttribs
.getToken( XML_t
, XML_n
);
333 maCellData
.mnXfId
= rAttribs
.getInteger( XML_s
, -1 );
334 maCellData
.mbShowPhonetic
= rAttribs
.getBool( XML_ph
, false );
336 // reset cell value, formula settings, and inline string
339 mbHasFormula
= false;
341 // update used area of the sheet
342 extendUsedArea( maCellData
.maCellAddr
);
347 void SheetDataContext::importFormula( const AttributeList
& rAttribs
)
350 mbValidRange
= mrAddressConv
.convertToCellRange( maFmlaData
.maFormulaRef
, rAttribs
.getString( XML_ref
, OUString() ), mnSheet
, true, true );
352 maFmlaData
.mnFormulaType
= rAttribs
.getToken( XML_t
, XML_normal
);
353 maFmlaData
.mnSharedId
= rAttribs
.getInteger( XML_si
, -1 );
355 if( maFmlaData
.mnFormulaType
== XML_dataTable
)
357 maTableData
.maRef1
= rAttribs
.getString( XML_r1
, OUString() );
358 maTableData
.maRef2
= rAttribs
.getString( XML_r2
, OUString() );
359 maTableData
.mb2dTable
= rAttribs
.getBool( XML_dt2D
, false );
360 maTableData
.mbRowTable
= rAttribs
.getBool( XML_dtr
, false );
361 maTableData
.mbRef1Deleted
= rAttribs
.getBool( XML_del1
, false );
362 maTableData
.mbRef2Deleted
= rAttribs
.getBool( XML_del2
, false );
365 maFormulaStr
.clear();
368 void SheetDataContext::importRow( SequenceInputStream
& rStrm
)
371 sal_Int32 nSpanCount
;
372 sal_uInt16 nHeight
, nFlags1
;
374 maCurrPos
.mnRow
= rStrm
.readInt32();
375 aModel
.mnXfId
= rStrm
.readInt32();
376 nHeight
= rStrm
.readuInt16();
377 nFlags1
= rStrm
.readuInt16();
378 nFlags2
= rStrm
.readuChar();
379 nSpanCount
= rStrm
.readInt32();
382 mrAddressConv
.checkRow( maCurrPos
.mnRow
, true);
383 // row index is 0-based in BIFF12, but RowModel expects 1-based
384 aModel
.mnRow
= maCurrPos
.mnRow
+ 1;
385 // row height is in twips in BIFF12, convert to points
386 aModel
.mfHeight
= nHeight
/ 20.0;
387 aModel
.mnLevel
= extractValue
< sal_Int32
>( nFlags1
, 8, 3 );
388 aModel
.mbCustomHeight
= getFlag( nFlags1
, BIFF12_ROW_CUSTOMHEIGHT
);
389 aModel
.mbCustomFormat
= getFlag( nFlags1
, BIFF12_ROW_CUSTOMFORMAT
);
390 aModel
.mbShowPhonetic
= getFlag( nFlags2
, BIFF12_ROW_SHOWPHONETIC
);
391 aModel
.mbHidden
= getFlag( nFlags1
, BIFF12_ROW_HIDDEN
);
392 aModel
.mbCollapsed
= getFlag( nFlags1
, BIFF12_ROW_COLLAPSED
);
393 aModel
.mbThickTop
= getFlag( nFlags1
, BIFF12_ROW_THICKTOP
);
394 aModel
.mbThickBottom
= getFlag( nFlags1
, BIFF12_ROW_THICKBOTTOM
);
396 // read the column spans
397 for( sal_Int32 nSpanIdx
= 0; (nSpanIdx
< nSpanCount
) && !rStrm
.isEof(); ++nSpanIdx
)
399 sal_Int32 nFirstCol
, nLastCol
;
400 nFirstCol
= rStrm
.readInt32();
401 mrAddressConv
.checkCol( nFirstCol
, true);
402 nLastCol
= rStrm
.readInt32();
403 mrAddressConv
.checkCol( nLastCol
, true);
406 // set row properties in the current sheet
407 setRowModel( aModel
);
410 bool SheetDataContext::readCellHeader( SequenceInputStream
& rStrm
, CellType eCellType
)
415 case CELLTYPE_FORMULA
: maCurrPos
.mnCol
= rStrm
.readInt32(); break;
416 case CELLTYPE_MULTI
: ++maCurrPos
.mnCol
; break;
419 sal_uInt32 nXfId
= rStrm
.readuInt32();
421 bool bValidAddr
= mrAddressConv
.convertToCellAddress( maCellData
.maCellAddr
, maCurrPos
, mnSheet
, true );
422 maCellData
.mnXfId
= extractValue
< sal_Int32
>( nXfId
, 0, 24 );
423 maCellData
.mbShowPhonetic
= getFlag( nXfId
, BIFF12_CELL_SHOWPHONETIC
);
425 // update used area of the sheet
427 extendUsedArea( maCellData
.maCellAddr
);
431 ApiTokenSequence
SheetDataContext::readCellFormula( SequenceInputStream
& rStrm
)
434 return mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FormulaType::Cell
, rStrm
);
437 bool SheetDataContext::readFormulaRef( SequenceInputStream
& rStrm
)
441 return mrAddressConv
.convertToCellRange( maFmlaData
.maFormulaRef
, aRange
, mnSheet
, true, true );
444 void SheetDataContext::importCellBool( SequenceInputStream
& rStrm
, CellType eCellType
)
446 if( readCellHeader( rStrm
, eCellType
) )
448 maCellData
.mnCellType
= XML_b
;
449 bool bValue
= rStrm
.readuInt8() != 0;
450 if( eCellType
== CELLTYPE_FORMULA
)
451 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
453 mrSheetData
.setBooleanCell( maCellData
, bValue
);
457 void SheetDataContext::importCellBlank( SequenceInputStream
& rStrm
, CellType eCellType
)
459 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellBlank - no formula cells supported" );
460 if( readCellHeader( rStrm
, eCellType
) )
461 mrSheetData
.setBlankCell( maCellData
);
464 void SheetDataContext::importCellDouble( SequenceInputStream
& rStrm
, CellType eCellType
)
466 if( readCellHeader( rStrm
, eCellType
) )
468 maCellData
.mnCellType
= XML_n
;
469 double fValue
= rStrm
.readDouble();
470 if( eCellType
== CELLTYPE_FORMULA
)
471 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
473 mrSheetData
.setValueCell( maCellData
, fValue
);
477 void SheetDataContext::importCellError( SequenceInputStream
& rStrm
, CellType eCellType
)
479 if( readCellHeader( rStrm
, eCellType
) )
481 maCellData
.mnCellType
= XML_e
;
482 sal_uInt8 nErrorCode
= rStrm
.readuInt8();
483 if( eCellType
== CELLTYPE_FORMULA
)
484 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
486 mrSheetData
.setErrorCell( maCellData
, nErrorCode
);
490 void SheetDataContext::importCellRk( SequenceInputStream
& rStrm
, CellType eCellType
)
492 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellRk - no formula cells supported" );
493 if( readCellHeader( rStrm
, eCellType
) )
495 maCellData
.mnCellType
= XML_n
;
496 mrSheetData
.setValueCell( maCellData
, BiffHelper::calcDoubleFromRk( rStrm
.readInt32() ) );
500 void SheetDataContext::importCellRString( SequenceInputStream
& rStrm
, CellType eCellType
)
502 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellRString - no formula cells supported" );
503 if( readCellHeader( rStrm
, eCellType
) )
505 maCellData
.mnCellType
= XML_inlineStr
;
506 RichStringRef xString
= std::make_shared
<RichString
>();
507 xString
->importString( rStrm
, true, *this );
508 xString
->finalizeImport( *this );
509 mrSheetData
.setStringCell( maCellData
, xString
);
513 void SheetDataContext::importCellSi( SequenceInputStream
& rStrm
, CellType eCellType
)
515 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellSi - no formula cells supported" );
516 if( readCellHeader( rStrm
, eCellType
) )
518 maCellData
.mnCellType
= XML_s
;
519 mrSheetData
.setStringCell( maCellData
, rStrm
.readInt32() );
523 void SheetDataContext::importCellString( SequenceInputStream
& rStrm
, CellType eCellType
)
525 if( readCellHeader( rStrm
, eCellType
) )
527 maCellData
.mnCellType
= XML_inlineStr
;
528 // always import the string, stream will point to formula afterwards, if existing
529 RichStringRef xString
= std::make_shared
<RichString
>();
530 xString
->importString( rStrm
, false, *this );
531 xString
->finalizeImport( *this );
532 if( eCellType
== CELLTYPE_FORMULA
)
533 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
535 mrSheetData
.setStringCell( maCellData
, xString
);
539 void SheetDataContext::importArray( SequenceInputStream
& rStrm
)
541 if( readFormulaRef( rStrm
) && maFmlaData
.isValidArrayRef( maCellData
.maCellAddr
) )
544 ApiTokenSequence aTokens
= mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FormulaType::Array
, rStrm
);
545 mrSheetData
.createArrayFormula( maFmlaData
.maFormulaRef
, aTokens
);
549 void SheetDataContext::importDataTable( SequenceInputStream
& rStrm
)
551 if( !readFormulaRef( rStrm
) )
554 BinAddress aRef1
, aRef2
;
556 rStrm
>> aRef1
>> aRef2
;
557 nFlags
= rStrm
.readuChar();
558 maTableData
.maRef1
= FormulaProcessorBase::generateAddress2dString( aRef1
, false );
559 maTableData
.maRef2
= FormulaProcessorBase::generateAddress2dString( aRef2
, false );
560 maTableData
.mbRowTable
= getFlag( nFlags
, BIFF12_DATATABLE_ROW
);
561 maTableData
.mb2dTable
= getFlag( nFlags
, BIFF12_DATATABLE_2D
);
562 maTableData
.mbRef1Deleted
= getFlag( nFlags
, BIFF12_DATATABLE_REF1DEL
);
563 maTableData
.mbRef2Deleted
= getFlag( nFlags
, BIFF12_DATATABLE_REF2DEL
);
564 mrSheetData
.createTableOperation( maFmlaData
.maFormulaRef
, maTableData
);
567 void SheetDataContext::importSharedFmla( SequenceInputStream
& rStrm
)
569 if( readFormulaRef( rStrm
) && maFmlaData
.isValidSharedRef( maCellData
.maCellAddr
) )
571 ApiTokenSequence aTokens
= mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FormulaType::SharedFormula
, rStrm
);
572 mrSheetData
.createSharedFormula( maCellData
.maCellAddr
, aTokens
);
578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */