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 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 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 81 ScFormulaParserObj::~ScFormulaParserObj() 82 { 83 if (mpDocShell) 84 mpDocShell->GetDocument()->RemoveUnoObject(*this); 85 } 86 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 95 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 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 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 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 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 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 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 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 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 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 457 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler) 458 : formula::FormulaOpCodeMapperObj(_pCompiler) 459 { 460 } 461 462 // ============================================================================ 463 464