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