Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/tools/source/fsys/urlobj.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 <sal/config.h>
21
22
#include <tools/urlobj.hxx>
23
#include <tools/debug.hxx>
24
#include <tools/inetmime.hxx>
25
#include <tools/stream.hxx>
26
#include <com/sun/star/uno/Reference.hxx>
27
#include <com/sun/star/util/XStringWidth.hpp>
28
#include <o3tl/enumarray.hxx>
29
#include <osl/diagnose.h>
30
#include <osl/file.hxx>
31
#include <rtl/character.hxx>
32
#include <rtl/string.h>
33
#include <rtl/textenc.h>
34
#include <rtl/ustring.hxx>
35
#include <sal/log.hxx>
36
#include <sal/types.h>
37
38
#include <algorithm>
39
#include <cassert>
40
#include <limits>
41
#include <memory>
42
#include <string_view>
43
44
#include <string.h>
45
46
#include <com/sun/star/uno/Sequence.hxx>
47
#include <comphelper/base64.hxx>
48
#include <comphelper/string.hxx>
49
50
using namespace css;
51
52
//  INetURLObject
53
54
/* The URI grammar (using RFC 2234 conventions).
55
56
   Constructs of the form
57
       {reference <rule1> using rule2}
58
   stand for a rule matching the given rule1 specified in the given reference,
59
   encoded to URI syntax using rule2 (as specified in this URI grammar).
60
61
62
   ; RFC 1738, RFC 2396, RFC 2732, private
63
   login = [user [":" password] "@"] hostport
64
   user = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~")
65
   password = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~")
66
   hostport = host [":" port]
67
   host = incomplete-hostname / hostname / IPv4address / IPv6reference
68
   incomplete-hostname = *(domainlabel ".") domainlabel
69
   hostname = *(domainlabel ".") toplabel ["."]
70
   domainlabel = alphanum [*(alphanum / "-") alphanum]
71
   toplabel = ALPHA [*(alphanum / "-") alphanum]
72
   IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
73
   IPv6reference = "[" hexpart [":" IPv4address] "]"
74
   hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
75
   hexseq = hex4 *(":" hex4)
76
   hex4 = 1*4HEXDIG
77
   port = *DIGIT
78
   escaped = "%" HEXDIG HEXDIG
79
   reserved = "$" / "&" / "+" / "," / "/" / ":" / ";" / "=" / "?" / "@" / "[" / "]"
80
   mark = "!" / "'" / "(" / ")" / "*" / "-" / "." / "_" / "~"
81
   alphanum = ALPHA / DIGIT
82
   unreserved = alphanum / mark
83
   uric = escaped / reserved / unreserved
84
   pchar = escaped / unreserved / "$" / "&" / "+" / "," / ":" / "=" / "@"
85
86
87
   ; RFC 1738, RFC 2396
88
   ftp-url = "FTP://" login ["/" segment *("/" segment) [";TYPE=" ("A" / "D" / "I")]]
89
   segment = *pchar
90
91
92
   ; RFC 1738, RFC 2396
93
   http-url = "HTTP://" hostport ["/" segment *("/" segment) ["?" *uric]]
94
   segment = *(pchar / ";")
95
96
97
   ; RFC 1738, RFC 2396, <http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q188997&>
98
   file-url = "FILE://" [host / "LOCALHOST" / netbios-name] ["/" segment *("/" segment)]
99
   segment = *pchar
100
   netbios-name = 1*{<alphanum / "!" / "#" / "$" / "%" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "^" / "_" / "{" / "}" / "~"> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "_" / "~")}
101
102
103
   ; RFC 2368, RFC 2396
104
   mailto-url = "MAILTO:" [to] [headers]
105
   to = {RFC 822 <#mailbox> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
106
   headers = "?" header *("&" header)
107
   header = hname "=" hvalue
108
   hname = {RFC 822 <field-name> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} / "BODY"
109
   hvalue = {RFC 822 <field-body> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
110
111
112
   ; private (see RFC 1738, RFC 2396)
113
   vnd-sun-star-webdav-url = "VND.SUN.STAR.WEBDAV://" hostport ["/" segment *("/" segment) ["?" *uric]]
114
   segment = *(pchar / ";")
115
116
117
   ; private
118
   private-url = "PRIVATE:" path ["?" *uric]
119
   path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
120
121
122
   ; private
123
   vnd-sun-star-help-url = "VND.SUN.STAR.HELP://" name *("/" segment) ["?" *uric]
124
   name = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
125
   segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
126
127
128
   ; private
129
   https-url = "HTTPS://" hostport ["/" segment *("/" segment) ["?" *uric]]
130
   segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
131
132
133
   ; private
134
   macro-url = "MACRO:" path ["?" *uric]
135
   path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
136
137
138
   ; private
139
   javascript-url = "JAVASCRIPT:" *uric
140
141
142
   ; RFC 2397
143
   data-url = "DATA:" [mediatype] [";BASE64"] "," *uric
144
   mediatype = [type "/" subtype] *(";" attribute "=" value)
145
   type = {RFC 2045 <type> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
146
   subtype = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
147
   attribute = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
148
   value = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
149
150
151
   ; RFC 2392, RFC 2396
152
   cid-url = "CID:" {RFC 822 <addr-spec> using *uric}
153
154
155
   ; private
156
   vnd-sun-star-hier-url = "VND.SUN.STAR.HIER:" ["//"reg_name] *("/" *pchar)
157
   reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
158
159
160
   ; private
161
   uno-url = ".UNO:" path ["?" *uric]
162
   path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
163
164
165
   ; private
166
   component-url = ".COMPONENT:" path ["?" *uric]
167
   path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
168
169
170
   ; private
171
   vnd-sun-star-pkg-url = "VND.SUN.STAR.PKG://" reg_name *("/" *pchar) ["?" *uric]
172
   reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
173
174
175
   ; RFC 2255
176
   ldap-url = "LDAP://" [hostport] ["/" [dn ["?" [attrdesct *("," attrdesc)] ["?" ["base" / "one" / "sub"] ["?" [filter] ["?" extension *("," extension)]]]]]]
177
   dn = {RFC 2253 <distinguishedName> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
178
   attrdesc = {RFC 2251 <AttributeDescription> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
179
   filter = {RFC 2254 <filter> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
180
   extension = ["!"] ["X-"] extoken ["=" exvalue]
181
   extoken = {RFC 2252 <oid> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
182
   exvalue = {RFC 2251 <LDAPString> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
183
184
185
   ; private
186
   db-url = "DB:" *uric
187
188
189
   ; private
190
   vnd-sun-star-cmd-url = "VND.SUN.STAR.CMD:" opaque_part
191
   opaque_part = uric_no_slash *uric
192
   uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
193
194
195
   ; RFC 1738
196
   telnet-url = "TELNET://" login ["/"]
197
198
199
   ; private
200
   vnd-sun-star-expand-url = "VND.SUN.STAR.EXPAND:" opaque_part
201
   opaque_part = uric_no_slash *uric
202
   uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
203
204
205
   ; private
206
   vnd-sun-star-tdoc-url = "VND.SUN.STAR.TDOC:/" segment *("/" segment)
207
   segment = *pchar
208
209
210
   ; private
211
   unknown-url = scheme ":" 1*uric
212
   scheme = ALPHA *(alphanum / "+" / "-" / ".")
213
214
215
   ; private (http://ubiqx.org/cifs/Appendix-D.html):
216
   smb-url = "SMB://" login ["/" segment *("/" segment) ["?" *uric]]
217
   segment = *(pchar / ";")
218
 */
219
220
sal_Int32 INetURLObject::SubString::clear()
221
24.3M
{
222
24.3M
    sal_Int32 nDelta = -m_nLength;
223
24.3M
    m_nBegin = -1;
224
24.3M
    m_nLength = 0;
225
24.3M
    return nDelta;
226
24.3M
}
227
228
sal_Int32 INetURLObject::SubString::set(OUStringBuffer & rString,
229
                                       std::u16string_view rSubString)
230
707k
{
231
707k
    sal_Int32 nDelta = rSubString.size() - m_nLength;
232
233
707k
    rString.remove(m_nBegin, m_nLength);
234
707k
    rString.insert(m_nBegin, rSubString);
235
236
707k
    m_nLength = rSubString.size();
237
707k
    return nDelta;
238
707k
}
239
240
sal_Int32 INetURLObject::SubString::set(OUString & rString,
241
                                       std::u16string_view rSubString)
242
0
{
243
0
    sal_Int32 nDelta = rSubString.size() - m_nLength;
244
245
0
    rString = OUString::Concat(rString.subView(0, m_nBegin)) +
246
0
             rSubString + rString.subView(m_nBegin + m_nLength);
247
248
0
    m_nLength = rSubString.size();
249
0
    return nDelta;
250
0
}
251
252
sal_Int32 INetURLObject::SubString::set(OUStringBuffer & rString,
253
                                        std::u16string_view rSubString,
254
                                        sal_Int32 nTheBegin)
255
682k
{
256
682k
    m_nBegin = nTheBegin;
257
682k
    return set(rString, rSubString);
258
682k
}
259
260
inline void INetURLObject::SubString::operator +=(sal_Int32 nDelta)
261
386k
{
262
386k
    if (isPresent())
263
147k
        m_nBegin = m_nBegin + nDelta;
264
386k
}
265
266
int INetURLObject::SubString::compare(SubString const & rOther,
267
                                      OUStringBuffer const & rThisString,
268
                                      OUStringBuffer const & rOtherString) const
269
0
{
270
0
    sal_Int32 len = std::min(m_nLength, rOther.m_nLength);
271
0
    sal_Unicode const * p1 = rThisString.getStr() + m_nBegin;
272
0
    sal_Unicode const * end = p1 + len;
273
0
    sal_Unicode const * p2 = rOtherString.getStr() + rOther.m_nBegin;
274
0
    while (p1 != end) {
275
0
        if (*p1 < *p2) {
276
0
            return -1;
277
0
        } else if (*p1 > *p2) {
278
0
            return 1;
279
0
        }
280
0
        ++p1;
281
0
        ++p2;
282
0
    }
283
0
    return m_nLength < rOther.m_nLength ? -1
284
0
        : m_nLength > rOther.m_nLength ? 1
285
0
        : 0;
286
0
}
287
288
struct INetURLObject::SchemeInfo
289
{
290
    OUString m_sScheme;
291
    OUString m_aPrefix;
292
    bool m_bAuthority;
293
    bool m_bUser;
294
    bool m_bAuth;
295
    bool m_bPassword;
296
    bool m_bHost;
297
    bool m_bPort;
298
    bool m_bHierarchical;
299
    bool m_bQuery;
300
};
301
302
struct INetURLObject::PrefixInfo
303
{
304
    enum class Kind { Official, Internal, External }; // order is important!
305
306
    OUString     m_aPrefix;
307
    OUString     m_aTranslatedPrefix;
308
    INetProtocol m_eScheme;
309
    Kind         m_eKind;
310
};
311
312
// static
313
inline INetURLObject::SchemeInfo const &
314
INetURLObject::getSchemeInfo(INetProtocol eTheScheme)
315
11.7M
{
316
11.7M
    static constexpr OUString EMPTY = u""_ustr;
317
11.7M
    static constexpr OUString FTP = u"ftp"_ustr;
318
11.7M
    static constexpr OUString HTTP = u"http"_ustr;
319
11.7M
    static constexpr OUString FILE1 = u"file"_ustr; // because FILE is already defined
320
11.7M
    static constexpr OUString MAILTO = u"mailto"_ustr;
321
11.7M
    static constexpr OUString VND_WEBDAV = u"vnd.sun.star.webdav"_ustr;
322
11.7M
    static constexpr OUString PRIVATE = u"private"_ustr;
323
11.7M
    static constexpr OUString VND_HELP = u"vnd.sun.star.help"_ustr;
324
11.7M
    static constexpr OUString HTTPS = u"https"_ustr;
325
11.7M
    static constexpr OUString MACRO = u"macro"_ustr;
326
11.7M
    static constexpr OUString JAVASCRIPT = u"javascript"_ustr;
327
11.7M
    static constexpr OUString DATA = u"data"_ustr;
328
11.7M
    static constexpr OUString CID = u"cid"_ustr;
329
11.7M
    static constexpr OUString VND_HIER = u"vnd.sun.star.hier"_ustr;
330
11.7M
    static constexpr OUString UNO = u".uno"_ustr;
331
11.7M
    static constexpr OUString COMPONENT = u".component"_ustr;
332
11.7M
    static constexpr OUString VND_PKG = u"vnd.sun.star.pkg"_ustr;
333
11.7M
    static constexpr OUString LDAP = u"ldap"_ustr;
334
11.7M
    static constexpr OUString DB = u"db"_ustr;
335
11.7M
    static constexpr OUString VND_CMD = u"vnd.sun.star.cmd"_ustr;
336
11.7M
    static constexpr OUString TELNET = u"telnet"_ustr;
337
11.7M
    static constexpr OUString VND_EXPAND = u"vnd.sun.star.expand"_ustr;
338
11.7M
    static constexpr OUString VND_TDOC = u"vnd.sun.star.tdoc"_ustr;
339
11.7M
    static constexpr OUString SMB = u"smb"_ustr;
340
11.7M
    static constexpr OUString HID = u"hid"_ustr;
341
11.7M
    static constexpr OUString SFTP = u"sftp"_ustr;
342
11.7M
    static constexpr OUString VND_CMIS = u"vnd.libreoffice.cmis"_ustr;
343
344
11.7M
    static o3tl::enumarray<INetProtocol, SchemeInfo> constexpr map = {
345
        // [-loplugin:redundantfcast]:
346
11.7M
        SchemeInfo{
347
11.7M
            EMPTY, u""_ustr, false, false, false, false, false, false, false, false},
348
11.7M
        SchemeInfo{
349
11.7M
            FTP, u"ftp://"_ustr, true, true, false, true, true, true, true,
350
11.7M
            false},
351
11.7M
        SchemeInfo{
352
11.7M
            HTTP, u"http://"_ustr, true, false, false, false, true, true, true,
353
11.7M
            true},
354
11.7M
        SchemeInfo{
355
11.7M
            FILE1, u"file://"_ustr, true, false, false, false, true, false, true,
356
11.7M
            false},
357
11.7M
        SchemeInfo{
358
11.7M
            MAILTO, u"mailto:"_ustr, false, false, false, false, false, false,
359
11.7M
            false, true},
360
11.7M
        SchemeInfo{
361
11.7M
            VND_WEBDAV, u"vnd.sun.star.webdav://"_ustr, true, false,
362
11.7M
            false, false, true, true, true, true},
363
11.7M
        SchemeInfo{
364
11.7M
            PRIVATE, u"private:"_ustr, false, false, false, false, false, false,
365
11.7M
            false, true},
366
11.7M
        SchemeInfo{
367
11.7M
            VND_HELP, u"vnd.sun.star.help://"_ustr, true, false, false,
368
11.7M
            false, false, false, true, true},
369
11.7M
        SchemeInfo{
370
11.7M
            HTTPS, u"https://"_ustr, true, false, false, false, true, true,
371
11.7M
            true, true},
372
11.7M
        SchemeInfo{
373
11.7M
            MACRO, u"macro:"_ustr, false, false, false, false, false, false,
374
11.7M
            false, true},
375
11.7M
        SchemeInfo{
376
11.7M
            JAVASCRIPT, u"javascript:"_ustr, false, false, false, false, false,
377
11.7M
            false, false, false},
378
11.7M
        SchemeInfo{
379
11.7M
            DATA, u"data:"_ustr, false, false, false, false, false, false, false,
380
11.7M
            false},
381
11.7M
        SchemeInfo{
382
11.7M
            CID, u"cid:"_ustr, false, false, false, false, false, false, false,
383
11.7M
            false},
384
11.7M
        SchemeInfo{
385
11.7M
            VND_HIER, u"vnd.sun.star.hier:"_ustr, true, false, false,
386
11.7M
            false, false, false, true, false},
387
11.7M
        SchemeInfo{
388
11.7M
            UNO, u".uno:"_ustr, false, false, false, false, false, false, false,
389
11.7M
            true},
390
11.7M
        SchemeInfo{
391
11.7M
            COMPONENT, u".component:"_ustr, false, false, false, false, false,
392
11.7M
            false, false, true},
393
11.7M
        SchemeInfo{
394
11.7M
            VND_PKG, u"vnd.sun.star.pkg://"_ustr, true, false, false,
395
11.7M
            false, false, false, true, true},
396
11.7M
        SchemeInfo{
397
11.7M
            LDAP, u"ldap://"_ustr, true, false, false, false, true, true,
398
11.7M
            false, true},
399
11.7M
        SchemeInfo{
400
11.7M
            DB, u"db:"_ustr, false, false, false, false, false, false, false,
401
11.7M
            false},
402
11.7M
        SchemeInfo{
403
11.7M
            VND_CMD, u"vnd.sun.star.cmd:"_ustr, false, false, false,
404
11.7M
            false, false, false, false, false},
405
11.7M
        SchemeInfo{
406
11.7M
            TELNET, u"telnet://"_ustr, true, true, false, true, true, true,
407
11.7M
            true, false},
408
11.7M
        SchemeInfo{
409
11.7M
            VND_EXPAND, u"vnd.sun.star.expand:"_ustr, false, false,
410
11.7M
            false, false, false, false, false, false},
411
11.7M
        SchemeInfo{
412
11.7M
            VND_TDOC, u"vnd.sun.star.tdoc:"_ustr, false, false, false,
413
11.7M
            false, false, false, true, false},
414
11.7M
        SchemeInfo{
415
11.7M
            EMPTY, u""_ustr, false, false, false, false, true, true, true, false },
416
11.7M
        SchemeInfo{
417
11.7M
            SMB, u"smb://"_ustr, true, true, false, true, true, true, true,
418
11.7M
            true},
419
11.7M
        SchemeInfo{
420
11.7M
            HID, u"hid:"_ustr, false, false, false, false, false, false, false,
421
11.7M
            true},
422
11.7M
        SchemeInfo{
423
11.7M
            SFTP, u"sftp://"_ustr, true, true, false, true, true, true, true,
424
11.7M
            true},
425
11.7M
        SchemeInfo{
426
11.7M
            VND_CMIS, u"vnd.libreoffice.cmis://"_ustr, true, true,
427
11.7M
            false, false, true, false, true, true} };
428
11.7M
    return map[eTheScheme];
429
11.7M
};
430
431
inline INetURLObject::SchemeInfo const & INetURLObject::getSchemeInfo() const
432
11.7M
{
433
11.7M
    return getSchemeInfo(m_eScheme);
434
11.7M
}
435
436
namespace {
437
438
sal_Unicode getHexDigit(sal_uInt32 nWeight)
439
65.2M
{
440
65.2M
    assert(nWeight < 16);
441
65.2M
    static const sal_Unicode aDigits[16]
442
65.2M
        = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
443
65.2M
            'D', 'E', 'F' };
444
65.2M
    return aDigits[nWeight];
445
65.2M
}
446
447
}
448
449
// static
450
inline void INetURLObject::appendEscape(OUStringBuffer & rTheText,
451
                                        sal_uInt32 nOctet)
452
32.6M
{
453
32.6M
    rTheText.append( '%' );
454
32.6M
    rTheText.append( getHexDigit(nOctet >> 4) );
455
32.6M
    rTheText.append( getHexDigit(nOctet & 15) );
456
32.6M
}
457
458
namespace {
459
460
enum
461
{
462
    PA = INetURLObject::PART_USER_PASSWORD,
463
    PD = INetURLObject::PART_FPATH,
464
    PE = INetURLObject::PART_AUTHORITY,
465
    PF = INetURLObject::PART_REL_SEGMENT_EXTRA,
466
    PG = INetURLObject::PART_URIC,
467
    PH = INetURLObject::PART_HTTP_PATH,
468
    PI = INetURLObject::PART_MESSAGE_ID_PATH,
469
    PJ = INetURLObject::PART_MAILTO,
470
    PK = INetURLObject::PART_PATH_BEFORE_QUERY,
471
    PL = INetURLObject::PART_PCHAR,
472
    PM = INetURLObject::PART_VISIBLE,
473
    PN = INetURLObject::PART_VISIBLE_NONSPECIAL,
474
    PO = INetURLObject::PART_UNO_PARAM_VALUE,
475
    PP = INetURLObject::PART_UNAMBIGUOUS,
476
    PQ = INetURLObject::PART_URIC_NO_SLASH,
477
    PR = INetURLObject::PART_HTTP_QUERY,
478
};
479
480
sal_uInt32 const aMustEncodeMap[128]
481
    = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
482
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
483
/*   */                                              PP,
484
/* ! */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
485
/* " */                                  PM+PN   +PP,
486
/* # */                                  PM,
487
/* $ */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
488
/* % */                                  PM,
489
/* & */ PA   +PD+PE+PF+PG+PH+PI   +PK+PL+PM+PN+PO   +PQ+PR,
490
/* ' */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
491
/* ( */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
492
/* ) */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
493
/* * */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
494
/* + */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO   +PQ+PR,
495
/* , */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN      +PQ+PR,
496
/* - */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
497
/* . */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
498
/* / */      +PD      +PG+PH+PI+PJ+PK   +PM+PN+PO,
499
/* 0 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
500
/* 1 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
501
/* 2 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
502
/* 3 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
503
/* 4 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
504
/* 5 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
505
/* 6 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
506
/* 7 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
507
/* 8 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
508
/* 9 */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
509
/* : */      +PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO   +PQ+PR,
510
/* ; */ PA      +PE+PF+PG+PH+PI+PJ+PK   +PM         +PQ+PR,
511
/* < */                     +PI         +PM+PN   +PP,
512
/* = */ PA   +PD+PE+PF+PG+PH      +PK+PL+PM+PN      +PQ+PR,
513
/* > */                     +PI         +PM+PN   +PP,
514
/* ? */               +PG               +PM   +PO   +PQ,
515
/* @ */      +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
516
/* A */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
517
/* B */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
518
/* C */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
519
/* D */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
520
/* E */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
521
/* F */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
522
/* G */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
523
/* H */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
524
/* I */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
525
/* J */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
526
/* K */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
527
/* L */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
528
/* M */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
529
/* N */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
530
/* O */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
531
/* P */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
532
/* Q */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
533
/* R */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
534
/* S */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
535
/* T */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
536
/* U */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
537
/* V */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
538
/* W */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
539
/* X */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
540
/* Y */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
541
/* Z */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
542
/* [ */                PG               +PM+PN+PO,
543
/* \ */                                 +PM+PN   +PP,
544
/* ] */                PG               +PM+PN+PO,
545
/* ^ */                                  PM+PN   +PP,
546
/* _ */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
547
/* ` */                                  PM+PN   +PP,
548
/* a */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
549
/* b */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
550
/* c */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
551
/* d */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
552
/* e */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
553
/* f */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
554
/* g */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
555
/* h */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
556
/* i */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
557
/* j */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
558
/* k */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
559
/* l */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
560
/* m */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
561
/* n */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
562
/* o */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
563
/* p */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
564
/* q */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
565
/* r */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
566
/* s */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
567
/* t */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
568
/* u */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
569
/* v */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
570
/* w */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
571
/* x */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
572
/* y */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
573
/* z */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR,
574
/* { */                                  PM+PN   +PP,
575
/* | */                                 +PM+PN   +PP,
576
/* } */                                  PM+PN   +PP,
577
/* ~ */ PA   +PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ,
578
        0 };
579
580
bool mustEncode(sal_uInt32 nUTF32, INetURLObject::Part ePart)
581
43.6M
{
582
43.6M
    return !rtl::isAscii(nUTF32) || !(aMustEncodeMap[nUTF32] & ePart);
583
43.6M
}
584
585
}
586
587
void INetURLObject::setInvalid()
588
3.04M
{
589
3.04M
    m_aAbsURIRef.setLength(0);
590
3.04M
    m_eScheme = INetProtocol::NotValid;
591
3.04M
    m_aScheme.clear();
592
3.04M
    m_aUser.clear();
593
3.04M
    m_aAuth.clear();
594
3.04M
    m_aHost.clear();
595
3.04M
    m_aPort.clear();
596
3.04M
    m_aPath.clear();
597
3.04M
    m_aQuery.clear();
598
3.04M
    m_aFragment.clear();
599
3.04M
}
600
601
namespace {
602
603
std::unique_ptr<SvMemoryStream> memoryStream(
604
        void const * data, sal_Int32 length)
605
33.1k
{
606
33.1k
    std::unique_ptr<char[]> b(
607
33.1k
        new char[length]);
608
33.1k
    memcpy(b.get(), data, length);
609
33.1k
    std::unique_ptr<SvMemoryStream> s(
610
33.1k
        new SvMemoryStream(b.get(), length, StreamMode::READ));
611
33.1k
    s->ObjectOwnsMemory(true);
612
    // coverity[leaked_storage : FALSE] - belongs to SvMemoryStream s at this point
613
33.1k
    b.release();
614
33.1k
    return s;
615
33.1k
}
616
617
}
618
619
std::unique_ptr<SvMemoryStream> INetURLObject::getData() const
620
38.4k
{
621
38.4k
    if( GetProtocol() != INetProtocol::Data )
622
0
    {
623
0
        return nullptr;
624
0
    }
625
626
38.4k
    OUString sURLPath = GetURLPath( DecodeMechanism::WithCharset, RTL_TEXTENCODING_ISO_8859_1 );
627
38.4k
    sal_Unicode const * pSkippedMediatype = INetMIME::scanContentType( sURLPath );
628
38.4k
    sal_Int32 nCharactersSkipped = pSkippedMediatype == nullptr
629
38.4k
        ? 0 : pSkippedMediatype-sURLPath.getStr();
630
38.4k
    if (sURLPath.match(",", nCharactersSkipped))
631
29.9k
    {
632
29.9k
        nCharactersSkipped += strlen(",");
633
29.9k
        OString sURLEncodedData(
634
29.9k
            sURLPath.getStr() + nCharactersSkipped,
635
29.9k
            sURLPath.getLength() - nCharactersSkipped,
636
29.9k
            RTL_TEXTENCODING_ISO_8859_1, OUSTRING_TO_OSTRING_CVTFLAGS);
637
29.9k
        return memoryStream(
638
29.9k
            sURLEncodedData.getStr(), sURLEncodedData.getLength());
639
29.9k
    }
640
8.49k
    else if (sURLPath.matchIgnoreAsciiCase(";base64,", nCharactersSkipped))
641
3.93k
    {
642
3.93k
        nCharactersSkipped += strlen(";base64,");
643
3.93k
        std::u16string_view sBase64Data = sURLPath.subView( nCharactersSkipped );
644
3.93k
        css::uno::Sequence< sal_Int8 > aDecodedData;
645
3.93k
        if (comphelper::Base64::decodeSomeChars(aDecodedData, sBase64Data)
646
3.93k
            == sBase64Data.size())
647
3.20k
        {
648
3.20k
            return memoryStream(
649
3.20k
                aDecodedData.getArray(), aDecodedData.getLength());
650
3.20k
        }
651
3.93k
    }
652
5.29k
    return nullptr;
653
38.4k
}
654
655
namespace {
656
657
FSysStyle guessFSysStyleByCounting(sal_Unicode const * pBegin,
658
                                                  sal_Unicode const * pEnd,
659
                                                  FSysStyle eStyle)
660
297k
{
661
297k
    DBG_ASSERT(eStyle
662
297k
                   & (FSysStyle::Unix
663
297k
                          | FSysStyle::Dos),
664
297k
               "guessFSysStyleByCounting(): Bad style");
665
297k
    DBG_ASSERT(std::numeric_limits< sal_Int32 >::min() < pBegin - pEnd
666
297k
               && pEnd - pBegin <= std::numeric_limits< sal_Int32 >::max(),
667
297k
               "guessFSysStyleByCounting(): Too big");
668
297k
    sal_Int32 nSlashCount
669
297k
        = (eStyle & FSysStyle::Unix) ?
670
297k
              0 : std::numeric_limits< sal_Int32 >::min();
671
297k
    sal_Int32 nBackslashCount
672
297k
        = (eStyle & FSysStyle::Dos) ?
673
297k
              0 : std::numeric_limits< sal_Int32 >::min();
674
2.33M
    while (pBegin != pEnd)
675
2.03M
        switch (*pBegin++)
676
2.03M
        {
677
158k
            case '/':
678
158k
                ++nSlashCount;
679
158k
                break;
680
681
92.6k
            case '\\':
682
92.6k
                ++nBackslashCount;
683
92.6k
                break;
684
2.03M
        }
685
297k
    return nSlashCount >= nBackslashCount ?
686
261k
                   FSysStyle::Unix : FSysStyle::Dos;
687
297k
}
688
689
OUString parseScheme(
690
    sal_Unicode const ** begin, sal_Unicode const * end,
691
    sal_uInt32 fragmentDelimiter)
692
1.19M
{
693
1.19M
    sal_Unicode const * p = *begin;
694
1.19M
    if (p != end && rtl::isAsciiAlpha(*p)) {
695
1.17M
        do {
696
1.17M
            ++p;
697
1.17M
        } while (p != end
698
1.09M
                 && (rtl::isAsciiAlphanumeric(*p) || *p == '+' || *p == '-'
699
306k
                     || *p == '.'));
700
        // #i34835# To avoid problems with Windows file paths like "C:\foo",
701
        // do not accept generic schemes that are only one character long:
702
292k
        if (end - p > 1 && p[0] == ':' && p[1] != fragmentDelimiter
703
21.0k
            && p - *begin >= 2)
704
16.7k
        {
705
16.7k
            OUString scheme(
706
16.7k
                OUString(*begin, p - *begin).toAsciiLowerCase());
707
16.7k
            *begin = p + 1;
708
16.7k
            return scheme;
709
16.7k
        }
710
292k
    }
711
1.17M
    return OUString();
712
1.19M
}
713
714
}
715
716
bool INetURLObject::setAbsURIRef(std::u16string_view rTheAbsURIRef,
717
                                 EncodeMechanism eMechanism,
718
                                 rtl_TextEncoding eCharset,
719
                                 bool bSmart,
720
                                 FSysStyle eStyle)
721
2.34M
{
722
2.34M
    sal_Unicode const * pPos = rTheAbsURIRef.data();
723
2.34M
    sal_Unicode const * pEnd = pPos + rTheAbsURIRef.size();
724
725
2.34M
    setInvalid();
726
727
2.34M
    sal_uInt32 nFragmentDelimiter = '#';
728
729
2.34M
    m_aAbsURIRef.setLength(0);
730
731
    // Parse <scheme>:
732
2.34M
    sal_Unicode const * p = pPos;
733
2.34M
    PrefixInfo const * pPrefix = getPrefix(p, pEnd);
734
2.34M
    if (pPrefix)
735
1.51M
    {
736
1.51M
        pPos = p;
737
1.51M
        m_eScheme = pPrefix->m_eScheme;
738
739
1.51M
        const OUString & rTemp = pPrefix->m_eKind >= PrefixInfo::Kind::External ?
740
0
                                             pPrefix->m_aTranslatedPrefix :
741
1.51M
                                             pPrefix->m_aPrefix;
742
1.51M
        m_aAbsURIRef.append(rTemp);
743
1.51M
        m_aScheme = SubString( 0, rTemp.indexOf(':') );
744
1.51M
    }
745
838k
    else
746
838k
    {
747
838k
        if (bSmart)
748
211k
        {
749
            // For scheme detection, the first (if any) of the following
750
            // productions that matches the input string (and for which the
751
            // appropriate style bit is set in eStyle, if applicable)
752
            // determines the scheme. The productions use the auxiliary rules
753
754
            //    domain = label *("." label)
755
            //    label = alphanum [*(alphanum / "-") alphanum]
756
            //    alphanum = ALPHA / DIGIT
757
            //    IPv6reference = "[" IPv6address "]"
758
            //    IPv6address = hexpart [":" IPv4address]
759
            //    IPv4address = 1*3DIGIT 3("." 1*3DIGIT)
760
            //    hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
761
            //    hexseq = hex4 *(":" hex4)
762
            //    hex4 = 1*4HEXDIG
763
            //    UCS4 = <any UCS4 character>
764
765
            // 1st Production (known scheme; handled by the "if (pPrefix)" branch above):
766
            //    <one of the known schemes, ignoring case> ":" *UCS4
767
            // 2nd Production (mailto):
768
            //    domain "@" domain
769
            // 3rd Production (ftp):
770
            //    "FTP" 2*("." label) ["/" *UCS4]
771
            // 4th Production (http):
772
            //    label 2*("." label) ["/" *UCS4]
773
            // 5th Production (file):
774
            //    "//" (domain / IPv6reference) ["/" *UCS4]
775
            // 6th Production (Unix file):
776
            //    "/" *UCS4
777
            // 7th Production (UNC file; FSysStyle::Dos only):
778
            //    "\\" domain ["\" *UCS4]
779
            // 8th Production (Unix-like DOS file; FSysStyle::Dos only):
780
            //    ALPHA ":" ["/" *UCS4]
781
            // 9th Production (DOS file; FSysStyle::Dos only):
782
            //    ALPHA ":" ["\" *UCS4]
783
            // 10th Production (any scheme; handled by the "m_eScheme = INetProtocol::Generic;" code
784
            // after this else branch):
785
            //    <any scheme> ":" *UCS4
786
787
            // For the 'non URL' file productions 6--9, the interpretation of
788
            // the input as a (degenerate) URI is turned off, i.e., escape
789
            // sequences and fragments are never detected as such, but are
790
            // taken as literal characters.
791
792
211k
            sal_Unicode const * p1 = pPos;
793
211k
            if (eStyle & FSysStyle::Dos
794
211k
                && pEnd - p1 >= 2
795
194k
                && rtl::isAsciiAlpha(p1[0])
796
120k
                && p1[1] == ':'
797
3.01k
                && (pEnd - p1 == 2 || p1[2] == '/' || p1[2] == '\\'))
798
2.74k
            {
799
2.74k
                m_eScheme = INetProtocol::File; // 8th, 9th
800
2.74k
                eMechanism = EncodeMechanism::All;
801
2.74k
                nFragmentDelimiter = 0x80000000;
802
2.74k
            }
803
208k
            else if (eStyle & FSysStyle::Dos
804
208k
                && pEnd - p1 >= 6
805
183k
                && p1[0] == '\\' && p1[1] == '\\' && p1[2] == '?' && p1[3] == '\\'
806
7.39k
                && rtl::isAsciiAlpha(p1[4])
807
6.66k
                && p1[5] == ':'
808
1.79k
                && (pEnd - p1 == 6 || p1[6] == '/' || p1[6] == '\\'))
809
1.45k
            {
810
1.45k
                m_eScheme = INetProtocol::File; // 8th, 9th
811
1.45k
                eMechanism = EncodeMechanism::All;
812
1.45k
                nFragmentDelimiter = 0x80000000;
813
1.45k
            }
814
207k
            else if (pEnd - p1 >= 2 && p1[0] == '/' && p1[1] == '/')
815
8.02k
            {
816
8.02k
                p1 += 2;
817
8.02k
                if ((scanDomain(p1, pEnd) > 0 || scanIPv6reference(p1, pEnd))
818
3.36k
                    && (p1 == pEnd || *p1 == '/'))
819
1.92k
                    m_eScheme = INetProtocol::File; // 5th
820
8.02k
            }
821
199k
            else if (p1 != pEnd && *p1 == '/')
822
20.2k
            {
823
20.2k
                m_eScheme = INetProtocol::File; // 6th
824
20.2k
                eMechanism = EncodeMechanism::All;
825
20.2k
                nFragmentDelimiter = 0x80000000;
826
20.2k
            }
827
178k
            else if (eStyle & FSysStyle::Dos
828
178k
                     && pEnd - p1 >= 2
829
163k
                     && p1[0] == '\\'
830
28.6k
                     && p1[1] == '\\')
831
28.2k
            {
832
28.2k
                p1 += 2;
833
28.2k
                if (pEnd - p1 >= 6 && p1[0] == '?' && p1[1] == '\\' && p1[5] == '\\'
834
3.98k
                    && rtl::toAsciiLowerCase(p1[2]) == 'u'
835
3.02k
                    && rtl::toAsciiLowerCase(p1[3]) == 'n'
836
2.51k
                    && rtl::toAsciiLowerCase(p1[4]) == 'c')
837
1.95k
                {
838
1.95k
                    p1 += 6; // "\\?\UNC\Servername\..."
839
1.95k
                }
840
841
28.2k
                sal_Int32 n = rtl_ustr_indexOfChar_WithLength(
842
28.2k
                    p1, pEnd - p1, '\\');
843
28.2k
                sal_Unicode const * pe = n == -1 ? pEnd : p1 + n;
844
28.2k
                if (
845
28.2k
                    parseHostOrNetBiosName(
846
28.2k
                        p1, pe, EncodeMechanism::All, RTL_TEXTENCODING_DONTKNOW,
847
28.2k
                        true, nullptr) ||
848
8.85k
                    (scanDomain(p1, pe) > 0 && p1 == pe)
849
28.2k
                   )
850
19.4k
                {
851
19.4k
                    m_eScheme = INetProtocol::File; // 7th
852
19.4k
                    eMechanism = EncodeMechanism::All;
853
19.4k
                    nFragmentDelimiter = 0x80000000;
854
19.4k
                }
855
28.2k
            }
856
150k
            else
857
150k
            {
858
150k
                sal_Unicode const * pDomainEnd = p1;
859
150k
                sal_uInt32 nLabels = scanDomain(pDomainEnd, pEnd);
860
150k
                if (nLabels > 0 && pDomainEnd != pEnd && *pDomainEnd == '@')
861
1.15k
                {
862
1.15k
                    ++pDomainEnd;
863
1.15k
                    if (scanDomain(pDomainEnd, pEnd) > 0
864
827
                        && pDomainEnd == pEnd)
865
452
                        m_eScheme = INetProtocol::Mailto; // 2nd
866
1.15k
                }
867
149k
                else if (nLabels >= 3
868
1.79k
                         && (pDomainEnd == pEnd || *pDomainEnd == '/'))
869
1.16k
                    m_eScheme
870
1.16k
                        = pDomainEnd - p1 >= 4
871
1.16k
                          && (p1[0] == 'f' || p1[0] == 'F')
872
569
                          && (p1[1] == 't' || p1[1] == 'T')
873
164
                          && (p1[2] == 'p' || p1[2] == 'P')
874
80
                          && p1[3] == '.' ?
875
1.16k
                              INetProtocol::Ftp : INetProtocol::Http; // 3rd, 4th
876
150k
            }
877
211k
        }
878
879
838k
        OUString aSynScheme;
880
838k
        if (m_eScheme == INetProtocol::NotValid) {
881
790k
            sal_Unicode const * p1 = pPos;
882
790k
            aSynScheme = parseScheme(&p1, pEnd, nFragmentDelimiter);
883
790k
            if (!aSynScheme.isEmpty())
884
13.7k
            {
885
13.7k
                if (bSmart && m_eSmartScheme != m_eScheme && p1 != pEnd && rtl::isAsciiDigit(*p1))
886
2.79k
                {
887
                    // rTheAbsURIRef doesn't define a known scheme (handled by the "if (pPrefix)"
888
                    // branch above); but a known scheme is defined in m_eSmartScheme. If this
889
                    // scheme may have a port in authority component, then avoid misinterpreting
890
                    // URLs like www.foo.bar:123/baz as using unknown "www.foo.bar" scheme with
891
                    // 123/baz rootless path. For now, do not try to handle possible colons in
892
                    // user information, require such ambiguous URLs to have explicit scheme part.
893
                    // Also ignore possibility of empty port.
894
2.79k
                    const SchemeInfo& rInfo = getSchemeInfo(m_eSmartScheme);
895
2.79k
                    if (rInfo.m_bAuthority && rInfo.m_bPort)
896
2.79k
                    {
897
                        // Make sure that all characters from colon to [/?#] or to EOL are digits.
898
                        // Or maybe make it simple, and just assume that "xyz:1..." is more likely
899
                        // to be host "xyz" and port "1...", than scheme "xyz" and path "1..."?
900
2.79k
                        sal_Unicode const* p2 = p1 + 1;
901
8.01k
                        while (p2 != pEnd && rtl::isAsciiDigit(*p2))
902
5.22k
                            ++p2;
903
2.79k
                        if (p2 == pEnd || *p2 == '/' || *p2 == '?' || *p2 == '#')
904
856
                            m_eScheme = m_eSmartScheme;
905
2.79k
                    }
906
2.79k
                }
907
908
13.7k
                if (m_eScheme == INetProtocol::NotValid)
909
12.8k
                {
910
12.8k
                    m_eScheme = INetProtocol::Generic;
911
12.8k
                    pPos = p1;
912
12.8k
                }
913
13.7k
            }
914
790k
        }
915
916
838k
        if (bSmart && m_eScheme == INetProtocol::NotValid && pPos != pEnd
917
159k
            && *pPos != nFragmentDelimiter)
918
159k
        {
919
159k
            m_eScheme = m_eSmartScheme;
920
159k
        }
921
922
838k
        if (m_eScheme == INetProtocol::NotValid)
923
617k
        {
924
617k
            setInvalid();
925
617k
            return false;
926
617k
        }
927
928
220k
        if (m_eScheme != INetProtocol::Generic) {
929
208k
            aSynScheme = getSchemeInfo().m_sScheme;
930
208k
        }
931
220k
        m_aScheme.set(m_aAbsURIRef, aSynScheme, m_aAbsURIRef.getLength());
932
220k
        m_aAbsURIRef.append(':');
933
220k
    }
934
935
1.73M
    sal_uInt32 nSegmentDelimiter = '/';
936
1.73M
    sal_uInt32 nAltSegmentDelimiter = 0x80000000;
937
1.73M
    bool bSkippedInitialSlash = false;
938
939
    // Parse //<user>;AUTH=<auth>@<host>:<port> or
940
    // //<user>:<password>@<host>:<port> or
941
    // //<reg_name>
942
1.73M
    if (getSchemeInfo().m_bAuthority)
943
1.56M
    {
944
1.56M
        sal_Unicode const * pUserInfoBegin = nullptr;
945
1.56M
        sal_Unicode const * pUserInfoEnd = nullptr;
946
1.56M
        sal_Unicode const * pHostPortBegin = nullptr;
947
1.56M
        sal_Unicode const * pHostPortEnd = nullptr;
948
949
1.56M
        switch (m_eScheme)
950
1.56M
        {
951
0
            case INetProtocol::VndSunStarHelp:
952
0
            {
953
0
                if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/')
954
0
                {
955
0
                    setInvalid();
956
0
                    return false;
957
0
                }
958
0
                m_aAbsURIRef.append("//");
959
0
                OUStringBuffer aSynAuthority;
960
0
                while (pPos < pEnd
961
0
                       && *pPos != '/' && *pPos != '?'
962
0
                       && *pPos != nFragmentDelimiter)
963
0
                {
964
0
                    EscapeType eEscapeType;
965
0
                    sal_uInt32 nUTF32 = getUTF32(pPos, pEnd,
966
0
                                                 eMechanism,
967
0
                                                 eCharset, eEscapeType);
968
0
                    appendUCS4(aSynAuthority, nUTF32, eEscapeType,
969
0
                               PART_AUTHORITY, eCharset, false);
970
0
                }
971
0
                m_aHost.set(m_aAbsURIRef,
972
0
                            aSynAuthority,
973
0
                            m_aAbsURIRef.getLength());
974
                    // misusing m_aHost to store the authority
975
0
                break;
976
0
            }
977
978
0
            case INetProtocol::VndSunStarHier:
979
0
            {
980
0
                if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
981
0
                {
982
0
                    pPos += 2;
983
0
                    m_aAbsURIRef.append("//");
984
0
                    OUStringBuffer aSynAuthority;
985
0
                    while (pPos < pEnd
986
0
                           && *pPos != '/' && *pPos != '?'
987
0
                           && *pPos != nFragmentDelimiter)
988
0
                    {
989
0
                        EscapeType eEscapeType;
990
0
                        sal_uInt32 nUTF32 = getUTF32(pPos,
991
0
                                                     pEnd,
992
0
                                                     eMechanism,
993
0
                                                     eCharset,
994
0
                                                     eEscapeType);
995
0
                        appendUCS4(aSynAuthority,
996
0
                                   nUTF32,
997
0
                                   eEscapeType,
998
0
                                   PART_AUTHORITY,
999
0
                                   eCharset,
1000
0
                                   false);
1001
0
                    }
1002
0
                    if (aSynAuthority.isEmpty())
1003
0
                    {
1004
0
                        setInvalid();
1005
0
                        return false;
1006
0
                    }
1007
0
                    m_aHost.set(m_aAbsURIRef,
1008
0
                                aSynAuthority,
1009
0
                                m_aAbsURIRef.getLength());
1010
                        // misusing m_aHost to store the authority
1011
0
                }
1012
0
                break;
1013
0
            }
1014
1015
45
            case INetProtocol::VndSunStarPkg:
1016
45
            case INetProtocol::Cmis:
1017
45
            {
1018
45
                if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/')
1019
0
                {
1020
0
                    setInvalid();
1021
0
                    return false;
1022
0
                }
1023
45
                m_aAbsURIRef.append("//");
1024
45
                OUStringBuffer aSynUser(128);
1025
1026
45
                bool bHasUser = false;
1027
1.26k
                while (pPos < pEnd && *pPos != '@'
1028
1.21k
                       && *pPos != '/' && *pPos != '?'
1029
1.21k
                       && *pPos != nFragmentDelimiter)
1030
1.21k
                {
1031
1.21k
                    EscapeType eEscapeType;
1032
1.21k
                    sal_uInt32 nUTF32 = getUTF32(pPos, pEnd,
1033
1.21k
                                                 eMechanism,
1034
1.21k
                                                 eCharset, eEscapeType);
1035
1.21k
                    appendUCS4(aSynUser, nUTF32, eEscapeType,
1036
1.21k
                               PART_USER_PASSWORD, eCharset, false);
1037
1038
1.21k
                    bHasUser = *pPos == '@';
1039
1.21k
                }
1040
1041
45
                OUStringBuffer aSynAuthority(64);
1042
45
                if ( !bHasUser )
1043
45
                {
1044
45
                    aSynAuthority = std::move(aSynUser);
1045
45
                }
1046
0
                else
1047
0
                {
1048
0
                    m_aUser.set(m_aAbsURIRef,
1049
0
                            aSynUser,
1050
0
                            m_aAbsURIRef.getLength());
1051
0
                    m_aAbsURIRef.append("@");
1052
0
                    ++pPos;
1053
1054
0
                    while (pPos < pEnd
1055
0
                           && *pPos != '/' && *pPos != '?'
1056
0
                           && *pPos != nFragmentDelimiter)
1057
0
                    {
1058
0
                        EscapeType eEscapeType;
1059
0
                        sal_uInt32 nUTF32 = getUTF32(pPos, pEnd,
1060
0
                                                     eMechanism,
1061
0
                                                     eCharset, eEscapeType);
1062
0
                        appendUCS4(aSynAuthority, nUTF32, eEscapeType,
1063
0
                                   PART_AUTHORITY, eCharset, false);
1064
0
                    }
1065
0
                }
1066
45
                if (aSynAuthority.isEmpty())
1067
0
                {
1068
0
                    setInvalid();
1069
0
                    return false;
1070
0
                }
1071
45
                m_aHost.set(m_aAbsURIRef,
1072
45
                            aSynAuthority,
1073
45
                            m_aAbsURIRef.getLength());
1074
                    // misusing m_aHost to store the authority
1075
45
                break;
1076
45
            }
1077
1078
1.11M
            case INetProtocol::File:
1079
1.11M
                if (bSmart)
1080
557k
                {
1081
                    // The first of the following seven productions that
1082
                    // matches the rest of the input string (and for which the
1083
                    // appropriate style bit is set in eStyle, if applicable)
1084
                    // determines the used notation.  The productions use the
1085
                    // auxiliary rules
1086
1087
                    //    domain = label *("." label)
1088
                    //    label = alphanum [*(alphanum / "-") alphanum]
1089
                    //    alphanum = ALPHA / DIGIT
1090
                    //    IPv6reference = "[" IPv6address "]"
1091
                    //    IPv6address = hexpart [":" IPv4address]
1092
                    //    IPv4address = 1*3DIGIT 3("." 1*3DIGIT)
1093
                    //    hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
1094
                    //    hexseq = hex4 *(":" hex4)
1095
                    //    hex4 = 1*4HEXDIG
1096
                    //    path = <any UCS4 character except "#">
1097
                    //    UCS4 = <any UCS4 character>
1098
1099
                    // 1st Production (URL):
1100
                    //    "//" [domain / IPv6reference] ["/" *path]
1101
                    //        ["#" *UCS4]
1102
                    //  becomes
1103
                    //    "file://" domain "/" *path ["#" *UCS4]
1104
557k
                    if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
1105
505k
                    {
1106
505k
                        sal_Unicode const * p1 = pPos + 2;
1107
589k
                        while (p1 != pEnd && *p1 != '/' &&
1108
83.4k
                               *p1 != nFragmentDelimiter)
1109
83.4k
                        {
1110
83.4k
                            ++p1;
1111
83.4k
                        }
1112
505k
                        if (parseHostOrNetBiosName(
1113
505k
                                pPos + 2, p1, EncodeMechanism::All,
1114
505k
                                RTL_TEXTENCODING_DONTKNOW, true, nullptr))
1115
502k
                        {
1116
502k
                            m_aAbsURIRef.append("//");
1117
502k
                            pHostPortBegin = pPos + 2;
1118
502k
                            pHostPortEnd = p1;
1119
502k
                            pPos = p1;
1120
502k
                            break;
1121
502k
                        }
1122
505k
                    }
1123
1124
                    // 2nd Production (MS IE generated 1; FSysStyle::Dos only):
1125
                    //    "//" ALPHA ":" ["/" *path] ["#" *UCS4]
1126
                    //  becomes
1127
                    //    "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
1128
                    //  replacing "\" by "/" within <*path>
1129
                    // 3rd Production (MS IE generated 2; FSysStyle::Dos only):
1130
                    //    "//" ALPHA ":" ["\" *path] ["#" *UCS4]
1131
                    //  becomes
1132
                    //    "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
1133
                    //  replacing "\" by "/" within <*path>
1134
                    // 4th Production (miscounted slashes):
1135
                    //    "//" *path ["#" *UCS4]
1136
                    //  becomes
1137
                    //    "file:///" *path ["#" *UCS4]
1138
55.4k
                    if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
1139
3.71k
                    {
1140
3.71k
                        m_aAbsURIRef.append("//");
1141
3.71k
                        pPos += 2;
1142
3.71k
                        bSkippedInitialSlash = true;
1143
3.71k
                        if ((eStyle & FSysStyle::Dos)
1144
3.71k
                            && pEnd - pPos >= 2
1145
3.67k
                            && rtl::isAsciiAlpha(pPos[0])
1146
1.05k
                            && pPos[1] == ':'
1147
883
                            && (pEnd - pPos == 2
1148
757
                                || pPos[2] == '/' || pPos[2] == '\\'))
1149
158
                            nAltSegmentDelimiter = '\\';
1150
3.71k
                        break;
1151
3.71k
                    }
1152
1153
                    // 5th Production (Unix):
1154
                    //    "/" *path ["#" *UCS4]
1155
                    //  becomes
1156
                    //    "file:///" *path ["#" *UCS4]
1157
51.7k
                    if (pPos < pEnd && *pPos == '/')
1158
20.3k
                    {
1159
20.3k
                        m_aAbsURIRef.append("//");
1160
20.3k
                        break;
1161
20.3k
                    }
1162
1163
                    // 6th Production (UNC; FSysStyle::Dos only):
1164
                    //    "\\" domain ["\" *path] ["#" *UCS4]
1165
                    //  becomes
1166
                    //    "file://" domain "/" *path ["#" *UCS4]
1167
                    //  replacing "\" by "/" within <*path>
1168
31.4k
                    if (eStyle & FSysStyle::Dos
1169
31.4k
                        && pEnd - pPos >= 2
1170
29.8k
                        && pPos[0] == '\\'
1171
23.4k
                        && pPos[1] == '\\')
1172
23.2k
                    {
1173
23.2k
                        sal_Unicode const * p1 = pPos + 2;
1174
23.2k
                        sal_Unicode const * pHostPortTentativeBegin = p1;
1175
23.2k
                        if (pEnd - p1 >= 6 && p1[0] == '?' && p1[1] == '\\' && p1[5] == '\\'
1176
1.05k
                            && rtl::toAsciiLowerCase(p1[2]) == 'u'
1177
794
                            && rtl::toAsciiLowerCase(p1[3]) == 'n'
1178
426
                            && rtl::toAsciiLowerCase(p1[4]) == 'c')
1179
323
                        {
1180
323
                            p1 += 6; // "\\?\UNC\Servername\..."
1181
323
                            pHostPortTentativeBegin = p1;
1182
323
                        }
1183
1184
23.2k
                        sal_Unicode const * pe = p1;
1185
251k
                        while (pe < pEnd && *pe != '\\' &&
1186
229k
                               *pe != nFragmentDelimiter)
1187
228k
                        {
1188
228k
                            ++pe;
1189
228k
                        }
1190
23.2k
                        if (
1191
23.2k
                             parseHostOrNetBiosName(
1192
23.2k
                                p1, pe, EncodeMechanism::All,
1193
23.2k
                                RTL_TEXTENCODING_DONTKNOW, true, nullptr) ||
1194
3.45k
                             (scanDomain(p1, pe) > 0 && p1 == pe)
1195
23.2k
                           )
1196
19.8k
                        {
1197
19.8k
                            m_aAbsURIRef.append("//");
1198
19.8k
                            pHostPortBegin = pHostPortTentativeBegin;
1199
19.8k
                            pHostPortEnd = pe;
1200
19.8k
                            pPos = pe;
1201
19.8k
                            nSegmentDelimiter = '\\';
1202
19.8k
                            break;
1203
19.8k
                        }
1204
23.2k
                    }
1205
1206
                    // 7th Production (Unix-like DOS; FSysStyle::Dos only):
1207
                    //    ALPHA ":" ["/" *path] ["#" *UCS4]
1208
                    //  becomes
1209
                    //    "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
1210
                    //  replacing "\" by "/" within <*path>
1211
                    // 8th Production (DOS; FSysStyle::Dos only):
1212
                    //    ALPHA ":" ["\" *path] ["#" *UCS4]
1213
                    //  becomes
1214
                    //    "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
1215
                    //  replacing "\" by "/" within <*path>
1216
11.6k
                    if (eStyle & FSysStyle::Dos)
1217
11.6k
                    {
1218
11.6k
                        sal_Unicode const* p1 = pPos;
1219
11.6k
                        if (pEnd - p1 >= 4 && p1[0] == '\\' && p1[1] == '\\' && p1[2] == '?'
1220
1.72k
                            && p1[3] == '\\')
1221
1.60k
                            p1 += 4; // "\\?\c:\..."
1222
1223
11.6k
                        if (pEnd - p1 >= 2
1224
10.0k
                            && rtl::isAsciiAlpha(p1[0])
1225
7.11k
                            && p1[1] == ':'
1226
4.35k
                            && (pEnd - p1 == 2
1227
3.47k
                                || p1[2] == '/'
1228
1.84k
                                || p1[2] == '\\'))
1229
4.19k
                        {
1230
4.19k
                            pPos = p1;
1231
4.19k
                            m_aAbsURIRef.append("//");
1232
4.19k
                            nAltSegmentDelimiter = '\\';
1233
4.19k
                            bSkippedInitialSlash = true;
1234
4.19k
                            break;
1235
4.19k
                        }
1236
11.6k
                    }
1237
1238
                    // 9th Production (any):
1239
                    //    *path ["#" *UCS4]
1240
                    //  becomes
1241
                    //    "file:///" *path ["#" *UCS4]
1242
                    //  replacing the delimiter by "/" within <*path>.  The
1243
                    //  delimiter is that character from the set { "/", "\"}
1244
                    // which appears most often in <*path> (if FSysStyle::Unix
1245
                    //  is not among the style bits, "/" is removed from the
1246
                    //  set; if FSysStyle::Dos is not among the style bits, "\" is
1247
                    //  removed from the set).  If two or
1248
                    //  more characters appear the same number of times, the
1249
                    //  character mentioned first in that set is chosen.  If
1250
                    //  the first character of <*path> is the delimiter, that
1251
                    //  character is not copied
1252
7.43k
                    if (eStyle & (FSysStyle::Unix | FSysStyle::Dos))
1253
7.43k
                    {
1254
7.43k
                        m_aAbsURIRef.append("//");
1255
7.43k
                        switch (guessFSysStyleByCounting(pPos, pEnd, eStyle))
1256
7.43k
                        {
1257
5.22k
                            case FSysStyle::Unix:
1258
5.22k
                                nSegmentDelimiter = '/';
1259
5.22k
                                break;
1260
1261
2.20k
                            case FSysStyle::Dos:
1262
2.20k
                                nSegmentDelimiter = '\\';
1263
2.20k
                                break;
1264
1265
0
                            default:
1266
0
                                OSL_FAIL(
1267
0
                                    "INetURLObject::setAbsURIRef():"
1268
0
                                        " Bad guessFSysStyleByCounting");
1269
0
                                break;
1270
7.43k
                        }
1271
7.43k
                        bSkippedInitialSlash
1272
7.43k
                            = pPos != pEnd && *pPos != nSegmentDelimiter;
1273
7.43k
                        break;
1274
7.43k
                    }
1275
7.43k
                }
1276
562k
                [[fallthrough]];
1277
1.00M
            default:
1278
1.00M
            {
1279
                // For INetProtocol::File, allow an empty authority ("//") to be
1280
                // missing if the following path starts with an explicit "/"
1281
                // (Java is notorious in generating such file URLs, so be
1282
                // liberal here):
1283
1.00M
                if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
1284
839k
                    pPos += 2;
1285
166k
                else if (!bSmart
1286
17.8k
                         && !(m_eScheme == INetProtocol::File
1287
11.1k
                              && pPos != pEnd && *pPos == '/'))
1288
10.0k
                {
1289
10.0k
                    setInvalid();
1290
10.0k
                    return false;
1291
10.0k
                }
1292
996k
                m_aAbsURIRef.append("//");
1293
1294
996k
                sal_Unicode const * pAuthority = pPos;
1295
996k
                sal_uInt32 c = getSchemeInfo().m_bQuery ? '?' : 0x80000000;
1296
6.65M
                while (pPos < pEnd && *pPos != '/' && *pPos != c
1297
5.73M
                       && *pPos != nFragmentDelimiter)
1298
5.65M
                    ++pPos;
1299
996k
                if (getSchemeInfo().m_bUser)
1300
59.6k
                    if (getSchemeInfo().m_bHost)
1301
59.6k
                    {
1302
59.6k
                        sal_Unicode const * p1 = pAuthority;
1303
920k
                        while (p1 < pPos && *p1 != '@')
1304
861k
                            ++p1;
1305
59.6k
                        if (p1 == pPos)
1306
41.4k
                        {
1307
41.4k
                            pHostPortBegin = pAuthority;
1308
41.4k
                            pHostPortEnd = pPos;
1309
41.4k
                        }
1310
18.1k
                        else
1311
18.1k
                        {
1312
18.1k
                            pUserInfoBegin = pAuthority;
1313
18.1k
                            pUserInfoEnd = p1;
1314
18.1k
                            pHostPortBegin = p1 + 1;
1315
18.1k
                            pHostPortEnd = pPos;
1316
18.1k
                        }
1317
59.6k
                    }
1318
0
                    else
1319
0
                    {
1320
0
                        pUserInfoBegin = pAuthority;
1321
0
                        pUserInfoEnd = pPos;
1322
0
                    }
1323
936k
                else if (getSchemeInfo().m_bHost)
1324
936k
                {
1325
936k
                    pHostPortBegin = pAuthority;
1326
936k
                    pHostPortEnd = pPos;
1327
936k
                }
1328
0
                else if (pPos != pAuthority)
1329
0
                {
1330
0
                    setInvalid();
1331
0
                    return false;
1332
0
                }
1333
996k
                break;
1334
996k
            }
1335
1.56M
        }
1336
1337
1.55M
        if (pUserInfoBegin)
1338
18.1k
        {
1339
18.1k
            Part ePart = PART_USER_PASSWORD;
1340
18.1k
            bool bSupportsPassword = getSchemeInfo().m_bPassword;
1341
18.1k
            bool bSupportsAuth
1342
18.1k
                = !bSupportsPassword && getSchemeInfo().m_bAuth;
1343
18.1k
            bool bHasAuth = false;
1344
18.1k
            OUStringBuffer aSynUser;
1345
18.1k
            sal_Unicode const * p1 = pUserInfoBegin;
1346
168k
            while (p1 < pUserInfoEnd)
1347
167k
            {
1348
167k
                EscapeType eEscapeType;
1349
167k
                sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd,
1350
167k
                                             eMechanism, eCharset, eEscapeType);
1351
167k
                if (eEscapeType == EscapeType::NONE)
1352
164k
                {
1353
164k
                    if (nUTF32 == ':' && bSupportsPassword)
1354
16.7k
                    {
1355
16.7k
                        bHasAuth = true;
1356
16.7k
                        break;
1357
16.7k
                    }
1358
147k
                    else if (nUTF32 == ';' && bSupportsAuth
1359
0
                             && pUserInfoEnd - p1
1360
0
                                    > RTL_CONSTASCII_LENGTH("auth=")
1361
0
                             && INetMIME::equalIgnoreCase(
1362
0
                                    p1,
1363
0
                                    p1 + RTL_CONSTASCII_LENGTH("auth="),
1364
0
                                    "auth="))
1365
0
                    {
1366
0
                        p1 += RTL_CONSTASCII_LENGTH("auth=");
1367
0
                        bHasAuth = true;
1368
0
                        break;
1369
0
                    }
1370
164k
                }
1371
150k
                appendUCS4(aSynUser, nUTF32, eEscapeType, ePart,
1372
150k
                           eCharset, false);
1373
150k
            }
1374
18.1k
            m_aUser.set(m_aAbsURIRef, aSynUser, m_aAbsURIRef.getLength());
1375
18.1k
            if (bHasAuth)
1376
16.7k
            {
1377
16.7k
                if (bSupportsPassword)
1378
16.7k
                {
1379
16.7k
                    m_aAbsURIRef.append(':');
1380
16.7k
                    OUStringBuffer aSynAuth;
1381
296k
                    while (p1 < pUserInfoEnd)
1382
280k
                    {
1383
280k
                        EscapeType eEscapeType;
1384
280k
                        sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd,
1385
280k
                                                     eMechanism, eCharset,
1386
280k
                                                     eEscapeType);
1387
280k
                        appendUCS4(aSynAuth, nUTF32, eEscapeType,
1388
280k
                                   ePart, eCharset, false);
1389
280k
                    }
1390
16.7k
                    m_aAuth.set(m_aAbsURIRef, aSynAuth, m_aAbsURIRef.getLength());
1391
16.7k
                }
1392
0
                else
1393
0
                {
1394
0
                    m_aAbsURIRef.append(";AUTH=");
1395
0
                    OUStringBuffer aSynAuth;
1396
0
                    while (p1 < pUserInfoEnd)
1397
0
                    {
1398
0
                        EscapeType eEscapeType;
1399
0
                        sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd,
1400
0
                                                     eMechanism, eCharset,
1401
0
                                                     eEscapeType);
1402
0
                        if (!INetMIME::isIMAPAtomChar(nUTF32))
1403
0
                        {
1404
0
                            setInvalid();
1405
0
                            return false;
1406
0
                        }
1407
0
                        appendUCS4(aSynAuth, nUTF32, eEscapeType,
1408
0
                                   ePart, eCharset, false);
1409
0
                    }
1410
0
                    m_aAuth.set(m_aAbsURIRef, aSynAuth, m_aAbsURIRef.getLength());
1411
0
                }
1412
16.7k
            }
