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 : //===== ResourceId ============================================================
47 :
48 22 : WeakReference<util::XURLTransformer> ResourceId::mxURLTransformerWeak;
49 :
50 1220 : ResourceId::ResourceId()
51 : : ResourceIdInterfaceBase(),
52 : maResourceURLs(0),
53 1220 : mpURL()
54 : {
55 1220 : }
56 :
57 0 : ResourceId::ResourceId (
58 : const std::vector<OUString>& rResourceURLs)
59 : : ResourceIdInterfaceBase(),
60 : maResourceURLs(rResourceURLs),
61 0 : mpURL()
62 : {
63 0 : ParseResourceURL();
64 0 : }
65 :
66 7530 : ResourceId::ResourceId (
67 : const OUString& rsResourceURL)
68 : : ResourceIdInterfaceBase(),
69 : maResourceURLs(1, rsResourceURL),
70 7530 : mpURL()
71 : {
72 : // Handle the special case of an empty resource URL.
73 7530 : if (rsResourceURL.isEmpty())
74 0 : maResourceURLs.clear();
75 7530 : ParseResourceURL();
76 7530 : }
77 :
78 505 : ResourceId::ResourceId (
79 : const OUString& rsResourceURL,
80 : const OUString& rsAnchorURL)
81 : : ResourceIdInterfaceBase(),
82 : maResourceURLs(2),
83 505 : mpURL()
84 : {
85 505 : maResourceURLs[0] = rsResourceURL;
86 505 : maResourceURLs[1] = rsAnchorURL;
87 505 : ParseResourceURL();
88 505 : }
89 :
90 291 : ResourceId::ResourceId (
91 : const OUString& rsResourceURL,
92 : const OUString& rsFirstAnchorURL,
93 : const Sequence<OUString>& rAnchorURLs)
94 : : ResourceIdInterfaceBase(),
95 291 : maResourceURLs(2+rAnchorURLs.getLength()),
96 582 : mpURL()
97 : {
98 291 : maResourceURLs[0] = rsResourceURL;
99 291 : maResourceURLs[1] = rsFirstAnchorURL;
100 291 : for (sal_Int32 nIndex=0; nIndex<rAnchorURLs.getLength(); ++nIndex)
101 0 : maResourceURLs[nIndex+2] = rAnchorURLs[nIndex];
102 291 : ParseResourceURL();
103 291 : }
104 :
105 28260 : ResourceId::~ResourceId()
106 : {
107 9420 : mpURL.reset();
108 18840 : }
109 :
110 : OUString SAL_CALL
111 23167 : ResourceId::getResourceURL()
112 : throw(com::sun::star::uno::RuntimeException, std::exception)
113 : {
114 23167 : if (!maResourceURLs.empty())
115 23167 : return maResourceURLs[0];
116 : else
117 0 : return OUString();
118 : }
119 :
120 : util::URL SAL_CALL
121 0 : ResourceId::getFullResourceURL()
122 : throw(com::sun::star::uno::RuntimeException, std::exception)
123 : {
124 0 : if (mpURL.get() != NULL)
125 0 : return *mpURL;
126 :
127 0 : Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
128 0 : if (xURLTransformer.is() && !maResourceURLs.empty() )
129 : {
130 0 : mpURL.reset(new util::URL);
131 0 : mpURL->Complete = maResourceURLs[0];
132 0 : xURLTransformer->parseStrict(*mpURL);
133 0 : return *mpURL;
134 : }
135 :
136 0 : util::URL aURL;
137 0 : if (!maResourceURLs.empty())
138 0 : aURL.Complete = maResourceURLs[0];
139 0 : return aURL;
140 : }
141 :
142 : sal_Bool SAL_CALL
143 0 : ResourceId::hasAnchor()
144 : throw (RuntimeException, std::exception)
145 : {
146 0 : return maResourceURLs.size()>1;
147 : }
148 :
149 : Reference<XResourceId> SAL_CALL
150 1126 : ResourceId::getAnchor()
151 : throw (RuntimeException, std::exception)
152 : {
153 1126 : ::rtl::Reference<ResourceId> rResourceId (new ResourceId());
154 1126 : const sal_Int32 nAnchorCount (maResourceURLs.size()-1);
155 1126 : if (nAnchorCount > 0)
156 : {
157 1126 : rResourceId->maResourceURLs.resize(nAnchorCount);
158 2252 : for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex)
159 1126 : rResourceId->maResourceURLs[nIndex] = maResourceURLs[nIndex+1];
160 : }
161 1126 : return Reference<XResourceId>(rResourceId.get());
162 : }
163 :
164 : Sequence<OUString> SAL_CALL
165 291 : ResourceId::getAnchorURLs()
166 : throw (RuntimeException, std::exception)
167 : {
168 291 : const sal_Int32 nAnchorCount (maResourceURLs.size() - 1);
169 291 : if (nAnchorCount > 0)
170 : {
171 0 : Sequence<OUString> aAnchorURLs (nAnchorCount);
172 0 : for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex)
173 0 : aAnchorURLs[nIndex] = maResourceURLs[nIndex+1];
174 0 : return aAnchorURLs;
175 : }
176 : else
177 291 : return Sequence<OUString>();
178 : }
179 :
180 : OUString SAL_CALL
181 1131 : ResourceId::getResourceTypePrefix()
182 : throw (RuntimeException, std::exception)
183 : {
184 1131 : if (!maResourceURLs.empty() )
185 : {
186 : // Return the "private:resource/<type>/" prefix.
187 :
188 : // Get the prefix that ends with the second "/".
189 1131 : const OUString& rsResourceURL (maResourceURLs[0]);
190 1131 : sal_Int32 nPrefixEnd (rsResourceURL.indexOf('/', 0));
191 1131 : if (nPrefixEnd >= 0)
192 1131 : nPrefixEnd = rsResourceURL.indexOf('/', nPrefixEnd+1) + 1;
193 : else
194 0 : nPrefixEnd = 0;
195 :
196 1131 : return rsResourceURL.copy(0,nPrefixEnd);
197 : }
198 : else
199 0 : return OUString();
200 : }
201 :
202 : sal_Int16 SAL_CALL
203 46473 : ResourceId::compareTo (const Reference<XResourceId>& rxResourceId)
204 : throw (RuntimeException, std::exception)
205 : {
206 46473 : sal_Int16 nResult (0);
207 :
208 46473 : if ( ! rxResourceId.is())
209 : {
210 : // The empty reference is interpreted as empty resource id object.
211 0 : if (!maResourceURLs.empty())
212 0 : nResult = +1;
213 : else
214 0 : nResult = 0;
215 : }
216 : else
217 : {
218 46473 : ResourceId* pId = NULL;
219 : #ifdef USE_OPTIMIZATIONS
220 46473 : pId = dynamic_cast<ResourceId*>(rxResourceId.get());
221 : #endif
222 46473 : if (pId != NULL)
223 : {
224 : // We have direct access to the implementation of the given
225 : // resource id object.
226 46473 : nResult = CompareToLocalImplementation(*pId);
227 : }
228 : else
229 : {
230 : // We have to do the comparison via the UNO interface of the
231 : // given resource id object.
232 0 : nResult = CompareToExternalImplementation(rxResourceId);
233 : }
234 : }
235 :
236 46473 : return nResult;
237 : }
238 :
239 46473 : sal_Int16 ResourceId::CompareToLocalImplementation (const ResourceId& rId) const
240 : {
241 46473 : sal_Int16 nResult (0);
242 :
243 46473 : const sal_uInt32 nLocalURLCount (maResourceURLs.size());
244 46473 : const sal_uInt32 nURLCount(rId.maResourceURLs.size());
245 :
246 : // Start comparison with the top most anchors.
247 100220 : for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
248 76240 : nIndex>=0 && nLocalIndex>=0;
249 : --nIndex,--nLocalIndex)
250 : {
251 65926 : const OUString sLocalURL (maResourceURLs[nLocalIndex]);
252 119673 : const OUString sURL (rId.maResourceURLs[nIndex]);
253 65926 : const sal_Int32 nLocalResult (sURL.compareTo(sLocalURL));
254 65926 : if (nLocalResult != 0)
255 : {
256 12179 : if (nLocalResult < 0)
257 7004 : nResult = -1;
258 : else
259 5175 : nResult = +1;
260 12179 : break;
261 : }
262 53747 : }
263 :
264 46473 : if (nResult == 0)
265 : {
266 : // No difference found yet. When the lengths are the same then the
267 : // two resource ids are equivalent. Otherwise the shorter comes
268 : // first.
269 34294 : if (nLocalURLCount != nURLCount)
270 : {
271 12010 : if (nLocalURLCount < nURLCount)
272 10314 : nResult = -1;
273 : else
274 1696 : nResult = +1;
275 : }
276 : }
277 :
278 46473 : return nResult;
279 : }
280 :
281 0 : sal_Int16 ResourceId::CompareToExternalImplementation (const Reference<XResourceId>& rxId) const
282 : {
283 0 : sal_Int16 nResult (0);
284 :
285 0 : const Sequence<OUString> aAnchorURLs (rxId->getAnchorURLs());
286 0 : const sal_uInt32 nLocalURLCount (maResourceURLs.size());
287 0 : const sal_uInt32 nURLCount(1+aAnchorURLs.getLength());
288 :
289 : // Start comparison with the top most anchors.
290 0 : sal_Int32 nLocalResult (0);
291 0 : for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
292 0 : nIndex>=0&&nLocalIndex>=0;
293 : --nIndex,--nLocalIndex)
294 : {
295 0 : if (nIndex == 0 )
296 0 : nLocalResult = maResourceURLs[nIndex].compareTo(rxId->getResourceURL());
297 : else
298 0 : nLocalResult = maResourceURLs[nIndex].compareTo(aAnchorURLs[nIndex-1]);
299 0 : if (nLocalResult != 0)
300 : {
301 0 : if (nLocalResult < 0)
302 0 : nResult = -1;
303 : else
304 0 : nResult = +1;
305 0 : break;
306 : }
307 : }
308 :
309 0 : if (nResult == 0)
310 : {
311 : // No difference found yet. When the lengths are the same then the
312 : // two resource ids are equivalent. Otherwise the shorter comes
313 : // first.
314 0 : if (nLocalURLCount != nURLCount)
315 : {
316 0 : if (nLocalURLCount < nURLCount)
317 0 : nResult = -1;
318 : else
319 0 : nResult = +1;
320 : }
321 : }
322 :
323 0 : return nResult;
324 : }
325 :
326 : sal_Bool SAL_CALL
327 60343 : ResourceId::isBoundTo (
328 : const Reference<XResourceId>& rxResourceId,
329 : AnchorBindingMode eMode)
330 : throw (RuntimeException, std::exception)
331 : {
332 60343 : if ( ! rxResourceId.is())
333 : {
334 : // An empty reference is interpreted as empty resource id.
335 8049 : return IsBoundToAnchor(NULL, NULL, eMode);
336 : }
337 :
338 52294 : ResourceId* pId = NULL;
339 : #ifdef USE_OPTIMIZATIONS
340 52294 : pId = dynamic_cast<ResourceId*>(rxResourceId.get());
341 : #endif
342 52294 : if (pId != NULL)
343 : {
344 52294 : return IsBoundToAnchor(pId->maResourceURLs, eMode);
345 : }
346 : else
347 : {
348 0 : const OUString sResourceURL (rxResourceId->getResourceURL());
349 0 : const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs());
350 0 : return IsBoundToAnchor(&sResourceURL, &aAnchorURLs, eMode);
351 : }
352 : }
353 :
354 : sal_Bool SAL_CALL
355 2447 : ResourceId::isBoundToURL (
356 : const OUString& rsAnchorURL,
357 : AnchorBindingMode eMode)
358 : throw (RuntimeException, std::exception)
359 : {
360 2447 : return IsBoundToAnchor(&rsAnchorURL, NULL, eMode);
361 : }
362 :
363 : Reference<XResourceId> SAL_CALL
364 0 : ResourceId::clone()
365 : throw(RuntimeException, std::exception)
366 : {
367 0 : return new ResourceId(maResourceURLs);
368 : }
369 :
370 : //----- XInitialization -------------------------------------------------------
371 :
372 94 : void SAL_CALL ResourceId::initialize (const Sequence<Any>& aArguments)
373 : throw (RuntimeException, std::exception)
374 : {
375 94 : sal_uInt32 nCount (aArguments.getLength());
376 187 : for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
377 : {
378 93 : OUString sResourceURL;
379 93 : if (aArguments[nIndex] >>= sResourceURL)
380 93 : maResourceURLs.push_back(sResourceURL);
381 : else
382 : {
383 0 : Reference<XResourceId> xAnchor;
384 0 : if (aArguments[nIndex] >>= xAnchor)
385 : {
386 0 : if (xAnchor.is())
387 : {
388 0 : maResourceURLs.push_back(xAnchor->getResourceURL());
389 0 : Sequence<OUString> aAnchorURLs (xAnchor->getAnchorURLs());
390 0 : for (sal_Int32 nURLIndex=0; nURLIndex<aAnchorURLs.getLength(); ++nURLIndex)
391 : {
392 0 : maResourceURLs.push_back(aAnchorURLs[nURLIndex]);
393 0 : }
394 : }
395 0 : }
396 : }
397 93 : }
398 94 : ParseResourceURL();
399 94 : }
400 :
401 1 : OUString ResourceId::getImplementationName()
402 : throw (css::uno::RuntimeException, std::exception)
403 : {
404 1 : return OUString("com.sun.star.comp.Draw.framework.ResourceId");
405 : }
406 :
407 0 : sal_Bool ResourceId::supportsService(OUString const & ServiceName)
408 : throw (css::uno::RuntimeException, std::exception)
409 : {
410 0 : return cppu::supportsService(this, ServiceName);
411 : }
412 :
413 1 : css::uno::Sequence<OUString> ResourceId::getSupportedServiceNames()
414 : throw (css::uno::RuntimeException, std::exception)
415 : {
416 : return css::uno::Sequence<OUString>{
417 1 : "com.sun.star.drawing.framework.ResourceId"};
418 : }
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 10496 : bool ResourceId::IsBoundToAnchor (
426 : const OUString* psFirstAnchorURL,
427 : const Sequence<OUString>* paAnchorURLs,
428 : AnchorBindingMode eMode) const
429 : {
430 10496 : const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
431 10496 : const bool bHasFirstAnchorURL (psFirstAnchorURL!=NULL);
432 : const sal_uInt32 nAnchorURLCount ((bHasFirstAnchorURL?1:0)
433 10496 : + (paAnchorURLs!=NULL ? paAnchorURLs->getLength() : 0));
434 :
435 : // Check the lengths.
436 10496 : if (nLocalAnchorURLCount<nAnchorURLCount ||
437 5137 : (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
438 : {
439 2147 : return false;
440 : }
441 :
442 : // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
443 : // id and the given anchor.
444 8349 : sal_uInt32 nOffset = 0;
445 8349 : 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 8349 : if (bHasFirstAnchorURL)
459 : {
460 1986 : if ( ! psFirstAnchorURL->equals(maResourceURLs[nLocalAnchorURLCount - nOffset]))
461 809 : return false;
462 : }
463 :
464 7540 : return true;
465 : }
466 :
467 52294 : bool ResourceId::IsBoundToAnchor (
468 : const ::std::vector<OUString>& rAnchorURLs,
469 : AnchorBindingMode eMode) const
470 : {
471 52294 : const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
472 52294 : const sal_uInt32 nAnchorURLCount (rAnchorURLs.size());
473 :
474 : // Check the lengths.
475 52294 : if (nLocalAnchorURLCount<nAnchorURLCount ||
476 22050 : (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
477 : {
478 27856 : return false;
479 : }
480 :
481 : // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
482 : // id and the given anchor.
483 36092 : for (sal_uInt32 nOffset=0; nOffset<nAnchorURLCount; ++nOffset)
484 : {
485 48876 : if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals(
486 48876 : rAnchorURLs[nAnchorURLCount - 1 - nOffset]))
487 : {
488 12784 : return false;
489 : }
490 : }
491 :
492 11654 : return true;
493 : }
494 :
495 8420 : void ResourceId::ParseResourceURL()
496 : {
497 8420 : ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex());
498 16840 : Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
499 8420 : if ( ! xURLTransformer.is())
500 : {
501 : // Create the URL transformer.
502 15 : Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
503 15 : xURLTransformer = Reference<util::XURLTransformer>(util::URLTransformer::create(xContext));
504 15 : mxURLTransformerWeak = xURLTransformer;
505 15 : SdGlobalResourceContainer::Instance().AddResource(
506 30 : Reference<XInterface>(xURLTransformer,UNO_QUERY));
507 : }
508 :
509 8420 : if (xURLTransformer.is() && !maResourceURLs.empty() )
510 : {
511 8419 : mpURL.reset(new util::URL);
512 8419 : mpURL->Complete = maResourceURLs[0];
513 8419 : xURLTransformer->parseStrict(*mpURL);
514 8419 : if (mpURL->Main == maResourceURLs[0])
515 8419 : mpURL.reset();
516 : else
517 0 : maResourceURLs[0] = mpURL->Main;
518 8420 : }
519 8420 : }
520 :
521 : } } // end of namespace sd::framework
522 :
523 :
524 : extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
525 94 : com_sun_star_comp_Draw_framework_ResourceID_get_implementation(::com::sun::star::uno::XComponentContext*,
526 : ::com::sun::star::uno::Sequence<css::uno::Any> const &)
527 : {
528 94 : return cppu::acquire(new sd::framework::ResourceId());
529 66 : }
530 :
531 :
532 :
533 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|