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