1413
18.1k
            if (pHostPortBegin)
1414
18.1k
                m_aAbsURIRef.append('@');
1415
18.1k
        }
1416
1417
1.55M
        if (pHostPortBegin)
1418
1.51M
        {
1419
1.51M
            sal_Unicode const * pPort = pHostPortEnd;
1420
1.51M
            if ( getSchemeInfo().m_bPort && pHostPortBegin < pHostPortEnd )
1421
435k
            {
1422
435k
                sal_Unicode const * p1 = pHostPortEnd - 1;
1423
644k
                while (p1 > pHostPortBegin && rtl::isAsciiDigit(*p1))
1424
209k
                    --p1;
1425
435k
                if (*p1 == ':')
1426
8.16k
                    pPort = p1;
1427
435k
            }
1428
1.51M
            bool bNetBiosName = false;
1429
1.51M
            switch (m_eScheme)
1430
1.51M
            {
1431
1.08M
                case INetProtocol::File:
1432
                    // If the host equals "LOCALHOST" (unencoded and ignoring
1433
                    // case), turn it into an empty host:
1434
1.08M
                    if (INetMIME::equalIgnoreCase(pHostPortBegin, pPort,
1435
1.08M
                                                  "localhost"))
1436
0
                        pHostPortBegin = pPort;
1437
1.08M
                    bNetBiosName = true;
1438
1.08M
                    break;
1439
1440
300
                case INetProtocol::Ldap:
1441
2.99k
                case INetProtocol::Smb:
1442
2.99k
                    if (pHostPortBegin == pPort && pPort != pHostPortEnd)
1443
1.24k
                    {
1444
1.24k
                        setInvalid();
1445
1.24k
                        return false;
1446
1.24k
                    }
1447
1.75k
                    break;
1448
434k
                default:
1449
434k
                    if (pHostPortBegin == pPort)
1450
1.88k
                    {
1451
1.88k
                        setInvalid();
1452
1.88k
                        return false;
1453
1.88k
                    }
1454
432k
                    break;
1455
1.51M
            }
1456
1.51M
            sal_Int32 nLenBeforeHost = m_aAbsURIRef.getLength();
1457
1.51M
            if (!parseHostOrNetBiosName(
1458
1.51M
                    pHostPortBegin, pPort, eMechanism, eCharset,
1459
1.51M
                    bNetBiosName, &m_aAbsURIRef))
1460
60.1k
            {
1461
60.1k
                setInvalid();
1462
60.1k
                return false;
1463
60.1k
            }
1464
1.45M
            m_aHost = SubString(nLenBeforeHost, m_aAbsURIRef.getLength() - nLenBeforeHost);
1465
1.45M
            if (pPort != pHostPortEnd)
1466
6.02k
            {
1467
6.02k
                m_aAbsURIRef.append(':');
1468
6.02k
                m_aPort.set(m_aAbsURIRef,
1469
6.02k
                    std::u16string_view{pPort + 1, static_cast<size_t>(pHostPortEnd - (pPort + 1))},
1470
6.02k
                    m_aAbsURIRef.getLength());
1471
6.02k
            }
1472
1.45M
        }
1473
1.55M
    }
1474
1475
    // Parse <path>
1476
1.65M
    sal_Int32 nBeforePathLength = m_aAbsURIRef.getLength();
1477
1.65M
    if (!parsePath(m_eScheme, &pPos, pEnd, eMechanism, eCharset,
1478
1.65M
                   bSkippedInitialSlash, nSegmentDelimiter,
1479
1.65M
                   nAltSegmentDelimiter,
1480
1.65M
                   getSchemeInfo().m_bQuery ? '?' : 0x80000000,
1481
1.65M
                   nFragmentDelimiter, m_aAbsURIRef))
1482
591
    {
1483
591
        setInvalid();
1484
591
        return false;
1485
591
    }
1486
1.65M
    m_aPath = SubString(nBeforePathLength, m_aAbsURIRef.getLength() - nBeforePathLength);
1487
1488
    // Parse ?<query>
1489
1.65M
    if (getSchemeInfo().m_bQuery && pPos < pEnd && *pPos == '?')
1490
64.3k
    {
1491
64.3k
        m_aAbsURIRef.append('?');
1492
64.3k
        OUStringBuffer aSynQuery;
1493
3.70M
        for (++pPos; pPos < pEnd && *pPos != nFragmentDelimiter;)
1494
3.64M
        {
1495
3.64M
            EscapeType eEscapeType;
1496
3.64M
            sal_uInt32 nUTF32 = getUTF32(pPos, pEnd,
1497
3.64M
                                         eMechanism, eCharset, eEscapeType);
1498
3.64M
            appendUCS4(aSynQuery, nUTF32, eEscapeType,
1499
3.64M
                       PART_URIC, eCharset, true);
1500
3.64M
        }
1501
64.3k
        m_aQuery.set(m_aAbsURIRef, aSynQuery, m_aAbsURIRef.getLength());
1502
64.3k
    }
1503
1504
    // Parse #<fragment>
1505
1.65M
    if (pPos < pEnd && *pPos == nFragmentDelimiter)
1506
243k
    {
1507
243k
        m_aAbsURIRef.append(sal_Unicode(nFragmentDelimiter));
1508
243k
        OUStringBuffer aSynFragment;
1509
16.0M
        for (++pPos; pPos < pEnd;)
1510
15.8M
        {
1511
15.8M
            EscapeType eEscapeType;
1512
15.8M
            sal_uInt32 nUTF32 = getUTF32(pPos, pEnd,
1513
15.8M
                                         eMechanism, eCharset, eEscapeType);
1514
15.8M
            appendUCS4(aSynFragment, nUTF32, eEscapeType, PART_URIC,
1515
15.8M
                       eCharset, true);
1516
15.8M
        }
1517
243k
        m_aFragment.set(m_aAbsURIRef, aSynFragment, m_aAbsURIRef.getLength());
1518
243k
    }
1519
1520
1.65M
    if (pPos != pEnd)
1521
0
    {
1522
0
        setInvalid();
1523
0
        return false;
1524
0
    }
1525
1526
1.65M
    return true;
1527
1.65M
}
1528
1529
0
void INetURLObject::changeScheme(INetProtocol eTargetScheme) {
1530
0
    sal_Int32 oldSchemeLen = 0;
1531
0
    const OUString& rOldSchemeName = getSchemeInfo().m_sScheme;
1532
0
    if (m_eScheme == INetProtocol::Generic)
1533
0
        oldSchemeLen = m_aScheme.getLength();
1534
0
    else
1535
0
        oldSchemeLen = rOldSchemeName.getLength();
1536
0
    m_eScheme=eTargetScheme;
1537
0
    const OUString& rNewSchemeName = getSchemeInfo().m_sScheme;
1538
0
    sal_Int32 newSchemeLen = rNewSchemeName.getLength();
1539
0
    m_aAbsURIRef.remove(0, oldSchemeLen);
1540
0
    m_aAbsURIRef.insert(0, rNewSchemeName);
1541
0
    sal_Int32 delta=newSchemeLen-oldSchemeLen;
1542
0
    m_aUser+=delta;
1543
0
    m_aAuth+=delta;
1544
0
    m_aHost+=delta;
1545
0
    m_aPort+=delta;
1546
0
    m_aPath+=delta;
1547
0
    m_aQuery+=delta;
1548
0
    m_aFragment+=delta;
1549
0
}
1550
1551
bool INetURLObject::convertRelToAbs(OUString const & rTheRelURIRef,
1552
                                    INetURLObject & rTheAbsURIRef,
1553
                                    bool & rWasAbsolute,
1554
                                    EncodeMechanism eMechanism,
1555
                                    rtl_TextEncoding eCharset,
1556
                                    bool bIgnoreFragment, bool bSmart,
1557
                                    bool bRelativeNonURIs, FSysStyle eStyle)
1558
    const
1559
543k
{
1560
543k
    sal_Unicode const * p = rTheRelURIRef.getStr();
1561
543k
    sal_Unicode const * pEnd = p + rTheRelURIRef.getLength();
1562
1563
543k
    sal_Unicode const * pPrefixBegin = p;
1564
543k
    PrefixInfo const * pPrefix = getPrefix(pPrefixBegin, pEnd);
1565
543k
    bool hasScheme = pPrefix != nullptr;
1566
543k
    if (!hasScheme) {
1567
403k
        pPrefixBegin = p;
1568
403k
        hasScheme = !parseScheme(&pPrefixBegin, pEnd, '#').isEmpty();
1569
403k
    }
1570
1571
543k
    sal_uInt32 nSegmentDelimiter = '/';
1572
543k
    sal_uInt32 nQueryDelimiter
1573
543k
        = !bSmart || getSchemeInfo().m_bQuery ? '?' : 0x80000000;
1574
543k
    sal_uInt32 nFragmentDelimiter = '#';
1575
543k
    Part ePart = PART_VISIBLE;
1576
1577
543k
    if (!hasScheme && bSmart)
1578
313k
    {
1579
        // If the input matches any of the following productions (for which
1580
        // the appropriate style bit is set in eStyle), it is assumed to be an
1581
        // absolute file system path, rather than a relative URI reference.
1582
        // (This is only a subset of the productions used for scheme detection
1583
        // in INetURLObject::setAbsURIRef(), because most of those productions
1584
        // interfere with the syntax of relative URI references.)  The
1585
        // productions use the auxiliary rules
1586
1587
        //    domain = label *("." label)
1588
        //    label = alphanum [*(alphanum / "-") alphanum]
1589
        //    alphanum = ALPHA / DIGIT
1590
        //    UCS4 = <any UCS4 character>
1591
1592
        // 1st Production (UNC file; FSysStyle::Dos only):
1593
        //    "\\" domain ["\" *UCS4]
1594
        // 2nd Production (Unix-like DOS file; FSysStyle::Dos only):
1595
        //    ALPHA ":" ["/" *UCS4]
1596
        // 3rd Production (DOS file; FSysStyle::Dos only):
1597
        //    ALPHA ":" ["\" *UCS4]
1598
313k
        if (eStyle & FSysStyle::Dos)
1599
313k
        {
1600
313k
            bool bFSys = false;
1601
313k
            sal_Unicode const * q = p;
1602
313k
            if (pEnd - q >= 2
1603
213k
                && rtl::isAsciiAlpha(q[0])
1604
24.8k
                && q[1] == ':'
1605
4.05k
                && (pEnd - q == 2 || q[2] == '/' || q[2] == '\\'))
1606
2.09k
                bFSys = true; // 2nd, 3rd
1607
311k
            else if (pEnd - q >= 2 && q[0] == '\\' && q[1] == '\\')
1608
45.1k
            {
1609
45.1k
                q += 2;
1610
45.1k
                sal_Int32 n = rtl_ustr_indexOfChar_WithLength(
1611
45.1k
                    q, pEnd - q, '\\');
1612
45.1k
                if (n == 1 && q[0] == '?')
1613
9.21k
                {
1614
                    // "\\?\c:\..." or "\\?\UNC\servername\..."
1615
9.21k
                    q += 2;
1616
9.21k
                    if (pEnd - q >= 2
1617
8.38k
                        && rtl::isAsciiAlpha(q[0])
1618
6.53k
                        && q[1] == ':'
1619
1.79k
                        && (pEnd - q == 2 || q[2] == '/' || q[2] == '\\'))
1620
1.45k
                    {
1621
1.45k
                        bFSys = true; // 2nd, 3rd
1622
1.45k
                    }
1623
7.76k
                    else if (pEnd - q >= 4
1624
6.10k
                        && q[3] == '\\'
1625
4.02k
                        && rtl::toAsciiLowerCase(q[0]) == 'u'
1626
2.90k
                        && rtl::toAsciiLowerCase(q[1]) == 'n'
1627
2.38k
                        && rtl::toAsciiLowerCase(q[2]) == 'c')
1628
1.93k
                    {
1629
1.93k
                        q += 4; // Check if it's 1st below
1630
1.93k
                    }
1631
9.21k
                }
1632
45.1k
                if (!bFSys)
1633
43.7k
                {
1634
43.7k
                    sal_Unicode const * qe = n == -1 ? pEnd : q + n;
1635
43.7k
                    if (parseHostOrNetBiosName(
1636
43.7k
                            q, qe, EncodeMechanism::All, RTL_TEXTENCODING_DONTKNOW,
1637
43.7k
                            true, nullptr))
1638
24.5k
                    {
1639
24.5k
                        bFSys = true; // 1st
1640
24.5k
                    }
1641
43.7k
                }
1642
45.1k
            }
1643
313k
            if (bFSys)
1644
28.1k
            {
1645
28.1k
                INetURLObject aNewURI;
1646
28.1k
                aNewURI.setAbsURIRef(rTheRelURIRef, eMechanism,
1647
28.1k
                                     eCharset, true, eStyle);
1648
28.1k
                if (!aNewURI.HasError())
1649
22.0k
                {
1650
22.0k
                    rTheAbsURIRef = std::move(aNewURI);
1651
22.0k
                    rWasAbsolute = true;
1652
22.0k
                    return true;
1653
22.0k
                }
1654
28.1k
            }
1655
313k
        }
1656
1657
        // When the base URL is a file URL, accept relative file system paths
1658
        // using "\" or ":" as delimiter (and ignoring URI conventions for "%"
1659
        // and "#"), as well as relative URIs using "/" as delimiter:
1660
291k
        if (m_eScheme == INetProtocol::File)
1661
290k
            switch (guessFSysStyleByCounting(p, pEnd, eStyle))
1662
290k
            {
1663
255k
                case FSysStyle::Unix:
1664
255k
                    nSegmentDelimiter = '/';
1665
255k
                    break;
1666
1667
34.1k
                case FSysStyle::Dos:
1668
34.1k
                    nSegmentDelimiter = '\\';
1669
34.1k
                    bRelativeNonURIs = true;
1670
34.1k
                    break;
1671
1672
0
                default:
1673
0
                    OSL_FAIL("INetURLObject::convertRelToAbs():"
1674
0
                                  " Bad guessFSysStyleByCounting");
1675
0
                    break;
1676
290k
            }
1677
1678
291k
        if (bRelativeNonURIs)
1679
34.1k
        {
1680
34.1k
            eMechanism = EncodeMechanism::All;
1681
34.1k
            nQueryDelimiter = 0x80000000;
1682
34.1k
            nFragmentDelimiter = 0x80000000;
1683
34.1k
            ePart = PART_VISIBLE_NONSPECIAL;
1684
34.1k
        }
1685
291k
    }
1686
1687
    // If the relative URI has the same scheme as the base URI, and that
1688
    // scheme is hierarchical, then ignore its presence in the relative
1689
    // URI in order to be backward compatible (cf. RFC 2396 section 5.2
1690
    // step 3):
1691
521k
    if (pPrefix && pPrefix->m_eScheme == m_eScheme
1692
83.5k
        && getSchemeInfo().m_bHierarchical)
1693
83.5k
    {
1694
83.5k
        hasScheme = false;
1695
417k
        while (p != pEnd && *p++ != ':') ;
1696
83.5k
    }
1697
521k
    rWasAbsolute = hasScheme;
1698
1699
    // Fast solution for non-relative URIs:
1700
521k
    if (hasScheme)
1701
59.5k
    {
1702
59.5k
        INetURLObject aNewURI(rTheRelURIRef, eMechanism, eCharset);
1703
59.5k
        if (aNewURI.HasError())
1704
6.06k
        {
1705
6.06k
            rWasAbsolute = false;
1706
6.06k
            return false;
1707
6.06k
        }
1708
1709
53.4k
        if (bIgnoreFragment)
1710
0
            aNewURI.clearFragment();
1711
53.4k
        rTheAbsURIRef = std::move(aNewURI);
1712
53.4k
        return true;
1713
59.5k
    }
1714
1715
461k
    enum State { STATE_AUTH, STATE_ABS_PATH, STATE_REL_PATH, STATE_FRAGMENT,
1716
461k
                 STATE_DONE };
1717
1718
461k
    OUStringBuffer aSynAbsURIRef(128);
1719
    // make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme
1720
    // is empty ("") in that case, so take the scheme from m_aAbsURIRef
1721
461k
    if (m_eScheme != INetProtocol::Generic)
1722
460k
    {
1723
460k
        aSynAbsURIRef.append(getSchemeInfo().m_sScheme);
1724
460k
    }
1725
717
    else
1726
717
    {
1727
717
        sal_Unicode const * pSchemeBegin
1728
717
            = m_aAbsURIRef.getStr();
1729
717
        sal_Unicode const * pSchemeEnd = pSchemeBegin;
1730
4.13k
        while (pSchemeEnd[0] != ':')
1731
3.41k
        {
1732
3.41k
            ++pSchemeEnd;
1733
3.41k
        }
1734
717
        aSynAbsURIRef.append(pSchemeBegin, pSchemeEnd - pSchemeBegin);
1735
717
    }
1736
461k
    aSynAbsURIRef.append(':');
1737
1738
461k
    State eState = STATE_AUTH;
1739
461k
    bool bSameDoc = true;
1740
1741
461k
    if (getSchemeInfo().m_bAuthority)
1742
376k
    {
1743
376k
        if (pEnd - p >= 2 && p[0] == '/' && p[1] == '/')
1744
103k
        {
1745
103k
            aSynAbsURIRef.append("//");
1746
103k
            p += 2;
1747
103k
            eState = STATE_ABS_PATH;
1748
103k
            bSameDoc = false;
1749
352k
            while (p != pEnd)
1750
333k
            {
1751
333k
                EscapeType eEscapeType;
1752
333k
                sal_uInt32 nUTF32
1753
333k
                    = getUTF32(p, pEnd, eMechanism,
1754
333k
                               eCharset, eEscapeType);
1755
333k
                if (eEscapeType == EscapeType::NONE)
1756
332k
                {
1757
332k
                    if (nUTF32 == nSegmentDelimiter)
1758
83.0k
                        break;
1759
249k
                    else if (nUTF32 == nFragmentDelimiter)
1760
1.04k
                    {
1761
1.04k
                        eState = STATE_FRAGMENT;
1762
1.04k
                        break;
1763
1.04k
                    }
1764
332k
                }
1765
248k
                appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType,
1766
248k
                           PART_VISIBLE, eCharset, true);
1767
248k
            }
1768
103k
        }
1769
273k
        else
1770
273k
        {
1771
273k
            SubString aAuthority(getAuthority());
1772
273k
            aSynAbsURIRef.append(m_aAbsURIRef.getStr()
1773
273k
                                     + aAuthority.getBegin(),
1774
273k
                                 aAuthority.getLength());
1775
273k
        }
1776
376k
    }
1777
1778
461k
    if (eState == STATE_AUTH)
1779
358k
    {
1780
358k
        if (p == pEnd)
1781
25.4k
            eState = STATE_DONE;
1782
332k
        else if (*p == nFragmentDelimiter)
1783
9.90k
        {
1784
9.90k
            ++p;
1785
9.90k
            eState = STATE_FRAGMENT;
1786
9.90k
        }
1787
323k
        else if (*p == nSegmentDelimiter)
1788
68.2k
        {
1789
68.2k
            ++p;
1790
68.2k
            eState = STATE_ABS_PATH;
1791
68.2k
            bSameDoc = false;
1792
68.2k
        }
1793
254k
        else
1794
254k
        {
1795
254k
            eState = STATE_REL_PATH;
1796
254k
            bSameDoc = false;
1797
254k
        }
1798
358k
    }
1799
1800
461k
    if (eState == STATE_ABS_PATH)
1801
170k
    {
1802
170k
        aSynAbsURIRef.append('/');
1803
170k
        eState = STATE_DONE;
1804
1.52M
        while (p != pEnd)
1805
1.36M
        {
1806
1.36M
            EscapeType eEscapeType;
1807
1.36M
            sal_uInt32 nUTF32
1808
1.36M
                = getUTF32(p, pEnd, eMechanism, eCharset, eEscapeType);
1809
1.36M
            if (eEscapeType == EscapeType::NONE)
1810
1.30M
            {
1811
1.30M
                if (nUTF32 == nFragmentDelimiter)
1812
10.8k
                {
1813
10.8k
                    eState = STATE_FRAGMENT;
1814
10.8k
                    break;
1815
10.8k
                }
1816
1.29M
                else if (nUTF32 == nSegmentDelimiter)
1817
140k
                    nUTF32 = '/';
1818
1.30M
            }
1819
1.35M
            appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, ePart,
1820
1.35M
                       eCharset, true);
1821
1.35M
        }
1822
170k
    }
1823
291k
    else if (eState == STATE_REL_PATH)
1824
254k
    {
1825
254k
        if (!getSchemeInfo().m_bHierarchical)
1826
70.8k
        {
1827
            // Detect cases where a relative input could not be made absolute
1828
            // because the given base URL is broken (most probably because it is
1829
            // empty):
1830
70.8k
            SAL_WARN_IF(
1831
70.8k
                HasError(), "tools.urlobj",
1832
70.8k
                "cannot make <" << rTheRelURIRef
1833
70.8k
                    << "> absolute against broken base <"
1834
70.8k
                    << GetMainURL(DecodeMechanism::NONE) << ">");
1835
70.8k
            rWasAbsolute = false;
1836
70.8k
            return false;
1837
70.8k
        }
1838
1839
183k
        sal_Unicode const * pBasePathBegin
1840
183k
            = m_aAbsURIRef.getStr() + m_aPath.getBegin();
1841
183k
        sal_Unicode const * pBasePathEnd
1842
183k
            = pBasePathBegin + m_aPath.getLength();
1843
1.66M
        while (pBasePathEnd != pBasePathBegin)
1844
1.66M
            if (*(--pBasePathEnd) == '/')
1845
183k
            {
1846
183k
                ++pBasePathEnd;
1847
183k
                break;
1848
183k
            }
1849
1850
183k
        sal_Int32 nPathBegin = aSynAbsURIRef.getLength();
1851
183k
        aSynAbsURIRef.append(pBasePathBegin, pBasePathEnd - pBasePathBegin);
1852
183k
        DBG_ASSERT(aSynAbsURIRef.getLength() > nPathBegin
1853
183k
                 && aSynAbsURIRef[aSynAbsURIRef.getLength() - 1] == '/',
1854
183k
                 "INetURLObject::convertRelToAbs(): Bad base path");
1855
1856
385k
        while (p != pEnd && *p != nQueryDelimiter && *p != nFragmentDelimiter)
1857
201k
        {
1858
201k
            if (*p == '.')
1859
14.7k
            {
1860
14.7k
                if (pEnd - p == 1
1861
11.8k
                    || p[1] == nSegmentDelimiter
1862
10.8k
                    || p[1] == nQueryDelimiter
1863
10.8k
                    || p[1] == nFragmentDelimiter)
1864
4.18k
                {
1865
4.18k
                    ++p;
1866
4.18k
                    if (p != pEnd && *p == nSegmentDelimiter)
1867
1.00k
                        ++p;
1868
4.18k
                    continue;
1869
4.18k
                }
1870
10.5k
                else if (pEnd - p >= 2
1871
10.5k
                         && p[1] == '.'
1872
8.35k
                         && (pEnd - p == 2
1873
6.66k
                             || p[2] == nSegmentDelimiter
1874
1.23k
                             || p[2] == nQueryDelimiter
1875
1.23k
                             || p[2] == nFragmentDelimiter)
1876
7.52k
                         && aSynAbsURIRef.getLength() - nPathBegin > 1)
1877
6.06k
                {
1878
6.06k
                    p += 2;
1879
6.06k
                    if (p != pEnd && *p == nSegmentDelimiter)
1880
4.00k
                        ++p;
1881
1882
6.06k
                    sal_Int32 i = aSynAbsURIRef.getLength() - 2;
1883
39.4k
                    while (i > nPathBegin && aSynAbsURIRef[i] != '/')
1884
33.4k
                        --i;
1885
6.06k
                    aSynAbsURIRef.setLength(i + 1);
1886
6.06k
                    DBG_ASSERT(
1887
6.06k
                        aSynAbsURIRef.getLength() > nPathBegin
1888
6.06k
                        && aSynAbsURIRef[aSynAbsURIRef.getLength() - 1] == '/',
1889
6.06k
                        "INetURLObject::convertRelToAbs(): Bad base path");
1890
6.06k
                    continue;
1891
6.06k
                }
1892
14.7k
            }
1893
1894
829k
            while (p != pEnd
1895
728k
                   && *p != nSegmentDelimiter
1896
642k
                   && *p != nQueryDelimiter
1897
642k
                   && *p != nFragmentDelimiter)
1898
638k
            {
1899
638k
                EscapeType eEscapeType;
1900
638k
                sal_uInt32 nUTF32
1901
638k
                    = getUTF32(p, pEnd, eMechanism,
1902
638k
                               eCharset, eEscapeType);
1903
638k
                appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, ePart,
1904
638k
                           eCharset, true);
1905
638k
            }
1906
191k
            if (p != pEnd && *p == nSegmentDelimiter)
1907
86.1k
            {
1908
86.1k
                aSynAbsURIRef.append('/');
1909
86.1k
                ++p;
1910
86.1k
            }
1911
191k
        }
1912
1913
185k
        while (p != pEnd && *p != nFragmentDelimiter)
1914
1.92k
        {
1915
1.92k
            EscapeType eEscapeType;
1916
1.92k
            sal_uInt32 nUTF32
1917
1.92k
                = getUTF32(p, pEnd, eMechanism, eCharset, eEscapeType);
1918
1.92k
            appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, ePart,
1919
1.92k
                       eCharset, true);
1920
1.92k
        }
1921
1922
183k
        if (p == pEnd)
1923
178k
            eState = STATE_DONE;
1924
5.16k
        else
1925
5.16k
        {
1926
5.16k
            ++p;
1927
5.16k
            eState = STATE_FRAGMENT;
1928
5.16k
        }
1929
183k
    }
1930
36.4k
    else if (bSameDoc)
1931
35.3k
    {
1932
35.3k
        aSynAbsURIRef.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(),
1933
35.3k
                             m_aPath.getLength());
1934
35.3k
        if (m_aQuery.isPresent())
1935
0
            aSynAbsURIRef.append(m_aAbsURIRef.getStr()
1936
0
                                     + m_aQuery.getBegin() - 1,
1937
0
                                 m_aQuery.getLength() + 1);
1938
35.3k
    }
1939
1940
390k
    if (eState == STATE_FRAGMENT && !bIgnoreFragment)
1941
26.9k
    {
1942
26.9k
        aSynAbsURIRef.append('#');
1943
377k
        while (p != pEnd)
1944
350k
        {
1945
350k
            EscapeType eEscapeType;
1946
350k
            sal_uInt32 nUTF32
1947
350k
                = getUTF32(p, pEnd, eMechanism, eCharset, eEscapeType);
1948
350k
            appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType,
1949
350k
                       PART_VISIBLE, eCharset, true);
1950
350k
        }
1951
26.9k
    }
1952
1953
390k
    INetURLObject aNewURI(aSynAbsURIRef);
1954
390k
    if (aNewURI.HasError())
1955
31.9k
    {
1956
        // Detect cases where a relative input could not be made absolute
1957
        // because the given base URL is broken (most probably because it is
1958
        // empty):
1959
31.9k
        SAL_WARN_IF(
1960
31.9k
            HasError(), "tools.urlobj",
1961
31.9k
            "cannot make <" << rTheRelURIRef
1962
31.9k
                << "> absolute against broken base <" << GetMainURL(DecodeMechanism::NONE)
1963
31.9k
                << ">");
1964
31.9k
        rWasAbsolute = false;
1965
31.9k
        return false;
1966
31.9k
    }
1967
1968
358k
    rTheAbsURIRef = std::move(aNewURI);
1969
358k
    return true;
1970
390k
}
1971
1972
bool INetURLObject::convertAbsToRel(OUString const & rTheAbsURIRef,
1973
                                    OUString & rTheRelURIRef,
1974
                                    EncodeMechanism eEncodeMechanism,
1975
                                    DecodeMechanism eDecodeMechanism,
1976
                                    rtl_TextEncoding eCharset,
1977
                                    FSysStyle eStyle) const
1978
0
{
1979
    // Check for hierarchical base URL:
1980
0
    if (!getSchemeInfo().m_bHierarchical)
1981
0
    {
1982
0
        rTheRelURIRef = decode(rTheAbsURIRef, eDecodeMechanism, eCharset);
1983
0
        return false;
1984
0
    }
1985
1986
    // Convert the input (absolute or relative URI ref) to an absolute URI
1987
    // ref:
1988
0
    INetURLObject aSubject;
1989
0
    bool bWasAbsolute;
1990
0
    if (!convertRelToAbs(rTheAbsURIRef, aSubject, bWasAbsolute,
1991
0
                         eEncodeMechanism, eCharset, false, false, false,
1992
0
                         eStyle))
1993
0
    {
1994
0
        rTheRelURIRef = decode(rTheAbsURIRef, eDecodeMechanism, eCharset);
1995
0
        return false;
1996
0
    }
1997
1998
    // Check for differing scheme or authority parts:
1999
0
    if ((m_aScheme.compare(
2000
0
             aSubject.m_aScheme, m_aAbsURIRef, aSubject.m_aAbsURIRef)
2001
0
         != 0)
2002
0
        || (m_aUser.compare(
2003
0
                aSubject.m_aUser, m_aAbsURIRef, aSubject.m_aAbsURIRef)
2004
0
            != 0)
2005
0
        || (m_aAuth.compare(
2006
0
                aSubject.m_aAuth, m_aAbsURIRef, aSubject.m_aAbsURIRef)
2007
0
            != 0)
2008
0
        || (m_aHost.compare(
2009
0
                aSubject.m_aHost, m_aAbsURIRef, aSubject.m_aAbsURIRef)
2010
0
            != 0)
2011
0
        || (m_aPort.compare(
2012
0
                aSubject.m_aPort, m_aAbsURIRef, aSubject.m_aAbsURIRef)
2013
0
            != 0))
2014
0
    {
2015
0
        rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
2016
0
        return false;
2017
0
    }
2018
2019
0
    sal_Unicode const * pBasePathBegin
2020
0
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
2021
0
    sal_Unicode const * pBasePathEnd = pBasePathBegin + m_aPath.getLength();
2022
0
    sal_Unicode const * pSubjectPathBegin
2023
0
        = aSubject.m_aAbsURIRef.getStr() + aSubject.m_aPath.getBegin();
2024
0
    sal_Unicode const * pSubjectPathEnd
2025
0
        = pSubjectPathBegin + aSubject.m_aPath.getLength();
2026
2027
    // Make nMatch point past the last matching slash, or past the end of the
2028
    // paths, in case they are equal:
2029
0
    sal_Unicode const * pSlash = nullptr;
2030
0
    sal_Unicode const * p1 = pBasePathBegin;
2031
0
    sal_Unicode const * p2 = pSubjectPathBegin;
2032
0
    for (;;)
2033
0
    {
2034
0
        if (p1 == pBasePathEnd || p2 == pSubjectPathEnd)
2035
0
        {
2036
0
            if (p1 == pBasePathEnd && p2 == pSubjectPathEnd)
2037
0
                pSlash = p1;
2038
0
            break;
2039
0
        }
2040
2041
0
        sal_Unicode c = *p1++;
2042
0
        if (c != *p2++)
2043
0
            break;
2044
0
        if (c == '/')
2045
0
            pSlash = p1;
2046
0
    }
2047
0
    if (!pSlash)
2048
0
    {
2049
        // One of the paths does not start with '/':
2050
0
        rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
2051
0
        return false;
2052
0
    }
2053
0
    sal_Int32 nMatch = pSlash - pBasePathBegin;
2054
2055
    // If the two URLs are DOS file URLs starting with different volumes
2056
    // (e.g., file:///a:/... and file:///b:/...), the subject is not made
2057
    // relative (it could be, but some people do not like that):
2058
0
    if (m_eScheme == INetProtocol::File
2059
0
        && nMatch <= 1
2060
0
        && hasDosVolume(eStyle)
2061
0
        && aSubject.hasDosVolume(eStyle)) //TODO! ok to use eStyle for these?
2062
0
    {
2063
0
        rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
2064
0
        return false;
2065
0
    }
2066
2067
    // For every slash in the base path after nMatch, a prefix of "../" is
2068
    // added to the new relative URL (if the common prefix of the two paths is
2069
    // only "/"---but see handling of file URLs above---, the complete subject
2070
    // path could go into the new relative URL instead, but some people don't
2071
    // like that):
2072
0
    OUStringBuffer aSynRelURIRef;
2073
0
    for (sal_Unicode const * p = pBasePathBegin + nMatch; p != pBasePathEnd;
2074
0
         ++p)
2075
0
    {
2076
0
        if (*p == '/')
2077
0
            aSynRelURIRef.append("../");
2078
0
    }
2079
2080
    // If the new relative URL would start with "//" (i.e., it would be
2081
    // mistaken for a relative URL starting with an authority part), or if the
2082
    // new relative URL would neither be empty nor start with <"/"> nor start
2083
    // with <1*rseg> (i.e., it could be mistaken for an absolute URL starting
2084
    // with a scheme part), then the new relative URL is prefixed with "./":
2085
0
    if (aSynRelURIRef.isEmpty())
2086
0
    {
2087
0
        if (pSubjectPathEnd - pSubjectPathBegin >= nMatch + 2
2088
0
            && pSubjectPathBegin[nMatch] == '/'
2089
0
            && pSubjectPathBegin[nMatch + 1] == '/')
2090
0
        {
2091
0
            aSynRelURIRef.append("./");
2092
0
        }
2093
0
        else
2094
0
        {
2095
0
            for (sal_Unicode const * p = pSubjectPathBegin + nMatch;
2096
0
                 p != pSubjectPathEnd && *p != '/'; ++p)
2097
0
            {
2098
0
                if (mustEncode(*p, PART_REL_SEGMENT_EXTRA))
2099
0
                {
2100
0
                    aSynRelURIRef.append("./");
2101
0
                    break;
2102
0
                }
2103
0
            }
2104
0
        }
2105
0
    }
2106
2107
    // The remainder of the subject path, starting at nMatch, is appended to
2108
    // the new relative URL:
2109
0
    aSynRelURIRef.append(decode(pSubjectPathBegin + nMatch, pSubjectPathEnd,
2110
0
                            eDecodeMechanism, eCharset));
2111
2112
    // If the subject has defined query or fragment parts, they are appended
2113
    // to the new relative URL:
2114
0
    if (aSubject.m_aQuery.isPresent())
2115
0
    {
2116
0
        aSynRelURIRef.append("?"
2117
0
            + aSubject.decode(aSubject.m_aQuery, eDecodeMechanism, eCharset));
2118
0
    }
2119
0
    if (aSubject.m_aFragment.isPresent())
2120
0
    {
2121
0
        aSynRelURIRef.append("#"
2122
0
            + aSubject.decode(aSubject.m_aFragment, eDecodeMechanism, eCharset));
2123
0
    }
2124
2125
0
    rTheRelURIRef = aSynRelURIRef.makeStringAndClear();
2126
0
    return true;
2127
0
}
2128
2129
// static
2130
bool INetURLObject::convertIntToExt(std::u16string_view rTheIntURIRef,
2131
                                    OUString & rTheExtURIRef,
2132
                                    DecodeMechanism eDecodeMechanism,
2133
                                    rtl_TextEncoding eCharset)
2134
0
{
2135
0
    OUStringBuffer aSynExtURIRef(256);
2136
0
    encodeText(aSynExtURIRef, rTheIntURIRef, PART_VISIBLE,
2137
0
               EncodeMechanism::NotCanonical, eCharset, true);
2138
0
    sal_Unicode const * pBegin = aSynExtURIRef.getStr();
2139
0
    sal_Unicode const * pEnd = pBegin + aSynExtURIRef.getLength();
2140
0
    sal_Unicode const * p = pBegin;
2141
0
    PrefixInfo const * pPrefix = getPrefix(p, pEnd);
2142
0
    bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::Kind::Internal;
2143
0
    if (bConvert)
2144
0
    {
2145
0
        comphelper::string::replaceAt(aSynExtURIRef, 0, p - pBegin,
2146
0
                pPrefix->m_aTranslatedPrefix);
2147
0
    }
2148
0
    rTheExtURIRef = decode(aSynExtURIRef, eDecodeMechanism, eCharset);
2149
0
    return bConvert;
2150
0
}
2151
2152
// static
2153
bool INetURLObject::convertExtToInt(std::u16string_view rTheExtURIRef,
2154
                                    OUString & rTheIntURIRef,
2155
                                    DecodeMechanism eDecodeMechanism,
2156
                                    rtl_TextEncoding eCharset)
2157
0
{
2158
0
    OUStringBuffer aSynIntURIRef(256);
2159
0
    encodeText(aSynIntURIRef, rTheExtURIRef, PART_VISIBLE,
2160
0
               EncodeMechanism::NotCanonical, eCharset, true);
2161
0
    sal_Unicode const * pBegin = aSynIntURIRef.getStr();
2162
0
    sal_Unicode const * pEnd = pBegin + aSynIntURIRef.getLength();
2163
0
    sal_Unicode const * p = pBegin;
2164
0
    PrefixInfo const * pPrefix = getPrefix(p, pEnd);
2165
0
    bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::Kind::External;
2166
0
    if (bConvert)
2167
0
    {
2168
0
        comphelper::string::replaceAt(aSynIntURIRef, 0, p - pBegin,
2169
0
            pPrefix->m_aTranslatedPrefix);
2170
0
    }
2171
0
    rTheIntURIRef = decode(aSynIntURIRef, eDecodeMechanism, eCharset);
2172
0
    return bConvert;
2173
0
}
2174
2175
// static
2176
INetURLObject::PrefixInfo const * INetURLObject::getPrefix(sal_Unicode const *& rBegin,
2177
                                                           sal_Unicode const * pEnd)
2178
4.19M
{
2179
4.19M
    static PrefixInfo constexpr aMap[]
2180
4.19M
          { // dummy entry at front needed, because pLast may point here:
2181
4.19M
            { u""_ustr, u""_ustr, INetProtocol::NotValid, PrefixInfo::Kind::Internal },
2182
4.19M
            { u".component:"_ustr, u"staroffice.component:"_ustr, INetProtocol::Component,
2183
4.19M
              PrefixInfo::Kind::Internal },
2184
4.19M
            { u".uno:"_ustr, u"staroffice.uno:"_ustr, INetProtocol::Uno,
2185
4.19M
              PrefixInfo::Kind::Internal },
2186
4.19M
            { u"cid:"_ustr, u""_ustr, INetProtocol::Cid, PrefixInfo::Kind::Official },
2187
4.19M
            { u"data:"_ustr, u""_ustr, INetProtocol::Data, PrefixInfo::Kind::Official },
2188
4.19M
            { u"db:"_ustr, u"staroffice.db:"_ustr, INetProtocol::Db, PrefixInfo::Kind::Internal },
2189
4.19M
            { u"file:"_ustr, u""_ustr, INetProtocol::File, PrefixInfo::Kind::Official },
2190
4.19M
            { u"ftp:"_ustr, u""_ustr, INetProtocol::Ftp, PrefixInfo::Kind::Official },
2191
4.19M
            { u"hid:"_ustr, u"staroffice.hid:"_ustr, INetProtocol::Hid,
2192
4.19M
              PrefixInfo::Kind::Internal },
2193
4.19M
            { u"http:"_ustr, u""_ustr, INetProtocol::Http, PrefixInfo::Kind::Official },
2194
4.19M
            { u"https:"_ustr, u""_ustr, INetProtocol::Https, PrefixInfo::Kind::Official },
2195
4.19M
            { u"javascript:"_ustr, u""_ustr, INetProtocol::Javascript, PrefixInfo::Kind::Official },
2196
4.19M
            { u"ldap:"_ustr, u""_ustr, INetProtocol::Ldap, PrefixInfo::Kind::Official },
2197
4.19M
            { u"macro:"_ustr, u"staroffice.macro:"_ustr, INetProtocol::Macro,
2198
4.19M
              PrefixInfo::Kind::Internal },
2199
4.19M
            { u"mailto:"_ustr, u""_ustr, INetProtocol::Mailto, PrefixInfo::Kind::Official },
2200
4.19M
            { u"private:"_ustr, u"staroffice.private:"_ustr, INetProtocol::PrivSoffice,
2201
4.19M
              PrefixInfo::Kind::Internal },
2202
4.19M
            { u"private:factory/"_ustr, u"staroffice.factory:"_ustr,
2203
4.19M
              INetProtocol::PrivSoffice, PrefixInfo::Kind::Internal },
2204
4.19M
            { u"private:helpid/"_ustr, u"staroffice.helpid:"_ustr, INetProtocol::PrivSoffice,
2205
4.19M
              PrefixInfo::Kind::Internal },
2206
4.19M
            { u"private:java/"_ustr, u"staroffice.java:"_ustr, INetProtocol::PrivSoffice,
2207
4.19M
              PrefixInfo::Kind::Internal },
2208
4.19M
            { u"private:searchfolder:"_ustr, u"staroffice.searchfolder:"_ustr,
2209
4.19M
              INetProtocol::PrivSoffice, PrefixInfo::Kind::Internal },
2210
4.19M
            { u"private:trashcan:"_ustr, u"staroffice.trashcan:"_ustr,
2211
4.19M
              INetProtocol::PrivSoffice, PrefixInfo::Kind::Internal },
2212
4.19M
            { u"sftp:"_ustr, u""_ustr, INetProtocol::Sftp, PrefixInfo::Kind::Official },
2213
4.19M
            { u"smb:"_ustr, u""_ustr, INetProtocol::Smb, PrefixInfo::Kind::Official },
2214
4.19M
            { u"staroffice.component:"_ustr, u".component:"_ustr, INetProtocol::Component,
2215
4.19M
              PrefixInfo::Kind::External },
2216
4.19M
            { u"staroffice.db:"_ustr, u"db:"_ustr, INetProtocol::Db, PrefixInfo::Kind::External },
2217
4.19M
            { u"staroffice.factory:"_ustr, u"private:factory/"_ustr,
2218
4.19M
              INetProtocol::PrivSoffice, PrefixInfo::Kind::External },
2219
4.19M
            { u"staroffice.helpid:"_ustr, u"private:helpid/"_ustr, INetProtocol::PrivSoffice,
2220
4.19M
              PrefixInfo::Kind::External },
2221
4.19M
            { u"staroffice.hid:"_ustr, u"hid:"_ustr, INetProtocol::Hid,
2222
4.19M
              PrefixInfo::Kind::External },
2223
4.19M
            { u"staroffice.java:"_ustr, u"private:java/"_ustr, INetProtocol::PrivSoffice,
2224
4.19M
              PrefixInfo::Kind::External },
2225
4.19M
            { u"staroffice.macro:"_ustr, u"macro:"_ustr, INetProtocol::Macro,
2226
4.19M
              PrefixInfo::Kind::External },
2227
4.19M
            { u"staroffice.private:"_ustr, u"private:"_ustr, INetProtocol::PrivSoffice,
2228
4.19M
              PrefixInfo::Kind::External },
2229
4.19M
            { u"staroffice.searchfolder:"_ustr, u"private:searchfolder:"_ustr,
2230
4.19M
              INetProtocol::PrivSoffice, PrefixInfo::Kind::External },
2231
4.19M
            { u"staroffice.trashcan:"_ustr, u"private:trashcan:"_ustr,
2232
4.19M
              INetProtocol::PrivSoffice, PrefixInfo::Kind::External },
2233
4.19M
            { u"staroffice.uno:"_ustr, u".uno:"_ustr, INetProtocol::Uno,
2234
4.19M
              PrefixInfo::Kind::External },
2235
4.19M
            { u"staroffice:"_ustr, u"private:"_ustr, INetProtocol::PrivSoffice,
2236
4.19M
              PrefixInfo::Kind::External },
2237
4.19M
            { u"telnet:"_ustr, u""_ustr, INetProtocol::Telnet, PrefixInfo::Kind::Official },
2238
4.19M
            { u"vnd.libreoffice.cmis:"_ustr, u""_ustr, INetProtocol::Cmis, PrefixInfo::Kind::Internal },
2239
4.19M
            { u"vnd.sun.star.cmd:"_ustr, u""_ustr, INetProtocol::VndSunStarCmd,
2240
4.19M
              PrefixInfo::Kind::Official },
2241
4.19M
            { u"vnd.sun.star.expand:"_ustr, u""_ustr, INetProtocol::VndSunStarExpand,
2242
4.19M
              PrefixInfo::Kind::Official },
2243
4.19M
            { u"vnd.sun.star.help:"_ustr, u""_ustr, INetProtocol::VndSunStarHelp,
2244
4.19M
              PrefixInfo::Kind::Official },
2245
4.19M
            { u"vnd.sun.star.hier:"_ustr, u""_ustr, INetProtocol::VndSunStarHier,
2246
4.19M
              PrefixInfo::Kind::Official },
2247
4.19M
            { u"vnd.sun.star.pkg:"_ustr, u""_ustr, INetProtocol::VndSunStarPkg,
2248
4.19M
              PrefixInfo::Kind::Official },
2249
4.19M
            { u"vnd.sun.star.tdoc:"_ustr, u""_ustr, INetProtocol::VndSunStarTdoc,
2250
4.19M
              PrefixInfo::Kind::Official },
2251
4.19M
            { u"vnd.sun.star.webdav:"_ustr, u""_ustr, INetProtocol::VndSunStarWebdav,
2252
4.19M
              PrefixInfo::Kind::Official }
2253
4.19M
        };
2254
/* This list needs to be sorted, or you'll introduce serious bugs */
2255
2256
4.19M
    PrefixInfo const * pFirst = aMap + 1;
2257
4.19M
    PrefixInfo const * pLast = std::end(aMap) - 1;
2258
4.19M
    PrefixInfo const * pMatch = nullptr;
2259
4.19M
    sal_Unicode const * pMatched = rBegin;
2260
4.19M
    sal_Unicode const * p = rBegin;
2261
4.19M
    sal_Int32 i = 0;
2262
10.7M
    for (; pFirst < pLast; ++i)
2263
7.61M
    {
2264
7.61M
        assert(!pFirst->m_aPrefix.isEmpty() && "we start search after the dummy entry");
2265
7.61M
        if (i == pFirst->m_aPrefix.getLength())
2266
68.9k
        {
2267
68.9k
            pMatch = pFirst++;
2268
68.9k
            pMatched = p;
2269
68.9k
        }
2270
7.61M
        if (p >= pEnd)
2271
1.04M
            break;
2272
6.57M
        sal_uInt32 nChar = rtl::toAsciiLowerCase(*p++);
2273
23.2M
        while (pFirst <= pLast && static_cast<unsigned char>(pFirst->m_aPrefix[i]) < nChar)
2274
16.6M
            ++pFirst;
2275
124M
        while (pFirst <= pLast && static_cast<unsigned char>(pLast->m_aPrefix[i]) > nChar)
2276
117M
            --pLast;
2277
6.57M
    }
2278
4.19M
    if (pFirst == pLast)
2279
1.93M
    {
2280
1.93M
        sal_Unicode const * q = pFirst->m_aPrefix.getStr() + i;
2281
6.35M
        while (p < pEnd && *q != '\0'
2282
4.55M
               && rtl::toAsciiLowerCase(*p) == static_cast<unsigned char>(*q))
2283
4.41M
        {
2284
4.41M
            ++p;
2285
4.41M
            ++q;
2286
4.41M
        }
2287
1.93M
        if (*q == '\0')
2288
1.77M
        {
2289
1.77M
            rBegin = p;
2290
1.77M
            return pFirst;
2291
1.77M
        }
2292
1.93M
    }
2293
2.42M
    rBegin = pMatched;
2294
2.42M
    return pMatch;
2295
4.19M
}
2296
2297
sal_Int32 INetURLObject::getAuthorityBegin() const
2298
273k
{
2299
273k
    DBG_ASSERT(getSchemeInfo().m_bAuthority,
2300
273k
               "INetURLObject::getAuthority(): Bad scheme");
2301
273k
    sal_Int32 nBegin;
2302
273k
    if (m_aUser.isPresent())
2303
0
        nBegin = m_aUser.getBegin();
2304
273k
    else if (m_aHost.isPresent())
2305
273k
        nBegin = m_aHost.getBegin();
2306
0
    else
2307
0
        nBegin = m_aPath.getBegin();
2308
273k
    nBegin -= RTL_CONSTASCII_LENGTH("//");
2309
273k
    DBG_ASSERT(m_aAbsURIRef[nBegin] == '/' && m_aAbsURIRef[nBegin + 1] == '/',
2310
273k
               "INetURLObject::getAuthority(): Bad authority");
2311
273k
    return nBegin;
2312
273k
}
2313
2314
INetURLObject::SubString INetURLObject::getAuthority() const
2315
273k
{
2316
273k
    sal_Int32 nBegin = getAuthorityBegin();
2317
273k
    sal_Int32 nEnd = m_aPort.isPresent() ? m_aPort.getEnd() :
2318
273k
                      m_aHost.isPresent() ? m_aHost.getEnd() :
2319
273k
                      m_aAuth.isPresent() ? m_aAuth.getEnd() :
2320
0
                      m_aUser.isPresent() ? m_aUser.getEnd() :
2321
0
                          nBegin + RTL_CONSTASCII_LENGTH("//");
2322
273k
    return SubString(nBegin, nEnd - nBegin);
2323
273k
}
2324
2325
bool INetURLObject::setUser(std::u16string_view rTheUser,
2326
                            rtl_TextEncoding eCharset)
2327
0
{
2328
0
    if (
2329
0
         !getSchemeInfo().m_bUser
2330
0
       )
2331
0
    {
2332
0
        return false;
2333
0
    }
2334
2335
0
    OUStringBuffer aNewUser;
2336
0
    encodeText(aNewUser, rTheUser, PART_USER_PASSWORD,
2337
0
              EncodeMechanism::WasEncoded, eCharset, false);
2338
0
    sal_Int32 nDelta;
2339
0
    if (m_aUser.isPresent())
2340
0
        nDelta = m_aUser.set(m_aAbsURIRef, aNewUser);
2341
0
    else if (m_aHost.isPresent())
2342
0
    {
2343
0
        m_aAbsURIRef.insert(m_aHost.getBegin(), u'@');
2344
0
        nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aHost.getBegin()) + 1;
2345
0
    }
2346
0
    else if (getSchemeInfo().m_bHost)
2347
0
        return false;
2348
0
    else
2349
0
        nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aPath.getBegin());
2350
0
    m_aAuth += nDelta;
2351
0
    m_aHost += nDelta;
2352
0
    m_aPort += nDelta;
2353
0
    m_aPath += nDelta;
2354
0
    m_aQuery += nDelta;
2355
0
    m_aFragment += nDelta;
2356
0
    return true;
2357
0
}
2358
2359
namespace
2360
{
2361
    void lcl_Erase(OUStringBuffer &rBuf, sal_Int32 index, sal_Int32 count)
2362
67
    {
2363
67
        OUString sTemp(rBuf.makeStringAndClear());
2364
67
        rBuf.append(sTemp.replaceAt(index, count, u""));
2365
67
    }
2366
}
2367
2368
bool INetURLObject::clearPassword()
2369
11.8k
{
2370
11.8k
    if (!getSchemeInfo().m_bPassword)
2371
11.8k
        return false;
2372
0
    if (m_aAuth.isPresent())
2373
0
    {
2374
0
        lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin() - 1,
2375
0
            m_aAuth.getLength() + 1);
2376
0
        sal_Int32 nDelta = m_aAuth.clear() - 1;
2377
0
        m_aHost += nDelta;
2378
0
        m_aPort += nDelta;
2379
0
        m_aPath += nDelta;
2380
0
        m_aQuery += nDelta;
2381
0
        m_aFragment += nDelta;
2382
0
    }
2383
0
    return true;
2384
11.8k
}
2385
2386
bool INetURLObject::setPassword(std::u16string_view rThePassword,
2387
                                rtl_TextEncoding eCharset)
