Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sal/rtl/uri.cxx
Line
Count
Source
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 <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>
32
33
#include <uri_internal.hxx>
34
35
#include <algorithm>
36
#include <cstddef>
37
38
namespace {
39
40
sal_Unicode const cEscapePrefix = 0x25; // '%'
41
42
int getHexWeight(sal_uInt32 nUtf32)
43
1.48M
{
44
1.48M
    return nUtf32 >= 0x30 && nUtf32 <= 0x39 ? // '0'--'9'
45
765k
               static_cast< int >(nUtf32 - 0x30) :
46
1.48M
           nUtf32 >= 0x41 && nUtf32 <= 0x46 ? // 'A'--'F'
47
718k
               static_cast< int >(nUtf32 - 0x41 + 10) :
48
719k
           nUtf32 >= 0x61 && nUtf32 <= 0x66 ? // 'a'--'f'
49
15
               static_cast< int >(nUtf32 - 0x61 + 10) :
50
269
               -1; // not a hex digit
51
1.48M
}
52
53
bool isValid(sal_Bool const * pCharClass, sal_uInt32 nUtf32)
54
29.3M
{
55
29.3M
    return nUtf32 < rtl::UriCharClassSize && pCharClass[nUtf32];
56
29.3M
}
57
58
void writeUnicode(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
59
                         sal_Unicode cChar)
60
33.5M
{
61
33.5M
    rtl_uStringbuffer_insert(pBuffer, pCapacity, (*pBuffer)->length, &cChar, 1);
62
33.5M
}
63
64
}
65
66
namespace rtl::uri::detail {
67
68
/** Read any of the following:
69
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.
74
 */
75
sal_uInt32 readUcs4(sal_Unicode const ** pBegin, sal_Unicode const * pEnd,
76
                    bool bEncoded, rtl_TextEncoding eCharset,
77
                    EscapeType * pType)
78
103M
{
79
103M
    sal_uInt32 nChar = *(*pBegin)++;
80
103M
    int nWeight1;
81
103M
    int nWeight2;
82
103M
    if (nChar == cEscapePrefix && bEncoded && pEnd - *pBegin >= 2
83
739k
        && (nWeight1 = getHexWeight((*pBegin)[0])) >= 0
84
738k
        && (nWeight2 = getHexWeight((*pBegin)[1])) >= 0)
85
738k
    {
86
738k
        *pBegin += 2;
87
738k
        nChar = static_cast< sal_uInt32 >(nWeight1 << 4 | nWeight2);
88
738k
        if (nChar <= 0x7F)
89
736k
        {
90
736k
            *pType = EscapeChar;
91
736k
        }
92
2.22k
        else if (eCharset == RTL_TEXTENCODING_UTF8)
93
2.21k
        {
94
2.21k
            if (nChar >= 0xC0 && nChar <= 0xF4)
95
2.20k
            {
96
2.20k
                sal_uInt32 nEncoded;
97
2.20k
                int nShift;
98
2.20k
                sal_uInt32 nMin;
99
2.20k
                if (nChar <= 0xDF)
100
1.15k
                {
101
1.15k
                    nEncoded = (nChar & 0x1F) << 6;
102
1.15k
                    nShift = 0;
103
1.15k
                    nMin = 0x80;
104
1.15k
                }
105
1.05k
                else if (nChar <= 0xEF)
106
1.00k
                {
107
1.00k
                    nEncoded = (nChar & 0x0F) << 12;
108
1.00k
                    nShift = 6;
109
1.00k
                    nMin = 0x800;
110
1.00k
                }
111
42
                else
112
42
                {
113
42
                    nEncoded = (nChar & 0x07) << 18;
114
42
                    nShift = 12;
115
42
                    nMin = 0x10000;
116
42
                }
117
118
2.20k
                sal_Unicode const * p = *pBegin;
119
2.20k
                bool bUTF8 = true;
120
121
5.49k
                for (; nShift >= 0; nShift -= 6)
122
3.29k
                {
123
3.29k
                    if (pEnd - p < 3 || p[0] != cEscapePrefix
124
3.29k
                        || (nWeight1 = getHexWeight(p[1])) < 8
125
3.29k
                        || nWeight1 > 11
126
3.29k
                        || (nWeight2 = getHexWeight(p[2])) < 0)
127
2
                    {
128
2
                        bUTF8 = false;
129
2
                        break;
130
2
                    }
131
3.29k
                    p += 3;
132
3.29k
                    nEncoded |= ((nWeight1 & 3) << 4 | nWeight2) << nShift;
133
3.29k
                }
134
2.20k
                if (bUTF8 && rtl::isUnicodeScalarValue(nEncoded)
135
2.19k
                    && nEncoded >= nMin)
136
2.19k
                {
137
2.19k
                    *pBegin = p;
138
2.19k
                    *pType = EscapeChar;
139
2.19k
                    return nEncoded;
140
2.19k
                }
141
2.20k
            }
142
24
            *pType = EscapeOctet;
143
24
        }
144
6
        else
145
6
        {
146
6
            OStringBuffer aBuf(16);
147
6
            aBuf.append(static_cast< char >(nChar));
148
6
            rtl_TextToUnicodeConverter aConverter
149
6
                = rtl_createTextToUnicodeConverter(eCharset);
150
6
            sal_Unicode const * p = *pBegin;
151
152
6
            for (;;)
153
6
            {
154
6
                sal_Unicode aDst[2];
155
6
                sal_uInt32 nInfo;
156
6
                sal_Size nConverted;
157
6
                sal_Size nDstSize = rtl_convertTextToUnicode(
158
6
                    aConverter, nullptr, aBuf.getStr(), aBuf.getLength(), aDst,
159
6
                    SAL_N_ELEMENTS( aDst ),
160
6
                    (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
161
6
                     | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
162
6
                     | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR),
163
6
                    &nInfo, &nConverted);
164
165
6
                if (nInfo == 0)
166
6
                {
167
6
                    assert( nConverted
168
6
                        == sal::static_int_cast< sal_uInt32 >(
169
6
                            aBuf.getLength()));
170
171
6
                    rtl_destroyTextToUnicodeConverter(aConverter);
172
6
                    *pBegin = p;
173
6
                    *pType = EscapeChar;
174
175
6
                    assert( nDstSize == 1
176
6
                        || (nDstSize == 2 && rtl::isHighSurrogate(aDst[0])
177
6
                            && rtl::isLowSurrogate(aDst[1])));
178
179
6
                    return nDstSize == 1
180
6
                        ? aDst[0] : rtl::combineSurrogates(aDst[0], aDst[1]);
181
6
                }
182
0
                if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL
183
0
                         && pEnd - p >= 3 && p[0] == cEscapePrefix
184
0
                         && (nWeight1 = getHexWeight(p[1])) >= 0
185
0
                         && (nWeight2 = getHexWeight(p[2])) >= 0)
186
0
                {
187
0
                    p += 3;
188
0
                    aBuf.append(static_cast< char >(nWeight1 << 4 | nWeight2));
189
0
                }
190
0
                else if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL
191
0
                         && p != pEnd && *p <= 0x7F)
192
0
                {
193
0
                    aBuf.append(static_cast< char >(*p++));
194
0
                }
195
0
                else
196
0
                {
197
0
                    assert(
198
0
                        (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL)
199
0
                        == 0);
200
0
                    break;
201
0
                }
202
0
            }
203
0
            rtl_destroyTextToUnicodeConverter(aConverter);
204
0
            *pType = EscapeOctet;
205
0
        }
206
736k
        return nChar;
207
738k
    }
208
209
103M
    *pType = EscapeNo;
210
103M
    return rtl::isHighSurrogate(nChar) && *pBegin < pEnd
211
3.11k
           && rtl::isLowSurrogate(**pBegin) ?
212
103M
               rtl::combineSurrogates(nChar, *(*pBegin)++) : nChar;
213
103M
}
214
215
}
216
217
namespace {
218
219
void writeUcs4(rtl_uString ** pBuffer, sal_Int32 * pCapacity, sal_uInt32 nUtf32)
220
25.2M
{
221
25.2M
    rtl_uStringbuffer_insertUtf32(pBuffer, pCapacity, (*pBuffer)->length, nUtf32);
222
25.2M
}
223
224
void writeEscapeOctet(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
225
                      sal_uInt32 nOctet)
226
1.81M
{
227
1.81M
    assert(nOctet <= 0xFF); // bad octet
228
229
1.81M
    static sal_Unicode const aHex[16]
230
1.81M
        = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
231
1.81M
            0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }; /* '0'--'9', 'A'--'F' */
232
233
1.81M
    writeUnicode(pBuffer, pCapacity, cEscapePrefix);
234
1.81M
    writeUnicode(pBuffer, pCapacity, aHex[nOctet >> 4]);
235
1.81M
    writeUnicode(pBuffer, pCapacity, aHex[nOctet & 15]);
236
1.81M
}
237
238
bool writeEscapeChar(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
239
                     sal_uInt32 nUtf32, rtl_TextEncoding eCharset, bool bStrict)
240
1.25M
{
241
1.25M
    assert(rtl::isUnicodeCodePoint(nUtf32));
242
1.25M
    if (eCharset == RTL_TEXTENCODING_UTF8)
243
1.25M
    {
244
1.25M
        if (nUtf32 < 0x80)
245
950k
        {
246
950k
            writeEscapeOctet(pBuffer, pCapacity, nUtf32);
247
950k
        }
248
307k
        else if (nUtf32 < 0x800)
249
54.0k
        {
250
54.0k
            writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 6 | 0xC0);
251
54.0k
            writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
252
54.0k
        }
253
253k
        else if (nUtf32 < 0x10000)
254
253k
        {
255
253k
            writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 12 | 0xE0);
256
253k
            writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 6 & 0x3F) | 0x80);
257
253k
            writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
258
253k
        }
259
350
        else
260
350
        {
261
350
            writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 18 | 0xF0);
262
350
            writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 12 & 0x3F) | 0x80);
263
350
            writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 6 & 0x3F) | 0x80);
264
350
            writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
265
350
        }
266
1.25M
    }
267
0
    else
268
0
    {
269
0
        rtl_UnicodeToTextConverter aConverter
270
0
            = rtl_createUnicodeToTextConverter(eCharset);
271
0
        sal_Unicode aSrc[2];
272
0
        sal_Size nSrcSize = rtl::splitSurrogates(nUtf32, aSrc);
273
274
0
        char aDst[32]; // FIXME  random value
275
0
        sal_uInt32 nInfo;
276
0
        sal_Size nConverted;
277
0
        sal_Size nDstSize = rtl_convertUnicodeToText(
278
0
            aConverter, nullptr, aSrc, nSrcSize, aDst, sizeof aDst,
279
0
            RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
280
0
            | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
281
0
            | RTL_UNICODETOTEXT_FLAGS_FLUSH,
282
0
            &nInfo, &nConverted);
283
0
        assert((nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) == 0);
284
0
        rtl_destroyUnicodeToTextConverter(aConverter);
285
286
0
        if (nInfo == 0)
287
0
        {
288
0
            assert(nConverted == nSrcSize); // bad rtl_convertUnicodeToText
289
290
0
            for (sal_Size i = 0; i < nDstSize; ++i)
291
0
            {
292
0
                writeEscapeOctet(pBuffer, pCapacity,
293
0
                                 static_cast< unsigned char >(aDst[i]));
294
                    // FIXME  all octets are escaped, even if there is no need
295
0
            }
296
0
        }
297
0
        else
298
0
        {
299
0
            if (bStrict)
300
0
                return false;
301
302
0
            writeUcs4(pBuffer, pCapacity, nUtf32);
303
0
        }
304
0
    }
305
1.25M
    return true;
