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 10 : static const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap()
48 : {
49 : static const SfxItemPropertyMapEntry aFormulaParserMap_Impl[] =
50 : {
51 10 : {OUString(SC_UNO_COMPILEFAP), 0, getBooleanCppuType(), 0, 0 },
52 10 : {OUString(SC_UNO_COMPILEENGLISH), 0, getBooleanCppuType(), 0, 0 },
53 10 : {OUString(SC_UNO_IGNORELEADING), 0, getBooleanCppuType(), 0, 0 },
54 10 : {OUString(SC_UNO_FORMULACONVENTION), 0, getCppuType(&sheet::AddressConvention::UNSPECIFIED), 0, 0 },
55 10 : {OUString(SC_UNO_OPCODEMAP), 0, getCppuType((uno::Sequence< sheet::FormulaOpCodeMapEntry >*)0), 0, 0 },
56 : { OUString(), 0, css::uno::Type(), 0, 0 }
57 70 : };
58 10 : return aFormulaParserMap_Impl;
59 : }
60 :
61 0 : SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS )
62 :
63 434 : ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
64 : mpDocShell( pDocSh ),
65 : mnConv( sheet::AddressConvention::UNSPECIFIED ),
66 : mbEnglish( false ),
67 : mbIgnoreSpaces( true ),
68 434 : mbCompileFAP( false )
69 : {
70 434 : mpDocShell->GetDocument().AddUnoObject(*this);
71 434 : }
72 :
73 1302 : ScFormulaParserObj::~ScFormulaParserObj()
74 : {
75 434 : SolarMutexGuard g;
76 :
77 434 : if (mpDocShell)
78 432 : mpDocShell->GetDocument().RemoveUnoObject(*this);
79 868 : }
80 :
81 10589 : void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
82 : {
83 10589 : const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
84 10589 : if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DYING )
85 2 : mpDocShell = NULL;
86 10589 : }
87 :
88 : // XFormulaParser
89 :
90 234 : 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 234 : if (mxOpCodeMap.get())
104 148 : rCompiler.SetFormulaLanguage( mxOpCodeMap );
105 : else
106 : {
107 : sal_Int32 nFormulaLanguage = mbEnglish ?
108 : sheet::FormulaLanguage::ENGLISH :
109 86 : sheet::FormulaLanguage::NATIVE;
110 86 : ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage);
111 86 : rCompiler.SetFormulaLanguage( xMap);
112 : }
113 :
114 234 : formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
115 234 : if (mnConv >= 0 && mnConv < nConvMapCount)
116 232 : eConv = aConvMap[mnConv];
117 :
118 234 : rCompiler.SetRefConvention( eConv );
119 234 : rCompiler.EnableJumpCommandReorder(!mbCompileFAP);
120 234 : rCompiler.EnableStopOnError(!mbCompileFAP);
121 :
122 234 : rCompiler.SetExternalLinks( maExternalLinks);
123 234 : }
124 :
125 192 : uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula(
126 : const OUString& aFormula, const table::CellAddress& rReferencePos )
127 : throw (uno::RuntimeException, std::exception)
128 : {
129 192 : SolarMutexGuard aGuard;
130 192 : uno::Sequence<sheet::FormulaToken> aRet;
131 :
132 192 : if (mpDocShell)
133 : {
134 192 : ScDocument& rDoc = mpDocShell->GetDocument();
135 192 : ScExternalRefManager::ApiGuard aExtRefGuard(&rDoc);
136 :
137 192 : ScAddress aRefPos( ScAddress::UNINITIALIZED );
138 192 : ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
139 384 : ScCompiler aCompiler( &rDoc, aRefPos);
140 192 : aCompiler.SetGrammar(rDoc.GetGrammar());
141 192 : SetCompilerFlags( aCompiler );
142 :
143 192 : ScTokenArray* pCode = aCompiler.CompileString( aFormula );
144 192 : (void)ScTokenConversion::ConvertToTokenSequence( rDoc, aRet, *pCode );
145 384 : delete pCode;
146 : }
147 :
148 192 : return aRet;
149 : }
150 :
151 42 : OUString SAL_CALL ScFormulaParserObj::printFormula(
152 : const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
153 : throw (uno::RuntimeException, std::exception)
154 : {
155 42 : SolarMutexGuard aGuard;
156 42 : OUString aRet;
157 :
158 42 : if (mpDocShell)
159 : {
160 42 : ScDocument& rDoc = mpDocShell->GetDocument();
161 42 : ScTokenArray aCode;
162 42 : (void)ScTokenConversion::ConvertToTokenArray( rDoc, aCode, aTokens );
163 42 : ScAddress aRefPos( ScAddress::UNINITIALIZED );
164 42 : ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
165 84 : ScCompiler aCompiler( &rDoc, aRefPos, aCode);
166 42 : aCompiler.SetGrammar(rDoc.GetGrammar());
167 42 : SetCompilerFlags( aCompiler );
168 :
169 84 : OUStringBuffer aBuffer;
170 42 : aCompiler.CreateStringFromTokenArray( aBuffer );
171 84 : aRet = aBuffer.makeStringAndClear();
172 : }
173 :
174 42 : return aRet;
175 : }
176 :
177 : // XPropertySet
178 :
179 388 : uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
180 : throw(uno::RuntimeException, std::exception)
181 : {
182 388 : SolarMutexGuard aGuard;
183 388 : static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
184 388 : return aRef;
185 : }
186 :
187 1676 : 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 1676 : SolarMutexGuard aGuard;
194 3352 : OUString aString(aPropertyName);
195 1676 : if ( aString.equalsAscii( SC_UNO_COMPILEFAP ) )
196 : {
197 0 : aValue >>= mbCompileFAP;
198 : }
199 1676 : else if ( aString.equalsAscii( SC_UNO_COMPILEENGLISH ) )
200 : {
201 388 : bool bOldEnglish = mbEnglish;
202 388 : 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 388 : 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 = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
213 : }
214 : }
215 : else
216 0 : throw lang::IllegalArgumentException();
217 : }
218 1288 : else if ( aString.equalsAscii( SC_UNO_FORMULACONVENTION ) )
219 : {
220 472 : aValue >>= mnConv;
221 : }
222 816 : else if ( aString.equalsAscii( SC_UNO_IGNORELEADING ) )
223 : {
224 388 : aValue >>= mbIgnoreSpaces;
225 : }
226 428 : else if ( aString.equalsAscii( SC_UNO_OPCODEMAP ) )
227 : {
228 388 : if (aValue >>= maOpCodeMapping)
229 : {
230 388 : ScDocument& rDoc = mpDocShell->GetDocument();
231 388 : ScCompiler aCompiler( &rDoc, ScAddress());
232 388 : aCompiler.SetGrammar(rDoc.GetGrammar());
233 388 : mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
234 : }
235 : else
236 0 : throw lang::IllegalArgumentException();
237 : }
238 40 : else if ( aString.equalsAscii( SC_UNO_EXTERNALLINKS ) )
239 : {
240 40 : if (!(aValue >>= maExternalLinks))
241 0 : throw lang::IllegalArgumentException();
242 : }
243 : else
244 1676 : throw beans::UnknownPropertyException();
245 1676 : }
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.equalsAscii( SC_UNO_COMPILEFAP ) )
255 : {
256 0 : aRet <<= mbCompileFAP;
257 : }
258 0 : else if ( aString.equalsAscii( SC_UNO_COMPILEENGLISH ) )
259 : {
260 0 : aRet <<= mbEnglish;
261 : }
262 0 : else if ( aString.equalsAscii( SC_UNO_FORMULACONVENTION ) )
263 : {
264 0 : aRet <<= mnConv;
265 : }
266 0 : else if ( aString.equalsAscii( SC_UNO_IGNORELEADING ) )
267 : {
268 0 : aRet <<= mbIgnoreSpaces;
269 : }
270 0 : else if ( aString.equalsAscii( SC_UNO_OPCODEMAP ) )
271 : {
272 0 : aRet <<= maOpCodeMapping;
273 : }
274 0 : else if ( aString.equalsAscii( 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 296 : static void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
319 : {
320 296 : sal_Int32 nFlags = 0;
321 296 : if ( rRef.IsColRel() )
322 : {
323 12 : nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
324 12 : rAPI.RelativeColumn = rRef.Col();
325 12 : rAPI.Column = 0;
326 : }
327 : else
328 : {
329 284 : rAPI.RelativeColumn = 0;
330 284 : rAPI.Column = rRef.Col();
331 : }
332 :
333 296 : if ( rRef.IsRowRel() )
334 : {
335 12 : nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
336 12 : rAPI.RelativeRow = rRef.Row();
337 12 : rAPI.Row = 0;
338 : }
339 : else
340 : {
341 284 : rAPI.RelativeRow = 0;
342 284 : rAPI.Row = rRef.Row();
343 : }
344 :
345 296 : if ( rRef.IsTabRel() )
346 : {
347 12 : nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
348 12 : rAPI.RelativeSheet = rRef.Tab();
349 12 : rAPI.Sheet = 0;
350 : }
351 : else
352 : {
353 284 : rAPI.RelativeSheet = 0;
354 284 : rAPI.Sheet = rRef.Tab();
355 : }
356 :
357 296 : if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
358 296 : if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
359 296 : if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
360 296 : if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
361 296 : if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
362 296 : rAPI.Flags = nFlags;
363 296 : }
364 :
365 214 : bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
366 : ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
367 : {
368 214 : return !rTokenArray.Fill(rSequence, rDoc.GetSharedStringPool(), rDoc.GetExternalRefManager());
369 : }
370 :
371 216 : bool ScTokenConversion::ConvertToTokenSequence( const ScDocument& rDoc,
372 : uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray )
373 : {
374 216 : bool bError = false;
375 :
376 216 : sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
377 216 : formula::FormulaToken** pTokens = rTokenArray.GetArray();
378 216 : if ( pTokens )
379 : {
380 216 : rSequence.realloc(nLen);
381 456 : for (sal_Int32 nPos=0; nPos<nLen; nPos++)
382 : {
383 240 : const formula::FormulaToken& rToken = *pTokens[nPos];
384 240 : sheet::FormulaToken& rAPI = rSequence[nPos];
385 :
386 240 : OpCode eOpCode = rToken.GetOpCode();
387 : // eOpCode may be changed in the following switch/case
388 240 : switch ( rToken.GetType() )
389 : {
390 : case svByte:
391 : // Only the count of spaces is stored as "long". Parameter count is ignored.
392 12 : if ( eOpCode == ocSpaces )
393 0 : rAPI.Data <<= (sal_Int32) rToken.GetByte();
394 : else
395 12 : rAPI.Data.clear(); // no data
396 12 : break;
397 : case formula::svDouble:
398 22 : rAPI.Data <<= rToken.GetDouble();
399 22 : break;
400 : case formula::svString:
401 0 : rAPI.Data <<= rToken.GetString().getString();
402 0 : 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 100 : sheet::SingleReference aSingleRef;
411 100 : lcl_SingleRefToApi( aSingleRef, *rToken.GetSingleRef() );
412 100 : rAPI.Data <<= aSingleRef;
413 : }
414 100 : break;
415 : case formula::svDoubleRef:
416 : {
417 98 : sheet::ComplexReference aCompRef;
418 98 : lcl_SingleRefToApi( aCompRef.Reference1, *rToken.GetSingleRef() );
419 98 : lcl_SingleRefToApi( aCompRef.Reference2, *rToken.GetSingleRef2() );
420 98 : rAPI.Data <<= aCompRef;
421 : }
422 98 : break;
423 : case svIndex:
424 : {
425 4 : sheet::NameToken aNameToken;
426 4 : aNameToken.Index = static_cast<sal_Int32>( rToken.GetIndex() );
427 4 : aNameToken.Global = rToken.IsGlobal();
428 4 : rAPI.Data <<= aNameToken;
429 : }
430 4 : break;
431 : case svMatrix:
432 4 : if (!ScRangeToSequence::FillMixedArray( rAPI.Data, rToken.GetMatrix(), true))
433 0 : rAPI.Data.clear();
434 4 : 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, ocChose
484 : case svMissing: // occurs with ocMissing
485 0 : rAPI.Data.clear(); // no data
486 : }
487 240 : rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment
488 : }
489 : }
490 : else
491 0 : rSequence.realloc(0);
492 :
493 216 : return !bError;
494 : }
495 :
496 428 : ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::unique_ptr<formula::FormulaCompiler> && _pCompiler)
497 428 : : formula::FormulaOpCodeMapperObj(std::move(_pCompiler))
498 : {
499 656 : }
500 :
501 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|