2388
0
{
2389
0
    if (!getSchemeInfo().m_bPassword)
2390
0
        return false;
2391
0
    OUStringBuffer aNewAuth;
2392
0
    encodeText(aNewAuth, rThePassword, PART_USER_PASSWORD,
2393
0
                  EncodeMechanism::WasEncoded, eCharset, false);
2394
0
    sal_Int32 nDelta;
2395
0
    if (m_aAuth.isPresent())
2396
0
        nDelta = m_aAuth.set(m_aAbsURIRef, aNewAuth);
2397
0
    else if (m_aUser.isPresent())
2398
0
    {
2399
0
        m_aAbsURIRef.insert(m_aUser.getEnd(), u':');
2400
0
        nDelta
2401
0
            = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aUser.getEnd() + 1) + 1;
2402
0
    }
2403
0
    else if (m_aHost.isPresent())
2404
0
    {
2405
0
        m_aAbsURIRef.insert(m_aHost.getBegin(), ":@" );
2406
0
        m_aUser.set(m_aAbsURIRef, std::u16string_view{}, m_aHost.getBegin());
2407
0
        nDelta
2408
0
            = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aHost.getBegin() + 1) + 2;
2409
0
    }
2410
0
    else if (getSchemeInfo().m_bHost)
2411
0
        return false;
2412
0
    else
2413
0
    {
2414
0
        m_aAbsURIRef.insert(m_aPath.getBegin(), u':');
2415
0
        m_aUser.set(m_aAbsURIRef, std::u16string_view{}, m_aPath.getBegin());
2416
0
        nDelta
2417
0
            = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aPath.getBegin() + 1) + 1;
2418
0
    }
2419
0
    m_aHost += nDelta;
2420
0
    m_aPort += nDelta;
2421
0
    m_aPath += nDelta;
2422
0
    m_aQuery += nDelta;
2423
0
    m_aFragment += nDelta;
2424
0
    return true;
2425
0
}
2426
2427
// static
2428
bool INetURLObject::parseHost(sal_Unicode const *& rBegin, sal_Unicode const * pEnd,
2429
    OUStringBuffer* pCanonic)
2430
576k
{
2431
    // RFC 2373 is inconsistent about how to write an IPv6 address in which an
2432
    // IPv4 address directly follows the abbreviating "::".  The ABNF in
2433
    // Appendix B suggests ":::13.1.68.3", while an example in 2.2/3 explicitly
2434
    // mentions "::13:1.68.3".  This algorithm accepts both variants:
2435
576k
    enum State { STATE_INITIAL, STATE_LABEL, STATE_LABEL_HYPHEN,
2436
576k
                 STATE_LABEL_DOT, STATE_TOPLABEL, STATE_TOPLABEL_HYPHEN,
2437
576k
                 STATE_TOPLABEL_DOT, STATE_IP4, STATE_IP4_DOT, STATE_IP6,
2438
576k
                 STATE_IP6_COLON, STATE_IP6_2COLON, STATE_IP6_3COLON,
2439
576k
                 STATE_IP6_HEXSEQ1, STATE_IP6_HEXSEQ1_COLON,
2440
576k
                 STATE_IP6_HEXSEQ1_MAYBE_IP4, STATE_IP6_HEXSEQ2,
2441
576k
                 STATE_IP6_HEXSEQ2_COLON, STATE_IP6_HEXSEQ2_MAYBE_IP4,
2442
576k
                 STATE_IP6_IP4, STATE_IP6_IP4_DOT, STATE_IP6_DONE };
2443
576k
    sal_uInt32 nNumber = 0;
2444
576k
    int nDigits = 0;
2445
576k
    int nOctets = 0;
2446
576k
    State eState = STATE_INITIAL;
2447
576k
    sal_Unicode const * p = rBegin;
2448
576k
    sal_Int32 nOriginalCanonicLength = pCanonic ? pCanonic->getLength() : 0;
2449
4.70M
    for (; p != pEnd; ++p)
2450
4.24M
        switch (eState)
2451
4.24M
        {
2452
576k
            case STATE_INITIAL:
2453
576k
                if (*p == '[')
2454
58.0k
                {
2455
58.0k
                    if (pCanonic)
2456
26.6k
                        pCanonic->append('[');
2457
58.0k
                    eState = STATE_IP6;
2458
58.0k
                }
2459
518k
                else if (rtl::isAsciiAlpha(*p) || *p == '_')
2460
431k
                    eState = STATE_TOPLABEL;
2461
86.5k
                else if (rtl::isAsciiDigit(*p))
2462
53.3k
                {
2463
53.3k
                    nNumber = INetMIME::getWeight(*p);
2464
53.3k
                    nDigits = 1;
2465
53.3k
                    nOctets = 1;
2466
53.3k
                    eState = STATE_IP4;
2467
53.3k
                }
2468
33.2k
                else
2469
33.2k
                    goto done;
2470
542k
                break;
2471
2472
542k
            case STATE_LABEL:
2473
298k
                if (*p == '.')
2474
15.1k
                    eState = STATE_LABEL_DOT;
2475
282k
                else if (*p == '-')
2476
13.3k
                    eState = STATE_LABEL_HYPHEN;
2477
269k
                else if (!rtl::isAsciiAlphanumeric(*p) && *p != '_')
2478
10.1k
                    goto done;
2479
287k
                break;
2480
2481
287k
            case STATE_LABEL_HYPHEN:
2482
24.5k
                if (rtl::isAsciiAlphanumeric(*p) || *p == '_')
2483
14.0k
                    eState = STATE_LABEL;
2484
10.5k
                else if (*p != '-')
2485
2.42k
                    goto done;
2486
22.1k
                break;
2487
2488
22.1k
            case STATE_LABEL_DOT:
2489
16.4k
                if (rtl::isAsciiAlpha(*p) || *p == '_')
2490
5.67k
                    eState = STATE_TOPLABEL;
2491
10.7k
                else if (rtl::isAsciiDigit(*p))
2492
6.91k
                    eState = STATE_LABEL;
2493
3.84k
                else
2494
3.84k
                    goto done;
2495
12.5k
                break;
2496
2497
2.47M
            case STATE_TOPLABEL:
2498
2.47M
                if (*p == '.')
2499
328k
                    eState = STATE_TOPLABEL_DOT;
2500
2.14M
                else if (*p == '-')
2501
25.4k
                    eState = STATE_TOPLABEL_HYPHEN;
2502
2.11M
                else if (!rtl::isAsciiAlphanumeric(*p) && *p != '_')
2503
22.5k
                    goto done;
2504
2.45M
                break;
2505
2506
2.45M
            case STATE_TOPLABEL_HYPHEN:
2507
30.0k
                if (rtl::isAsciiAlphanumeric(*p) || *p == '_')
2508
21.4k
                    eState = STATE_TOPLABEL;
2509
8.58k
                else if (*p != '-')
2510
1.70k
                    goto done;
2511
28.3k
                break;
2512
2513
185k
            case STATE_TOPLABEL_DOT:
2514
185k
                if (rtl::isAsciiAlpha(*p) || *p == '_')
2515
178k
                    eState = STATE_TOPLABEL;
2516
6.91k
                else if (rtl::isAsciiDigit(*p))
2517
2.81k
                    eState = STATE_LABEL;
2518
4.10k
                else
2519
4.10k
                    goto done;
2520
180k
                break;
2521
2522
180k
            case STATE_IP4:
2523
119k
                if (*p == '.')
2524
28.0k
                    if (nOctets < 4)
2525
25.8k
                    {
2526
25.8k
                        if (pCanonic)
2527
13.5k
                        {
2528
13.5k
                            pCanonic->append(static_cast<sal_Int64>(nNumber));
2529
13.5k
                            pCanonic->append( '.' );
2530
13.5k
                        }
2531
25.8k
                        ++nOctets;
2532
25.8k
                        eState = STATE_IP4_DOT;
2533
25.8k
                    }
2534
2.18k
                    else
2535
2.18k
                        eState = STATE_LABEL_DOT;
2536
91.7k
                else if (*p == '-')
2537
6.63k
                    eState = STATE_LABEL_HYPHEN;
2538
85.0k
                else if (rtl::isAsciiAlpha(*p) || *p == '_')
2539
12.3k
                    eState = STATE_LABEL;
2540
72.7k
                else if (rtl::isAsciiDigit(*p))
2541
58.6k
                    if (nDigits < 3)
2542
50.5k
                    {
2543
50.5k
                        nNumber = 10 * nNumber + INetMIME::getWeight(*p);
2544
50.5k
                        ++nDigits;
2545
50.5k
                    }
2546
8.02k
                    else
2547
8.02k
                        eState = STATE_LABEL;
2548
14.1k
                else
2549
14.1k
                    goto done;
2550
105k
                break;
2551
2552
105k
            case STATE_IP4_DOT:
2553
25.7k
                if (rtl::isAsciiAlpha(*p) || *p == '_')
2554
2.89k
                    eState = STATE_TOPLABEL;
2555
22.8k
                else if (rtl::isAsciiDigit(*p))
2556
21.9k
                {
2557
21.9k
                    nNumber = INetMIME::getWeight(*p);
2558
21.9k
                    nDigits = 1;
2559
21.9k
                    eState = STATE_IP4;
2560
21.9k
                }
2561
914
                else
2562
914
                    goto done;
2563
24.8k
                break;
2564
2565
57.9k
            case STATE_IP6:
2566
57.9k
                if (*p == ':')
2567
15.0k
                    eState = STATE_IP6_COLON;
2568
42.8k
                else if (rtl::isAsciiHexDigit(*p))
2569
40.7k
                {
2570
40.7k
                    nNumber = INetMIME::getHexWeight(*p);
2571
40.7k
                    nDigits = 1;
2572
40.7k
                    eState = STATE_IP6_HEXSEQ1;
2573
40.7k
                }
2574
2.13k
                else
2575
2.13k
                    goto done;
2576
55.7k
                break;
2577
2578
55.7k
            case STATE_IP6_COLON:
2579
14.9k
                if (*p == ':')
2580
14.3k
                {
2581
14.3k
                    if (pCanonic)
2582
5.12k
                        pCanonic->append("::");
2583
14.3k
                    eState = STATE_IP6_2COLON;
2584
14.3k
                }
2585
586
                else
2586
586
                    goto done;
2587
14.3k
                break;
2588
2589
33.7k
            case STATE_IP6_2COLON:
2590
33.7k
                if (*p == ']')
2591
9.53k
                    eState = STATE_IP6_DONE;
2592
24.2k
                else if (*p == ':')
2593
2.93k
                {
2594
2.93k
                    if (pCanonic)
2595
1.99k
                        pCanonic->append(':');
2596
2.93k
                    eState = STATE_IP6_3COLON;
2597
2.93k
                }
2598
21.2k
                else if (rtl::isAsciiDigit(*p))
2599
10.0k
                {
2600
10.0k
                    nNumber = INetMIME::getWeight(*p);
2601
10.0k
                    nDigits = 1;
2602
10.0k
                    eState = STATE_IP6_HEXSEQ2_MAYBE_IP4;
2603
10.0k
                }
2604
11.2k
                else if (rtl::isAsciiHexDigit(*p))
2605
10.0k
                {
2606
10.0k
                    nNumber = INetMIME::getHexWeight(*p);
2607
10.0k
                    nDigits = 1;
2608
10.0k
                    eState = STATE_IP6_HEXSEQ2;
2609
10.0k
                }
2610
1.20k
                else
2611
1.20k
                    goto done;
2612
32.5k
                break;
2613
2614
32.5k
            case STATE_IP6_3COLON:
2615
2.79k
                if (rtl::isAsciiDigit(*p))
2616
2.13k
                {
2617
2.13k
                    nNumber = INetMIME::getWeight(*p);
2618
2.13k
                    nDigits = 1;
2619
2.13k
                    nOctets = 1;
2620
2.13k
                    eState = STATE_IP6_IP4;
2621
2.13k
                }
2622
664
                else
2623
664
                    goto done;
2624
2.13k
                break;
2625
2626
109k
            case STATE_IP6_HEXSEQ1:
2627
109k
                if (*p == ']')
2628
7.94k
                {
2629
7.94k
                    if (pCanonic)
2630
3.22k
                        pCanonic->append(
2631
3.22k
                            OUString::number(nNumber, 16));
2632
7.94k
                    eState = STATE_IP6_DONE;
2633
7.94k
                }
2634
101k
                else if (*p == ':')
2635
53.4k
                {
2636
53.4k
                    if (pCanonic)
2637
21.3k
                    {
2638
21.3k
                        pCanonic->append(
2639
21.3k
                            OUString::number(nNumber, 16));
2640
21.3k
                        pCanonic->append(':');
2641
21.3k
                    }
2642
53.4k
                    eState = STATE_IP6_HEXSEQ1_COLON;
2643
53.4k
                }
2644
47.6k
                else if (rtl::isAsciiHexDigit(*p) && nDigits < 4)
2645
43.0k
                {
2646
43.0k
                    assert(nNumber < 0xffff);
2647
43.0k
                    nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
2648
43.0k
                    ++nDigits;
2649
43.0k
                }
2650
4.62k
                else
2651
4.62k
                    goto done;
2652
104k
                break;
2653
2654
104k
            case STATE_IP6_HEXSEQ1_COLON:
2655
69.9k
                if (*p == ':')
2656
19.3k
                {
2657
19.3k
                    if (pCanonic)
2658
8.66k
                        pCanonic->append(':');
2659
19.3k
                    eState = STATE_IP6_2COLON;
2660
19.3k
                }
2661
50.6k
                else if (rtl::isAsciiDigit(*p))
2662
32.2k
                {
2663
32.2k
                    nNumber = INetMIME::getWeight(*p);
2664
32.2k
                    nDigits = 1;
2665
32.2k
                    eState = STATE_IP6_HEXSEQ1_MAYBE_IP4;
2666
32.2k
                }
2667
18.3k
                else if (rtl::isAsciiHexDigit(*p))
2668
16.8k
                {
2669
16.8k
                    nNumber = INetMIME::getHexWeight(*p);
2670
16.8k
                    nDigits = 1;
2671
16.8k
                    eState = STATE_IP6_HEXSEQ1;
2672
16.8k
                }
2673
1.50k
                else
2674
1.50k
                    goto done;
2675
68.4k
                break;
2676
2677
68.4k
            case STATE_IP6_HEXSEQ1_MAYBE_IP4:
2678
45.9k
                if (*p == ']')
2679
3.24k
                {
2680
3.24k
                    if (pCanonic)
2681
1.44k
                        pCanonic->append(
2682
1.44k
                            OUString::number(nNumber, 16));
2683
3.24k
                    eState = STATE_IP6_DONE;
2684
3.24k
                }
2685
42.6k
                else if (*p == ':')
2686
16.5k
                {
2687
16.5k
                    if (pCanonic)
2688
8.51k
                    {
2689
8.51k
                        pCanonic->append(
2690
8.51k
                            OUString::number(nNumber, 16));
2691
8.51k
                        pCanonic->append(':');
2692
8.51k
                    }
2693
16.5k
                    eState = STATE_IP6_HEXSEQ1_COLON;
2694
16.5k
                }
2695
26.1k
                else if (*p == '.')
2696
2.48k
                {
2697
2.48k
                    nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15)
2698
2.48k
                                  + (nNumber & 15);
2699
2.48k
                    if (pCanonic)
2700
816
                    {
2701
816
                        pCanonic->append(
2702
816
                            OUString::number(nNumber));
2703
816
                        pCanonic->append('.');
2704
816
                    }
2705
2.48k
                    nOctets = 2;
2706
2.48k
                    eState = STATE_IP6_IP4_DOT;
2707
2.48k
                }
2708
23.6k
                else if (rtl::isAsciiDigit(*p) && nDigits < 3)
2709
13.6k
                {
2710
13.6k
                    assert(nNumber < 0xfff);
2711
13.6k
                    nNumber = 16 * nNumber + INetMIME::getWeight(*p);
2712
13.6k
                    ++nDigits;
2713
13.6k
                }
2714
10.0k
                else if (rtl::isAsciiHexDigit(*p) && nDigits < 4)
2715
8.60k
                {
2716
8.60k
                    nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
2717
8.60k
                    ++nDigits;
2718
8.60k
                    eState = STATE_IP6_HEXSEQ1;
2719
8.60k
                }
2720
1.39k
                else
2721
1.39k
                    goto done;
2722
44.5k
                break;
2723
2724
73.8k
            case STATE_IP6_HEXSEQ2:
2725
73.8k
                if (*p == ']')
2726
8.94k
                {
2727
8.94k
                    if (pCanonic)
2728
2.54k
                        pCanonic->append(
2729
2.54k
                            OUString::number(nNumber, 16));
2730
8.94k
                    eState = STATE_IP6_DONE;
2731
8.94k
                }
2732
64.9k
                else if (*p == ':')
2733
21.0k
                {
2734
21.0k
                    if (pCanonic)
2735
7.29k
                    {
2736
7.29k
                        pCanonic->append(
2737
7.29k
                            OUString::number(nNumber, 16));
2738
7.29k
                        pCanonic->append(':');
2739
7.29k
                    }
2740
21.0k
                    eState = STATE_IP6_HEXSEQ2_COLON;
2741
21.0k
                }
2742
43.8k
                else if (rtl::isAsciiHexDigit(*p) && nDigits < 4)
2743
41.0k
                {
2744
41.0k
                    assert(nNumber < 0xffff);
2745
41.0k
                    nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
2746
41.0k
                    ++nDigits;
2747
41.0k
                }
2748
2.84k
                else
2749
2.84k
                    goto done;
2750
71.0k
                break;
2751
2752
71.0k
            case STATE_IP6_HEXSEQ2_COLON:
2753
27.9k
                if (rtl::isAsciiDigit(*p))
2754
11.6k
                {
2755
11.6k
                    nNumber = INetMIME::getWeight(*p);
2756
11.6k
                    nDigits = 1;
2757
11.6k
                    eState = STATE_IP6_HEXSEQ2_MAYBE_IP4;
2758
11.6k
                }
2759
16.2k
                else if (rtl::isAsciiHexDigit(*p))
2760
15.0k
                {
2761
15.0k
                    nNumber = INetMIME::getHexWeight(*p);
2762
15.0k
                    nDigits = 1;
2763
15.0k
                    eState = STATE_IP6_HEXSEQ2;
2764
15.0k
                }
2765
1.25k
                else
2766
1.25k
                    goto done;
2767
26.6k
                break;
2768
2769
32.3k
            case STATE_IP6_HEXSEQ2_MAYBE_IP4:
2770
32.3k
                if (*p == ']')
2771
3.23k
                {
2772
3.23k
                    if (pCanonic)
2773
1.08k
                        pCanonic->append(
2774
1.08k
                            OUString::number(nNumber, 16));
2775
3.23k
                    eState = STATE_IP6_DONE;
2776
3.23k
                }
2777
29.0k
                else if (*p == ':')
2778
6.91k
                {
2779
6.91k
                    if (pCanonic)
2780
3.00k
                    {
2781
3.00k
                        pCanonic->append(
2782
3.00k
                            OUString::number(nNumber, 16));
2783
3.00k
                        pCanonic->append(':');
2784
3.00k
                    }
2785
6.91k
                    eState = STATE_IP6_HEXSEQ2_COLON;
2786
6.91k
                }
2787
22.1k
                else if (*p == '.')
2788
2.02k
                {
2789
2.02k
                    nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15)
2790
2.02k
                                  + (nNumber & 15);
2791
2.02k
                    if (pCanonic)
2792
1.23k
                    {
2793
1.23k
                        pCanonic->append(
2794
1.23k
                            OUString::number(nNumber));
2795
1.23k
                        pCanonic->append('.');
2796
1.23k
                    }
2797
2.02k
                    nOctets = 2;
2798
2.02k
                    eState = STATE_IP6_IP4_DOT;
2799
2.02k
                }
2800
20.1k
                else if (rtl::isAsciiDigit(*p) && nDigits < 3)
2801
10.7k
                {
2802
10.7k
                    assert(nNumber < 0xfff);
2803
10.7k
                    nNumber = 16 * nNumber + INetMIME::getWeight(*p);
2804
10.7k
                    ++nDigits;
2805
10.7k
                }
2806
9.38k
                else if (rtl::isAsciiHexDigit(*p) && nDigits < 4)
2807
7.91k
                {
2808
7.91k
                    nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
2809
7.91k
                    ++nDigits;
2810
7.91k
                    eState = STATE_IP6_HEXSEQ2;
2811
7.91k
                }
2812
1.47k
                else
2813
1.47k
                    goto done;
2814
30.8k
                break;
2815
2816
30.8k
            case STATE_IP6_IP4:
2817
18.1k
                if (*p == ']')
2818
2.62k
                    if (nOctets == 4)
2819
2.15k
                    {
2820
2.15k
                        if (pCanonic)
2821
924
                            pCanonic->append(
2822
924
                                OUString::number(nNumber));
2823
2.15k
                        eState = STATE_IP6_DONE;
2824
2.15k
                    }
2825
471
                    else
2826
471
                        goto done;
2827
15.5k
                else if (*p == '.')
2828
7.82k
                    if (nOctets < 4)
2829
7.53k
                    {
2830
7.53k
                        if (pCanonic)
2831
3.48k
                        {
2832
3.48k
                            pCanonic->append(
2833
3.48k
                                OUString::number(nNumber));
2834
3.48k
                            pCanonic->append('.');
2835
3.48k
                        }
2836
7.53k
                        ++nOctets;
2837
7.53k
                        eState = STATE_IP6_IP4_DOT;
2838
7.53k
                    }
2839
285
                    else
2840
285
                        goto done;
2841
7.74k
                else if (rtl::isAsciiDigit(*p) && nDigits < 3)
2842
5.88k
                {
2843
5.88k
                    assert(nNumber < 999);
2844
5.88k
                    nNumber = 10 * nNumber + INetMIME::getWeight(*p);
2845
5.88k
                    ++nDigits;
2846
5.88k
                }
2847
1.86k
                else
2848
1.86k
                    goto done;
2849
15.5k
                break;
2850
2851
15.5k
            case STATE_IP6_IP4_DOT:
2852
12.0k
                if (rtl::isAsciiDigit(*p))
2853
10.2k
                {
2854
10.2k
                    nNumber = INetMIME::getWeight(*p);
2855
10.2k
                    nDigits = 1;
2856
10.2k
                    eState = STATE_IP6_IP4;
2857
10.2k
                }
2858
1.77k
                else
2859
1.77k
                    goto done;
2860
10.2k
                break;
2861
2862
10.2k
            case STATE_IP6_DONE:
2863
1.48k
                goto done;
2864
4.24M
        }
2865
576k
 done:
2866
576k
    switch (eState)
2867
576k
    {
2868
15.7k
        case STATE_LABEL:
2869
301k
        case STATE_TOPLABEL:
2870
448k
        case STATE_TOPLABEL_DOT:
2871
448k
            if (pCanonic)
2872
419k
            {
2873
419k
                pCanonic->setLength(nOriginalCanonicLength);
2874
419k
                pCanonic->append(rBegin, p - rBegin);
2875
419k
            }
2876
448k
            rBegin = p;
2877
448k
            return true;
2878
2879
20.2k
        case STATE_IP4:
2880
20.2k
            if (nOctets == 4)
2881
2.88k
            {
2882
2.88k
                if (pCanonic)
2883
1.52k
                    pCanonic->append(
2884
1.52k
                        OUString::number(nNumber));
2885
2.88k
                rBegin = p;
2886
2.88k
                return true;
2887
2.88k
            }
2888
17.3k
            if (pCanonic)
2889
6.66k
                pCanonic->setLength(nOriginalCanonicLength);
2890
17.3k
            return false;
2891
2892
35.0k
        case STATE_IP6_DONE:
2893
35.0k
            if (pCanonic)
2894
11.5k
                pCanonic->append(']');
2895
35.0k
            rBegin = p;
2896
35.0k
            return true;
2897
2898
71.8k
        default:
2899
71.8k
            if (pCanonic)
2900
38.5k
                pCanonic->setLength(nOriginalCanonicLength);
2901
71.8k
            return false;
2902
576k
    }
2903
576k
}
2904
2905
// static
2906
bool INetURLObject::parseHostOrNetBiosName(
2907
    sal_Unicode const * pBegin, sal_Unicode const * pEnd,
2908
    EncodeMechanism eMechanism, rtl_TextEncoding eCharset, bool bNetBiosName,
2909
    OUStringBuffer* pCanonic)
2910
2.11M
{
2911
2.11M
    if (pBegin >= pEnd)
2912
1.54M
        return true;
2913
576k
    sal_Int32 nOriginalCanonicLength = pCanonic ? pCanonic->getLength() : 0;
2914
576k
    if (sal_Unicode const* p = pBegin; parseHost(p, pEnd, pCanonic) && p == pEnd)
2915
446k
        return true;
2916
129k
    if (pCanonic)
2917
70.3k
        pCanonic->setLength(nOriginalCanonicLength); // discard parseHost results
2918
129k
    if (!bNetBiosName)
2919
42.0k
        return false;
2920
559k
    while (pBegin < pEnd)
2921
524k
    {
2922
524k
        EscapeType eEscapeType;
2923
524k
        switch (sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, eMechanism, eCharset, eEscapeType))
2924
524k
        {
2925
479k
            default:
2926
479k
                if (INetMIME::isVisible(nUTF32))
2927
471k
                {
2928
471k
                    if (pCanonic)
2929
115k
                        appendUCS4(*pCanonic, nUTF32, eEscapeType, PART_URIC, eCharset, true);
2930
471k
                    break;
2931
471k
                }
2932
8.10k
                [[fallthrough]];
2933
8.98k
            case '"':
2934
9.35k
            case '*':
2935
10.2k
            case '+':
2936
12.5k
            case ',':
2937
13.7k
            case '/':
2938
15.6k
            case ':':
2939
16.5k
            case ';':
2940
17.3k
            case '<':
2941
18.2k
            case '=':
2942
21.7k
            case '>':
2943
29.4k
            case '?':
2944
50.3k
            case '[':
2945
50.5k
            case '\\':
2946
51.3k
            case ']':
2947
51.9k
            case '`':
2948
53.2k
            case '|':
2949
53.2k
                if (pCanonic)
2950
18.0k
                    pCanonic->setLength(nOriginalCanonicLength);
2951
53.2k
                return false;
2952
524k
        }
2953
524k
    }
2954
34.6k
    return true;
2955
87.8k
}
2956
2957
// static
2958
bool INetURLObject::parsePath(INetProtocol eScheme,
2959
                              sal_Unicode const ** pBegin,
2960
                              sal_Unicode const * pEnd,
2961
                              EncodeMechanism eMechanism,
2962
                              rtl_TextEncoding eCharset,
2963
                              bool bSkippedInitialSlash,
2964
                              sal_uInt32 nSegmentDelimiter,
2965
                              sal_uInt32 nAltSegmentDelimiter,
2966
                              sal_uInt32 nQueryDelimiter,
2967
                              sal_uInt32 nFragmentDelimiter,
2968
                              OUStringBuffer &rSynPath)
2969
1.68M
{
2970
1.68M
    DBG_ASSERT(pBegin, "INetURLObject::parsePath(): Null output param");
2971
2972
1.68M
    sal_Unicode const * pPos = *pBegin;
2973
1.68M
    const sal_Int32 nSynPathBeforeLen = rSynPath.getLength();
2974
1.68M
    switch (eScheme)
2975
1.68M
    {
2976
0
        case INetProtocol::NotValid:
2977
0
            return false;
2978
2979
55.1k
        case INetProtocol::Ftp:
2980
55.1k
            if (pPos < pEnd && *pPos != '/' && *pPos != nFragmentDelimiter)
2981
0
                goto failed;
2982
219k
            while (pPos < pEnd && *pPos != nFragmentDelimiter)
2983
164k
            {
2984
164k
                EscapeType eEscapeType;
2985
164k
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
2986
164k
                                             eCharset, eEscapeType);
2987
164k
                appendUCS4(rSynPath, nUTF32, eEscapeType,
2988
164k
                           PART_HTTP_PATH, eCharset, true);
2989
164k
            }
2990
55.1k
            if (rSynPath.getLength() - nSynPathBeforeLen == 0)
2991
2.12k
                rSynPath.append('/');
2992
55.1k
            break;
2993
2994
315k
        case INetProtocol::Http:
2995
315k
        case INetProtocol::VndSunStarWebdav:
2996
335k
        case INetProtocol::Https:
2997
336k
        case INetProtocol::Smb:
2998
336k
        case INetProtocol::Cmis:
2999
336k
            if (pPos < pEnd && *pPos != '/' && *pPos != nQueryDelimiter
3000
79.0k
                && *pPos != nFragmentDelimiter)
3001
0
                goto failed;
3002
2.04M
            while (pPos < pEnd && *pPos != nQueryDelimiter
3003
1.87M
                   && *pPos != nFragmentDelimiter)
3004
1.71M
            {
3005
1.71M
                EscapeType eEscapeType;
3006
1.71M
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3007
1.71M
                                             eCharset, eEscapeType);
3008
1.71M
                appendUCS4(rSynPath, nUTF32, eEscapeType,
3009
1.71M
                           PART_HTTP_PATH, eCharset, true);
3010
1.71M
            }
3011
336k
            if (rSynPath.getLength() - nSynPathBeforeLen == 0)
3012
125k
                rSynPath.append('/');
3013
336k
            break;
3014
3015
1.12M
        case INetProtocol::File:
3016
1.12M
        {
3017
1.12M
            if (bSkippedInitialSlash)
3018
13.1k
                rSynPath.append('/');
3019
1.11M
            else if (pPos < pEnd
3020
1.09M
                     && *pPos != nSegmentDelimiter
3021
591
                     && *pPos != nAltSegmentDelimiter)
3022
591
                goto failed;
3023
17.0M
            while (pPos < pEnd && *pPos != nFragmentDelimiter)
3024
15.9M
            {
3025
15.9M
                EscapeType eEscapeType;
3026
15.9M
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3027
15.9M
                                             eCharset, eEscapeType);
3028
15.9M
                if (eEscapeType == EscapeType::NONE)
3029
15.4M
                {
3030
15.4M
                    if (nUTF32 == nSegmentDelimiter
3031
13.0M
                        || nUTF32 == nAltSegmentDelimiter)
3032
2.45M
                    {
3033
2.45M
                        rSynPath.append('/');
3034
2.45M
                        continue;
3035
2.45M
                    }
3036
13.0M
                    else if (nUTF32 == '|'
3037
20.6k
                             && (pPos == pEnd
3038
13.9k
                                 || *pPos == nFragmentDelimiter
3039
13.4k
                                 || *pPos == nSegmentDelimiter
3040
12.2k
                                 || *pPos == nAltSegmentDelimiter)
3041
8.59k
                             && rSynPath.getLength() - nSynPathBeforeLen == 2
3042
2.64k
                             && rtl::isAsciiAlpha(rSynPath[nSynPathBeforeLen + 1]))
3043
1.44k
                    {
3044
                        // A first segment of <ALPHA "|"> is translated to
3045
                        // <ALPHA ":">:
3046
1.44k
                        rSynPath.append(':');
3047
1.44k
                        continue;
3048
1.44k
                    }
3049
15.4M
                }
3050
13.5M
                appendUCS4(rSynPath, nUTF32, eEscapeType,
3051
13.5M
                           PART_PCHAR, eCharset, true);
3052
13.5M
            }
3053
1.12M
            if (rSynPath.getLength() - nSynPathBeforeLen == 0)
3054
15.1k
                rSynPath.append('/');
3055
1.12M
            break;
3056
1.12M
        }
3057
3058
1.84k
        case INetProtocol::Mailto:
3059
39.5k
            while (pPos < pEnd && *pPos != nQueryDelimiter
3060
37.6k
                   && *pPos != nFragmentDelimiter)
3061
37.6k
            {
3062
37.6k
                EscapeType eEscapeType;
3063
37.6k
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3064
37.6k
                                             eCharset, eEscapeType);
3065
37.6k
                appendUCS4(rSynPath, nUTF32, eEscapeType,
3066
37.6k
                           PART_MAILTO, eCharset, true);
3067
37.6k
            }
3068
1.84k
            break;
3069
3070
3071
68.9k
        case INetProtocol::PrivSoffice:
3072
70.3k
        case INetProtocol::Hid:
3073
70.3k
        case INetProtocol::Macro:
3074
70.3k
        case INetProtocol::Uno:
3075
70.3k
        case INetProtocol::Component:
3076
70.6k
        case INetProtocol::Ldap:
3077
489k
            while (pPos < pEnd && *pPos != nQueryDelimiter
3078
418k
                   && *pPos != nFragmentDelimiter)
3079
418k
            {
3080
418k
                EscapeType eEscapeType;
3081
418k
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3082
418k
                                             eCharset, eEscapeType);
3083
418k
                appendUCS4(rSynPath, nUTF32, eEscapeType,
3084
418k
                           PART_PATH_BEFORE_QUERY, eCharset, true);
3085
418k
            }
3086
70.6k
            break;
3087
3088
0
        case INetProtocol::VndSunStarHelp:
3089
0
            if (pPos == pEnd
3090
0
                || *pPos == nQueryDelimiter
3091
0
                || *pPos == nFragmentDelimiter)
3092
0
                rSynPath.append('/');
3093
0
            else
3094
0
            {
3095
0
                if (*pPos != '/')
3096
0
                    goto failed;
3097
0
                while (pPos < pEnd && *pPos != nQueryDelimiter
3098
0
                       && *pPos != nFragmentDelimiter)
3099
0
                {
3100
0
                    EscapeType eEscapeType;
3101
0
                    sal_uInt32 nUTF32 = getUTF32(pPos, pEnd,
3102
0
                                                 eMechanism,
3103
0
                                                 eCharset, eEscapeType);
3104
0
                    appendUCS4(rSynPath, nUTF32, eEscapeType,
3105
0
                               PART_HTTP_PATH, eCharset, true);
3106
0
                }
3107
0
            }
3108
0
            break;
3109
3110
808
        case INetProtocol::Javascript:
3111
81.1k
        case INetProtocol::Data:
3112
82.0k
        case INetProtocol::Cid:
3113
82.6k
        case INetProtocol::Db:
3114
4.87M
            while (pPos < pEnd && *pPos != nFragmentDelimiter)
3115
4.78M
            {
3116
4.78M
                EscapeType eEscapeType;
3117
4.78M
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3118
4.78M
                                             eCharset, eEscapeType);
3119
4.78M
                appendUCS4(rSynPath, nUTF32, eEscapeType,
3120
4.78M
                           PART_URIC, eCharset, true);
3121
4.78M
            }
3122
82.6k
            break;
3123
3124
0
        case INetProtocol::VndSunStarHier:
3125
45
        case INetProtocol::VndSunStarPkg:
3126
45
            if (pPos < pEnd && *pPos != '/'
3127
0
                && *pPos != nQueryDelimiter && *pPos != nFragmentDelimiter)
3128
0
                goto failed;
3129
45
            while (pPos < pEnd && *pPos != nQueryDelimiter
3130
0
                   && *pPos != nFragmentDelimiter)
3131
0
            {
3132
0
                EscapeType eEscapeType;
3133
0
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3134
0
                                             eCharset, eEscapeType);
3135
0
                if (eEscapeType == EscapeType::NONE && nUTF32 == '/')
3136
0
                    rSynPath.append('/');
3137
0
                else
3138
0
                    appendUCS4(rSynPath, nUTF32, eEscapeType,
3139
0
                               PART_PCHAR, eCharset, false);
3140
0
            }
3141
45
            if (rSynPath.getLength() - nSynPathBeforeLen == 0)
3142
45
                rSynPath.append('/');
3143
45
            break;
3144
3145
0
        case INetProtocol::VndSunStarCmd:
3146
0
        case INetProtocol::VndSunStarExpand:
3147
0
        {
3148
0
            if (pPos == pEnd || *pPos == nFragmentDelimiter)
3149
0
                goto failed;
3150
0
            Part ePart = PART_URIC_NO_SLASH;
3151
0
            while (pPos != pEnd && *pPos != nFragmentDelimiter)
3152
0
            {
3153
0
                EscapeType eEscapeType;
3154
0
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3155
0
                                             eCharset, eEscapeType);
3156
0
                appendUCS4(rSynPath, nUTF32, eEscapeType, ePart,
3157
0
                           eCharset, true);
3158
0
                ePart = PART_URIC;
3159
0
            }
3160
0
            break;
3161
0
        }
3162
3163
1
        case INetProtocol::Telnet:
3164
1
            if (pPos < pEnd)
3165
0
            {
3166
0
                if (*pPos != '/' || pEnd - pPos > 1)
3167
0
                    goto failed;
3168
0
                ++pPos;
3169
0
            }
3170
1
            rSynPath.append('/');
3171
1
            break;
3172
3173
0
        case INetProtocol::VndSunStarTdoc:
3174
0
            if (pPos == pEnd || *pPos != '/')
3175
0
                goto failed;
3176
0
            while (pPos < pEnd && *pPos != nFragmentDelimiter)
3177
0
            {
3178
0
                EscapeType eEscapeType;
3179
0
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3180
0
                                             eCharset, eEscapeType);
3181
0
                if (eEscapeType == EscapeType::NONE && nUTF32 == '/')
3182
0
                    rSynPath.append('/');
3183
0
                else
3184
0
                    appendUCS4(rSynPath, nUTF32, eEscapeType,
3185
0
                               PART_PCHAR, eCharset, false);
3186
0
            }
3187
0
            break;
3188
3189
12.8k
        case INetProtocol::Generic:
3190
12.9k
        case INetProtocol::Sftp:
3191
438k
            while (pPos < pEnd && *pPos != nFragmentDelimiter)
3192
425k
            {
3193
425k
                EscapeType eEscapeType;
3194
425k
                sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, eMechanism,
3195
425k
                                             eCharset, eEscapeType);
3196
425k
                appendUCS4(rSynPath, nUTF32, eEscapeType,
3197
425k
                           PART_URIC, eCharset, true);
3198
425k
            }
3199
12.9k
            if (rSynPath.isEmpty())
3200
0
                goto failed;
3201
12.9k
            break;
3202
12.9k
        default:
3203
0
            OSL_ASSERT(false);
3204
0
            break;
3205
1.68M
    }
3206
3207
1.68M
    *pBegin = pPos;
3208
1.68M
    return true;
3209
591
failed:
3210
591
    rSynPath.setLength(nSynPathBeforeLen);
3211
591
    return false;
3212
1.68M
}
3213
3214
bool INetURLObject::setPath(std::u16string_view rThePath,
3215
                            EncodeMechanism eMechanism,
3216
                            rtl_TextEncoding eCharset)
3217
25.2k
{
3218
25.2k
    OUStringBuffer aSynPath(256);
3219
25.2k
    sal_Unicode const * p = rThePath.data();
3220
25.2k
    sal_Unicode const * pEnd = p + rThePath.size();
3221
25.2k
    if (!parsePath(m_eScheme, &p, pEnd, eMechanism, eCharset, false,
3222
25.2k
                   '/', 0x80000000, 0x80000000, 0x80000000, aSynPath)
3223
25.2k
        || p != pEnd)
3224
0
        return false;
3225
25.2k
    sal_Int32 nDelta = m_aPath.set(m_aAbsURIRef, aSynPath);
3226
25.2k
    m_aQuery += nDelta;
3227
25.2k
    m_aFragment += nDelta;
3228
25.2k
    return true;
3229
25.2k
}
3230
3231
188k
bool INetURLObject::checkHierarchical() const {
3232
188k
    if (m_eScheme == INetProtocol::VndSunStarExpand) {
3233
0
        OSL_FAIL(
3234
0
            "INetURLObject::checkHierarchical vnd.sun.star.expand");
3235
0
        return true;
3236
188k
    } else {
3237
188k
        return getSchemeInfo().m_bHierarchical;
3238
188k
    }
3239
188k
}
3240
3241
bool INetURLObject::Append(std::u16string_view rTheSegment,
3242
                           EncodeMechanism eMechanism,
3243
                           rtl_TextEncoding eCharset)
3244
439
{
3245
439
    return insertName(rTheSegment, false, LAST_SEGMENT, eMechanism, eCharset);
3246
439
}
3247
3248
INetURLObject::SubString INetURLObject::getSegment(sal_Int32 nIndex,
3249
                                                   bool bIgnoreFinalSlash)
3250
    const
3251
136k
{
3252
136k
    DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT,
3253
136k
               "INetURLObject::getSegment(): Bad index");
3254
3255
136k
    if (!checkHierarchical())
3256
15.9k
        return SubString();
3257
3258
120k
    sal_Unicode const * pPathBegin
3259
120k
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
3260
120k
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
3261
120k
    sal_Unicode const * pSegBegin;
3262
120k
    sal_Unicode const * pSegEnd;
3263
120k
    if (nIndex == LAST_SEGMENT)
3264
120k
    {
3265
120k
        pSegEnd = pPathEnd;
3266
120k
        if (bIgnoreFinalSlash && pSegEnd > pPathBegin && pSegEnd[-1] == '/')
3267
349
            --pSegEnd;
3268
120k
        if (pSegEnd <= pPathBegin)
3269
343
            return SubString();
3270
119k
        pSegBegin = pSegEnd - 1;
3271
1.00M
        while (pSegBegin > pPathBegin && *pSegBegin != '/')
3272
881k
            --pSegBegin;
3273
119k
    }
3274
174
    else
3275
174
    {
3276
174
        pSegBegin = pPathBegin;
3277
342
        while (nIndex-- > 0)
3278
168
            do
3279
1.02k
            {
3280
1.02k
                ++pSegBegin;
3281
1.02k
                if (pSegBegin >= pPathEnd)
3282
0
                    return SubString();
3283
1.02k
            }
3284
1.02k
            while (*pSegBegin != '/');
3285
174
        pSegEnd = pSegBegin + 1;
3286
1.18k
        while (pSegEnd < pPathEnd && *pSegEnd != '/')
3287
1.01k
            ++pSegEnd;
3288
174
    }
3289
3290
119k
    return SubString(pSegBegin - m_aAbsURIRef.getStr(),
3291
119k
                     pSegEnd - pSegBegin);
3292
120k
}
3293
3294
bool INetURLObject::insertName(std::u16string_view rTheName,
3295
                               bool bAppendFinalSlash, sal_Int32 nIndex,
3296
                               EncodeMechanism eMechanism,
3297
                               rtl_TextEncoding eCharset)
3298
7.33k
{
3299
7.33k
    DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT,
3300
7.33k
               "INetURLObject::insertName(): Bad index");
3301
3302
7.33k
    if (!checkHierarchical())
3303
414
        return false;
3304
3305
6.91k
    sal_Unicode const * pPathBegin
3306
6.91k
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
3307
6.91k
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
3308
6.91k
    sal_Unicode const * pPrefixEnd;
3309
6.91k
    bool bInsertSlash;
3310
6.91k
    sal_Unicode const * pSuffixBegin;
3311
6.91k
    if (nIndex == LAST_SEGMENT)
3312
6.91k
    {
3313
6.91k
        pPrefixEnd = pPathEnd;
3314
6.91k
        if (pPrefixEnd > pPathBegin &&
3315
6.91k
            pPrefixEnd[-1] == '/')
3316
6.47k
        {
3317
6.47k
            --pPrefixEnd;
3318
6.47k
        }
3319
6.91k
        bInsertSlash = bAppendFinalSlash;
3320
6.91k
        pSuffixBegin = pPathEnd;
3321
6.91k
    }
3322
0
    else if (nIndex == 0)
3323
0
    {
3324
0
        pPrefixEnd = pPathBegin;
3325
0
        bInsertSlash =
3326
0
            (pPathBegin < pPathEnd && *pPathBegin != '/') ||
3327
0
            (pPathBegin == pPathEnd && bAppendFinalSlash);
3328
0
        pSuffixBegin =
3329
0
            (pPathEnd - pPathBegin == 1 && *pPathBegin == '/' &&
3330
0
             !bAppendFinalSlash)
3331
0
            ? pPathEnd : pPathBegin;
3332
0
    }
3333
0
    else
3334
0
    {
3335
0
        pPrefixEnd = pPathBegin;
3336
0
        sal_Unicode const * pEnd = pPathEnd;
3337
0
        if (pEnd > pPathBegin && pEnd[-1] == '/')
3338
0
            --pEnd;
3339
0
        bool bSkip = pPrefixEnd < pEnd && *pPrefixEnd == '/';
3340
0
        bInsertSlash = false;
3341
0
        pSuffixBegin = pPathEnd;
3342
0
        while (nIndex-- > 0)
3343
0
            for (;;)
3344
0
            {
3345
0
                if (bSkip)
3346
0
                    ++pPrefixEnd;
3347
0
                bSkip = true;
3348
0
                if (pPrefixEnd >= pEnd)
3349
0
                {
3350
0
                    if (nIndex == 0)
3351
0
                    {
3352
0
                        bInsertSlash = bAppendFinalSlash;
3353
0
                        break;
3354
0
                    }
3355
0
                    else
3356
0
                        return false;
3357
0
                }
3358
0
                if (*pPrefixEnd == '/')
3359
0
                {
3360
0
                    pSuffixBegin = pPrefixEnd;
3361
0
                    break;
3362
0
                }
3363
0
            }
3364
0
    }
3365
3366
6.91k
    OUStringBuffer aNewPath(256);
3367
6.91k
    aNewPath.append(
3368
6.91k
        OUString::Concat(std::u16string_view(pPathBegin, pPrefixEnd - pPathBegin))
3369
6.91k
        + "/");
3370
6.91k
    encodeText(aNewPath, rTheName, PART_PCHAR,
3371
6.91k
               eMechanism, eCharset, true);
3372
6.91k
    if (bInsertSlash) {
3373
0
        aNewPath.append('/');
3374
0
    }
3375
6.91k
    aNewPath.append(pSuffixBegin, pPathEnd - pSuffixBegin);
3376
3377
6.91k
    return setPath(aNewPath, EncodeMechanism::NotCanonical,
3378
6.91k
        RTL_TEXTENCODING_UTF8);
3379
6.91k
}
3380
3381
void INetURLObject::clearQuery()
3382
167
{
3383
167
    if (HasError())
3384
0
        return;
3385
167
    if (m_aQuery.isPresent())
3386
67
    {
3387
67
        lcl_Erase(m_aAbsURIRef, m_aQuery.getBegin() - 1,
3388
67
            m_aQuery.getLength() + 1);
3389
67
        m_aFragment += m_aQuery.clear() - 1;
3390
67
    }
3391
167
}
3392
3393
bool INetURLObject::setQuery(std::u16string_view rTheQuery,
3394
                             EncodeMechanism eMechanism,
3395
                             rtl_TextEncoding eCharset)
3396
0
{
3397
0
    if (!getSchemeInfo().m_bQuery)
3398
0
        return false;
3399
0
    OUStringBuffer aNewQuery;
3400
0
    encodeText(aNewQuery, rTheQuery, PART_URIC,
3401
0
               eMechanism, eCharset, true);
3402
0
    sal_Int32 nDelta;
3403
0
    if (m_aQuery.isPresent())
3404
0
        nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery);
3405
0
    else
3406
0
    {
3407
0
        m_aAbsURIRef.insert(m_aPath.getEnd(), u'?');
3408
0
        nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery, m_aPath.getEnd() + 1)
3409
0
                     + 1;
3410
0
    }
3411
0
    m_aFragment += nDelta;
3412
0
    return true;
3413
0
}
3414
3415
bool INetURLObject::clearFragment()
3416
40.1k
{
3417
40.1k
    if (HasError())
3418
22.1k
        return false;
3419
17.9k
    if (m_aFragment.isPresent())
3420
2.90k
    {
3421
2.90k
        m_aAbsURIRef.setLength(m_aFragment.getBegin() - 1);
3422
2.90k
        m_aFragment.clear();
3423
2.90k
    }
3424
17.9k
    return true;
3425
40.1k
}
3426
3427
bool INetURLObject::setFragment(std::u16string_view rTheFragment,
3428
                                EncodeMechanism eMechanism,
3429
                                rtl_TextEncoding eCharset)
3430
6.86k
{
3431
6.86k
    if (HasError())
3432
6.86k
        return false;
3433
0
    OUStringBuffer aNewFragment;
3434
0
    encodeText(aNewFragment, rTheFragment, PART_URIC,
3435
0
              eMechanism, eCharset, true);
3436
0
    if (m_aFragment.isPresent())
3437
0
        m_aFragment.set(m_aAbsURIRef, aNewFragment);
3438
0
    else
3439
0
    {
3440
0
        m_aAbsURIRef.append('#');
3441
0
        m_aFragment.set(m_aAbsURIRef, aNewFragment, m_aAbsURIRef.getLength());
3442
0
    }
3443
0
    return true;
3444
6.86k
}
3445
3446
bool INetURLObject::hasDosVolume(FSysStyle eStyle) const
3447
0
{
3448
0
    sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
3449
0
    return (eStyle & FSysStyle::Dos)
3450
0
           && m_aPath.getLength() >= 3
3451
0
           && p[0] == '/'
3452
0
           && rtl::isAsciiAlpha(p[1])
3453
0
           && p[2] == ':'
3454
0
           && (m_aPath.getLength() == 3 || p[3] == '/');
3455
0
}
3456
3457
// static
3458
void INetURLObject::encodeText( OUStringBuffer& rOutputBuffer,
3459
                                sal_Unicode const * pBegin,
3460
                                sal_Unicode const * pEnd,
3461
                                Part ePart, EncodeMechanism eMechanism,
3462
                                rtl_TextEncoding eCharset,
3463
                                bool bKeepVisibleEscapes)
3464
6.96k
{
3465
57.8k
    while (pBegin < pEnd)
3466
50.9k
    {
3467
50.9k
        EscapeType eEscapeType;
3468
50.9k
        sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd,
3469
50.9k
                                     eMechanism, eCharset, eEscapeType);
3470
50.9k
        appendUCS4(rOutputBuffer, nUTF32, eEscapeType, ePart,
3471
50.9k
                   eCharset, bKeepVisibleEscapes);
3472
50.9k
    }
3473
6.96k
}
3474
3475
// static
3476
OUString INetURLObject::decode(sal_Unicode const * pBegin,
3477
                                sal_Unicode const * pEnd,
3478
                                DecodeMechanism eMechanism,
3479
                                rtl_TextEncoding eCharset)
3480
1.23M
{
3481
1.23M
    switch (eMechanism)
3482
1.23M
    {
3483
741k
        case DecodeMechanism::NONE:
3484
741k
            return OUString(pBegin, pEnd - pBegin);
3485
3486
353k
        case DecodeMechanism::ToIUri:
3487
353k
            eCharset = RTL_TEXTENCODING_UTF8;
3488
353k
            break;
3489
3490
140k
        default:
3491
140k
            break;
3492
1.23M
    }
3493
493k
    OUStringBuffer aResult(static_cast<int>(pEnd-pBegin));
3494
19.3M
    while (pBegin < pEnd)
3495
18.8M
    {
3496
18.8M
        EscapeType eEscapeType;
3497
18.8M
        sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd,
3498
18.8M
                                     EncodeMechanism::WasEncoded, eCharset, eEscapeType);
3499
18.8M
        switch (eEscapeType)
3500
18.8M
        {
3501
10.6M
            case EscapeType::NONE:
3502
10.6M
                aResult.appendUtf32(nUTF32);
3503
10.6M
                break;
3504
3505
5.00k
            case EscapeType::Octet:
3506
5.00k
                appendEscape(aResult, nUTF32);
3507
5.00k
                break;
3508
3509
8.15M
            case EscapeType::Utf32:
3510
8.15M
                if (
3511
8.15M
                     rtl::isAscii(nUTF32) &&
3512
4.71M
                     (
3513
4.71M
                       eMechanism == DecodeMechanism::ToIUri ||
3514
246k
                       (
3515
246k
                         eMechanism == DecodeMechanism::Unambiguous &&
3516
351
                         mustEncode(nUTF32, PART_UNAMBIGUOUS)
3517
246k
                       )
3518
4.71M
                     )
3519
8.15M
                   )
3520
4.47M
                {
3521
4.47M
                    appendEscape(aResult, nUTF32);
3522
4.47M
                }
3523
3.68M
                else
3524
3.68M
                    aResult.appendUtf32(nUTF32);
3525
8.15M
                break;
3526
18.8M
        }
3527
18.8M
    }
3528
493k
    return aResult.makeStringAndClear();
3529
493k
}
3530
3531
OUString INetURLObject::GetURLNoPass(DecodeMechanism eMechanism,
3532
                                      rtl_TextEncoding eCharset) const
3533
11.8k
{
3534
11.8k
    INetURLObject aTemp(*this);
3535
11.8k
    aTemp.clearPassword();
3536
11.8k
    return aTemp.GetMainURL(eMechanism, eCharset);
3537
11.8k
}
3538
3539
OUString INetURLObject::GetURLNoMark(DecodeMechanism eMechanism,
3540
                                      rtl_TextEncoding eCharset) const
3541
2.88k
{
3542
2.88k
    INetURLObject aTemp(*this);
3543
2.88k
    aTemp.clearFragment();
3544
2.88k
    return aTemp.GetMainURL(eMechanism, eCharset);
3545
2.88k
}
3546
3547
OUString
3548
INetURLObject::getAbbreviated(
3549
    uno::Reference< util::XStringWidth > const & rStringWidth,
3550
    sal_Int32 nWidth,
3551
    DecodeMechanism eMechanism,
3552
    rtl_TextEncoding eCharset)
3553
    const
