Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "tokenuno.hxx"
21 :
22 : #include <sal/macros.h>
23 :
24 : #include <com/sun/star/sheet/ComplexReference.hpp>
25 : #include <com/sun/star/sheet/ExternalReference.hpp>
26 : #include <com/sun/star/sheet/ReferenceFlags.hpp>
27 : #include <com/sun/star/sheet/AddressConvention.hpp>
28 : #include <com/sun/star/sheet/NameToken.hpp>
29 : #include <com/sun/star/table/CellAddress.hpp>
30 :
31 : #include <svl/itemprop.hxx>
32 : #include <vcl/svapp.hxx>
33 :
34 : #include "miscuno.hxx"
35 : #include "convuno.hxx"
36 : #include "unonames.hxx"
37 : #include "token.hxx"
38 : #include "compiler.hxx"
39 : #include "tokenarray.hxx"
40 : #include "docsh.hxx"
41 : #include "rangeseq.hxx"
42 : #include "externalrefmgr.hxx"
43 :
44 : using namespace ::formula;
45 : using namespace ::com::sun::star;
46 :
47 5 : static const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap()
48 : {
49 : static const SfxItemPropertyMapEntry aFormulaParserMap_Impl[] =
50 : {
51 5 : {OUString(SC_UNO_COMPILEFAP), 0, cppu::UnoType<bool>::get(), 0, 0 },
52 5 : {OUString(SC_UNO_COMPILEENGLISH), 0, cppu::UnoType<bool>::get(), 0, 0 },
53 5 : {OUString(SC_UNO_IGNORELEADING), 0, cppu::UnoType<bool>::get(), 0, 0 },
54 5 : {OUString(SC_UNO_FORMULACONVENTION), 0, cppu::UnoType<decltype(sheet::AddressConvention::UNSPECIFIED)>::get(), 0, 0 },
55 5 : {OUString(SC_UNO_OPCODEMAP), 0, cppu::UnoType<uno::Sequence< sheet::FormulaOpCodeMapEntry >>::get(), 0, 0 },
56 : { OUString(), 0, css::uno::Type(), 0, 0 }
57 35 : };
58 5 : return aFormulaParserMap_Impl;
59 : }
60 :
61 0 : SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS )
62 :
63 506 : ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
64 : mpDocShell( pDocSh ),
65 : mnConv( sheet::AddressConvention::UNSPECIFIED ),
66 : mbEnglish( false ),
67 : mbIgnoreSpaces( true ),
68 506 : mbCompileFAP( false )
69 : {
70 506 : mpDocShell->GetDocument().AddUnoObject(*this);
71 506 : }
72 :
73 1518 : ScFormulaParserObj::~ScFormulaParserObj()
74 : {
75 506 : SolarMutexGuard g;
76 :
77 506 : if (mpDocShell)
78 506 : mpDocShell->GetDocument().RemoveUnoObject(*this);
79 1012 : }
80 :
81 11857 : void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
82 : {
83 11857 : const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
84 11857 : if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DYING )
85 0 : mpDocShell = NULL;
86 11857 : }
87 :
88 : // XFormulaParser
89 :
90 453 : void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const
91 : {
92 : static const formula::FormulaGrammar::AddressConvention aConvMap[] = {
93 : formula::FormulaGrammar::CONV_OOO, // <- AddressConvention::OOO
94 : formula::FormulaGrammar::CONV_XL_A1, // <- AddressConvention::XL_A1
95 : formula::FormulaGrammar::CONV_XL_R1C1, // <- AddressConvention::XL_R1C1
96 : formula::FormulaGrammar::CONV_XL_OOX, // <- AddressConvention::XL_OOX
97 : formula::FormulaGrammar::CONV_LOTUS_A1 // <- AddressConvention::LOTUS_A1
98 : };
99 : static const sal_Int16 nConvMapCount = sizeof(aConvMap)/sizeof(aConvMap[0]);
100 :
101 : // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
102 : // don't need to initialize things twice.
103 453 : if (mxOpCodeMap.get())
104 272 : rCompiler.SetFormulaLanguage( mxOpCodeMap );
105 : else
106 : {
107 : sal_Int32 nFormulaLanguage = mbEnglish ?
108 : sheet::FormulaLanguage::ENGLISH :
109 181 : sheet::FormulaLanguage::NATIVE;
110 181 : ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage);
111 181 : rCompiler.SetFormulaLanguage( xMap);
112 : }
113 :
114 453 : formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
115 453 : if (mnConv >= 0 && mnConv < nConvMapCount)
116 452 : eConv = aConvMap[mnConv];
117 :
118 453 : rCompiler.SetRefConvention( eConv );
119 453 : rCompiler.EnableJumpCommandReorder(!mbCompileFAP);
120 453 : rCompiler.EnableStopOnError(!mbCompileFAP);
121 :
122 453 : rCompiler.SetExternalLinks( maExternalLinks);
123 453 : }
124 :
125 363 : uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula(
126 : const OUString& aFormula, const table::CellAddress& rReferencePos )
127 : throw (uno::RuntimeException, std::exception)
128 : {
129 363 : SolarMutexGuard aGuard;
130 363 : uno::Sequence<sheet::FormulaToken> aRet;
131 :
132 363 : if (mpDocShell)
133 : {
134 363 : ScDocument& rDoc = mpDocShell->GetDocument();
135 363 : ScExternalRefManager::ApiGuard aExtRefGuard(&rDoc);
136 :
137 363 : ScAddress aRefPos( ScAddress::UNINITIALIZED );
138 363 : ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
139 726 : ScCompiler aCompiler( &rDoc, aRefPos);
140 363 : aCompiler.SetGrammar(rDoc.GetGrammar());
141 363 : SetCompilerFlags( aCompiler );
142 :
143 363 : ScTokenArray* pCode = aCompiler.CompileString( aFormula );
144 363 : (void)ScTokenConversion::ConvertToTokenSequence( rDoc, aRet, *pCode );
145 726 : delete pCode;
146 : }
147 :
148 363 : return aRet;
149 : }
150 :
151 90 : OUString SAL_CALL ScFormulaParserObj::printFormula(
152 : const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
153 : throw (uno::RuntimeException, std::exception)
154 : {
155 90 : SolarMutexGuard aGuard;
156 90 : OUString aRet;
157 :
158 90 : if (mpDocShell)
159 : {
160 90 : ScDocument& rDoc = mpDocShell->GetDocument();
161 90 : ScTokenArray aCode;
162 90 : (void)ScTokenConversion::ConvertToTokenArray( rDoc, aCode, aTokens );
163 90 : ScAddress aRefPos( ScAddress::UNINITIALIZED );
164 90 : ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
165 180 : ScCompiler aCompiler( &rDoc, aRefPos, aCode);
166 90 : aCompiler.SetGrammar(rDoc.GetGrammar());
167 90 : SetCompilerFlags( aCompiler );
168 :
169 180 : OUStringBuffer aBuffer;
170 90 : aCompiler.CreateStringFromTokenArray( aBuffer );
171 180 : aRet = aBuffer.makeStringAndClear();
172 : }
173 :
174 90 : return aRet;
175 : }
176 :
177 : // XPropertySet
178 :
179 414 : uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
180 : throw(uno::RuntimeException, std::exception)
181 : {
182 414 : SolarMutexGuard aGuard;
183 414 : static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
184 414 : return aRef;
185 : }
186 :
187 1908 : void SAL_CALL ScFormulaParserObj::setPropertyValue(
188 : const OUString& aPropertyName, const uno::Any& aValue )
189 : throw(beans::UnknownPropertyException, beans::PropertyVetoException,
190 : lang::IllegalArgumentException, lang::WrappedTargetException,
191 : uno::RuntimeException, std::exception)
192 : {
193 1908 : SolarMutexGuard aGuard;
194 3816 : OUString aString(aPropertyName);
195 1908 : if ( aString == SC_UNO_COMPILEFAP )
196 : {
197 0 : aValue >>= mbCompileFAP;
198 : }
199 1908 : else if ( aString == SC_UNO_COMPILEENGLISH )
200 : {
201 414 : bool bOldEnglish = mbEnglish;
202 414 : if (aValue >>= mbEnglish)
203 : {
204 : // Need to recreate the symbol map to change English property
205 : // because the map is const. So for performance reasons set
206 : // CompileEnglish _before_ OpCodeMap!
207 414 : if (mxOpCodeMap.get() && mbEnglish != bOldEnglish)
208 : {
209 0 : ScDocument& rDoc = mpDocShell->GetDocument();
210 0 : ScCompiler aCompiler( &rDoc, ScAddress());
211 0 : aCompiler.SetGrammar(rDoc.GetGrammar());
212 0 : mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
213 : }
214 : }
215 : else
216 0 : throw lang::IllegalArgumentException();
217 : }
218 1494 : else if ( aString == SC_UNO_FORMULACONVENTION )
219 : {
220 594 : aValue >>= mnConv;
221 : }
222 900 : else if ( aString == SC_UNO_IGNORELEADING )
223 : {
224 414 : aValue >>= mbIgnoreSpaces;
225 : }
226 486 : else if ( aString == SC_UNO_OPCODEMAP )
227 : {
228 414 : if (aValue >>= maOpCodeMapping)
229 : {
230 414 : ScDocument& rDoc = mpDocShell->GetDocument();
231 414 : ScCompiler aCompiler( &rDoc, ScAddress());
232 414 : aCompiler.SetGrammar(rDoc.GetGrammar());
233 414 : mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
234 : }
235 : else
236 0 : throw lang::IllegalArgumentException();
237 : }
238 72 : else if ( aString == SC_UNO_EXTERNALLINKS )
239 : {
240 72 : if (!(aValue >>= maExternalLinks))
241 0 : throw lang::IllegalArgumentException();
242 : }
243 : else
244 1908 : throw beans::UnknownPropertyException();
245 1908 : }
246 :
247 0 : uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const OUString& aPropertyName )
248 : throw(beans::UnknownPropertyException, lang::WrappedTargetException,
249 : uno::RuntimeException, std::exception)
250 : {
251 0 : SolarMutexGuard aGuard;
252 0 : uno::Any aRet;
253 0 : OUString aString(aPropertyName);
254 0 : if ( aString == SC_UNO_COMPILEFAP )
255 : {
256 0 : aRet <<= mbCompileFAP;
257 : }
258 0 : else if ( aString == SC_UNO_COMPILEENGLISH )
259 : {
260 0 : aRet <<= mbEnglish;
261 : }
262 0 : else if ( aString == SC_UNO_FORMULACONVENTION )
263 : {
264 0 : aRet <<= mnConv;
265 : }
266 0 : else if ( aString == SC_UNO_IGNORELEADING )
267 : {
268 0 : aRet <<= mbIgnoreSpaces;
269 : }
270 0 : else if ( aString == SC_UNO_OPCODEMAP )
271 : {
272 0 : aRet <<= maOpCodeMapping;
273 : }
274 0 : else if ( aString == SC_UNO_EXTERNALLINKS )
275 : {
276 0 : aRet <<= maExternalLinks;
277 : }
278 : else
279 0 : throw beans::UnknownPropertyException();
280 0 : return aRet;
281 : }
282 :
283 0 : SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj )
284 :
285 0 : static void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
286 : {
287 0 : rAPI.Column = 0;
288 0 : rAPI.Row = 0;
289 0 : rAPI.Sheet = 0;
290 0 : rAPI.RelativeColumn = 0;
291 0 : rAPI.RelativeRow = 0;
292 0 : rAPI.RelativeSheet = 0;
293 :
294 0 : sal_Int32 nFlags = 0;
295 0 : if ( rRef.IsColRel() )
296 : {
297 0 : nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
298 0 : rAPI.RelativeColumn = rRef.Col();
299 : }
300 : else
301 0 : rAPI.Column = rRef.Col();
302 :
303 0 : if ( rRef.IsRowRel() )
304 : {
305 0 : nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
306 0 : rAPI.RelativeRow = rRef.Row();
307 : }
308 : else
309 0 : rAPI.Row = rRef.Row();
310 :
311 0 : if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
312 0 : if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
313 0 : if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
314 0 : if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
315 0 : rAPI.Flags = nFlags;
316 0 : }
317 :
318 567 : static void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
319 : {
320 567 : sal_Int32 nFlags = 0;
321 567 : if ( rRef.IsColRel() )
322 : {
323 7 : nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
324 7 : rAPI.RelativeColumn = rRef.Col();
325 7 : rAPI.Column = 0;
326 : }
327 : else
328 : {
329 560 : rAPI.RelativeColumn = 0;
330 560 : rAPI.Column = rRef.Col();
331 : }
332 :
333 567 : if ( rRef.IsRowRel() )
334 : {
335 7 : nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
336 7 : rAPI.RelativeRow = rRef.Row();
337 7 : rAPI.Row = 0;
338 : }
339 : else
340 : {
341 560 : rAPI.RelativeRow = 0;
342 560 : rAPI.Row = rRef.Row();
343 : }
344 :
345 567 : if ( rRef.IsTabRel() )
346 : {
347 7 : nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
348 7 : rAPI.RelativeSheet = rRef.Tab();
349 7 : rAPI.Sheet = 0;
350 : }
351 : else
352 : {
353 560 : rAPI.RelativeSheet = 0;
354 560 : rAPI.Sheet = rRef.Tab();
355 : }
356 :
357 567 : if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
358 567 : if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
359 567 : if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
360 567 : if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
361 567 : if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
362 567 : rAPI.Flags = nFlags;
363 567 : }
364 :
365 407 : bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
366 : ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
367 : {
368 407 : return !rTokenArray.Fill(rSequence, rDoc.GetSharedStringPool(), rDoc.GetExternalRefManager());
369 : }
370 :
371 375 : bool ScTokenConversion::ConvertToTokenSequence( const ScDocument& rDoc,
372 : uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray )
373 : {
374 375 : bool bError = false;
375 :
376 375 : sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
377 375 : formula::FormulaToken** pTokens = rTokenArray.GetArray();
378 375 : if ( pTokens )
379 : {
380 375 : rSequence.realloc(nLen);
381 773 : for (sal_Int32 nPos=0; nPos<nLen; nPos++)
382 : {
383 398 : const formula::FormulaToken& rToken = *pTokens[nPos];
384 398 : sheet::FormulaToken& rAPI = rSequence[nPos];
385 :
386 398 : OpCode eOpCode = rToken.GetOpCode();
387 : // eOpCode may be changed in the following switch/case
388 398 : switch ( rToken.GetType() )
389 : {
390 : case svByte:
391 : // Only the count of spaces is stored as "long". Parameter count is ignored.
392 9 : if ( eOpCode == ocSpaces )
393 0 : rAPI.Data <<= (sal_Int32) rToken.GetByte();
394 : else
395 9 : rAPI.Data.clear(); // no data
396 9 : break;
397 : case formula::svDouble:
398 11 : rAPI.Data <<= rToken.GetDouble();
399 11 : break;
400 : case formula::svString:
401 1 : rAPI.Data <<= rToken.GetString().getString();
402 1 : break;
403 : case svExternal:
404 : // Function name is stored as string.
405 : // Byte (parameter count) is ignored.
406 0 : rAPI.Data <<= OUString( rToken.GetExternal() );
407 0 : break;
408 : case svSingleRef:
409 : {
410 169 : sheet::SingleReference aSingleRef;
411 169 : lcl_SingleRefToApi( aSingleRef, *rToken.GetSingleRef() );
412 169 : rAPI.Data <<= aSingleRef;
413 : }
414 169 : break;
415 : case formula::svDoubleRef:
416 : {
417 199 : sheet::ComplexReference aCompRef;
418 199 : lcl_SingleRefToApi( aCompRef.Reference1, *rToken.GetSingleRef() );
419 199 : lcl_SingleRefToApi( aCompRef.Reference2, *rToken.GetSingleRef2() );
420 199 : rAPI.Data <<= aCompRef;
421 : }
422 199 : break;
423 : case svIndex:
424 : {
425 1 : sheet::NameToken aNameToken;
426 1 : aNameToken.Index = static_cast<sal_Int32>( rToken.GetIndex() );
427 1 : aNameToken.Global = rToken.IsGlobal();
428 1 : rAPI.Data <<= aNameToken;
429 : }
430 1 : break;
431 : case svMatrix:
432 1 : if (!ScRangeToSequence::FillMixedArray( rAPI.Data, rToken.GetMatrix(), true))
433 0 : rAPI.Data.clear();
434 1 : break;
435 : case svExternalSingleRef:
436 : {
437 0 : sheet::SingleReference aSingleRef;
438 0 : lcl_ExternalRefToApi( aSingleRef, *rToken.GetSingleRef() );
439 : size_t nCacheId;
440 : rDoc.GetExternalRefManager()->getCacheTable(
441 0 : rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
442 0 : aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId );
443 0 : sheet::ExternalReference aExtRef;
444 0 : aExtRef.Index = rToken.GetIndex();
445 0 : aExtRef.Reference <<= aSingleRef;
446 0 : rAPI.Data <<= aExtRef;
447 0 : eOpCode = ocPush;
448 : }
449 0 : break;
450 : case svExternalDoubleRef:
451 : {
452 0 : sheet::ComplexReference aComplRef;
453 0 : lcl_ExternalRefToApi( aComplRef.Reference1, *rToken.GetSingleRef() );
454 0 : lcl_ExternalRefToApi( aComplRef.Reference2, *rToken.GetSingleRef2() );
455 : size_t nCacheId;
456 : rDoc.GetExternalRefManager()->getCacheTable(
457 0 : rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
458 0 : aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId );
459 : // NOTE: This assumes that cached sheets are in consecutive order!
460 : aComplRef.Reference2.Sheet =
461 0 : aComplRef.Reference1.Sheet +
462 0 : (rToken.GetSingleRef2()->Tab() - rToken.GetSingleRef()->Tab());
463 0 : sheet::ExternalReference aExtRef;
464 0 : aExtRef.Index = rToken.GetIndex();
465 0 : aExtRef.Reference <<= aComplRef;
466 0 : rAPI.Data <<= aExtRef;
467 0 : eOpCode = ocPush;
468 : }
469 0 : break;
470 : case svExternalName:
471 : {
472 0 : sheet::ExternalReference aExtRef;
473 0 : aExtRef.Index = rToken.GetIndex();
474 0 : aExtRef.Reference <<= rToken.GetString().getString();
475 0 : rAPI.Data <<= aExtRef;
476 0 : eOpCode = ocPush;
477 : }
478 0 : break;
479 : default:
480 : OSL_TRACE( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken.GetType());
481 : //fall-through
482 : case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray*
483 : case svJump: // occurs with ocIf, ocChoose
484 : case svMissing: // occurs with ocMissing
485 7 : rAPI.Data.clear(); // no data
486 : }
487 398 : rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment
488 : }
489 : }
490 : else
491 0 : rSequence.realloc(0);
492 :
493 375 : return !bError;
494 : }
495 :
496 470 : ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::unique_ptr<formula::FormulaCompiler> && _pCompiler)
497 470 : : formula::FormulaOpCodeMapperObj(std::move(_pCompiler))
498 : {
499 626 : }
500 :
501 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|