306
1.25M
}
307
308
struct Component
309
{
310
    sal_Unicode const * pBegin;
311
    sal_Unicode const * pEnd;
312
313
120k
    Component(): pBegin(nullptr), pEnd(nullptr) {}
314
315
37.8k
    bool isPresent() const { return pBegin != nullptr; }
316
317
    sal_Int32 getLength() const;
318
};
319
320
sal_Int32 Component::getLength() const
321
8.11k
{
322
8.11k
    assert(isPresent()); // taking length of non-present component
323
8.11k
    return static_cast< sal_Int32 >(pEnd - pBegin);
324
8.11k
}
325
326
struct Components
327
{
328
    Component aScheme;
329
    Component aAuthority;
330
    Component aPath;
331
    Component aQuery;
332
    Component aFragment;
333
};
334
335
void parseUriRef(rtl_uString const * pUriRef, Components * pComponents)
336
24.1k
{
337
    // This algorithm is liberal and accepts various forms of illegal input.
338
339
24.1k
    sal_Unicode const * pBegin = pUriRef->buffer;
340
24.1k
    sal_Unicode const * pEnd = pBegin + pUriRef->length;
341
24.1k
    sal_Unicode const * pPos = pBegin;
342
343
24.1k
    if (pPos != pEnd && rtl::isAsciiAlpha(*pPos))
344
4.18k
    {
345
20.5k
        for (sal_Unicode const * p = pPos + 1; p != pEnd; ++p)
346
20.4k
        {
347
20.4k
            if (*p == ':')
348
4.04k
            {
349
4.04k
                pComponents->aScheme.pBegin = pBegin;
350
4.04k
                pComponents->aScheme.pEnd = ++p;
351
4.04k
                pPos = p;
352
4.04k
                break;
353
4.04k
            }
354
355
16.4k
            if (!rtl::isAsciiAlphanumeric(*p) && *p != '+' && *p != '-'
356
123
                     && *p != '.')
357
114
            {
358
114
                break;
359
114
            }
360
16.4k
        }
361
4.18k
    }
362
363
24.1k
    if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
364
2.80k
    {
365
2.80k
        pComponents->aAuthority.pBegin = pPos;
366
2.80k
        pPos += 2;
367
49.5k
        while (pPos != pEnd && *pPos != '/' && *pPos != '?' && *pPos != '#')
368
46.7k
        {
369
46.7k
            ++pPos;
370
46.7k
        }
371
372
2.80k
        pComponents->aAuthority.pEnd = pPos;
373
2.80k
    }
374
375
24.1k
    pComponents->aPath.pBegin = pPos;
376
162k
    while (pPos != pEnd && *pPos != '?' && * pPos != '#')
377
138k
    {
378
138k
        ++pPos;
379
138k
    }
380
381
24.1k
    pComponents->aPath.pEnd = pPos;
382
383
24.1k
    if (pPos != pEnd && *pPos == '?')
384
581
    {
385
581
        pComponents->aQuery.pBegin = pPos++;
386
25.3k
        while (pPos != pEnd && * pPos != '#')
387
24.7k
        {
388
24.7k
            ++pPos;
389
24.7k
        }
390
391
581
        pComponents->aQuery.pEnd = pPos;
392
581
    }
393
394
24.1k
    if (pPos != pEnd)
395
64
    {
396
64
        assert(*pPos == '#');
397
64
        pComponents->aFragment.pBegin = pPos;
398
64
        pComponents->aFragment.pEnd = pEnd;
399
64
    }
400
24.1k
}
401
402
void appendPath(
403
    OUStringBuffer & buffer, sal_Int32 bufferStart, bool precedingSlash,
404
    sal_Unicode const * pathBegin, sal_Unicode const * pathEnd)
405
3.29k
{
406
13.7k
    while (precedingSlash || pathBegin != pathEnd)
407
10.4k
    {
408
10.4k
        sal_Unicode const * p = pathBegin;
409
122k
        while (p != pathEnd && *p != '/')
410
112k
        {
411
112k
            ++p;
412
112k
        }
413
414
10.4k
        std::size_t n = p - pathBegin;
415
10.4k
        if (n == 1 && pathBegin[0] == '.')
416
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
426
0
        }
427
10.4k
        else if (n == 2 && pathBegin[0] == '.' && pathBegin[1] == '.')
428
0
        {
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
0
            if (precedingSlash)
440
0
            {
441
0
                buffer.truncate(
442
0
                    bufferStart
443
0
                    + std::max<sal_Int32>(
444
0
                        rtl_ustr_lastIndexOfChar_WithLength(
445
0
                            buffer.getStr() + bufferStart,
446
0
                            buffer.getLength() - bufferStart, '/'),
447
0
                        0));
448
0
            }
449
0
        }
450
10.4k
        else
451
10.4k
        {
452
10.4k
            if (precedingSlash)
453
7.17k
                buffer.append('/');
454
455
10.4k
            buffer.append(pathBegin, n);
456
10.4k
            precedingSlash = p != pathEnd;
457
10.4k
        }
458
10.4k
        pathBegin = p + (p == pathEnd ? 0 : 1);
459
10.4k
    }
