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 655 : bool isDigit(sal_Unicode c) {
60 655 : return c >= '0' && c <= '9';
61 : }
62 :
63 25134 : bool isUpperCase(sal_Unicode c) {
64 25134 : return c >= 'A' && c <= 'Z';
65 : }
66 :
67 16338 : bool isLowerCase(sal_Unicode c) {
68 16338 : return c >= 'a' && c <= 'z';
69 : }
70 :
71 16442 : bool isAlpha(sal_Unicode c) {
72 16442 : 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 2 : sal_Unicode toLowerCase(sal_Unicode c) {
80 2 : 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 0 : bool equalIgnoreEscapeCase(rtl::OUString const & s1, rtl::OUString const & s2) {
88 0 : if (s1.getLength() == s2.getLength()) {
89 0 : for (sal_Int32 i = 0; i < s1.getLength();) {
90 0 : 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 0 : } else if (s1[i] != s2[i]) {
98 0 : return false;
99 : } else {
100 0 : ++i;
101 : }
102 : }
103 0 : return true;
104 : } else {
105 0 : return false;
106 : }
107 : }
108 :
109 2726 : sal_Int32 parseScheme(rtl::OUString const & uriReference) {
110 2726 : if (uriReference.getLength() >= 2 && isAlpha(uriReference[0])) {
111 16185 : for (sal_Int32 i = 0; i < uriReference.getLength(); ++i) {
112 15881 : sal_Unicode c = uriReference[i];
113 15881 : if (c == ':') {
114 2165 : return i;
115 13716 : } else if (!isAlpha(c) && !isDigit(c) && c != '+' && c != '-'
116 : && c != '.')
117 : {
118 257 : break;
119 : }
120 : }
121 : }
122 561 : return -1;
123 : }
124 :
125 : class UriReference: public cppu::WeakImplHelper1< css::uri::XUriReference > {
126 : public:
127 2724 : 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 2724 : query)
134 2724 : {}
135 :
136 704 : virtual rtl::OUString SAL_CALL getUriReference()
137 : throw (com::sun::star::uno::RuntimeException)
138 704 : { return m_base.getUriReference(); }
139 :
140 1122 : virtual sal_Bool SAL_CALL isAbsolute()
141 : throw (com::sun::star::uno::RuntimeException)
142 1122 : { return m_base.isAbsolute(); }
143 :
144 561 : virtual rtl::OUString SAL_CALL getScheme()
145 : throw (com::sun::star::uno::RuntimeException)
146 561 : { 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 561 : virtual sal_Bool SAL_CALL isHierarchical()
153 : throw (com::sun::star::uno::RuntimeException)
154 561 : { return m_base.isHierarchical(); }
155 :
156 1683 : virtual sal_Bool SAL_CALL hasAuthority()
157 : throw (com::sun::star::uno::RuntimeException)
158 1683 : { return m_base.hasAuthority(); }
159 :
160 561 : virtual rtl::OUString SAL_CALL getAuthority()
161 : throw (com::sun::star::uno::RuntimeException)
162 561 : { return m_base.getAuthority(); }
163 :
164 1665 : virtual rtl::OUString SAL_CALL getPath()
165 : throw (com::sun::star::uno::RuntimeException)
166 1665 : { return m_base.getPath(); }
167 :
168 561 : virtual sal_Bool SAL_CALL hasRelativePath()
169 : throw (com::sun::star::uno::RuntimeException)
170 561 : { return m_base.hasRelativePath(); }
171 :
172 1140 : virtual sal_Int32 SAL_CALL getPathSegmentCount()
173 : throw (com::sun::star::uno::RuntimeException)
174 1140 : { return m_base.getPathSegmentCount(); }
175 :
176 2624 : virtual rtl::OUString SAL_CALL getPathSegment(sal_Int32 index)
177 : throw (com::sun::star::uno::RuntimeException)
178 2624 : { return m_base.getPathSegment(index); }
179 :
180 561 : virtual sal_Bool SAL_CALL hasQuery()
181 : throw (com::sun::star::uno::RuntimeException)
182 561 : { return m_base.hasQuery(); }
183 :
184 0 : virtual rtl::OUString SAL_CALL getQuery()
185 : throw (com::sun::star::uno::RuntimeException)
186 0 : { return m_base.getQuery(); }
187 :
188 561 : virtual sal_Bool SAL_CALL hasFragment()
189 : throw (com::sun::star::uno::RuntimeException)
190 561 : { return m_base.hasFragment(); }
191 :
192 0 : virtual rtl::OUString SAL_CALL getFragment()
193 : throw (com::sun::star::uno::RuntimeException)
194 0 : { return m_base.getFragment(); }
195 :
196 0 : virtual void SAL_CALL setFragment(rtl::OUString const & fragment)
197 : throw (com::sun::star::uno::RuntimeException)
198 0 : { m_base.setFragment(fragment); }
199 :
200 686 : virtual void SAL_CALL clearFragment()
201 : throw (com::sun::star::uno::RuntimeException)
202 686 : { m_base.clearFragment(); }
203 :
204 : private:
205 : UriReference(UriReference &); // not implemented
206 : void operator =(UriReference); // not implemented
207 :
208 5448 : virtual ~UriReference() {}
209 :
210 : stoc::uriproc::UriReference m_base;
211 : };
212 :
213 : // throws std::bad_alloc
214 2724 : css::uno::Reference< css::uri::XUriReference > parseGeneric(
215 : rtl::OUString const & scheme, rtl::OUString const & schemeSpecificPart)
216 : {
217 2724 : bool isAbsolute = !scheme.isEmpty();
218 : bool isHierarchical
219 2724 : = !isAbsolute
220 2724 : || (!schemeSpecificPart.isEmpty() && schemeSpecificPart[0] == '/');
221 2724 : bool hasAuthority = false;
222 2724 : rtl::OUString authority;
223 2724 : rtl::OUString path;
224 2724 : bool hasQuery = false;
225 2724 : rtl::OUString query;
226 2724 : if (isHierarchical) {
227 2724 : sal_Int32 len = schemeSpecificPart.getLength();
228 2724 : sal_Int32 i = 0;
229 4887 : if (len - i >= 2 && schemeSpecificPart[i] == '/'
230 2163 : && schemeSpecificPart[i + 1] == '/')
231 : {
232 2163 : i += 2;
233 2163 : sal_Int32 n = i;
234 4326 : while (i < len && schemeSpecificPart[i] != '/'
235 0 : && schemeSpecificPart[i] != '?') {
236 0 : ++i;
237 : }
238 2163 : hasAuthority = true;
239 2163 : authority = schemeSpecificPart.copy(n, i - n);
240 : }
241 2724 : sal_Int32 n = i;
242 2724 : i = schemeSpecificPart.indexOf('?', i);
243 2724 : if (i == -1) {
244 2724 : i = len;
245 : }
246 2724 : path = schemeSpecificPart.copy(n, i - n);
247 2724 : if (i != len) {
248 0 : hasQuery = true;
249 0 : query = schemeSpecificPart.copy(i + 1);
250 : }
251 : } else {
252 0 : if (schemeSpecificPart.isEmpty()) {
253 : // The scheme-specific part of an opaque URI must not be empty:
254 0 : return 0;
255 : }
256 0 : path = schemeSpecificPart;
257 : }
258 : return new UriReference(
259 2724 : scheme, isHierarchical, hasAuthority, authority, path, hasQuery, query);
260 : }
261 :
262 : typedef std::vector< sal_Int32 > Segments;
263 :
264 1122 : void processSegments(
265 : Segments & segments,
266 : css::uno::Reference< css::uri::XUriReference > const & uriReference,
267 : bool base, bool processSpecialSegments)
268 : {
269 1122 : sal_Int32 count = uriReference->getPathSegmentCount() - (base ? 1 : 0);
270 : OSL_ASSERT(count <= SAL_MAX_INT32 - 1 && -count >= SAL_MIN_INT32 + 1);
271 2425 : for (sal_Int32 i = 0; i < count; ++i) {
272 1303 : if (processSpecialSegments) {
273 1303 : rtl::OUString segment(uriReference->getPathSegment(i));
274 1303 : if ( segment == "." ) {
275 0 : if (!base && i == count - 1) {
276 0 : segments.push_back(0);
277 : }
278 0 : continue;
279 1303 : } 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 1303 : }
289 : }
290 1303 : segments.push_back(base ? -(i + 2) : i + 2);
291 : }
292 1122 : }
293 :
294 : class Factory: public cppu::WeakImplHelper2<
295 : css::lang::XServiceInfo, css::uri::XUriReferenceFactory >
296 : {
297 : public:
298 1372 : explicit Factory(
299 : css::uno::Reference< css::uno::XComponentContext > const & context):
300 1372 : 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 2744 : virtual ~Factory() {}
337 :
338 0 : css::uno::Reference< css::uri::XUriReference > clone(
339 : css::uno::Reference< css::uri::XUriReference > const & uriReference)
340 0 : { 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 2726 : css::uno::Reference< css::uri::XUriReference > Factory::parse(
365 : rtl::OUString const & uriReference) throw (css::uno::RuntimeException)
366 : {
367 2726 : sal_Int32 fragment = uriReference.indexOf('#');
368 2726 : if (fragment == -1) {
369 2726 : fragment = uriReference.getLength();
370 : }
371 2726 : rtl::OUString scheme;
372 2726 : rtl::OUString schemeSpecificPart;
373 2726 : rtl::OUString serviceName;
374 2726 : sal_Int32 n = parseScheme(uriReference);
375 : OSL_ASSERT(n < fragment);
376 2726 : if (n >= 0) {
377 2165 : scheme = uriReference.copy(0, n);
378 2165 : schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
379 2165 : rtl::OUStringBuffer buf;
380 : buf.appendAscii(
381 2165 : RTL_CONSTASCII_STRINGPARAM("com.sun.star.uri.UriSchemeParser_"));
382 10855 : for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
383 8690 : sal_Unicode c = scheme[i];
384 8690 : if (isUpperCase(c)) {
385 2 : buf.append(toLowerCase(c));
386 8688 : } else if (c == '+') {
387 0 : buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("PLUS"));
388 8688 : } else if (c == '-') {
389 0 : buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("HYPHEN"));
390 8688 : } else if (c == '.') {
391 6 : buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("DOT"));
392 : } else {
393 : OSL_ASSERT(isLowerCase(c) || isDigit(c));
394 8682 : buf.append(c);
395 : }
396 : }
397 2165 : serviceName = buf.makeStringAndClear();
398 : } else {
399 561 : schemeSpecificPart = uriReference.copy(0, fragment);
400 : }
401 2726 : css::uno::Reference< css::uri::XUriSchemeParser > parser;
402 2726 : if (!serviceName.isEmpty()) {
403 : css::uno::Reference< css::lang::XMultiComponentFactory > factory(
404 2165 : m_context->getServiceManager());
405 2165 : if (factory.is()) {
406 2165 : css::uno::Reference< css::uno::XInterface > service;
407 : try {
408 2165 : service = factory->createInstanceWithContext(
409 2165 : 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 2165 : if (service.is()) {
420 : parser = css::uno::Reference< css::uri::XUriSchemeParser >(
421 2 : service, css::uno::UNO_QUERY_THROW);
422 2165 : }
423 2165 : }
424 : }
425 2726 : css::uno::Reference< css::uri::XUriReference > uriRef;
426 2726 : if (parser.is()) {
427 2 : uriRef = parser->parse(scheme, schemeSpecificPart);
428 : } else {
429 : try {
430 2724 : 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 2726 : if (uriRef.is() && fragment != uriReference.getLength()) {
438 0 : uriRef->setFragment(uriReference.copy(fragment + 1));
439 : }
440 2726 : return uriRef;
441 : }
442 :
443 561 : 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 1683 : if (!baseUriReference.is() || !baseUriReference->isAbsolute()
451 1122 : || !baseUriReference->isHierarchical() || !uriReference.is()) {
452 0 : return 0;
453 561 : } else if (uriReference->isAbsolute()) {
454 0 : return clone(uriReference);
455 2244 : } else if (!uriReference->hasAuthority()
456 1683 : && 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 561 : rtl::OUStringBuffer abs(baseUriReference->getScheme());
468 561 : abs.append(static_cast< sal_Unicode >(':'));
469 561 : if (uriReference->hasAuthority()) {
470 0 : abs.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
471 0 : abs.append(uriReference->getAuthority());
472 561 : } else if (baseUriReference->hasAuthority()) {
473 561 : abs.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
474 561 : abs.append(baseUriReference->getAuthority());
475 : }
476 561 : if (uriReference->hasRelativePath()) {
477 561 : Segments segments;
478 : processSegments(
479 561 : segments, baseUriReference, true, processSpecialBaseSegments);
480 561 : 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 561 : bool slash = !baseUriReference->getPath().isEmpty();
488 561 : if (slash) {
489 561 : abs.append(static_cast< sal_Unicode >('/'));
490 : }
491 1864 : for (Segments::iterator i(segments.begin()); i != segments.end();
492 : ++i)
493 : {
494 1303 : if (*i < -1) {
495 : rtl::OUString segment(
496 485 : baseUriReference->getPathSegment(-(*i + 2)));
497 485 : if (!segment.isEmpty() || segments.size() > 1) {
498 485 : if (!slash) {
499 0 : abs.append(static_cast< sal_Unicode >('/'));
500 : }
501 485 : abs.append(segment);
502 485 : slash = true;
503 485 : abs.append(static_cast< sal_Unicode >('/'));
504 485 : }
505 818 : } else if (*i > 1) {
506 818 : rtl::OUString segment(uriReference->getPathSegment(*i - 2));
507 818 : if (!segment.isEmpty() || segments.size() > 1) {
508 818 : if (!slash) {
509 257 : abs.append(static_cast< sal_Unicode >('/'));
510 : }
511 818 : abs.append(segment);
512 818 : slash = false;
513 818 : }
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 561 : }
543 : } else {
544 0 : abs.append(uriReference->getPath());
545 : }
546 561 : if (uriReference->hasQuery()) {
547 0 : abs.append(static_cast< sal_Unicode >('?'));
548 0 : abs.append(uriReference->getQuery());
549 : }
550 561 : if (uriReference->hasFragment()) {
551 0 : abs.append(static_cast< sal_Unicode >('#'));
552 0 : abs.append(uriReference->getFragment());
553 : }
554 561 : return parse(abs.makeStringAndClear());
555 : }
556 : }
557 :
558 0 : 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 0 : if (!baseUriReference.is() || !baseUriReference->isAbsolute()
567 0 : || !baseUriReference->isHierarchical() || !uriReference.is()) {
568 0 : return 0;
569 0 : } else if (!uriReference->isAbsolute() || !uriReference->isHierarchical()
570 0 : || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
571 0 : uriReference->getScheme())) {
572 0 : return clone(uriReference);
573 : } else {
574 0 : rtl::OUStringBuffer rel;
575 0 : bool omitQuery = false;
576 0 : if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
577 : || !equalIgnoreEscapeCase(
578 0 : baseUriReference->getAuthority(),
579 0 : 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 0 : } else if ((equalIgnoreEscapeCase(
587 0 : baseUriReference->getPath(), uriReference->getPath())
588 0 : || (baseUriReference->getPath().getLength() <= 1
589 0 : && uriReference->getPath().getLength() <= 1))
590 0 : && baseUriReference->hasQuery() == uriReference->hasQuery()
591 : && equalIgnoreEscapeCase(
592 0 : baseUriReference->getQuery(), uriReference->getQuery()))
593 : {
594 0 : omitQuery = true;
595 : } else {
596 : sal_Int32 count1 = std::max< sal_Int32 >(
597 0 : baseUriReference->getPathSegmentCount(), 1);
598 : sal_Int32 count2 = std::max< sal_Int32 >(
599 0 : uriReference->getPathSegmentCount(), 1);
600 0 : sal_Int32 i = 0;
601 0 : for (; i < std::min(count1, count2) - 1; ++i) {
602 0 : if (!equalIgnoreEscapeCase(
603 0 : baseUriReference->getPathSegment(i),
604 0 : uriReference->getPathSegment(i)))
605 : {
606 0 : break;
607 : }
608 : }
609 0 : if (i == 0 && preferAbsoluteOverRelativePath
610 : && (preferAuthorityOverRelativePath
611 0 : || !uriReference->getPath().matchAsciiL(
612 0 : RTL_CONSTASCII_STRINGPARAM("//"))))
613 : {
614 0 : if (baseUriReference->getPath().getLength() > 1
615 0 : || uriReference->getPath().getLength() > 1)
616 : {
617 0 : if (uriReference->getPath().isEmpty()) {
618 0 : rel.append(static_cast< sal_Unicode >('/'));
619 : } else {
620 : OSL_ASSERT(uriReference->getPath()[0] == '/');
621 0 : if (uriReference->getPath().matchAsciiL(
622 0 : RTL_CONSTASCII_STRINGPARAM("//"))) {
623 : OSL_ASSERT(uriReference->hasAuthority());
624 0 : rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
625 0 : rel.append(uriReference->getAuthority());
626 : }
627 0 : rel.append(uriReference->getPath());
628 : }
629 : }
630 : } else {
631 0 : bool segments = false;
632 0 : for (sal_Int32 j = i; j < count1 - 1; ++j) {
633 0 : if (segments) {
634 0 : rel.append(static_cast< sal_Unicode >('/'));
635 : }
636 0 : rel.appendAscii(RTL_CONSTASCII_STRINGPARAM(".."));
637 0 : segments = true;
638 : }
639 0 : if (i < count2 - 1
640 0 : || (!uriReference->getPathSegment(count2 - 1).isEmpty()))
641 : {
642 0 : if (!segments
643 0 : && (uriReference->getPathSegment(i).isEmpty()
644 0 : || (parseScheme(uriReference->getPathSegment(i))
645 : >= 0)))
646 : {
647 0 : rel.append(static_cast< sal_Unicode >('.'));
648 0 : segments = true;
649 : }
650 0 : for (; i < count2; ++i) {
651 0 : if (segments) {
652 0 : rel.append(static_cast< sal_Unicode >('/'));
653 : }
654 0 : rtl::OUString s(uriReference->getPathSegment(i));
655 0 : if (encodeRetainedSpecialSegments
656 0 : && s.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".")))
657 : {
658 0 : rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("%2E"));
659 0 : } 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 0 : rel.append(s);
667 : }
668 0 : segments = true;
669 0 : }
670 : }
671 : }
672 : }
673 0 : if (!omitQuery && uriReference->hasQuery()) {
674 0 : rel.append(static_cast< sal_Unicode >('?'));
675 0 : rel.append(uriReference->getQuery());
676 : }
677 0 : if (uriReference->hasFragment()) {
678 0 : rel.append(static_cast< sal_Unicode >('#'));
679 0 : rel.append(uriReference->getFragment());
680 : }
681 0 : return parse(rel.makeStringAndClear());
682 : }
683 : }
684 :
685 : }
686 :
687 : namespace stoc_services { namespace UriReferenceFactory {
688 :
689 1372 : 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 1372 : 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 28 : rtl::OUString getImplementationName() {
702 : return rtl::OUString(
703 28 : RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.uri.UriReferenceFactory"));
704 : }
705 :
706 18 : css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
707 18 : css::uno::Sequence< rtl::OUString > s(1);
708 18 : s[0] = rtl::OUString(
709 36 : RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uri.UriReferenceFactory"));
710 18 : return s;
711 : }
712 :
713 : } }
714 :
715 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|