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 "precompiled_sd.hxx" 25 26 #include "framework/ResourceId.hxx" 27 #include "framework/FrameworkHelper.hxx" 28 #include "tools/SdGlobalResourceContainer.hxx" 29 #include <com/sun/star/lang/IllegalArgumentException.hpp> 30 #include <com/sun/star/uno/XComponentContext.hpp> 31 #include <comphelper/processfactory.hxx> 32 #include <rtl/ref.hxx> 33 34 using namespace ::com::sun::star; 35 using namespace ::com::sun::star::uno; 36 using namespace ::com::sun::star::lang; 37 using namespace ::com::sun::star::drawing::framework; 38 using ::rtl::OUString; 39 40 /** When the USE_OPTIMIZATIONS symbol is defined then at some optimizations 41 are activated that work only together with XResourceId objects that are 42 implemented by the ResourceId class. For other implementations of when 43 the USE_OPTIMIZATIONS symbol is not defined then alternative code is 44 used instead. 45 */ 46 #define USE_OPTIMIZATIONS 47 48 namespace sd { namespace framework { 49 50 Reference<XInterface> SAL_CALL ResourceId_createInstance ( 51 const Reference<XComponentContext>& rxContext) 52 { 53 (void)rxContext; 54 return Reference<XInterface>(static_cast<XWeak*>(new ::sd::framework::ResourceId())); 55 } 56 57 58 59 60 ::rtl::OUString ResourceId_getImplementationName (void) throw(RuntimeException) 61 { 62 return ::rtl::OUString( 63 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Draw.framework.ResourceId")); 64 } 65 66 67 68 69 Sequence<rtl::OUString> SAL_CALL ResourceId_getSupportedServiceNames (void) 70 throw (RuntimeException) 71 { 72 static const ::rtl::OUString sServiceName( 73 ::rtl::OUString::createFromAscii("com.sun.star.drawing.framework.ResourceId")); 74 return Sequence<rtl::OUString>(&sServiceName, 1); 75 } 76 77 78 79 80 //===== ResourceId ============================================================ 81 82 WeakReference<util::XURLTransformer> ResourceId::mxURLTransformerWeak; 83 84 ResourceId::ResourceId (void) 85 : ResourceIdInterfaceBase(), 86 maResourceURLs(0), 87 mpURL() 88 { 89 } 90 91 92 93 94 ResourceId::ResourceId ( 95 const std::vector<OUString>& rResourceURLs) 96 : ResourceIdInterfaceBase(), 97 maResourceURLs(rResourceURLs), 98 mpURL() 99 { 100 ParseResourceURL(); 101 } 102 103 104 105 106 ResourceId::ResourceId ( 107 const OUString& rsResourceURL) 108 : ResourceIdInterfaceBase(), 109 maResourceURLs(1, rsResourceURL), 110 mpURL() 111 { 112 // Handle the special case of an empty resource URL. 113 if (rsResourceURL.getLength() == 0) 114 maResourceURLs.clear(); 115 ParseResourceURL(); 116 } 117 118 119 120 121 ResourceId::ResourceId ( 122 const OUString& rsResourceURL, 123 const OUString& rsAnchorURL) 124 : ResourceIdInterfaceBase(), 125 maResourceURLs(2), 126 mpURL() 127 { 128 maResourceURLs[0] = rsResourceURL; 129 maResourceURLs[1] = rsAnchorURL; 130 ParseResourceURL(); 131 } 132 133 134 135 136 ResourceId::ResourceId ( 137 const OUString& rsResourceURL, 138 const ::std::vector<OUString>& rAnchorURLs) 139 : ResourceIdInterfaceBase(), 140 maResourceURLs(1+rAnchorURLs.size()), 141 mpURL() 142 { 143 maResourceURLs[0] = rsResourceURL; 144 for (sal_uInt32 nIndex=0; nIndex<rAnchorURLs.size(); ++nIndex) 145 maResourceURLs[nIndex+1] = rAnchorURLs[nIndex]; 146 ParseResourceURL(); 147 } 148 149 150 151 152 ResourceId::ResourceId ( 153 const OUString& rsResourceURL, 154 const OUString& rsFirstAnchorURL, 155 const Sequence<OUString>& rAnchorURLs) 156 : ResourceIdInterfaceBase(), 157 maResourceURLs(2+rAnchorURLs.getLength()), 158 mpURL() 159 { 160 maResourceURLs[0] = rsResourceURL; 161 maResourceURLs[1] = rsFirstAnchorURL; 162 for (sal_Int32 nIndex=0; nIndex<rAnchorURLs.getLength(); ++nIndex) 163 maResourceURLs[nIndex+2] = rAnchorURLs[nIndex]; 164 ParseResourceURL(); 165 } 166 167 168 169 170 ResourceId::~ResourceId (void) 171 { 172 mpURL.reset(); 173 } 174 175 176 177 178 OUString SAL_CALL 179 ResourceId::getResourceURL (void) 180 throw(com::sun::star::uno::RuntimeException) 181 { 182 if (!maResourceURLs.empty()) 183 return maResourceURLs[0]; 184 else 185 return OUString(); 186 } 187 188 189 190 191 util::URL SAL_CALL 192 ResourceId::getFullResourceURL (void) 193 throw(com::sun::star::uno::RuntimeException) 194 { 195 if (mpURL.get() != NULL) 196 return *mpURL; 197 198 Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak); 199 if (xURLTransformer.is() && !maResourceURLs.empty() ) 200 { 201 mpURL.reset(new util::URL); 202 mpURL->Complete = maResourceURLs[0]; 203 xURLTransformer->parseStrict(*mpURL); 204 return *mpURL; 205 } 206 207 util::URL aURL; 208 if (!maResourceURLs.empty()) 209 aURL.Complete = maResourceURLs[0]; 210 return aURL; 211 } 212 213 214 215 216 sal_Bool SAL_CALL 217 ResourceId::hasAnchor (void) 218 throw (RuntimeException) 219 { 220 return maResourceURLs.size()>1; 221 } 222 223 224 225 226 Reference<XResourceId> SAL_CALL 227 ResourceId::getAnchor (void) 228 throw (RuntimeException) 229 { 230 ::rtl::Reference<ResourceId> rResourceId (new ResourceId()); 231 const sal_Int32 nAnchorCount (maResourceURLs.size()-1); 232 if (nAnchorCount > 0) 233 { 234 rResourceId->maResourceURLs.resize(nAnchorCount); 235 for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex) 236 rResourceId->maResourceURLs[nIndex] = maResourceURLs[nIndex+1]; 237 } 238 return Reference<XResourceId>(rResourceId.get()); 239 } 240 241 242 243 244 Sequence<OUString> SAL_CALL 245 ResourceId::getAnchorURLs (void) 246 throw (RuntimeException) 247 { 248 const sal_Int32 nAnchorCount (maResourceURLs.size() - 1); 249 if (nAnchorCount > 0) 250 { 251 Sequence<OUString> aAnchorURLs (nAnchorCount); 252 for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex) 253 aAnchorURLs[nIndex] = maResourceURLs[nIndex+1]; 254 return aAnchorURLs; 255 } 256 else 257 return Sequence<OUString>(); 258 } 259 260 261 262 263 OUString SAL_CALL 264 ResourceId::getResourceTypePrefix (void) 265 throw (RuntimeException) 266 { 267 if (!maResourceURLs.empty() ) 268 { 269 // Return the "private:resource/<type>/" prefix. 270 271 // Get the the prefix that ends with the second "/". 272 const OUString& rsResourceURL (maResourceURLs[0]); 273 sal_Int32 nPrefixEnd (rsResourceURL.indexOf(sal_Unicode('/'), 0)); 274 if (nPrefixEnd >= 0) 275 nPrefixEnd = rsResourceURL.indexOf(sal_Unicode('/'), nPrefixEnd+1) + 1; 276 else 277 nPrefixEnd = 0; 278 279 return rsResourceURL.copy(0,nPrefixEnd); 280 } 281 else 282 return OUString(); 283 } 284 285 286 287 288 sal_Int16 SAL_CALL 289 ResourceId::compareTo (const Reference<XResourceId>& rxResourceId) 290 throw (RuntimeException) 291 { 292 sal_Int16 nResult (0); 293 294 if ( ! rxResourceId.is()) 295 { 296 // The empty reference is interpreted as empty resource id object. 297 if (!maResourceURLs.empty()) 298 nResult = +1; 299 else 300 nResult = 0; 301 } 302 else 303 { 304 ResourceId* pId = NULL; 305 #ifdef USE_OPTIMIZATIONS 306 pId = dynamic_cast<ResourceId*>(rxResourceId.get()); 307 #endif 308 if (pId != NULL) 309 { 310 // We have direct access to the implementation of the given 311 // resource id object. 312 nResult = CompareToLocalImplementation(*pId); 313 } 314 else 315 { 316 // We have to do the comparison via the UNO interface of the 317 // given resource id object. 318 nResult = CompareToExternalImplementation(rxResourceId); 319 } 320 } 321 322 return nResult; 323 } 324 325 326 327 328 sal_Int16 ResourceId::CompareToLocalImplementation (const ResourceId& rId) const 329 { 330 sal_Int16 nResult (0); 331 332 const sal_uInt32 nLocalURLCount (maResourceURLs.size()); 333 const sal_uInt32 nURLCount(rId.maResourceURLs.size()); 334 335 // Start comparison with the top most anchors. 336 for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1; 337 nIndex>=0 && nLocalIndex>=0; 338 --nIndex,--nLocalIndex) 339 { 340 const OUString sLocalURL (maResourceURLs[nLocalIndex]); 341 const OUString sURL (rId.maResourceURLs[nIndex]); 342 const sal_Int32 nLocalResult (sURL.compareTo(sLocalURL)); 343 if (nLocalResult != 0) 344 { 345 if (nLocalResult < 0) 346 nResult = -1; 347 else 348 nResult = +1; 349 break; 350 } 351 } 352 353 if (nResult == 0) 354 { 355 // No difference found yet. When the lengths are the same then the 356 // two resource ids are equivalent. Otherwise the shorter comes 357 // first. 358 if (nLocalURLCount != nURLCount) 359 { 360 if (nLocalURLCount < nURLCount) 361 nResult = -1; 362 else 363 nResult = +1; 364 } 365 } 366 367 return nResult; 368 } 369 370 371 372 373 sal_Int16 ResourceId::CompareToExternalImplementation (const Reference<XResourceId>& rxId) const 374 { 375 sal_Int16 nResult (0); 376 377 const Sequence<OUString> aAnchorURLs (rxId->getAnchorURLs()); 378 const sal_uInt32 nLocalURLCount (maResourceURLs.size()); 379 const sal_uInt32 nURLCount(1+aAnchorURLs.getLength()); 380 381 // Start comparison with the top most anchors. 382 sal_Int32 nLocalResult (0); 383 for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1; 384 nIndex>=0&&nLocalIndex>=0; 385 --nIndex,--nLocalIndex) 386 { 387 if (nIndex == 0 ) 388 nLocalResult = maResourceURLs[nIndex].compareTo(rxId->getResourceURL()); 389 else 390 nLocalResult = maResourceURLs[nIndex].compareTo(aAnchorURLs[nIndex-1]); 391 if (nLocalResult != 0) 392 { 393 if (nLocalResult < 0) 394 nResult = -1; 395 else 396 nResult = +1; 397 break; 398 } 399 } 400 401 if (nResult == 0) 402 { 403 // No difference found yet. When the lengths are the same then the 404 // two resource ids are equivalent. Otherwise the shorter comes 405 // first. 406 if (nLocalURLCount != nURLCount) 407 { 408 if (nLocalURLCount < nURLCount) 409 nResult = -1; 410 else 411 nResult = +1; 412 } 413 } 414 415 return nResult; 416 } 417 418 419 420 421 sal_Bool SAL_CALL 422 ResourceId::isBoundTo ( 423 const Reference<XResourceId>& rxResourceId, 424 AnchorBindingMode eMode) 425 throw (RuntimeException) 426 { 427 if ( ! rxResourceId.is()) 428 { 429 // An empty reference is interpreted as empty resource id. 430 return IsBoundToAnchor(NULL, NULL, eMode); 431 } 432 433 ResourceId* pId = NULL; 434 #ifdef USE_OPTIMIZATIONS 435 pId = dynamic_cast<ResourceId*>(rxResourceId.get()); 436 #endif 437 if (pId != NULL) 438 { 439 return IsBoundToAnchor(pId->maResourceURLs, eMode); 440 } 441 else 442 { 443 const OUString sResourceURL (rxResourceId->getResourceURL()); 444 const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs()); 445 return IsBoundToAnchor(&sResourceURL, &aAnchorURLs, eMode); 446 } 447 } 448 449 450 451 452 sal_Bool SAL_CALL 453 ResourceId::isBoundToURL ( 454 const OUString& rsAnchorURL, 455 AnchorBindingMode eMode) 456 throw (RuntimeException) 457 { 458 return IsBoundToAnchor(&rsAnchorURL, NULL, eMode); 459 } 460 461 462 463 464 Reference<XResourceId> SAL_CALL 465 ResourceId::clone (void) 466 throw(RuntimeException) 467 { 468 return new ResourceId(maResourceURLs); 469 } 470 471 472 473 474 //----- XInitialization ------------------------------------------------------- 475 476 void SAL_CALL ResourceId::initialize (const Sequence<Any>& aArguments) 477 throw (RuntimeException) 478 { 479 sal_uInt32 nCount (aArguments.getLength()); 480 for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex) 481 { 482 OUString sResourceURL; 483 if (aArguments[nIndex] >>= sResourceURL) 484 maResourceURLs.push_back(sResourceURL); 485 else 486 { 487 Reference<XResourceId> xAnchor; 488 if (aArguments[nIndex] >>= xAnchor) 489 { 490 if (xAnchor.is()) 491 { 492 maResourceURLs.push_back(xAnchor->getResourceURL()); 493 Sequence<OUString> aAnchorURLs (xAnchor->getAnchorURLs()); 494 for (sal_Int32 nURLIndex=0; nURLIndex<aAnchorURLs.getLength(); ++nURLIndex) 495 { 496 maResourceURLs.push_back(aAnchorURLs[nURLIndex]); 497 } 498 } 499 } 500 } 501 } 502 ParseResourceURL(); 503 } 504 505 506 507 508 //----------------------------------------------------------------------------- 509 510 /** When eMode is DIRECTLY then the anchor of the called object and the 511 anchor represented by the given sequence of anchor URLs have to be 512 identical. When eMode is RECURSIVE then the anchor of the called 513 object has to start with the given anchor URLs. 514 */ 515 bool ResourceId::IsBoundToAnchor ( 516 const OUString* psFirstAnchorURL, 517 const Sequence<OUString>* paAnchorURLs, 518 AnchorBindingMode eMode) const 519 { 520 const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1); 521 const bool bHasFirstAnchorURL (psFirstAnchorURL!=NULL); 522 const sal_uInt32 nAnchorURLCount ((bHasFirstAnchorURL?1:0) 523 + (paAnchorURLs!=NULL ? paAnchorURLs->getLength() : 0)); 524 525 // Check the lengths. 526 if (nLocalAnchorURLCount<nAnchorURLCount || 527 (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount)) 528 { 529 return false; 530 } 531 532 // Compare the nAnchorURLCount bottom-most anchor URLs of this resource 533 // id and the given anchor. 534 sal_uInt32 nOffset = 0; 535 if (paAnchorURLs != NULL) 536 { 537 sal_uInt32 nCount = paAnchorURLs->getLength(); 538 while (nOffset < nCount) 539 { 540 if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals( 541 (*paAnchorURLs)[nCount - 1 - nOffset])) 542 { 543 return false; 544 } 545 ++nOffset; 546 } 547 } 548 if (bHasFirstAnchorURL) 549 { 550 if ( ! psFirstAnchorURL->equals(maResourceURLs[nLocalAnchorURLCount - nOffset])) 551 return false; 552 } 553 554 return true; 555 } 556 557 558 559 560 bool ResourceId::IsBoundToAnchor ( 561 const ::std::vector<OUString>& rAnchorURLs, 562 AnchorBindingMode eMode) const 563 { 564 const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1); 565 const sal_uInt32 nAnchorURLCount (rAnchorURLs.size()); 566 567 // Check the lengths. 568 if (nLocalAnchorURLCount<nAnchorURLCount || 569 (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount)) 570 { 571 return false; 572 } 573 574 // Compare the nAnchorURLCount bottom-most anchor URLs of this resource 575 // id and the given anchor. 576 for (sal_uInt32 nOffset=0; nOffset<nAnchorURLCount; ++nOffset) 577 { 578 if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals( 579 rAnchorURLs[nAnchorURLCount - 1 - nOffset])) 580 { 581 return false; 582 } 583 } 584 585 return true; 586 } 587 588 589 590 591 void ResourceId::ParseResourceURL (void) 592 { 593 ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex()); 594 Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak); 595 if ( ! xURLTransformer.is()) 596 { 597 // Create the URL transformer. 598 Reference<lang::XMultiServiceFactory> xServiceManager ( 599 ::comphelper::getProcessServiceFactory()); 600 xURLTransformer = Reference<util::XURLTransformer>( 601 xServiceManager->createInstance( 602 OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer"))), 603 UNO_QUERY); 604 mxURLTransformerWeak = xURLTransformer; 605 SdGlobalResourceContainer::Instance().AddResource( 606 Reference<XInterface>(xURLTransformer,UNO_QUERY)); 607 } 608 609 if (xURLTransformer.is() && !maResourceURLs.empty() ) 610 { 611 mpURL.reset(new util::URL); 612 mpURL->Complete = maResourceURLs[0]; 613 xURLTransformer->parseStrict(*mpURL); 614 if (mpURL->Main == maResourceURLs[0]) 615 mpURL.reset(); 616 else 617 maResourceURLs[0] = mpURL->Main; 618 } 619 } 620 621 622 } } // end of namespace sd::framework 623