3554
0
{
3555
0
    OSL_ENSURE(rStringWidth.is(), "specification violation");
3556
0
    OUStringBuffer aBuffer;
3557
    // make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme
3558
    // is empty ("") in that case, so take the scheme from m_aAbsURIRef
3559
0
    if (m_eScheme != INetProtocol::Generic)
3560
0
    {
3561
0
        aBuffer.append(getSchemeInfo().m_sScheme);
3562
0
    }
3563
0
    else
3564
0
    {
3565
0
        if (!m_aAbsURIRef.isEmpty())
3566
0
        {
3567
0
            sal_Unicode const * pSchemeBegin
3568
0
                = m_aAbsURIRef.getStr();
3569
0
            sal_Unicode const * pSchemeEnd = pSchemeBegin;
3570
3571
0
            while (pSchemeEnd[0] != ':')
3572
0
            {
3573
0
                ++pSchemeEnd;
3574
0
            }
3575
0
            aBuffer.append(pSchemeBegin, pSchemeEnd - pSchemeBegin);
3576
0
        }
3577
0
    }
3578
0
    aBuffer.append(':');
3579
0
    bool bAuthority = getSchemeInfo().m_bAuthority;
3580
0
    sal_Unicode const * pCoreBegin
3581
0
        = m_aAbsURIRef.getStr() + (bAuthority ? getAuthorityBegin() :
3582
0
                                                   m_aPath.getBegin());
3583
0
    sal_Unicode const * pCoreEnd
3584
0
        = m_aAbsURIRef.getStr() + m_aPath.getBegin() + m_aPath.getLength();
3585
0
    bool bSegment = false;
3586
0
    if (getSchemeInfo().m_bHierarchical)
3587
0
    {
3588
0
        OUString aRest;
3589
0
        if (m_aQuery.isPresent())
3590
0
            aRest = "?...";
3591
0
        else if (m_aFragment.isPresent())
3592
0
            aRest = "#...";
3593
0
        OUStringBuffer aTrailer;
3594
0
        sal_Unicode const * pBegin = pCoreBegin;
3595
0
        sal_Unicode const * pEnd = pCoreEnd;
3596
0
        sal_Unicode const * pPrefixBegin = pBegin;
3597
0
        sal_Unicode const * pSuffixEnd = pEnd;
3598
0
        bool bPrefix = true;
3599
0
        bool bSuffix = true;
3600
0
        do
3601
0
        {
3602
0
            if (bSuffix)
3603
0
            {
3604
0
                sal_Unicode const * p = pSuffixEnd - 1;
3605
0
                if (pSuffixEnd == pCoreEnd && *p == '/')
3606
0
                    --p;
3607
0
                while (*p != '/')
3608
0
                    --p;
3609
0
                if (bAuthority && p == pCoreBegin + 1)
3610
0
                    --p;
3611
0
                OUString
3612
0
                    aSegment(decode(p + (p == pBegin && pBegin != pCoreBegin ?
3613
0
                                             1 : 0),
3614
0
                                    pSuffixEnd,
3615
0
                                    eMechanism,
3616
0
                                    eCharset));
3617
0
                pSuffixEnd = p;
3618
0
                OUStringBuffer aResult(aBuffer);
3619
0
                if (pSuffixEnd != pBegin)
3620
0
                    aResult.append("...");
3621
0
                aResult.append(aSegment + aTrailer + aRest);
3622
0
                if (rStringWidth->
3623
0
                            queryStringWidth(aResult.makeStringAndClear())
3624
0
                        <= nWidth)
3625
0
                {
3626
0
                    aTrailer.insert(0, aSegment);
3627
0
                    bSegment = true;
3628
0
                    pEnd = pSuffixEnd;
3629
0
                }
3630
0
                else
3631
0
                    bSuffix = false;
3632
0
                if (pPrefixBegin > pSuffixEnd)
3633
0
                    pPrefixBegin = pSuffixEnd;
3634
0
                if (pBegin == pEnd)
3635
0
                    break;
3636
0
            }
3637
0
            if (bPrefix)
3638
0
            {
3639
0
                sal_Unicode const * p
3640
0
                    = pPrefixBegin
3641
0
                          + (bAuthority && pPrefixBegin == pCoreBegin ? 2 :
3642
0
                                                                        1);
3643
0
                OSL_ASSERT(p <= pEnd);
3644
0
                while (p < pEnd && *p != '/')
3645
0
                    ++p;
3646
0
                if (p == pCoreEnd - 1 && *p == '/')
3647
0
                    ++p;
3648
0
                OUString
3649
0
                    aSegment(decode(pPrefixBegin
3650
0
                                        + (pPrefixBegin == pCoreBegin ? 0 :
3651
0
                                                                        1),
3652
0
                                    p == pEnd ? p : p + 1,
3653
0
                                    eMechanism,
3654
0
                                    eCharset));
3655
0
                pPrefixBegin = p;
3656
0
                OUStringBuffer aResult(aBuffer + aSegment);
3657
0
                if (pPrefixBegin != pEnd)
3658
0
                    aResult.append("...");
3659
0
                aResult.append(aTrailer + aRest);
3660
0
                if (rStringWidth->
3661
0
                            queryStringWidth(aResult.makeStringAndClear())
3662
0
                        <= nWidth)
3663
0
                {
3664
0
                    aBuffer.append(aSegment);
3665
0
                    bSegment = true;
3666
0
                    pBegin = pPrefixBegin;
3667
0
                }
3668
0
                else
3669
0
                    bPrefix = false;
3670
0
                if (pPrefixBegin > pSuffixEnd)
3671
0
                    pSuffixEnd = pPrefixBegin;
3672
0
                if (pBegin == pEnd)
3673
0
                    break;
3674
0
            }
3675
0
        }
3676
0
        while (bPrefix || bSuffix);
3677
0
        if (bSegment)
3678
0
        {
3679
0
            if (pPrefixBegin != pBegin || pSuffixEnd != pEnd)
3680
0
                aBuffer.append("...");
3681
0
            aBuffer.append(aTrailer);
3682
0
        }
3683
0
    }
3684
0
    if (!bSegment)
3685
0
        aBuffer.append(decode(pCoreBegin,
3686
0
                              pCoreEnd,
3687
0
                              eMechanism,
3688
0
                              eCharset));
3689
0
    if (m_aQuery.isPresent())
3690
0
    {
3691
0
        aBuffer.append("?" + decode(m_aQuery, eMechanism, eCharset));
3692
0
    }
3693
0
    if (m_aFragment.isPresent())
3694
0
    {
3695
0
        aBuffer.append("#" + decode(m_aFragment, eMechanism, eCharset));
3696
0
    }
3697
0
    if (!aBuffer.isEmpty())
3698
0
    {
3699
0
        OUStringBuffer aResult(aBuffer);
3700
0
        if (rStringWidth->queryStringWidth(aResult.makeStringAndClear())
3701
0
                > nWidth)
3702
0
            for (sal_Int32 i = aBuffer.getLength();;)
3703
0
            {
3704
0
                if (i == 0)
3705
0
                {
3706
0
                    aBuffer.setLength(aBuffer.getLength() - 1);
3707
0
                    if (aBuffer.isEmpty())
3708
0
                        break;
3709
0
                }
3710
0
                else
3711
0
                {
3712
0
                    aBuffer.setLength(--i);
3713
0
                    aBuffer.append("...");
3714
0
                }
3715
0
                aResult = aBuffer;
3716
0
                if (rStringWidth->
3717
0
                            queryStringWidth(aResult.makeStringAndClear())
3718
0
                        <= nWidth)
3719
0
                    break;
3720
0
            }
3721
0
    }
3722
0
    return aBuffer.makeStringAndClear();
3723
0
}
3724
3725
bool INetURLObject::operator ==(INetURLObject const & rObject) const
3726
0
{
3727
0
    if (m_eScheme != rObject.m_eScheme)
3728
0
        return false;
3729
0
    if (m_eScheme == INetProtocol::NotValid)
3730
0
        return std::u16string_view(m_aAbsURIRef) == std::u16string_view(rObject.m_aAbsURIRef);
3731
0
    if ((m_aScheme.compare(
3732
0
             rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef)
3733
0
         != 0)
3734
0
        || GetUser(DecodeMechanism::NONE) != rObject.GetUser(DecodeMechanism::NONE)
3735
0
        || GetPass(DecodeMechanism::NONE) != rObject.GetPass(DecodeMechanism::NONE)
3736
0
        || !GetHost(DecodeMechanism::NONE).equalsIgnoreAsciiCase(
3737
0
            rObject.GetHost(DecodeMechanism::NONE))
3738
0
        || GetPort() != rObject.GetPort()
3739
0
        || HasParam() != rObject.HasParam()
3740
0
        || GetParam() != rObject.GetParam())
3741
0
        return false;
3742
0
    OUString aPath1(GetURLPath(DecodeMechanism::NONE));
3743
0
    OUString aPath2(rObject.GetURLPath(DecodeMechanism::NONE));
3744
0
    switch (m_eScheme)
3745
0
    {
3746
0
        case INetProtocol::File:
3747
0
        {
3748
            // If the URL paths of two file URLs only differ in that one has a
3749
            // final '/' and the other has not, take the two paths as
3750
            // equivalent (this could be useful for other schemes, too):
3751
0
            sal_Int32 nLength = aPath1.getLength();
3752
0
            switch (nLength - aPath2.getLength())
3753
0
            {
3754
0
                case -1:
3755
0
                    if (aPath2[nLength] != '/')
3756
0
                        return false;
3757
0
                    break;
3758
3759
0
                case 0:
3760
0
                    break;
3761
3762
0
                case 1:
3763
0
                    if (aPath1[--nLength] != '/')
3764
0
                        return false;
3765
0
                    break;
3766
3767
0
                default:
3768
0
                    return false;
3769
0
            }
3770
0
            return aPath1.compareTo(aPath2, nLength) == 0;
3771
0
        }
3772
3773
0
        default:
3774
0
            return aPath1 == aPath2;
3775
0
    }
3776
0
}
3777
3778
bool INetURLObject::ConcatData(INetProtocol eTheScheme,
3779
                               std::u16string_view rTheUser,
3780
                               std::u16string_view rThePassword,
3781
                               std::u16string_view rTheHost,
3782
                               sal_uInt32 nThePort,
3783
                               std::u16string_view rThePath)
3784
0
{
3785
0
    setInvalid();
3786
0
    m_eScheme = eTheScheme;
3787
0
    if (HasError() || m_eScheme == INetProtocol::Generic)
3788
0
        return false;
3789
0
    m_aAbsURIRef.setLength(0);
3790
0
    m_aAbsURIRef.append(getSchemeInfo().m_sScheme);
3791
0
    m_aAbsURIRef.append(':');
3792
0
    if (getSchemeInfo().m_bAuthority)
3793
0
    {
3794
0
        m_aAbsURIRef.append("//");
3795
0
        bool bUserInfo = false;
3796
0
        if (getSchemeInfo().m_bUser)
3797
0
        {
3798
0
            if (!rTheUser.empty())
3799
0
            {
3800
0
                OUStringBuffer aNewUser;
3801
0
                encodeText(aNewUser, rTheUser, PART_USER_PASSWORD,
3802
0
                           EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, false);
3803
0
                m_aUser.set(m_aAbsURIRef, aNewUser, m_aAbsURIRef.getLength());
3804
0
                bUserInfo = true;
3805
0
            }
3806
0
        }
3807
0
        else if (!rTheUser.empty())
3808
0
        {
3809
0
            setInvalid();
3810
0
            return false;
3811
0
        }
3812
0
        if (!rThePassword.empty())
3813
0
        {
3814
0
            if (getSchemeInfo().m_bPassword)
3815
0
            {
3816
0
                m_aAbsURIRef.append(':');
3817
0
                OUStringBuffer aNewAuth;
3818
0
                encodeText(aNewAuth, rThePassword, PART_USER_PASSWORD,
3819
0
                           EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, false);
3820
0
                m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aAbsURIRef.getLength());
3821
0
                bUserInfo = true;
3822
0
            }
3823
0
            else
3824
0
            {
3825
0
                setInvalid();
3826
0
                return false;
3827
0
            }
3828
0
        }
3829
0
        if (bUserInfo && getSchemeInfo().m_bHost)
3830
0
            m_aAbsURIRef.append('@');
3831
0
        if (getSchemeInfo().m_bHost)
3832
0
        {
3833
0
            OUStringBuffer aSynHost(rTheHost);
3834
0
            bool bNetBiosName = false;
3835
0
            switch (m_eScheme)
3836
0
            {
3837
0
                case INetProtocol::File:
3838
0
                    {
3839
0
                        if (OUString::unacquired(aSynHost).equalsIgnoreAsciiCase( "localhost" ))
3840
0
                        {
3841
0
                            aSynHost.setLength(0);
3842
0
                        }
3843
0
                        bNetBiosName = true;
3844
0
                    }
3845
0
                    break;
3846
3847
0
                case INetProtocol::Ldap:
3848
0
                    if (aSynHost.isEmpty() && nThePort != 0)
3849
0
                    {
3850
0
                        setInvalid();
3851
0
                        return false;
3852
0
                    }
3853
0
                    break;
3854
3855
0
                default:
3856
0
                    if (aSynHost.isEmpty())
3857
0
                    {
3858
0
                        setInvalid();
3859
0
                        return false;
3860
0
                    }
3861
0
                    break;
3862
0
            }
3863
0
            if (!parseHostOrNetBiosName(
3864
0
                    aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(),
3865
0
                    EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, bNetBiosName, &aSynHost))
3866
0
            {
3867
0
                setInvalid();
3868
0
                return false;
3869
0
            }
3870
0
            m_aHost.set(m_aAbsURIRef, aSynHost, m_aAbsURIRef.getLength());
3871
0
            if (nThePort != 0)
3872
0
            {
3873
0
                if (getSchemeInfo().m_bPort)
3874
0
                {
3875
0
                    m_aAbsURIRef.append(':');
3876
0
                    m_aPort.set(m_aAbsURIRef,
3877
0
                                OUString::number(nThePort),
3878
0
                                m_aAbsURIRef.getLength());
3879
0
                }
3880
0
                else
3881
0
                {
3882
0
                    setInvalid();
3883
0
                    return false;
3884
0
                }
3885
0
            }
3886
0
        }
3887
0
        else if (!rTheHost.empty() || nThePort != 0)
3888
0
        {
3889
0
            setInvalid();
3890
0
            return false;
3891
0
        }
3892
0
    }
3893
0
    OUStringBuffer aSynPath(256);
3894
0
    sal_Unicode const * p = rThePath.data();
3895
0
    sal_Unicode const * pEnd = p + rThePath.size();
3896
0
    if (!parsePath(m_eScheme, &p, pEnd, EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, false, '/',
3897
0
                   0x80000000, 0x80000000, 0x80000000, aSynPath)
3898
0
        || p != pEnd)
3899
0
    {
3900
0
        setInvalid();
3901
0
        return false;
3902
0
    }
3903
0
    m_aPath.set(m_aAbsURIRef, aSynPath, m_aAbsURIRef.getLength());
3904
0
    return true;
3905
0
}
3906
3907
// static
3908
OUString INetURLObject::GetAbsURL(std::u16string_view rTheBaseURIRef,
3909
                                       OUString const & rTheRelURIRef,
3910
                                       EncodeMechanism eEncodeMechanism,
3911
                                       DecodeMechanism eDecodeMechanism,
3912
                                       rtl_TextEncoding eCharset)
3913
85.4k
{
3914
    // Backwards compatibility:
3915
85.4k
    if (rTheRelURIRef.isEmpty() || rTheRelURIRef[0] == '#')
3916
1.36k
        return rTheRelURIRef;
3917
3918
84.1k
    INetURLObject aTheAbsURIRef;
3919
84.1k
    bool bWasAbsolute;
3920
84.1k
    return INetURLObject(rTheBaseURIRef, eEncodeMechanism, eCharset).
3921
84.1k
            convertRelToAbs(rTheRelURIRef, aTheAbsURIRef,
3922
84.1k
                            bWasAbsolute, eEncodeMechanism,
3923
84.1k
                            eCharset, false, false,
3924
84.1k
                            false, FSysStyle::Detect)
3925
37.2k
           || eEncodeMechanism != EncodeMechanism::WasEncoded
3926
37.2k
           || eDecodeMechanism != DecodeMechanism::ToIUri
3927
37.2k
           || eCharset != RTL_TEXTENCODING_UTF8 ?
3928
46.9k
               aTheAbsURIRef.GetMainURL(eDecodeMechanism, eCharset) :
3929
84.1k
               rTheRelURIRef;
3930
85.4k
}
3931
3932
OUString INetURLObject::getExternalURL() const
3933
0
{
3934
0
    OUString aTheExtURIRef;
3935
0
    translateToExternal(
3936
0
        m_aAbsURIRef, aTheExtURIRef);
3937
0
    return aTheExtURIRef;
3938
0
}
3939
3940
76.4k
bool INetURLObject::isSchemeEqualTo(std::u16string_view scheme) const {
3941
76.4k
    return m_aScheme.isPresent()
3942
11.5k
        && (rtl_ustr_compareIgnoreAsciiCase_WithLength(
3943
11.5k
                scheme.data(), scheme.size(),
3944
11.5k
                m_aAbsURIRef.getStr() + m_aScheme.getBegin(),
3945
11.5k
                m_aScheme.getLength())
3946
11.5k
            == 0);
3947
76.4k
}
3948
3949
25.7k
bool INetURLObject::isAnyKnownWebDAVScheme() const {
3950
25.7k
    return ( isSchemeEqualTo( INetProtocol::Http ) ||
3951
22.3k
             isSchemeEqualTo( INetProtocol::Https ) ||
3952
21.9k
             isSchemeEqualTo( INetProtocol::VndSunStarWebdav ) ||
3953
21.9k
             isSchemeEqualTo( u"vnd.sun.star.webdavs" ) ||
3954
21.9k
             isSchemeEqualTo( u"webdav" ) ||
3955
21.9k
             isSchemeEqualTo( u"webdavs" ));
3956
25.7k
}
3957
3958
// static
3959
const OUString & INetURLObject::GetScheme(INetProtocol eTheScheme)
3960
167
{
3961
167
    return getSchemeInfo(eTheScheme).m_aPrefix;
3962
167
}
3963
3964
// static
3965
const OUString & INetURLObject::GetSchemeName(INetProtocol eTheScheme)
3966
0
{
3967
0
    return getSchemeInfo(eTheScheme).m_sScheme;
3968
0
}
3969
3970
// static
3971
INetProtocol INetURLObject::CompareProtocolScheme(std::u16string_view aTheAbsURIRef)
3972
1.30M
{
3973
1.30M
    sal_Unicode const * p = aTheAbsURIRef.data();
3974
1.30M
    PrefixInfo const * pPrefix = getPrefix(p, p + aTheAbsURIRef.size());
3975
1.30M
    return pPrefix ? pPrefix->m_eScheme : INetProtocol::NotValid;
3976
1.30M
}
3977
3978
OUString INetURLObject::GetHostPort(DecodeMechanism eMechanism,
3979
                                     rtl_TextEncoding eCharset) const
3980
0
{
3981
    // Check because PROT_VND_SUN_STAR_HELP, PROT_VND_SUN_STAR_HIER, and
3982
    // PROT_VND_SUN_STAR_PKG misuse m_aHost:
3983
0
    if (!getSchemeInfo().m_bHost)
3984
0
        return OUString();
3985
0
    OUStringBuffer aHostPort(decode(m_aHost, eMechanism, eCharset));
3986
0
    if (m_aPort.isPresent())
3987
0
    {
3988
0
        aHostPort.append(":" + decode(m_aPort, eMechanism, eCharset));
3989
0
    }
3990
0
    return aHostPort.makeStringAndClear();
3991
0
}
3992
3993
sal_uInt32 INetURLObject::GetPort() const
3994
167
{
3995
167
    if (m_aPort.isPresent())
3996
0
    {
3997
0
        sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin();
3998
0
        sal_Unicode const * pEnd = p + m_aPort.getLength();
3999
0
        sal_uInt32 nThePort;
4000
0
        if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd)
4001
0
            return nThePort;
4002
0
    }
4003
167
    return 0;
4004
167
}
4005
4006
bool INetURLObject::SetPort(sal_uInt32 nThePort)
4007
112k
{
4008
112k
    if (getSchemeInfo().m_bPort && m_aHost.isPresent())
4009
112k
    {
4010
112k
        sal_Int32 nDelta;
4011
112k
        if (m_aPort.isPresent())
4012
0
            nDelta = m_aPort.set(m_aAbsURIRef, OUString::number(nThePort));
4013
112k
        else
4014
112k
        {
4015
112k
            m_aAbsURIRef.insert(m_aHost.getEnd(), u':');
4016
112k
            nDelta = m_aPort.set(m_aAbsURIRef, OUString::number(nThePort), m_aHost.getEnd() + 1)
4017
112k
                         + 1;
4018
112k
        }
4019
112k
        m_aPath += nDelta;
4020
112k
        m_aQuery += nDelta;
4021
112k
        m_aFragment += nDelta;
4022
112k
        return true;
4023
112k
    }
4024
0
    return false;
4025
112k
}
4026
4027
sal_Int32 INetURLObject::getSegmentCount(bool bIgnoreFinalSlash) const
4028
167
{
4029
167
    if (!checkHierarchical())
4030
15
        return 0;
4031
4032
152
    sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4033
152
    sal_Unicode const * pEnd = p + m_aPath.getLength();
4034
152
    if (bIgnoreFinalSlash && pEnd > p && pEnd[-1] == '/')
4035
0
        --pEnd;
4036
152
    sal_Int32 n = p == pEnd || *p == '/' ? 0 : 1;
4037
3.56k
    while (p != pEnd)
4038
3.41k
        if (*p++ == '/')
4039
326
            ++n;
4040
152
    return n;
4041
167
}
4042
4043
bool INetURLObject::removeSegment(sal_Int32 nIndex, bool bIgnoreFinalSlash)
4044
9.17k
{
4045
9.17k
    SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4046
9.17k
    if (!aSegment.isPresent())
4047
0
        return false;
4048
4049
9.17k
    OUStringBuffer aNewPath(m_aPath.getLength());
4050
9.17k
    aNewPath.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(),
4051
9.17k
                       aSegment.getBegin() - m_aPath.getBegin());
4052
9.17k
    if (bIgnoreFinalSlash && aSegment.getEnd() == m_aPath.getEnd())
4053
9.17k
        aNewPath.append('/');
4054
0
    else
4055
0
        aNewPath.append(m_aAbsURIRef.getStr() + aSegment.getEnd(),
4056
0
                        m_aPath.getEnd() - aSegment.getEnd());
4057
9.17k
    if (aNewPath.isEmpty() && !aSegment.isEmpty() &&
4058
0
        m_aAbsURIRef[aSegment.getBegin()] == '/')
4059
0
    {
4060
0
        aNewPath.append('/');
4061
0
    }
4062
4063
9.17k
    return setPath(aNewPath, EncodeMechanism::NotCanonical,
4064
9.17k
        RTL_TEXTENCODING_UTF8);
4065
9.17k
}
4066
4067
OUString INetURLObject::getName(sal_Int32 nIndex, bool bIgnoreFinalSlash,
4068
                                 DecodeMechanism eMechanism,
4069
                                 rtl_TextEncoding eCharset) const
4070
386
{
4071
386
    SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4072
386
    if (!aSegment.isPresent())
4073
60
        return OUString();
4074
4075
326
    sal_Unicode const * pSegBegin
4076
326
        = m_aAbsURIRef.getStr() + aSegment.getBegin();
4077
326
    sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4078
4079
326
    if (pSegBegin < pSegEnd && *pSegBegin == '/')
4080
326
        ++pSegBegin;
4081
326
    sal_Unicode const * p = pSegBegin;
4082
3.41k
    while (p != pSegEnd && *p != ';')
4083
3.08k
        ++p;
4084
4085
326
    return decode(pSegBegin, p, eMechanism, eCharset);
4086
386
}
4087
4088
bool INetURLObject::setName(std::u16string_view rTheName, EncodeMechanism eMechanism,
4089
                            rtl_TextEncoding eCharset)
4090
0
{
4091
0
    SubString aSegment(getSegment(LAST_SEGMENT, true));
4092
0
    if (!aSegment.isPresent())
4093
0
        return false;
4094
4095
0
    sal_Unicode const * pPathBegin
4096
0
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4097
0
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4098
0
    sal_Unicode const * pSegBegin
4099
0
        = m_aAbsURIRef.getStr() + aSegment.getBegin();
4100
0
    sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4101
4102
0
    if (pSegBegin < pSegEnd && *pSegBegin == '/')
4103
0
        ++pSegBegin;
4104
0
    sal_Unicode const * p = pSegBegin;
4105
0
    while (p != pSegEnd && *p != ';')
4106
0
        ++p;
4107
4108
0
    OUStringBuffer aNewPath(256);
4109
0
    aNewPath.append(std::u16string_view(pPathBegin, pSegBegin - pPathBegin));
4110
0
    encodeText(aNewPath, rTheName, PART_PCHAR, eMechanism, eCharset, true);
4111
0
    aNewPath.append(std::u16string_view(p, pPathEnd - p));
4112
0
    return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8);
4113
0
}
4114
4115
bool INetURLObject::hasExtension()
4116
    const
4117
0
{
4118
0
    SubString aSegment(getSegment(LAST_SEGMENT, true/*bIgnoreFinalSlash*/));
4119
0
    if (!aSegment.isPresent())
4120
0
        return false;
4121
4122
0
    sal_Unicode const * pSegBegin
4123
0
        = m_aAbsURIRef.getStr() + aSegment.getBegin();
4124
0
    sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4125
4126
0
    if (pSegBegin < pSegEnd && *pSegBegin == '/')
4127
0
        ++pSegBegin;
4128
0
    for (sal_Unicode const * p = pSegBegin; p != pSegEnd && *p != ';'; ++p)
4129
0
        if (*p == '.' && p != pSegBegin)
4130
0
            return true;
4131
0
    return false;
4132
0
}
4133
4134
OUString INetURLObject::getBase(sal_Int32 nIndex, bool bIgnoreFinalSlash,
4135
                                 DecodeMechanism eMechanism,
4136
                                 rtl_TextEncoding eCharset) const
4137
24.9k
{
4138
24.9k
    SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4139
24.9k
    if (!aSegment.isPresent())
4140
15.1k
        return OUString();
4141
4142
9.85k
    sal_Unicode const * pSegBegin
4143
9.85k
        = m_aAbsURIRef.getStr() + aSegment.getBegin();
4144
9.85k
    sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4145
4146
9.85k
    if (pSegBegin < pSegEnd && *pSegBegin == '/')
4147
9.85k
        ++pSegBegin;
4148
9.85k
    sal_Unicode const * pExtension = nullptr;
4149
9.85k
    sal_Unicode const * p = pSegBegin;
4150
334k
    for (; p != pSegEnd && *p != ';'; ++p)
4151
324k
        if (*p == '.' && p != pSegBegin)
4152
9.74k
            pExtension = p;
4153
9.85k
    if (!pExtension)
4154
138
        pExtension = p;
4155
4156
9.85k
    return decode(pSegBegin, pExtension, eMechanism, eCharset);
4157
24.9k
}
4158
4159
bool INetURLObject::setBase(std::u16string_view rTheBase, sal_Int32 nIndex,
4160
                            EncodeMechanism eMechanism,
4161
                            rtl_TextEncoding eCharset)
4162
0
{
4163
0
    SubString aSegment(getSegment(nIndex, true/*bIgnoreFinalSlash*/));
4164
0
    if (!aSegment.isPresent())
4165
0
        return false;
4166
4167
0
    sal_Unicode const * pPathBegin
4168
0
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4169
0
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4170
0
    sal_Unicode const * pSegBegin
4171
0
        = m_aAbsURIRef.getStr() + aSegment.getBegin();
4172
0
    sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4173
4174
0
    if (pSegBegin < pSegEnd && *pSegBegin == '/')
4175
0
        ++pSegBegin;
4176
0
    sal_Unicode const * pExtension = nullptr;
4177
0
    sal_Unicode const * p = pSegBegin;
4178
0
    for (; p != pSegEnd && *p != ';'; ++p)
4179
0
        if (*p == '.' && p != pSegBegin)
4180
0
            pExtension = p;
4181
0
    if (!pExtension)
4182
0
        pExtension = p;
4183
4184
0
    OUStringBuffer aNewPath(256);
4185
0
    aNewPath.append(std::u16string_view(pPathBegin, pSegBegin - pPathBegin));
4186
0
    encodeText(aNewPath, rTheBase, PART_PCHAR, eMechanism, eCharset, true);
4187
0
    aNewPath.append(std::u16string_view(pExtension, pPathEnd - pExtension));
4188
0
    return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8);
4189
0
}
4190
4191
OUString INetURLObject::getExtension(sal_Int32 nIndex,
4192
                                      bool bIgnoreFinalSlash,
4193
                                      DecodeMechanism eMechanism,
4194
                                      rtl_TextEncoding eCharset) const
4195
101k
{
4196
101k
    SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4197
101k
    if (!aSegment.isPresent())
4198
660
        return OUString();
4199
4200
100k
    sal_Unicode const * pSegBegin
4201
100k
        = m_aAbsURIRef.getStr() + aSegment.getBegin();
4202
100k
    sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4203
4204
100k
    if (pSegBegin < pSegEnd && *pSegBegin == '/')
4205
100k
        ++pSegBegin;
4206
100k
    sal_Unicode const * pExtension = nullptr;
4207
100k
    sal_Unicode const * p = pSegBegin;
4208
608k
    for (; p != pSegEnd && *p != ';'; ++p)
4209
508k
        if (*p == '.' && p != pSegBegin)
4210
100k
            pExtension = p;
4211
4212
100k
    if (!pExtension)
4213
91
        return OUString();
4214
4215
100k
    return decode(pExtension + 1, p, eMechanism, eCharset);
4216
100k
}
4217
4218
bool INetURLObject::setExtension(std::u16string_view rTheExtension,
4219
                                 sal_Int32 nIndex, bool bIgnoreFinalSlash,
4220
                                 rtl_TextEncoding eCharset)
4221
414
{
4222
414
    SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4223
414
    if (!aSegment.isPresent())
4224
414
        return false;
4225
4226
0
    sal_Unicode const * pPathBegin
4227
0
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4228
0
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4229
0
    sal_Unicode const * pSegBegin
4230
0
        = m_aAbsURIRef.getStr() + aSegment.getBegin();
4231
0
    sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4232
4233
0
    if (pSegBegin < pSegEnd && *pSegBegin == '/')
4234
0
        ++pSegBegin;
4235
0
    sal_Unicode const * pExtension = nullptr;
4236
0
    sal_Unicode const * p = pSegBegin;
4237
0
    for (; p != pSegEnd && *p != ';'; ++p)
4238
0
        if (*p == '.' && p != pSegBegin)
4239
0
            pExtension = p;
4240
0
    if (!pExtension)
4241
0
        pExtension = p;
4242
4243
0
    OUStringBuffer aNewPath(256);
4244
0
    aNewPath.append(OUString::Concat(std::u16string_view(pPathBegin, pExtension - pPathBegin)) + ".");
4245
0
    encodeText(aNewPath, rTheExtension, PART_PCHAR, EncodeMechanism::WasEncoded, eCharset, true);
4246
0
    aNewPath.append(std::u16string_view(p, pPathEnd - p));
4247
0
    return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8);
4248
414
}
4249
4250
bool INetURLObject::removeExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash)
4251
0
{
4252
0
    SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4253
0
    if (!aSegment.isPresent())
4254
0
        return false;
4255
4256
0
    sal_Unicode const * pPathBegin
4257
0
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4258
0
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4259
0
    sal_Unicode const * pSegBegin
4260
0
        = m_aAbsURIRef.getStr() + aSegment.getBegin();
4261
0
    sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4262
4263
0
    if (pSegBegin < pSegEnd && *pSegBegin == '/')
4264
0
        ++pSegBegin;
4265
0
    sal_Unicode const * pExtension = nullptr;
4266
0
    sal_Unicode const * p = pSegBegin;
4267
0
    for (; p != pSegEnd && *p != ';'; ++p)
4268
0
        if (*p == '.' && p != pSegBegin)
4269
0
            pExtension = p;
4270
0
    if (!pExtension)
4271
0
        return true;
4272
4273
0
    OUString aNewPath =
4274
0
        OUString::Concat(std::u16string_view(pPathBegin, pExtension - pPathBegin)) +
4275
0
        std::u16string_view(p, pPathEnd - p);
4276
4277
0
    return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8);
4278
0
}
4279
4280
bool INetURLObject::hasFinalSlash() const
4281
200
{
4282
200
    if (!checkHierarchical())
4283
42
        return false;
4284
4285
158
    sal_Unicode const * pPathBegin
4286
158
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4287
158
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4288
158
    return pPathEnd > pPathBegin && pPathEnd[-1] == '/';
4289
200
}
4290
4291
bool INetURLObject::setFinalSlash()
4292
0
{
4293
0
    if (!checkHierarchical())
4294
0
        return false;
4295
4296
0
    sal_Unicode const * pPathBegin
4297
0
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4298
0
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4299
0
    if (pPathEnd > pPathBegin && pPathEnd[-1] == '/')
4300
0
        return true;
4301
4302
0
    OUString aNewPath
4303
0
        = OUString::Concat(std::u16string_view(pPathBegin, pPathEnd - pPathBegin)) + "/";
4304
4305
0
    return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8);
