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/helper/attributelist.hxx>
23 #include <oox/helper/binaryinputstream.hxx>
24 #include <oox/token/namespaces.hxx>
25 #include <oox/token/tokens.hxx>
26 #include <addressconverter.hxx>
27 #include <biffhelper.hxx>
28 #include <formulaparser.hxx>
29 #include <richstringcontext.hxx>
30 #include <sal/log.hxx>
34 using ::oox::core::ContextHandlerRef
;
38 // record constants -----------------------------------------------------------
40 const sal_uInt32 BIFF12_CELL_SHOWPHONETIC
= 0x01000000;
42 const sal_uInt8 BIFF12_DATATABLE_ROW
= 0x01;
43 const sal_uInt8 BIFF12_DATATABLE_2D
= 0x02;
44 const sal_uInt8 BIFF12_DATATABLE_REF1DEL
= 0x04;
45 const sal_uInt8 BIFF12_DATATABLE_REF2DEL
= 0x08;
47 const sal_uInt16 BIFF12_ROW_THICKTOP
= 0x0001;
48 const sal_uInt16 BIFF12_ROW_THICKBOTTOM
= 0x0002;
49 const sal_uInt16 BIFF12_ROW_COLLAPSED
= 0x0800;
50 const sal_uInt16 BIFF12_ROW_HIDDEN
= 0x1000;
51 const sal_uInt16 BIFF12_ROW_CUSTOMHEIGHT
= 0x2000;
52 const sal_uInt16 BIFF12_ROW_CUSTOMFORMAT
= 0x4000;
53 const sal_uInt8 BIFF12_ROW_SHOWPHONETIC
= 0x01;
57 SheetDataContext::SheetDataContext( WorksheetFragmentBase
& rFragment
) :
58 WorksheetContextBase( rFragment
),
59 mrAddressConv( rFragment
.getAddressConverter() ),
60 mrSheetData( rFragment
.getSheetData() ),
61 mnSheet( rFragment
.getSheetIndex() ),
62 mbHasFormula( false ),
63 mbValidRange( false ),
67 SAL_INFO( "sc.filter", "start safe sheet data context - unlock" );
68 mxFormulaParser
.reset(rFragment
.createFormulaParser());
71 SheetDataContext::~SheetDataContext()
73 SAL_INFO( "sc.filter", "end safe sheet data context - relock" );
76 ContextHandlerRef
SheetDataContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
78 switch( getCurrentElement() )
80 case XLS_TOKEN( sheetData
):
81 if( nElement
== XLS_TOKEN( row
) ) { importRow( rAttribs
); return this; }
84 case XLS_TOKEN( row
):
85 // do not process cell elements with invalid (out-of-range) address
86 if( nElement
== XLS_TOKEN( c
) && importCell( rAttribs
) )
94 mxInlineStr
= std::make_shared
<RichString
>( *this );
95 return new RichStringContext( *this, mxInlineStr
);
97 return this; // characters contain cell value
99 importFormula( rAttribs
);
100 return this; // characters contain formula string
107 void SheetDataContext::onCharacters( const OUString
& rChars
)
109 switch( getCurrentElement() )
112 maCellValue
= rChars
;
115 if( maFmlaData
.mnFormulaType
!= XML_TOKEN_INVALID
)
117 maFormulaStr
= rChars
;
123 void SheetDataContext::onEndElement()
125 if( getCurrentElement() != XLS_TOKEN( c
) )
128 // try to create a formula cell
129 if( mbHasFormula
) switch( maFmlaData
.mnFormulaType
)
131 // will buffer formulas but need to
132 // a) need to set format first
135 setCellFormula( maCellData
.maCellAddr
, maFormulaStr
);
136 mrSheetData
.setCellFormat( maCellData
);
138 // If a number cell has some preloaded value, stick it into the buffer
139 // but do this only for real cell formulas (not array, shared etc.)
140 if (!maCellValue
.isEmpty())
141 setCellFormulaValue(maCellData
.maCellAddr
, maCellValue
, maCellData
.mnCellType
);
145 if( maFmlaData
.mnSharedId
>= 0 )
147 if( mbValidRange
&& maFmlaData
.isValidSharedRef( maCellData
.maCellAddr
) )
148 createSharedFormulaMapEntry(maCellData
.maCellAddr
, maFmlaData
.mnSharedId
, maFormulaStr
);
150 setCellFormula(maCellData
.maCellAddr
, maFmlaData
.mnSharedId
, maCellValue
, maCellData
.mnCellType
);
151 mrSheetData
.setCellFormat( maCellData
);
154 // no success, set plain cell value and formatting below
155 mbHasFormula
= false;
158 if( mbValidRange
&& maFmlaData
.isValidArrayRef( maCellData
.maCellAddr
) )
160 setCellArrayFormula( maFmlaData
.maFormulaRef
, maCellData
.maCellAddr
, maFormulaStr
);
162 // set cell formatting, but do not set result as cell value
163 mrSheetData
.setBlankCell( maCellData
);
167 mrSheetData
.createTableOperation( maFmlaData
.maFormulaRef
, maTableData
);
168 // set cell formatting, but do not set result as cell value
169 mrSheetData
.setBlankCell( maCellData
);
172 OSL_ENSURE( maFmlaData
.mnFormulaType
== XML_TOKEN_INVALID
, "SheetDataContext::onEndElement - unknown formula type" );
173 mbHasFormula
= false;
179 // no formula created: try to set the cell value
180 if( !maCellValue
.isEmpty() ) switch( maCellData
.mnCellType
)
183 mrSheetData
.setValueCell( maCellData
, maCellValue
.toDouble() );
186 mrSheetData
.setBooleanCell( maCellData
, maCellValue
.toDouble() != 0.0 );
189 mrSheetData
.setErrorCell( maCellData
, maCellValue
);
192 mrSheetData
.setStringCell( maCellData
, maCellValue
);
195 mrSheetData
.setStringCell( maCellData
, maCellValue
.toInt32() );
198 mrSheetData
.setDateCell( maCellData
, maCellValue
);
201 else if( (maCellData
.mnCellType
== XML_inlineStr
) && mxInlineStr
)
203 mxInlineStr
->finalizeImport();
204 mrSheetData
.setStringCell( maCellData
, mxInlineStr
);
208 // empty cell, update cell type
209 maCellData
.mnCellType
= XML_TOKEN_INVALID
;
210 mrSheetData
.setBlankCell( maCellData
);
214 ContextHandlerRef
SheetDataContext::onCreateRecordContext( sal_Int32 nRecId
, SequenceInputStream
& rStrm
)
216 switch( getCurrentElement() )
218 case BIFF12_ID_SHEETDATA
:
219 if( nRecId
== BIFF12_ID_ROW
) { importRow( rStrm
); return this; }
225 case BIFF12_ID_ARRAY
: importArray( rStrm
); break;
226 case BIFF12_ID_CELL_BOOL
: importCellBool( rStrm
, CELLTYPE_VALUE
); break;
227 case BIFF12_ID_CELL_BLANK
: importCellBlank( rStrm
, CELLTYPE_VALUE
); break;
228 case BIFF12_ID_CELL_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_VALUE
); break;
229 case BIFF12_ID_CELL_ERROR
: importCellError( rStrm
, CELLTYPE_VALUE
); break;
230 case BIFF12_ID_CELL_RK
: importCellRk( rStrm
, CELLTYPE_VALUE
); break;
231 case BIFF12_ID_CELL_RSTRING
: importCellRString( rStrm
, CELLTYPE_VALUE
); break;
232 case BIFF12_ID_CELL_SI
: importCellSi( rStrm
, CELLTYPE_VALUE
); break;
233 case BIFF12_ID_CELL_STRING
: importCellString( rStrm
, CELLTYPE_VALUE
); break;
234 case BIFF12_ID_DATATABLE
: importDataTable( rStrm
); break;
235 case BIFF12_ID_FORMULA_BOOL
: importCellBool( rStrm
, CELLTYPE_FORMULA
); break;
236 case BIFF12_ID_FORMULA_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_FORMULA
); break;
237 case BIFF12_ID_FORMULA_ERROR
: importCellError( rStrm
, CELLTYPE_FORMULA
); break;
238 case BIFF12_ID_FORMULA_STRING
: importCellString( rStrm
, CELLTYPE_FORMULA
); break;
239 case BIFF12_ID_MULTCELL_BOOL
: importCellBool( rStrm
, CELLTYPE_MULTI
); break;
240 case BIFF12_ID_MULTCELL_BLANK
: importCellBlank( rStrm
, CELLTYPE_MULTI
); break;
241 case BIFF12_ID_MULTCELL_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_MULTI
); break;
242 case BIFF12_ID_MULTCELL_ERROR
: importCellError( rStrm
, CELLTYPE_MULTI
); break;
243 case BIFF12_ID_MULTCELL_RK
: importCellRk( rStrm
, CELLTYPE_MULTI
); break;
244 case BIFF12_ID_MULTCELL_RSTRING
:importCellRString( rStrm
, CELLTYPE_MULTI
); break;
245 case BIFF12_ID_MULTCELL_SI
: importCellSi( rStrm
, CELLTYPE_MULTI
); break;
246 case BIFF12_ID_MULTCELL_STRING
: importCellString( rStrm
, CELLTYPE_MULTI
); break;
247 case BIFF12_ID_SHAREDFMLA
: importSharedFmla( rStrm
); break;
254 // private --------------------------------------------------------------------
256 void SheetDataContext::importRow( const AttributeList
& rAttribs
)
259 sal_Int32 nRow
= rAttribs
.getInteger( XML_r
, -1 ); // 1-based row index
263 mnRow
= nRow
-1; // to 0-based row index.
266 aModel
.mnRow
= (++mnRow
+ 1); // increment 0-based row index, to 1-based model row
267 mrAddressConv
.checkRow( mnRow
, true);
270 aModel
.mfHeight
= rAttribs
.getDouble( XML_ht
, -1.0 );
271 aModel
.mnXfId
= rAttribs
.getInteger( XML_s
, -1 );
272 aModel
.mnLevel
= rAttribs
.getInteger( XML_outlineLevel
, 0 );
273 aModel
.mbCustomHeight
= rAttribs
.getBool( XML_customHeight
, false );
274 aModel
.mbCustomFormat
= rAttribs
.getBool( XML_customFormat
, false );
275 aModel
.mbShowPhonetic
= rAttribs
.getBool( XML_ph
, false );
276 aModel
.mbHidden
= rAttribs
.getBool( XML_hidden
, false );
277 aModel
.mbCollapsed
= rAttribs
.getBool( XML_collapsed
, false );
278 aModel
.mbThickTop
= rAttribs
.getBool( XML_thickTop
, false );
279 aModel
.mbThickBottom
= rAttribs
.getBool( XML_thickBot
, false );
281 // decode the column spans (space-separated list of colon-separated integer pairs)
282 OUString aColSpansText
= rAttribs
.getString( XML_spans
, OUString() );
283 sal_Int32 nMaxCol
= mrAddressConv
.getMaxApiAddress().Col();
284 sal_Int32 nIndex
= 0;
287 OUString aColSpanToken
= aColSpansText
.getToken( 0, ' ', nIndex
);
288 sal_Int32 nSepPos
= aColSpanToken
.indexOf( ':' );
289 if( (0 < nSepPos
) && (nSepPos
+ 1 < aColSpanToken
.getLength()) )
291 // OOXML uses 1-based integer column indexes, row model expects 0-based colspans
292 const sal_Int32 nCol1
= aColSpanToken
.copy( 0, nSepPos
).toInt32() - 1;
293 const bool bValid1
= mrAddressConv
.checkCol( nCol1
, true);
296 const sal_Int32 nCol2
= aColSpanToken
.copy( nSepPos
+ 1 ).toInt32() - 1;
297 mrAddressConv
.checkCol( nCol2
, true);
298 aModel
.insertColSpan( ValueRange( nCol1
, ::std::min( nCol2
, nMaxCol
)));
303 // set row properties in the current sheet
304 setRowModel( aModel
);
307 bool SheetDataContext::importCell( const AttributeList
& rAttribs
)
310 const char* p
= rAttribs
.getChar(XML_r
);
315 ScAddress
aAddress( mnCol
, mnRow
, mnSheet
);
316 bValid
= mrAddressConv
.checkCellAddress( aAddress
, true );
317 maCellData
.maCellAddr
= aAddress
;
321 bValid
= mrAddressConv
.convertToCellAddress(maCellData
.maCellAddr
, p
, mnSheet
, true);
322 mnCol
= maCellData
.maCellAddr
.Col();
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 );
331 // reset cell value, formula settings, and inline string
334 mbHasFormula
= false;
336 // update used area of the sheet
337 extendUsedArea( maCellData
.maCellAddr
);
342 void SheetDataContext::importFormula( const AttributeList
& rAttribs
)
345 mbValidRange
= mrAddressConv
.convertToCellRange( maFmlaData
.maFormulaRef
, rAttribs
.getString( XML_ref
, OUString() ), mnSheet
, true, true );
347 maFmlaData
.mnFormulaType
= rAttribs
.getToken( XML_t
, XML_normal
);
348 maFmlaData
.mnSharedId
= rAttribs
.getInteger( XML_si
, -1 );
350 if( maFmlaData
.mnFormulaType
== XML_dataTable
)
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 );
360 maFormulaStr
.clear();
363 void SheetDataContext::importRow( SequenceInputStream
& rStrm
)
366 sal_Int32 nSpanCount
;
367 sal_uInt16 nHeight
, nFlags1
;
369 maCurrPos
.mnRow
= rStrm
.readInt32();
370 aModel
.mnXfId
= rStrm
.readInt32();
371 nHeight
= rStrm
.readuInt16();
372 nFlags1
= rStrm
.readuInt16();
373 nFlags2
= rStrm
.readuChar();
374 nSpanCount
= rStrm
.readInt32();
377 mrAddressConv
.checkRow( maCurrPos
.mnRow
, true);
378 // row index is 0-based in BIFF12, but RowModel expects 1-based
379 aModel
.mnRow
= maCurrPos
.mnRow
+ 1;
380 // row height is in twips in BIFF12, convert to points
381 aModel
.mfHeight
= nHeight
/ 20.0;
382 aModel
.mnLevel
= extractValue
< sal_Int32
>( nFlags1
, 8, 3 );
383 aModel
.mbCustomHeight
= getFlag( nFlags1
, BIFF12_ROW_CUSTOMHEIGHT
);
384 aModel
.mbCustomFormat
= getFlag( nFlags1
, BIFF12_ROW_CUSTOMFORMAT
);
385 aModel
.mbShowPhonetic
= getFlag( nFlags2
, BIFF12_ROW_SHOWPHONETIC
);
386 aModel
.mbHidden
= getFlag( nFlags1
, BIFF12_ROW_HIDDEN
);
387 aModel
.mbCollapsed
= getFlag( nFlags1
, BIFF12_ROW_COLLAPSED
);
388 aModel
.mbThickTop
= getFlag( nFlags1
, BIFF12_ROW_THICKTOP
);
389 aModel
.mbThickBottom
= getFlag( nFlags1
, BIFF12_ROW_THICKBOTTOM
);
391 // read the column spans
392 sal_Int32 nMaxCol
= mrAddressConv
.getMaxApiAddress().Col();
393 for( sal_Int32 nSpanIdx
= 0; (nSpanIdx
< nSpanCount
) && !rStrm
.isEof(); ++nSpanIdx
)
395 sal_Int32 nFirstCol
, nLastCol
;
396 nFirstCol
= rStrm
.readInt32();
397 const bool bValid1
= mrAddressConv
.checkCol( nFirstCol
, true);
398 nLastCol
= rStrm
.readInt32();
399 mrAddressConv
.checkCol( nLastCol
, true);
401 aModel
.insertColSpan( ValueRange( nFirstCol
, ::std::min( nLastCol
, nMaxCol
) ) );
404 // set row properties in the current sheet
405 setRowModel( aModel
);
408 bool SheetDataContext::readCellHeader( SequenceInputStream
& rStrm
, CellType eCellType
)
413 case CELLTYPE_FORMULA
: maCurrPos
.mnCol
= rStrm
.readInt32(); break;
414 case CELLTYPE_MULTI
: ++maCurrPos
.mnCol
; break;
417 sal_uInt32 nXfId
= rStrm
.readuInt32();
419 bool bValidAddr
= mrAddressConv
.convertToCellAddress( maCellData
.maCellAddr
, maCurrPos
, mnSheet
, true );
420 maCellData
.mnXfId
= extractValue
< sal_Int32
>( nXfId
, 0, 24 );
421 maCellData
.mbShowPhonetic
= getFlag( nXfId
, BIFF12_CELL_SHOWPHONETIC
);
423 // update used area of the sheet
425 extendUsedArea( maCellData
.maCellAddr
);
429 ApiTokenSequence
SheetDataContext::readCellFormula( SequenceInputStream
& rStrm
)
432 return mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FormulaType::Cell
, rStrm
);
435 bool SheetDataContext::readFormulaRef( SequenceInputStream
& rStrm
)
439 return mrAddressConv
.convertToCellRange( maFmlaData
.maFormulaRef
, aRange
, mnSheet
, true, true );
442 void SheetDataContext::importCellBool( SequenceInputStream
& rStrm
, CellType eCellType
)
444 if( readCellHeader( rStrm
, eCellType
) )
446 maCellData
.mnCellType
= XML_b
;
447 bool bValue
= rStrm
.readuInt8() != 0;
448 if( eCellType
== CELLTYPE_FORMULA
)
449 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
451 mrSheetData
.setBooleanCell( maCellData
, bValue
);
455 void SheetDataContext::importCellBlank( SequenceInputStream
& rStrm
, CellType eCellType
)
457 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellBlank - no formula cells supported" );
458 if( readCellHeader( rStrm
, eCellType
) )
459 mrSheetData
.setBlankCell( maCellData
);
462 void SheetDataContext::importCellDouble( SequenceInputStream
& rStrm
, CellType eCellType
)
464 if( readCellHeader( rStrm
, eCellType
) )
466 maCellData
.mnCellType
= XML_n
;
467 double fValue
= rStrm
.readDouble();
468 if( eCellType
== CELLTYPE_FORMULA
)
469 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
471 mrSheetData
.setValueCell( maCellData
, fValue
);
475 void SheetDataContext::importCellError( SequenceInputStream
& rStrm
, CellType eCellType
)
477 if( readCellHeader( rStrm
, eCellType
) )
479 maCellData
.mnCellType
= XML_e
;
480 sal_uInt8 nErrorCode
= rStrm
.readuInt8();
481 if( eCellType
== CELLTYPE_FORMULA
)
482 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
484 mrSheetData
.setErrorCell( maCellData
, nErrorCode
);
488 void SheetDataContext::importCellRk( SequenceInputStream
& rStrm
, CellType eCellType
)
490 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellRk - no formula cells supported" );
491 if( readCellHeader( rStrm
, eCellType
) )
493 maCellData
.mnCellType
= XML_n
;
494 mrSheetData
.setValueCell( maCellData
, BiffHelper::calcDoubleFromRk( rStrm
.readInt32() ) );
498 void SheetDataContext::importCellRString( SequenceInputStream
& rStrm
, CellType eCellType
)
500 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellRString - no formula cells supported" );
501 if( readCellHeader( rStrm
, eCellType
) )
503 maCellData
.mnCellType
= XML_inlineStr
;
504 RichStringRef xString
= std::make_shared
<RichString
>( *this );
505 xString
->importString( rStrm
, true );
506 xString
->finalizeImport();
507 mrSheetData
.setStringCell( maCellData
, xString
);
511 void SheetDataContext::importCellSi( SequenceInputStream
& rStrm
, CellType eCellType
)
513 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellSi - no formula cells supported" );
514 if( readCellHeader( rStrm
, eCellType
) )
516 maCellData
.mnCellType
= XML_s
;
517 mrSheetData
.setStringCell( maCellData
, rStrm
.readInt32() );
521 void SheetDataContext::importCellString( SequenceInputStream
& rStrm
, CellType eCellType
)
523 if( readCellHeader( rStrm
, eCellType
) )
525 maCellData
.mnCellType
= XML_inlineStr
;
526 // always import the string, stream will point to formula afterwards, if existing
527 RichStringRef xString
= std::make_shared
<RichString
>( *this );
528 xString
->importString( rStrm
, false );
529 xString
->finalizeImport();
530 if( eCellType
== CELLTYPE_FORMULA
)
531 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
533 mrSheetData
.setStringCell( maCellData
, xString
);
537 void SheetDataContext::importArray( SequenceInputStream
& rStrm
)
539 if( readFormulaRef( rStrm
) && maFmlaData
.isValidArrayRef( maCellData
.maCellAddr
) )
542 ApiTokenSequence aTokens
= mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FormulaType::Array
, rStrm
);
543 mrSheetData
.createArrayFormula( maFmlaData
.maFormulaRef
, aTokens
);
547 void SheetDataContext::importDataTable( SequenceInputStream
& rStrm
)
549 if( !readFormulaRef( rStrm
) )
552 BinAddress aRef1
, aRef2
;
554 rStrm
>> aRef1
>> aRef2
;
555 nFlags
= rStrm
.readuChar();
556 maTableData
.maRef1
= FormulaProcessorBase::generateAddress2dString( aRef1
, false );
557 maTableData
.maRef2
= FormulaProcessorBase::generateAddress2dString( aRef2
, false );
558 maTableData
.mbRowTable
= getFlag( nFlags
, BIFF12_DATATABLE_ROW
);
559 maTableData
.mb2dTable
= getFlag( nFlags
, BIFF12_DATATABLE_2D
);
560 maTableData
.mbRef1Deleted
= getFlag( nFlags
, BIFF12_DATATABLE_REF1DEL
);
561 maTableData
.mbRef2Deleted
= getFlag( nFlags
, BIFF12_DATATABLE_REF2DEL
);
562 mrSheetData
.createTableOperation( maFmlaData
.maFormulaRef
, maTableData
);
565 void SheetDataContext::importSharedFmla( SequenceInputStream
& rStrm
)
567 if( readFormulaRef( rStrm
) && maFmlaData
.isValidSharedRef( maCellData
.maCellAddr
) )
569 ApiTokenSequence aTokens
= mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FormulaType::SharedFormula
, rStrm
);
570 mrSheetData
.createSharedFormula( maCellData
.maCellAddr
, aTokens
);
576 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */