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