Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "framework/ResourceId.hxx"
21 : #include "framework/FrameworkHelper.hxx"
22 : #include "tools/SdGlobalResourceContainer.hxx"
23 : #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 : #include <com/sun/star/uno/XComponentContext.hpp>
25 : #include <com/sun/star/util/URLTransformer.hpp>
26 : #include <comphelper/processfactory.hxx>
27 : #include <rtl/ref.hxx>
28 :
29 : #include <facreg.hxx>
30 :
31 : using namespace ::com::sun::star;
32 : using namespace ::com::sun::star::uno;
33 : using namespace ::com::sun::star::lang;
34 : using namespace ::com::sun::star::drawing::framework;
35 :
36 : /** When the USE_OPTIMIZATIONS symbol is defined then at some optimizations
37 : are activated that work only together with XResourceId objects that are
38 : implemented by the ResourceId class. For other implementations of when
39 : the USE_OPTIMIZATIONS symbol is not defined then alternative code is
40 : used instead.
41 : */
42 : #define USE_OPTIMIZATIONS
43 :
44 : namespace sd { namespace framework {
45 :
46 176 : Reference<XInterface> SAL_CALL ResourceId_createInstance (
47 : const Reference<XComponentContext>& rxContext) throw (css::uno::Exception)
48 : {
49 : (void)rxContext;
50 176 : return Reference<XInterface>(static_cast<XWeak*>(new ::sd::framework::ResourceId()));
51 : }
52 :
53 52 : OUString ResourceId_getImplementationName (void) throw(RuntimeException)
54 : {
55 52 : return OUString("com.sun.star.comp.Draw.framework.ResourceId");
56 : }
57 :
58 18 : Sequence<OUString> SAL_CALL ResourceId_getSupportedServiceNames (void)
59 : throw (RuntimeException)
60 : {
61 18 : static const OUString sServiceName("com.sun.star.drawing.framework.ResourceId");
62 18 : return Sequence<OUString>(&sServiceName, 1);
63 : }
64 :
65 : //===== ResourceId ============================================================
66 :
67 38 : WeakReference<util::XURLTransformer> ResourceId::mxURLTransformerWeak;
68 :
69 1854 : ResourceId::ResourceId (void)
70 : : ResourceIdInterfaceBase(),
71 : maResourceURLs(0),
72 1854 : mpURL()
73 : {
74 1854 : }
75 :
76 0 : ResourceId::ResourceId (
77 : const std::vector<OUString>& rResourceURLs)
78 : : ResourceIdInterfaceBase(),
79 : maResourceURLs(rResourceURLs),
80 0 : mpURL()
81 : {
82 0 : ParseResourceURL();
83 0 : }
84 :
85 11532 : ResourceId::ResourceId (
86 : const OUString& rsResourceURL)
87 : : ResourceIdInterfaceBase(),
88 : maResourceURLs(1, rsResourceURL),
89 11532 : mpURL()
90 : {
91 : // Handle the special case of an empty resource URL.
92 11532 : if (rsResourceURL.isEmpty())
93 0 : maResourceURLs.clear();
94 11532 : ParseResourceURL();
95 11532 : }
96 :
97 728 : ResourceId::ResourceId (
98 : const OUString& rsResourceURL,
99 : const OUString& rsAnchorURL)
100 : : ResourceIdInterfaceBase(),
101 : maResourceURLs(2),
102 728 : mpURL()
103 : {
104 728 : maResourceURLs[0] = rsResourceURL;
105 728 : maResourceURLs[1] = rsAnchorURL;
106 728 : ParseResourceURL();
107 728 : }
108 :
109 420 : ResourceId::ResourceId (
110 : const OUString& rsResourceURL,
111 : const OUString& rsFirstAnchorURL,
112 : const Sequence<OUString>& rAnchorURLs)
113 : : ResourceIdInterfaceBase(),
114 420 : maResourceURLs(2+rAnchorURLs.getLength()),
115 840 : mpURL()
116 : {
117 420 : maResourceURLs[0] = rsResourceURL;
118 420 : maResourceURLs[1] = rsFirstAnchorURL;
119 420 : for (sal_Int32 nIndex=0; nIndex<rAnchorURLs.getLength(); ++nIndex)
120 0 : maResourceURLs[nIndex+2] = rAnchorURLs[nIndex];
121 420 : ParseResourceURL();
122 420 : }
123 :
124 42966 : ResourceId::~ResourceId (void)
125 : {
126 14322 : mpURL.reset();
127 28644 : }
128 :
129 : OUString SAL_CALL
130 34762 : ResourceId::getResourceURL (void)
131 : throw(com::sun::star::uno::RuntimeException, std::exception)
132 : {
133 34762 : if (!maResourceURLs.empty())
134 34762 : return maResourceURLs[0];
135 : else
136 0 : return OUString();
137 : }
138 :
139 : util::URL SAL_CALL
140 0 : ResourceId::getFullResourceURL (void)
141 : throw(com::sun::star::uno::RuntimeException, std::exception)
142 : {
143 0 : if (mpURL.get() != NULL)
144 0 : return *mpURL;
145 :
146 0 : Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
147 0 : if (xURLTransformer.is() && !maResourceURLs.empty() )
148 : {
149 0 : mpURL.reset(new util::URL);
150 0 : mpURL->Complete = maResourceURLs[0];
151 0 : xURLTransformer->parseStrict(*mpURL);
152 0 : return *mpURL;
153 : }
154 :
155 0 : util::URL aURL;
156 0 : if (!maResourceURLs.empty())
157 0 : aURL.Complete = maResourceURLs[0];
158 0 : return aURL;
159 : }
160 :
161 : sal_Bool SAL_CALL
162 0 : ResourceId::hasAnchor (void)
163 : throw (RuntimeException, std::exception)
164 : {
165 0 : return maResourceURLs.size()>1;
166 : }
167 :
168 : Reference<XResourceId> SAL_CALL
169 1678 : ResourceId::getAnchor (void)
170 : throw (RuntimeException, std::exception)
171 : {
172 1678 : ::rtl::Reference<ResourceId> rResourceId (new ResourceId());
173 1678 : const sal_Int32 nAnchorCount (maResourceURLs.size()-1);
174 1678 : if (nAnchorCount > 0)
175 : {
176 1678 : rResourceId->maResourceURLs.resize(nAnchorCount);
177 3356 : for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex)
178 1678 : rResourceId->maResourceURLs[nIndex] = maResourceURLs[nIndex+1];
179 : }
180 1678 : return Reference<XResourceId>(rResourceId.get());
181 : }
182 :
183 : Sequence<OUString> SAL_CALL
184 420 : ResourceId::getAnchorURLs (void)
185 : throw (RuntimeException, std::exception)
186 : {
187 420 : const sal_Int32 nAnchorCount (maResourceURLs.size() - 1);
188 420 : if (nAnchorCount > 0)
189 : {
190 0 : Sequence<OUString> aAnchorURLs (nAnchorCount);
191 0 : for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex)
192 0 : aAnchorURLs[nIndex] = maResourceURLs[nIndex+1];
193 0 : return aAnchorURLs;
194 : }
195 : else
196 420 : return Sequence<OUString>();
197 : }
198 :
199 : OUString SAL_CALL
200 1784 : ResourceId::getResourceTypePrefix (void)
201 : throw (RuntimeException, std::exception)
202 : {
203 1784 : if (!maResourceURLs.empty() )
204 : {
205 : // Return the "private:resource/<type>/" prefix.
206 :
207 : // Get the prefix that ends with the second "/".
208 1784 : const OUString& rsResourceURL (maResourceURLs[0]);
209 1784 : sal_Int32 nPrefixEnd (rsResourceURL.indexOf('/', 0));
210 1784 : if (nPrefixEnd >= 0)
211 1784 : nPrefixEnd = rsResourceURL.indexOf('/', nPrefixEnd+1) + 1;
212 : else
213 0 : nPrefixEnd = 0;
214 :
215 1784 : return rsResourceURL.copy(0,nPrefixEnd);
216 : }
217 : else
218 0 : return OUString();
219 : }
220 :
221 : sal_Int16 SAL_CALL
222 71540 : ResourceId::compareTo (const Reference<XResourceId>& rxResourceId)
223 : throw (RuntimeException, std::exception)
224 : {
225 71540 : sal_Int16 nResult (0);
226 :
227 71540 : if ( ! rxResourceId.is())
228 : {
229 : // The empty reference is interpreted as empty resource id object.
230 0 : if (!maResourceURLs.empty())
231 0 : nResult = +1;
232 : else
233 0 : nResult = 0;
234 : }
235 : else
236 : {
237 71540 : ResourceId* pId = NULL;
238 : #ifdef USE_OPTIMIZATIONS
239 71540 : pId = dynamic_cast<ResourceId*>(rxResourceId.get());
240 : #endif
241 71540 : if (pId != NULL)
242 : {
243 : // We have direct access to the implementation of the given
244 : // resource id object.
245 71540 : nResult = CompareToLocalImplementation(*pId);
246 : }
247 : else
248 : {
249 : // We have to do the comparison via the UNO interface of the
250 : // given resource id object.
251 0 : nResult = CompareToExternalImplementation(rxResourceId);
252 : }
253 : }
254 :
255 71540 : return nResult;
256 : }
257 :
258 71540 : sal_Int16 ResourceId::CompareToLocalImplementation (const ResourceId& rId) const
259 : {
260 71540 : sal_Int16 nResult (0);
261 :
262 71540 : const sal_uInt32 nLocalURLCount (maResourceURLs.size());
263 71540 : const sal_uInt32 nURLCount(rId.maResourceURLs.size());
264 :
265 : // Start comparison with the top most anchors.
266 153646 : for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
267 116142 : nIndex>=0 && nLocalIndex>=0;
268 : --nIndex,--nLocalIndex)
269 : {
270 100154 : const OUString sLocalURL (maResourceURLs[nLocalIndex]);
271 182260 : const OUString sURL (rId.maResourceURLs[nIndex]);
272 100154 : const sal_Int32 nLocalResult (sURL.compareTo(sLocalURL));
273 100154 : if (nLocalResult != 0)
274 : {
275 18048 : if (nLocalResult < 0)
276 10830 : nResult = -1;
277 : else
278 7218 : nResult = +1;
279 18048 : break;
280 : }
281 82106 : }
282 :
283 71540 : if (nResult == 0)
284 : {
285 : // No difference found yet. When the lengths are the same then the
286 : // two resource ids are equivalent. Otherwise the shorter comes
287 : // first.
288 53492 : if (nLocalURLCount != nURLCount)
289 : {
290 18658 : if (nLocalURLCount < nURLCount)
291 15988 : nResult = -1;
292 : else
293 2670 : nResult = +1;
294 : }
295 : }
296 :
297 71540 : return nResult;
298 : }
299 :
300 0 : sal_Int16 ResourceId::CompareToExternalImplementation (const Reference<XResourceId>& rxId) const
301 : {
302 0 : sal_Int16 nResult (0);
303 :
304 0 : const Sequence<OUString> aAnchorURLs (rxId->getAnchorURLs());
305 0 : const sal_uInt32 nLocalURLCount (maResourceURLs.size());
306 0 : const sal_uInt32 nURLCount(1+aAnchorURLs.getLength());
307 :
308 : // Start comparison with the top most anchors.
309 0 : sal_Int32 nLocalResult (0);
310 0 : for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
311 0 : nIndex>=0&&nLocalIndex>=0;
312 : --nIndex,--nLocalIndex)
313 : {
314 0 : if (nIndex == 0 )
315 0 : nLocalResult = maResourceURLs[nIndex].compareTo(rxId->getResourceURL());
316 : else
317 0 : nLocalResult = maResourceURLs[nIndex].compareTo(aAnchorURLs[nIndex-1]);
318 0 : if (nLocalResult != 0)
319 : {
320 0 : if (nLocalResult < 0)
321 0 : nResult = -1;
322 : else
323 0 : nResult = +1;
324 0 : break;
325 : }
326 : }
327 :
328 0 : if (nResult == 0)
329 : {
330 : // No difference found yet. When the lengths are the same then the
331 : // two resource ids are equivalent. Otherwise the shorter comes
332 : // first.
333 0 : if (nLocalURLCount != nURLCount)
334 : {
335 0 : if (nLocalURLCount < nURLCount)
336 0 : nResult = -1;
337 : else
338 0 : nResult = +1;
339 : }
340 : }
341 :
342 0 : return nResult;
343 : }
344 :
345 : sal_Bool SAL_CALL
346 88576 : ResourceId::isBoundTo (
347 : const Reference<XResourceId>& rxResourceId,
348 : AnchorBindingMode eMode)
349 : throw (RuntimeException, std::exception)
350 : {
351 88576 : if ( ! rxResourceId.is())
352 : {
353 : // An empty reference is interpreted as empty resource id.
354 12632 : return IsBoundToAnchor(NULL, NULL, eMode);
355 : }
356 :
357 75944 : ResourceId* pId = NULL;
358 : #ifdef USE_OPTIMIZATIONS
359 75944 : pId = dynamic_cast<ResourceId*>(rxResourceId.get());
360 : #endif
361 75944 : if (pId != NULL)
362 : {
363 75944 : return IsBoundToAnchor(pId->maResourceURLs, eMode);
364 : }
365 : else
366 : {
367 0 : const OUString sResourceURL (rxResourceId->getResourceURL());
368 0 : const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs());
369 0 : return IsBoundToAnchor(&sResourceURL, &aAnchorURLs, eMode);
370 : }
371 : }
372 :
373 : sal_Bool SAL_CALL
374 3828 : ResourceId::isBoundToURL (
375 : const OUString& rsAnchorURL,
376 : AnchorBindingMode eMode)
377 : throw (RuntimeException, std::exception)
378 : {
379 3828 : return IsBoundToAnchor(&rsAnchorURL, NULL, eMode);
380 : }
381 :
382 : Reference<XResourceId> SAL_CALL
383 0 : ResourceId::clone (void)
384 : throw(RuntimeException, std::exception)
385 : {
386 0 : return new ResourceId(maResourceURLs);
387 : }
388 :
389 : //----- XInitialization -------------------------------------------------------
390 :
391 176 : void SAL_CALL ResourceId::initialize (const Sequence<Any>& aArguments)
392 : throw (RuntimeException, std::exception)
393 : {
394 176 : sal_uInt32 nCount (aArguments.getLength());
395 350 : for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
396 : {
397 174 : OUString sResourceURL;
398 174 : if (aArguments[nIndex] >>= sResourceURL)
399 174 : maResourceURLs.push_back(sResourceURL);
400 : else
401 : {
402 0 : Reference<XResourceId> xAnchor;
403 0 : if (aArguments[nIndex] >>= xAnchor)
404 : {
405 0 : if (xAnchor.is())
406 : {
407 0 : maResourceURLs.push_back(xAnchor->getResourceURL());
408 0 : Sequence<OUString> aAnchorURLs (xAnchor->getAnchorURLs());
409 0 : for (sal_Int32 nURLIndex=0; nURLIndex<aAnchorURLs.getLength(); ++nURLIndex)
410 : {
411 0 : maResourceURLs.push_back(aAnchorURLs[nURLIndex]);
412 0 : }
413 : }
414 0 : }
415 : }
416 174 : }
417 176 : ParseResourceURL();
418 176 : }
419 :
420 : /** When eMode is DIRECTLY then the anchor of the called object and the
421 : anchor represented by the given sequence of anchor URLs have to be
422 : identical. When eMode is RECURSIVE then the anchor of the called
423 : object has to start with the given anchor URLs.
424 : */
425 16460 : bool ResourceId::IsBoundToAnchor (
426 : const OUString* psFirstAnchorURL,
427 : const Sequence<OUString>* paAnchorURLs,
428 : AnchorBindingMode eMode) const
429 : {
430 16460 : const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
431 16460 : const bool bHasFirstAnchorURL (psFirstAnchorURL!=NULL);
432 : const sal_uInt32 nAnchorURLCount ((bHasFirstAnchorURL?1:0)
433 16460 : + (paAnchorURLs!=NULL ? paAnchorURLs->getLength() : 0));
434 :
435 : // Check the lengths.
436 16460 : if (nLocalAnchorURLCount<nAnchorURLCount ||
437 8132 : (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
438 : {
439 3314 : return false;
440 : }
441 :
442 : // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
443 : // id and the given anchor.
444 13146 : sal_uInt32 nOffset = 0;
445 13146 : if (paAnchorURLs != NULL)
446 : {
447 0 : sal_uInt32 nCount = paAnchorURLs->getLength();
448 0 : while (nOffset < nCount)
449 : {
450 0 : if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals(
451 0 : (*paAnchorURLs)[nCount - 1 - nOffset]))
452 : {
453 0 : return false;
454 : }
455 0 : ++nOffset;
456 : }
457 : }
458 13146 : if (bHasFirstAnchorURL)
459 : {
460 3144 : if ( ! psFirstAnchorURL->equals(maResourceURLs[nLocalAnchorURLCount - nOffset]))
461 1348 : return false;
462 : }
463 :
464 11798 : return true;
465 : }
466 :
467 75944 : bool ResourceId::IsBoundToAnchor (
468 : const ::std::vector<OUString>& rAnchorURLs,
469 : AnchorBindingMode eMode) const
470 : {
471 75944 : const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
472 75944 : const sal_uInt32 nAnchorURLCount (rAnchorURLs.size());
473 :
474 : // Check the lengths.
475 75944 : if (nLocalAnchorURLCount<nAnchorURLCount ||
476 31298 : (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
477 : {
478 40920 : return false;
479 : }
480 :
481 : // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
482 : // id and the given anchor.
483 51770 : for (sal_uInt32 nOffset=0; nOffset<nAnchorURLCount; ++nOffset)
484 : {
485 70048 : if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals(
486 70048 : rAnchorURLs[nAnchorURLCount - 1 - nOffset]))
487 : {
488 18278 : return false;
489 : }
490 : }
491 :
492 16746 : return true;
493 : }
494 :
495 12856 : void ResourceId::ParseResourceURL (void)
496 : {
497 12856 : ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex());
498 25712 : Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
499 12856 : if ( ! xURLTransformer.is())
500 : {
501 : // Create the URL transformer.
502 24 : Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
503 24 : xURLTransformer = Reference<util::XURLTransformer>(util::URLTransformer::create(xContext));
504 24 : mxURLTransformerWeak = xURLTransformer;
505 24 : SdGlobalResourceContainer::Instance().AddResource(
506 48 : Reference<XInterface>(xURLTransformer,UNO_QUERY));
507 : }
508 :
509 12856 : if (xURLTransformer.is() && !maResourceURLs.empty() )
510 : {
511 12854 : mpURL.reset(new util::URL);
512 12854 : mpURL->Complete = maResourceURLs[0];
513 12854 : xURLTransformer->parseStrict(*mpURL);
514 12854 : if (mpURL->Main == maResourceURLs[0])
515 12854 : mpURL.reset();
516 : else
517 0 : maResourceURLs[0] = mpURL->Main;
518 12856 : }
519 12856 : }
520 :
521 114 : } } // end of namespace sd::framework
522 :
523 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|