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