1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "oox/xls/defnamesbuffer.hxx" 29 30 #include <com/sun/star/sheet/ComplexReference.hpp> 31 #include <com/sun/star/sheet/ExternalReference.hpp> 32 #include <com/sun/star/sheet/NamedRangeFlag.hpp> 33 #include <com/sun/star/sheet/ReferenceFlags.hpp> 34 #include <com/sun/star/sheet/SingleReference.hpp> 35 #include <com/sun/star/sheet/XFormulaTokens.hpp> 36 #include <com/sun/star/sheet/XPrintAreas.hpp> 37 #include <rtl/ustrbuf.hxx> 38 #include "oox/helper/attributelist.hxx" 39 #include "oox/helper/containerhelper.hxx" 40 #include "oox/helper/propertyset.hxx" 41 #include "oox/xls/addressconverter.hxx" 42 #include "oox/xls/biffinputstream.hxx" 43 #include "oox/xls/externallinkbuffer.hxx" 44 #include "oox/xls/formulaparser.hxx" 45 #include "oox/xls/worksheetbuffer.hxx" 46 47 namespace oox { 48 namespace xls { 49 50 // ============================================================================ 51 52 using namespace ::com::sun::star::sheet; 53 using namespace ::com::sun::star::table; 54 using namespace ::com::sun::star::uno; 55 56 using ::rtl::OUString; 57 using ::rtl::OUStringBuffer; 58 59 // ============================================================================ 60 61 namespace { 62 63 const sal_uInt32 BIFF12_DEFNAME_HIDDEN = 0x00000001; 64 const sal_uInt32 BIFF12_DEFNAME_FUNC = 0x00000002; 65 const sal_uInt32 BIFF12_DEFNAME_VBNAME = 0x00000004; 66 const sal_uInt32 BIFF12_DEFNAME_MACRO = 0x00000008; 67 const sal_uInt32 BIFF12_DEFNAME_CALCEXP = 0x00000010; 68 const sal_uInt32 BIFF12_DEFNAME_BUILTIN = 0x00000020; 69 const sal_uInt32 BIFF12_DEFNAME_PUBLISHED = 0x00008000; 70 const sal_uInt32 BIFF12_DEFNAME_WBPARAM = 0x00010000; 71 72 const sal_uInt16 BIFF_DEFNAME_HIDDEN = 0x0001; 73 const sal_uInt16 BIFF_DEFNAME_FUNC = 0x0002; 74 const sal_uInt16 BIFF_DEFNAME_VBNAME = 0x0004; 75 const sal_uInt16 BIFF_DEFNAME_MACRO = 0x0008; 76 const sal_uInt16 BIFF_DEFNAME_CALCEXP = 0x0010; 77 const sal_uInt16 BIFF_DEFNAME_BUILTIN = 0x0020; 78 const sal_uInt16 BIFF_DEFNAME_BIG = 0x1000; 79 80 const sal_uInt8 BIFF2_DEFNAME_FUNC = 0x02; /// BIFF2 function/command flag. 81 82 const sal_uInt16 BIFF_DEFNAME_GLOBAL = 0; /// 0 = Globally defined name. 83 84 const sal_uInt16 BIFF_REFFLAG_COL1REL = 0x0001; 85 const sal_uInt16 BIFF_REFFLAG_ROW1REL = 0x0002; 86 const sal_uInt16 BIFF_REFFLAG_COL2REL = 0x0004; 87 const sal_uInt16 BIFF_REFFLAG_ROW2REL = 0x0008; 88 89 // ---------------------------------------------------------------------------- 90 91 const sal_Char* const spcLegacyPrefix = "Excel_BuiltIn_"; 92 const sal_Char* const spcOoxPrefix = "_xlnm."; 93 94 const sal_Char* const sppcBaseNames[] = 95 { 96 "Consolidate_Area", 97 "Auto_Open", 98 "Auto_Close", 99 "Extract", 100 "Database", 101 "Criteria", 102 "Print_Area", 103 "Print_Titles", 104 "Recorder", 105 "Data_Form", 106 "Auto_Activate", 107 "Auto_Deactivate", 108 "Sheet_Title", 109 "_FilterDatabase" 110 }; 111 112 /** Localized names for _xlnm._FilterDatabase as used in BIFF5. */ 113 const sal_Char* const sppcFilterDbNames[] = 114 { 115 "_FilterDatabase", // English 116 "_FilterDatenbank" // German 117 }; 118 119 OUString lclGetBaseName( sal_Unicode cBuiltinId ) 120 { 121 OSL_ENSURE( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ), "lclGetBaseName - unsupported built-in identifier" ); 122 OUStringBuffer aBuffer; 123 if( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ) ) 124 aBuffer.appendAscii( sppcBaseNames[ cBuiltinId ] ); 125 else 126 aBuffer.append( static_cast< sal_Int32 >( cBuiltinId ) ); 127 return aBuffer.makeStringAndClear(); 128 } 129 130 OUString lclGetPrefixedName( sal_Unicode cBuiltinId ) 131 { 132 return OUStringBuffer().appendAscii( spcOoxPrefix ).append( lclGetBaseName( cBuiltinId ) ).makeStringAndClear(); 133 } 134 135 /** returns the built-in name identifier from a perfixed built-in name, e.g. '_xlnm.Print_Area'. */ 136 sal_Unicode lclGetBuiltinIdFromPrefixedName( const OUString& rModelName ) 137 { 138 OUString aPrefix = OUString::createFromAscii( spcOoxPrefix ); 139 sal_Int32 nPrefixLen = aPrefix.getLength(); 140 if( rModelName.matchIgnoreAsciiCase( aPrefix ) ) 141 { 142 for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId ) 143 { 144 OUString aBaseName = lclGetBaseName( cBuiltinId ); 145 sal_Int32 nBaseNameLen = aBaseName.getLength(); 146 if( (rModelName.getLength() == nPrefixLen + nBaseNameLen) && rModelName.matchIgnoreAsciiCase( aBaseName, nPrefixLen ) ) 147 return cBuiltinId; 148 } 149 } 150 return BIFF_DEFNAME_UNKNOWN; 151 } 152 153 /** returns the built-in name identifier from a built-in base name, e.g. 'Print_Area'. */ 154 sal_Unicode lclGetBuiltinIdFromBaseName( const OUString& rModelName ) 155 { 156 for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId ) 157 if( rModelName.equalsIgnoreAsciiCaseAscii( sppcBaseNames[ cBuiltinId ] ) ) 158 return cBuiltinId; 159 return BIFF_DEFNAME_UNKNOWN; 160 } 161 162 bool lclIsFilterDatabaseName( const OUString& rModelName ) 163 { 164 for( const sal_Char* const* ppcName = sppcFilterDbNames; ppcName < STATIC_ARRAY_END( sppcFilterDbNames ); ++ppcName ) 165 if( rModelName.equalsIgnoreAsciiCaseAscii( *ppcName ) ) 166 return true; 167 return false; 168 } 169 170 OUString lclGetUpcaseModelName( const OUString& rModelName ) 171 { 172 // TODO: i18n? 173 return rModelName.toAsciiUpperCase(); 174 } 175 176 void lclConvertRefFlags( sal_Int32& ornFlags, sal_Int32& ornAbsPos, sal_Int32& ornRelPos, sal_Int32 nBasePos, sal_Int32 nApiRelFlag, bool bRel ) 177 { 178 if( getFlag( ornFlags, nApiRelFlag ) && !bRel ) 179 { 180 // convert relative to absolute 181 setFlag( ornFlags, nApiRelFlag, false ); 182 ornAbsPos = nBasePos + ornRelPos; 183 } 184 else if( !getFlag( ornFlags, nApiRelFlag ) && bRel ) 185 { 186 // convert absolute to relative 187 setFlag( ornFlags, nApiRelFlag, true ); 188 ornRelPos = ornAbsPos - nBasePos; 189 } 190 } 191 192 void lclConvertSingleRefFlags( SingleReference& orApiRef, const CellAddress& rBaseAddr, bool bColRel, bool bRowRel ) 193 { 194 using namespace ::com::sun::star::sheet::ReferenceFlags; 195 lclConvertRefFlags( 196 orApiRef.Flags, orApiRef.Column, orApiRef.RelativeColumn, 197 rBaseAddr.Column, COLUMN_RELATIVE, bColRel ); 198 lclConvertRefFlags( 199 orApiRef.Flags, orApiRef.Row, orApiRef.RelativeRow, 200 rBaseAddr.Row, ROW_RELATIVE, bRowRel ); 201 } 202 203 Any lclConvertReference( const Any& rRefAny, const CellAddress& rBaseAddr, sal_uInt16 nRelFlags ) 204 { 205 if( rRefAny.has< SingleReference >() && !getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ) && !getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) ) 206 { 207 SingleReference aApiRef; 208 rRefAny >>= aApiRef; 209 lclConvertSingleRefFlags( aApiRef, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) ); 210 return Any( aApiRef ); 211 } 212 if( rRefAny.has< ComplexReference >() ) 213 { 214 ComplexReference aApiRef; 215 rRefAny >>= aApiRef; 216 lclConvertSingleRefFlags( aApiRef.Reference1, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) ); 217 lclConvertSingleRefFlags( aApiRef.Reference2, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) ); 218 return Any( aApiRef ); 219 } 220 return Any(); 221 } 222 223 } // namespace 224 225 // ============================================================================ 226 227 DefinedNameModel::DefinedNameModel() : 228 mnSheet( -1 ), 229 mnFuncGroupId( -1 ), 230 mbMacro( false ), 231 mbFunction( false ), 232 mbVBName( false ), 233 mbHidden( false ) 234 { 235 } 236 237 // ============================================================================ 238 239 DefinedNameBase::DefinedNameBase( const WorkbookHelper& rHelper ) : 240 WorkbookHelper( rHelper ) 241 { 242 } 243 244 const OUString& DefinedNameBase::getUpcaseModelName() const 245 { 246 if( maUpModelName.getLength() == 0 ) 247 maUpModelName = lclGetUpcaseModelName( maModel.maName ); 248 return maUpModelName; 249 } 250 251 Any DefinedNameBase::getReference( const CellAddress& rBaseAddr ) const 252 { 253 if( maRefAny.hasValue() && (maModel.maName.getLength() >= 2) && (maModel.maName[ 0 ] == '\x01') ) 254 { 255 sal_Unicode cFlagsChar = getUpcaseModelName()[ 1 ]; 256 if( ('A' <= cFlagsChar) && (cFlagsChar <= 'P') ) 257 { 258 sal_uInt16 nRelFlags = static_cast< sal_uInt16 >( cFlagsChar - 'A' ); 259 if( maRefAny.has< ExternalReference >() ) 260 { 261 ExternalReference aApiExtRef; 262 maRefAny >>= aApiExtRef; 263 Any aRefAny = lclConvertReference( aApiExtRef.Reference, rBaseAddr, nRelFlags ); 264 if( aRefAny.hasValue() ) 265 { 266 aApiExtRef.Reference <<= aRefAny; 267 return Any( aApiExtRef ); 268 } 269 } 270 else 271 { 272 return lclConvertReference( maRefAny, rBaseAddr, nRelFlags ); 273 } 274 } 275 } 276 return Any(); 277 } 278 279 ApiTokenSequence DefinedNameBase::importOoxFormula( sal_Int16 nBaseSheet ) 280 { 281 return (maModel.maFormula.getLength() > 0) ? 282 getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), maModel.maFormula ) : 283 getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME ); 284 } 285 286 ApiTokenSequence DefinedNameBase::importBiff12Formula( sal_Int16 nBaseSheet, SequenceInputStream& rStrm ) 287 { 288 return getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm ); 289 } 290 291 ApiTokenSequence DefinedNameBase::importBiffFormula( sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) 292 { 293 return (!pnFmlaSize || (*pnFmlaSize > 0)) ? 294 getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm, pnFmlaSize ) : 295 getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME ); 296 } 297 298 void DefinedNameBase::extractReference( const ApiTokenSequence& rTokens ) 299 { 300 OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "DefinedNameBase::extractReference - unexpected call" ); 301 maRefAny = getFormulaParser().extractReference( rTokens ); 302 } 303 304 // ============================================================================ 305 306 DefinedName::DefinedName( const WorkbookHelper& rHelper ) : 307 DefinedNameBase( rHelper ), 308 mnTokenIndex( -1 ), 309 mcBuiltinId( BIFF_DEFNAME_UNKNOWN ), 310 mnFmlaSize( 0 ) 311 { 312 } 313 314 void DefinedName::importDefinedName( const AttributeList& rAttribs ) 315 { 316 maModel.maName = rAttribs.getXString( XML_name, OUString() ); 317 maModel.mnSheet = rAttribs.getInteger( XML_localSheetId, -1 ); 318 maModel.mnFuncGroupId = rAttribs.getInteger( XML_functionGroupId, -1 ); 319 maModel.mbMacro = rAttribs.getBool( XML_xlm, false ); 320 maModel.mbFunction = rAttribs.getBool( XML_function, false ); 321 maModel.mbVBName = rAttribs.getBool( XML_vbProcedure, false ); 322 maModel.mbHidden = rAttribs.getBool( XML_hidden, false ); 323 mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1; 324 325 /* Detect built-in state from name itself, there is no built-in flag. 326 Built-in names are prexixed with '_xlnm.' instead. */ 327 mcBuiltinId = lclGetBuiltinIdFromPrefixedName( maModel.maName ); 328 } 329 330 void DefinedName::setFormula( const OUString& rFormula ) 331 { 332 maModel.maFormula = rFormula; 333 } 334 335 void DefinedName::importDefinedName( SequenceInputStream& rStrm ) 336 { 337 sal_uInt32 nFlags; 338 rStrm >> nFlags; 339 rStrm.skip( 1 ); // keyboard shortcut 340 rStrm >> maModel.mnSheet >> maModel.maName; 341 mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1; 342 343 // macro function/command, hidden flag 344 maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 9 ); 345 maModel.mbMacro = getFlag( nFlags, BIFF12_DEFNAME_MACRO ); 346 maModel.mbFunction = getFlag( nFlags, BIFF12_DEFNAME_FUNC ); 347 maModel.mbVBName = getFlag( nFlags, BIFF12_DEFNAME_VBNAME ); 348 maModel.mbHidden = getFlag( nFlags, BIFF12_DEFNAME_HIDDEN ); 349 350 // get built-in name index from name 351 if( getFlag( nFlags, BIFF12_DEFNAME_BUILTIN ) ) 352 mcBuiltinId = lclGetBuiltinIdFromBaseName( maModel.maName ); 353 354 // store token array data 355 sal_Int64 nRecPos = rStrm.tell(); 356 sal_Int32 nFmlaSize = rStrm.readInt32(); 357 rStrm.skip( nFmlaSize ); 358 sal_Int32 nAddDataSize = rStrm.readInt32(); 359 if( !rStrm.isEof() && (nFmlaSize > 0) && (nAddDataSize >= 0) && (rStrm.getRemaining() >= nAddDataSize) ) 360 { 361 sal_Int32 nTotalSize = 8 + nFmlaSize + nAddDataSize; 362 mxFormula.reset( new StreamDataSequence ); 363 rStrm.seek( nRecPos ); 364 rStrm.readData( *mxFormula, nTotalSize ); 365 } 366 } 367 368 void DefinedName::importDefinedName( BiffInputStream& rStrm, sal_Int16 nCalcSheet ) 369 { 370 BiffType eBiff = getBiff(); 371 sal_uInt16 nFlags = 0; 372 sal_Int16 nRefId = BIFF_DEFNAME_GLOBAL; 373 sal_Int16 nTabId = BIFF_DEFNAME_GLOBAL; 374 sal_uInt8 nNameLen = 0, nShortCut = 0; 375 376 switch( eBiff ) 377 { 378 case BIFF2: 379 { 380 sal_uInt8 nFlagsBiff2; 381 rStrm >> nFlagsBiff2; 382 rStrm.skip( 1 ); 383 rStrm >> nShortCut >> nNameLen; 384 mnFmlaSize = rStrm.readuInt8(); 385 setFlag( nFlags, BIFF_DEFNAME_FUNC, getFlag( nFlagsBiff2, BIFF2_DEFNAME_FUNC ) ); 386 maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true ); 387 } 388 break; 389 case BIFF3: 390 case BIFF4: 391 rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize; 392 maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true ); 393 break; 394 case BIFF5: 395 rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId; 396 rStrm.skip( 4 ); 397 maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true ); 398 break; 399 case BIFF8: 400 rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId; 401 rStrm.skip( 4 ); 402 maModel.maName = rStrm.readUniStringBody( nNameLen, true ); 403 break; 404 case BIFF_UNKNOWN: break; 405 } 406 407 // macro function/command, hidden flag 408 maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 6 ); 409 maModel.mbMacro = getFlag( nFlags, BIFF_DEFNAME_MACRO ); 410 maModel.mbFunction = getFlag( nFlags, BIFF_DEFNAME_FUNC ); 411 maModel.mbVBName = getFlag( nFlags, BIFF_DEFNAME_VBNAME ); 412 maModel.mbHidden = getFlag( nFlags, BIFF_DEFNAME_HIDDEN ); 413 414 // get built-in name index from name 415 if( getFlag( nFlags, BIFF_DEFNAME_BUILTIN ) ) 416 { 417 // name may be the built-in identifier or the built-in base name 418 if( maModel.maName.getLength() == 1 ) 419 mcBuiltinId = maModel.maName[ 0 ]; 420 else 421 mcBuiltinId = lclGetBuiltinIdFromBaseName( maModel.maName ); 422 } 423 /* In BIFF5, '_FilterDatabase' appears as hidden user name without 424 built-in flag, and even worse, localized. */ 425 else if( (eBiff == BIFF5) && lclIsFilterDatabaseName( maModel.maName ) ) 426 { 427 mcBuiltinId = BIFF_DEFNAME_FILTERDATABASE; 428 } 429 430 // get sheet index for sheet-local names in BIFF5-BIFF8 431 switch( getBiff() ) 432 { 433 case BIFF2: 434 case BIFF3: 435 case BIFF4: 436 // BIFF2-BIFF4: all defined names are sheet-local 437 mnCalcSheet = nCalcSheet; 438 break; 439 case BIFF5: 440 // #i44019# nTabId may be invalid, resolve nRefId to sheet index 441 if( nRefId != BIFF_DEFNAME_GLOBAL ) 442 if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() ) 443 if( pExtLink->getLinkType() == LINKTYPE_INTERNAL ) 444 mnCalcSheet = pExtLink->getCalcSheetIndex(); 445 break; 446 case BIFF8: 447 // convert one-based worksheet index to zero-based Calc sheet index 448 OSL_ENSURE( nTabId >= 0, "DefinedName::importDefinedName - invalid local sheet index" ); 449 if( nTabId != BIFF_DEFNAME_GLOBAL ) 450 mnCalcSheet = getWorksheets().getCalcSheetIndex( nTabId - 1 ); 451 break; 452 case BIFF_UNKNOWN: 453 break; 454 } 455 456 if( (getBiff() <= BIFF4) && maModel.mbHidden && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') ) 457 { 458 /* Read the token array of special internal names containing addresses 459 for BIFF3-BIFF4 3D references immediately. It is expected that 460 these names contain a simple cell reference or range reference. 461 Other regular defined names and external names rely on existence of 462 this reference. */ 463 ApiTokenSequence aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize ); 464 extractReference( aTokens ); 465 } 466 else 467 { 468 /* Store record position of other defined names to be able to import 469 token array later. This is needed to correctly resolve references 470 to names that are stored later in the defined names list following 471 this name. */ 472 mxBiffStrm.reset( new BiffInputStreamPos( rStrm ) ); 473 } 474 } 475 476 void DefinedName::createNameObject() 477 { 478 // do not create names for (macro) functions or VBA procedures 479 // #163146# do not ignore hidden names (may be regular names created by VBA scripts) 480 if( /*maModel.mbHidden ||*/ maModel.mbFunction || maModel.mbVBName ) 481 return; 482 483 // skip BIFF names without stream position (e.g. BIFF3-BIFF4 internal 3D references) 484 if( (getFilterType() == FILTER_BIFF) && !mxBiffStrm.get() ) 485 return; 486 487 // convert original name to final Calc name (TODO: filter invalid characters from model name) 488 maCalcName = isBuiltinName() ? lclGetPrefixedName( mcBuiltinId ) : maModel.maName; 489 490 // #163146# do not rename sheet-local names by default, this breaks VBA scripts 491 #if 0 492 // append sheet index for local names in multi-sheet documents 493 if( isWorkbookFile() && !isGlobalName() ) 494 maCalcName = OUStringBuffer( maCalcName ).append( sal_Unicode( '_' ) ). 495 append( static_cast< sal_Int32 >( mnCalcSheet + 1 ) ).makeStringAndClear(); 496 #endif 497 498 // special flags for this name 499 sal_Int32 nNameFlags = 0; 500 using namespace ::com::sun::star::sheet::NamedRangeFlag; 501 if( !isGlobalName() ) switch( mcBuiltinId ) 502 { 503 case BIFF_DEFNAME_CRITERIA: nNameFlags = FILTER_CRITERIA; break; 504 case BIFF_DEFNAME_PRINTAREA: nNameFlags = PRINT_AREA; break; 505 case BIFF_DEFNAME_PRINTTITLES: nNameFlags = COLUMN_HEADER | ROW_HEADER; break; 506 } 507 508 // create the name and insert it into the document, maCalcName will be changed to the resulting name 509 mxNamedRange = createNamedRangeObject( maCalcName, nNameFlags ); 510 // index of this defined name used in formula token arrays 511 PropertySet aPropSet( mxNamedRange ); 512 aPropSet.getProperty( mnTokenIndex, PROP_TokenIndex ); 513 } 514 515 void DefinedName::convertFormula() 516 { 517 Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY ); 518 if( !xTokens.is() ) 519 return; 520 521 // convert and set formula of the defined name 522 ApiTokenSequence aTokens; 523 switch( getFilterType() ) 524 { 525 case FILTER_OOXML: 526 { 527 if( mxFormula.get() ) 528 { 529 SequenceInputStream aStrm( *mxFormula ); 530 aTokens = importBiff12Formula( mnCalcSheet, aStrm ); 531 } 532 else 533 aTokens = importOoxFormula( mnCalcSheet ); 534 } 535 break; 536 case FILTER_BIFF: 537 { 538 OSL_ENSURE( mxBiffStrm.get(), "DefinedName::convertFormula - missing BIFF stream" ); 539 if( mxBiffStrm.get() ) 540 { 541 BiffInputStream& rStrm = mxBiffStrm->getStream(); 542 BiffInputStreamPosGuard aStrmGuard( rStrm ); 543 if( mxBiffStrm->restorePosition() ) 544 aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize ); 545 } 546 } 547 break; 548 case FILTER_UNKNOWN: 549 break; 550 } 551 xTokens->setTokens( aTokens ); 552 553 // set built-in names (print ranges, repeated titles, filter ranges) 554 if( !isGlobalName() ) switch( mcBuiltinId ) 555 { 556 case BIFF_DEFNAME_PRINTAREA: 557 { 558 Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY ); 559 ApiCellRangeList aPrintRanges; 560 getFormulaParser().extractCellRangeList( aPrintRanges, xTokens->getTokens(), false, mnCalcSheet ); 561 if( xPrintAreas.is() && !aPrintRanges.empty() ) 562 xPrintAreas->setPrintAreas( ContainerHelper::vectorToSequence( aPrintRanges ) ); 563 } 564 break; 565 case BIFF_DEFNAME_PRINTTITLES: 566 { 567 Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY ); 568 ApiCellRangeList aTitleRanges; 569 getFormulaParser().extractCellRangeList( aTitleRanges, xTokens->getTokens(), false, mnCalcSheet ); 570 if( xPrintAreas.is() && !aTitleRanges.empty() ) 571 { 572 bool bHasRowTitles = false; 573 bool bHasColTitles = false; 574 const CellAddress& rMaxPos = getAddressConverter().getMaxAddress(); 575 for( ApiCellRangeList::const_iterator aIt = aTitleRanges.begin(), aEnd = aTitleRanges.end(); (aIt != aEnd) && (!bHasRowTitles || !bHasColTitles); ++aIt ) 576 { 577 bool bFullRow = (aIt->StartColumn == 0) && (aIt->EndColumn >= rMaxPos.Column); 578 bool bFullCol = (aIt->StartRow == 0) && (aIt->EndRow >= rMaxPos.Row); 579 if( !bHasRowTitles && bFullRow && !bFullCol ) 580 { 581 xPrintAreas->setTitleRows( *aIt ); 582 xPrintAreas->setPrintTitleRows( sal_True ); 583 bHasRowTitles = true; 584 } 585 else if( !bHasColTitles && bFullCol && !bFullRow ) 586 { 587 xPrintAreas->setTitleColumns( *aIt ); 588 xPrintAreas->setPrintTitleColumns( sal_True ); 589 bHasColTitles = true; 590 } 591 } 592 } 593 } 594 break; 595 } 596 } 597 598 bool DefinedName::getAbsoluteRange( CellRangeAddress& orRange ) const 599 { 600 /* ScNamedRangeObj::XCellRangeReferrer::getReferredCells is buggy with 601 relative references, so we extract an absolute reference by hand. */ 602 Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY ); 603 return xTokens.is() && getFormulaParser().extractCellRange( orRange, xTokens->getTokens(), false ); 604 } 605 606 // ============================================================================ 607 608 DefinedNamesBuffer::DefinedNamesBuffer( const WorkbookHelper& rHelper ) : 609 WorkbookHelper( rHelper ), 610 mnCalcSheet( -1 ) 611 { 612 } 613 614 void DefinedNamesBuffer::setLocalCalcSheet( sal_Int16 nCalcSheet ) 615 { 616 OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), 617 "DefinedNamesBuffer::setLocalCalcSheet - invalid call" ); 618 mnCalcSheet = nCalcSheet; 619 } 620 621 DefinedNameRef DefinedNamesBuffer::importDefinedName( const AttributeList& rAttribs ) 622 { 623 DefinedNameRef xDefName = createDefinedName(); 624 xDefName->importDefinedName( rAttribs ); 625 return xDefName; 626 } 627 628 void DefinedNamesBuffer::importDefinedName( SequenceInputStream& rStrm ) 629 { 630 createDefinedName()->importDefinedName( rStrm ); 631 } 632 633 void DefinedNamesBuffer::importDefinedName( BiffInputStream& rStrm ) 634 { 635 createDefinedName()->importDefinedName( rStrm, mnCalcSheet ); 636 } 637 638 void DefinedNamesBuffer::finalizeImport() 639 { 640 // first insert all names without formula definition into the document, and insert them into the maps 641 for( DefNameVector::iterator aIt = maDefNames.begin(), aEnd = maDefNames.end(); aIt != aEnd; ++aIt ) 642 { 643 DefinedNameRef xDefName = *aIt; 644 xDefName->createNameObject(); 645 // map by sheet index and original model name 646 maModelNameMap[ SheetNameKey( xDefName->getLocalCalcSheet(), xDefName->getUpcaseModelName() ) ] = xDefName; 647 // map by sheet index and built-in identifier 648 if( !xDefName->isGlobalName() && xDefName->isBuiltinName() ) 649 maBuiltinMap[ BuiltinKey( xDefName->getLocalCalcSheet(), xDefName->getBuiltinId() ) ] = xDefName; 650 // map by API formula token identifier 651 sal_Int32 nTokenIndex = xDefName->getTokenIndex(); 652 if( nTokenIndex >= 0 ) 653 maTokenIdMap[ nTokenIndex ] = xDefName; 654 } 655 656 /* Now convert all name formulas, so that the formula parser can find all 657 names in case of circular dependencies. */ 658 maDefNames.forEachMem( &DefinedName::convertFormula ); 659 } 660 661 DefinedNameRef DefinedNamesBuffer::getByIndex( sal_Int32 nIndex ) const 662 { 663 return maDefNames.get( nIndex ); 664 } 665 666 DefinedNameRef DefinedNamesBuffer::getByTokenIndex( sal_Int32 nIndex ) const 667 { 668 return maTokenIdMap.get( nIndex ); 669 } 670 671 DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, sal_Int16 nCalcSheet ) const 672 { 673 OUString aUpcaseName = lclGetUpcaseModelName( rModelName ); 674 DefinedNameRef xDefName = maModelNameMap.get( SheetNameKey( nCalcSheet, aUpcaseName ) ); 675 // lookup global name, if no local name exists 676 if( !xDefName && (nCalcSheet >= 0) ) 677 xDefName = maModelNameMap.get( SheetNameKey( -1, aUpcaseName ) ); 678 return xDefName; 679 } 680 681 DefinedNameRef DefinedNamesBuffer::getByBuiltinId( sal_Unicode cBuiltinId, sal_Int16 nCalcSheet ) const 682 { 683 return maBuiltinMap.get( BuiltinKey( nCalcSheet, cBuiltinId ) ); 684 } 685 686 DefinedNameRef DefinedNamesBuffer::createDefinedName() 687 { 688 DefinedNameRef xDefName( new DefinedName( *this ) ); 689 maDefNames.push_back( xDefName ); 690 return xDefName; 691 } 692 693 // ============================================================================ 694 695 } // namespace xls 696 } // namespace oox 697