1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <string_view>
23 #include <sal/config.h>
25 #include <unicode/idna.h>
27 #include <svl/urihelper.hxx>
28 #include <com/sun/star/ucb/Command.hpp>
29 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
30 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
31 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
32 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
33 #include <com/sun/star/ucb/XCommandProcessor.hpp>
34 #include <com/sun/star/ucb/XContent.hpp>
35 #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
36 #include <com/sun/star/uno/Any.hxx>
37 #include <com/sun/star/uno/Exception.hpp>
38 #include <com/sun/star/uno/Reference.hxx>
39 #include <com/sun/star/uno/RuntimeException.hpp>
40 #include <com/sun/star/uno/XComponentContext.hpp>
41 #include <com/sun/star/uri/UriReferenceFactory.hpp>
42 #include <com/sun/star/uri/XUriReference.hpp>
43 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
44 #include <comphelper/processfactory.hxx>
45 #include <osl/diagnose.h>
46 #include <rtl/character.hxx>
47 #include <rtl/instance.hxx>
48 #include <rtl/ustrbuf.hxx>
49 #include <rtl/ustring.hxx>
50 #include <sal/types.h>
51 #include <sal/log.hxx>
52 #include <tools/inetmime.hxx>
53 #include <unotools/charclass.hxx>
55 using namespace com::sun::star
;
57 OUString
URIHelper::SmartRel2Abs(INetURLObject
const & rTheBaseURIRef
,
58 OUString
const & rTheRelURIRef
,
59 Link
<OUString
*, bool> const & rMaybeFileHdl
,
60 bool bCheckFileExists
,
62 INetURLObject::EncodeMechanism eEncodeMechanism
,
63 INetURLObject::DecodeMechanism eDecodeMechanism
,
64 rtl_TextEncoding eCharset
,
67 // Backwards compatibility:
68 if( rTheRelURIRef
.startsWith("#") )
71 INetURLObject aAbsURIRef
;
72 if (rTheBaseURIRef
.HasError())
73 aAbsURIRef
. SetSmartURL(rTheRelURIRef
, eEncodeMechanism
, eCharset
, eStyle
);
77 aAbsURIRef
= rTheBaseURIRef
.smartRel2Abs(rTheRelURIRef
,
82 false/*bRelativeNonURIs*/,
86 && (aAbsURIRef
.GetProtocol() == INetProtocol::File
))
88 INetURLObject aNonFileURIRef
;
89 aNonFileURIRef
.SetSmartURL(rTheRelURIRef
,
93 if (!aNonFileURIRef
.HasError()
94 && aNonFileURIRef
.GetProtocol() != INetProtocol::File
)
96 bool bMaybeFile
= false;
97 if (rMaybeFileHdl
.IsSet())
99 OUString
aFilePath(rTheRelURIRef
);
100 bMaybeFile
= rMaybeFileHdl
.Call(&aFilePath
);
103 aAbsURIRef
= aNonFileURIRef
;
107 return aAbsURIRef
.GetMainURL(eDecodeMechanism
, eCharset
);
110 namespace { struct MaybeFileHdl
: public rtl::Static
< Link
<OUString
*, bool>, MaybeFileHdl
> {}; }
112 void URIHelper::SetMaybeFileHdl(Link
<OUString
*, bool> const & rTheMaybeFileHdl
)
114 MaybeFileHdl::get() = rTheMaybeFileHdl
;
117 Link
<OUString
*, bool> const & URIHelper::GetMaybeFileHdl()
119 return MaybeFileHdl::get();
124 bool isAbsoluteHierarchicalUriReference(
125 css::uno::Reference
< css::uri::XUriReference
> const & uriReference
)
127 return uriReference
.is() && uriReference
->isAbsolute()
128 && !uriReference
->hasRelativePath();
131 // To improve performance, assume that if for any prefix URL of a given
132 // hierarchical URL either a UCB content cannot be created, or the UCB content
133 // does not support the getCasePreservingURL command, then this will hold for
134 // any other prefix URL of the given URL, too:
135 enum Result
{ Success
, GeneralFailure
, SpecificFailure
};
137 Result
normalizePrefix( css::uno::Reference
< css::ucb::XUniversalContentBroker
> const & broker
,
138 OUString
const & uri
, OUString
* normalized
)
140 OSL_ASSERT(broker
.is() && normalized
!= nullptr);
141 css::uno::Reference
< css::ucb::XContent
> content
;
143 content
= broker
->queryContent(broker
->createContentIdentifier(uri
));
144 } catch (css::ucb::IllegalIdentifierException
&) {}
146 return GeneralFailure
;
150 (css::uno::Reference
< css::ucb::XCommandProcessor
>(
151 content
, css::uno::UNO_QUERY_THROW
)->execute(
152 css::ucb::Command("getCasePreservingURL",
153 -1, css::uno::Any()),
155 css::uno::Reference
< css::ucb::XCommandEnvironment
>())
158 } catch (css::uno::RuntimeException
&) {
160 } catch (css::ucb::UnsupportedCommandException
&) {
161 return GeneralFailure
;
162 } catch (css::uno::Exception
&) {
163 return SpecificFailure
;
169 css::uno::Reference
< css::ucb::XUniversalContentBroker
> const & broker
,
170 css::uno::Reference
< css::uri::XUriReferenceFactory
> const & uriFactory
,
171 OUString
const & uriReference
)
173 // normalizePrefix can potentially fail (a typically example being a file
174 // URL that denotes a non-existing resource); in such a case, try to
175 // normalize as long a prefix of the given URL as possible (i.e., normalize
176 // all the existing directories within the path):
178 sal_Int32 n
= uriReference
.indexOf('#');
179 normalized
= n
== -1 ? uriReference
: uriReference
.copy(0, n
);
180 switch (normalizePrefix(broker
, normalized
, &normalized
)) {
182 return n
== -1 ? normalized
: normalized
+ uriReference
.subView(n
);
185 case SpecificFailure
:
189 css::uno::Reference
< css::uri::XUriReference
> ref(
190 uriFactory
->parse(uriReference
));
191 if (!isAbsoluteHierarchicalUriReference(ref
)) {
194 sal_Int32 count
= ref
->getPathSegmentCount();
198 OUStringBuffer
head(ref
->getScheme());
200 if (ref
->hasAuthority()) {
202 head
.append(ref
->getAuthority());
204 for (sal_Int32 i
= count
- 1; i
> 0; --i
) {
205 OUStringBuffer
buf(head
);
206 for (sal_Int32 j
= 0; j
< i
; ++j
) {
208 buf
.append(ref
->getPathSegment(j
));
210 normalized
= buf
.makeStringAndClear();
211 if (normalizePrefix(broker
, normalized
, &normalized
) != SpecificFailure
)
213 buf
.append(normalized
);
214 css::uno::Reference
< css::uri::XUriReference
> preRef(
215 uriFactory
->parse(normalized
));
216 if (!isAbsoluteHierarchicalUriReference(preRef
)) {
217 // This could only happen if something is inconsistent:
220 sal_Int32 preCount
= preRef
->getPathSegmentCount();
221 // normalizePrefix may have added or removed a final slash:
223 if (preCount
== i
- 1) {
225 } else if (preCount
- 1 == i
&& !buf
.isEmpty()
226 && buf
[buf
.getLength() - 1] == '/')
228 buf
.setLength(buf
.getLength() - 1);
230 // This could only happen if something is inconsistent:
234 for (sal_Int32 j
= i
; j
< count
; ++j
) {
236 buf
.append(ref
->getPathSegment(j
));
238 if (ref
->hasQuery()) {
240 buf
.append(ref
->getQuery());
242 if (ref
->hasFragment()) {
244 buf
.append(ref
->getFragment());
246 return buf
.makeStringAndClear();
254 css::uno::Reference
< css::uri::XUriReference
>
255 URIHelper::normalizedMakeRelative(
256 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
257 OUString
const & baseUriReference
, OUString
const & uriReference
)
259 OSL_ASSERT(context
.is());
260 css::uno::Reference
< css::ucb::XUniversalContentBroker
> broker(
261 css::ucb::UniversalContentBroker::create(context
));
262 css::uno::Reference
< css::uri::XUriReferenceFactory
> uriFactory(
263 css::uri::UriReferenceFactory::create(context
));
264 return uriFactory
->makeRelative(
265 uriFactory
->parse(normalize(broker
, uriFactory
, baseUriReference
)),
266 uriFactory
->parse(normalize(broker
, uriFactory
, uriReference
)), true,
270 OUString
URIHelper::simpleNormalizedMakeRelative(
271 OUString
const & baseUriReference
, OUString
const & uriReference
)
273 css::uno::Reference
< css::uri::XUriReference
> rel(
274 URIHelper::normalizedMakeRelative(
275 comphelper::getProcessComponentContext(), baseUriReference
,
277 return rel
.is() ? rel
->getUriReference() : uriReference
;
281 // FindFirstURLInText
286 sal_Int32
nextChar(OUString
const & rStr
, sal_Int32 nPos
)
288 return rtl::isHighSurrogate(rStr
[nPos
])
289 && rStr
.getLength() - nPos
>= 2
290 && rtl::isLowSurrogate(rStr
[nPos
+ 1]) ?
294 bool isBoundary1(CharClass
const & rCharClass
, OUString
const & rStr
,
295 sal_Int32 nPos
, sal_Int32 nEnd
)
299 if (rCharClass
.isLetterNumeric(rStr
, nPos
))
316 bool isBoundary2(CharClass
const & rCharClass
, OUString
const & rStr
,
317 sal_Int32 nPos
, sal_Int32 nEnd
)
321 if (rCharClass
.isLetterNumeric(rStr
, nPos
))
351 bool checkWChar(CharClass
const & rCharClass
, OUString
const & rStr
,
352 sal_Int32
* pPos
, sal_Int32
* pEnd
, bool bBackslash
= false,
355 sal_Unicode c
= rStr
[*pPos
];
358 static sal_uInt8
const aMap
[128]
359 = { 0, 0, 0, 0, 0, 0, 0, 0,
360 0, 0, 0, 0, 0, 0, 0, 0,
361 0, 0, 0, 0, 0, 0, 0, 0,
362 0, 0, 0, 0, 0, 0, 0, 0,
363 0, 1, 0, 0, 4, 4, 4, 1, // !"#$%&'
364 1, 1, 1, 1, 1, 4, 1, 4, // ()*+,-./
365 4, 4, 4, 4, 4, 4, 4, 4, // 01234567
366 4, 4, 1, 1, 0, 1, 0, 1, // 89:;<=>?
367 4, 4, 4, 4, 4, 4, 4, 4, // @ABCDEFG
368 4, 4, 4, 4, 4, 4, 4, 4, // HIJKLMNO
369 4, 4, 4, 4, 4, 4, 4, 4, // PQRSTUVW
370 4, 4, 4, 1, 2, 1, 0, 1, // XYZ[\]^_
371 0, 4, 4, 4, 4, 4, 4, 4, // `abcdefg
372 4, 4, 4, 4, 4, 4, 4, 4, // hijklmno
373 4, 4, 4, 4, 4, 4, 4, 4, // pqrstuvw
374 4, 4, 4, 0, 3, 0, 1, 0 }; // xyz{|}~
402 case 4: // alpha, digit, "$", "%", "&", "-", "/", "@" (see
408 else if (rCharClass
.isLetterNumeric(rStr
, *pPos
))
410 *pEnd
= *pPos
= nextChar(rStr
, *pPos
);
417 sal_uInt32
scanDomain(OUString
const & rStr
, sal_Int32
* pPos
,
420 sal_Unicode
const * pBuffer
= rStr
.getStr();
421 sal_Unicode
const * p
= pBuffer
+ *pPos
;
422 sal_uInt32 nLabels
= INetURLObject::scanDomain(p
, pBuffer
+ nEnd
, false);
423 *pPos
= sal::static_int_cast
< sal_Int32
>(p
- pBuffer
);
429 OUString
URIHelper::FindFirstURLInText(OUString
const & rText
,
432 CharClass
const & rCharClass
,
433 INetURLObject::EncodeMechanism eMechanism
,
434 rtl_TextEncoding eCharset
)
436 if (rBegin
> rEnd
|| rEnd
> rText
.getLength())
439 // Search for the first substring of [rBegin..rEnd[ that matches any of the
440 // following productions (for which the appropriate style bit is set in
441 // eStyle, if applicable).
443 // 1st Production (known scheme):
444 // \B1 <one of the known schemes, except file> ":" 1*wchar ["#" 1*wchar]
447 // 2nd Production (file):
448 // \B1 "FILE:" 1*(wchar / "\" / "|") ["#" 1*wchar] \B1
450 // 3rd Production (ftp):
451 // \B1 "FTP" 2*("." label) ["/" *wchar] ["#" 1*wchar] \B1
453 // 4th Production (http):
454 // \B1 "WWW" 2*("." label) ["/" *wchar] ["#" 1*wchar] \B1
456 // 5th Production (mailto):
457 // \B2 local-part "@" domain \B1
459 // 6th Production (UNC file):
460 // \B1 "\\" domain "\" *(wchar / "\") \B1
462 // 7th Production (DOS file):
463 // \B1 ALPHA ":\" *(wchar / "\") \B1
465 // 8th Production (Unix-like DOS file):
466 // \B1 ALPHA ":/" *(wchar / "\") \B1
468 // The productions use the following auxiliary rules.
470 // local-part = atom *("." atom)
471 // atom = 1*(alphanum / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+"
472 // / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}"
474 // domain = label *("." label)
475 // label = alphanum [*(alphanum / "-") alphanum]
476 // alphanum = ALPHA / DIGIT
477 // wchar = <any uric character (ignoring the escaped rule), or "%", or
478 // a letter or digit (according to rCharClass)>
480 // "\B1" (boundary 1) stands for the beginning or end of the block of text,
481 // or a character that is neither (a) a letter or digit (according to
482 // rCharClass), nor (b) any of "$", "%", "&", "-", "/", "@", or "\".
483 // (FIXME: What was the rationale for this set of punctuation characters?)
485 // "\B2" (boundary 2) stands for the beginning or end of the block of text,
486 // or a character that is neither (a) a letter or digit (according to
487 // rCharClass), nor (b) any of "!", "#", "$", "%", "&", "'", "*", "+", "-",
488 // "/", "=", "?", "@", "^", "_", "`", "{", "|", "}", or "~" (i.e., an RFC
489 // 822 <atom> character, or "@" from \B1's set above).
491 // Productions 1--4, and 6--8 try to find a maximum-length match, but they
492 // stop at the first <wchar> character that is a "\B1" character which is
493 // only followed by "\B1" characters (taking "\" and "|" characters into
494 // account appropriately). Production 5 simply tries to find a maximum-
497 // Productions 1--4 use the given eMechanism and eCharset. Productions 5--9
498 // use EncodeMechanism::All.
500 // Productions 6--9 are only applicable if the FSysStyle::Dos bit is set in
503 bool bBoundary1
= true;
504 bool bBoundary2
= true;
505 for (sal_Int32 nPos
= rBegin
; nPos
!= rEnd
; nPos
= nextChar(rText
, nPos
))
507 sal_Unicode c
= rText
[nPos
];
510 if (rtl::isAsciiAlpha(c
))
513 INetProtocol eScheme
= INetURLObject::CompareProtocolScheme(rText
.copy(i
, rEnd
- i
));
514 if (eScheme
== INetProtocol::File
) // 2nd
516 while (rText
[i
++] != ':') ;
517 sal_Int32 nPrefixEnd
= i
;
518 sal_Int32 nUriEnd
= i
;
520 && checkWChar(rCharClass
, rText
, &i
, &nUriEnd
, true,
522 if (i
!= nPrefixEnd
&& i
!= rEnd
&& rText
[i
] == '#')
526 && checkWChar(rCharClass
, rText
, &i
, &nUriEnd
)) ;
528 if (nUriEnd
!= nPrefixEnd
529 && isBoundary1(rCharClass
, rText
, nUriEnd
, rEnd
))
531 INetURLObject
aUri(rText
.copy(nPos
, nUriEnd
- nPos
),
532 INetProtocol::File
, eMechanism
, eCharset
,
534 if (!aUri
.HasError())
539 aUri
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
543 else if (eScheme
!= INetProtocol::NotValid
) // 1st
545 while (rText
[i
++] != ':') ;
546 sal_Int32 nPrefixEnd
= i
;
547 sal_Int32 nUriEnd
= i
;
549 && checkWChar(rCharClass
, rText
, &i
, &nUriEnd
)) ;
550 if (i
!= nPrefixEnd
&& i
!= rEnd
&& rText
[i
] == '#')
554 && checkWChar(rCharClass
, rText
, &i
, &nUriEnd
)) ;
556 if (nUriEnd
!= nPrefixEnd
557 && (isBoundary1(rCharClass
, rText
, nUriEnd
, rEnd
)
558 || rText
[nUriEnd
] == '\\'))
560 INetURLObject
aUri(rText
.copy(nPos
, nUriEnd
- nPos
),
561 INetProtocol::Http
, eMechanism
,
563 if (!aUri
.HasError())
568 aUri
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
575 sal_uInt32 nLabels
= scanDomain(rText
, &i
, rEnd
);
577 && rText
[nPos
+ 3] == '.'
578 && (((rText
[nPos
] == 'w'
579 || rText
[nPos
] == 'W')
580 && (rText
[nPos
+ 1] == 'w'
581 || rText
[nPos
+ 1] == 'W')
582 && (rText
[nPos
+ 2] == 'w'
583 || rText
[nPos
+ 2] == 'W'))
584 || ((rText
[nPos
] == 'f'
585 || rText
[nPos
] == 'F')
586 && (rText
[nPos
+ 1] == 't'
587 || rText
[nPos
+ 1] == 'T')
588 && (rText
[nPos
+ 2] == 'p'
589 || rText
[nPos
+ 2] == 'P'))))
590 // (note that rText.GetChar(nPos + 3) is guaranteed to be
593 sal_Int32 nUriEnd
= i
;
594 if (i
!= rEnd
&& rText
[i
] == '/')
598 && checkWChar(rCharClass
, rText
, &i
, &nUriEnd
)) ;
600 if (i
!= rEnd
&& rText
[i
] == '#')
604 && checkWChar(rCharClass
, rText
, &i
, &nUriEnd
)) ;
606 if (isBoundary1(rCharClass
, rText
, nUriEnd
, rEnd
)
607 || rText
[nUriEnd
] == '\\')
609 INetURLObject
aUri(rText
.copy(nPos
, nUriEnd
- nPos
),
610 INetProtocol::Http
, eMechanism
,
612 if (!aUri
.HasError())
617 aUri
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
623 && rText
[nPos
+ 1] == ':'
624 && (rText
[nPos
+ 2] == '/'
625 || rText
[nPos
+ 2] == '\\')) // 7th, 8th
628 sal_Int32 nUriEnd
= i
;
630 && checkWChar(rCharClass
, rText
, &i
, &nUriEnd
)) ;
631 if (isBoundary1(rCharClass
, rText
, nUriEnd
, rEnd
))
633 INetURLObject
aUri(rText
.copy(nPos
, nUriEnd
- nPos
),
635 INetURLObject::EncodeMechanism::All
,
636 RTL_TEXTENCODING_UTF8
,
638 if (!aUri
.HasError())
643 aUri
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
648 else if (rEnd
- nPos
>= 2
649 && rText
[nPos
] == '\\'
650 && rText
[nPos
+ 1] == '\\') // 6th
652 sal_Int32 i
= nPos
+ 2;
653 sal_uInt32 nLabels
= scanDomain(rText
, &i
, rEnd
);
654 if (nLabels
>= 1 && i
!= rEnd
&& rText
[i
] == '\\')
656 sal_Int32 nUriEnd
= ++i
;
658 && checkWChar(rCharClass
, rText
, &i
, &nUriEnd
,
660 if (isBoundary1(rCharClass
, rText
, nUriEnd
, rEnd
))
662 INetURLObject
aUri(rText
.copy(nPos
, nUriEnd
- nPos
),
664 INetURLObject::EncodeMechanism::All
,
665 RTL_TEXTENCODING_UTF8
,
667 if (!aUri
.HasError())
672 aUri
.GetMainURL(INetURLObject::DecodeMechanism::ToIUri
);
678 if (bBoundary2
&& INetMIME::isAtomChar(c
)) // 5th
681 for (sal_Int32 i
= nPos
+ 1; i
!= rEnd
; ++i
)
683 sal_Unicode c2
= rText
[i
];
684 if (INetMIME::isAtomChar(c2
))
695 sal_uInt32 nLabels
= scanDomain(rText
, &i
, rEnd
);
697 && isBoundary1(rCharClass
, rText
, i
, rEnd
))
699 INetURLObject
aUri(rText
.copy(nPos
, i
- nPos
),
700 INetProtocol::Mailto
,
701 INetURLObject::EncodeMechanism::All
);
702 if (!aUri
.HasError())
706 return aUri
.GetMainURL(
707 INetURLObject::DecodeMechanism::ToIUri
);
715 bBoundary1
= isBoundary1(rCharClass
, rText
, nPos
, rEnd
);
716 bBoundary2
= isBoundary2(rCharClass
, rText
, nPos
, rEnd
);
722 OUString
URIHelper::removePassword(OUString
const & rURI
,
723 INetURLObject::EncodeMechanism eEncodeMechanism
,
724 INetURLObject::DecodeMechanism eDecodeMechanism
,
725 rtl_TextEncoding eCharset
)
727 INetURLObject
aObj(rURI
, eEncodeMechanism
, eCharset
);
728 return aObj
.HasError() ?
730 aObj
.GetURLNoPass(eDecodeMechanism
, eCharset
);
733 OUString
URIHelper::resolveIdnaHost(OUString
const & url
) {
734 css::uno::Reference
<css::uri::XUriReference
> uri(
735 css::uri::UriReferenceFactory::create(
736 comphelper::getProcessComponentContext())
738 if (!(uri
.is() && uri
->hasAuthority())) {
741 auto auth(uri
->getAuthority());
744 sal_Int32 hostStart
= auth
.indexOf('@') + 1;
745 sal_Int32 hostEnd
= auth
.getLength();
746 while (hostEnd
> hostStart
&& rtl::isAsciiDigit(auth
[hostEnd
- 1])) {
749 if (hostEnd
> hostStart
&& auth
[hostEnd
- 1] == ':') {
752 hostEnd
= auth
.getLength();
754 auto asciiOnly
= true;
755 for (auto i
= hostStart
; i
!= hostEnd
; ++i
) {
756 if (!rtl::isAscii(auth
[i
])) {
762 // Avoid icu::IDNA case normalization in purely non-IDNA domain names:
765 UErrorCode e
= U_ZERO_ERROR
;
766 std::unique_ptr
<icu::IDNA
> idna(
767 icu::IDNA::createUTS46Instance(
768 (UIDNA_USE_STD3_RULES
| UIDNA_CHECK_BIDI
| UIDNA_CHECK_CONTEXTJ
769 #if U_ICU_VERSION_MAJOR_NUM >= 49
770 | UIDNA_CHECK_CONTEXTO
775 SAL_WARN("vcl.gdi", "icu::IDNA::createUTS46Instance " << e
);
778 icu::UnicodeString ascii
;
782 reinterpret_cast<UChar
const *>(auth
.getStr() + hostStart
),
783 hostEnd
- hostStart
),
785 if (U_FAILURE(e
) || info
.hasErrors()) {
788 OUStringBuffer
buf(uri
->getScheme());
789 buf
.append("://").append(std::u16string_view(auth
).substr(0, hostStart
));
791 reinterpret_cast<sal_Unicode
const *>(ascii
.getBuffer()),
793 buf
.append(std::u16string_view(auth
).substr(hostEnd
)).append(uri
->getPath());
794 if (uri
->hasQuery()) {
795 buf
.append('?').append(uri
->getQuery());
797 if (uri
->hasFragment()) {
798 buf
.append('#').append(uri
->getFragment());
800 return buf
.makeStringAndClear();
803 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */