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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmloff.hxx" 30 #include <tools/debug.hxx> 31 #include <rtl/ustring.hxx> 32 #include <rtl/ustrbuf.hxx> 33 34 #ifndef _XMLTOKEN_HXX 35 #include <xmloff/xmltoken.hxx> 36 #endif 37 #include <xmloff/nmspmap.hxx> 38 39 #include "xmloff/xmlnmspe.hxx" 40 41 42 using ::rtl::OUString; 43 using ::rtl::OUStringBuffer; 44 using namespace ::xmloff::token; 45 46 /* The basic idea of this class is that we have two two ways to search our 47 * data...by prefix and by key. We use an STL hash_map for fast prefix 48 * searching and an STL map for fast key searching. 49 * 50 * The references to an 'Index' refer to an earlier implementation of the 51 * name space map and remain to support code which uses these interfaces. 52 * 53 * In this implementation, key and index should always be the same number. 54 * 55 * All references to Indices are now deprecated and the corresponding 56 * 'Key' methods should be used instead 57 * 58 * Martin 13/06/01 59 */ 60 61 SvXMLNamespaceMap::SvXMLNamespaceMap() 62 : sXMLNS( GetXMLToken ( XML_XMLNS ) ) 63 { 64 } 65 66 SvXMLNamespaceMap::SvXMLNamespaceMap( const SvXMLNamespaceMap& rMap ) 67 : sXMLNS( GetXMLToken ( XML_XMLNS ) ) 68 { 69 aNameHash = rMap.aNameHash; 70 aNameMap = rMap.aNameMap; 71 } 72 73 void SvXMLNamespaceMap::operator=( const SvXMLNamespaceMap& rMap ) 74 { 75 aNameHash = rMap.aNameHash; 76 aNameMap = rMap.aNameMap; 77 } 78 79 SvXMLNamespaceMap::~SvXMLNamespaceMap() 80 { 81 QNameCache::iterator aIter = aQNameCache.begin(), aEnd = aQNameCache.end(); 82 while ( aIter != aEnd ) 83 { 84 const OUString *pString = (*aIter).first.second; 85 aIter++; 86 delete pString; 87 } 88 } 89 90 int SvXMLNamespaceMap::operator ==( const SvXMLNamespaceMap& rCmp ) const 91 { 92 return static_cast < int > (aNameHash == rCmp.aNameHash); 93 } 94 95 sal_uInt16 SvXMLNamespaceMap::_Add( const OUString& rPrefix, const OUString &rName, sal_uInt16 nKey ) 96 { 97 if( XML_NAMESPACE_UNKNOWN == nKey ) 98 { 99 // create a new unique key with UNKNOWN flag set 100 nKey = XML_NAMESPACE_UNKNOWN_FLAG; 101 do 102 { 103 NameSpaceMap::const_iterator aIter = aNameMap.find ( nKey ); 104 if( aIter == aNameMap.end() ) 105 break; 106 nKey++; 107 } 108 while ( sal_True ); 109 } 110 ::vos::ORef<NameSpaceEntry> pEntry(new NameSpaceEntry); 111 pEntry->sName = rName; 112 pEntry->nKey = nKey; 113 pEntry->sPrefix = rPrefix; 114 aNameHash[ rPrefix ] = pEntry; 115 aNameMap [ nKey ] = pEntry; 116 return nKey; 117 } 118 119 sal_uInt16 SvXMLNamespaceMap::Add( const OUString& rPrefix, const OUString& rName, 120 sal_uInt16 nKey ) 121 { 122 if( XML_NAMESPACE_UNKNOWN == nKey ) 123 nKey = GetKeyByName( rName ); 124 125 DBG_ASSERT( XML_NAMESPACE_NONE != nKey, 126 "SvXMLNamespaceMap::Add: invalid namespace key" ); 127 128 if( XML_NAMESPACE_NONE == nKey ) 129 return USHRT_MAX; 130 131 if ( aNameHash.find ( rPrefix ) == aNameHash.end() ) 132 nKey = _Add( rPrefix, rName, nKey ); 133 134 return nKey; 135 } 136 137 sal_uInt16 SvXMLNamespaceMap::AddIfKnown( const OUString& rPrefix, const OUString& rName ) 138 { 139 sal_uInt16 nKey = GetKeyByName( rName ); 140 141 DBG_ASSERT( XML_NAMESPACE_NONE != nKey, 142 "SvXMLNamespaceMap::AddIfKnown: invalid namespace key" ); 143 144 if( XML_NAMESPACE_NONE == nKey ) 145 return XML_NAMESPACE_UNKNOWN; 146 147 if( XML_NAMESPACE_UNKNOWN != nKey ) 148 { 149 NameSpaceHash::const_iterator aIter = aNameHash.find( rPrefix ); 150 if( aIter == aNameHash.end() || (*aIter).second->sName != rName ) 151 nKey = _Add( rPrefix, rName, nKey ); 152 } 153 154 return nKey; 155 } 156 157 158 sal_uInt16 SvXMLNamespaceMap::GetKeyByPrefix( const OUString& rPrefix ) const 159 { 160 NameSpaceHash::const_iterator aIter = aNameHash.find(rPrefix); 161 return (aIter != aNameHash.end()) ? (*aIter).second->nKey : USHRT_MAX; 162 } 163 164 sal_uInt16 SvXMLNamespaceMap::GetKeyByName( const OUString& rName ) const 165 { 166 sal_uInt16 nKey = XML_NAMESPACE_UNKNOWN; 167 NameSpaceHash::const_iterator aIter = aNameHash.begin(), aEnd = aNameHash.end(); 168 while (aIter != aEnd ) 169 { 170 if ((*aIter).second->sName == rName) 171 { 172 nKey = (*aIter).second->nKey; 173 break; 174 } 175 aIter++; 176 } 177 return nKey; 178 } 179 180 const OUString& SvXMLNamespaceMap::GetPrefixByKey( sal_uInt16 nKey ) const 181 { 182 NameSpaceMap::const_iterator aIter = aNameMap.find (nKey); 183 return (aIter != aNameMap.end()) ? (*aIter).second->sPrefix : sEmpty; 184 } 185 186 const OUString& SvXMLNamespaceMap::GetNameByKey( sal_uInt16 nKey ) const 187 { 188 NameSpaceMap::const_iterator aIter = aNameMap.find (nKey); 189 return (aIter != aNameMap.end()) ? (*aIter).second->sName : sEmpty; 190 } 191 192 OUString SvXMLNamespaceMap::GetAttrNameByKey( sal_uInt16 nKey ) const 193 { 194 OUStringBuffer sAttrName; 195 NameSpaceMap::const_iterator aIter = aNameMap.find ( nKey ); 196 if (aIter != aNameMap.end()) 197 { 198 sAttrName.append( sXMLNS ); 199 const ::rtl::OUString & prefix( (*aIter).second->sPrefix ); 200 if (prefix.getLength()) // not default namespace 201 { 202 sAttrName.append( sal_Unicode(':') ); 203 sAttrName.append( prefix ); 204 } 205 } 206 return sAttrName.makeStringAndClear(); 207 } 208 209 OUString SvXMLNamespaceMap::GetQNameByKey( sal_uInt16 nKey, 210 const OUString& rLocalName, 211 sal_Bool bCache) const 212 { 213 // We always want to return at least the rLocalName... 214 215 switch ( nKey ) 216 { 217 case XML_NAMESPACE_UNKNOWN: 218 // ...if it's a completely unknown namespace, assert and return the local name 219 DBG_ASSERT( sal_False, "SvXMLNamespaceMap::GetQNameByKey: invalid namespace key" ); 220 case XML_NAMESPACE_NONE: 221 // ...if there isn't one, return the local name 222 return rLocalName; 223 case XML_NAMESPACE_XMLNS: 224 { 225 // ...if it's in the xmlns namespace, make the prefix 226 // don't bother caching this, it rarely happens 227 OUStringBuffer sQName; 228 sQName.append ( sXMLNS ); 229 if (rLocalName.getLength()) // not default namespace 230 { 231 sQName.append ( sal_Unicode(':') ); 232 sQName.append ( rLocalName ); 233 } 234 return sQName.makeStringAndClear();; 235 } 236 case XML_NAMESPACE_XML: 237 { 238 // this namespace is reserved, and needs not to be declared 239 OUStringBuffer sQName; 240 sQName.append ( GetXMLToken(XML_XML) ); 241 sQName.append ( sal_Unicode(':') ); 242 sQName.append ( rLocalName ); 243 return sQName.makeStringAndClear();; 244 } 245 default: 246 { 247 QNameCache::const_iterator aQCacheIter; 248 if (bCache) 249 aQCacheIter = aQNameCache.find ( QNamePair ( nKey, &rLocalName ) ); 250 else 251 aQCacheIter = aQNameCache.end(); 252 if ( aQCacheIter != aQNameCache.end() ) 253 return (*aQCacheIter).second; 254 else 255 { 256 NameSpaceMap::const_iterator aIter = aNameMap.find ( nKey ); 257 if ( aIter != aNameMap.end() ) 258 { 259 OUStringBuffer sQName; 260 // ...if it's in our map, make the prefix 261 const OUString & prefix( (*aIter).second->sPrefix ); 262 if (prefix.getLength()) // not default namespace 263 { 264 sQName.append( prefix ); 265 sQName.append( sal_Unicode(':') ); 266 } 267 sQName.append ( rLocalName ); 268 if (bCache) 269 { 270 OUString sString(sQName.makeStringAndClear()); 271 OUString *pString = new OUString ( rLocalName ); 272 const_cast < QNameCache * > (&aQNameCache)->operator[] ( QNamePair ( nKey, pString ) ) = sString; 273 return sString; 274 } 275 else 276 return sQName.makeStringAndClear(); 277 } 278 else 279 { 280 // ... if it isn't, this is a Bad Thing, assert and return the local name 281 DBG_ASSERT( sal_False, "SvXMLNamespaceMap::GetQNameByKey: invalid namespace key" ); 282 return rLocalName; 283 } 284 } 285 } 286 } 287 } 288 289 sal_uInt16 SvXMLNamespaceMap::_GetKeyByAttrName( 290 const OUString& rAttrName, 291 OUString *pLocalName, 292 sal_Bool bCache) const 293 { 294 return _GetKeyByAttrName( rAttrName, 0, pLocalName, 0, bCache ); 295 } 296 297 sal_uInt16 SvXMLNamespaceMap::_GetKeyByAttrName( const OUString& rAttrName, 298 OUString *pPrefix, 299 OUString *pLocalName, 300 OUString *pNamespace, 301 sal_Bool bCache) const 302 { 303 sal_uInt16 nKey = XML_NAMESPACE_UNKNOWN; 304 305 NameSpaceHash::const_iterator it; 306 if (bCache) 307 it = aNameCache.find ( rAttrName ); 308 else 309 it = aNameCache.end(); 310 if ( it != aNameCache.end() ) 311 { 312 const NameSpaceEntry &rEntry = (*it).second.getBody(); 313 if ( pPrefix ) 314 *pPrefix = rEntry.sPrefix; 315 if ( pLocalName ) 316 *pLocalName = rEntry.sName; 317 nKey = rEntry.nKey; 318 if ( pNamespace ) 319 { 320 NameSpaceMap::const_iterator aMapIter = aNameMap.find (nKey); 321 *pNamespace = aMapIter != aNameMap.end() ? (*aMapIter).second->sName : sEmpty; 322 } 323 } 324 else 325 { 326 vos::ORef<NameSpaceEntry> xEntry(new NameSpaceEntry()); 327 328 sal_Int32 nColonPos = rAttrName.indexOf( sal_Unicode(':') ); 329 if( -1L == nColonPos ) 330 { 331 // case: no ':' found -> default namespace 332 xEntry->sPrefix = OUString(); 333 xEntry->sName = rAttrName; 334 } 335 else 336 { 337 // normal case: ':' found -> get prefix/suffix 338 xEntry->sPrefix = rAttrName.copy( 0L, nColonPos ); 339 xEntry->sName = rAttrName.copy( nColonPos + 1L ); 340 } 341 342 if( pPrefix ) 343 *pPrefix = xEntry->sPrefix; 344 if( pLocalName ) 345 *pLocalName = xEntry->sName; 346 347 NameSpaceHash::const_iterator aIter = aNameHash.find( xEntry->sPrefix ); 348 if ( aIter != aNameHash.end() ) 349 { 350 // found: retrieve namespace key 351 nKey = xEntry->nKey = (*aIter).second->nKey; 352 if ( pNamespace ) 353 *pNamespace = (*aIter).second->sName; 354 } 355 else if ( xEntry->sPrefix == sXMLNS ) 356 // not found, but xmlns prefix: return xmlns 'namespace' 357 nKey = xEntry->nKey = XML_NAMESPACE_XMLNS; 358 else if( nColonPos == -1L ) 359 // not found, and no namespace: 'namespace' none 360 nKey = xEntry->nKey = XML_NAMESPACE_NONE; 361 362 if (bCache) 363 { 364 typedef std::pair< const rtl::OUString, vos::ORef<NameSpaceEntry> > value_type; 365 (void) const_cast<NameSpaceHash*>(&aNameCache)->insert (value_type (rAttrName, xEntry)); 366 } 367 } 368 369 return nKey; 370 } 371 372 sal_uInt16 SvXMLNamespaceMap::GetFirstKey() const 373 { 374 return aNameMap.empty() ? USHRT_MAX : (*aNameMap.begin()).second->nKey; 375 } 376 377 sal_uInt16 SvXMLNamespaceMap::GetNextKey( sal_uInt16 nLastKey ) const 378 { 379 NameSpaceMap::const_iterator aIter = aNameMap.find ( nLastKey ); 380 return (++aIter == aNameMap.end()) ? USHRT_MAX : (*aIter).second->nKey; 381 } 382 383 384 // All methods after this are deprecated... 385 386 sal_uInt16 SvXMLNamespaceMap::GetKeyByIndex( sal_uInt16 nIdx ) const 387 { 388 return nIdx; 389 } 390 391 sal_uInt16 SvXMLNamespaceMap::GetIndexByKey( sal_uInt16 nKey ) const 392 { 393 return nKey; 394 } 395 sal_uInt16 SvXMLNamespaceMap::GetFirstIndex() const 396 { 397 return aNameMap.empty() ? USHRT_MAX : (*aNameMap.begin()).second->nKey; 398 } 399 400 sal_uInt16 SvXMLNamespaceMap::GetNextIndex( sal_uInt16 nOldIdx ) const 401 { 402 NameSpaceMap::const_iterator aIter = aNameMap.find ( nOldIdx ); 403 return (++aIter == aNameMap.end()) ? USHRT_MAX : (*aIter).second->nKey; 404 } 405 406 sal_Bool SvXMLNamespaceMap::AddAtIndex( sal_uInt16 /*nIdx*/, const OUString& rPrefix, 407 const OUString& rName, sal_uInt16 nKey ) 408 { 409 sal_Bool bRet = sal_False; 410 411 if( XML_NAMESPACE_UNKNOWN == nKey ) 412 nKey = GetKeyByName( rName ); 413 414 DBG_ASSERT( XML_NAMESPACE_NONE != nKey, 415 "SvXMLNamespaceMap::AddAtIndex: invalid namespace key" ); 416 if( XML_NAMESPACE_NONE != nKey && ! ( aNameHash.count ( rPrefix ) ) ) 417 { 418 _Add( rPrefix, rName, nKey ); 419 bRet = sal_True; 420 } 421 return bRet; 422 } 423 424 sal_Bool SvXMLNamespaceMap::AddAtIndex( sal_uInt16 nIdx, const sal_Char *pPrefix, 425 const sal_Char *pName, sal_uInt16 nKey ) 426 { 427 OUString sPrefix( OUString::createFromAscii(pPrefix) ); 428 OUString sName( OUString::createFromAscii(pName) ); 429 430 return AddAtIndex( nIdx, sPrefix, sName, nKey ); 431 } 432 433 OUString SvXMLNamespaceMap::GetAttrNameByIndex( sal_uInt16 nIdx ) const 434 { 435 return GetAttrNameByKey( nIdx ); 436 } 437 438 OUString SvXMLNamespaceMap::GetQNameByIndex( sal_uInt16 nIdx, 439 const OUString& rLocalName ) const 440 { 441 return GetQNameByKey( nIdx, rLocalName ); 442 } 443 444 const OUString& SvXMLNamespaceMap::GetPrefixByIndex( sal_uInt16 nIdx ) const 445 { 446 NameSpaceMap::const_iterator aIter = aNameMap.find (nIdx); 447 return (aIter != aNameMap.end()) ? (*aIter).second->sPrefix : sEmpty; 448 } 449 450 const OUString& SvXMLNamespaceMap::GetNameByIndex( sal_uInt16 nIdx ) const 451 { 452 NameSpaceMap::const_iterator aIter = aNameMap.find (nIdx); 453 return (aIter != aNameMap.end()) ? (*aIter).second->sName : sEmpty; 454 } 455 456 sal_uInt16 SvXMLNamespaceMap::GetIndexByPrefix( const OUString& rPrefix ) const 457 { 458 NameSpaceHash::const_iterator aIter = aNameHash.find(rPrefix); 459 return (aIter != aNameHash.end()) ? (*aIter).second->nKey : USHRT_MAX; 460 } 461 sal_uInt16 SvXMLNamespaceMap::GetKeyByAttrName( 462 const OUString& rAttrName, 463 OUString *pLocalName, 464 sal_uInt16 /*nIdxGuess*/) const 465 { 466 return _GetKeyByAttrName( rAttrName, 0, pLocalName, 0 ); 467 } 468 469 sal_uInt16 SvXMLNamespaceMap::GetKeyByAttrName( const OUString& rAttrName, 470 OUString *pPrefix, 471 OUString *pLocalName, 472 OUString *pNamespace, 473 sal_uInt16 /*nIdxGuess*/ ) const 474 { 475 return _GetKeyByAttrName ( rAttrName, pPrefix, pLocalName, pNamespace ); 476 } 477 478 sal_Bool SvXMLNamespaceMap::NormalizeURI( ::rtl::OUString& rName ) 479 { 480 // try OASIS + W3 URI normalization 481 sal_Bool bSuccess = NormalizeOasisURN( rName ); 482 if( ! bSuccess ) 483 bSuccess = NormalizeW3URI( rName ); 484 return bSuccess; 485 } 486 487 sal_Bool SvXMLNamespaceMap::NormalizeW3URI( ::rtl::OUString& rName ) 488 { 489 // check if URI matches: 490 // http://www.w3.org/[0-9]*/[:letter:]* 491 // (year)/(WG name) 492 // For the following WG/standards names: 493 // - xforms 494 495 sal_Bool bSuccess = sal_False; 496 const OUString sURIPrefix = GetXMLToken( XML_URI_W3_PREFIX ); 497 if( rName.compareTo( sURIPrefix, sURIPrefix.getLength() ) == 0 ) 498 { 499 const OUString sURISuffix = GetXMLToken( XML_URI_XFORMS_SUFFIX ); 500 sal_Int32 nCompareFrom = rName.getLength() - sURISuffix.getLength(); 501 if( rName.copy( nCompareFrom ).equals( sURISuffix ) ) 502 { 503 // found W3 prefix, and xforms suffix 504 rName = GetXMLToken( XML_N_XFORMS_1_0 ); 505 bSuccess = sal_True; 506 } 507 } 508 return bSuccess; 509 } 510 511 sal_Bool SvXMLNamespaceMap::NormalizeOasisURN( ::rtl::OUString& rName ) 512 { 513 // #i38644# 514 // we exported the wrong namespace for smil, so we correct this here on load 515 // for older documents 516 if( IsXMLToken( rName, ::xmloff::token::XML_N_SVG ) ) 517 { 518 rName = GetXMLToken( ::xmloff::token::XML_N_SVG_COMPAT ); 519 return sal_True; 520 } 521 else if( IsXMLToken( rName, ::xmloff::token::XML_N_FO ) ) 522 { 523 rName = GetXMLToken( ::xmloff::token::XML_N_FO_COMPAT ); 524 return sal_True; 525 } 526 else if( IsXMLToken( rName, ::xmloff::token::XML_N_SMIL ) || 527 IsXMLToken( rName, ::xmloff::token::XML_N_SMIL_OLD ) ) 528 { 529 rName = GetXMLToken( ::xmloff::token::XML_N_SMIL_COMPAT ); 530 return sal_True; 531 } 532 533 // 534 // Check if URN matches 535 // :urn:oasis:names:tc:[^:]*:xmlns:[^:]*:1.[^:]* 536 // |---| |---| |-----| 537 // TC-Id Sub-Id Version 538 539 sal_Int32 nNameLen = rName.getLength(); 540 // :urn:oasis:names:tc.* 541 const OUString& rOasisURN = GetXMLToken( XML_URN_OASIS_NAMES_TC ); 542 if( 0 != rName.compareTo( rOasisURN, rOasisURN.getLength() ) ) 543 return sal_False; 544 545 // :urn:oasis:names:tc:.* 546 sal_Int32 nPos = rOasisURN.getLength(); 547 if( nPos >= nNameLen || rName[nPos] != ':' ) 548 return sal_False; 549 550 // :urn:oasis:names:tc:[^:]:.* 551 sal_Int32 nTCIdStart = nPos+1; 552 sal_Int32 nTCIdEnd = rName.indexOf( ':', nTCIdStart ); 553 if( -1 == nTCIdEnd ) 554 return sal_False; 555 556 // :urn:oasis:names:tc:[^:]:xmlns.* 557 nPos = nTCIdEnd + 1; 558 OUString sTmp( rName.copy( nPos ) ); 559 const OUString& rXMLNS = GetXMLToken( XML_XMLNS ); 560 if( 0!= sTmp.compareTo( rXMLNS, rXMLNS.getLength() ) ) 561 return sal_False; 562 563 // :urn:oasis:names:tc:[^:]:xmlns:.* 564 nPos += rXMLNS.getLength(); 565 if( nPos >= nNameLen || rName[nPos] != ':' ) 566 return sal_False; 567 568 // :urn:oasis:names:tc:[^:]:xmlns:[^:]*:.* 569 nPos = rName.indexOf( ':', nPos+1 ); 570 if( -1 == nPos ) 571 return sal_False; 572 573 // :urn:oasis:names:tc:[^:]:xmlns:[^:]*:[^:][^:][^:][^:]* 574 sal_Int32 nVersionStart = nPos+1; 575 if( nVersionStart+2 >= nNameLen || 576 -1 != rName.indexOf( ':', nVersionStart ) ) 577 return sal_False; 578 579 // :urn:oasis:names:tc:[^:]:xmlns:[^:]*:1\.[^:][^:]* 580 if( rName[nVersionStart] != '1' || rName[nVersionStart+1] != '.' ) 581 return sal_False; 582 583 // replace [tcid] with current TCID and version with current version. 584 OUStringBuffer aNewName( nNameLen +20 ); 585 aNewName.append( rName.copy( 0, nTCIdStart ) ); 586 aNewName.append( GetXMLToken( XML_OPENDOCUMENT ) ); 587 aNewName.append( rName.copy( nTCIdEnd, nVersionStart-nTCIdEnd ) ); 588 aNewName.append( GetXMLToken( XML_1_0 ) ); 589 590 rName = aNewName.makeStringAndClear(); 591 592 return sal_True; 593 } 594