Bump version to 24.04.3.4
[LibreOffice.git] / sal / rtl / uri.cxx
blob06163084893f10e8231040d08ce974123c9e8d9d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <rtl/character.hxx>
21 #include <rtl/strbuf.hxx>
22 #include <rtl/textenc.h>
23 #include <rtl/textcvt.h>
24 #include <rtl/uri.h>
25 #include <rtl/uri.hxx>
26 #include <rtl/ustrbuf.h>
27 #include <rtl/ustrbuf.hxx>
28 #include <rtl/ustring.h>
29 #include <rtl/ustring.hxx>
30 #include <sal/types.h>
31 #include <sal/macros.h>
33 #include <uri_internal.hxx>
35 #include <algorithm>
36 #include <cstddef>
38 namespace {
40 sal_Unicode const cEscapePrefix = 0x25; // '%'
42 int getHexWeight(sal_uInt32 nUtf32)
44 return nUtf32 >= 0x30 && nUtf32 <= 0x39 ? // '0'--'9'
45 static_cast< int >(nUtf32 - 0x30) :
46 nUtf32 >= 0x41 && nUtf32 <= 0x46 ? // 'A'--'F'
47 static_cast< int >(nUtf32 - 0x41 + 10) :
48 nUtf32 >= 0x61 && nUtf32 <= 0x66 ? // 'a'--'f'
49 static_cast< int >(nUtf32 - 0x61 + 10) :
50 -1; // not a hex digit
53 bool isValid(sal_Bool const * pCharClass, sal_uInt32 nUtf32)
55 return nUtf32 < rtl::UriCharClassSize && pCharClass[nUtf32];
58 void writeUnicode(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
59 sal_Unicode cChar)
61 rtl_uStringbuffer_insert(pBuffer, pCapacity, (*pBuffer)->length, &cChar, 1);
66 namespace rtl::uri::detail {
68 /** Read any of the following:
70 @li sequence of escape sequences representing character from eCharset,
71 translated to single UCS4 character; or
72 @li pair of UTF-16 surrogates, translated to single UCS4 character; or
73 @li single UTF-16 character, extended to UCS4 character.
75 sal_uInt32 readUcs4(sal_Unicode const ** pBegin, sal_Unicode const * pEnd,
76 bool bEncoded, rtl_TextEncoding eCharset,
77 EscapeType * pType)
79 sal_uInt32 nChar = *(*pBegin)++;
80 int nWeight1;
81 int nWeight2;
82 if (nChar == cEscapePrefix && bEncoded && pEnd - *pBegin >= 2
83 && (nWeight1 = getHexWeight((*pBegin)[0])) >= 0
84 && (nWeight2 = getHexWeight((*pBegin)[1])) >= 0)
86 *pBegin += 2;
87 nChar = static_cast< sal_uInt32 >(nWeight1 << 4 | nWeight2);
88 if (nChar <= 0x7F)
90 *pType = EscapeChar;
92 else if (eCharset == RTL_TEXTENCODING_UTF8)
94 if (nChar >= 0xC0 && nChar <= 0xF4)
96 sal_uInt32 nEncoded;
97 int nShift;
98 sal_uInt32 nMin;
99 if (nChar <= 0xDF)
101 nEncoded = (nChar & 0x1F) << 6;
102 nShift = 0;
103 nMin = 0x80;
105 else if (nChar <= 0xEF)
107 nEncoded = (nChar & 0x0F) << 12;
108 nShift = 6;
109 nMin = 0x800;
111 else
113 nEncoded = (nChar & 0x07) << 18;
114 nShift = 12;
115 nMin = 0x10000;
118 sal_Unicode const * p = *pBegin;
119 bool bUTF8 = true;
121 for (; nShift >= 0; nShift -= 6)
123 if (pEnd - p < 3 || p[0] != cEscapePrefix
124 || (nWeight1 = getHexWeight(p[1])) < 8
125 || nWeight1 > 11
126 || (nWeight2 = getHexWeight(p[2])) < 0)
128 bUTF8 = false;
129 break;
131 p += 3;
132 nEncoded |= ((nWeight1 & 3) << 4 | nWeight2) << nShift;
134 if (bUTF8 && rtl::isUnicodeScalarValue(nEncoded)
135 && nEncoded >= nMin)
137 *pBegin = p;
138 *pType = EscapeChar;
139 return nEncoded;
142 *pType = EscapeOctet;
144 else
146 OStringBuffer aBuf(16);
147 aBuf.append(static_cast< char >(nChar));
148 rtl_TextToUnicodeConverter aConverter
149 = rtl_createTextToUnicodeConverter(eCharset);
150 sal_Unicode const * p = *pBegin;
152 for (;;)
154 sal_Unicode aDst[2];
155 sal_uInt32 nInfo;
156 sal_Size nConverted;
157 sal_Size nDstSize = rtl_convertTextToUnicode(
158 aConverter, nullptr, aBuf.getStr(), aBuf.getLength(), aDst,
159 SAL_N_ELEMENTS( aDst ),
160 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
161 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
162 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR),
163 &nInfo, &nConverted);
165 if (nInfo == 0)
167 assert( nConverted
168 == sal::static_int_cast< sal_uInt32 >(
169 aBuf.getLength()));
171 rtl_destroyTextToUnicodeConverter(aConverter);
172 *pBegin = p;
173 *pType = EscapeChar;
175 assert( nDstSize == 1
176 || (nDstSize == 2 && rtl::isHighSurrogate(aDst[0])
177 && rtl::isLowSurrogate(aDst[1])));
179 return nDstSize == 1
180 ? aDst[0] : rtl::combineSurrogates(aDst[0], aDst[1]);
182 if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL
183 && pEnd - p >= 3 && p[0] == cEscapePrefix
184 && (nWeight1 = getHexWeight(p[1])) >= 0
185 && (nWeight2 = getHexWeight(p[2])) >= 0)
187 p += 3;
188 aBuf.append(static_cast< char >(nWeight1 << 4 | nWeight2));
190 else if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL
191 && p != pEnd && *p <= 0x7F)
193 aBuf.append(static_cast< char >(*p++));
195 else
197 assert(
198 (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL)
199 == 0);
200 break;
203 rtl_destroyTextToUnicodeConverter(aConverter);
204 *pType = EscapeOctet;
206 return nChar;
209 *pType = EscapeNo;
210 return rtl::isHighSurrogate(nChar) && *pBegin < pEnd
211 && rtl::isLowSurrogate(**pBegin) ?
212 rtl::combineSurrogates(nChar, *(*pBegin)++) : nChar;
217 namespace {
219 void writeUcs4(rtl_uString ** pBuffer, sal_Int32 * pCapacity, sal_uInt32 nUtf32)
221 rtl_uStringbuffer_insertUtf32(pBuffer, pCapacity, (*pBuffer)->length, nUtf32);
224 void writeEscapeOctet(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
225 sal_uInt32 nOctet)
227 assert(nOctet <= 0xFF); // bad octet
229 static sal_Unicode const aHex[16]
230 = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
231 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }; /* '0'--'9', 'A'--'F' */
233 writeUnicode(pBuffer, pCapacity, cEscapePrefix);
234 writeUnicode(pBuffer, pCapacity, aHex[nOctet >> 4]);
235 writeUnicode(pBuffer, pCapacity, aHex[nOctet & 15]);
238 bool writeEscapeChar(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
239 sal_uInt32 nUtf32, rtl_TextEncoding eCharset, bool bStrict)
241 assert(rtl::isUnicodeCodePoint(nUtf32));
242 if (eCharset == RTL_TEXTENCODING_UTF8)
244 if (nUtf32 < 0x80)
246 writeEscapeOctet(pBuffer, pCapacity, nUtf32);
248 else if (nUtf32 < 0x800)
250 writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 6 | 0xC0);
251 writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
253 else if (nUtf32 < 0x10000)
255 writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 12 | 0xE0);
256 writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 6 & 0x3F) | 0x80);
257 writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
259 else
261 writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 18 | 0xF0);
262 writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 12 & 0x3F) | 0x80);
263 writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 6 & 0x3F) | 0x80);
264 writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
267 else
269 rtl_UnicodeToTextConverter aConverter
270 = rtl_createUnicodeToTextConverter(eCharset);
271 sal_Unicode aSrc[2];
272 sal_Size nSrcSize = rtl::splitSurrogates(nUtf32, aSrc);
274 char aDst[32]; // FIXME random value
275 sal_uInt32 nInfo;
276 sal_Size nConverted;
277 sal_Size nDstSize = rtl_convertUnicodeToText(
278 aConverter, nullptr, aSrc, nSrcSize, aDst, sizeof aDst,
279 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
280 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
281 | RTL_UNICODETOTEXT_FLAGS_FLUSH,
282 &nInfo, &nConverted);
283 assert((nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) == 0);
284 rtl_destroyUnicodeToTextConverter(aConverter);
286 if (nInfo == 0)
288 assert(nConverted == nSrcSize); // bad rtl_convertUnicodeToText
290 for (sal_Size i = 0; i < nDstSize; ++i)
292 writeEscapeOctet(pBuffer, pCapacity,
293 static_cast< unsigned char >(aDst[i]));
294 // FIXME all octets are escaped, even if there is no need
297 else
299 if (bStrict)
300 return false;
302 writeUcs4(pBuffer, pCapacity, nUtf32);
305 return true;
308 struct Component
310 sal_Unicode const * pBegin;
311 sal_Unicode const * pEnd;
313 Component(): pBegin(nullptr), pEnd(nullptr) {}
315 bool isPresent() const { return pBegin != nullptr; }
317 sal_Int32 getLength() const;
320 sal_Int32 Component::getLength() const
322 assert(isPresent()); // taking length of non-present component
323 return static_cast< sal_Int32 >(pEnd - pBegin);
326 struct Components
328 Component aScheme;
329 Component aAuthority;
330 Component aPath;
331 Component aQuery;
332 Component aFragment;
335 void parseUriRef(rtl_uString const * pUriRef, Components * pComponents)
337 // This algorithm is liberal and accepts various forms of illegal input.
339 sal_Unicode const * pBegin = pUriRef->buffer;
340 sal_Unicode const * pEnd = pBegin + pUriRef->length;
341 sal_Unicode const * pPos = pBegin;
343 if (pPos != pEnd && rtl::isAsciiAlpha(*pPos))
345 for (sal_Unicode const * p = pPos + 1; p != pEnd; ++p)
347 if (*p == ':')
349 pComponents->aScheme.pBegin = pBegin;
350 pComponents->aScheme.pEnd = ++p;
351 pPos = p;
352 break;
355 if (!rtl::isAsciiAlphanumeric(*p) && *p != '+' && *p != '-'
356 && *p != '.')
358 break;
363 if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
365 pComponents->aAuthority.pBegin = pPos;
366 pPos += 2;
367 while (pPos != pEnd && *pPos != '/' && *pPos != '?' && *pPos != '#')
369 ++pPos;
372 pComponents->aAuthority.pEnd = pPos;
375 pComponents->aPath.pBegin = pPos;
376 while (pPos != pEnd && *pPos != '?' && * pPos != '#')
378 ++pPos;
381 pComponents->aPath.pEnd = pPos;
383 if (pPos != pEnd && *pPos == '?')
385 pComponents->aQuery.pBegin = pPos++;
386 while (pPos != pEnd && * pPos != '#')
388 ++pPos;
391 pComponents->aQuery.pEnd = pPos;
394 if (pPos != pEnd)
396 assert(*pPos == '#');
397 pComponents->aFragment.pBegin = pPos;
398 pComponents->aFragment.pEnd = pEnd;
402 void appendPath(
403 OUStringBuffer & buffer, sal_Int32 bufferStart, bool precedingSlash,
404 sal_Unicode const * pathBegin, sal_Unicode const * pathEnd)
406 while (precedingSlash || pathBegin != pathEnd)
408 sal_Unicode const * p = pathBegin;
409 while (p != pathEnd && *p != '/')
411 ++p;
414 std::size_t n = p - pathBegin;
415 if (n == 1 && pathBegin[0] == '.')
417 // input begins with "." -> remove from input (and done):
418 // i.e., !precedingSlash -> !precedingSlash
419 // input begins with "./" -> remove from input:
420 // i.e., !precedingSlash -> !precedingSlash
421 // input begins with "/." -> replace with "/" in input (and not yet
422 // done):
423 // i.e., precedingSlash -> precedingSlash
424 // input begins with "/./" -> replace with "/" in input:
425 // i.e., precedingSlash -> precedingSlash
427 else if (n == 2 && pathBegin[0] == '.' && pathBegin[1] == '.')
429 // input begins with ".." -> remove from input (and done):
430 // i.e., !precedingSlash -> !precedingSlash
431 // input begins with "../" -> remove from input
432 // i.e., !precedingSlash -> !precedingSlash
433 // input begins with "/.." -> replace with "/" in input, and shrink
434 // output (not yet done):
435 // i.e., precedingSlash -> precedingSlash
436 // input begins with "/../" -> replace with "/" in input, and shrink
437 // output:
438 // i.e., precedingSlash -> precedingSlash
439 if (precedingSlash)
441 buffer.truncate(
442 bufferStart
443 + std::max<sal_Int32>(
444 rtl_ustr_lastIndexOfChar_WithLength(
445 buffer.getStr() + bufferStart,
446 buffer.getLength() - bufferStart, '/'),
447 0));
450 else
452 if (precedingSlash)
453 buffer.append('/');
455 buffer.append(pathBegin, n);
456 precedingSlash = p != pathEnd;
458 pathBegin = p + (p == pathEnd ? 0 : 1);
464 sal_Bool const * SAL_CALL rtl_getUriCharClass(rtl_UriCharClass eCharClass)
465 SAL_THROW_EXTERN_C()
467 static constexpr std::array<sal_Bool, rtl::UriCharClassSize> aCharClass[] = {
468 rtl::createUriCharClass(u8""), // None
469 rtl::createUriCharClass(
470 u8"!$&'()*+,-./:;=?@[]_~"
471 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // Uric
472 rtl::createUriCharClass(
473 u8"!$&'()*+,-.:;=?@_~"
474 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // UricNoSlash
475 rtl::createUriCharClass(
476 u8"!$&'()*+,-.;=@_~"
477 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // RelSegment
478 rtl::createUriCharClass(
479 u8"!$&'()*+,-.:;=@_~"
480 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // RegName
481 rtl::createUriCharClass(
482 u8"!$&'()*+,-.:;=_~"
483 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // Userinfo
484 rtl::createUriCharClass(
485 u8"!$&'()*+,-.:=@_~"
486 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // Pchar
487 rtl::createUriCharClass(
488 u8"!$&'()*+-./:?@_~"
489 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")}; // UnoParamValue
491 assert(
492 (eCharClass >= 0
493 && (sal::static_int_cast< std::size_t >(eCharClass)
494 < SAL_N_ELEMENTS(aCharClass)))); // bad eCharClass
495 return aCharClass[eCharClass].data();
498 void SAL_CALL rtl_uriEncode(rtl_uString * pText, sal_Bool const * pCharClass,
499 rtl_UriEncodeMechanism eMechanism,
500 rtl_TextEncoding eCharset, rtl_uString ** pResult)
501 SAL_THROW_EXTERN_C()
503 assert(!pCharClass[0x25]); // make sure the percent sign is encoded...
505 sal_Unicode const * p = pText->buffer;
506 sal_Unicode const * pEnd = p + pText->length;
507 sal_Int32 nCapacity = 256;
508 rtl_uString_new_WithLength(pResult, nCapacity);
510 while (p < pEnd)
512 rtl::uri::detail::EscapeType eType;
513 sal_uInt32 nUtf32 = rtl::uri::detail::readUcs4(
514 &p, pEnd,
515 (eMechanism == rtl_UriEncodeKeepEscapes
516 || eMechanism == rtl_UriEncodeCheckEscapes
517 || eMechanism == rtl_UriEncodeStrictKeepEscapes),
518 eMechanism == rtl_UriEncodeStrictKeepEscapes ? RTL_TEXTENCODING_UTF8 : eCharset,
519 &eType);
521 switch (eType)
523 case rtl::uri::detail::EscapeNo:
524 if (isValid(pCharClass, nUtf32)) // implies nUtf32 <= 0x7F
526 writeUnicode(pResult, &nCapacity,
527 static_cast< sal_Unicode >(nUtf32));
529 else if (!writeEscapeChar(
530 pResult, &nCapacity, nUtf32, eCharset,
531 (eMechanism == rtl_UriEncodeStrict
532 || eMechanism == rtl_UriEncodeStrictKeepEscapes)))
534 rtl_uString_new(pResult);
535 return;
537 break;
539 case rtl::uri::detail::EscapeChar:
540 if (eMechanism == rtl_UriEncodeCheckEscapes
541 && isValid(pCharClass, nUtf32)) // implies nUtf32 <= 0x7F
543 writeUnicode(pResult, &nCapacity,
544 static_cast< sal_Unicode >(nUtf32));
546 else if (!writeEscapeChar(
547 pResult, &nCapacity, nUtf32, eCharset,
548 (eMechanism == rtl_UriEncodeStrict
549 || eMechanism == rtl_UriEncodeStrictKeepEscapes)))
551 rtl_uString_new(pResult);
552 return;
554 break;
556 case rtl::uri::detail::EscapeOctet:
557 writeEscapeOctet(pResult, &nCapacity, nUtf32);
558 break;
561 *pResult = rtl_uStringBuffer_makeStringAndClear(pResult, &nCapacity);
564 void SAL_CALL rtl_uriDecode(rtl_uString * pText,
565 rtl_UriDecodeMechanism eMechanism,
566 rtl_TextEncoding eCharset, rtl_uString ** pResult)
567 SAL_THROW_EXTERN_C()
569 switch (eMechanism)
571 case rtl_UriDecodeNone:
572 rtl_uString_assign(pResult, pText);
573 break;
575 case rtl_UriDecodeToIuri:
576 eCharset = RTL_TEXTENCODING_UTF8;
577 [[fallthrough]];
578 default: // rtl_UriDecodeWithCharset, rtl_UriDecodeStrict
580 sal_Unicode const * p = pText->buffer;
581 sal_Unicode const * pEnd = p + pText->length;
582 sal_Int32 nCapacity = pText->length;
583 rtl_uString_new_WithLength(pResult, nCapacity);
585 while (p < pEnd)
587 rtl::uri::detail::EscapeType eType;
588 sal_uInt32 nUtf32 = rtl::uri::detail::readUcs4(&p, pEnd, true, eCharset, &eType);
589 switch (eType)
591 case rtl::uri::detail::EscapeChar:
592 if (nUtf32 <= 0x7F && eMechanism == rtl_UriDecodeToIuri)
594 writeEscapeOctet(pResult, &nCapacity, nUtf32);
595 break;
597 [[fallthrough]];
599 case rtl::uri::detail::EscapeNo:
600 writeUcs4(pResult, &nCapacity, nUtf32);
601 break;
603 case rtl::uri::detail::EscapeOctet:
604 if (eMechanism == rtl_UriDecodeStrict)
606 rtl_uString_new(pResult);
607 return;
609 writeEscapeOctet(pResult, &nCapacity, nUtf32);
610 break;
614 *pResult = rtl_uStringBuffer_makeStringAndClear( pResult, &nCapacity );
616 break;
620 sal_Bool SAL_CALL rtl_uriConvertRelToAbs(rtl_uString * pBaseUriRef,
621 rtl_uString * pRelUriRef,
622 rtl_uString ** pResult,
623 rtl_uString ** pException)
624 SAL_THROW_EXTERN_C()
626 // Use the strict parser algorithm from RFC 3986, section 5.2, to turn the
627 // relative URI into an absolute one:
628 Components aRelComponents;
629 parseUriRef(pRelUriRef, &aRelComponents);
630 OUStringBuffer aBuffer(256);
632 if (aRelComponents.aScheme.isPresent())
634 aBuffer.append(aRelComponents.aScheme.pBegin,
635 aRelComponents.aScheme.getLength());
637 if (aRelComponents.aAuthority.isPresent())
639 aBuffer.append(aRelComponents.aAuthority.pBegin,
640 aRelComponents.aAuthority.getLength());
643 appendPath(
644 aBuffer, aBuffer.getLength(), false, aRelComponents.aPath.pBegin,
645 aRelComponents.aPath.pEnd);
647 if (aRelComponents.aQuery.isPresent())
649 aBuffer.append(aRelComponents.aQuery.pBegin,
650 aRelComponents.aQuery.getLength());
653 else
655 Components aBaseComponents;
656 parseUriRef(pBaseUriRef, &aBaseComponents);
657 if (!aBaseComponents.aScheme.isPresent())
659 rtl_uString_assign(
660 pException,
661 (OUString(
662 "<" + OUString::unacquired(&pBaseUriRef)
663 + "> does not start with a scheme component")
664 .pData));
665 return false;
668 aBuffer.append(aBaseComponents.aScheme.pBegin,
669 aBaseComponents.aScheme.getLength());
670 if (aRelComponents.aAuthority.isPresent())
672 aBuffer.append(aRelComponents.aAuthority.pBegin,
673 aRelComponents.aAuthority.getLength());
674 appendPath(
675 aBuffer, aBuffer.getLength(), false,
676 aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
678 if (aRelComponents.aQuery.isPresent())
680 aBuffer.append(aRelComponents.aQuery.pBegin,
681 aRelComponents.aQuery.getLength());
684 else
686 if (aBaseComponents.aAuthority.isPresent())
688 aBuffer.append(aBaseComponents.aAuthority.pBegin,
689 aBaseComponents.aAuthority.getLength());
692 if (aRelComponents.aPath.pBegin == aRelComponents.aPath.pEnd)
694 aBuffer.append(aBaseComponents.aPath.pBegin,
695 aBaseComponents.aPath.getLength());
696 if (aRelComponents.aQuery.isPresent())
698 aBuffer.append(aRelComponents.aQuery.pBegin,
699 aRelComponents.aQuery.getLength());
701 else if (aBaseComponents.aQuery.isPresent())
703 aBuffer.append(aBaseComponents.aQuery.pBegin,
704 aBaseComponents.aQuery.getLength());
707 else
709 if (*aRelComponents.aPath.pBegin == '/')
711 appendPath(
712 aBuffer, aBuffer.getLength(), false,
713 aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
715 else if (aBaseComponents.aAuthority.isPresent()
716 && aBaseComponents.aPath.pBegin
717 == aBaseComponents.aPath.pEnd)
719 appendPath(
720 aBuffer, aBuffer.getLength(), true,
721 aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
723 else
725 sal_Int32 n = aBuffer.getLength();
726 sal_Int32 i = rtl_ustr_lastIndexOfChar_WithLength(
727 aBaseComponents.aPath.pBegin,
728 aBaseComponents.aPath.getLength(), '/');
730 if (i >= 0)
732 appendPath(
733 aBuffer, n, false, aBaseComponents.aPath.pBegin,
734 aBaseComponents.aPath.pBegin + i);
737 appendPath(
738 aBuffer, n, i >= 0, aRelComponents.aPath.pBegin,
739 aRelComponents.aPath.pEnd);
742 if (aRelComponents.aQuery.isPresent())
744 aBuffer.append(aRelComponents.aQuery.pBegin,
745 aRelComponents.aQuery.getLength());
750 if (aRelComponents.aFragment.isPresent())
752 aBuffer.append(aRelComponents.aFragment.pBegin,
753 aRelComponents.aFragment.getLength());
756 rtl_uString_assign(pResult, aBuffer.makeStringAndClear().pData);
757 return true;
760 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */