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