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