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
ResourceId_createInstance(const Reference<XComponentContext> & rxContext)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
ResourceId_getImplementationName(void)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
ResourceId_getSupportedServiceNames(void)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
ResourceId(void)84 ResourceId::ResourceId (void)
85 : ResourceIdInterfaceBase(),
86 maResourceURLs(0),
87 mpURL()
88 {
89 }
90
91
92
93
ResourceId(const std::vector<OUString> & rResourceURLs)94 ResourceId::ResourceId (
95 const std::vector<OUString>& rResourceURLs)
96 : ResourceIdInterfaceBase(),
97 maResourceURLs(rResourceURLs),
98 mpURL()
99 {
100 ParseResourceURL();
101 }
102
103
104
105
ResourceId(const OUString & rsResourceURL)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
ResourceId(const OUString & rsResourceURL,const OUString & rsAnchorURL)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
ResourceId(const OUString & rsResourceURL,const::std::vector<OUString> & rAnchorURLs)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
ResourceId(const OUString & rsResourceURL,const OUString & rsFirstAnchorURL,const Sequence<OUString> & rAnchorURLs)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
~ResourceId(void)170 ResourceId::~ResourceId (void)
171 {
172 mpURL.reset();
173 }
174
175
176
177
178 OUString SAL_CALL
getResourceURL(void)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
getFullResourceURL(void)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
hasAnchor(void)217 ResourceId::hasAnchor (void)
218 throw (RuntimeException)
219 {
220 return maResourceURLs.size()>1;
221 }
222
223
224
225
226 Reference<XResourceId> SAL_CALL
getAnchor(void)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
getAnchorURLs(void)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
getResourceTypePrefix(void)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
compareTo(const Reference<XResourceId> & rxResourceId)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
CompareToLocalImplementation(const ResourceId & rId) const328 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
CompareToExternalImplementation(const Reference<XResourceId> & rxId) const373 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
isBoundTo(const Reference<XResourceId> & rxResourceId,AnchorBindingMode eMode)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
isBoundToURL(const OUString & rsAnchorURL,AnchorBindingMode eMode)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
clone(void)465 ResourceId::clone (void)
466 throw(RuntimeException)
467 {
468 return new ResourceId(maResourceURLs);
469 }
470
471
472
473
474 //----- XInitialization -------------------------------------------------------
475
initialize(const Sequence<Any> & aArguments)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 */
IsBoundToAnchor(const OUString * psFirstAnchorURL,const Sequence<OUString> * paAnchorURLs,AnchorBindingMode eMode) const515 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
IsBoundToAnchor(const::std::vector<OUString> & rAnchorURLs,AnchorBindingMode eMode) const560 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
ParseResourceURL(void)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