Coverage Report

Created: 2026-07-10 11:04

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