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