460
3.29k
}
461
462
}
463
464
sal_Bool const * SAL_CALL rtl_getUriCharClass(rtl_UriCharClass eCharClass) noexcept
465
492
{
466
492
    static constexpr std::array<sal_Bool, rtl::UriCharClassSize> aCharClass[] = {
467
492
        rtl::createUriCharClass(u8""), // None
468
492
        rtl::createUriCharClass(
469
492
            u8"!$&'()*+,-./:;=?@[]_~"
470
492
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // Uric
471
492
        rtl::createUriCharClass(
472
492
            u8"!$&'()*+,-.:;=?@_~"
473
492
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // UricNoSlash
474
492
        rtl::createUriCharClass(
475
492
            u8"!$&'()*+,-.;=@_~"
476
492
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // RelSegment
477
492
        rtl::createUriCharClass(
478
492
            u8"!$&'()*+,-.:;=@_~"
479
492
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // RegName
480
492
        rtl::createUriCharClass(
481
492
            u8"!$&'()*+,-.:;=_~"
482
492
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // Userinfo
483
492
        rtl::createUriCharClass(
484
492
            u8"!$&'()*+,-.:=@_~"
485
492
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), // Pchar
486
492
        rtl::createUriCharClass(
487
492
            u8"!$&'()*+-./:?@_~"
488
492
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")}; // UnoParamValue
489
490
492
    assert(
491
492
        (eCharClass >= 0
492
492
         && (sal::static_int_cast< std::size_t >(eCharClass)
493
492
             < SAL_N_ELEMENTS(aCharClass)))); // bad eCharClass
494
492
    return aCharClass[eCharClass].data();
495
492
}
496
497
void SAL_CALL rtl_uriEncode(rtl_uString * pText, sal_Bool const * pCharClass,
498
                            rtl_UriEncodeMechanism eMechanism,
499
                            rtl_TextEncoding eCharset, rtl_uString ** pResult) noexcept
500
890k
{
501
890k
    assert(!pCharClass[0x25]); // make sure the percent sign is encoded...
502
503
890k
    sal_Unicode const * p = pText->buffer;
504
890k
    sal_Unicode const * pEnd = p + pText->length;
505
890k
    sal_Int32 nCapacity = 256;
506
890k
    rtl_uString_new_WithLength(pResult, nCapacity);
507
508
30.2M
    while (p < pEnd)
509
29.3M
    {
510
29.3M
        rtl::uri::detail::EscapeType eType;
511
29.3M
        sal_uInt32 nUtf32 = rtl::uri::detail::readUcs4(
512
29.3M
            &p, pEnd,
513
29.3M
            (eMechanism == rtl_UriEncodeKeepEscapes
514
29.3M
             || eMechanism == rtl_UriEncodeCheckEscapes
515
29.3M
             || eMechanism == rtl_UriEncodeStrictKeepEscapes),
516
29.3M
            eMechanism == rtl_UriEncodeStrictKeepEscapes ? RTL_TEXTENCODING_UTF8 : eCharset,
517
29.3M
            &eType);
518
519
29.3M
        switch (eType)
520
29.3M
        {
521
29.3M
        case rtl::uri::detail::EscapeNo:
522
29.3M
            if (isValid(pCharClass, nUtf32)) // implies nUtf32 <= 0x7F
523
28.1M
            {
524
28.1M
                writeUnicode(pResult, &nCapacity,
525
28.1M
                             static_cast< sal_Unicode >(nUtf32));
526
28.1M
            }
527
1.25M
            else if (!writeEscapeChar(
528
1.25M
                         pResult, &nCapacity, nUtf32, eCharset,
529
1.25M
                         (eMechanism == rtl_UriEncodeStrict
530
1.25M
                          || eMechanism == rtl_UriEncodeStrictKeepEscapes)))
531
0
            {
532
0
                rtl_uString_new(pResult);
533
0
                return;
534
0
            }
535
29.3M
            break;
536
537
29.3M
        case rtl::uri::detail::EscapeChar:
538
0
            if (eMechanism == rtl_UriEncodeCheckEscapes
539
0
                && isValid(pCharClass, nUtf32)) // implies nUtf32 <= 0x7F
540
0
            {
541
0
                writeUnicode(pResult, &nCapacity,
542
0
                             static_cast< sal_Unicode >(nUtf32));
543
0
            }
544
0
            else if (!writeEscapeChar(
545
0
                         pResult, &nCapacity, nUtf32, eCharset,
546
0
                         (eMechanism == rtl_UriEncodeStrict
547
0
                          || eMechanism == rtl_UriEncodeStrictKeepEscapes)))
548
0
            {
549
0
                rtl_uString_new(pResult);
550
0
                return;
551
0
            }
552
0
            break;
553
554
0
        case rtl::uri::detail::EscapeOctet:
555
0
            writeEscapeOctet(pResult, &nCapacity, nUtf32);
556
0
            break;
557
29.3M
        }
558
29.3M
    }
559
890k
    *pResult = rtl_uStringBuffer_makeStringAndClear(pResult, &nCapacity);
560
890k
}
561
562
void SAL_CALL rtl_uriDecode(rtl_uString * pText,
563
                            rtl_UriDecodeMechanism eMechanism,
564
                            rtl_TextEncoding eCharset, rtl_uString ** pResult) noexcept
565
799k
{
566
799k
    switch (eMechanism)
567
799k
    {
568
0
    case rtl_UriDecodeNone:
569
0
        rtl_uString_assign(pResult, pText);
570
0
        break;
571
572
0
    case rtl_UriDecodeToIuri:
573
0
        eCharset = RTL_TEXTENCODING_UTF8;
574
0
        [[fallthrough]];
575
799k
    default: // rtl_UriDecodeWithCharset, rtl_UriDecodeStrict
576
799k
        {
577
799k
            sal_Unicode const * p = pText->buffer;
578
799k
            sal_Unicode const * pEnd = p + pText->length;
579
799k
            sal_Int32 nCapacity = pText->length;
580
799k
            rtl_uString_new_WithLength(pResult, nCapacity);
581
582
26.0M
            while (p < pEnd)
583
25.2M
            {
584
25.2M
                rtl::uri::detail::EscapeType eType;
585
25.2M
                sal_uInt32 nUtf32 = rtl::uri::detail::readUcs4(&p, pEnd, true, eCharset, &eType);
586
25.2M
                switch (eType)
587
25.2M
                {
588
18.0k
                case rtl::uri::detail::EscapeChar:
589
18.0k
                    if (nUtf32 <= 0x7F && eMechanism == rtl_UriDecodeToIuri)
590
0
                    {
591
0
                        writeEscapeOctet(pResult, &nCapacity, nUtf32);
592
0
                        break;
593
0
                    }
594
18.0k
                    [[fallthrough]];
595
596
25.2M
                case rtl::uri::detail::EscapeNo:
597
25.2M
                    writeUcs4(pResult, &nCapacity, nUtf32);
598
25.2M
                    break;
599
600
15
                case rtl::uri::detail::EscapeOctet:
601
15
                    if (eMechanism == rtl_UriDecodeStrict)
602
0
                    {
603
0
                        rtl_uString_new(pResult);
604
0
                        return;
605
0
                    }
606
15
                    writeEscapeOctet(pResult, &nCapacity, nUtf32);
607
15
                    break;
608
25.2M
                }
609
25.2M
            }
610
611
799k
            *pResult = rtl_uStringBuffer_makeStringAndClear( pResult, &nCapacity );
612
799k
        }
613
0
        break;
614
799k
    }
615
799k
}
616
617
sal_Bool SAL_CALL rtl_uriConvertRelToAbs(rtl_uString * pBaseUriRef,
618
                                         rtl_uString * pRelUriRef,
619
                                         rtl_uString ** pResult,
620
                                         rtl_uString ** pException) noexcept
621
13.7k
{
622
    // Use the strict parser algorithm from RFC 3986, section 5.2, to turn the
623
    // relative URI into an absolute one:
624
13.7k
    Components aRelComponents;
625
13.7k
    parseUriRef(pRelUriRef, &aRelComponents);
626
13.7k
    OUStringBuffer aBuffer(256);
627
628
13.7k
    if (aRelComponents.aScheme.isPresent())
629
3.28k
    {
630
3.28k
        aBuffer.append(aRelComponents.aScheme.pBegin,
631
3.28k
                       aRelComponents.aScheme.getLength());
632
633
3.28k
        if (aRelComponents.aAuthority.isPresent())
634
2.42k
        {
635
2.42k
            aBuffer.append(aRelComponents.aAuthority.pBegin,
636
2.42k
                           aRelComponents.aAuthority.getLength());
637
2.42k
        }
638
639
3.28k
        appendPath(
640
3.28k
            aBuffer, aBuffer.getLength(), false, aRelComponents.aPath.pBegin,
641
3.28k
            aRelComponents.aPath.pEnd);
642
643
3.28k
        if (aRelComponents.aQuery.isPresent())
644
421
        {
645
421
            aBuffer.append(aRelComponents.aQuery.pBegin,
646
421
                           aRelComponents.aQuery.getLength());
647
421
        }
648
3.28k
    }
649
10.4k
    else
650
10.4k
    {
651
10.4k
        Components aBaseComponents;
652
10.4k
        parseUriRef(pBaseUriRef, &aBaseComponents);
653
10.4k
        if (!aBaseComponents.aScheme.isPresent())
654
9.69k
        {
655
9.69k
            rtl_uString_assign(
656
9.69k
                pException,
657
9.69k
                (OUString(
658
9.69k
                    "<" + OUString::unacquired(&pBaseUriRef)
659
9.69k
                    + "> does not start with a scheme component")
660
9.69k
                 .pData));
661
9.69k
            return false;
662
9.69k
        }
663
664
754
        aBuffer.append(aBaseComponents.aScheme.pBegin,
665
754
                       aBaseComponents.aScheme.getLength());
666
754
        if (aRelComponents.aAuthority.isPresent())
667
0
        {
668
0
            aBuffer.append(aRelComponents.aAuthority.pBegin,
669
0
                           aRelComponents.aAuthority.getLength());
670
0
            appendPath(
671
0
                aBuffer, aBuffer.getLength(), false,
672
0
                aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
673
674
0
            if (aRelComponents.aQuery.isPresent())
675
0
            {
676
0
                aBuffer.append(aRelComponents.aQuery.pBegin,
677
0
                               aRelComponents.aQuery.getLength());
678
0
            }
679
0
        }
680
754
        else
681
754
        {
682
754
            if (aBaseComponents.aAuthority.isPresent())
683
350
            {
684
350
                aBuffer.append(aBaseComponents.aAuthority.pBegin,
685
350
                               aBaseComponents.aAuthority.getLength());
686
350
            }
687
688
754
            if (aRelComponents.aPath.pBegin == aRelComponents.aPath.pEnd)
689
751
            {
690
751
                aBuffer.append(aBaseComponents.aPath.pBegin,
691
751
                               aBaseComponents.aPath.getLength());
692
751
                if (aRelComponents.aQuery.isPresent())
693
0
                {
694
0
                    aBuffer.append(aRelComponents.aQuery.pBegin,
695
0
                                   aRelComponents.aQuery.getLength());
696
0
                }
697
751
                else if (aBaseComponents.aQuery.isPresent())
698
86
                {
699
86
                    aBuffer.append(aBaseComponents.aQuery.pBegin,
700
86
                                   aBaseComponents.aQuery.getLength());
701
86
                }
702
751
            }
703
3
            else
704
3
            {
705
3
                if (*aRelComponents.aPath.pBegin == '/')
706
0
                {
707
0
                    appendPath(
708
0
                        aBuffer, aBuffer.getLength(), false,
709
0
                        aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
710
0
                }
711
3
                else if (aBaseComponents.aAuthority.isPresent()
712
3
                         && aBaseComponents.aPath.pBegin
713
3
                            == aBaseComponents.aPath.pEnd)
714
3
                {
715
3
                    appendPath(
716
3
                        aBuffer, aBuffer.getLength(), true,
717
3
                        aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
718
3
                }
719
0
                else
720
0
                {
721
0
                    sal_Int32 n = aBuffer.getLength();
722
0
                    sal_Int32 i = rtl_ustr_lastIndexOfChar_WithLength(
723
0
                        aBaseComponents.aPath.pBegin,
724
0
                        aBaseComponents.aPath.getLength(), '/');
725
726
0
                    if (i >= 0)
727
0
                    {
728
0
                        appendPath(
729
0
                            aBuffer, n, false, aBaseComponents.aPath.pBegin,
730
0
                            aBaseComponents.aPath.pBegin + i);
731
0
                    }
732
733
0
                    appendPath(
734
0
                        aBuffer, n, i >= 0, aRelComponents.aPath.pBegin,
735
0
                        aRelComponents.aPath.pEnd);
736
0
                }
737
738
3
                if (aRelComponents.aQuery.isPresent())
739
0
                {
740
0
                    aBuffer.append(aRelComponents.aQuery.pBegin,
741
0
                                   aRelComponents.aQuery.getLength());
742
0
                }
743
3
            }
744
754
        }
745
754
    }
746
4.04k
    if (aRelComponents.aFragment.isPresent())
747
36
    {
748
36
        aBuffer.append(aRelComponents.aFragment.pBegin,
749
36
                       aRelComponents.aFragment.getLength());
750
36
    }
751
752
4.04k
    rtl_uString_assign(pResult, aBuffer.makeStringAndClear().pData);
753
4.04k
    return true;
754
13.7k
}
755
756
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */