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>
47#include <rtl/character.hxx>
48#include <rtl/ustrbuf.hxx>
49#include <rtl/ustring.hxx>
56bool equalIgnoreEscapeCase(std::u16string_view s1, std::u16string_view s2) {
57 if (s1.size() == s2.size()) {
58 for (
size_t i = 0;
i < s1.size();) {
59 if (s1[i] ==
'%' && s2[i] ==
'%' && s1.size() - i > 2
60 && rtl::isAsciiHexDigit(s1[i + 1])
61 && rtl::isAsciiHexDigit(s1[i + 2])
62 && rtl::isAsciiHexDigit(s2[i + 1])
63 && rtl::isAsciiHexDigit(s2[i + 2])
64 && rtl::compareIgnoreAsciiCase(s1[i + 1], s2[i + 1]) == 0
65 && rtl::compareIgnoreAsciiCase(s1[i + 2], s2[i + 2]) == 0)
68 }
else if (s1[i] != s2[i]) {
80sal_Int32 parseScheme(std::u16string_view uriReference) {
81 if (uriReference.size() >= 2 && rtl::isAsciiAlpha(uriReference[0])) {
82 for (
size_t i = 0;
i < uriReference.size(); ++
i) {
86 }
else if (!rtl::isAsciiAlpha(c) && !rtl::isAsciiDigit(c)
87 && c !=
'+' && c !=
'-' && c !=
'.')
97 public cppu::WeakImplHelper<css::uri::XUriReference>
101 OUString
const & scheme,
bool bHasAuthority,
102 OUString
const & authority, OUString
const & path,
103 bool bHasQuery, OUString
const & query):
105 scheme, bHasAuthority, authority, path, bHasQuery,
109 UriReference(
const UriReference&) =
delete;
110 UriReference& operator=(
const UriReference&) =
delete;
112 virtual OUString SAL_CALL getUriReference()
override
113 {
return m_base.getUriReference(); }
115 virtual sal_Bool SAL_CALL isAbsolute()
override
116 {
return m_base.isAbsolute(); }
118 virtual OUString SAL_CALL getScheme()
override
119 {
return m_base.getScheme(); }
121 virtual OUString SAL_CALL getSchemeSpecificPart()
override
122 {
return m_base.getSchemeSpecificPart(); }
124 virtual sal_Bool SAL_CALL isHierarchical()
override
125 {
return m_base.isHierarchical(); }
127 virtual sal_Bool SAL_CALL hasAuthority()
override
128 {
return m_base.hasAuthority(); }
130 virtual OUString SAL_CALL getAuthority()
override
131 {
return m_base.getAuthority(); }
133 virtual OUString SAL_CALL getPath()
override
134 {
return m_base.getPath(); }
136 virtual sal_Bool SAL_CALL hasRelativePath()
override
137 {
return m_base.hasRelativePath(); }
139 virtual sal_Int32 SAL_CALL getPathSegmentCount()
override
140 {
return m_base.getPathSegmentCount(); }
142 virtual OUString SAL_CALL getPathSegment(sal_Int32 index)
override
143 {
return m_base.getPathSegment(index); }
145 virtual sal_Bool SAL_CALL hasQuery()
override
146 {
return m_base.hasQuery(); }
148 virtual OUString SAL_CALL getQuery()
override
149 {
return m_base.getQuery(); }
151 virtual sal_Bool SAL_CALL hasFragment()
override
152 {
return m_base.hasFragment(); }
154 virtual OUString SAL_CALL getFragment()
override
155 {
return m_base.getFragment(); }
157 virtual void SAL_CALL setFragment(OUString
const & fragment)
override
158 { m_base.setFragment(fragment); }
160 virtual void SAL_CALL clearFragment()
override
161 { m_base.clearFragment(); }
164 virtual ~UriReference()
override {}
169css::uno::Reference< css::uri::XUriReference > parseGeneric(
170 OUString
const & scheme, OUString
const & schemeSpecificPart)
172 sal_Int32 len = schemeSpecificPart.getLength();
174 bool hasAuthority =
false;
176 if (len - i >= 2 && schemeSpecificPart[i] ==
'/'
177 && schemeSpecificPart[i + 1] ==
'/')
181 while (i < len && schemeSpecificPart[i] !=
'/'
182 && schemeSpecificPart[i] !=
'?') {
186 authority = schemeSpecificPart.copy(n, i - n);
189 i = schemeSpecificPart.indexOf(
'?', i);
193 OUString path = schemeSpecificPart.copy(n, i - n);
194 bool hasQuery =
false;
198 query = schemeSpecificPart.copy(i + 1);
200 return new UriReference(
201 scheme, hasAuthority, authority, path, hasQuery, query);
207 std::u16string_view segment;
209 Segment(
bool theLeadingSlash,
bool theExcessParent, std::u16string_view theSegment):
210 leadingSlash(theLeadingSlash), excessParent(theExcessParent), segment(theSegment) {}
213std::pair<std::vector<Segment>,
bool> processSegments(
214 std::u16string_view first, std::u16string_view second,
bool processSpecialSegments)
216 std::vector<Segment> segments;
217 bool processed =
false;
218 std::u16string_view
const * half = &
first;
221 std::size_t
index = 0;
223 if (index == half->length()) {
227 if (index != half->length()) {
228 if ((*half)[index] == u
'/') {
233 if (index == half->length() && half == &first) {
237 if (index == half->length()) {
239 segments.emplace_back(
true,
false, std::u16string_view());
243 auto const n = std::min(half->find(u
'/', index), half->length());
244 auto const leadingSlash = slash;
245 auto const segment = half->substr(index, n - index);
246 auto const process = processSpecialSegments || half == &second;
249 if (index == half->length() && half == &first) {
253 if (index != half->length() && (*half)[index] == u
'/') {
258 if (segment == u
".") {
259 slash = leadingSlash;
262 }
else if (segment == u
"..") {
263 if (segments.empty() || segments.back().excessParent) {
264 segments.emplace_back(leadingSlash,
true, segment);
269 slash = leadingSlash;
275 segments.emplace_back(leadingSlash,
false, segment);
278 return {segments, processed};
282 public cppu::WeakImplHelper<
283 css::lang::XServiceInfo, css::uri::XUriReferenceFactory>
287 css::uno::Reference< css::uno::XComponentContext > context):
288 m_context(
std::move(context)) {}
290 Factory(
const Factory&) =
delete;
291 Factory& operator=(
const Factory&) =
delete;
297 virtual css::uno::Sequence< OUString > SAL_CALL
300 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
301 parse(OUString
const & uriReference)
override;
303 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
305 css::uno::Reference< css::uri::XUriReference >
const & baseUriReference,
306 css::uno::Reference< css::uri::XUriReference >
const & uriReference,
307 sal_Bool processAdditionalSpecialSegments,
308 css::uri::RelativeUriExcessParentSegments excessParentSegments)
override;
310 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
312 css::uno::Reference< css::uri::XUriReference >
const & baseUriReference,
313 css::uno::Reference< css::uri::XUriReference >
const & uriReference,
314 sal_Bool preferAuthorityOverRelativePath,
315 sal_Bool preferAbsoluteOverRelativePath,
316 sal_Bool encodeRetainedSpecialSegments)
override;
319 virtual ~Factory()
override {}
321 css::uno::Reference< css::uri::XUriReference >
clone(
322 css::uno::Reference< css::uri::XUriReference >
const & uriReference)
323 {
return parse(uriReference->getUriReference()); }
325 css::uno::Reference< css::uno::XComponentContext > m_context;
328OUString Factory::getImplementationName()
330 return "com.sun.star.comp.uri.UriReferenceFactory";
333sal_Bool Factory::supportsService(OUString
const & serviceName)
338css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
340 css::uno::Sequence< OUString > s {
"com.sun.star.uri.UriReferenceFactory" };
344css::uno::Reference< css::uri::XUriReference > Factory::parse(
345 OUString
const & uriReference)
347 sal_Int32
fragment = uriReference.indexOf(
'#');
348 if (fragment == -1) {
349 fragment = uriReference.getLength();
352 OUString schemeSpecificPart;
353 OUString serviceName;
354 sal_Int32
n = parseScheme(uriReference);
355 assert(n < fragment);
357 scheme = uriReference.copy(0, n);
358 schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
359 OUStringBuffer buf(128);
360 buf.append(
"com.sun.star.uri.UriSchemeParser_");
361 for (sal_Int32 i = 0;
i < scheme.getLength(); ++
i) {
363 if (rtl::isAsciiUpperCase(c)) {
364 buf.append(
static_cast<sal_Unicode>(rtl::toAsciiLowerCase(c)));
365 }
else if (c ==
'+') {
367 }
else if (c ==
'-') {
368 buf.append(
"HYPHEN");
369 }
else if (c ==
'.') {
372 assert(rtl::isAsciiLowerCase(c) || rtl::isAsciiDigit(c));
376 serviceName = buf.makeStringAndClear();
378 schemeSpecificPart = uriReference.copy(0, fragment);
380 css::uno::Reference< css::uri::XUriSchemeParser >
parser;
381 if (!serviceName.isEmpty()) {
382 css::uno::Reference< css::lang::XMultiComponentFactory > factory(
383 m_context->getServiceManager());
385 css::uno::Reference< css::uno::XInterface > service;
387 service = factory->createInstanceWithContext(
388 serviceName, m_context);
389 }
catch (css::uno::RuntimeException &) {
391 }
catch (
const css::uno::Exception &) {
393 throw css::lang::WrappedTargetRuntimeException(
394 "creating service " + serviceName,
399 parser.set( service, css::uno::UNO_QUERY_THROW);
403 css::uno::Reference< css::uri::XUriReference > uriRef(
405 ?
parser->parse(scheme, schemeSpecificPart)
406 : parseGeneric(scheme, schemeSpecificPart));
407 if (uriRef.is() && fragment != uriReference.getLength()) {
408 uriRef->setFragment(uriReference.copy(fragment + 1));
413css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
414 css::uno::Reference< css::uri::XUriReference >
const & baseUriReference,
415 css::uno::Reference< css::uri::XUriReference >
const & uriReference,
416 sal_Bool processAdditionalSpecialSegments,
417 css::uri::RelativeUriExcessParentSegments excessParentSegments)
419 if (!baseUriReference.is() || !baseUriReference->isAbsolute()
420 || !uriReference.is()) {
422 }
else if (uriReference->isAbsolute()) {
423 if (processAdditionalSpecialSegments) {
424 auto const path = uriReference->getPath();
425 auto [segments, proc] = processSegments(path, {},
true);
427 OUStringBuffer
abs(uriReference->getScheme() +
":");
428 if (uriReference->hasAuthority()) {
429 abs.append(
"//" + uriReference->getAuthority());
431 for (
auto const & i : segments)
433 if (
i.excessParent) {
434 switch (excessParentSegments) {
435 case css::uri::RelativeUriExcessParentSegments_ERROR:
438 case css::uri::RelativeUriExcessParentSegments_RETAIN:
439 assert(
i.segment == u
"..");
442 case css::uri::RelativeUriExcessParentSegments_REMOVE:
450 if (
i.leadingSlash) {
453 abs.append(
i.segment);
455 if (uriReference->hasQuery()) {
456 abs.append(
"?" + uriReference->getQuery());
458 if (uriReference->hasFragment()) {
459 abs.append(
"#" + uriReference->getFragment());
461 return parse(
abs.makeStringAndClear());
464 return clone(uriReference);
465 }
else if (!uriReference->hasAuthority()
466 && uriReference->getPath().isEmpty()) {
467 OUStringBuffer
abs(baseUriReference->getScheme() +
":");
468 if (baseUriReference->hasAuthority()) {
469 abs.append(
"//" + baseUriReference->getAuthority());
471 abs.append(baseUriReference->getPath());
472 if (uriReference->hasQuery()) {
473 abs.append(
"?" + uriReference->getQuery());
474 }
else if (baseUriReference->hasQuery()) {
475 abs.append(
"?" + baseUriReference->getQuery());
477 if (uriReference->hasFragment()) {
478 abs.append(
"#" + uriReference->getFragment());
480 return parse(
abs.makeStringAndClear());
482 OUStringBuffer
abs(128);
483 abs.append(baseUriReference->getScheme() +
":");
484 if (uriReference->hasAuthority()) {
485 abs.append(
"//" + uriReference->getAuthority());
486 }
else if (baseUriReference->hasAuthority()) {
487 abs.append(
"//" + baseUriReference->getAuthority());
489 if (uriReference->hasRelativePath()) {
490 auto path1 = baseUriReference->getPath();
491 if (path1.isEmpty()) {
492 if (baseUriReference->hasAuthority()) {
496 path1 = path1.copy(0, path1.lastIndexOf(
'/') + 1);
498 auto const path2 = uriReference->getPath();
499 auto [segments, _] = processSegments(path1, path2, processAdditionalSpecialSegments);
501 for (
auto const & i : segments)
503 if (
i.excessParent) {
504 switch (excessParentSegments) {
505 case css::uri::RelativeUriExcessParentSegments_ERROR:
508 case css::uri::RelativeUriExcessParentSegments_RETAIN:
509 assert(
i.segment == u
"..");
512 case css::uri::RelativeUriExcessParentSegments_REMOVE:
520 if (
i.leadingSlash) {
523 abs.append(
i.segment);
526 bool processed =
false;
527 if (processAdditionalSpecialSegments) {
528 auto const path = uriReference->getPath();
529 auto [segments, proc] = processSegments(path, {},
true);
531 for (
auto const & i : segments)
533 if (
i.excessParent) {
534 switch (excessParentSegments) {
535 case css::uri::RelativeUriExcessParentSegments_ERROR:
538 case css::uri::RelativeUriExcessParentSegments_RETAIN:
539 assert(
i.segment == u
"..");
542 case css::uri::RelativeUriExcessParentSegments_REMOVE:
550 if (
i.leadingSlash) {
553 abs.append(
i.segment);
559 abs.append(uriReference->getPath());
562 if (uriReference->hasQuery()) {
563 abs.append(
"?" + uriReference->getQuery());
565 if (uriReference->hasFragment()) {
566 abs.append(
"#" + uriReference->getFragment());
568 return parse(
abs.makeStringAndClear());
572css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
573 css::uno::Reference< css::uri::XUriReference >
const & baseUriReference,
574 css::uno::Reference< css::uri::XUriReference >
const & uriReference,
575 sal_Bool preferAuthorityOverRelativePath,
576 sal_Bool preferAbsoluteOverRelativePath,
577 sal_Bool encodeRetainedSpecialSegments)
579 if (!baseUriReference.is() || !baseUriReference->isAbsolute()
580 || !uriReference.is()) {
582 }
else if (!uriReference->isAbsolute() || uriReference->hasRelativePath()
583 || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
584 uriReference->getScheme())) {
585 return clone(uriReference);
587 OUStringBuffer rel(128);
588 bool omitQuery =
false;
589 if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
590 || !equalIgnoreEscapeCase(
591 baseUriReference->getAuthority(),
592 uriReference->getAuthority()))
594 if (uriReference->hasAuthority()) {
595 rel.append(
"//" + uriReference->getAuthority());
597 rel.append(uriReference->getPath());
598 }
else if ((equalIgnoreEscapeCase(
599 baseUriReference->getPath(), uriReference->getPath())
600 || (baseUriReference->getPath() ==
"/"
601 && uriReference->getPath().isEmpty()))
602 && baseUriReference->hasQuery() == uriReference->hasQuery()
603 && equalIgnoreEscapeCase(
604 baseUriReference->getQuery(), uriReference->getQuery()))
608 sal_Int32 count1 = std::max< sal_Int32 >(
609 baseUriReference->getPathSegmentCount(), 1);
610 sal_Int32 count2 = std::max< sal_Int32 >(
611 uriReference->getPathSegmentCount(), 1);
613 for (;
i < std::min(count1, count2) - 1; ++
i) {
614 if (!equalIgnoreEscapeCase(
615 baseUriReference->getPathSegment(i),
616 uriReference->getPathSegment(i)))
622 && (preferAbsoluteOverRelativePath || uriReference->hasQuery())
623 && (preferAuthorityOverRelativePath
624 || !uriReference->getPath().startsWith(
"//")))
626 if (uriReference->getPath().isEmpty()) {
627 if (!baseUriReference->getPath().isEmpty()
628 && baseUriReference->getPath() !=
"/")
632 }
else if (uriReference->getPath() ==
"/") {
633 if (baseUriReference->getPath().isEmpty()
634 || baseUriReference->getPath() !=
"/")
639 if (uriReference->getPath().startsWith(
"//")) {
640 assert(uriReference->hasAuthority());
641 rel.append(
"//" + uriReference->getAuthority());
643 rel.append(uriReference->getPath());
646 bool segments =
false;
647 for (sal_Int32 j = i; j < count1 - 1; ++j) {
655 || (!uriReference->getPathSegment(count2 - 1).isEmpty()))
658 && (uriReference->getPathSegment(i).isEmpty()
659 || (parseScheme(uriReference->getPathSegment(i))
665 for (;
i < count2; ++
i) {
669 OUString s(uriReference->getPathSegment(i));
670 if (encodeRetainedSpecialSegments && s ==
".") {
672 }
else if (encodeRetainedSpecialSegments && s ==
"..") {
673 rel.append(
"%2E%2E");
682 if (!omitQuery && uriReference->hasQuery()) {
683 rel.append(
"?" + uriReference->getQuery());
685 if (uriReference->hasFragment()) {
686 rel.append(
"#" + uriReference->getFragment());
688 return parse(rel.makeStringAndClear());
694extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
696 css::uno::Sequence<css::uno::Any>
const &)
698 return ::cppu::acquire(
new Factory(rxContext));
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_uri_UriReferenceFactory_get_implementation(css::uno::XComponentContext *rxContext, css::uno::Sequence< css::uno::Any > const &)
T * clone(T *const other)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
Any SAL_CALL getCaughtException()
constexpr OUStringLiteral first
store_handle_type *SAL_CALL query(OStoreObject *pHandle, store_handle_type *)
bool parse(OUString const &uri, SourceProviderScannerData *data)
SwNodeOffset abs(const SwNodeOffset &a)