4306
0
}
4307
4308
bool INetURLObject::removeFinalSlash()
4309
43.7k
{
4310
43.7k
    if (!checkHierarchical())
4311
0
        return false;
4312
4313
43.7k
    sal_Unicode const * pPathBegin
4314
43.7k
        = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4315
43.7k
    sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4316
43.7k
    if (pPathEnd <= pPathBegin || pPathEnd[-1] != '/')
4317
34.5k
        return true;
4318
4319
9.17k
    --pPathEnd;
4320
9.17k
    if (pPathEnd == pPathBegin && *pPathBegin == '/')
4321
0
        return false;
4322
9.17k
    OUString aNewPath(pPathBegin, pPathEnd - pPathBegin);
4323
4324
9.17k
    return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8);
4325
9.17k
}
4326
4327
OUString INetURLObject::getFSysPath(FSysStyle eStyle,
4328
                                     sal_Unicode * pDelimiter) const
4329
3.73k
{
4330
3.73k
    if (m_eScheme != INetProtocol::File)
4331
3.73k
        return OUString();
4332
4333
0
    if (((eStyle & FSysStyle::Vos) ? 1 : 0)
4334
0
                + ((eStyle & FSysStyle::Unix) ? 1 : 0)
4335
0
                + ((eStyle & FSysStyle::Dos) ? 1 : 0)
4336
0
            > 1)
4337
0
    {
4338
0
        if(eStyle & FSysStyle::Vos && m_aHost.isPresent() && m_aHost.getLength() > 0)
4339
0
        {
4340
0
            eStyle= FSysStyle::Vos;
4341
0
        }
4342
0
        else
4343
0
        {
4344
0
            if(hasDosVolume(eStyle) || ((eStyle & FSysStyle::Dos) && m_aHost.isPresent() && m_aHost.getLength() > 0))
4345
0
            {
4346
0
                eStyle = FSysStyle::Dos;
4347
0
            }
4348
0
            else
4349
0
            {
4350
0
                if(eStyle & FSysStyle::Unix && (!m_aHost.isPresent() || m_aHost.getLength() == 0))
4351
0
                {
4352
0
                    eStyle = FSysStyle::Unix;
4353
0
                }
4354
0
                else
4355
0
                {
4356
0
                    eStyle= FSysStyle(0);
4357
0
                }
4358
0
            }
4359
0
        }
4360
0
    }
4361
4362
0
    switch (eStyle)
4363
0
    {
4364
0
        case FSysStyle::Vos:
4365
0
        {
4366
0
            if (pDelimiter)
4367
0
                *pDelimiter = '/';
4368
4369
0
            OUStringBuffer aSynFSysPath("//");
4370
0
            if (m_aHost.isPresent() && m_aHost.getLength() > 0)
4371
0
                aSynFSysPath.append(decode(m_aHost, DecodeMechanism::WithCharset,
4372
0
                                       RTL_TEXTENCODING_UTF8));
4373
0
            else
4374
0
                aSynFSysPath.append('.');
4375
0
            aSynFSysPath.append(decode(m_aPath, DecodeMechanism::WithCharset,
4376
0
                                   RTL_TEXTENCODING_UTF8));
4377
0
            return aSynFSysPath.makeStringAndClear();
4378
0
        }
4379
4380
0
        case FSysStyle::Unix:
4381
0
        {
4382
0
            if (m_aHost.isPresent() && m_aHost.getLength() > 0)
4383
0
                return OUString();
4384
4385
0
            if (pDelimiter)
4386
0
                *pDelimiter = '/';
4387
4388
0
            return decode(m_aPath, DecodeMechanism::WithCharset, RTL_TEXTENCODING_UTF8);
4389
0
        }
4390
4391
0
        case FSysStyle::Dos:
4392
0
        {
4393
0
            if (pDelimiter)
4394
0
                *pDelimiter = '\\';
4395
4396
0
            OUStringBuffer aSynFSysPath(64);
4397
0
            if (m_aHost.isPresent() && m_aHost.getLength() > 0)
4398
0
            {
4399
0
                aSynFSysPath.append("\\\\"
4400
0
                    + decode(m_aHost, DecodeMechanism::WithCharset, RTL_TEXTENCODING_UTF8)
4401
0
                    + "\\");
4402
0
            }
4403
0
            sal_Unicode const * p
4404
0
                = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4405
0
            sal_Unicode const * pEnd = p + m_aPath.getLength();
4406
0
            DBG_ASSERT(p < pEnd && *p == '/',
4407
0
                       "INetURLObject::getFSysPath(): Bad path");
4408
0
            ++p;
4409
0
            while (p < pEnd)
4410
0
            {
4411
0
                EscapeType eEscapeType;
4412
0
                sal_uInt32 nUTF32 = getUTF32(p, pEnd, EncodeMechanism::WasEncoded,
4413
0
                                             RTL_TEXTENCODING_UTF8,
4414
0
                                             eEscapeType);
4415
0
                if (eEscapeType == EscapeType::NONE && nUTF32 == '/')
4416
0
                    aSynFSysPath.append('\\');
4417
0
                else
4418
0
                    aSynFSysPath.appendUtf32(nUTF32);
4419
0
            }
4420
0
            return aSynFSysPath.makeStringAndClear();
4421
0
        }
4422
4423
0
        default:
4424
0
            return OUString();
4425
0
    }
4426
0
}
4427
4428
// static
4429
void INetURLObject::appendUCS4Escape(OUStringBuffer & rTheText,
4430
                                     sal_uInt32 nUCS4)
4431
16.8M
{
4432
16.8M
    DBG_ASSERT(nUCS4 < 0x80000000,
4433
16.8M
               "INetURLObject::appendUCS4Escape(): Bad char");
4434
16.8M
    if (nUCS4 < 0x80)
4435
9.51M
        appendEscape(rTheText, nUCS4);
4436
7.32M
    else if (nUCS4 < 0x800)
4437
3.43M
    {
4438
3.43M
        appendEscape(rTheText, nUCS4 >> 6 | 0xC0);
4439
3.43M
        appendEscape(rTheText, (nUCS4 & 0x3F) | 0x80);
4440
3.43M
    }
4441
3.89M
    else if (nUCS4 < 0x10000)
4442
3.88M
    {
4443
3.88M
        appendEscape(rTheText, nUCS4 >> 12 | 0xE0);
4444
3.88M
        appendEscape(rTheText, (nUCS4 >> 6 & 0x3F) | 0x80);
4445
3.88M
        appendEscape(rTheText, (nUCS4 & 0x3F) | 0x80);
4446
3.88M
    }
4447
9.34k
    else if (nUCS4 < 0x200000)
4448
9.34k
    {
4449
9.34k
        appendEscape(rTheText, nUCS4 >> 18 | 0xF0);
4450
9.34k
        appendEscape(rTheText, (nUCS4 >> 12 & 0x3F) | 0x80);
4451
9.34k
        appendEscape(rTheText, (nUCS4 >> 6 & 0x3F) | 0x80);
4452
9.34k
        appendEscape(rTheText, (nUCS4 & 0x3F) | 0x80);
4453
9.34k
    }
4454
0
    else if (nUCS4 < 0x4000000)
4455
0
    {
4456
0
        appendEscape(rTheText, nUCS4 >> 24 | 0xF8);
4457
0
        appendEscape(rTheText, (nUCS4 >> 18 & 0x3F) | 0x80);
4458
0
        appendEscape(rTheText, (nUCS4 >> 12 & 0x3F) | 0x80);
4459
0
        appendEscape(rTheText, (nUCS4 >> 6 & 0x3F) | 0x80);
4460
0
        appendEscape(rTheText, (nUCS4 & 0x3F) | 0x80);
4461
0
    }
4462
0
    else
4463
0
    {
4464
0
        appendEscape(rTheText, nUCS4 >> 30 | 0xFC);
4465
0
        appendEscape(rTheText, (nUCS4 >> 24 & 0x3F) | 0x80);
4466
0
        appendEscape(rTheText, (nUCS4 >> 18 & 0x3F) | 0x80);
4467
0
        appendEscape(rTheText, (nUCS4 >> 12 & 0x3F) | 0x80);
4468
0
        appendEscape(rTheText, (nUCS4 >> 6 & 0x3F) | 0x80);
4469
0
        appendEscape(rTheText, (nUCS4 & 0x3F) | 0x80);
4470
0
    }
4471
16.8M
}
4472
4473
// static
4474
void INetURLObject::appendUCS4(OUStringBuffer& rTheText, sal_uInt32 nUCS4,
4475
                               EscapeType eEscapeType,
4476
                               Part ePart, rtl_TextEncoding eCharset,
4477
                               bool bKeepVisibleEscapes)
4478
43.7M
{
4479
43.7M
    bool bEscape;
4480
43.7M
    rtl_TextEncoding eTargetCharset = RTL_TEXTENCODING_DONTKNOW;
4481
43.7M
    switch (eEscapeType)
4482
43.7M
    {
4483
38.6M
        case EscapeType::NONE:
4484
38.6M
            if (mustEncode(nUCS4, ePart))
4485
11.8M
            {
4486
11.8M
                bEscape = true;
4487
11.8M
                eTargetCharset = RTL_TEXTENCODING_UTF8;
4488
11.8M
            }
4489
26.7M
            else
4490
26.7M
                bEscape = false;
4491
38.6M
            break;
4492
4493
47.3k
        case EscapeType::Octet:
4494
47.3k
            bEscape = true;
4495
47.3k
            eTargetCharset = RTL_TEXTENCODING_ISO_8859_1;
4496
47.3k
            break;
4497
4498
5.05M
        case EscapeType::Utf32:
4499
5.05M
            if (mustEncode(nUCS4, ePart))
4500
5.02M
            {
4501
5.02M
                bEscape = true;
4502
5.02M
                eTargetCharset = eCharset;
4503
5.02M
            }
4504
24.2k
            else if (bKeepVisibleEscapes && INetMIME::isVisible(nUCS4))
4505
23.2k
            {
4506
23.2k
                bEscape = true;
4507
23.2k
                eTargetCharset = RTL_TEXTENCODING_ASCII_US;
4508
23.2k
            }
4509
986
            else
4510
986
                bEscape = false;
4511
5.05M
            break;
4512
0
        default:
4513
0
            bEscape = false;
4514
43.7M
    }
4515
4516
43.7M
    if (bEscape)
4517
16.9M
    {
4518
16.9M
        switch (eTargetCharset)
4519
16.9M
        {
4520
0
            default:
4521
0
                OSL_FAIL("INetURLObject::appendUCS4(): Unsupported charset");
4522
0
                [[fallthrough]];
4523
23.2k
            case RTL_TEXTENCODING_ASCII_US:
4524
70.5k
            case RTL_TEXTENCODING_ISO_8859_1:
4525
70.5k
                appendEscape(rTheText, nUCS4);
4526
70.5k
                break;
4527
16.8M
            case RTL_TEXTENCODING_UTF8:
4528
16.8M
                appendUCS4Escape(rTheText, nUCS4);
4529
16.8M
                break;
4530
16.9M
        }
4531
16.9M
    }
4532
26.7M
    else
4533
26.7M
        rTheText.append(sal_Unicode(nUCS4));
4534
43.7M
}
4535
4536
// static
4537
sal_uInt32 INetURLObject::getUTF32(sal_Unicode const *& rBegin,
4538
                                   sal_Unicode const * pEnd,
4539
                                   EncodeMechanism eMechanism,
4540
                                   rtl_TextEncoding eCharset,
4541
                                   EscapeType & rEscapeType)
4542
65.5M
{
4543
65.5M
    DBG_ASSERT(rBegin < pEnd, "INetURLObject::getUTF32(): Bad sequence");
4544
65.5M
    sal_uInt32 nUTF32 = INetMIME::getUTF32Character(rBegin, pEnd);
4545
65.5M
    switch (eMechanism)
4546
65.5M
    {
4547
1.65M
        case EncodeMechanism::All:
4548
1.65M
            rEscapeType = EscapeType::NONE;
4549
1.65M
            break;
4550
4551
63.1M
        case EncodeMechanism::WasEncoded:
4552
63.1M
        {
4553
63.1M
            int nWeight1;
4554
63.1M
            int nWeight2;
4555
63.1M
            if (nUTF32 == static_cast<unsigned char>('%') && rBegin + 1 < pEnd
4556
13.3M
                && (nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0
4557
13.2M
                && (nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0)
4558
13.2M
            {
4559
13.2M
                rBegin += 2;
4560
13.2M
                nUTF32 = nWeight1 << 4 | nWeight2;
4561
13.2M
                switch (eCharset)
4562
13.2M
                {
4563
0
                    default:
4564
0
                        OSL_FAIL(
4565
0
                            "INetURLObject::getUTF32(): Unsupported charset");
4566
0
                        [[fallthrough]];
4567
306
                    case RTL_TEXTENCODING_ASCII_US:
4568
306
                        rEscapeType = rtl::isAscii(nUTF32) ?
4569
177
                                          EscapeType::Utf32 : EscapeType::Octet;
4570
306
                        break;
4571
4572
357k
                    case RTL_TEXTENCODING_ISO_8859_1:
4573
357k
                        rEscapeType = EscapeType::Utf32;
4574
357k
                        break;
4575
4576
12.9M
                    case RTL_TEXTENCODING_UTF8:
4577
12.9M
                        if (rtl::isAscii(nUTF32))
4578
9.23M
                            rEscapeType = EscapeType::Utf32;
4579
3.67M
                        else
4580
3.67M
                        {
4581
3.67M
                            if (nUTF32 >= 0xC0 && nUTF32 <= 0xF4)
4582
3.64M
                            {
4583
3.64M
                                sal_uInt32 nEncoded;
4584
3.64M
                                int nShift;
4585
3.64M
                                sal_uInt32 nMin;
4586
3.64M
                                if (nUTF32 <= 0xDF)
4587
1.72M
                                {
4588
1.72M
                                    nEncoded = (nUTF32 & 0x1F) << 6;
4589
1.72M
                                    nShift = 0;
4590
1.72M
                                    nMin = 0x80;
4591
1.72M
                                }
4592
1.92M
                                else if (nUTF32 <= 0xEF)
4593
1.90M
                                {
4594
1.90M
                                    nEncoded = (nUTF32 & 0x0F) << 12;
4595
1.90M
                                    nShift = 6;
4596
1.90M
                                    nMin = 0x800;
4597
1.90M
                                }
4598
16.6k
                                else
4599
16.6k
                                {
4600
16.6k
                                    nEncoded = (nUTF32 & 0x07) << 18;
4601
16.6k
                                    nShift = 12;
4602
16.6k
                                    nMin = 0x10000;
4603
16.6k
                                }
4604
3.64M
                                sal_Unicode const * p = rBegin;
4605
3.64M
                                bool bUTF8 = true;
4606
3.64M
                                for (;;)
4607
5.56M
                                {
4608
5.56M
                                    if (pEnd - p < 3
4609
5.56M
                                        || p[0] != '%'
4610
5.55M
                                        || (nWeight1
4611
5.55M
                                               = INetMIME::getHexWeight(p[1]))
4612
5.55M
                                               < 8
4613
5.54M
                                        || nWeight1 > 11
4614
5.54M
                                        || (nWeight2
4615
5.54M
                                               = INetMIME::getHexWeight(p[2]))
4616
5.54M
                                               < 0)
4617
26.2k
                                    {
4618
26.2k
                                        bUTF8 = false;
4619
26.2k
                                        break;
4620
26.2k
                                    }
4621
5.53M
                                    p += 3;
4622
5.53M
                                    nEncoded
4623
5.53M
                                        |= ((nWeight1 & 3) << 4 | nWeight2)
4624
5.53M
                                               << nShift;
4625
5.53M
                                    if (nShift == 0)
4626
3.62M
                                        break;
4627
1.91M
                                    nShift -= 6;
4628
1.91M
                                }
4629
3.64M
                                if (bUTF8 && rtl::isUnicodeScalarValue(nEncoded)
4630
3.62M
                                    && nEncoded >= nMin)
4631
3.61M
                                {
4632
3.61M
                                    rBegin = p;
4633
3.61M
                                    nUTF32 = nEncoded;
4634
3.61M
                                    rEscapeType = EscapeType::Utf32;
4635
3.61M
                                    break;
4636
3.61M
                                }
4637
3.64M
                            }
4638
52.0k
                            rEscapeType = EscapeType::Octet;
4639
52.0k
                        }
4640
9.28M
                        break;
4641
13.2M
                }
4642
13.2M
            }
4643
49.9M
            else
4644
49.9M
                rEscapeType = EscapeType::NONE;
4645
63.1M
            break;
4646
63.1M
        }
4647
4648
63.1M
        case EncodeMechanism::NotCanonical:
4649
675k
        {
4650
675k
            int nWeight1;
4651
675k
            int nWeight2;
4652
675k
            if (nUTF32 == static_cast<unsigned char>('%') && rBegin + 1 < pEnd
4653
132
                && ((nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0)
4654
132
                && ((nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0))
4655
132
            {
4656
132
                rBegin += 2;
4657
132
                nUTF32 = nWeight1 << 4 | nWeight2;
4658
132
                rEscapeType = EscapeType::Octet;
4659
132
            }
4660
675k
            else
4661
675k
                rEscapeType = EscapeType::NONE;
4662
675k
            break;
4663
63.1M
        }
4664
65.5M
    }
4665
65.5M
    return nUTF32;
4666
65.5M
}
4667
4668
// static
4669
sal_uInt32 INetURLObject::scanDomain(sal_Unicode const *& rBegin,
4670
                                     sal_Unicode const * pEnd,
4671
                                     bool bEager)
4672
172k
{
4673
172k
    enum class State { Dot, Label, Hyphen };
4674
172k
    State eState = State::Dot;
4675
172k
    sal_Int32 nLabels = 0;
4676
172k
    sal_Unicode const * pLastAlphanumeric = nullptr;
4677
837k
    for (sal_Unicode const * p = rBegin;; ++p)
4678
1.00M
        switch (eState)
4679
1.00M
        {
4680
261k
            case State::Dot:
4681
261k
                if (p != pEnd && (rtl::isAsciiAlphanumeric(*p) || *p == '_'))
4682
162k
                {
4683
162k
                    ++nLabels;
4684
162k
                    eState = State::Label;
4685
162k
                    break;
4686
162k
                }
4687
98.8k
                if (bEager || nLabels == 0)
4688
98.8k
                    return 0;
4689
0
                rBegin = p - 1;
4690
0
                return nLabels;
4691
4692
729k
            case State::Label:
4693
729k
                if (p != pEnd)
4694
708k
                {
4695
708k
                    if (rtl::isAsciiAlphanumeric(*p) || *p == '_')
4696
554k
                        break;
4697
153k
                    else if (*p == '.')
4698
89.0k
                    {
4699
89.0k
                        eState = State::Dot;
4700
89.0k
                        break;
4701
89.0k
                    }
4702
64.9k
                    else if (*p == '-')
4703
14.6k
                    {
4704
14.6k
                        pLastAlphanumeric = p;
4705
14.6k
                        eState = State::Hyphen;
4706
14.6k
                        break;
4707
14.6k
                    }
4708
708k
                }
4709
71.1k
                rBegin = p;
4710
71.1k
                return nLabels;
4711
4712
19.3k
            case State::Hyphen:
4713
19.3k
                if (p != pEnd)
4714
19.1k
                {
4715
19.1k
                    if (rtl::isAsciiAlphanumeric(*p) || *p == '_')
4716
12.5k
                    {
4717
12.5k
                        eState = State::Label;
4718
12.5k
                        break;
4719
12.5k
                    }
4720
6.62k
                    else if (*p == '-')
4721
4.71k
                        break;
4722
19.1k
                }
4723
2.12k
                if (bEager)
4724
2.12k
                    return 0;
4725
0
                rBegin = pLastAlphanumeric;
4726
0
                return nLabels;
4727
1.00M
        }
4728
172k
}
4729
4730
// static
4731
bool INetURLObject::scanIPv6reference(sal_Unicode const *& rBegin,
4732
                                      sal_Unicode const * pEnd)
4733
6.54k
{
4734
6.54k
    if (rBegin != pEnd && *rBegin == '[') {
4735
5.66k
        sal_Unicode const * p = rBegin + 1;
4736
        //TODO: check for valid IPv6address (RFC 2373):
4737
62.3k
        while (p != pEnd && (rtl::isAsciiHexDigit(*p) || *p == ':' || *p == '.'))
4738
56.6k
        {
4739
56.6k
            ++p;
4740
56.6k
        }
4741
5.66k
        if (p != pEnd && *p == ']') {
4742
1.88k
            rBegin = p + 1;
4743
1.88k
            return true;
4744
1.88k
        }
4745
5.66k
    }
4746
4.66k
    return false;
4747
6.54k
}
4748
4749
OUString INetURLObject::GetPartBeforeLastName()
4750
    const
4751
742
{
4752
742
    if (!checkHierarchical())
4753
742
        return OUString();
4754
0
    INetURLObject aTemp(*this);
4755
0
    aTemp.clearFragment();
4756
0
    aTemp.clearQuery();
4757
0
    aTemp.removeSegment(LAST_SEGMENT, false);
4758
0
    aTemp.setFinalSlash();
4759
0
    return aTemp.GetMainURL(DecodeMechanism::ToIUri);
4760
742
}
4761
4762
OUString INetURLObject::GetLastName(DecodeMechanism eMechanism,
4763
                                     rtl_TextEncoding eCharset) const
4764
60
{
4765
60
    return getName(LAST_SEGMENT, true, eMechanism, eCharset);
4766
60
}
4767
4768
OUString INetURLObject::GetFileExtension() const
4769
891
{
4770
891
    return getExtension(LAST_SEGMENT, false);
4771
891
}
4772
4773
void INetURLObject::CutLastName()
4774
0
{
4775
0
    INetURLObject aTemp(*this);
4776
0
    aTemp.clearFragment();
4777
0
    aTemp.clearQuery();
4778
0
    if (!aTemp.removeSegment(LAST_SEGMENT, false))
4779
0
        return;
4780
0
    *this = std::move(aTemp);
4781
0
}
4782
4783
OUString INetURLObject::PathToFileName() const
4784
34.5k
{
4785
34.5k
    if (m_eScheme != INetProtocol::File)
4786
0
        return OUString();
4787
34.5k
    OUString aSystemPath;
4788
34.5k
    if (osl::FileBase::getSystemPathFromFileURL(
4789
34.5k
                decode(m_aAbsURIRef.getStr(),
4790
34.5k
                       m_aAbsURIRef.getStr() + m_aPath.getEnd(),
4791
34.5k
                       DecodeMechanism::NONE, RTL_TEXTENCODING_UTF8),
4792
34.5k
                aSystemPath)
4793
34.5k
            != osl::FileBase::E_None)
4794
0
        return OUString();
4795
34.5k
    return aSystemPath;
4796
34.5k
}
4797
4798
OUString INetURLObject::GetFull() const
4799
34.5k
{
4800
34.5k
    INetURLObject aTemp(*this);
4801
34.5k
    aTemp.removeFinalSlash();
4802
34.5k
    return aTemp.PathToFileName();
4803
34.5k
}
4804
4805
OUString INetURLObject::GetPath() const
4806
0
{
4807
0
    INetURLObject aTemp(*this);
4808
0
    aTemp.removeSegment();
4809
0
    aTemp.removeFinalSlash();
4810
0
    return aTemp.PathToFileName();
4811
0
}
4812
4813
void INetURLObject::SetBase(std::u16string_view rTheBase)
4814
0
{
4815
0
    setBase(rTheBase, LAST_SEGMENT, EncodeMechanism::All);
4816
0
}
4817
4818
OUString INetURLObject::GetBase() const
4819
11.9k
{
4820
11.9k
    return getBase(LAST_SEGMENT, true, DecodeMechanism::WithCharset);
4821
11.9k
}
4822
4823
void INetURLObject::SetExtension(std::u16string_view rTheExtension)
4824
0
{
4825
0
    setExtension(rTheExtension, LAST_SEGMENT, false);
4826
0
}
4827
4828
OUString INetURLObject::CutExtension()
4829
0
{
4830
0
    OUString aTheExtension(getExtension(LAST_SEGMENT, false));
4831
0
    if (removeExtension(LAST_SEGMENT, false))
4832
0
        return aTheExtension;
4833
0
    return OUString();
4834
0
}
4835
4836
namespace {
4837
4838
// Treat the substring of rURL from nStart up to the next '/' or '?' as a
4839
// percent-encoded nested url and report whether that nested url is an
4840
// exotic protocol.
4841
bool isExoticNestedProtocol(const OUString& rURL, sal_Int32 nStart)
4842
0
{
4843
0
    auto const find = [&rURL, nStart](auto c) {
4844
0
        auto const n = rURL.indexOf(c, nStart);
4845
0
        return n == -1 ? rURL.getLength() : n;
4846
0
    };
4847
0
    return INetURLObject(
4848
0
               INetURLObject::decode(rURL.subView(nStart, std::min(find('/'), find('?')) - nStart),
4849
0
                                     INetURLObject::DecodeMechanism::WithCharset))
4850
0
        .IsExoticProtocol();
4851
0
}
4852
4853
}
4854
4855
bool INetURLObject::IsExoticProtocol() const
4856
91.8k
{
4857
    // We take a default-deny approach, and check if the protocol is outside
4858
    // of the acceptable ones.
4859
4860
91.8k
    if (m_eScheme == INetProtocol::NotValid
4861
42.1k
        || m_eScheme == INetProtocol::Ftp
4862
42.1k
        || m_eScheme == INetProtocol::Http
4863
28.9k
        || m_eScheme == INetProtocol::File
4864
6.79k
        || m_eScheme == INetProtocol::Mailto
4865
6.48k
        || m_eScheme == INetProtocol::VndSunStarWebdav
4866
6.48k
        || m_eScheme == INetProtocol::PrivSoffice
4867
6.48k
        || m_eScheme == INetProtocol::VndSunStarHelp
4868
6.48k
        || m_eScheme == INetProtocol::Https
4869
5.56k
        || m_eScheme == INetProtocol::Data
4870
2.44k
        || m_eScheme == INetProtocol::Cid
4871
2.16k
        || m_eScheme == INetProtocol::VndSunStarHier
4872
2.16k
        || m_eScheme == INetProtocol::Component
4873
2.16k
        || m_eScheme == INetProtocol::Ldap
4874
2.16k
        || m_eScheme == INetProtocol::Db
4875
2.16k
        || m_eScheme == INetProtocol::VndSunStarCmd
4876
2.16k
        || m_eScheme == INetProtocol::Telnet
4877
2.16k
        || m_eScheme == INetProtocol::VndSunStarTdoc
4878
2.16k
        || m_eScheme == INetProtocol::Smb
4879
2.16k
        || m_eScheme == INetProtocol::Hid
4880
1.77k
        || m_eScheme == INetProtocol::Sftp
4881
1.77k
        || m_eScheme == INetProtocol::Cmis)
4882
90.0k
            return false;
4883
4884
1.77k
    if (m_eScheme == INetProtocol::VndSunStarPkg)
4885
0
    {
4886
        // The package content provider (ucb/source/ucp/package/pkguri.cxx)
4887
        // treats the whole authority between "://" and the next '/' as the
4888
        // nested package url. GetHost() returns only the part after any '@',
4889
        // so match the provider and check that substring instead.
4890
0
        OUString sPayloadURL = GetMainURL(INetURLObject::DecodeMechanism::NONE);
4891
0
        sal_Int32 nStart = sPayloadURL.indexOf(u"://");
4892
0
        if (nStart == -1) {
4893
0
            return false;
4894
0
        }
4895
0
        return isExoticNestedProtocol(sPayloadURL, nStart + 3);
4896
0
    }
4897
4898
1.77k
    if (m_eScheme == INetProtocol::Generic)
4899
1.77k
    {
4900
        // Various things parse to INetProtocol::Generic, of which only some are known-good.
4901
1.77k
        if (isSchemeEqualTo(u"vnd.sun.star.zip"))
4902
0
        {
4903
0
            OUString sPayloadURL = GetURLPath(INetURLObject::DecodeMechanism::NONE);
4904
0
            if (!sPayloadURL.startsWith(u"//")) {
4905
0
                return false;
4906
0
            }
4907
0
            return isExoticNestedProtocol(sPayloadURL, 2);
4908
0
        }
4909
1.77k
        else if (isSchemeEqualTo(u"vnd.sun.star.webdavs"))
4910
0
            return false;
4911
1.77k
        else if (isSchemeEqualTo(u"webdav"))
4912
0
            return false;
4913
1.77k
        else if (isSchemeEqualTo(u"webdavs"))
4914
0
            return false;
4915
1.77k
        else if (isSchemeEqualTo(u"vnd.libreoffice.image"))
4916
0
            return false;
4917
1.77k
        else if (isSchemeEqualTo(u"vnd.sun.star.extension"))
4918
0
            return false;
4919
1.77k
    }
4920
4921
    // anything else is exotic
4922
1.77k
    SAL_INFO("tools.urlobj", "<" << m_aAbsURIRef.toString() << "> considered exotic");
4923
1.77k
    return true;
4924
1.77k
}
4925
4926
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */