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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_stoc.hxx"
26
27 #include "stocservices.hxx"
28
29 #include "UriReference.hxx"
30 #include "supportsService.hxx"
31
32 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
33 #include "com/sun/star/lang/XMultiComponentFactory.hpp"
34 #include "com/sun/star/lang/XServiceInfo.hpp"
35 #include "com/sun/star/uno/Any.hxx"
36 #include "com/sun/star/uno/Exception.hpp"
37 #include "com/sun/star/uno/Reference.hxx"
38 #include "com/sun/star/uno/RuntimeException.hpp"
39 #include "com/sun/star/uno/Sequence.hxx"
40 #include "com/sun/star/uno/XComponentContext.hpp"
41 #include "com/sun/star/uno/XInterface.hpp"
42 #include "com/sun/star/uri/RelativeUriExcessParentSegments.hpp"
43 #include "com/sun/star/uri/XUriReference.hpp"
44 #include "com/sun/star/uri/XUriReferenceFactory.hpp"
45 #include "com/sun/star/uri/XUriSchemeParser.hpp"
46 #include "cppuhelper/implbase1.hxx"
47 #include "cppuhelper/implbase2.hxx"
48 #include "cppuhelper/weak.hxx"
49 #include "osl/diagnose.h"
50 #include "rtl/string.h"
51 #include "rtl/ustrbuf.hxx"
52 #include "rtl/ustring.hxx"
53 #include "sal/types.h"
54
55 #include <algorithm>
56 #include /*MSVC trouble: <cstdlib>*/ <stdlib.h>
57 #include <new>
58 #include <vector>
59
60 namespace css = com::sun::star;
61
62 namespace {
63
isDigit(sal_Unicode c)64 bool isDigit(sal_Unicode c) { //TODO: generally available?
65 return c >= '0' && c <= '9';
66 }
67
isUpperCase(sal_Unicode c)68 bool isUpperCase(sal_Unicode c) { //TODO: generally available?
69 return c >= 'A' && c <= 'Z';
70 }
71
isLowerCase(sal_Unicode c)72 bool isLowerCase(sal_Unicode c) { //TODO: generally available?
73 return c >= 'a' && c <= 'z';
74 }
75
isAlpha(sal_Unicode c)76 bool isAlpha(sal_Unicode c) { //TODO: generally available?
77 return isUpperCase(c) || isLowerCase(c);
78 }
79
isHexDigit(sal_Unicode c)80 bool isHexDigit(sal_Unicode c) { //TODO: generally available?
81 return isDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
82 }
83
toLowerCase(sal_Unicode c)84 sal_Unicode toLowerCase(sal_Unicode c) { //TODO: generally available?
85 return isUpperCase(c) ? c + ('a' - 'A') : c;
86 }
87
equalIgnoreCase(sal_Unicode c1,sal_Unicode c2)88 bool equalIgnoreCase(sal_Unicode c1, sal_Unicode c2) {
89 //TODO: generally available?
90 return toLowerCase(c1) == toLowerCase(c2);
91 }
92
equalIgnoreEscapeCase(rtl::OUString const & s1,rtl::OUString const & s2)93 bool equalIgnoreEscapeCase(rtl::OUString const & s1, rtl::OUString const & s2) {
94 if (s1.getLength() == s2.getLength()) {
95 for (sal_Int32 i = 0; i < s1.getLength();) {
96 if (s1[i] == '%' && s2[i] == '%' && s1.getLength() - i > 2
97 && isHexDigit(s1[i + 1]) && isHexDigit(s1[i + 2])
98 && isHexDigit(s2[i + 1]) && isHexDigit(s2[i + 2])
99 && equalIgnoreCase(s1[i + 1], s2[i + 1])
100 && equalIgnoreCase(s1[i + 2], s2[i + 2]))
101 {
102 i += 3;
103 } else if (s1[i] != s2[i]) {
104 return false;
105 } else {
106 ++i;
107 }
108 }
109 return true;
110 } else {
111 return false;
112 }
113 }
114
parseScheme(rtl::OUString const & uriReference)115 sal_Int32 parseScheme(rtl::OUString const & uriReference) {
116 if (uriReference.getLength() >= 2 && isAlpha(uriReference[0])) {
117 for (sal_Int32 i = 0; i < uriReference.getLength(); ++i) {
118 sal_Unicode c = uriReference[i];
119 if (c == ':') {
120 return i;
121 } else if (!isAlpha(c) && !isDigit(c) && c != '+' && c != '-'
122 && c != '.')
123 {
124 break;
125 }
126 }
127 }
128 return -1;
129 }
130
131 class UriReference: public cppu::WeakImplHelper1< css::uri::XUriReference > {
132 public:
UriReference(rtl::OUString const & scheme,bool bIsHierarchical,bool bHasAuthority,rtl::OUString const & authority,rtl::OUString const & path,bool bHasQuery,rtl::OUString const & query)133 UriReference(
134 rtl::OUString const & scheme, bool bIsHierarchical, bool bHasAuthority,
135 rtl::OUString const & authority, rtl::OUString const & path,
136 bool bHasQuery, rtl::OUString const & query):
137 m_base(
138 scheme, bIsHierarchical, bHasAuthority, authority, path, bHasQuery,
139 query)
140 {}
141
getUriReference()142 virtual rtl::OUString SAL_CALL getUriReference()
143 throw (com::sun::star::uno::RuntimeException)
144 { return m_base.getUriReference(); }
145
isAbsolute()146 virtual sal_Bool SAL_CALL isAbsolute()
147 throw (com::sun::star::uno::RuntimeException)
148 { return m_base.isAbsolute(); }
149
getScheme()150 virtual rtl::OUString SAL_CALL getScheme()
151 throw (com::sun::star::uno::RuntimeException)
152 { return m_base.getScheme(); }
153
getSchemeSpecificPart()154 virtual rtl::OUString SAL_CALL getSchemeSpecificPart()
155 throw (com::sun::star::uno::RuntimeException)
156 { return m_base.getSchemeSpecificPart(); }
157
isHierarchical()158 virtual sal_Bool SAL_CALL isHierarchical()
159 throw (com::sun::star::uno::RuntimeException)
160 { return m_base.isHierarchical(); }
161
hasAuthority()162 virtual sal_Bool SAL_CALL hasAuthority()
163 throw (com::sun::star::uno::RuntimeException)
164 { return m_base.hasAuthority(); }
165
getAuthority()166 virtual rtl::OUString SAL_CALL getAuthority()
167 throw (com::sun::star::uno::RuntimeException)
168 { return m_base.getAuthority(); }
169
getPath()170 virtual rtl::OUString SAL_CALL getPath()
171 throw (com::sun::star::uno::RuntimeException)
172 { return m_base.getPath(); }
173
hasRelativePath()174 virtual sal_Bool SAL_CALL hasRelativePath()
175 throw (com::sun::star::uno::RuntimeException)
176 { return m_base.hasRelativePath(); }
177
getPathSegmentCount()178 virtual sal_Int32 SAL_CALL getPathSegmentCount()
179 throw (com::sun::star::uno::RuntimeException)
180 { return m_base.getPathSegmentCount(); }
181
getPathSegment(sal_Int32 index)182 virtual rtl::OUString SAL_CALL getPathSegment(sal_Int32 index)
183 throw (com::sun::star::uno::RuntimeException)
184 { return m_base.getPathSegment(index); }
185
hasQuery()186 virtual sal_Bool SAL_CALL hasQuery()
187 throw (com::sun::star::uno::RuntimeException)
188 { return m_base.hasQuery(); }
189
getQuery()190 virtual rtl::OUString SAL_CALL getQuery()
191 throw (com::sun::star::uno::RuntimeException)
192 { return m_base.getQuery(); }
193
hasFragment()194 virtual sal_Bool SAL_CALL hasFragment()
195 throw (com::sun::star::uno::RuntimeException)
196 { return m_base.hasFragment(); }
197
getFragment()198 virtual rtl::OUString SAL_CALL getFragment()
199 throw (com::sun::star::uno::RuntimeException)
200 { return m_base.getFragment(); }
201
setFragment(rtl::OUString const & fragment)202 virtual void SAL_CALL setFragment(rtl::OUString const & fragment)
203 throw (com::sun::star::uno::RuntimeException)
204 { m_base.setFragment(fragment); }
205
clearFragment()206 virtual void SAL_CALL clearFragment()
207 throw (com::sun::star::uno::RuntimeException)
208 { m_base.clearFragment(); }
209
210 private:
211 UriReference(UriReference &); // not implemented
212 void operator =(UriReference); // not implemented
213
~UriReference()214 virtual ~UriReference() {}
215
216 stoc::uriproc::UriReference m_base;
217 };
218
219 // throws std::bad_alloc
parseGeneric(rtl::OUString const & scheme,rtl::OUString const & schemeSpecificPart)220 css::uno::Reference< css::uri::XUriReference > parseGeneric(
221 rtl::OUString const & scheme, rtl::OUString const & schemeSpecificPart)
222 {
223 bool isAbsolute = scheme.getLength() != 0;
224 bool isHierarchical
225 = !isAbsolute
226 || (schemeSpecificPart.getLength() > 0 && schemeSpecificPart[0] == '/');
227 bool hasAuthority = false;
228 rtl::OUString authority;
229 rtl::OUString path;
230 bool hasQuery = false;
231 rtl::OUString query;
232 if (isHierarchical) {
233 sal_Int32 len = schemeSpecificPart.getLength();
234 sal_Int32 i = 0;
235 if (len - i >= 2 && schemeSpecificPart[i] == '/'
236 && schemeSpecificPart[i + 1] == '/')
237 {
238 i += 2;
239 sal_Int32 n = i;
240 while (i < len && schemeSpecificPart[i] != '/'
241 && schemeSpecificPart[i] != '?') {
242 ++i;
243 }
244 hasAuthority = true;
245 authority = schemeSpecificPart.copy(n, i - n);
246 }
247 sal_Int32 n = i;
248 i = schemeSpecificPart.indexOf('?', i);
249 if (i == -1) {
250 i = len;
251 }
252 path = schemeSpecificPart.copy(n, i - n);
253 if (i != len) {
254 hasQuery = true;
255 query = schemeSpecificPart.copy(i + 1);
256 }
257 } else {
258 if (schemeSpecificPart.getLength() == 0) {
259 // The scheme-specific part of an opaque URI must not be empty:
260 return 0;
261 }
262 path = schemeSpecificPart;
263 }
264 return new UriReference(
265 scheme, isHierarchical, hasAuthority, authority, path, hasQuery, query);
266 }
267
268 typedef std::vector< sal_Int32 > Segments;
269
processSegments(Segments & segments,css::uno::Reference<css::uri::XUriReference> const & uriReference,bool base,bool processSpecialSegments)270 void processSegments(
271 Segments & segments,
272 css::uno::Reference< css::uri::XUriReference > const & uriReference,
273 bool base, bool processSpecialSegments)
274 {
275 sal_Int32 count = uriReference->getPathSegmentCount() - (base ? 1 : 0);
276 OSL_ASSERT(count <= SAL_MAX_INT32 - 1 && -count >= SAL_MIN_INT32 + 1);
277 for (sal_Int32 i = 0; i < count; ++i) {
278 if (processSpecialSegments) {
279 rtl::OUString segment(uriReference->getPathSegment(i));
280 if (segment.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("."))) {
281 if (!base && i == count - 1) {
282 segments.push_back(0);
283 }
284 continue;
285 } else if (segment.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".."))) {
286 if (segments.empty()
287 || /*MSVC trouble: std::*/abs(segments.back()) == 1)
288 {
289 segments.push_back(base ? -1 : 1);
290 } else {
291 segments.pop_back();
292 }
293 continue;
294 }
295 }
296 segments.push_back(base ? -(i + 2) : i + 2);
297 }
298 }
299
300 class Factory: public cppu::WeakImplHelper2<
301 css::lang::XServiceInfo, css::uri::XUriReferenceFactory >
302 {
303 public:
Factory(css::uno::Reference<css::uno::XComponentContext> const & context)304 explicit Factory(
305 css::uno::Reference< css::uno::XComponentContext > const & context):
306 m_context(context) {}
307
308 virtual rtl::OUString SAL_CALL getImplementationName()
309 throw (css::uno::RuntimeException);
310
311 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
312 throw (css::uno::RuntimeException);
313
314 virtual css::uno::Sequence< rtl::OUString > SAL_CALL
315 getSupportedServiceNames() throw (css::uno::RuntimeException);
316
317 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
318 parse(rtl::OUString const & uriReference)
319 throw (css::uno::RuntimeException);
320
321 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
322 makeAbsolute(
323 css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
324 css::uno::Reference< css::uri::XUriReference > const & uriReference,
325 sal_Bool processSpecialBaseSegments,
326 css::uri::RelativeUriExcessParentSegments excessParentSegments)
327 throw (css::uno::RuntimeException);
328
329 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
330 makeRelative(
331 css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
332 css::uno::Reference< css::uri::XUriReference > const & uriReference,
333 sal_Bool preferAuthorityOverRelativePath,
334 sal_Bool preferAbsoluteOverRelativePath,
335 sal_Bool encodeRetainedSpecialSegments)
336 throw (css::uno::RuntimeException);
337
338 private:
339 Factory(Factory &); // not implemented
340 void operator =(Factory); // not implemented
341
~Factory()342 virtual ~Factory() {}
343
clone(css::uno::Reference<css::uri::XUriReference> const & uriReference)344 css::uno::Reference< css::uri::XUriReference > clone(
345 css::uno::Reference< css::uri::XUriReference > const & uriReference)
346 { return parse(uriReference->getUriReference()); }
347
348 css::uno::Reference< css::uno::XComponentContext > m_context;
349 };
350
getImplementationName()351 rtl::OUString Factory::getImplementationName()
352 throw (css::uno::RuntimeException)
353 {
354 return stoc_services::UriReferenceFactory::getImplementationName();
355 }
356
supportsService(rtl::OUString const & serviceName)357 sal_Bool Factory::supportsService(rtl::OUString const & serviceName)
358 throw (css::uno::RuntimeException)
359 {
360 return stoc::uriproc::supportsService(
361 getSupportedServiceNames(), serviceName);
362 }
363
getSupportedServiceNames()364 css::uno::Sequence< rtl::OUString > Factory::getSupportedServiceNames()
365 throw (css::uno::RuntimeException)
366 {
367 return stoc_services::UriReferenceFactory::getSupportedServiceNames();
368 }
369
parse(rtl::OUString const & uriReference)370 css::uno::Reference< css::uri::XUriReference > Factory::parse(
371 rtl::OUString const & uriReference) throw (css::uno::RuntimeException)
372 {
373 sal_Int32 fragment = uriReference.indexOf('#');
374 if (fragment == -1) {
375 fragment = uriReference.getLength();
376 }
377 rtl::OUString scheme;
378 rtl::OUString schemeSpecificPart;
379 rtl::OUString serviceName;
380 sal_Int32 n = parseScheme(uriReference);
381 OSL_ASSERT(n < fragment);
382 if (n >= 0) {
383 scheme = uriReference.copy(0, n);
384 schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
385 rtl::OUStringBuffer buf;
386 buf.appendAscii(
387 RTL_CONSTASCII_STRINGPARAM("com.sun.star.uri.UriSchemeParser_"));
388 for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
389 sal_Unicode c = scheme[i];
390 if (isUpperCase(c)) {
391 buf.append(toLowerCase(c));
392 } else if (c == '+') {
393 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("PLUS"));
394 } else if (c == '-') {
395 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("HYPHEN"));
396 } else if (c == '.') {
397 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("DOT"));
398 } else {
399 OSL_ASSERT(isLowerCase(c) || isDigit(c));
400 buf.append(c);
401 }
402 }
403 serviceName = buf.makeStringAndClear();
404 } else {
405 schemeSpecificPart = uriReference.copy(0, fragment);
406 }
407 css::uno::Reference< css::uri::XUriSchemeParser > parser;
408 if (serviceName.getLength() != 0) {
409 css::uno::Reference< css::lang::XMultiComponentFactory > factory(
410 m_context->getServiceManager());
411 if (factory.is()) {
412 css::uno::Reference< css::uno::XInterface > service;
413 try {
414 service = factory->createInstanceWithContext(
415 serviceName, m_context);
416 } catch (css::uno::RuntimeException &) {
417 throw;
418 } catch (css::uno::Exception & e) {
419 throw css::lang::WrappedTargetRuntimeException(
420 rtl::OUString::createFromAscii("creating service ")
421 + serviceName,
422 static_cast< cppu::OWeakObject * >(this),
423 css::uno::makeAny(e)); //TODO: preserve type of e
424 }
425 if (service.is()) {
426 parser = css::uno::Reference< css::uri::XUriSchemeParser >(
427 service, css::uno::UNO_QUERY_THROW);
428 }
429 }
430 }
431 css::uno::Reference< css::uri::XUriReference > uriRef;
432 if (parser.is()) {
433 uriRef = parser->parse(scheme, schemeSpecificPart);
434 } else {
435 try {
436 uriRef = parseGeneric(scheme, schemeSpecificPart);
437 } catch (std::bad_alloc &) {
438 throw css::uno::RuntimeException(
439 rtl::OUString::createFromAscii("std::bad_alloc"),
440 static_cast< cppu::OWeakObject * >(this));
441 }
442 }
443 if (uriRef.is() && fragment != uriReference.getLength()) {
444 uriRef->setFragment(uriReference.copy(fragment + 1));
445 }
446 return uriRef;
447 }
448
makeAbsolute(css::uno::Reference<css::uri::XUriReference> const & baseUriReference,css::uno::Reference<css::uri::XUriReference> const & uriReference,sal_Bool processSpecialBaseSegments,css::uri::RelativeUriExcessParentSegments excessParentSegments)449 css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
450 css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
451 css::uno::Reference< css::uri::XUriReference > const & uriReference,
452 sal_Bool processSpecialBaseSegments,
453 css::uri::RelativeUriExcessParentSegments excessParentSegments)
454 throw (css::uno::RuntimeException)
455 {
456 if (!baseUriReference.is() || !baseUriReference->isAbsolute()
457 || !baseUriReference->isHierarchical() || !uriReference.is()) {
458 return 0;
459 } else if (uriReference->isAbsolute()) {
460 return clone(uriReference);
461 } else if (!uriReference->hasAuthority()
462 && uriReference->getPath().getLength() == 0
463 && !uriReference->hasQuery()) {
464 css::uno::Reference< css::uri::XUriReference > abs(
465 clone(baseUriReference));
466 if (uriReference->hasFragment()) {
467 abs->setFragment(uriReference->getFragment());
468 } else {
469 abs->clearFragment();
470 }
471 return abs;
472 } else {
473 rtl::OUStringBuffer abs(baseUriReference->getScheme());
474 abs.append(static_cast< sal_Unicode >(':'));
475 if (uriReference->hasAuthority()) {
476 abs.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
477 abs.append(uriReference->getAuthority());
478 } else if (baseUriReference->hasAuthority()) {
479 abs.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
480 abs.append(baseUriReference->getAuthority());
481 }
482 if (uriReference->hasRelativePath()) {
483 Segments segments;
484 processSegments(
485 segments, baseUriReference, true, processSpecialBaseSegments);
486 processSegments(segments, uriReference, false, true);
487 // If the path component of the base URI reference is empty (which
488 // implies that the base URI reference denotes a "root entity"), and
489 // the resulting URI reference denotes the same root entity, make
490 // sure the path component of the resulting URI reference is also
491 // empty (and not "/"). RFC 2396 is unclear about this, and I chose
492 // these rules for consistent results.
493 bool slash = baseUriReference->getPath().getLength() != 0;
494 if (slash) {
495 abs.append(static_cast< sal_Unicode >('/'));
496 }
497 for (Segments::iterator i(segments.begin()); i != segments.end();
498 ++i)
499 {
500 if (*i < -1) {
501 rtl::OUString segment(
502 baseUriReference->getPathSegment(-(*i + 2)));
503 if (segment.getLength() != 0 || segments.size() > 1) {
504 if (!slash) {
505 abs.append(static_cast< sal_Unicode >('/'));
506 }
507 abs.append(segment);
508 slash = true;
509 abs.append(static_cast< sal_Unicode >('/'));
510 }
511 } else if (*i > 1) {
512 rtl::OUString segment(uriReference->getPathSegment(*i - 2));
513 if (segment.getLength() != 0 || segments.size() > 1) {
514 if (!slash) {
515 abs.append(static_cast< sal_Unicode >('/'));
516 }
517 abs.append(segment);
518 slash = false;
519 }
520 } else if (*i == 0) {
521 if (segments.size() > 1 && !slash) {
522 abs.append(static_cast< sal_Unicode >('/'));
523 }
524 } else {
525 switch (excessParentSegments) {
526 case css::uri::RelativeUriExcessParentSegments_ERROR:
527 return 0;
528
529 case css::uri::RelativeUriExcessParentSegments_RETAIN:
530 if (!slash) {
531 abs.append(static_cast< sal_Unicode >('/'));
532 }
533 abs.appendAscii(RTL_CONSTASCII_STRINGPARAM(".."));
534 slash = *i < 0;
535 if (slash) {
536 abs.append(static_cast< sal_Unicode >('/'));
537 }
538 break;
539
540 case css::uri::RelativeUriExcessParentSegments_REMOVE:
541 break;
542
543 default:
544 OSL_ASSERT(false);
545 break;
546 }
547 }
548 }
549 } else {
550 abs.append(uriReference->getPath());
551 }
552 if (uriReference->hasQuery()) {
553 abs.append(static_cast< sal_Unicode >('?'));
554 abs.append(uriReference->getQuery());
555 }
556 if (uriReference->hasFragment()) {
557 abs.append(static_cast< sal_Unicode >('#'));
558 abs.append(uriReference->getFragment());
559 }
560 return parse(abs.makeStringAndClear());
561 }
562 }
563
makeRelative(css::uno::Reference<css::uri::XUriReference> const & baseUriReference,css::uno::Reference<css::uri::XUriReference> const & uriReference,sal_Bool preferAuthorityOverRelativePath,sal_Bool preferAbsoluteOverRelativePath,sal_Bool encodeRetainedSpecialSegments)564 css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
565 css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
566 css::uno::Reference< css::uri::XUriReference > const & uriReference,
567 sal_Bool preferAuthorityOverRelativePath,
568 sal_Bool preferAbsoluteOverRelativePath,
569 sal_Bool encodeRetainedSpecialSegments)
570 throw (css::uno::RuntimeException)
571 {
572 if (!baseUriReference.is() || !baseUriReference->isAbsolute()
573 || !baseUriReference->isHierarchical() || !uriReference.is()) {
574 return 0;
575 } else if (!uriReference->isAbsolute() || !uriReference->isHierarchical()
576 || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
577 uriReference->getScheme())) {
578 return clone(uriReference);
579 } else {
580 rtl::OUStringBuffer rel;
581 bool omitQuery = false;
582 if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
583 || !equalIgnoreEscapeCase(
584 baseUriReference->getAuthority(),
585 uriReference->getAuthority()))
586 {
587 if (uriReference->hasAuthority()) {
588 rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
589 rel.append(uriReference->getAuthority());
590 }
591 rel.append(uriReference->getPath());
592 } else if ((equalIgnoreEscapeCase(
593 baseUriReference->getPath(), uriReference->getPath())
594 || (baseUriReference->getPath().getLength() <= 1
595 && uriReference->getPath().getLength() <= 1))
596 && baseUriReference->hasQuery() == uriReference->hasQuery()
597 && equalIgnoreEscapeCase(
598 baseUriReference->getQuery(), uriReference->getQuery()))
599 {
600 omitQuery = true;
601 } else {
602 sal_Int32 count1 = std::max< sal_Int32 >(
603 baseUriReference->getPathSegmentCount(), 1);
604 sal_Int32 count2 = std::max< sal_Int32 >(
605 uriReference->getPathSegmentCount(), 1);
606 sal_Int32 i = 0;
607 for (; i < std::min(count1, count2) - 1; ++i) {
608 if (!equalIgnoreEscapeCase(
609 baseUriReference->getPathSegment(i),
610 uriReference->getPathSegment(i)))
611 {
612 break;
613 }
614 }
615 if (i == 0 && preferAbsoluteOverRelativePath
616 && (preferAuthorityOverRelativePath
617 || !uriReference->getPath().matchAsciiL(
618 RTL_CONSTASCII_STRINGPARAM("//"))))
619 {
620 if (baseUriReference->getPath().getLength() > 1
621 || uriReference->getPath().getLength() > 1)
622 {
623 if (uriReference->getPath().getLength() == 0) {
624 rel.append(static_cast< sal_Unicode >('/'));
625 } else {
626 OSL_ASSERT(uriReference->getPath()[0] == '/');
627 if (uriReference->getPath().matchAsciiL(
628 RTL_CONSTASCII_STRINGPARAM("//"))) {
629 OSL_ASSERT(uriReference->hasAuthority());
630 rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
631 rel.append(uriReference->getAuthority());
632 }
633 rel.append(uriReference->getPath());
634 }
635 }
636 } else {
637 bool segments = false;
638 for (sal_Int32 j = i; j < count1 - 1; ++j) {
639 if (segments) {
640 rel.append(static_cast< sal_Unicode >('/'));
641 }
642 rel.appendAscii(RTL_CONSTASCII_STRINGPARAM(".."));
643 segments = true;
644 }
645 if (i < count2 - 1
646 || (uriReference->getPathSegment(count2 - 1).getLength()
647 != 0))
648 {
649 if (!segments
650 && (uriReference->getPathSegment(i).getLength() == 0
651 || (parseScheme(uriReference->getPathSegment(i))
652 >= 0)))
653 {
654 rel.append(static_cast< sal_Unicode >('.'));
655 segments = true;
656 }
657 for (; i < count2; ++i) {
658 if (segments) {
659 rel.append(static_cast< sal_Unicode >('/'));
660 }
661 rtl::OUString s(uriReference->getPathSegment(i));
662 if (encodeRetainedSpecialSegments
663 && s.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".")))
664 {
665 rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("%2E"));
666 } else if (encodeRetainedSpecialSegments
667 && s.equalsAsciiL(
668 RTL_CONSTASCII_STRINGPARAM("..")))
669 {
670 rel.appendAscii(
671 RTL_CONSTASCII_STRINGPARAM("%2E%2E"));
672 } else {
673 rel.append(s);
674 }
675 segments = true;
676 }
677 }
678 }
679 }
680 if (!omitQuery && uriReference->hasQuery()) {
681 rel.append(static_cast< sal_Unicode >('?'));
682 rel.append(uriReference->getQuery());
683 }
684 if (uriReference->hasFragment()) {
685 rel.append(static_cast< sal_Unicode >('#'));
686 rel.append(uriReference->getFragment());
687 }
688 return parse(rel.makeStringAndClear());
689 }
690 }
691
692 }
693
694 namespace stoc_services { namespace UriReferenceFactory {
695
create(css::uno::Reference<css::uno::XComponentContext> const & context)696 css::uno::Reference< css::uno::XInterface > create(
697 css::uno::Reference< css::uno::XComponentContext > const & context)
698 SAL_THROW((css::uno::Exception))
699 {
700 try {
701 return static_cast< cppu::OWeakObject * >(new Factory(context));
702 } catch (std::bad_alloc &) {
703 throw css::uno::RuntimeException(
704 rtl::OUString::createFromAscii("std::bad_alloc"), 0);
705 }
706 }
707
getImplementationName()708 rtl::OUString getImplementationName() {
709 return rtl::OUString::createFromAscii(
710 "com.sun.star.comp.uri.UriReferenceFactory");
711 }
712
getSupportedServiceNames()713 css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
714 css::uno::Sequence< rtl::OUString > s(1);
715 s[0] = rtl::OUString::createFromAscii(
716 "com.sun.star.uri.UriReferenceFactory");
717 return s;
718 }
719
720 } }
721