1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 #include "tokenuno.hxx"
28
29 #include <com/sun/star/sheet/ComplexReference.hpp>
30 #include <com/sun/star/sheet/ExternalReference.hpp>
31 #include <com/sun/star/sheet/ReferenceFlags.hpp>
32 #include <com/sun/star/sheet/AddressConvention.hpp>
33 #include <com/sun/star/table/CellAddress.hpp>
34
35 #include <svl/itemprop.hxx>
36
37 #include "miscuno.hxx"
38 #include "convuno.hxx"
39 #include "unonames.hxx"
40 #include "unoguard.hxx"
41 #include "token.hxx"
42 #include "compiler.hxx"
43 #include "tokenarray.hxx"
44 #include "docsh.hxx"
45 #include "rangeseq.hxx"
46 #include "externalrefmgr.hxx"
47
48 using namespace ::formula;
49 using namespace ::com::sun::star;
50
51 // ============================================================================
52
lcl_GetFormulaParserMap()53 const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap()
54 {
55 static SfxItemPropertyMapEntry aFormulaParserMap_Impl[] =
56 {
57 {MAP_CHAR_LEN(SC_UNO_COMPILEFAP), 0, &getBooleanCppuType(), 0, 0 },
58 {MAP_CHAR_LEN(SC_UNO_COMPILEENGLISH), 0, &getBooleanCppuType(), 0, 0 },
59 {MAP_CHAR_LEN(SC_UNO_IGNORELEADING), 0, &getBooleanCppuType(), 0, 0 },
60 {MAP_CHAR_LEN(SC_UNO_FORMULACONVENTION), 0, &getCppuType(&sheet::AddressConvention::UNSPECIFIED), 0, 0 },
61 {MAP_CHAR_LEN(SC_UNO_OPCODEMAP), 0, &getCppuType((uno::Sequence< sheet::FormulaOpCodeMapEntry >*)0), 0, 0 },
62 {0,0,0,0,0,0}
63 };
64 return aFormulaParserMap_Impl;
65 }
66
67 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS )
68
69 // ============================================================================
70
ScFormulaParserObj(ScDocShell * pDocSh)71 ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
72 mpDocShell( pDocSh ),
73 mnConv( sheet::AddressConvention::UNSPECIFIED ),
74 mbEnglish( false ),
75 mbIgnoreSpaces( true ),
76 mbCompileFAP( false )
77 {
78 mpDocShell->GetDocument()->AddUnoObject(*this);
79 }
80
~ScFormulaParserObj()81 ScFormulaParserObj::~ScFormulaParserObj()
82 {
83 if (mpDocShell)
84 mpDocShell->GetDocument()->RemoveUnoObject(*this);
85 }
86
Notify(SfxBroadcaster &,const SfxHint & rHint)87 void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
88 {
89 if ( rHint.ISA( SfxSimpleHint ) && ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
90 mpDocShell = NULL;
91 }
92
93 // XFormulaParser
94
SetCompilerFlags(ScCompiler & rCompiler) const95 void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const
96 {
97 static const formula::FormulaGrammar::AddressConvention aConvMap[] = {
98 formula::FormulaGrammar::CONV_OOO, // <- AddressConvention::OOO
99 formula::FormulaGrammar::CONV_XL_A1, // <- AddressConvention::XL_A1
100 formula::FormulaGrammar::CONV_XL_R1C1, // <- AddressConvention::XL_R1C1
101 formula::FormulaGrammar::CONV_XL_OOX, // <- AddressConvention::XL_OOX
102 formula::FormulaGrammar::CONV_LOTUS_A1 // <- AddressConvention::LOTUS_A1
103 };
104 static const sal_Int16 nConvMapCount = sizeof(aConvMap)/sizeof(aConvMap[0]);
105
106 // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
107 // don't need to initialize things twice.
108 if (mxOpCodeMap.get())
109 rCompiler.SetFormulaLanguage( mxOpCodeMap );
110 else
111 {
112 sal_Int32 nFormulaLanguage = mbEnglish ?
113 sheet::FormulaLanguage::ENGLISH :
114 sheet::FormulaLanguage::NATIVE;
115 ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage);
116 rCompiler.SetFormulaLanguage( xMap);
117 }
118
119 formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
120 if (mnConv >= 0 && mnConv < nConvMapCount)
121 eConv = aConvMap[mnConv];
122
123 rCompiler.SetRefConvention( eConv );
124
125 rCompiler.SetCompileForFAP(mbCompileFAP);
126
127 rCompiler.SetExternalLinks( maExternalLinks);
128 }
129
parseFormula(const rtl::OUString & aFormula,const table::CellAddress & rReferencePos)130 uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula(
131 const rtl::OUString& aFormula, const table::CellAddress& rReferencePos )
132 throw (uno::RuntimeException)
133 {
134 ScUnoGuard aGuard;
135 uno::Sequence<sheet::FormulaToken> aRet;
136
137 if (mpDocShell)
138 {
139 ScDocument* pDoc = mpDocShell->GetDocument();
140 ScExternalRefManager::ApiGuard aExtRefGuard(pDoc);
141
142 ScAddress aRefPos( ScAddress::UNINITIALIZED );
143 ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
144 ScCompiler aCompiler( pDoc, aRefPos);
145 aCompiler.SetGrammar(pDoc->GetGrammar());
146 SetCompilerFlags( aCompiler );
147
148 ScTokenArray* pCode = aCompiler.CompileString( aFormula );
149 (void)ScTokenConversion::ConvertToTokenSequence( *pDoc, aRet, *pCode );
150 delete pCode;
151 }
152
153 return aRet;
154 }
155
printFormula(const uno::Sequence<sheet::FormulaToken> & aTokens,const table::CellAddress & rReferencePos)156 rtl::OUString SAL_CALL ScFormulaParserObj::printFormula(
157 const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
158 throw (uno::RuntimeException)
159 {
160 ScUnoGuard aGuard;
161 rtl::OUString aRet;
162
163 if (mpDocShell)
164 {
165 ScDocument* pDoc = mpDocShell->GetDocument();
166 ScTokenArray aCode;
167 (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aCode, aTokens );
168 ScAddress aRefPos( ScAddress::UNINITIALIZED );
169 ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
170 ScCompiler aCompiler( pDoc, aRefPos, aCode);
171 aCompiler.SetGrammar(pDoc->GetGrammar());
172 SetCompilerFlags( aCompiler );
173
174 rtl::OUStringBuffer aBuffer;
175 aCompiler.CreateStringFromTokenArray( aBuffer );
176 aRet = aBuffer.makeStringAndClear();
177 }
178
179 return aRet;
180 }
181
182 // XPropertySet
183
getPropertySetInfo()184 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
185 throw(uno::RuntimeException)
186 {
187 ScUnoGuard aGuard;
188 static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
189 return aRef;
190 }
191
setPropertyValue(const rtl::OUString & aPropertyName,const uno::Any & aValue)192 void SAL_CALL ScFormulaParserObj::setPropertyValue(
193 const rtl::OUString& aPropertyName, const uno::Any& aValue )
194 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
195 lang::IllegalArgumentException, lang::WrappedTargetException,
196 uno::RuntimeException)
197 {
198 ScUnoGuard aGuard;
199 String aString(aPropertyName);
200 if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) )
201 {
202 aValue >>= mbCompileFAP;
203 }
204 else if ( aString.EqualsAscii( SC_UNO_COMPILEENGLISH ) )
205 {
206 bool bOldEnglish = mbEnglish;
207 if (aValue >>= mbEnglish)
208 {
209 // Need to recreate the symbol map to change English property
210 // because the map is const. So for performance reasons set
211 // CompileEnglish _before_ OpCodeMap!
212 if (mxOpCodeMap.get() && mbEnglish != bOldEnglish)
213 {
214 ScDocument* pDoc = mpDocShell->GetDocument();
215 ScCompiler aCompiler( pDoc, ScAddress());
216 aCompiler.SetGrammar(pDoc->GetGrammar());
217 mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
218 }
219 }
220 else
221 throw lang::IllegalArgumentException();
222 }
223 else if ( aString.EqualsAscii( SC_UNO_FORMULACONVENTION ) )
224 {
225 aValue >>= mnConv;
226 }
227 else if ( aString.EqualsAscii( SC_UNO_IGNORELEADING ) )
228 {
229 aValue >>= mbIgnoreSpaces;
230 }
231 else if ( aString.EqualsAscii( SC_UNO_OPCODEMAP ) )
232 {
233 if (aValue >>= maOpCodeMapping)
234 {
235 ScDocument* pDoc = mpDocShell->GetDocument();
236 ScCompiler aCompiler( pDoc, ScAddress());
237 aCompiler.SetGrammar(pDoc->GetGrammar());
238 mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
239 }
240 else
241 throw lang::IllegalArgumentException();
242 }
243 else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) )
244 {
245 if (!(aValue >>= maExternalLinks))
246 throw lang::IllegalArgumentException();
247 }
248 else
249 throw beans::UnknownPropertyException();
250 }
251
getPropertyValue(const rtl::OUString & aPropertyName)252 uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const rtl::OUString& aPropertyName )
253 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
254 uno::RuntimeException)
255 {
256 ScUnoGuard aGuard;
257 uno::Any aRet;
258 String aString(aPropertyName);
259 if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) )
260 {
261 aRet <<= mbCompileFAP;
262 }
263 else if ( aString.EqualsAscii( SC_UNO_COMPILEENGLISH ) )
264 {
265 aRet <<= mbEnglish;
266 }
267 else if ( aString.EqualsAscii( SC_UNO_FORMULACONVENTION ) )
268 {
269 aRet <<= mnConv;
270 }
271 else if ( aString.EqualsAscii( SC_UNO_IGNORELEADING ) )
272 {
273 aRet <<= mbIgnoreSpaces;
274 }
275 else if ( aString.EqualsAscii( SC_UNO_OPCODEMAP ) )
276 {
277 aRet <<= maOpCodeMapping;
278 }
279 else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) )
280 {
281 aRet <<= maExternalLinks;
282 }
283 else
284 throw beans::UnknownPropertyException();
285 return aRet;
286 }
287
SC_IMPL_DUMMY_PROPERTY_LISTENER(ScFormulaParserObj)288 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj )
289
290 // ============================================================================
291
292 void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
293 {
294 rAPI.Column = rRef.nCol;
295 rAPI.Row = rRef.nRow;
296 rAPI.Sheet = 0;
297 rAPI.RelativeColumn = rRef.nRelCol;
298 rAPI.RelativeRow = rRef.nRelRow;
299 rAPI.RelativeSheet = 0;
300
301 sal_Int32 nFlags = 0;
302 if ( rRef.IsColRel() ) nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
303 if ( rRef.IsRowRel() ) nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
304 if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
305 if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
306 if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
307 if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
308 rAPI.Flags = nFlags;
309 }
310
lcl_SingleRefToApi(sheet::SingleReference & rAPI,const ScSingleRefData & rRef)311 void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
312 {
313 rAPI.Column = rRef.nCol;
314 rAPI.Row = rRef.nRow;
315 rAPI.Sheet = rRef.nTab;
316 rAPI.RelativeColumn = rRef.nRelCol;
317 rAPI.RelativeRow = rRef.nRelRow;
318 rAPI.RelativeSheet = rRef.nRelTab;
319
320 sal_Int32 nFlags = 0;
321 if ( rRef.IsColRel() ) nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
322 if ( rRef.IsRowRel() ) nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
323 if ( rRef.IsTabRel() ) nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
324 if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
325 if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
326 if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
327 if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
328 if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
329 rAPI.Flags = nFlags;
330 }
331
332 // static
ConvertToTokenArray(ScDocument & rDoc,ScTokenArray & rTokenArray,const uno::Sequence<sheet::FormulaToken> & rSequence)333 bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
334 ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
335 {
336 return !rTokenArray.Fill(rSequence,rDoc.GetExternalRefManager());
337 }
338
339 // static
ConvertToTokenSequence(ScDocument & rDoc,uno::Sequence<sheet::FormulaToken> & rSequence,const ScTokenArray & rTokenArray)340 bool ScTokenConversion::ConvertToTokenSequence( ScDocument& rDoc,
341 uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray )
342 {
343 bool bError = false;
344
345 sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
346 formula::FormulaToken** pTokens = rTokenArray.GetArray();
347 if ( pTokens )
348 {
349 rSequence.realloc(nLen);
350 for (sal_Int32 nPos=0; nPos<nLen; nPos++)
351 {
352 const formula::FormulaToken& rToken = *pTokens[nPos];
353 sheet::FormulaToken& rAPI = rSequence[nPos];
354
355 OpCode eOpCode = rToken.GetOpCode();
356 // eOpCode may be changed in the following switch/case
357 switch ( rToken.GetType() )
358 {
359 case svByte:
360 // Only the count of spaces is stored as "long". Parameter count is ignored.
361 if ( eOpCode == ocSpaces )
362 rAPI.Data <<= (sal_Int32) rToken.GetByte();
363 else
364 rAPI.Data.clear(); // no data
365 break;
366 case formula::svDouble:
367 rAPI.Data <<= rToken.GetDouble();
368 break;
369 case formula::svString:
370 rAPI.Data <<= rtl::OUString( rToken.GetString() );
371 break;
372 case svExternal:
373 // Function name is stored as string.
374 // Byte (parameter count) is ignored.
375 rAPI.Data <<= rtl::OUString( rToken.GetExternal() );
376 break;
377 case svSingleRef:
378 {
379 sheet::SingleReference aSingleRef;
380 lcl_SingleRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() );
381 rAPI.Data <<= aSingleRef;
382 }
383 break;
384 case formula::svDoubleRef:
385 {
386 sheet::ComplexReference aCompRef;
387 lcl_SingleRefToApi( aCompRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() );
388 lcl_SingleRefToApi( aCompRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() );
389 rAPI.Data <<= aCompRef;
390 }
391 break;
392 case svIndex:
393 rAPI.Data <<= static_cast<sal_Int32>( rToken.GetIndex() );
394 break;
395 case svMatrix:
396 if (!ScRangeToSequence::FillMixedArray( rAPI.Data, static_cast<const ScToken&>(rToken).GetMatrix(), true))
397 rAPI.Data.clear();
398 break;
399 case svExternalSingleRef:
400 {
401 sheet::SingleReference aSingleRef;
402 lcl_ExternalRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() );
403 size_t nCacheId;
404 rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId );
405 aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId );
406 sheet::ExternalReference aExtRef;
407 aExtRef.Index = rToken.GetIndex();
408 aExtRef.Reference <<= aSingleRef;
409 rAPI.Data <<= aExtRef;
410 eOpCode = ocPush;
411 }
412 break;
413 case svExternalDoubleRef:
414 {
415 sheet::ComplexReference aComplRef;
416 lcl_ExternalRefToApi( aComplRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() );
417 lcl_ExternalRefToApi( aComplRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() );
418 size_t nCacheId;
419 rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId );
420 aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId );
421 // NOTE: This assumes that cached sheets are in consecutive order!
422 aComplRef.Reference2.Sheet = aComplRef.Reference1.Sheet + (static_cast<const ScToken&>(rToken).GetSingleRef2().nTab - static_cast<const ScToken&>(rToken).GetSingleRef().nTab);
423 sheet::ExternalReference aExtRef;
424 aExtRef.Index = rToken.GetIndex();
425 aExtRef.Reference <<= aComplRef;
426 rAPI.Data <<= aExtRef;
427 eOpCode = ocPush;
428 }
429 break;
430 case svExternalName:
431 {
432 sheet::ExternalReference aExtRef;
433 aExtRef.Index = rToken.GetIndex();
434 aExtRef.Reference <<= ::rtl::OUString( rToken.GetString() );
435 rAPI.Data <<= aExtRef;
436 eOpCode = ocPush;
437 }
438 break;
439 default:
440 DBG_ERROR1( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken.GetType());
441 case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray*
442 case svJump: // occurs with ocIf, ocChose
443 case svMissing: // occurs with ocMissing
444 rAPI.Data.clear(); // no data
445 }
446 rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment
447 }
448 }
449 else
450 rSequence.realloc(0);
451
452 return !bError;
453 }
454
455 // ============================================================================
456
ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler)457 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler)
458 : formula::FormulaOpCodeMapperObj(_pCompiler)
459 {
460 }
461
462 // ============================================================================
463
464