xref: /trunk/main/tools/source/fsys/urlobj.cxx (revision 86e1cf34)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_tools.hxx"
26 #include <tools/urlobj.hxx>
27 #include <tools/debug.hxx>
28 #include <tools/inetmime.hxx>
29 #include "com/sun/star/uno/Reference.hxx"
30 #include "com/sun/star/util/XStringWidth.hpp"
31 #include "osl/diagnose.h"
32 #include "osl/file.hxx"
33 #include "rtl/string.h"
34 #include "rtl/textenc.h"
35 #include "rtl/ustring.hxx"
36 #include "sal/types.h"
37 
38 #ifndef INCLUDED_ALGORITHM
39 #include <algorithm>
40 #define INCLUDED_ALGORITHM
41 #endif
42 #ifndef INCLUDED_LIMITS
43 #include <limits>
44 #define INCLUDED_LIMITS
45 #endif
46 
47 #include <string.h>
48 
49 namespace unnamed_tools_urlobj {} using namespace unnamed_tools_urlobj;
50 	// unnamed namespaces don't work well yet...
51 
52 using namespace com::sun;
53 
54 //============================================================================
55 //
56 //	INetURLObject
57 //
58 //============================================================================
59 
60 /* The URI grammar (using RFC 2234 conventions).
61 
62    Constructs of the form
63 	   {reference <rule1> using rule2}
64    stand for a rule matching the given rule1 specified in the given reference,
65    encoded to URI syntax using rule2 (as specified in this URI grammar).
66 
67 
68    ; RFC 1738, RFC 2396, RFC 2732, private
69    login = [user [":" password] "@"] hostport
70    user = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~")
71    password = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~")
72    hostport = host [":" port]
73    host = incomplete-hostname / hostname / IPv4address / IPv6reference
74    incomplete-hostname = *(domainlabel ".") domainlabel
75    hostname = *(domainlabel ".") toplabel ["."]
76    domainlabel = alphanum [*(alphanum / "-") alphanum]
77    toplabel = ALPHA [*(alphanum / "-") alphanum]
78    IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
79    IPv6reference = "[" hexpart [":" IPv4address] "]"
80    hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
81    hexseq = hex4 *(":" hex4)
82    hex4 = 1*4HEXDIG
83    port = *DIGIT
84    escaped = "%" HEXDIG HEXDIG
85    reserved = "$" / "&" / "+" / "," / "/" / ":" / ";" / "=" / "?" / "@" / "[" / "]"
86    mark = "!" / "'" / "(" / ")" / "*" / "-" / "." / "_" / "~"
87    alphanum = ALPHA / DIGIT
88    unreserved = alphanum / mark
89    uric = escaped / reserved / unreserved
90    pchar = escaped / unreserved / "$" / "&" / "+" / "," / ":" / "=" / "@"
91 
92 
93    ; RFC 1738, RFC 2396
94    ftp-url = "FTP://" login ["/" segment *("/" segment) [";TYPE=" ("A" / "D" / "I")]]
95    segment = *pchar
96 
97 
98    ; RFC 1738, RFC 2396
99    http-url = "HTTP://" hostport ["/" segment *("/" segment) ["?" *uric]]
100    segment = *(pchar / ";")
101 
102 
103    ; RFC 1738, RFC 2396, <http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q188997&>
104    file-url = "FILE://" [host / "LOCALHOST" / netbios-name] ["/" segment *("/" segment)]
105    segment = *pchar
106    netbios-name = 1*{<alphanum / "!" / "#" / "$" / "%" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "^" / "_" / "{" / "}" / "~"> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "_" / "~")}
107 
108 
109    ; RFC 2368, RFC 2396
110    mailto-url = "MAILTO:" [to] [headers]
111    to = {RFC 822 <#mailbox> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
112    headers = "?" header *("&" header)
113    header = hname "=" hvalue
114    hname = {RFC 822 <field-name> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} / "BODY"
115    hvalue = {RFC 822 <field-body> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
116 
117 
118    ; private (see RFC 1738, RFC 2396)
119    vnd-sun-star-webdav-url = "VND.SUN.STAR.WEBDAV://" hostport ["/" segment *("/" segment) ["?" *uric]]
120    segment = *(pchar / ";")
121 
122 
123    ; RFC 1738, RFC 2396, RFC 2732
124    news-url = "NEWS:" grouppart
125    grouppart = "*" / group / article
126    group = alpha *(alphanum / "+" / "-" / "." / "_")
127    article = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "?" / "_" / "~") "@" host
128 
129 
130    ; private
131    private-url = "PRIVATE:" path ["?" *uric]
132    path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
133 
134 
135    ; private
136    vnd-sun-star-help-url = "VND.SUN.STAR.HELP://" name *("/" segment) ["?" *uric]
137    name = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
138    segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
139 
140 
141    ; private
142    https-url = "HTTPS://" hostport ["/" segment *("/" segment) ["?" *uric]]
143    segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
144 
145 
146    ; private
147    slot-url = "SLOT:" path ["?" *uric]
148    path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
149 
150 
151    ; private
152    macro-url = "MACRO:" path ["?" *uric]
153    path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
154 
155 
156    ; private
157    javascript-url = "JAVASCRIPT:" *uric
158 
159 
160    ; private (see RFC 2192)
161    imap-url = "IMAP://" user [";AUTH=" auth] "@" hostport "/" segment *("/" segment) ["/;UID=" nz_number]
162    user = 1*{RFC 2060 <CHAR8> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "=" / "_" / "~")}
163    auth = {RFC 2060 <atom> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "+" / "," / "-" / "." / "=" / "_" / "~")}
164    segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / "=" / "@" / "_" / "~")
165    nz_number = {RFC 2060 <nz_number> using *DIGIT}
166 
167 
168    ; private
169    pop3-url = "POP3://" login ["/" ["<" *uric ">"]]
170 
171 
172    ; RFC 2397
173    data-url = "DATA:" [mediatype] [";BASE64"] "," *uric
174    mediatype = [type "/" subtype] *(";" attribute "=" value)
175    type = {RFC 2045 <type> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
176    subtype = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
177    attribute = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
178    value = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")}
179 
180 
181    ; RFC 2392, RFC 2396
182    cid-url = "CID:" {RFC 822 <addr-spec> using *uric}
183 
184 
185    ; private
186    out-url = "OUT:///~" name ["/" *uric]
187    name = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "?" / "@" / "_" / "~"
188 
189 
190    ; private
191    vnd-sun-star-hier-url = "VND.SUN.STAR.HIER:" ["//"reg_name] *("/" *pchar)
192    reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
193 
194    ; private
195    vim-url = "VIM://" +vimc [":" *vimc] ["/" [("INBOX" message) / ("NEWSGROUPS" ["/" [+vimc message]])]]
196    message = ["/" [+vimc [":" +DIGIT "." +DIGIT "." +DIGIT]]]
197    vimc = ("=" HEXDIG HEXDIG) / alphanum
198 
199 
200    ; private
201    uno-url = ".UNO:" path ["?" *uric]
202    path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
203 
204 
205    ; private
206    component-url = ".COMPONENT:" path ["?" *uric]
207    path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")
208 
209 
210    ; private
211    vnd-sun-star-pkg-url = "VND.SUN.STAR.PKG://" reg_name *("/" *pchar) ["?" *uric]
212    reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~")
213 
214 
215    ; RFC 2255
216    ldap-url = "LDAP://" [hostport] ["/" [dn ["?" [attrdesct *("," attrdesc)] ["?" ["base" / "one" / "sub"] ["?" [filter] ["?" extension *("," extension)]]]]]]
217    dn = {RFC 2253 <distinguishedName> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
218    attrdesc = {RFC 2251 <AttributeDescription> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
219    filter = {RFC 2254 <filter> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
220    extension = ["!"] ["X-"] extoken ["=" exvalue]
221    extoken = {RFC 2252 <oid> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")}
222    exvalue = {RFC 2251 <LDAPString> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")}
223 
224 
225    ; private
226    db-url = "DB:" *uric
227 
228 
229    ; private
230    vnd-sun-star-cmd-url = "VND.SUN.STAR.CMD:" opaque_part
231    opaque_part = uric_no_slash *uric
232    uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
233 
234 
235    ; private
236    vnd-sun-star-url = "VND.SUN.STAR.ODMA:" ["/" *uric_no_slash]
237    uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
238 
239 
240    ; RFC 1738
241    telnet-url = "TELNET://" login ["/"]
242 
243 
244    ; private
245    vnd-sun-star-expand-url = "VND.SUN.STAR.EXPAND:" opaque_part
246    opaque_part = uric_no_slash *uric
247    uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
248 
249 
250    ; private
251    vnd-sun-star-tdoc-url = "VND.SUN.STAR.TDOC:/" segment *("/" segment)
252    segment = *pchar
253 
254 
255    ; private
256    unknown-url = scheme ":" 1*uric
257    scheme = ALPHA *(alphanum / "+" / "-" / ".")
258 
259 
260    ; private (http://ubiqx.org/cifs/Appendix-D.html):
261    smb-url = "SMB://" login ["/" segment *("/" segment) ["?" *uric]]
262    segment = *(pchar / ";")
263  */
264 
265 //============================================================================
clear()266 inline sal_Int32 INetURLObject::SubString::clear()
267 {
268 	sal_Int32 nDelta = -m_nLength;
269 	m_nBegin = -1;
270 	m_nLength = 0;
271 	return nDelta;
272 }
273 
set(rtl::OUStringBuffer & rString,rtl::OUString const & rSubString)274 inline sal_Int32 INetURLObject::SubString::set(rtl::OUStringBuffer & rString,
275 									   rtl::OUString const & rSubString)
276 {
277 	rtl::OUString sTemp(rString.makeStringAndClear());
278 	sal_Int32 nDelta = set(sTemp, rSubString);
279 	rString.append(sTemp);
280 	return nDelta;
281 }
282 
set(rtl::OUString & rString,rtl::OUString const & rSubString)283 inline sal_Int32 INetURLObject::SubString::set(rtl::OUString & rString,
284 									   rtl::OUString const & rSubString)
285 {
286 	sal_Int32 nDelta = rSubString.getLength() - m_nLength;
287 
288 	rString = rString.replaceAt(m_nBegin, m_nLength, rSubString);
289 
290 	m_nLength = rSubString.getLength();
291 	return nDelta;
292 }
293 
set(rtl::OUStringBuffer & rString,rtl::OUString const & rSubString,sal_Int32 nTheBegin)294 inline sal_Int32 INetURLObject::SubString::set(rtl::OUStringBuffer & rString,
295 									   rtl::OUString const & rSubString,
296 											   sal_Int32 nTheBegin)
297 {
298 	m_nBegin = nTheBegin;
299 	return set(rString, rSubString);
300 }
301 
302 //============================================================================
operator +=(sal_Int32 nDelta)303 inline void INetURLObject::SubString::operator +=(sal_Int32 nDelta)
304 {
305 	if (isPresent())
306 		m_nBegin = m_nBegin + nDelta;
307 }
308 
309 //============================================================================
compare(SubString const & rOther,rtl::OUStringBuffer const & rThisString,rtl::OUStringBuffer const & rOtherString) const310 int INetURLObject::SubString::compare(SubString const & rOther,
311                                       rtl::OUStringBuffer const & rThisString,
312                                       rtl::OUStringBuffer const & rOtherString) const
313 {
314     sal_Int32 len = std::min(m_nLength, rOther.m_nLength);
315     sal_Unicode const * p1 = rThisString.getStr() + m_nBegin;
316     sal_Unicode const * end = p1 + len;
317     sal_Unicode const * p2 = rOtherString.getStr() + rOther.m_nBegin;
318     while (p1 != end) {
319         if (*p1 < *p2) {
320             return -1;
321         } else if (*p1 > *p2) {
322             return 1;
323         }
324         ++p1;
325         ++p2;
326     }
327     return m_nLength < rOther.m_nLength ? -1
328         : m_nLength > rOther.m_nLength ? 1
329         : 0;
330 }
331 
332 //============================================================================
333 struct INetURLObject::SchemeInfo
334 {
335 	sal_Char const * m_pScheme;
336 	sal_Char const * m_pPrefix;
337 	sal_uInt16 m_nDefaultPort;
338 	bool m_bAuthority;
339 	bool m_bUser;
340 	bool m_bAuth;
341 	bool m_bPassword;
342 	bool m_bHost;
343 	bool m_bPort;
344 	bool m_bHierarchical;
345 	bool m_bQuery;
346 };
347 
348 //============================================================================
349 struct INetURLObject::PrefixInfo
350 {
351 	enum Kind { OFFICIAL, INTERNAL, EXTERNAL, ALIAS }; // order is important!
352 
353 	sal_Char const * m_pPrefix;
354 	sal_Char const * m_pTranslatedPrefix;
355 	INetProtocol m_eScheme;
356 	Kind m_eKind;
357 };
358 
359 //============================================================================
360 static INetURLObject::SchemeInfo const aSchemeInfoMap[INET_PROT_END]
361 	= { { "", "", 0, false, false, false, false, false, false, false,
362 		  false },
363 		{ "ftp", "ftp://", 21, true, true, false, true, true, true, true,
364 		  false },
365 		{ "http", "http://", 80, true, false, false, false, true, true,
366 		  true, true },
367 		{ "file", "file://", 0, true, false, false, false, true, false,
368 		  true, false },
369 		{ "mailto", "mailto:", 0, false, false, false, false, false,
370 		  false, false, true },
371 		{ "vnd.sun.star.webdav", "vnd.sun.star.webdav://", 80, true, false,
372 		  false, false, true, true, true, true },
373 		{ "news", "news:", 0, false, false, false, false, false, false, false,
374           false },
375 		{ "private", "private:", 0, false, false, false, false, false,
376 		  false, false, true },
377 		{ "vnd.sun.star.help", "vnd.sun.star.help://", 0, true, false, false,
378 		  false, false, false, true, true },
379 		{ "https", "https://", 443, true, false, false, false, true, true,
380 		  true, true },
381 		{ "slot", "slot:", 0, false, false, false, false, false, false,
382 		  false, true },
383 		{ "macro", "macro:", 0, false, false, false, false, false, false,
384 		  false, true },
385 		{ "javascript", "javascript:", 0, false, false, false, false,
386 		  false, false, false, false },
387 		{ "imap", "imap://", 143, true, true, true, false, true, true,
388 		  true, false },
389 		{ "pop3", "pop3://", 110, true, true, false, true, true, true,
390 		  false, false },
391 		{ "data", "data:", 0, false, false, false, false, false, false,
392 		  false, false },
393 		{ "cid", "cid:", 0, false, false, false, false, false, false,
394 		  false, false },
395 		{ "out", "out://", 0, true, false, false, false, false, false,
396 		  false, false },
397 		{ "vnd.sun.star.hier", "vnd.sun.star.hier:", 0, true, false, false,
398 		  false, false, false, true, false },
399 		{ "vim", "vim://", 0, true, true, false, true, false, false, true,
400 		  false },
401 		{ ".uno", ".uno:", 0, false, false, false, false, false, false,
402 		  false, true },
403 		{ ".component", ".component:", 0, false, false, false, false,
404 		  false, false, false, true },
405 		{ "vnd.sun.star.pkg", "vnd.sun.star.pkg://", 0, true, false, false,
406 		  false, false, false, true, true },
407 		{ "ldap", "ldap://", 389, true, false, false, false, true, true,
408 		  false, true },
409 		{ "db", "db:", 0, false, false, false, false, false, false, false,
410 		  false },
411 		{ "vnd.sun.star.cmd", "vnd.sun.star.cmd:", 0, false, false, false,
412 		  false, false, false, false, false },
413 		{ "vnd.sun.star.odma", "vnd.sun.star.odma:", 0, false, false, false,
414 		  false, false, false, true, false },
415 		{ "telnet", "telnet://", 23, true, true, false, true, true, true, true,
416           false },
417 		{ "vnd.sun.star.expand", "vnd.sun.star.expand:", 0, false, false, false,
418 		  false, false, false, false, false },
419         { "vnd.sun.star.tdoc", "vnd.sun.star.tdoc:", 0, false, false, false,
420           false, false, false, true, false },
421         { "", "", 0, false, false, false, false, true, true, true, false },
422         { "smb", "smb://", 139, true, true, false, true, true, true, true,
423           true },
424 		{ "hid", "hid:", 0, false, false, false, false, false, false,
425         false, true } };
426 
427 // static
428 inline INetURLObject::SchemeInfo const &
getSchemeInfo(INetProtocol eTheScheme)429 INetURLObject::getSchemeInfo(INetProtocol eTheScheme)
430 {
431 	return aSchemeInfoMap[eTheScheme];
432 };
433 
434 //============================================================================
getSchemeInfo() const435 inline INetURLObject::SchemeInfo const & INetURLObject::getSchemeInfo() const
436 {
437 	return getSchemeInfo(m_eScheme);
438 }
439 
440 //============================================================================
441 // static
appendEscape(rtl::OUStringBuffer & rTheText,sal_Char cEscapePrefix,sal_uInt32 nOctet)442 inline void INetURLObject::appendEscape(rtl::OUStringBuffer & rTheText,
443 										sal_Char cEscapePrefix,
444 										sal_uInt32 nOctet)
445 {
446 	rTheText.append(sal_Unicode(cEscapePrefix));
447 	rTheText.append(sal_Unicode(INetMIME::getHexDigit(int(nOctet >> 4))));
448 	rTheText.append(sal_Unicode(INetMIME::getHexDigit(int(nOctet & 15))));
449 }
450 
451 //============================================================================
452 namespace unnamed_tools_urlobj {
453 
454 enum
455 {
456 	PA = INetURLObject::PART_OBSOLETE_NORMAL,
457 	PB = INetURLObject::PART_OBSOLETE_FILE,
458 	PC = INetURLObject::PART_OBSOLETE_PARAM,
459 	PD = INetURLObject::PART_USER_PASSWORD,
460 	PE = INetURLObject::PART_IMAP_ACHAR,
461 	PF = INetURLObject::PART_VIM,
462 	PG = INetURLObject::PART_HOST_EXTRA,
463 	PH = INetURLObject::PART_FPATH,
464 	PI = INetURLObject::PART_AUTHORITY,
465 	PJ = INetURLObject::PART_PATH_SEGMENTS_EXTRA,
466 	PK = INetURLObject::PART_REL_SEGMENT_EXTRA,
467 	PL = INetURLObject::PART_URIC,
468 	PM = INetURLObject::PART_HTTP_PATH,
469 	PN = INetURLObject::PART_FILE_SEGMENT_EXTRA,
470 	PO = INetURLObject::PART_MESSAGE_ID,
471 	PP = INetURLObject::PART_MESSAGE_ID_PATH,
472 	PQ = INetURLObject::PART_MAILTO,
473 	PR = INetURLObject::PART_PATH_BEFORE_QUERY,
474 	PS = INetURLObject::PART_PCHAR,
475 	PT = INetURLObject::PART_FRAGMENT,
476 	PU = INetURLObject::PART_VISIBLE,
477 	PV = INetURLObject::PART_VISIBLE_NONSPECIAL,
478 	PW = INetURLObject::PART_CREATEFRAGMENT,
479 	PX = INetURLObject::PART_UNO_PARAM_VALUE,
480 	PY = INetURLObject::PART_UNAMBIGUOUS,
481 	PZ = INetURLObject::PART_URIC_NO_SLASH,
482     P1 = INetURLObject::PART_HTTP_QUERY,
483     P2 = INetURLObject::PART_NEWS_ARTICLE_LOCALPART
484 };
485 
486 static sal_uInt32 const aMustEncodeMap[128]
487 	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
488 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
489 /*   */	                                                                        PY,
490 /* ! */	      PC+PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
491 /* " */	                                                            PU+PV      +PY,
492 /* # */	                                                            PU,
493 /* $ */	         PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
494 /* % */	                                                            PU,
495 /* & */ PA+PB+PC+PD+PE      +PH+PI+PJ+PK+PL+PM+PN+PO+PP   +PR+PS+PT+PU+PV+PW+PX   +PZ+P1+P2,
496 /* ' */	         PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
497 /* ( */	         PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
498 /* ) */	         PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
499 /* * */ PA+PB+PC+PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
500 /* + */ PA+PB+PC+PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX   +PZ+P1+P2,
501 /* , */ PA+PB+PC+PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW      +PZ+P1+P2,
502 /* - */ PA+PB+PC+PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
503 /* . */ PA+PB+PC+PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
504 /* / */ PA+PB+PC            +PH   +PJ   +PL+PM      +PP+PQ+PR   +PT+PU+PV   +PX         +P2,
505 /* 0 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
506 /* 1 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
507 /* 2 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
508 /* 3 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
509 /* 4 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
510 /* 5 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
511 /* 6 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
512 /* 7 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
513 /* 8 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
514 /* 9 */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
515 /* : */	   PB+PC            +PH+PI+PJ   +PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX   +PZ+P1+P2,
516 /* ; */	      PC+PD            +PI+PJ+PK+PL+PM   +PO+PP+PQ+PR   +PT+PU   +PW      +PZ+P1+P2,
517 /* < */	      PC                                 +PO+PP            +PU+PV      +PY,
518 /* = */ PA+PB+PC+PD+PE      +PH+PI+PJ+PK+PL+PM+PN         +PR+PS+PT+PU+PV+PW      +PZ+P1+P2,
519 /* > */	      PC                                 +PO+PP            +PU+PV      +PY,
520 /* ? */	      PC                        +PL                     +PT+PU   +PW+PX   +PZ   +P2,
521 /* @ */	      PC            +PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1,
522 /* A */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
523 /* B */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
524 /* C */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
525 /* D */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
526 /* E */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
527 /* F */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
528 /* G */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
529 /* H */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
530 /* I */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
531 /* J */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
532 /* K */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
533 /* L */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
534 /* M */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
535 /* N */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
536 /* O */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
537 /* P */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
538 /* Q */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
539 /* R */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
540 /* S */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
541 /* T */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
542 /* U */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
543 /* V */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
544 /* W */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
545 /* X */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
546 /* Y */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
547 /* Z */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
548 /* [ */	                                 PL                        +PU+PV   +PX,
549 /* \ */	   PB                                                      +PU+PV      +PY,
550 /* ] */	                                 PL                        +PU+PV   +PX,
551 /* ^ */	                                                            PU+PV      +PY,
552 /* _ */ PA+PB+PC+PD+PE   +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
553 /* ` */	                                                            PU+PV      +PY,
554 /* a */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
555 /* b */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
556 /* c */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
557 /* d */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
558 /* e */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
559 /* f */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
560 /* g */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
561 /* h */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
562 /* i */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
563 /* j */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
564 /* k */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
565 /* l */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
566 /* m */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
567 /* n */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
568 /* o */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
569 /* p */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
570 /* q */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
571 /* r */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
572 /* s */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
573 /* t */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
574 /* u */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
575 /* v */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
576 /* w */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
577 /* x */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
578 /* y */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
579 /* z */ PA+PB+PC+PD+PE+PF+PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2,
580 /* { */	                                                            PU+PV      +PY,
581 /* | */	   PB+PC                              +PN               +PT+PU+PV      +PY,
582 /* } */	                                                            PU+PV      +PY,
583 /* ~ */ PA+PB+PC+PD+PE      +PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ  +P2,
584 		0 };
585 
mustEncode(sal_uInt32 nUTF32,INetURLObject::Part ePart)586 inline bool mustEncode(sal_uInt32 nUTF32, INetURLObject::Part ePart)
587 {
588 	return !INetMIME::isUSASCII(nUTF32) || !(aMustEncodeMap[nUTF32] & ePart);
589 }
590 
591 }
592 
593 //============================================================================
setInvalid()594 void INetURLObject::setInvalid()
595 {
596 	m_aAbsURIRef.setLength(0);
597 	m_eScheme = INET_PROT_NOT_VALID;
598     m_aScheme.clear();
599 	m_aUser.clear();
600 	m_aAuth.clear();
601 	m_aHost.clear();
602 	m_aPort.clear();
603 	m_aPath.clear();
604 	m_aQuery.clear();
605 	m_aFragment.clear();
606 }
607 
608 //============================================================================
609 
610 namespace unnamed_tools_urlobj {
611 
612 INetURLObject::FSysStyle
guessFSysStyleByCounting(sal_Unicode const * pBegin,sal_Unicode const * pEnd,INetURLObject::FSysStyle eStyle)613 guessFSysStyleByCounting(sal_Unicode const * pBegin,
614 						 sal_Unicode const * pEnd,
615 						 INetURLObject::FSysStyle eStyle)
616 {
617 	DBG_ASSERT(eStyle
618 			       & (INetURLObject::FSYS_UNX
619 					      | INetURLObject::FSYS_DOS
620 					      | INetURLObject::FSYS_MAC),
621 			   "guessFSysStyleByCounting(): Bad style");
622 	DBG_ASSERT(std::numeric_limits< sal_Int32 >::min() < pBegin - pEnd
623 			   && pEnd - pBegin <= std::numeric_limits< sal_Int32 >::max(),
624 			   "guessFSysStyleByCounting(): Too big");
625 	sal_Int32 nSlashCount
626 		= eStyle & INetURLObject::FSYS_UNX ?
627 		      0 : std::numeric_limits< sal_Int32 >::min();
628 	sal_Int32 nBackslashCount
629 		= eStyle & INetURLObject::FSYS_DOS ?
630 		      0 : std::numeric_limits< sal_Int32 >::min();
631 	sal_Int32 nColonCount
632 		= eStyle & INetURLObject::FSYS_MAC ?
633 		      0 : std::numeric_limits< sal_Int32 >::min();
634 	while (pBegin != pEnd)
635 		switch (*pBegin++)
636 		{
637 			case '/':
638 				++nSlashCount;
639 				break;
640 
641 			case '\\':
642 				++nBackslashCount;
643 				break;
644 
645 			case ':':
646 				++nColonCount;
647 				break;
648 		}
649 	return nSlashCount >= nBackslashCount ?
650 		       nSlashCount >= nColonCount ?
651 		           INetURLObject::FSYS_UNX : INetURLObject::FSYS_MAC :
652 		       nBackslashCount >= nColonCount ?
653 		           INetURLObject::FSYS_DOS : INetURLObject::FSYS_MAC;
654 }
655 
parseScheme(sal_Unicode const ** begin,sal_Unicode const * end,sal_uInt32 fragmentDelimiter)656 rtl::OUString parseScheme(
657     sal_Unicode const ** begin, sal_Unicode const * end,
658     sal_uInt32 fragmentDelimiter)
659 {
660     sal_Unicode const * p = *begin;
661     if (p != end && INetMIME::isAlpha(*p)) {
662         do {
663             ++p;
664         } while (p != end
665                  && (INetMIME::isAlphanumeric(*p) || *p == '+' || *p == '-'
666                      || *p == '.'));
667         // #i34835# To avoid problems with Windows file paths like "C:\foo",
668         // do not accept generic schemes that are only one character long:
669         if (end - p > 1 && p[0] == ':' && p[1] != fragmentDelimiter
670             && p - *begin >= 2)
671         {
672 			rtl::OUString scheme(
673                 rtl::OUString(*begin, p - *begin).toAsciiLowerCase());
674             *begin = p + 1;
675             return scheme;
676         }
677     }
678     return rtl::OUString();
679 }
680 
681 }
682 
setAbsURIRef(rtl::OUString const & rTheAbsURIRef,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset,bool bSmart,FSysStyle eStyle)683 bool INetURLObject::setAbsURIRef(rtl::OUString const & rTheAbsURIRef,
684 								 bool bOctets,
685 								 EncodeMechanism eMechanism,
686 								 rtl_TextEncoding eCharset,
687 								 bool bSmart,
688 								 FSysStyle eStyle)
689 {
690 	sal_Unicode const * pPos = rTheAbsURIRef.getStr();
691 	sal_Unicode const * pEnd = pPos + rTheAbsURIRef.getLength();
692 
693 	setInvalid();
694 
695 	sal_uInt32 nFragmentDelimiter = '#';
696 
697 	rtl::OUStringBuffer aSynAbsURIRef;
698 
699 	// Parse <scheme>:
700 	sal_Unicode const * p = pPos;
701 	PrefixInfo const * pPrefix = getPrefix(p, pEnd);
702 	if (pPrefix)
703 	{
704 		pPos = p;
705 		m_eScheme = pPrefix->m_eScheme;
706 
707 		rtl::OUString sTemp(rtl::OUString::createFromAscii(pPrefix->m_eKind
708 										         >= PrefixInfo::EXTERNAL ?
709 										     pPrefix->m_pTranslatedPrefix :
710 										     pPrefix->m_pPrefix));
711 		aSynAbsURIRef.append(sTemp);
712         m_aScheme = SubString( 0, sTemp.indexOf(static_cast< sal_Unicode >(':')) );
713 	}
714 	else
715 	{
716 		if (bSmart)
717 		{
718 			// For scheme detection, the first (if any) of the following
719 			// productions that matches the input string (and for which the
720 			// appropriate style bit is set in eStyle, if applicable)
721 			// determines the scheme. The productions use the auxiliary rules
722 			//
723 			//	  domain = label *("." label)
724 			//	  label = alphanum [*(alphanum / "-") alphanum]
725 			//	  alphanum = ALPHA / DIGIT
726 			//	  IPv6reference = "[" IPv6address "]"
727 			//	  IPv6address = hexpart [":" IPv4address]
728 			//	  IPv4address = 1*3DIGIT 3("." 1*3DIGIT)
729 			//	  hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
730 			//	  hexseq = hex4 *(":" hex4)
731 			//	  hex4 = 1*4HEXDIG
732 			//	  UCS4 = <any UCS4 character>
733 			//
734 			// 1st Production (known scheme):
735 			//	  <one of the known schemes, ignoring case> ":" *UCS4
736 			//
737 			// 2nd Production (mailto):
738 			//	  domain "@" domain
739 			//
740 			// 3rd Production (ftp):
741 			//	  "FTP" 2*("." label) ["/" *UCS4]
742 			//
743 			// 4th Production (http):
744 			//	  label 2*("." label) ["/" *UCS4]
745 			//
746 			// 5th Production (file):
747 			//	  "//" (domain / IPv6reference) ["/" *UCS4]
748 			//
749 			// 6th Production (Unix file):
750 			//    "/" *UCS4
751 			//
752 			// 7th Production (UNC file; FSYS_DOS only):
753 			//	  "\\" domain ["\" *UCS4]
754 			//
755 			// 8th Production (Unix-like DOS file; FSYS_DOS only):
756 			//	  ALPHA ":" ["/" *UCS4]
757 			//
758 			// 9th Production (DOS file; FSYS_DOS only):
759 			//	  ALPHA ":" ["\" *UCS4]
760 			//
761 			// For the 'non URL' file productions 6--9, the interpretation of
762 			// the input as a (degenerate) URI is turned off, i.e., escape
763 			// sequences and fragments are never detected as such, but are
764 			// taken as literal characters.
765 
766 			sal_Unicode const * p1 = pPos;
767 			if (eStyle & FSYS_DOS
768 				&& pEnd - p1 >= 2
769 				&& INetMIME::isAlpha(p1[0])
770 				&& p1[1] == ':'
771                 && (pEnd - p1 == 2 || p1[2] == '/' || p1[2] == '\\'))
772 			{
773 				m_eScheme = INET_PROT_FILE; // 8th, 9th
774 				eMechanism = ENCODE_ALL;
775 				nFragmentDelimiter = 0x80000000;
776 			}
777 			else if (pEnd - p1 >= 2 && p1[0] == '/' && p1[1] == '/')
778 			{
779 				p1 += 2;
780 				if ((scanDomain(p1, pEnd) > 0 || scanIPv6reference(p1, pEnd))
781 					&& (p1 == pEnd || *p1 == '/'))
782 					m_eScheme = INET_PROT_FILE; // 5th
783 			}
784 			else if (p1 != pEnd && *p1 == '/')
785 			{
786 				m_eScheme = INET_PROT_FILE; // 6th
787 				eMechanism = ENCODE_ALL;
788 				nFragmentDelimiter = 0x80000000;
789 			}
790 			else if (eStyle & FSYS_DOS
791 					 && pEnd - p1 >= 2
792 					 && p1[0] == '\\'
793 					 && p1[1] == '\\')
794 			{
795 				p1 += 2;
796                 sal_Int32 n = rtl_ustr_indexOfChar_WithLength(
797                     p1, pEnd - p1, '\\');
798                 sal_Unicode const * pe = n == -1 ? pEnd : p1 + n;
799 				if (
800                     parseHostOrNetBiosName(
801                         p1, pe, bOctets, ENCODE_ALL, RTL_TEXTENCODING_DONTKNOW,
802                         true, NULL) ||
803                     (scanDomain(p1, pe) > 0 && p1 == pe)
804                    )
805 				{
806 					m_eScheme = INET_PROT_FILE; // 7th
807 					eMechanism = ENCODE_ALL;
808 					nFragmentDelimiter = 0x80000000;
809 				}
810 			}
811 			else
812 			{
813 				sal_Unicode const * pDomainEnd = p1;
814 				sal_uInt32 nLabels = scanDomain(pDomainEnd, pEnd);
815 				if (nLabels > 0 && pDomainEnd != pEnd && *pDomainEnd == '@')
816 				{
817 					++pDomainEnd;
818 					if (scanDomain(pDomainEnd, pEnd) > 0
819 						&& pDomainEnd == pEnd)
820 						m_eScheme = INET_PROT_MAILTO; // 2nd
821 				}
822 				else if (nLabels >= 3
823 						 && (pDomainEnd == pEnd || *pDomainEnd == '/'))
824 					m_eScheme
825 						= pDomainEnd - p1 >= 4
826                           && (p1[0] == 'f' || p1[0] == 'F')
827                           && (p1[1] == 't' || p1[1] == 'T')
828                           && (p1[2] == 'p' || p1[2] == 'P')
829 						  && p1[3] == '.' ?
830 						      INET_PROT_FTP : INET_PROT_HTTP; // 3rd, 4th
831 			}
832 		}
833 
834 		rtl::OUString aSynScheme;
835         if (m_eScheme == INET_PROT_NOT_VALID) {
836             sal_Unicode const * p1 = pPos;
837             aSynScheme = parseScheme(&p1, pEnd, nFragmentDelimiter);
838             if (aSynScheme.getLength() > 0)
839             {
840                 m_eScheme = INET_PROT_GENERIC;
841                 pPos = p1;
842             }
843         }
844 
845         if (bSmart && m_eScheme == INET_PROT_NOT_VALID && pPos != pEnd
846             && *pPos != nFragmentDelimiter)
847         {
848             m_eScheme = m_eSmartScheme;
849         }
850 
851 		if (m_eScheme == INET_PROT_NOT_VALID)
852 		{
853 			setInvalid();
854 			return false;
855 		}
856 
857         if (m_eScheme != INET_PROT_GENERIC) {
858             aSynScheme = rtl::OUString::createFromAscii(getSchemeInfo().m_pScheme);
859         }
860         m_aScheme.set(aSynAbsURIRef, aSynScheme, aSynAbsURIRef.getLength());
861         aSynAbsURIRef.append(sal_Unicode(':'));
862 	}
863 
864 	sal_Char cEscapePrefix = getEscapePrefix();
865 	sal_uInt32 nSegmentDelimiter = '/';
866 	sal_uInt32 nAltSegmentDelimiter = 0x80000000;
867 	bool bSkippedInitialSlash = false;
868 
869 	// Parse //<user>;AUTH=<auth>@<host>:<port> or
870 	// //<user>:<password>@<host>:<port> or
871     // //<reg_name>
872 	if (getSchemeInfo().m_bAuthority)
873 	{
874 		sal_Unicode const * pUserInfoBegin = 0;
875 		sal_Unicode const * pUserInfoEnd = 0;
876 		sal_Unicode const * pHostPortBegin = 0;
877 		sal_Unicode const * pHostPortEnd = 0;
878 
879 		switch (m_eScheme)
880 		{
881 			case INET_PROT_VND_SUN_STAR_HELP:
882 			{
883 				if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/')
884 				{
885 					setInvalid();
886 					return false;
887 				}
888                 aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
889 				rtl::OUStringBuffer aSynAuthority;
890 				while (pPos < pEnd
891 					   && *pPos != '/' && *pPos != '?'
892 					   && *pPos != nFragmentDelimiter)
893 				{
894 					EscapeType eEscapeType;
895 					sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
896 												 cEscapePrefix, eMechanism,
897 												 eCharset, eEscapeType);
898 					appendUCS4(aSynAuthority, nUTF32, eEscapeType, bOctets,
899 							   PART_AUTHORITY, cEscapePrefix, eCharset,
900 							   false);
901 				}
902 				m_aHost.set(aSynAbsURIRef,
903 							aSynAuthority.makeStringAndClear(),
904 							aSynAbsURIRef.getLength());
905 					// misusing m_aHost to store the authority
906 				break;
907 			}
908 
909             case INET_PROT_VND_SUN_STAR_HIER:
910             {
911                 if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
912                 {
913                     pPos += 2;
914                     aSynAbsURIRef.
915                         appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
916                     rtl::OUStringBuffer aSynAuthority;
917                     while (pPos < pEnd
918                            && *pPos != '/' && *pPos != '?'
919                            && *pPos != nFragmentDelimiter)
920                     {
921                         EscapeType eEscapeType;
922                         sal_uInt32 nUTF32 = getUTF32(pPos,
923                                                      pEnd,
924                                                      bOctets,
925                                                      cEscapePrefix,
926                                                      eMechanism,
927                                                      eCharset,
928                                                      eEscapeType);
929                         appendUCS4(aSynAuthority,
930                                    nUTF32,
931                                    eEscapeType,
932                                    bOctets,
933                                    PART_AUTHORITY,
934                                    cEscapePrefix,
935                                    eCharset,
936                                    false);
937                     }
938                     if (aSynAuthority.getLength() == 0)
939                     {
940                         setInvalid();
941                         return false;
942                     }
943                     m_aHost.set(aSynAbsURIRef,
944                                 aSynAuthority.makeStringAndClear(),
945                                 aSynAbsURIRef.getLength());
946                         // misusing m_aHost to store the authority
947                 }
948                 break;
949             }
950 
951 			case INET_PROT_VND_SUN_STAR_PKG:
952 			{
953 				if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/')
954 				{
955 					setInvalid();
956 					return false;
957 				}
958                 aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
959 				rtl::OUStringBuffer aSynAuthority;
960 				while (pPos < pEnd
961 					   && *pPos != '/' && *pPos != '?'
962 					   && *pPos != nFragmentDelimiter)
963 				{
964 					EscapeType eEscapeType;
965 					sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
966 												 cEscapePrefix, eMechanism,
967 												 eCharset, eEscapeType);
968 					appendUCS4(aSynAuthority, nUTF32, eEscapeType, bOctets,
969 							   PART_AUTHORITY, cEscapePrefix, eCharset,
970 							   false);
971 				}
972 				if (aSynAuthority.getLength() == 0)
973 				{
974 					setInvalid();
975 					return false;
976 				}
977 				m_aHost.set(aSynAbsURIRef,
978 							aSynAuthority.makeStringAndClear(),
979 							aSynAbsURIRef.getLength());
980 					// misusing m_aHost to store the authority
981 				break;
982 			}
983 
984 			case INET_PROT_FILE:
985 				if (bSmart)
986 				{
987 					// The first of the following seven productions that
988 					// matches the rest of the input string (and for which the
989 					// appropriate style bit is set in eStyle, if applicable)
990 					// determines the used notation.  The productions use the
991 					// auxiliary rules
992 					//
993 					//	  domain = label *("." label)
994 					//	  label = alphanum [*(alphanum / "-") alphanum]
995 					//	  alphanum = ALPHA / DIGIT
996 					//	  IPv6reference = "[" IPv6address "]"
997 					//	  IPv6address = hexpart [":" IPv4address]
998 					//	  IPv4address = 1*3DIGIT 3("." 1*3DIGIT)
999 					//	  hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq])
1000 					//	  hexseq = hex4 *(":" hex4)
1001 					//	  hex4 = 1*4HEXDIG
1002 					//	  path = <any UCS4 character except "#">
1003 					//	  UCS4 = <any UCS4 character>
1004 
1005 					// 1st Production (URL):
1006 					//	  "//" [domain / IPv6reference] ["/" *path]
1007 					//		  ["#" *UCS4]
1008 					//	becomes
1009 					//	  "file://" domain "/" *path ["#" *UCS4]
1010 					if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
1011 					{
1012 						sal_Unicode const * p1 = pPos + 2;
1013                         while (p1 != pEnd && *p1 != '/' &&
1014                                *p1 != nFragmentDelimiter)
1015                         {
1016                             ++p1;
1017                         }
1018                         if (parseHostOrNetBiosName(
1019                                 pPos + 2, p1, bOctets, ENCODE_ALL,
1020                                 RTL_TEXTENCODING_DONTKNOW, true, NULL))
1021 						{
1022                             aSynAbsURIRef.
1023                                 appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
1024 							pHostPortBegin = pPos + 2;
1025 							pHostPortEnd = p1;
1026 							pPos = p1;
1027 							break;
1028 						}
1029 					}
1030 
1031                     // 2nd Production (MS IE generated 1; FSYS_DOS only):
1032                     //    "//" ALPHA ":" ["/" *path] ["#" *UCS4]
1033 					//	becomes
1034 					//	  "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
1035 					//	replacing "\" by "/" within <*path>
1036                     //
1037                     // 3rd Production (MS IE generated 2; FSYS_DOS only):
1038                     //    "//" ALPHA ":" ["\" *path] ["#" *UCS4]
1039 					//	becomes
1040 					//	  "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
1041 					//	replacing "\" by "/" within <*path>
1042                     //
1043 					// 4th Production (misscounted slashes):
1044 					//	  "//" *path ["#" *UCS4]
1045 					//	becomes
1046 					//	  "file:///" *path ["#" *UCS4]
1047 					if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
1048 					{
1049                         aSynAbsURIRef.
1050                             appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
1051 						pPos += 2;
1052 						bSkippedInitialSlash = true;
1053                         if ((eStyle & FSYS_DOS) != 0
1054                             && pEnd - pPos >= 2
1055                             && INetMIME::isAlpha(pPos[0])
1056                             && pPos[1] == ':'
1057                             && (pEnd - pPos == 2
1058                                 || pPos[2] == '/' || pPos[2] == '\\'))
1059                             nAltSegmentDelimiter = '\\';
1060 						break;
1061 					}
1062 
1063 					// 5th Production (Unix):
1064 					//	  "/" *path ["#" *UCS4]
1065 					//	becomes
1066 					//	  "file:///" *path ["#" *UCS4]
1067 					if (pPos < pEnd && *pPos == '/')
1068                     {
1069                         aSynAbsURIRef.
1070                             appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
1071 						break;
1072                     }
1073 
1074 					// 6th Production (UNC; FSYS_DOS only):
1075 					//	  "\\" domain ["\" *path] ["#" *UCS4]
1076 					//	becomes
1077 					//	  "file://" domain "/" *path ["#" *UCS4]
1078 					//	replacing "\" by "/" within <*path>
1079 					if (eStyle & FSYS_DOS
1080 						&& pEnd - pPos >= 2
1081 						&& pPos[0] == '\\'
1082 						&& pPos[1] == '\\')
1083 					{
1084 						sal_Unicode const * p1 = pPos + 2;
1085                         sal_Unicode const * pe = p1;
1086                         while (pe < pEnd && *pe != '\\' &&
1087                                *pe != nFragmentDelimiter)
1088                         {
1089                             ++pe;
1090                         }
1091                         if (
1092                              parseHostOrNetBiosName(
1093                                 p1, pe, bOctets, ENCODE_ALL,
1094                                 RTL_TEXTENCODING_DONTKNOW, true, NULL) ||
1095                              (scanDomain(p1, pe) > 0 && p1 == pe)
1096                            )
1097 						{
1098                             aSynAbsURIRef.
1099                                 appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
1100 							pHostPortBegin = pPos + 2;
1101 							pHostPortEnd = pe;
1102 							pPos = pe;
1103 							nSegmentDelimiter = '\\';
1104 							break;
1105 						}
1106 					}
1107 
1108 					// 7th Production (Unix-like DOS; FSYS_DOS only):
1109 					//	  ALPHA ":" ["/" *path] ["#" *UCS4]
1110 					//	becomes
1111 					//	  "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
1112 					//	replacing "\" by "/" within <*path>
1113 					//
1114 					// 8th Production (DOS; FSYS_DOS only):
1115 					//	  ALPHA ":" ["\" *path] ["#" *UCS4]
1116 					//	becomes
1117 					//	  "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
1118 					//	replacing "\" by "/" within <*path>
1119 					if (eStyle & FSYS_DOS
1120 						&& pEnd - pPos >= 2
1121 						&& INetMIME::isAlpha(pPos[0])
1122 						&& pPos[1] == ':'
1123 						&& (pEnd - pPos == 2
1124                             || pPos[2] == '/'
1125                             || pPos[2] == '\\'))
1126 					{
1127                         aSynAbsURIRef.
1128                             appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
1129 						nAltSegmentDelimiter = '\\';
1130 						bSkippedInitialSlash = true;
1131 						break;
1132 					}
1133 
1134 					// 9th Production (any):
1135 					//	  *path ["#" *UCS4]
1136 					//	becomes
1137 					//	  "file:///" *path ["#" *UCS4]
1138 					//	replacing the delimiter by "/" within <*path>.	The
1139 					//	delimiter is that character from the set { "/", "\",
1140 					//	":" } which appears most often in <*path> (if FSYS_UNX
1141 					//  is not among the style bits, "/" is removed from the
1142 					//  set; if FSYS_DOS is not among the style bits, "\" is
1143 					//  removed from the set; if FSYS_MAC is not among the
1144 					//  style bits, ":" is removed from the set).  If two or
1145 					//	more characters appear the same number of times, the
1146 					//	character mentioned first in that set is chosen.  If
1147 					//	the first character of <*path> is the delimiter, that
1148 					//	character is not copied.
1149 					if (eStyle & (FSYS_UNX | FSYS_DOS | FSYS_MAC))
1150 					{
1151                         aSynAbsURIRef.
1152                             appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
1153 						switch (guessFSysStyleByCounting(pPos, pEnd, eStyle))
1154 						{
1155 							case FSYS_UNX:
1156 								nSegmentDelimiter = '/';
1157 								break;
1158 
1159 							case FSYS_DOS:
1160 								nSegmentDelimiter = '\\';
1161 								break;
1162 
1163 							case FSYS_MAC:
1164 								nSegmentDelimiter = ':';
1165 								break;
1166 
1167 							default:
1168 								DBG_ERROR(
1169 									"INetURLObject::setAbsURIRef():"
1170 									    " Bad guessFSysStyleByCounting");
1171 								break;
1172 						}
1173 						bSkippedInitialSlash
1174 							= pPos != pEnd && *pPos != nSegmentDelimiter;
1175 						break;
1176 					}
1177 				}
1178 			default:
1179 			{
1180                 // For INET_PROT_FILE, allow an empty authority ("//") to be
1181                 // missing if the following path starts with an explicit "/"
1182                 // (Java is notorious in generating such file URLs, so be
1183                 // liberal here):
1184 				if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
1185 					pPos += 2;
1186                 else if (!bSmart
1187                          && !(m_eScheme == INET_PROT_FILE
1188                               && pPos != pEnd && *pPos == '/'))
1189 				{
1190 					setInvalid();
1191 					return false;
1192 				}
1193                 aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
1194 
1195 				sal_Unicode const * pAuthority = pPos;
1196 				sal_uInt32 c = getSchemeInfo().m_bQuery ? '?' : 0x80000000;
1197 				while (pPos < pEnd && *pPos != '/' && *pPos != c
1198 					   && *pPos != nFragmentDelimiter)
1199 					++pPos;
1200 				if (getSchemeInfo().m_bUser)
1201 					if (getSchemeInfo().m_bHost)
1202 					{
1203 						sal_Unicode const * p1 = pAuthority;
1204 						while (p1 < pPos && *p1 != '@')
1205 							++p1;
1206 						if (p1 == pPos)
1207 						{
1208 							pHostPortBegin = pAuthority;
1209 							pHostPortEnd = pPos;
1210 						}
1211 						else
1212 						{
1213 							pUserInfoBegin = pAuthority;
1214 							pUserInfoEnd = p1;
1215 							pHostPortBegin = p1 + 1;
1216 							pHostPortEnd = pPos;
1217 						}
1218 					}
1219 					else
1220 					{
1221 						pUserInfoBegin = pAuthority;
1222 						pUserInfoEnd = pPos;
1223 					}
1224 				else if (getSchemeInfo().m_bHost)
1225 				{
1226 					pHostPortBegin = pAuthority;
1227 					pHostPortEnd = pPos;
1228 				}
1229 				else if (pPos != pAuthority)
1230 				{
1231 					setInvalid();
1232 					return false;
1233 				}
1234 				break;
1235 			}
1236 		}
1237 
1238 		if (pUserInfoBegin)
1239 		{
1240 			Part ePart = m_eScheme == INET_PROT_IMAP ?
1241 							 PART_IMAP_ACHAR :
1242 						 m_eScheme == INET_PROT_VIM ?
1243 							 PART_VIM :
1244 							 PART_USER_PASSWORD;
1245 			bool bSupportsPassword = getSchemeInfo().m_bPassword;
1246 			bool bSupportsAuth
1247 				= !bSupportsPassword && getSchemeInfo().m_bAuth;
1248 			bool bHasAuth = false;
1249 			rtl::OUStringBuffer aSynUser;
1250 			sal_Unicode const * p1 = pUserInfoBegin;
1251 			while (p1 < pUserInfoEnd)
1252 			{
1253 				EscapeType eEscapeType;
1254 				sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets,
1255 											 cEscapePrefix, eMechanism,
1256 											 eCharset, eEscapeType);
1257 				if (eEscapeType == ESCAPE_NO)
1258                 {
1259 					if (nUTF32 == ':' && bSupportsPassword)
1260 					{
1261 						bHasAuth = true;
1262 						break;
1263 					}
1264 					else if (nUTF32 == ';' && bSupportsAuth
1265 							 && pUserInfoEnd - p1
1266 									> RTL_CONSTASCII_LENGTH("auth=")
1267 							 && INetMIME::equalIgnoreCase(
1268 									p1,
1269 									p1 + RTL_CONSTASCII_LENGTH("auth="),
1270 									"auth="))
1271 					{
1272 						p1 += RTL_CONSTASCII_LENGTH("auth=");
1273 						bHasAuth = true;
1274 						break;
1275 					}
1276                 }
1277 				appendUCS4(aSynUser, nUTF32, eEscapeType, bOctets, ePart,
1278 						   cEscapePrefix, eCharset, false);
1279 			}
1280 			m_aUser.set(aSynAbsURIRef, aSynUser.makeStringAndClear(),
1281 				aSynAbsURIRef.getLength());
1282 			if (bHasAuth)
1283             {
1284 				if (bSupportsPassword)
1285 				{
1286 					aSynAbsURIRef.append(sal_Unicode(':'));
1287 					rtl::OUStringBuffer aSynAuth;
1288 					while (p1 < pUserInfoEnd)
1289 					{
1290 						EscapeType eEscapeType;
1291 						sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets,
1292 													 cEscapePrefix,
1293 													 eMechanism, eCharset,
1294 													 eEscapeType);
1295 						appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets,
1296 								   ePart, cEscapePrefix, eCharset, false);
1297 					}
1298 					m_aAuth.set(aSynAbsURIRef, aSynAuth.makeStringAndClear(),
1299 						aSynAbsURIRef.getLength());
1300 				}
1301 				else
1302 				{
1303 					aSynAbsURIRef.
1304 						appendAscii(RTL_CONSTASCII_STRINGPARAM(";AUTH="));
1305 					rtl::OUStringBuffer aSynAuth;
1306 					while (p1 < pUserInfoEnd)
1307 					{
1308 						EscapeType eEscapeType;
1309 						sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets,
1310 													 cEscapePrefix,
1311 													 eMechanism, eCharset,
1312 													 eEscapeType);
1313 						if (!INetMIME::isIMAPAtomChar(nUTF32))
1314 						{
1315 							setInvalid();
1316 							return false;
1317 						}
1318 						appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets,
1319 								   ePart, cEscapePrefix, eCharset, false);
1320 					}
1321 					m_aAuth.set(aSynAbsURIRef, aSynAuth.makeStringAndClear(),
1322 						aSynAbsURIRef.getLength());
1323 				}
1324             }
1325 			if (pHostPortBegin)
1326 				aSynAbsURIRef.append(sal_Unicode('@'));
1327 		}
1328 
1329 		if (pHostPortBegin)
1330 		{
1331 			sal_Unicode const * pPort = pHostPortEnd;
1332 			if ( getSchemeInfo().m_bPort && pHostPortBegin < pHostPortEnd )
1333 			{
1334 				sal_Unicode const * p1 = pHostPortEnd - 1;
1335 				while (p1 > pHostPortBegin && INetMIME::isDigit(*p1))
1336 					--p1;
1337 				if (*p1 == ':')
1338 					pPort = p1;
1339 			}
1340             bool bNetBiosName = false;
1341 			switch (m_eScheme)
1342 			{
1343 				case INET_PROT_FILE:
1344 					// If the host equals "LOCALHOST" (unencoded and ignoring
1345 					// case), turn it into an empty host:
1346 					if (INetMIME::equalIgnoreCase(pHostPortBegin, pPort,
1347 												  "localhost"))
1348 						pHostPortBegin = pPort;
1349                     bNetBiosName = true;
1350 					break;
1351 
1352 				case INET_PROT_LDAP:
1353                 case INET_PROT_SMB:
1354 					if (pHostPortBegin == pPort && pPort != pHostPortEnd)
1355 					{
1356 						setInvalid();
1357 						return false;
1358 					}
1359 					break;
1360 				default:
1361 					if (pHostPortBegin == pPort)
1362 					{
1363 						setInvalid();
1364 						return false;
1365 					}
1366 					break;
1367 			}
1368 			rtl::OUStringBuffer aSynHost;
1369 			if (!parseHostOrNetBiosName(
1370                     pHostPortBegin, pPort, bOctets, eMechanism, eCharset,
1371                     bNetBiosName, &aSynHost))
1372 			{
1373 				setInvalid();
1374 				return false;
1375 			}
1376 			m_aHost.set(aSynAbsURIRef, aSynHost.makeStringAndClear(),
1377 				aSynAbsURIRef.getLength());
1378 			if (pPort != pHostPortEnd)
1379 			{
1380 				aSynAbsURIRef.append(sal_Unicode(':'));
1381 				m_aPort.set(aSynAbsURIRef,
1382 					rtl::OUString(pPort + 1, pHostPortEnd - (pPort + 1)),
1383 					aSynAbsURIRef.getLength());
1384 			}
1385 		}
1386 	}
1387 
1388 	// Parse <path>
1389 	rtl::OUStringBuffer aSynPath;
1390 	if (!parsePath(m_eScheme, &pPos, pEnd, bOctets, eMechanism, eCharset,
1391 				   bSkippedInitialSlash, nSegmentDelimiter,
1392 				   nAltSegmentDelimiter,
1393 				   getSchemeInfo().m_bQuery ? '?' : 0x80000000,
1394 				   nFragmentDelimiter, aSynPath))
1395 	{
1396 		setInvalid();
1397 		return false;
1398 	}
1399 	m_aPath.set(aSynAbsURIRef, aSynPath.makeStringAndClear(),
1400 		aSynAbsURIRef.getLength());
1401 
1402 	// Parse ?<query>
1403 	if (getSchemeInfo().m_bQuery && pPos < pEnd && *pPos == '?')
1404 	{
1405 		aSynAbsURIRef.append(sal_Unicode('?'));
1406 		rtl::OUStringBuffer aSynQuery;
1407 		for (++pPos; pPos < pEnd && *pPos != nFragmentDelimiter;)
1408 		{
1409 			EscapeType eEscapeType;
1410 			sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, cEscapePrefix,
1411 										 eMechanism, eCharset, eEscapeType);
1412 			appendUCS4(aSynQuery, nUTF32, eEscapeType, bOctets,
1413 					   PART_URIC, cEscapePrefix, eCharset, true);
1414 		}
1415 		m_aQuery.set(aSynAbsURIRef, aSynQuery.makeStringAndClear(),
1416 			aSynAbsURIRef.getLength());
1417 	}
1418 
1419 	// Parse #<fragment>
1420 	if (pPos < pEnd && *pPos == nFragmentDelimiter)
1421 	{
1422 		aSynAbsURIRef.append(sal_Unicode(nFragmentDelimiter));
1423 		rtl::OUStringBuffer aSynFragment;
1424 		for (++pPos; pPos < pEnd;)
1425 		{
1426 			EscapeType eEscapeType;
1427 			sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, cEscapePrefix,
1428 										 eMechanism, eCharset, eEscapeType);
1429 			appendUCS4(aSynFragment, nUTF32, eEscapeType, bOctets, PART_URIC,
1430 					   cEscapePrefix, eCharset, true);
1431 		}
1432 		m_aFragment.set(aSynAbsURIRef, aSynFragment.makeStringAndClear(),
1433 			aSynAbsURIRef.getLength());
1434 	}
1435 
1436 	if (pPos != pEnd)
1437 	{
1438 		setInvalid();
1439 		return false;
1440 	}
1441 
1442 	m_aAbsURIRef = aSynAbsURIRef;
1443 
1444 	return true;
1445 }
1446 
1447 //============================================================================
convertRelToAbs(rtl::OUString const & rTheRelURIRef,bool bOctets,INetURLObject & rTheAbsURIRef,bool & rWasAbsolute,EncodeMechanism eMechanism,rtl_TextEncoding eCharset,bool bIgnoreFragment,bool bSmart,bool bRelativeNonURIs,FSysStyle eStyle) const1448 bool INetURLObject::convertRelToAbs(rtl::OUString const & rTheRelURIRef,
1449 									bool bOctets,
1450 									INetURLObject & rTheAbsURIRef,
1451 									bool & rWasAbsolute,
1452 									EncodeMechanism eMechanism,
1453 									rtl_TextEncoding eCharset,
1454 									bool bIgnoreFragment, bool bSmart,
1455 									bool bRelativeNonURIs, FSysStyle eStyle)
1456 	const
1457 {
1458 	sal_Unicode const * p = rTheRelURIRef.getStr();
1459 	sal_Unicode const * pEnd = p + rTheRelURIRef.getLength();
1460 
1461 	sal_Unicode const * pPrefixBegin = p;
1462 	PrefixInfo const * pPrefix = getPrefix(pPrefixBegin, pEnd);
1463     bool hasScheme = pPrefix != 0;
1464     if (!hasScheme) {
1465         pPrefixBegin = p;
1466         hasScheme = parseScheme(&pPrefixBegin, pEnd, '#').getLength() > 0;
1467     }
1468 
1469 	sal_uInt32 nSegmentDelimiter = '/';
1470 	sal_uInt32 nQueryDelimiter
1471 		= !bSmart || getSchemeInfo().m_bQuery ? '?' : 0x80000000;
1472 	sal_uInt32 nFragmentDelimiter = '#';
1473 	Part ePart = PART_VISIBLE;
1474 
1475 	if (!hasScheme && bSmart)
1476 	{
1477 		// If the input matches any of the following productions (for which
1478 		// the appropriate style bit is set in eStyle), it is assumed to be an
1479 		// absolute file system path, rather than a relative URI reference.
1480 		// (This is only a subset of the productions used for scheme detection
1481 		// in INetURLObject::setAbsURIRef(), because most of those productions
1482 		// interfere with the syntax of relative URI references.)  The
1483 		// productions use the auxiliary rules
1484 		//
1485 		//	  domain = label *("." label)
1486 		//	  label = alphanum [*(alphanum / "-") alphanum]
1487 		//	  alphanum = ALPHA / DIGIT
1488 		//	  UCS4 = <any UCS4 character>
1489 		//
1490 		// 1st Production (UNC file; FSYS_DOS only):
1491 		//	  "\\" domain ["\" *UCS4]
1492 		//
1493 		// 2nd Production (Unix-like DOS file; FSYS_DOS only):
1494 		//	  ALPHA ":" ["/" *UCS4]
1495 		//
1496 		// 3rd Production (DOS file; FSYS_DOS only):
1497 		//	  ALPHA ":" ["\" *UCS4]
1498 		if (eStyle & FSYS_DOS)
1499 		{
1500 			bool bFSys = false;
1501 			sal_Unicode const * q = p;
1502 			if (pEnd - q >= 2
1503 				&& INetMIME::isAlpha(q[0])
1504 				&& q[1] == ':'
1505                 && (pEnd - q == 2 || q[2] == '/' || q[2] == '\\'))
1506 				bFSys = true; // 2nd, 3rd
1507 			else if (pEnd - q >= 2 && q[0] == '\\' && q[1] == '\\')
1508 			{
1509 				q += 2;
1510                 sal_Int32 n = rtl_ustr_indexOfChar_WithLength(
1511                     q, pEnd - q, '\\');
1512                 sal_Unicode const * qe = n == -1 ? pEnd : q + n;
1513                 if (parseHostOrNetBiosName(
1514                         q, qe, bOctets, ENCODE_ALL, RTL_TEXTENCODING_DONTKNOW,
1515                         true, NULL))
1516                 {
1517 					bFSys = true; // 1st
1518                 }
1519 			}
1520 			if (bFSys)
1521 			{
1522 				INetURLObject aNewURI;
1523 				aNewURI.setAbsURIRef(rTheRelURIRef, bOctets, eMechanism,
1524 									 eCharset, true, eStyle);
1525 				if (!aNewURI.HasError())
1526 				{
1527 					rTheAbsURIRef = aNewURI;
1528 					rWasAbsolute = true;
1529 					return true;
1530 				}
1531 			}
1532 		}
1533 
1534 		// When the base URL is a file URL, accept relative file system paths
1535 		// using "\" or ":" as delimiter (and ignoring URI conventions for "%"
1536 		// and "#"), as well as relative URIs using "/" as delimiter:
1537 		if (m_eScheme == INET_PROT_FILE)
1538 			switch (guessFSysStyleByCounting(p, pEnd, eStyle))
1539 			{
1540 				case FSYS_UNX:
1541 					nSegmentDelimiter = '/';
1542 					break;
1543 
1544 				case FSYS_DOS:
1545 					nSegmentDelimiter = '\\';
1546 					bRelativeNonURIs = true;
1547 					break;
1548 
1549 				case FSYS_MAC:
1550 					nSegmentDelimiter = ':';
1551 					bRelativeNonURIs = true;
1552 					break;
1553 
1554 				default:
1555 					DBG_ERROR("INetURLObject::convertRelToAbs():"
1556 							      " Bad guessFSysStyleByCounting");
1557 					break;
1558 			}
1559 
1560 		if (bRelativeNonURIs)
1561 		{
1562 			eMechanism = ENCODE_ALL;
1563 			nQueryDelimiter = 0x80000000;
1564 			nFragmentDelimiter = 0x80000000;
1565 			ePart = PART_VISIBLE_NONSPECIAL;
1566 		}
1567 	}
1568 
1569 	// If the relative URI has the same scheme as the base URI, and that
1570 	// scheme is hierarchical, then ignore its presence in the relative
1571 	// URI in order to be backward compatible (cf. RFC 2396 section 5.2
1572 	// step 3):
1573 	if (pPrefix && pPrefix->m_eScheme == m_eScheme
1574 		&& getSchemeInfo().m_bHierarchical)
1575 	{
1576 		hasScheme = false;
1577 		while (p != pEnd && *p++ != ':') ;
1578 	}
1579 	rWasAbsolute = hasScheme;
1580 
1581 	// Fast solution for non-relative URIs:
1582 	if (hasScheme)
1583 	{
1584 		INetURLObject aNewURI(rTheRelURIRef, eMechanism, eCharset);
1585 		if (aNewURI.HasError())
1586 		{
1587 			rWasAbsolute = false;
1588 			return false;
1589 		}
1590 
1591 		if (bIgnoreFragment)
1592 			aNewURI.clearFragment();
1593 		rTheAbsURIRef = aNewURI;
1594 		return true;
1595 	}
1596 
1597 	enum State { STATE_AUTH, STATE_ABS_PATH, STATE_REL_PATH, STATE_FRAGMENT,
1598 				 STATE_DONE };
1599 
1600 	rtl::OUStringBuffer aSynAbsURIRef;
1601 	// make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme
1602 	// is empty ("") in that case, so take the scheme from m_aAbsURIRef
1603 	if (m_eScheme != INET_PROT_GENERIC)
1604 	{
1605 		aSynAbsURIRef.appendAscii(getSchemeInfo().m_pScheme);
1606 	}
1607 	else
1608 	{
1609 		sal_Unicode const * pSchemeBegin
1610 			= m_aAbsURIRef.getStr();
1611 		sal_Unicode const * pSchemeEnd = pSchemeBegin;
1612 		while (pSchemeEnd[0] != ':')
1613 		{
1614 			++pSchemeEnd;
1615 		}
1616 		aSynAbsURIRef.append(pSchemeBegin, pSchemeEnd - pSchemeBegin);
1617 	}
1618 	aSynAbsURIRef.append(sal_Unicode(':'));
1619 
1620 	sal_Char cEscapePrefix = getEscapePrefix();
1621 
1622 	State eState = STATE_AUTH;
1623 	bool bSameDoc = true;
1624 
1625 	if (getSchemeInfo().m_bAuthority)
1626     {
1627 		if (pEnd - p >= 2 && p[0] == '/' && p[1] == '/')
1628 		{
1629 			aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
1630 			p += 2;
1631 			eState = STATE_ABS_PATH;
1632 			bSameDoc = false;
1633 			while (p != pEnd)
1634 			{
1635 				EscapeType eEscapeType;
1636 				sal_uInt32 nUTF32
1637 					= getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
1638 							   eCharset, eEscapeType);
1639 				if (eEscapeType == ESCAPE_NO)
1640                 {
1641 					if (nUTF32 == nSegmentDelimiter)
1642 						break;
1643 					else if (nUTF32 == nFragmentDelimiter)
1644 					{
1645 						eState = STATE_FRAGMENT;
1646 						break;
1647 					}
1648                 }
1649 				appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets,
1650 						   PART_VISIBLE, cEscapePrefix, eCharset, true);
1651 			}
1652 		}
1653 		else
1654 		{
1655 			SubString aAuthority(getAuthority());
1656 			aSynAbsURIRef.append(m_aAbsURIRef.getStr()
1657 								     + aAuthority.getBegin(),
1658 								 aAuthority.getLength());
1659 		}
1660     }
1661 
1662 	if (eState == STATE_AUTH)
1663     {
1664 		if (p == pEnd)
1665 			eState = STATE_DONE;
1666 		else if (*p == nFragmentDelimiter)
1667 		{
1668 			++p;
1669 			eState = STATE_FRAGMENT;
1670 		}
1671 		else if (*p == nSegmentDelimiter)
1672 		{
1673 			++p;
1674 			eState = STATE_ABS_PATH;
1675 			bSameDoc = false;
1676 		}
1677 		else
1678 		{
1679 			eState = STATE_REL_PATH;
1680 			bSameDoc = false;
1681 		}
1682     }
1683 
1684 	if (eState == STATE_ABS_PATH)
1685 	{
1686 		aSynAbsURIRef.append(sal_Unicode('/'));
1687 		eState = STATE_DONE;
1688 		while (p != pEnd)
1689 		{
1690 			EscapeType eEscapeType;
1691 			sal_uInt32 nUTF32
1692 				= getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
1693 						   eCharset, eEscapeType);
1694 			if (eEscapeType == ESCAPE_NO)
1695             {
1696 				if (nUTF32 == nFragmentDelimiter)
1697 				{
1698 					eState = STATE_FRAGMENT;
1699 					break;
1700 				}
1701 				else if (nUTF32 == nSegmentDelimiter)
1702 					nUTF32 = '/';
1703             }
1704 			appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart,
1705 					   cEscapePrefix, eCharset, true);
1706 		}
1707 	}
1708 	else if (eState == STATE_REL_PATH)
1709 	{
1710 		if (!getSchemeInfo().m_bHierarchical)
1711 		{
1712             // Detect cases where a relative input could not be made absolute
1713             // because the given base URL is broken (most probably because it is
1714             // empty):
1715             OSL_ASSERT(!HasError());
1716 			rWasAbsolute = false;
1717 			return false;
1718 		}
1719 
1720 		sal_Unicode const * pBasePathBegin
1721 			= m_aAbsURIRef.getStr() + m_aPath.getBegin();
1722 		sal_Unicode const * pBasePathEnd
1723 			= pBasePathBegin + m_aPath.getLength();
1724 		while (pBasePathEnd != pBasePathBegin)
1725 			if (*(--pBasePathEnd) == '/')
1726 			{
1727 				++pBasePathEnd;
1728 				break;
1729 			}
1730 
1731 		sal_Int32 nPathBegin = aSynAbsURIRef.getLength();
1732 		aSynAbsURIRef.append(pBasePathBegin, pBasePathEnd - pBasePathBegin);
1733 		DBG_ASSERT(aSynAbsURIRef.getLength() > nPathBegin
1734 				 && aSynAbsURIRef.charAt(aSynAbsURIRef.getLength() - 1) == '/',
1735 				 "INetURLObject::convertRelToAbs(): Bad base path");
1736 
1737 		while (p != pEnd && *p != nQueryDelimiter && *p != nFragmentDelimiter)
1738 		{
1739 			if (*p == '.')
1740             {
1741 				if (pEnd - p == 1
1742 					|| p[1] == nSegmentDelimiter
1743 					|| p[1] == nQueryDelimiter
1744 					|| p[1] == nFragmentDelimiter)
1745 				{
1746 					++p;
1747 					if (p != pEnd && *p == nSegmentDelimiter)
1748 						++p;
1749 					continue;
1750 				}
1751 				else if (pEnd - p >= 2
1752 						 && p[1] == '.'
1753 						 && (pEnd - p == 2
1754 							 || p[2] == nSegmentDelimiter
1755 							 || p[2] == nQueryDelimiter
1756 							 || p[2] == nFragmentDelimiter)
1757 						 && aSynAbsURIRef.getLength() - nPathBegin > 1)
1758 				{
1759 					p += 2;
1760 					if (p != pEnd && *p == nSegmentDelimiter)
1761 						++p;
1762 
1763 					sal_Int32 i = aSynAbsURIRef.getLength() - 2;
1764 					while (i > nPathBegin && aSynAbsURIRef.charAt(i) != '/')
1765 						--i;
1766 					aSynAbsURIRef.setLength(i + 1);
1767 					DBG_ASSERT(
1768 						aSynAbsURIRef.getLength() > nPathBegin
1769 						&& aSynAbsURIRef.charAt(aSynAbsURIRef.getLength() - 1)
1770 						       == '/',
1771 						"INetURLObject::convertRelToAbs(): Bad base path");
1772 					continue;
1773 				}
1774             }
1775 
1776 			while (p != pEnd
1777 				   && *p != nSegmentDelimiter
1778 				   && *p != nQueryDelimiter
1779 				   && *p != nFragmentDelimiter)
1780 			{
1781 				EscapeType eEscapeType;
1782 				sal_uInt32 nUTF32
1783 					= getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
1784 							   eCharset, eEscapeType);
1785 				appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart,
1786 						   cEscapePrefix, eCharset, true);
1787 			}
1788 			if (p != pEnd && *p == nSegmentDelimiter)
1789 			{
1790 				aSynAbsURIRef.append(sal_Unicode('/'));
1791 				++p;
1792 			}
1793 		}
1794 
1795 		while (p != pEnd && *p != nFragmentDelimiter)
1796 		{
1797 			EscapeType eEscapeType;
1798 			sal_uInt32 nUTF32
1799 				= getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
1800 						   eCharset, eEscapeType);
1801 			appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart,
1802 					   cEscapePrefix, eCharset, true);
1803 		}
1804 
1805 		if (p == pEnd)
1806 			eState = STATE_DONE;
1807 		else
1808 		{
1809 			++p;
1810 			eState = STATE_FRAGMENT;
1811 		}
1812 	}
1813 	else if (bSameDoc)
1814 	{
1815 		aSynAbsURIRef.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(),
1816 							 m_aPath.getLength());
1817 		if (m_aQuery.isPresent())
1818 			aSynAbsURIRef.append(m_aAbsURIRef.getStr()
1819 								     + m_aQuery.getBegin() - 1,
1820 								 m_aQuery.getLength() + 1);
1821 	}
1822 
1823 	if (eState == STATE_FRAGMENT && !bIgnoreFragment)
1824 	{
1825 		aSynAbsURIRef.append(sal_Unicode('#'));
1826 		while (p != pEnd)
1827 		{
1828 			EscapeType eEscapeType;
1829 			sal_uInt32 nUTF32
1830 				= getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism,
1831 						   eCharset, eEscapeType);
1832 			appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets,
1833 					   PART_VISIBLE, cEscapePrefix, eCharset, true);
1834 		}
1835 	}
1836 
1837 	INetURLObject aNewURI(aSynAbsURIRef.makeStringAndClear());
1838 	if (aNewURI.HasError())
1839 	{
1840         // Detect cases where a relative input could not be made absolute
1841         // because the given base URL is broken (most probably because it is
1842         // empty):
1843         OSL_ASSERT(!HasError());
1844 		rWasAbsolute = false;
1845 		return false;
1846 	}
1847 
1848 	rTheAbsURIRef = aNewURI;
1849 	return true;
1850 }
1851 
1852 //============================================================================
convertAbsToRel(rtl::OUString const & rTheAbsURIRef,bool bOctets,rtl::OUString & rTheRelURIRef,EncodeMechanism eEncodeMechanism,DecodeMechanism eDecodeMechanism,rtl_TextEncoding eCharset,FSysStyle eStyle) const1853 bool INetURLObject::convertAbsToRel(rtl::OUString const & rTheAbsURIRef,
1854 									bool bOctets, rtl::OUString & rTheRelURIRef,
1855 									EncodeMechanism eEncodeMechanism,
1856 									DecodeMechanism eDecodeMechanism,
1857 									rtl_TextEncoding eCharset,
1858 									FSysStyle eStyle) const
1859 {
1860 	// Check for hierarchical base URL:
1861 	if (!getSchemeInfo().m_bHierarchical)
1862 	{
1863 		rTheRelURIRef
1864 			= decode(rTheAbsURIRef,
1865 					 getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)),
1866 					 eDecodeMechanism, eCharset);
1867 		return false;
1868 	}
1869 
1870 	// Convert the input (absolute or relative URI ref) to an absolute URI
1871     // ref:
1872 	INetURLObject aSubject;
1873 	bool bWasAbsolute;
1874 	if (!convertRelToAbs(rTheAbsURIRef, bOctets, aSubject, bWasAbsolute,
1875 						 eEncodeMechanism, eCharset, false, false, false,
1876 						 eStyle))
1877 	{
1878 		rTheRelURIRef
1879 			= decode(rTheAbsURIRef,
1880 					 getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)),
1881 					 eDecodeMechanism, eCharset);
1882 		return false;
1883 	}
1884 
1885 	// Check for differing scheme or authority parts:
1886     if ((m_aScheme.compare(
1887              aSubject.m_aScheme, m_aAbsURIRef, aSubject.m_aAbsURIRef)
1888          != 0)
1889         || (m_aUser.compare(
1890                 aSubject.m_aUser, m_aAbsURIRef, aSubject.m_aAbsURIRef)
1891             != 0)
1892         || (m_aAuth.compare(
1893                 aSubject.m_aAuth, m_aAbsURIRef, aSubject.m_aAbsURIRef)
1894             != 0)
1895         || (m_aHost.compare(
1896                 aSubject.m_aHost, m_aAbsURIRef, aSubject.m_aAbsURIRef)
1897             != 0)
1898         || (m_aPort.compare(
1899                 aSubject.m_aPort, m_aAbsURIRef, aSubject.m_aAbsURIRef)
1900             != 0))
1901 	{
1902 		rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
1903 		return false;
1904 	}
1905 
1906 	sal_Unicode const * pBasePathBegin
1907 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
1908 	sal_Unicode const * pBasePathEnd = pBasePathBegin + m_aPath.getLength();
1909 	sal_Unicode const * pSubjectPathBegin
1910 		= aSubject.m_aAbsURIRef.getStr() + aSubject.m_aPath.getBegin();
1911 	sal_Unicode const * pSubjectPathEnd
1912 		= pSubjectPathBegin + aSubject.m_aPath.getLength();
1913 
1914 	// Make nMatch point past the last matching slash, or past the end of the
1915 	// paths, in case they are equal:
1916 	sal_Unicode const * pSlash = 0;
1917 	sal_Unicode const * p1 = pBasePathBegin;
1918 	sal_Unicode const * p2 = pSubjectPathBegin;
1919 	for (;;)
1920 	{
1921 		if (p1 == pBasePathEnd || p2 == pSubjectPathEnd)
1922 		{
1923 			if (p1 == pBasePathEnd && p2 == pSubjectPathEnd)
1924 				pSlash = p1;
1925 			break;
1926 		}
1927 
1928 		sal_Unicode c = *p1++;
1929 		if (c != *p2++)
1930 			break;
1931 		if (c == '/')
1932 			pSlash = p1;
1933 	}
1934 	if (!pSlash)
1935 	{
1936 		// One of the paths does not start with '/':
1937 		rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
1938 		return false;
1939 	}
1940 	sal_Int32 nMatch = pSlash - pBasePathBegin;
1941 
1942     // If the two URLs are DOS file URLs starting with different volumes
1943     // (e.g., file:///a:/... and file:///b:/...), the subject is not made
1944     // relative (it could be, but some people do not like that):
1945     if (m_eScheme == INET_PROT_FILE
1946         && nMatch <= 1
1947         && hasDosVolume(eStyle)
1948         && aSubject.hasDosVolume(eStyle)) //TODO! ok to use eStyle for these?
1949 	{
1950 		rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset);
1951 		return false;
1952 	}
1953 
1954 	// For every slash in the base path after nMatch, a prefix of "../" is
1955 	// added to the new relative URL (if the common prefix of the two paths is
1956 	// only "/"---but see handling of file URLs above---, the complete subject
1957 	// path could go into the new relative URL instead, but some people don't
1958 	// like that):
1959 	rtl::OUStringBuffer aSynRelURIRef;
1960 //	if (nMatch <= 1) nMatch = 0; else // see comment above
1961 	for (sal_Unicode const * p = pBasePathBegin + nMatch; p != pBasePathEnd;
1962 		 ++p)
1963 	{
1964 		if (*p == '/')
1965 			aSynRelURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("../"));
1966 	}
1967 
1968 	// If the new relative URL would start with "//" (i.e., it would be
1969 	// mistaken for a relative URL starting with an authority part), or if the
1970 	// new relative URL would neither be empty nor start with <"/"> nor start
1971 	// with <1*rseg> (i.e., it could be mistaken for an absolute URL starting
1972 	// with a scheme part), then the new relative URL is prefixed with "./":
1973 	if (aSynRelURIRef.getLength() == 0)
1974     {
1975 		if (pSubjectPathEnd - pSubjectPathBegin >= nMatch + 2
1976 			&& pSubjectPathBegin[nMatch] == '/'
1977 			&& pSubjectPathBegin[nMatch + 1] == '/')
1978         {
1979 			aSynRelURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("./"));
1980         }
1981 		else
1982         {
1983 			for (sal_Unicode const * p = pSubjectPathBegin + nMatch;
1984 				 p != pSubjectPathEnd && *p != '/'; ++p)
1985             {
1986 				if (mustEncode(*p, PART_REL_SEGMENT_EXTRA))
1987 				{
1988 					aSynRelURIRef.
1989 						appendAscii(RTL_CONSTASCII_STRINGPARAM("./"));
1990 					break;
1991 				}
1992             }
1993         }
1994     }
1995 
1996 	// The remainder of the subject path, starting at nMatch, is appended to
1997 	// the new relative URL:
1998 	sal_Char cEscapePrefix = getEscapePrefix();
1999 	aSynRelURIRef.append(decode(pSubjectPathBegin + nMatch, pSubjectPathEnd,
2000 							cEscapePrefix, eDecodeMechanism, eCharset));
2001 
2002 	// If the subject has defined query or fragment parts, they are appended
2003 	// to the new relative URL:
2004 	if (aSubject.m_aQuery.isPresent())
2005 	{
2006 		aSynRelURIRef.append(sal_Unicode('?'));
2007 		aSynRelURIRef.append(aSubject.decode(aSubject.m_aQuery, cEscapePrefix,
2008 										 eDecodeMechanism, eCharset));
2009 	}
2010 	if (aSubject.m_aFragment.isPresent())
2011 	{
2012 		aSynRelURIRef.append(sal_Unicode('#'));
2013 		aSynRelURIRef.append(aSubject.decode(aSubject.m_aFragment,
2014 			cEscapePrefix, eDecodeMechanism, eCharset));
2015 	}
2016 
2017 	rTheRelURIRef = aSynRelURIRef.makeStringAndClear();
2018 	return true;
2019 }
2020 
2021 //============================================================================
2022 // static
convertIntToExt(rtl::OUString const & rTheIntURIRef,bool bOctets,rtl::OUString & rTheExtURIRef,DecodeMechanism eDecodeMechanism,rtl_TextEncoding eCharset)2023 bool INetURLObject::convertIntToExt(rtl::OUString const & rTheIntURIRef,
2024 									bool bOctets, rtl::OUString & rTheExtURIRef,
2025 									DecodeMechanism eDecodeMechanism,
2026 									rtl_TextEncoding eCharset)
2027 {
2028 	sal_Char cEscapePrefix
2029 		= getEscapePrefix(CompareProtocolScheme(rTheIntURIRef));
2030 	rtl::OUString aSynExtURIRef(encodeText(rTheIntURIRef, bOctets, PART_VISIBLE,
2031 									   cEscapePrefix, NOT_CANONIC, eCharset,
2032 									   true));
2033 	sal_Unicode const * pBegin = aSynExtURIRef.getStr();
2034 	sal_Unicode const * pEnd = pBegin + aSynExtURIRef.getLength();
2035 	sal_Unicode const * p = pBegin;
2036 	PrefixInfo const * pPrefix = getPrefix(p, pEnd);
2037 	bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::INTERNAL;
2038 	if (bConvert)
2039 	{
2040 		aSynExtURIRef =
2041 			aSynExtURIRef.replaceAt(0, p - pBegin,
2042 				rtl::OUString::createFromAscii(pPrefix->m_pTranslatedPrefix));
2043 	}
2044 	rTheExtURIRef = decode(aSynExtURIRef, cEscapePrefix, eDecodeMechanism,
2045 						   eCharset);
2046 	return bConvert;
2047 }
2048 
2049 //============================================================================
2050 // static
convertExtToInt(rtl::OUString const & rTheExtURIRef,bool bOctets,rtl::OUString & rTheIntURIRef,DecodeMechanism eDecodeMechanism,rtl_TextEncoding eCharset)2051 bool INetURLObject::convertExtToInt(rtl::OUString const & rTheExtURIRef,
2052 									bool bOctets, rtl::OUString & rTheIntURIRef,
2053 									DecodeMechanism eDecodeMechanism,
2054 									rtl_TextEncoding eCharset)
2055 {
2056 	sal_Char cEscapePrefix
2057 		= getEscapePrefix(CompareProtocolScheme(rTheExtURIRef));
2058 	rtl::OUString aSynIntURIRef(encodeText(rTheExtURIRef, bOctets, PART_VISIBLE,
2059 									   cEscapePrefix, NOT_CANONIC, eCharset,
2060 									   true));
2061 	sal_Unicode const * pBegin = aSynIntURIRef.getStr();
2062 	sal_Unicode const * pEnd = pBegin + aSynIntURIRef.getLength();
2063 	sal_Unicode const * p = pBegin;
2064 	PrefixInfo const * pPrefix = getPrefix(p, pEnd);
2065 	bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::EXTERNAL;
2066 	if (bConvert)
2067 	{
2068 		aSynIntURIRef =
2069 			aSynIntURIRef.replaceAt(0, p - pBegin,
2070 				rtl::OUString::createFromAscii(pPrefix->m_pTranslatedPrefix));
2071 	}
2072 	rTheIntURIRef = decode(aSynIntURIRef, cEscapePrefix, eDecodeMechanism,
2073 						   eCharset);
2074 	return bConvert;
2075 }
2076 
2077 //============================================================================
2078 // static
2079 INetURLObject::PrefixInfo const *
getPrefix(sal_Unicode const * & rBegin,sal_Unicode const * pEnd)2080 INetURLObject::getPrefix(sal_Unicode const *& rBegin,
2081 						 sal_Unicode const * pEnd)
2082 {
2083 	static PrefixInfo const aMap[]
2084 		= { // dummy entry at front needed, because pLast may point here:
2085 			{ 0, 0, INET_PROT_NOT_VALID, PrefixInfo::INTERNAL },
2086 			{ ".component:", "staroffice.component:", INET_PROT_COMPONENT,
2087 			  PrefixInfo::INTERNAL },
2088 			{ ".uno:", "staroffice.uno:", INET_PROT_UNO,
2089 			  PrefixInfo::INTERNAL },
2090 			{ "cid:", 0, INET_PROT_CID, PrefixInfo::OFFICIAL },
2091 			{ "data:", 0, INET_PROT_DATA, PrefixInfo::OFFICIAL },
2092 			{ "db:", "staroffice.db:", INET_PROT_DB, PrefixInfo::INTERNAL },
2093 			{ "file:", 0, INET_PROT_FILE, PrefixInfo::OFFICIAL },
2094 			{ "ftp:", 0, INET_PROT_FTP, PrefixInfo::OFFICIAL },
2095 			{ "hid:", "staroffice.hid:", INET_PROT_HID,
2096 			  PrefixInfo::INTERNAL },
2097 			{ "http:", 0, INET_PROT_HTTP, PrefixInfo::OFFICIAL },
2098 			{ "https:", 0, INET_PROT_HTTPS, PrefixInfo::OFFICIAL },
2099 			{ "imap:", 0, INET_PROT_IMAP, PrefixInfo::OFFICIAL },
2100 			{ "javascript:", 0, INET_PROT_JAVASCRIPT, PrefixInfo::OFFICIAL },
2101 			{ "ldap:", 0, INET_PROT_LDAP, PrefixInfo::OFFICIAL },
2102 			{ "macro:", "staroffice.macro:", INET_PROT_MACRO,
2103 			  PrefixInfo::INTERNAL },
2104 			{ "mailto:", 0, INET_PROT_MAILTO, PrefixInfo::OFFICIAL },
2105 			{ "news:", 0, INET_PROT_NEWS, PrefixInfo::OFFICIAL },
2106 			{ "out:", "staroffice.out:", INET_PROT_OUT,
2107 			  PrefixInfo::INTERNAL },
2108 			{ "pop3:", "staroffice.pop3:", INET_PROT_POP3,
2109 			  PrefixInfo::INTERNAL },
2110 			{ "private:", "staroffice.private:", INET_PROT_PRIV_SOFFICE,
2111 			  PrefixInfo::INTERNAL },
2112 			{ "private:factory/", "staroffice.factory:",
2113 			  INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL },
2114 			{ "private:helpid/", "staroffice.helpid:", INET_PROT_PRIV_SOFFICE,
2115 			  PrefixInfo::INTERNAL },
2116 			{ "private:java/", "staroffice.java:", INET_PROT_PRIV_SOFFICE,
2117 			  PrefixInfo::INTERNAL },
2118 			{ "private:searchfolder:", "staroffice.searchfolder:",
2119 			  INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL },
2120 			{ "private:trashcan:", "staroffice.trashcan:",
2121 			  INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL },
2122 			{ "slot:", "staroffice.slot:", INET_PROT_SLOT,
2123 			  PrefixInfo::INTERNAL },
2124             { "smb:", 0, INET_PROT_SMB, PrefixInfo::OFFICIAL },
2125 			{ "staroffice.component:", ".component:", INET_PROT_COMPONENT,
2126 			  PrefixInfo::EXTERNAL },
2127 			{ "staroffice.db:", "db:", INET_PROT_DB, PrefixInfo::EXTERNAL },
2128 			{ "staroffice.factory:", "private:factory/",
2129 			  INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL },
2130 			{ "staroffice.helpid:", "private:helpid/", INET_PROT_PRIV_SOFFICE,
2131 			  PrefixInfo::EXTERNAL },
2132 			{ "staroffice.hid:", "hid:", INET_PROT_HID,
2133 			  PrefixInfo::EXTERNAL },
2134 			{ "staroffice.java:", "private:java/", INET_PROT_PRIV_SOFFICE,
2135 			  PrefixInfo::EXTERNAL },
2136 			{ "staroffice.macro:", "macro:", INET_PROT_MACRO,
2137 			  PrefixInfo::EXTERNAL },
2138 			{ "staroffice.out:", "out:", INET_PROT_OUT,
2139 			  PrefixInfo::EXTERNAL },
2140 			{ "staroffice.pop3:", "pop3:", INET_PROT_POP3,
2141 			  PrefixInfo::EXTERNAL },
2142 			{ "staroffice.private:", "private:", INET_PROT_PRIV_SOFFICE,
2143 			  PrefixInfo::EXTERNAL },
2144 			{ "staroffice.searchfolder:", "private:searchfolder:",
2145 			  INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL },
2146 			{ "staroffice.slot:", "slot:", INET_PROT_SLOT,
2147 			  PrefixInfo::EXTERNAL },
2148 			{ "staroffice.trashcan:", "private:trashcan:",
2149 			  INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL },
2150 			{ "staroffice.uno:", ".uno:", INET_PROT_UNO,
2151 			  PrefixInfo::EXTERNAL },
2152 			{ "staroffice.vim:", "vim:", INET_PROT_VIM,
2153 			  PrefixInfo::EXTERNAL },
2154 			{ "staroffice:", "private:", INET_PROT_PRIV_SOFFICE,
2155 			  PrefixInfo::EXTERNAL },
2156             { "telnet:", 0, INET_PROT_TELNET, PrefixInfo::OFFICIAL },
2157 			{ "vim:", "staroffice.vim:", INET_PROT_VIM,
2158 			  PrefixInfo::INTERNAL },
2159 			{ "vnd.sun.star.cmd:", 0, INET_PROT_VND_SUN_STAR_CMD,
2160 			  PrefixInfo::OFFICIAL },
2161 			{ "vnd.sun.star.expand:", 0, INET_PROT_VND_SUN_STAR_EXPAND,
2162 			  PrefixInfo::OFFICIAL },
2163 			{ "vnd.sun.star.help:", 0, INET_PROT_VND_SUN_STAR_HELP,
2164 			  PrefixInfo::OFFICIAL },
2165 			{ "vnd.sun.star.hier:", 0, INET_PROT_VND_SUN_STAR_HIER,
2166 			  PrefixInfo::OFFICIAL },
2167 			{ "vnd.sun.star.odma:", 0, INET_PROT_VND_SUN_STAR_ODMA,
2168 			  PrefixInfo::OFFICIAL },
2169 			{ "vnd.sun.star.pkg:", 0, INET_PROT_VND_SUN_STAR_PKG,
2170 			  PrefixInfo::OFFICIAL },
2171             { "vnd.sun.star.tdoc:", 0, INET_PROT_VND_SUN_STAR_TDOC,
2172               PrefixInfo::OFFICIAL },
2173 			{ "vnd.sun.star.webdav:", 0, INET_PROT_VND_SUN_STAR_WEBDAV,
2174 			  PrefixInfo::OFFICIAL } };
2175 	PrefixInfo const * pFirst = aMap + 1;
2176 	PrefixInfo const * pLast = aMap + sizeof aMap / sizeof (PrefixInfo) - 1;
2177 	PrefixInfo const * pMatch = 0;
2178 	sal_Unicode const * pMatched = rBegin;
2179 	sal_Unicode const * p = rBegin;
2180 	sal_Int32 i = 0;
2181 	for (; pFirst < pLast; ++i)
2182 	{
2183 		if (pFirst->m_pPrefix[i] == '\0')
2184 		{
2185 			pMatch = pFirst++;
2186 			pMatched = p;
2187 		}
2188 		if (p >= pEnd)
2189 			break;
2190 		sal_uInt32 nChar = INetMIME::toLowerCase(*p++);
2191 		while (pFirst <= pLast && sal_uChar(pFirst->m_pPrefix[i]) < nChar)
2192 			++pFirst;
2193 		while (pFirst <= pLast && sal_uChar(pLast->m_pPrefix[i]) > nChar)
2194 			--pLast;
2195 	}
2196 	if (pFirst == pLast)
2197 	{
2198 		sal_Char const * q = pFirst->m_pPrefix + i;
2199 		while (p < pEnd && *q != '\0'
2200 			   && INetMIME::toLowerCase(*p) == sal_uChar(*q))
2201 		{
2202 			++p;
2203 			++q;
2204 		}
2205 		if (*q == '\0')
2206 		{
2207 			rBegin = p;
2208 			return pFirst;
2209 		}
2210 	}
2211 	rBegin = pMatched;
2212 	return pMatch;
2213 }
2214 
2215 //============================================================================
getAuthorityBegin() const2216 sal_Int32 INetURLObject::getAuthorityBegin() const
2217 {
2218 	DBG_ASSERT(getSchemeInfo().m_bAuthority,
2219 			   "INetURLObject::getAuthority(): Bad scheme");
2220 	sal_Int32 nBegin;
2221 	if (m_aUser.isPresent())
2222 		nBegin = m_aUser.getBegin();
2223 	else if (m_aHost.isPresent())
2224 		nBegin = m_aHost.getBegin();
2225 	else
2226 		nBegin = m_aPath.getBegin();
2227 	nBegin -= RTL_CONSTASCII_LENGTH("//");
2228 	DBG_ASSERT(m_aAbsURIRef.charAt(nBegin) == '/'
2229 			   && m_aAbsURIRef.charAt(nBegin + 1) == '/',
2230 			   "INetURLObject::getAuthority(): Bad authority");
2231     return nBegin;
2232 }
2233 
2234 //============================================================================
getAuthority() const2235 INetURLObject::SubString INetURLObject::getAuthority() const
2236 {
2237     sal_Int32 nBegin = getAuthorityBegin();
2238 	sal_Int32 nEnd = m_aPort.isPresent() ? m_aPort.getEnd() :
2239 					  m_aHost.isPresent() ? m_aHost.getEnd() :
2240 					  m_aAuth.isPresent() ? m_aAuth.getEnd() :
2241 		              m_aUser.isPresent() ? m_aUser.getEnd() :
2242 		                  nBegin + RTL_CONSTASCII_LENGTH("//");
2243 	return SubString(nBegin, nEnd - nBegin);
2244 }
2245 
2246 //============================================================================
setUser(rtl::OUString const & rTheUser,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)2247 bool INetURLObject::setUser(rtl::OUString const & rTheUser,
2248 							bool bOctets, EncodeMechanism eMechanism,
2249 							rtl_TextEncoding eCharset)
2250 {
2251 	if (
2252          !getSchemeInfo().m_bUser ||
2253          (m_eScheme == INET_PROT_IMAP && rTheUser.getLength() == 0)
2254        )
2255     {
2256 		return false;
2257     }
2258 
2259 	rtl::OUString aNewUser(encodeText(rTheUser, bOctets,
2260 								  m_eScheme == INET_PROT_IMAP ?
2261 									  PART_IMAP_ACHAR :
2262 								  m_eScheme == INET_PROT_VIM ?
2263 									  PART_VIM :
2264 									  PART_USER_PASSWORD,
2265 								  getEscapePrefix(), eMechanism, eCharset,
2266 								  false));
2267 	sal_Int32 nDelta;
2268 	if (m_aUser.isPresent())
2269 		nDelta = m_aUser.set(m_aAbsURIRef, aNewUser);
2270 	else if (m_aHost.isPresent())
2271 	{
2272 		m_aAbsURIRef.insert(m_aHost.getBegin(), sal_Unicode('@'));
2273 		nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aHost.getBegin()) + 1;
2274 	}
2275 	else if (getSchemeInfo().m_bHost)
2276 		return false;
2277 	else
2278 		nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aPath.getBegin());
2279 	m_aAuth += nDelta;
2280 	m_aHost += nDelta;
2281 	m_aPort += nDelta;
2282 	m_aPath += nDelta;
2283 	m_aQuery += nDelta;
2284 	m_aFragment += nDelta;
2285 	return true;
2286 }
2287 
2288 namespace
2289 {
lcl_Erase(rtl::OUStringBuffer & rBuf,sal_Int32 index,sal_Int32 count)2290 	void lcl_Erase(rtl::OUStringBuffer &rBuf, sal_Int32 index, sal_Int32 count)
2291 	{
2292 		rtl::OUString sTemp(rBuf.makeStringAndClear());
2293 		rBuf.append(sTemp.replaceAt(index, count, rtl::OUString()));
2294 	}
2295 }
2296 
2297 //============================================================================
clearPassword()2298 bool INetURLObject::clearPassword()
2299 {
2300 	if (!getSchemeInfo().m_bPassword)
2301 		return false;
2302 	if (m_aAuth.isPresent())
2303 	{
2304 		lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin() - 1,
2305 			m_aAuth.getLength() + 1);
2306 		sal_Int32 nDelta = m_aAuth.clear() - 1;
2307 		m_aHost += nDelta;
2308 		m_aPort += nDelta;
2309 		m_aPath += nDelta;
2310 		m_aQuery += nDelta;
2311 		m_aFragment += nDelta;
2312 	}
2313 	return true;
2314 }
2315 
2316 //============================================================================
setPassword(rtl::OUString const & rThePassword,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)2317 bool INetURLObject::setPassword(rtl::OUString const & rThePassword,
2318 								bool bOctets, EncodeMechanism eMechanism,
2319 								rtl_TextEncoding eCharset)
2320 {
2321 	if (!getSchemeInfo().m_bPassword)
2322 		return false;
2323 	rtl::OUString aNewAuth(encodeText(rThePassword, bOctets,
2324 								  m_eScheme == INET_PROT_VIM ?
2325 									  PART_VIM : PART_USER_PASSWORD,
2326 								  getEscapePrefix(), eMechanism, eCharset,
2327 								  false));
2328 	sal_Int32 nDelta;
2329 	if (m_aAuth.isPresent())
2330 		nDelta = m_aAuth.set(m_aAbsURIRef, aNewAuth);
2331 	else if (m_aUser.isPresent())
2332 	{
2333 		m_aAbsURIRef.insert(m_aUser.getEnd(), sal_Unicode(':'));
2334 		nDelta
2335 			= m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aUser.getEnd() + 1) + 1;
2336 	}
2337 	else if (m_aHost.isPresent())
2338 	{
2339 		m_aAbsURIRef.insert(m_aHost.getBegin(),
2340 			rtl::OUString::createFromAscii(":@"));
2341 		m_aUser.set(m_aAbsURIRef, rtl::OUString(), m_aHost.getBegin());
2342 		nDelta
2343 			= m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aHost.getBegin() + 1) + 2;
2344 	}
2345 	else if (getSchemeInfo().m_bHost)
2346 		return false;
2347 	else
2348 	{
2349 		m_aAbsURIRef.insert(m_aPath.getBegin(), sal_Unicode(':'));
2350 		m_aUser.set(m_aAbsURIRef, rtl::OUString(), m_aPath.getBegin());
2351 		nDelta
2352 			= m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aPath.getBegin() + 1) + 1;
2353 	}
2354 	m_aHost += nDelta;
2355 	m_aPort += nDelta;
2356 	m_aPath += nDelta;
2357 	m_aQuery += nDelta;
2358 	m_aFragment += nDelta;
2359 	return true;
2360 }
2361 
2362 //============================================================================
2363 // static
parseHost(sal_Unicode const * & rBegin,sal_Unicode const * pEnd,rtl::OUString & rCanonic)2364 bool INetURLObject::parseHost(
2365     sal_Unicode const *& rBegin, sal_Unicode const * pEnd,
2366     rtl::OUString & rCanonic)
2367 {
2368     // RFC 2373 is inconsistent about how to write an IPv6 address in which an
2369     // IPv4 address directly follows the abbreviating "::".  The ABNF in
2370     // Appendix B suggests ":::13.1.68.3", while an example in 2.2/3 explicitly
2371     // mentions "::13:1.68.3".  This algorithm accepts both variants:
2372 	enum State { STATE_INITIAL, STATE_LABEL, STATE_LABEL_HYPHEN,
2373 				 STATE_LABEL_DOT, STATE_TOPLABEL, STATE_TOPLABEL_HYPHEN,
2374 				 STATE_TOPLABEL_DOT, STATE_IP4, STATE_IP4_DOT, STATE_IP6,
2375 				 STATE_IP6_COLON, STATE_IP6_2COLON, STATE_IP6_3COLON,
2376 				 STATE_IP6_HEXSEQ1, STATE_IP6_HEXSEQ1_COLON,
2377 				 STATE_IP6_HEXSEQ1_MAYBE_IP4, STATE_IP6_HEXSEQ2,
2378 				 STATE_IP6_HEXSEQ2_COLON, STATE_IP6_HEXSEQ2_MAYBE_IP4,
2379 				 STATE_IP6_IP4, STATE_IP6_IP4_DOT, STATE_IP6_DONE };
2380 	rtl::OUStringBuffer aTheCanonic;
2381 	sal_uInt32 nNumber = 0;
2382 	int nDigits = 0;
2383 	int nOctets = 0;
2384 	State eState = STATE_INITIAL;
2385 	sal_Unicode const * p = rBegin;
2386 	for (; p != pEnd; ++p)
2387 		switch (eState)
2388 		{
2389 			case STATE_INITIAL:
2390 				if (*p == '[')
2391 				{
2392 					aTheCanonic.append(sal_Unicode('['));
2393 					eState = STATE_IP6;
2394 				}
2395 				else if (INetMIME::isAlpha(*p))
2396 					eState = STATE_TOPLABEL;
2397 				else if (INetMIME::isDigit(*p))
2398 				{
2399 					nNumber = INetMIME::getWeight(*p);
2400 					nDigits = 1;
2401 					nOctets = 1;
2402 					eState = STATE_IP4;
2403 				}
2404 				else
2405 					goto done;
2406 				break;
2407 
2408 			case STATE_LABEL:
2409 				if (*p == '.')
2410 					eState = STATE_LABEL_DOT;
2411 				else if (*p == '-')
2412 					eState = STATE_LABEL_HYPHEN;
2413 				else if (!INetMIME::isAlphanumeric(*p))
2414 					goto done;
2415 				break;
2416 
2417 			case STATE_LABEL_HYPHEN:
2418 				if (INetMIME::isAlphanumeric(*p))
2419 					eState = STATE_LABEL;
2420 				else if (*p != '-')
2421 					goto done;
2422 				break;
2423 
2424 			case STATE_LABEL_DOT:
2425 				if (INetMIME::isAlpha(*p))
2426 					eState = STATE_TOPLABEL;
2427 				else if (INetMIME::isDigit(*p))
2428 					eState = STATE_LABEL;
2429 				else
2430 					goto done;
2431 				break;
2432 
2433 			case STATE_TOPLABEL:
2434 				if (*p == '.')
2435 					eState = STATE_TOPLABEL_DOT;
2436 				else if (*p == '-')
2437 					eState = STATE_TOPLABEL_HYPHEN;
2438 				else if (!INetMIME::isAlphanumeric(*p))
2439 					goto done;
2440 				break;
2441 
2442 			case STATE_TOPLABEL_HYPHEN:
2443 				if (INetMIME::isAlphanumeric(*p))
2444 					eState = STATE_TOPLABEL;
2445 				else if (*p != '-')
2446 					goto done;
2447 				break;
2448 
2449 			case STATE_TOPLABEL_DOT:
2450 				if (INetMIME::isAlpha(*p))
2451 					eState = STATE_TOPLABEL;
2452 				else if (INetMIME::isDigit(*p))
2453 					eState = STATE_LABEL;
2454 				else
2455 					goto done;
2456 				break;
2457 
2458 			case STATE_IP4:
2459 				if (*p == '.')
2460 					if (nOctets < 4)
2461 					{
2462 						aTheCanonic.append(
2463 							rtl::OUString::valueOf(sal_Int32(nNumber)));
2464 						aTheCanonic.append(sal_Unicode('.'));
2465 						++nOctets;
2466 						eState = STATE_IP4_DOT;
2467 					}
2468 					else
2469 						eState = STATE_LABEL_DOT;
2470 				else if (*p == '-')
2471 					eState = STATE_LABEL_HYPHEN;
2472 				else if (INetMIME::isAlpha(*p))
2473 					eState = STATE_LABEL;
2474 				else if (INetMIME::isDigit(*p))
2475 					if (nDigits < 3)
2476 					{
2477 						nNumber = 10 * nNumber + INetMIME::getWeight(*p);
2478 						++nDigits;
2479 					}
2480 					else
2481 						eState = STATE_LABEL;
2482 				else
2483 					goto done;
2484 				break;
2485 
2486 			case STATE_IP4_DOT:
2487 				if (INetMIME::isAlpha(*p))
2488 					eState = STATE_TOPLABEL;
2489 				else if (INetMIME::isDigit(*p))
2490 				{
2491 					nNumber = INetMIME::getWeight(*p);
2492 					nDigits = 1;
2493 					eState = STATE_IP4;
2494 				}
2495 				else
2496 					goto done;
2497 				break;
2498 
2499 			case STATE_IP6:
2500 				if (*p == ':')
2501 					eState = STATE_IP6_COLON;
2502 				else if (INetMIME::isHexDigit(*p))
2503 				{
2504 					nNumber = INetMIME::getHexWeight(*p);
2505 					nDigits = 1;
2506 					eState = STATE_IP6_HEXSEQ1;
2507 				}
2508 				else
2509 					goto done;
2510 				break;
2511 
2512 			case STATE_IP6_COLON:
2513 				if (*p == ':')
2514 				{
2515 					aTheCanonic.appendAscii(RTL_CONSTASCII_STRINGPARAM("::"));
2516 					eState = STATE_IP6_2COLON;
2517 				}
2518 				else
2519 					goto done;
2520 				break;
2521 
2522 			case STATE_IP6_2COLON:
2523 				if (*p == ']')
2524 					eState = STATE_IP6_DONE;
2525 				else if (*p == ':')
2526 				{
2527 					aTheCanonic.append(sal_Unicode(':'));
2528 					eState = STATE_IP6_3COLON;
2529 				}
2530                 else if (INetMIME::isDigit(*p))
2531                 {
2532                     nNumber = INetMIME::getWeight(*p);
2533                     nDigits = 1;
2534                     eState = STATE_IP6_HEXSEQ2_MAYBE_IP4;
2535                 }
2536 				else if (INetMIME::isHexDigit(*p))
2537 				{
2538 					nNumber = INetMIME::getHexWeight(*p);
2539 					nDigits = 1;
2540 					eState = STATE_IP6_HEXSEQ2;
2541 				}
2542 				else
2543 					goto done;
2544 				break;
2545 
2546 			case STATE_IP6_3COLON:
2547 				if (INetMIME::isDigit(*p))
2548 				{
2549 					nNumber = INetMIME::getWeight(*p);
2550 					nDigits = 1;
2551 					nOctets = 1;
2552 					eState = STATE_IP6_IP4;
2553 				}
2554 				else
2555 					goto done;
2556 				break;
2557 
2558 			case STATE_IP6_HEXSEQ1:
2559 				if (*p == ']')
2560 				{
2561 					aTheCanonic.append(
2562 						rtl::OUString::valueOf(sal_Int32(nNumber), 16));
2563 					eState = STATE_IP6_DONE;
2564 				}
2565 				else if (*p == ':')
2566 				{
2567 					aTheCanonic.append(
2568 						rtl::OUString::valueOf(sal_Int32(nNumber), 16));
2569 					aTheCanonic.append(sal_Unicode(':'));
2570 					eState = STATE_IP6_HEXSEQ1_COLON;
2571 				}
2572 				else if (INetMIME::isHexDigit(*p) && nDigits < 4)
2573 				{
2574 					nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
2575 					++nDigits;
2576 				}
2577 				else
2578 					goto done;
2579 				break;
2580 
2581 			case STATE_IP6_HEXSEQ1_COLON:
2582 				if (*p == ':')
2583 				{
2584 					aTheCanonic.append(sal_Unicode(':'));
2585 					eState = STATE_IP6_2COLON;
2586 				}
2587 				else if (INetMIME::isDigit(*p))
2588 				{
2589 					nNumber = INetMIME::getWeight(*p);
2590 					nDigits = 1;
2591 					eState = STATE_IP6_HEXSEQ1_MAYBE_IP4;
2592 				}
2593 				else if (INetMIME::isHexDigit(*p))
2594 				{
2595 					nNumber = INetMIME::getHexWeight(*p);
2596 					nDigits = 1;
2597 					eState = STATE_IP6_HEXSEQ1;
2598 				}
2599 				else
2600 					goto done;
2601 				break;
2602 
2603 			case STATE_IP6_HEXSEQ1_MAYBE_IP4:
2604 				if (*p == ']')
2605 				{
2606 					aTheCanonic.append(
2607 						rtl::OUString::valueOf(sal_Int32(nNumber), 16));
2608 					eState = STATE_IP6_DONE;
2609 				}
2610 				else if (*p == ':')
2611 				{
2612 					aTheCanonic.append(
2613 						rtl::OUString::valueOf(sal_Int32(nNumber), 16));
2614 					aTheCanonic.append(sal_Unicode(':'));
2615 					eState = STATE_IP6_HEXSEQ1_COLON;
2616 				}
2617 				else if (*p == '.')
2618 				{
2619 					nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15)
2620 								  + (nNumber & 15);
2621 					aTheCanonic.append(
2622 						rtl::OUString::valueOf(sal_Int32(nNumber)));
2623 					aTheCanonic.append(sal_Unicode('.'));
2624 					nOctets = 2;
2625 					eState = STATE_IP6_IP4_DOT;
2626 				}
2627 				else if (INetMIME::isDigit(*p) && nDigits < 3)
2628 				{
2629 					nNumber = 16 * nNumber + INetMIME::getWeight(*p);
2630 					++nDigits;
2631 				}
2632 				else if (INetMIME::isHexDigit(*p) && nDigits < 4)
2633 				{
2634 					nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
2635 					++nDigits;
2636 					eState = STATE_IP6_HEXSEQ1;
2637 				}
2638 				else
2639 					goto done;
2640 				break;
2641 
2642 			case STATE_IP6_HEXSEQ2:
2643 				if (*p == ']')
2644 				{
2645 					aTheCanonic.append(
2646 						rtl::OUString::valueOf(sal_Int32(nNumber), 16));
2647 					eState = STATE_IP6_DONE;
2648 				}
2649 				else if (*p == ':')
2650 				{
2651 					aTheCanonic.append(
2652 						rtl::OUString::valueOf(sal_Int32(nNumber), 16));
2653 					aTheCanonic.append(sal_Unicode(':'));
2654 					eState = STATE_IP6_HEXSEQ2_COLON;
2655 				}
2656 				else if (INetMIME::isHexDigit(*p) && nDigits < 4)
2657 				{
2658 					nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
2659 					++nDigits;
2660 				}
2661 				else
2662 					goto done;
2663 				break;
2664 
2665 			case STATE_IP6_HEXSEQ2_COLON:
2666 				if (INetMIME::isDigit(*p))
2667 				{
2668 					nNumber = INetMIME::getWeight(*p);
2669 					nDigits = 1;
2670 					eState = STATE_IP6_HEXSEQ2_MAYBE_IP4;
2671 				}
2672 				else if (INetMIME::isHexDigit(*p))
2673 				{
2674 					nNumber = INetMIME::getHexWeight(*p);
2675 					nDigits = 1;
2676 					eState = STATE_IP6_HEXSEQ2;
2677 				}
2678 				else
2679 					goto done;
2680 				break;
2681 
2682 			case STATE_IP6_HEXSEQ2_MAYBE_IP4:
2683 				if (*p == ']')
2684 				{
2685 					aTheCanonic.append(
2686 						rtl::OUString::valueOf(sal_Int32(nNumber), 16));
2687 					eState = STATE_IP6_DONE;
2688 				}
2689 				else if (*p == ':')
2690 				{
2691 					aTheCanonic.append(
2692 						rtl::OUString::valueOf(sal_Int32(nNumber), 16));
2693 					aTheCanonic.append(sal_Unicode(':'));
2694 					eState = STATE_IP6_HEXSEQ2_COLON;
2695 				}
2696 				else if (*p == '.')
2697 				{
2698 					nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15)
2699 								  + (nNumber & 15);
2700 					aTheCanonic.append(
2701 						rtl::OUString::valueOf(sal_Int32(nNumber)));
2702 					aTheCanonic.append(sal_Unicode('.'));
2703 					nOctets = 2;
2704 					eState = STATE_IP6_IP4_DOT;
2705 				}
2706 				else if (INetMIME::isDigit(*p) && nDigits < 3)
2707 				{
2708 					nNumber = 16 * nNumber + INetMIME::getWeight(*p);
2709 					++nDigits;
2710 				}
2711 				else if (INetMIME::isHexDigit(*p) && nDigits < 4)
2712 				{
2713 					nNumber = 16 * nNumber + INetMIME::getHexWeight(*p);
2714 					++nDigits;
2715 					eState = STATE_IP6_HEXSEQ2;
2716 				}
2717 				else
2718 					goto done;
2719 				break;
2720 
2721 			case STATE_IP6_IP4:
2722 				if (*p == ']')
2723 					if (nOctets == 4)
2724 					{
2725 						aTheCanonic.append(
2726 							rtl::OUString::valueOf(sal_Int32(nNumber)));
2727 						eState = STATE_IP6_DONE;
2728 					}
2729 					else
2730 						goto done;
2731 				else if (*p == '.')
2732 					if (nOctets < 4)
2733 					{
2734 						aTheCanonic.append(
2735 							rtl::OUString::valueOf(sal_Int32(nNumber)));
2736 						aTheCanonic.append(sal_Unicode('.'));
2737 						++nOctets;
2738 						eState = STATE_IP6_IP4_DOT;
2739 					}
2740 					else
2741 						goto done;
2742 				else if (INetMIME::isDigit(*p) && nDigits < 3)
2743 				{
2744 					nNumber = 10 * nNumber + INetMIME::getWeight(*p);
2745 					++nDigits;
2746 				}
2747 				else
2748 					goto done;
2749 				break;
2750 
2751 			case STATE_IP6_IP4_DOT:
2752 				if (INetMIME::isDigit(*p))
2753 				{
2754 					nNumber = INetMIME::getWeight(*p);
2755 					nDigits = 1;
2756 					eState = STATE_IP6_IP4;
2757 				}
2758 				else
2759 					goto done;
2760 				break;
2761 
2762             case STATE_IP6_DONE:
2763                 goto done;
2764 		}
2765  done:
2766 	switch (eState)
2767 	{
2768 		case STATE_LABEL:
2769 		case STATE_TOPLABEL:
2770 		case STATE_TOPLABEL_DOT:
2771 			aTheCanonic.setLength(0);
2772 			aTheCanonic.append(rBegin, p - rBegin);
2773 			rBegin = p;
2774 			rCanonic = aTheCanonic.makeStringAndClear();
2775 			return true;
2776 
2777 		case STATE_IP4:
2778 			if (nOctets == 4)
2779 			{
2780 				aTheCanonic.append(
2781 					rtl::OUString::valueOf(sal_Int32(nNumber)));
2782 				rBegin = p;
2783 				rCanonic = aTheCanonic.makeStringAndClear();
2784 				return true;
2785 			}
2786 			return false;
2787 
2788 		case STATE_IP6_DONE:
2789 			aTheCanonic.append(sal_Unicode(']'));
2790 			rBegin = p;
2791 			rCanonic = aTheCanonic.makeStringAndClear();
2792 			return true;
2793 
2794         default:
2795             return false;
2796 	}
2797 }
2798 
2799 //============================================================================
2800 // static
parseHostOrNetBiosName(sal_Unicode const * pBegin,sal_Unicode const * pEnd,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset,bool bNetBiosName,rtl::OUStringBuffer * pCanonic)2801 bool INetURLObject::parseHostOrNetBiosName(
2802     sal_Unicode const * pBegin, sal_Unicode const * pEnd, bool bOctets,
2803     EncodeMechanism eMechanism, rtl_TextEncoding eCharset, bool bNetBiosName,
2804     rtl::OUStringBuffer* pCanonic)
2805 {
2806 	rtl::OUString aTheCanonic;
2807     if (pBegin < pEnd)
2808     {
2809         sal_Unicode const * p = pBegin;
2810         if (!parseHost(p, pEnd, aTheCanonic) || p != pEnd)
2811         {
2812             if (bNetBiosName)
2813             {
2814                 rtl::OUStringBuffer buf;
2815                 while (pBegin < pEnd)
2816                 {
2817                     EscapeType eEscapeType;
2818                     sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, bOctets, '%',
2819                                                  eMechanism, eCharset,
2820                                                  eEscapeType);
2821                     if (!INetMIME::isVisible(nUTF32))
2822                         return false;
2823                     if (!INetMIME::isAlphanumeric(nUTF32))
2824                         switch (nUTF32)
2825                         {
2826                         case '"':
2827                         case '*':
2828                         case '+':
2829                         case ',':
2830                         case '/':
2831                         case ':':
2832                         case ';':
2833                         case '<':
2834                         case '=':
2835                         case '>':
2836                         case '?':
2837                         case '[':
2838                         case '\\':
2839                         case ']':
2840                         case '`':
2841                         case '|':
2842                             return false;;
2843                         }
2844                     if (pCanonic != NULL) {
2845                         appendUCS4(
2846                             buf, nUTF32, eEscapeType, bOctets, PART_URIC, '%',
2847                             eCharset, true);
2848                     }
2849                 }
2850                 aTheCanonic = buf.makeStringAndClear();
2851             }
2852             else
2853                 return false;
2854         }
2855     }
2856     if (pCanonic != NULL) {
2857         *pCanonic = aTheCanonic;
2858     }
2859     return true;
2860 }
2861 
2862 //============================================================================
2863 // static
encodeHostPort(rtl::OUString const & rTheHostPort,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)2864 rtl::OUString INetURLObject::encodeHostPort(rtl::OUString const & rTheHostPort,
2865 										bool bOctets,
2866 										EncodeMechanism eMechanism,
2867 										rtl_TextEncoding eCharset)
2868 {
2869 	sal_Int32 nPort = rTheHostPort.getLength();
2870 	if (nPort != 0)
2871 	{
2872 		sal_Int32 i = nPort - 1;
2873 		while (i != 0 && INetMIME::isDigit(rTheHostPort.getStr()[i]))
2874 			--i;
2875 		if (rTheHostPort.getStr()[i] == ':')
2876 			nPort = i;
2877 	}
2878 	rtl::OUString aResult(encodeText(rTheHostPort.copy(0, nPort), bOctets,
2879 								 PART_HOST_EXTRA, '%', eMechanism, eCharset,
2880 								 true));
2881 	aResult += rTheHostPort.copy(nPort);
2882 	return aResult;
2883 }
2884 
2885 //============================================================================
setHost(rtl::OUString const & rTheHost,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)2886 bool INetURLObject::setHost(rtl::OUString const & rTheHost, bool bOctets,
2887 							EncodeMechanism eMechanism,
2888 							rtl_TextEncoding eCharset)
2889 {
2890 	if (!getSchemeInfo().m_bHost)
2891 		return false;
2892 	rtl::OUStringBuffer aSynHost(rTheHost);
2893     bool bNetBiosName = false;
2894 	switch (m_eScheme)
2895 	{
2896 		case INET_PROT_FILE:
2897 			{
2898 				rtl::OUString sTemp(aSynHost);
2899 				if (sTemp.equalsIgnoreAsciiCaseAsciiL(
2900 					RTL_CONSTASCII_STRINGPARAM("localhost")))
2901 				{
2902 					aSynHost.setLength(0);
2903 				}
2904             	bNetBiosName = true;
2905 			}
2906 			break;
2907 		case INET_PROT_LDAP:
2908 			if (aSynHost.getLength() == 0 && m_aPort.isPresent())
2909 				return false;
2910 			break;
2911 
2912 		default:
2913 			if (aSynHost.getLength() == 0)
2914 				return false;
2915 			break;
2916 	}
2917     if (!parseHostOrNetBiosName(
2918             aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(),
2919             bOctets, eMechanism, eCharset, bNetBiosName, &aSynHost))
2920         return false;
2921 	sal_Int32 nDelta = m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear());
2922 	m_aPort += nDelta;
2923 	m_aPath += nDelta;
2924 	m_aQuery += nDelta;
2925 	m_aFragment += nDelta;
2926 	return true;
2927 }
2928 
2929 //============================================================================
2930 // static
parsePath(INetProtocol eScheme,sal_Unicode const ** pBegin,sal_Unicode const * pEnd,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset,bool bSkippedInitialSlash,sal_uInt32 nSegmentDelimiter,sal_uInt32 nAltSegmentDelimiter,sal_uInt32 nQueryDelimiter,sal_uInt32 nFragmentDelimiter,rtl::OUStringBuffer & rSynPath)2931 bool INetURLObject::parsePath(INetProtocol eScheme,
2932                               sal_Unicode const ** pBegin,
2933 							  sal_Unicode const * pEnd,
2934 							  bool bOctets,
2935 							  EncodeMechanism eMechanism,
2936 							  rtl_TextEncoding eCharset,
2937 							  bool bSkippedInitialSlash,
2938 							  sal_uInt32 nSegmentDelimiter,
2939 							  sal_uInt32 nAltSegmentDelimiter,
2940 							  sal_uInt32 nQueryDelimiter,
2941 							  sal_uInt32 nFragmentDelimiter,
2942 							  rtl::OUStringBuffer &rSynPath)
2943 {
2944 	DBG_ASSERT(pBegin, "INetURLObject::parsePath(): Null output param");
2945 
2946 	sal_Unicode const * pPos = *pBegin;
2947 	rtl::OUStringBuffer aTheSynPath;
2948 
2949 	switch (eScheme)
2950 	{
2951 		case INET_PROT_NOT_VALID:
2952 			return false;
2953 
2954 		case INET_PROT_FTP:
2955 		case INET_PROT_IMAP:
2956 			if (pPos < pEnd && *pPos != '/')
2957 				return false;
2958 			while (pPos < pEnd && *pPos != nFragmentDelimiter)
2959 			{
2960 				EscapeType eEscapeType;
2961 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
2962 											 '%', eMechanism,
2963 											 eCharset, eEscapeType);
2964 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
2965 						   PART_HTTP_PATH, '%', eCharset, true);
2966 			}
2967 			if (aTheSynPath.getLength() == 0)
2968 				aTheSynPath.append(sal_Unicode('/'));
2969 			break;
2970 
2971 		case INET_PROT_HTTP:
2972 		case INET_PROT_VND_SUN_STAR_WEBDAV:
2973 		case INET_PROT_HTTPS:
2974         case INET_PROT_SMB:
2975 			if (pPos < pEnd && *pPos != '/')
2976 				return false;
2977 			while (pPos < pEnd && *pPos != nQueryDelimiter
2978 				   && *pPos != nFragmentDelimiter)
2979 			{
2980 				EscapeType eEscapeType;
2981 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
2982 											 '%', eMechanism,
2983 											 eCharset, eEscapeType);
2984 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
2985 						   PART_HTTP_PATH, '%', eCharset, true);
2986 			}
2987 			if (aTheSynPath.getLength() == 0)
2988 				aTheSynPath.append(sal_Unicode('/'));
2989 			break;
2990 
2991 		case INET_PROT_FILE:
2992 		{
2993 			if (bSkippedInitialSlash)
2994 				aTheSynPath.append(sal_Unicode('/'));
2995 			else if (pPos < pEnd
2996 					 && *pPos != nSegmentDelimiter
2997 					 && *pPos != nAltSegmentDelimiter)
2998 				return false;
2999 			while (pPos < pEnd && *pPos != nFragmentDelimiter)
3000 			{
3001 				EscapeType eEscapeType;
3002 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3003 											 '%', eMechanism,
3004 											 eCharset, eEscapeType);
3005 				if (eEscapeType == ESCAPE_NO)
3006                 {
3007 					if (nUTF32 == nSegmentDelimiter
3008 						|| nUTF32 == nAltSegmentDelimiter)
3009 					{
3010 						aTheSynPath.append(sal_Unicode('/'));
3011 						continue;
3012 					}
3013 					else if (nUTF32 == '|'
3014 							 && (pPos == pEnd
3015 								 || *pPos == nFragmentDelimiter
3016 								 || *pPos == nSegmentDelimiter
3017 								 || *pPos == nAltSegmentDelimiter)
3018 							 && aTheSynPath.getLength() == 2
3019 							 && INetMIME::isAlpha(aTheSynPath.charAt(1)))
3020 					{
3021 						// A first segment of <ALPHA "|"> is translated to
3022 						// <ALPHA ":">:
3023 						aTheSynPath.append(sal_Unicode(':'));
3024 						continue;
3025 					}
3026                 }
3027 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3028 						   PART_PCHAR, '%', eCharset, true);
3029 			}
3030 			if (aTheSynPath.getLength() == 0)
3031 				aTheSynPath.append(sal_Unicode('/'));
3032 			break;
3033 		}
3034 
3035 		case INET_PROT_MAILTO:
3036 			while (pPos < pEnd && *pPos != nQueryDelimiter
3037 				   && *pPos != nFragmentDelimiter)
3038 			{
3039 				EscapeType eEscapeType;
3040 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3041 											 '%', eMechanism,
3042 											 eCharset, eEscapeType);
3043 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3044 						   PART_MAILTO, '%', eCharset, true);
3045 			}
3046 			break;
3047 
3048 		case INET_PROT_NEWS:
3049             if (pPos == pEnd || *pPos == nQueryDelimiter
3050                 || *pPos == nFragmentDelimiter)
3051                 return false;
3052 
3053             // Match <"*">:
3054             if (*pPos == '*'
3055                 && (pEnd - pPos == 1 || pPos[1] == nQueryDelimiter
3056                     || pPos[1] == nFragmentDelimiter))
3057             {
3058                 ++pPos;
3059                 aTheSynPath.append(sal_Unicode('*'));
3060                 break;
3061             }
3062 
3063             // Match <group>:
3064             if (INetMIME::isAlpha(*pPos))
3065                 for (sal_Unicode const * p = pPos + 1;; ++p)
3066                     if (p == pEnd || *p == nQueryDelimiter
3067                         || *p == nFragmentDelimiter)
3068                     {
3069                         aTheSynPath.setLength(0);
3070                         aTheSynPath.append(pPos, p - pPos);
3071                         pPos = p;
3072                         goto done;
3073                     }
3074                     else if (!INetMIME::isAlphanumeric(*p) && *p != '+'
3075                              && *p != '-' && *p != '.' && *p != '_')
3076                         break;
3077 
3078             // Match <article>:
3079             for (;;)
3080             {
3081                 if (pPos == pEnd || *pPos == nQueryDelimiter
3082                     || *pPos == nFragmentDelimiter)
3083                     return false;
3084                 if (*pPos == '@')
3085                     break;
3086                 EscapeType eEscapeType;
3087                 sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, '%',
3088                                              eMechanism, eCharset, eEscapeType);
3089                 appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3090                            PART_NEWS_ARTICLE_LOCALPART, '%', eCharset, true);
3091             }
3092             if (aTheSynPath.getLength() == 0)
3093                 return false;
3094             ++pPos;
3095             aTheSynPath.append(sal_Unicode('@'));
3096             {
3097                 sal_Unicode const * p = pPos;
3098                 while (p < pEnd && *pPos != nQueryDelimiter
3099                        && *pPos != nFragmentDelimiter)
3100                     ++p;
3101                 rtl::OUString aCanonic;
3102                 if (!parseHost(pPos, p, aCanonic))
3103                     return false;
3104                 aTheSynPath.append(aCanonic);
3105             }
3106 
3107         done:
3108             break;
3109 
3110 		case INET_PROT_POP3:
3111 			while (pPos < pEnd && *pPos != nFragmentDelimiter)
3112 			{
3113 				EscapeType eEscapeType;
3114 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3115 											 '%', eMechanism,
3116 											 eCharset, eEscapeType);
3117 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3118 						   PART_MESSAGE_ID_PATH, '%', eCharset,
3119 						   true);
3120 			}
3121 			break;
3122 
3123 		case INET_PROT_PRIV_SOFFICE:
3124 		case INET_PROT_SLOT:
3125         case INET_PROT_HID:
3126 		case INET_PROT_MACRO:
3127 		case INET_PROT_UNO:
3128 		case INET_PROT_COMPONENT:
3129 		case INET_PROT_LDAP:
3130 			while (pPos < pEnd && *pPos != nQueryDelimiter
3131 				   && *pPos != nFragmentDelimiter)
3132 			{
3133 				EscapeType eEscapeType;
3134 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3135 											 '%', eMechanism,
3136 											 eCharset, eEscapeType);
3137 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3138 						   PART_PATH_BEFORE_QUERY, '%', eCharset,
3139 						   true);
3140 			}
3141 			break;
3142 
3143 		case INET_PROT_VND_SUN_STAR_HELP:
3144 			if (pPos == pEnd
3145                 || *pPos == nQueryDelimiter
3146                 || *pPos == nFragmentDelimiter)
3147 				aTheSynPath.append(sal_Unicode('/'));
3148 			else
3149 			{
3150 				if (*pPos != '/')
3151 					return false;
3152                 while (pPos < pEnd && *pPos != nQueryDelimiter
3153                        && *pPos != nFragmentDelimiter)
3154                 {
3155                     EscapeType eEscapeType;
3156                     sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3157                                                  '%', eMechanism,
3158                                                  eCharset, eEscapeType);
3159                     appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3160                                PART_HTTP_PATH, '%', eCharset, true);
3161                 }
3162             }
3163 			break;
3164 
3165 		case INET_PROT_JAVASCRIPT:
3166 		case INET_PROT_DATA:
3167 		case INET_PROT_CID:
3168 		case INET_PROT_DB:
3169 			while (pPos < pEnd && *pPos != nFragmentDelimiter)
3170 			{
3171 				EscapeType eEscapeType;
3172 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3173 											 '%', eMechanism,
3174 											 eCharset, eEscapeType);
3175 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3176 						   PART_URIC, '%', eCharset, true);
3177 			}
3178 			break;
3179 
3180 		case INET_PROT_OUT:
3181 			if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '~')
3182 				return false;
3183 			aTheSynPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("/~"));
3184 			while (pPos < pEnd && *pPos != nFragmentDelimiter)
3185 			{
3186 				EscapeType eEscapeType;
3187 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3188 											 '%', eMechanism,
3189 											 eCharset, eEscapeType);
3190 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3191 						   PART_URIC, '%', eCharset, true);
3192 			}
3193 			break;
3194 
3195 		case INET_PROT_VND_SUN_STAR_HIER:
3196 		case INET_PROT_VND_SUN_STAR_PKG:
3197 			if (pPos < pEnd && *pPos != '/'
3198                 && *pPos != nQueryDelimiter && *pPos != nFragmentDelimiter)
3199 				return false;
3200 			while (pPos < pEnd && *pPos != nQueryDelimiter
3201 				   && *pPos != nFragmentDelimiter)
3202 			{
3203 				EscapeType eEscapeType;
3204 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3205 											 '%', eMechanism,
3206 											 eCharset, eEscapeType);
3207 				if (eEscapeType == ESCAPE_NO && nUTF32 == '/')
3208 					aTheSynPath.append(sal_Unicode('/'));
3209 				else
3210 					appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3211 							   PART_PCHAR, '%', eCharset, false);
3212 			}
3213 			if (aTheSynPath.getLength() == 0)
3214 				aTheSynPath.append(sal_Unicode('/'));
3215 			break;
3216 
3217 		case INET_PROT_VIM:
3218 		{
3219 /* test had to be taken out to make parsePath static; ok since INET_PROT_VIM is
3220    obsolete, anyway
3221 			if (m_aUser.isEmpty())
3222 				return false;
3223 */
3224 			sal_Unicode const * pPathEnd = pPos;
3225 			while (pPathEnd < pEnd && *pPathEnd != nFragmentDelimiter)
3226 				++pPathEnd;
3227 			aTheSynPath.append(sal_Unicode('/'));
3228 			if (pPos == pPathEnd)
3229 				break;
3230 			else if (*pPos++ != '/')
3231 				return false;
3232 			if (pPos == pPathEnd)
3233 				break;
3234 			while (pPos < pPathEnd && *pPos != '/')
3235 			{
3236 				EscapeType eEscapeType;
3237 				sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets,
3238 											 '=', eMechanism,
3239 											 eCharset, eEscapeType);
3240 				appendUCS4(aTheSynPath,
3241 						   eEscapeType == ESCAPE_NO ?
3242 							   INetMIME::toLowerCase(nUTF32) : nUTF32,
3243 						   eEscapeType, bOctets, PART_VIM, '=',
3244 						   eCharset, false);
3245 			}
3246 			bool bInbox;
3247 			rtl::OUString sCompare(aTheSynPath);
3248 			if (sCompare.equalsAscii("/inbox"))
3249 				bInbox = true;
3250 			else if (sCompare.equalsAscii("/newsgroups"))
3251 				bInbox = false;
3252 			else
3253 				return false;
3254 			aTheSynPath.append(sal_Unicode('/'));
3255 			if (pPos == pPathEnd)
3256 				break;
3257 			else if (*pPos++ != '/')
3258 				return false;
3259 			if (!bInbox)
3260 			{
3261 				bool bEmpty = true;
3262 				while (pPos < pPathEnd && *pPos != '/')
3263 				{
3264 					EscapeType eEscapeType;
3265 					sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets,
3266 												 '=', eMechanism,
3267 												 eCharset, eEscapeType);
3268 					appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3269 							   PART_VIM, '=', eCharset, false);
3270 					bEmpty = false;
3271 				}
3272 				if (bEmpty)
3273 					return false;
3274 				aTheSynPath.append(sal_Unicode('/'));
3275 				if (pPos == pPathEnd)
3276 					break;
3277 				else if (*pPos++ != '/')
3278 					return false;
3279 			}
3280 			bool bEmpty = true;
3281 			while (pPos < pPathEnd && *pPos != ':')
3282 			{
3283 				EscapeType eEscapeType;
3284 				sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets,
3285 											 '=', eMechanism,
3286 											 eCharset, eEscapeType);
3287 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3288 						   PART_VIM, '=', eCharset, false);
3289 				bEmpty = false;
3290 			}
3291 			if (bEmpty)
3292 				return false;
3293 			if (pPos == pPathEnd)
3294 				break;
3295 			else if (*pPos++ != ':')
3296 				return false;
3297 			aTheSynPath.append(sal_Unicode(':'));
3298 			for (int i = 0; i < 3; ++i)
3299 			{
3300 				if (i != 0)
3301 				{
3302 					if (pPos == pPathEnd || *pPos++ != '.')
3303 						return false;
3304 					aTheSynPath.append(sal_Unicode('.'));
3305 				}
3306 				bEmpty = true;
3307 				while (pPos < pPathEnd && *pPos != '.')
3308 				{
3309 					EscapeType eEscapeType;
3310 					sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets,
3311 												 '=', eMechanism,
3312 												 eCharset, eEscapeType);
3313 					if (!INetMIME::isDigit(nUTF32))
3314 						return false;
3315 					aTheSynPath.append(sal_Unicode(nUTF32));
3316 					bEmpty = false;
3317 				}
3318 				if (bEmpty)
3319 					return false;
3320 			}
3321 			if (pPos != pPathEnd)
3322 				return false;
3323 			break;
3324 		}
3325 
3326 		case INET_PROT_VND_SUN_STAR_CMD:
3327 		case INET_PROT_VND_SUN_STAR_EXPAND:
3328 		{
3329 			if (pPos == pEnd || *pPos == nFragmentDelimiter)
3330 				return false;
3331 			Part ePart = PART_URIC_NO_SLASH;
3332 			while (pPos != pEnd && *pPos != nFragmentDelimiter)
3333 			{
3334 				EscapeType eEscapeType;
3335 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3336 											 '%', eMechanism,
3337 											 eCharset, eEscapeType);
3338 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, ePart,
3339 						   '%', eCharset, true);
3340 				ePart = PART_URIC;
3341 			}
3342 			break;
3343 		}
3344 
3345         case INET_PROT_VND_SUN_STAR_ODMA:
3346 			if (pPos < pEnd)
3347             {
3348                 if (*pPos == '/')
3349                     ++pPos;
3350                 else
3351                     return false;
3352             }
3353             aTheSynPath.append(sal_Unicode('/'));
3354 			while (pPos < pEnd && *pPos != nFragmentDelimiter)
3355 			{
3356 				EscapeType eEscapeType;
3357 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3358 											 '%', eMechanism,
3359 											 eCharset, eEscapeType);
3360 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3361 						   PART_URIC_NO_SLASH, '%', eCharset, true);
3362 			}
3363 			break;
3364 
3365         case INET_PROT_TELNET:
3366             if (pPos < pEnd)
3367             {
3368                 if (*pPos != '/' || pEnd - pPos > 1)
3369                     return false;
3370                 ++pPos;
3371             }
3372             aTheSynPath.append(sal_Unicode('/'));
3373             break;
3374 
3375 		case INET_PROT_VND_SUN_STAR_TDOC:
3376 			if (pPos == pEnd || *pPos != '/')
3377 				return false;
3378 			while (pPos < pEnd && *pPos != nFragmentDelimiter)
3379 			{
3380 				EscapeType eEscapeType;
3381 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3382 											 '%', eMechanism,
3383 											 eCharset, eEscapeType);
3384 				if (eEscapeType == ESCAPE_NO && nUTF32 == '/')
3385 					aTheSynPath.append(sal_Unicode('/'));
3386 				else
3387 					appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3388 							   PART_PCHAR, '%', eCharset, false);
3389 			}
3390 			break;
3391 
3392         case INET_PROT_GENERIC:
3393 			while (pPos < pEnd && *pPos != nFragmentDelimiter)
3394 			{
3395 				EscapeType eEscapeType;
3396 				sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets,
3397 											 '%', eMechanism,
3398 											 eCharset, eEscapeType);
3399 				appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets,
3400 						   PART_URIC, '%', eCharset, true);
3401 			}
3402 			if (aTheSynPath.getLength() == 0)
3403                 return false;
3404 			break;
3405         default:
3406             OSL_ASSERT(false);
3407             break;
3408 	}
3409 
3410 	*pBegin = pPos;
3411 	rSynPath = aTheSynPath;
3412 	return true;
3413 }
3414 
3415 //============================================================================
setPath(rtl::OUString const & rThePath,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)3416 bool INetURLObject::setPath(rtl::OUString const & rThePath, bool bOctets,
3417 							EncodeMechanism eMechanism,
3418 							rtl_TextEncoding eCharset)
3419 {
3420 	rtl::OUStringBuffer aSynPath;
3421 	sal_Unicode const * p = rThePath.getStr();
3422 	sal_Unicode const * pEnd = p + rThePath.getLength();
3423 	if (!parsePath(m_eScheme, &p, pEnd, bOctets, eMechanism, eCharset, false,
3424                    '/', 0x80000000, 0x80000000, 0x80000000, aSynPath)
3425 		|| p != pEnd)
3426 		return false;
3427 	sal_Int32 nDelta = m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear());
3428 	m_aQuery += nDelta;
3429 	m_aFragment += nDelta;
3430 	return true;
3431 }
3432 
3433 //============================================================================
checkHierarchical() const3434 bool INetURLObject::checkHierarchical() const {
3435     if (m_eScheme == INET_PROT_VND_SUN_STAR_EXPAND) {
3436         OSL_ENSURE(
3437             false, "INetURLObject::checkHierarchical vnd.sun.star.expand");
3438         return true;
3439     } else {
3440         return getSchemeInfo().m_bHierarchical;
3441     }
3442 }
3443 
3444 //============================================================================
appendSegment(rtl::OUString const & rTheSegment,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)3445 bool INetURLObject::appendSegment(rtl::OUString const & rTheSegment,
3446 								  bool bOctets, EncodeMechanism eMechanism,
3447 								  rtl_TextEncoding eCharset)
3448 {
3449 	return insertName(rTheSegment, bOctets, false, LAST_SEGMENT, true,
3450 					  eMechanism, eCharset);
3451 }
3452 
3453 //============================================================================
getSegment(sal_Int32 nIndex,bool bIgnoreFinalSlash) const3454 INetURLObject::SubString INetURLObject::getSegment(sal_Int32 nIndex,
3455 												   bool bIgnoreFinalSlash)
3456 	const
3457 {
3458 	DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT,
3459 			   "INetURLObject::getSegment(): Bad index");
3460 
3461 	if (!checkHierarchical())
3462 		return SubString();
3463 
3464 	sal_Unicode const * pPathBegin
3465 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
3466 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
3467 	sal_Unicode const * pSegBegin;
3468 	sal_Unicode const * pSegEnd;
3469 	if (nIndex == LAST_SEGMENT)
3470 	{
3471 		pSegEnd = pPathEnd;
3472 		if (bIgnoreFinalSlash && pSegEnd > pPathBegin && pSegEnd[-1] == '/')
3473 			--pSegEnd;
3474         if (pSegEnd <= pPathBegin)
3475             return SubString();
3476 		pSegBegin = pSegEnd - 1;
3477 		while (pSegBegin > pPathBegin && *pSegBegin != '/')
3478 			--pSegBegin;
3479 	}
3480 	else
3481 	{
3482 		pSegBegin = pPathBegin;
3483 		while (nIndex-- > 0)
3484 			do
3485 			{
3486 				++pSegBegin;
3487 				if (pSegBegin >= pPathEnd)
3488 					return SubString();
3489 			}
3490 			while (*pSegBegin != '/');
3491 		pSegEnd = pSegBegin + 1;
3492 		while (pSegEnd < pPathEnd && *pSegEnd != '/')
3493 			++pSegEnd;
3494 	}
3495 
3496 	return SubString(pSegBegin - m_aAbsURIRef.getStr(),
3497 					 pSegEnd - pSegBegin);
3498 }
3499 
3500 //============================================================================
insertName(rtl::OUString const & rTheName,bool bOctets,bool bAppendFinalSlash,sal_Int32 nIndex,bool bIgnoreFinalSlash,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)3501 bool INetURLObject::insertName(rtl::OUString const & rTheName, bool bOctets,
3502 							   bool bAppendFinalSlash, sal_Int32 nIndex,
3503 							   bool bIgnoreFinalSlash,
3504 							   EncodeMechanism eMechanism,
3505 							   rtl_TextEncoding eCharset)
3506 {
3507 	DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT,
3508 			   "INetURLObject::insertName(): Bad index");
3509 
3510 	if (!checkHierarchical())
3511 		return false;
3512 
3513 	sal_Unicode const * pPathBegin
3514 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
3515 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
3516 	sal_Unicode const * pPrefixEnd;
3517     bool bInsertSlash;
3518 	sal_Unicode const * pSuffixBegin;
3519 	if (nIndex == LAST_SEGMENT)
3520 	{
3521 		pPrefixEnd = pPathEnd;
3522 		if (bIgnoreFinalSlash && pPrefixEnd > pPathBegin &&
3523             pPrefixEnd[-1] == '/')
3524         {
3525 			--pPrefixEnd;
3526         }
3527         bInsertSlash = bAppendFinalSlash;
3528         pSuffixBegin = pPathEnd;
3529 	}
3530     else if (nIndex == 0)
3531     {
3532         pPrefixEnd = pPathBegin;
3533         bInsertSlash =
3534             (pPathBegin < pPathEnd && *pPathBegin != '/') ||
3535             (pPathBegin == pPathEnd && bAppendFinalSlash);
3536         pSuffixBegin =
3537             (pPathEnd - pPathBegin == 1 && *pPathBegin == '/' &&
3538              !bAppendFinalSlash && bIgnoreFinalSlash)
3539             ? pPathEnd : pPathBegin;
3540     }
3541 	else
3542 	{
3543 		pPrefixEnd = pPathBegin;
3544 		sal_Unicode const * pEnd = pPathEnd;
3545 		if (bIgnoreFinalSlash && pEnd > pPathBegin && pEnd[-1] == '/')
3546 			--pEnd;
3547         bool bSkip = pPrefixEnd < pEnd && *pPrefixEnd == '/';
3548         bInsertSlash = false;
3549         pSuffixBegin = pPathEnd;
3550  		while (nIndex-- > 0)
3551 			for (;;)
3552 			{
3553                 if (bSkip)
3554                     ++pPrefixEnd;
3555                 bSkip = true;
3556 				if (pPrefixEnd >= pEnd)
3557                 {
3558 					if (nIndex == 0)
3559 					{
3560                         bInsertSlash = bAppendFinalSlash;
3561 						break;
3562 					}
3563 					else
3564 						return false;
3565                 }
3566 				if (*pPrefixEnd == '/')
3567 				{
3568 					pSuffixBegin = pPrefixEnd;
3569 					break;
3570 				}
3571 			}
3572 	}
3573 
3574 	rtl::OUStringBuffer aNewPath;
3575 	aNewPath.append(pPathBegin, pPrefixEnd - pPathBegin);
3576     aNewPath.append(sal_Unicode('/'));
3577 	aNewPath.append(encodeText(rTheName, bOctets, PART_PCHAR, getEscapePrefix(),
3578 						   eMechanism, eCharset, true));
3579     if (bInsertSlash) {
3580         aNewPath.append(sal_Unicode('/'));
3581     }
3582     aNewPath.append(pSuffixBegin, pPathEnd - pSuffixBegin);
3583 
3584 	return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
3585 		RTL_TEXTENCODING_UTF8);
3586 }
3587 
3588 //============================================================================
clearQuery()3589 bool INetURLObject::clearQuery()
3590 {
3591 	if (HasError())
3592 		return false;
3593 	if (m_aQuery.isPresent())
3594 	{
3595 		lcl_Erase(m_aAbsURIRef, m_aQuery.getBegin() - 1,
3596 			m_aQuery.getLength() + 1);
3597 		m_aFragment += m_aQuery.clear() - 1;
3598 	}
3599 	return false;
3600 }
3601 
3602 //============================================================================
setQuery(rtl::OUString const & rTheQuery,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)3603 bool INetURLObject::setQuery(rtl::OUString const & rTheQuery, bool bOctets,
3604 							 EncodeMechanism eMechanism,
3605 							 rtl_TextEncoding eCharset)
3606 {
3607 	if (!getSchemeInfo().m_bQuery)
3608 		return false;
3609 	rtl::OUString aNewQuery(encodeText(rTheQuery, bOctets, PART_URIC,
3610 								   getEscapePrefix(), eMechanism, eCharset,
3611 								   true));
3612 	sal_Int32 nDelta;
3613 	if (m_aQuery.isPresent())
3614 		nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery);
3615 	else
3616 	{
3617 		m_aAbsURIRef.insert(m_aPath.getEnd(), sal_Unicode('?'));
3618 		nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery, m_aPath.getEnd() + 1)
3619 					 + 1;
3620 	}
3621 	m_aFragment += nDelta;
3622 	return true;
3623 }
3624 
3625 //============================================================================
clearFragment()3626 bool INetURLObject::clearFragment()
3627 {
3628 	if (HasError())
3629 		return false;
3630 	if (m_aFragment.isPresent())
3631 	{
3632 		m_aAbsURIRef.setLength(m_aFragment.getBegin() - 1);
3633 		m_aFragment.clear();
3634 	}
3635 	return true;
3636 }
3637 
3638 //============================================================================
setFragment(rtl::OUString const & rTheFragment,bool bOctets,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)3639 bool INetURLObject::setFragment(rtl::OUString const & rTheFragment,
3640 								bool bOctets, EncodeMechanism eMechanism,
3641 								rtl_TextEncoding eCharset)
3642 {
3643 	if (HasError())
3644 		return false;
3645 	rtl::OUString aNewFragment(encodeText(rTheFragment, bOctets, PART_URIC,
3646 									  getEscapePrefix(), eMechanism,
3647 									  eCharset, true));
3648 	if (m_aFragment.isPresent())
3649 		m_aFragment.set(m_aAbsURIRef, aNewFragment);
3650 	else
3651 	{
3652 		m_aAbsURIRef.append(sal_Unicode('#'));
3653 		m_aFragment.set(m_aAbsURIRef, aNewFragment, m_aAbsURIRef.getLength());
3654 	}
3655 	return true;
3656 }
3657 
3658 //============================================================================
getFTPType() const3659 INetURLObject::FTPType INetURLObject::getFTPType() const
3660 {
3661 	if (m_eScheme == INET_PROT_FTP
3662 		&& m_aPath.getLength() >= RTL_CONSTASCII_LENGTH(";type=") + 1
3663 		&& rtl::OUString(m_aAbsURIRef).copy(
3664 			m_aPath.getEnd() - (RTL_CONSTASCII_LENGTH(";type=") + 1),
3665 			RTL_CONSTASCII_LENGTH(";type=")).equalsIgnoreAsciiCaseAscii(";type="))
3666 		switch (m_aAbsURIRef.charAt(m_aPath.getEnd()))
3667 		{
3668 			case 'A':
3669 			case 'a':
3670 				return FTP_TYPE_A;
3671 
3672 			case 'D':
3673 			case 'd':
3674 				return FTP_TYPE_D;
3675 
3676 			case 'I':
3677 			case 'i':
3678 				return FTP_TYPE_I;
3679 		}
3680 	return FTP_TYPE_NONE;
3681 }
3682 
3683 //============================================================================
hasDosVolume(FSysStyle eStyle) const3684 bool INetURLObject::hasDosVolume(FSysStyle eStyle) const
3685 {
3686     sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
3687     return (eStyle & FSYS_DOS) != 0
3688            && m_aPath.getLength() >= 3
3689            && p[0] == '/'
3690            && INetMIME::isAlpha(p[1])
3691            && p[2] == ':'
3692            && (m_aPath.getLength() == 3 || p[3] == '/');
3693 }
3694 
3695 //============================================================================
getIMAPUID() const3696 sal_uInt32 INetURLObject::getIMAPUID() const
3697 {
3698 	if (m_eScheme == INET_PROT_IMAP
3699 		&& m_aPath.getLength() >= RTL_CONSTASCII_LENGTH("/;uid=") + 1)
3700 	{
3701 		sal_Unicode const * pBegin = m_aAbsURIRef.getStr()
3702 										 + m_aPath.getBegin()
3703 										 + RTL_CONSTASCII_LENGTH("/;uid=");
3704 		sal_Unicode const * pEnd = pBegin + m_aPath.getLength();
3705 		sal_Unicode const * p = pEnd;
3706 		while (p > pBegin && INetMIME::isDigit(p[-1]))
3707 			--p;
3708 		if (p < pEnd && *--p != '0'
3709 			&& rtl::OUString(m_aAbsURIRef).copy(
3710 				p - RTL_CONSTASCII_LENGTH("/;uid=") - m_aAbsURIRef.getStr(),
3711 				RTL_CONSTASCII_LENGTH("/;uid=")).equalsIgnoreAsciiCaseAscii("/;uid=")
3712 		   )
3713 		{
3714 			sal_uInt32 nUID;
3715 			if (INetMIME::scanUnsigned(p, pEnd, false, nUID))
3716 				return nUID;
3717 		}
3718 	}
3719 	return 0;
3720 }
3721 
3722 //============================================================================
3723 // static
encodeText(sal_Unicode const * pBegin,sal_Unicode const * pEnd,bool bOctets,Part ePart,sal_Char cEscapePrefix,EncodeMechanism eMechanism,rtl_TextEncoding eCharset,bool bKeepVisibleEscapes)3724 rtl::OUString INetURLObject::encodeText(sal_Unicode const * pBegin,
3725 									sal_Unicode const * pEnd, bool bOctets,
3726 									Part ePart, sal_Char cEscapePrefix,
3727 									EncodeMechanism eMechanism,
3728 									rtl_TextEncoding eCharset,
3729 									bool bKeepVisibleEscapes)
3730 {
3731 	rtl::OUStringBuffer aResult;
3732 	while (pBegin < pEnd)
3733 	{
3734 		EscapeType eEscapeType;
3735 		sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, bOctets, cEscapePrefix,
3736 									 eMechanism, eCharset, eEscapeType);
3737 		appendUCS4(aResult, nUTF32, eEscapeType, bOctets, ePart,
3738 				   cEscapePrefix, eCharset, bKeepVisibleEscapes);
3739 	}
3740 	return aResult.makeStringAndClear();
3741 }
3742 
3743 //============================================================================
3744 // static
decode(sal_Unicode const * pBegin,sal_Unicode const * pEnd,sal_Char cEscapePrefix,DecodeMechanism eMechanism,rtl_TextEncoding eCharset)3745 rtl::OUString INetURLObject::decode(sal_Unicode const * pBegin,
3746 								sal_Unicode const * pEnd,
3747 								sal_Char cEscapePrefix,
3748 								DecodeMechanism eMechanism,
3749 								rtl_TextEncoding eCharset)
3750 {
3751 	switch (eMechanism)
3752 	{
3753 		case NO_DECODE:
3754 			return rtl::OUString(pBegin, pEnd - pBegin);
3755 
3756 		case DECODE_TO_IURI:
3757 			eCharset = RTL_TEXTENCODING_UTF8;
3758 			break;
3759 
3760         default:
3761             break;
3762 	}
3763 	rtl::OUStringBuffer aResult;
3764 	while (pBegin < pEnd)
3765 	{
3766 		EscapeType eEscapeType;
3767 		sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, false, cEscapePrefix,
3768 									 WAS_ENCODED, eCharset, eEscapeType);
3769 		switch (eEscapeType)
3770 		{
3771 			case ESCAPE_NO:
3772 				aResult.append(sal_Unicode(nUTF32));
3773 				break;
3774 
3775 			case ESCAPE_OCTET:
3776 				appendEscape(aResult, cEscapePrefix, nUTF32);
3777 				break;
3778 
3779 			case ESCAPE_UTF32:
3780 				if (
3781                      INetMIME::isUSASCII(nUTF32) &&
3782                      (
3783                        eMechanism == DECODE_TO_IURI ||
3784                        (
3785                          eMechanism == DECODE_UNAMBIGUOUS &&
3786                          mustEncode(nUTF32, PART_UNAMBIGUOUS)
3787                        )
3788                      )
3789                    )
3790                 {
3791 					appendEscape(aResult, cEscapePrefix, nUTF32);
3792                 }
3793 				else
3794 					aResult.append(sal_Unicode(nUTF32));
3795 				break;
3796 		}
3797 	}
3798 	return aResult.makeStringAndClear();
3799 }
3800 
3801 //============================================================================
GetURLNoPass(DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const3802 rtl::OUString INetURLObject::GetURLNoPass(DecodeMechanism eMechanism,
3803 									  rtl_TextEncoding eCharset) const
3804 {
3805 	INetURLObject aTemp(*this);
3806 	aTemp.clearPassword();
3807 	return aTemp.GetMainURL(eMechanism, eCharset);
3808 }
3809 
3810 //============================================================================
GetURLNoMark(DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const3811 rtl::OUString INetURLObject::GetURLNoMark(DecodeMechanism eMechanism,
3812 									  rtl_TextEncoding eCharset) const
3813 {
3814 	INetURLObject aTemp(*this);
3815 	aTemp.clearFragment();
3816 	return aTemp.GetMainURL(eMechanism, eCharset);
3817 }
3818 
3819 //============================================================================
3820 rtl::OUString
getAbbreviated(star::uno::Reference<star::util::XStringWidth> const & rStringWidth,sal_Int32 nWidth,DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const3821 INetURLObject::getAbbreviated(
3822     star::uno::Reference< star::util::XStringWidth > const & rStringWidth,
3823     sal_Int32 nWidth,
3824     DecodeMechanism eMechanism,
3825     rtl_TextEncoding eCharset)
3826     const
3827 {
3828     OSL_ENSURE(rStringWidth.is(), "specification violation");
3829     sal_Char cEscapePrefix = getEscapePrefix();
3830     rtl::OUStringBuffer aBuffer;
3831 	// make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme
3832 	// is empty ("") in that case, so take the scheme from m_aAbsURIRef
3833 	if (m_eScheme != INET_PROT_GENERIC)
3834 	{
3835 		aBuffer.appendAscii(getSchemeInfo().m_pScheme);
3836 	}
3837 	else
3838 	{
3839 		if (m_aAbsURIRef)
3840 		{
3841 			sal_Unicode const * pSchemeBegin
3842 				= m_aAbsURIRef.getStr();
3843 			sal_Unicode const * pSchemeEnd = pSchemeBegin;
3844 
3845 			while (pSchemeEnd[0] != ':')
3846 			{
3847 				++pSchemeEnd;
3848 			}
3849 			aBuffer.append(pSchemeBegin, pSchemeEnd - pSchemeBegin);
3850 		}
3851 	}
3852     aBuffer.append(static_cast< sal_Unicode >(':'));
3853     bool bAuthority = getSchemeInfo().m_bAuthority;
3854     sal_Unicode const * pCoreBegin
3855         = m_aAbsURIRef.getStr() + (bAuthority ? getAuthorityBegin() :
3856                                                    m_aPath.getBegin());
3857     sal_Unicode const * pCoreEnd
3858         = m_aAbsURIRef.getStr() + m_aPath.getBegin() + m_aPath.getLength();
3859     bool bSegment = false;
3860     if (getSchemeInfo().m_bHierarchical)
3861     {
3862         rtl::OUString aRest;
3863         if (m_aQuery.isPresent())
3864             aRest = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("?..."));
3865         else if (m_aFragment.isPresent())
3866             aRest = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("#..."));
3867         rtl::OUStringBuffer aTrailer;
3868         sal_Unicode const * pBegin = pCoreBegin;
3869         sal_Unicode const * pEnd = pCoreEnd;
3870         sal_Unicode const * pPrefixBegin = pBegin;
3871         sal_Unicode const * pSuffixEnd = pEnd;
3872         bool bPrefix = true;
3873         bool bSuffix = true;
3874         do
3875         {
3876             if (bSuffix)
3877             {
3878                 sal_Unicode const * p = pSuffixEnd - 1;
3879                 if (pSuffixEnd == pCoreEnd && *p == '/')
3880                     --p;
3881                 while (*p != '/')
3882                     --p;
3883                 if (bAuthority && p == pCoreBegin + 1)
3884                     --p;
3885                 rtl::OUString
3886                     aSegment(decode(p + (p == pBegin && pBegin != pCoreBegin ?
3887                                              1 : 0),
3888                                     pSuffixEnd,
3889                                     cEscapePrefix,
3890                                     eMechanism,
3891                                     eCharset));
3892                 pSuffixEnd = p;
3893                 rtl::OUStringBuffer aResult(aBuffer);
3894                 if (pSuffixEnd != pBegin)
3895                     aResult.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
3896                 aResult.append(aSegment);
3897                 aResult.append(aTrailer);
3898                 aResult.append(aRest);
3899                 if (rStringWidth->
3900                             queryStringWidth(aResult.makeStringAndClear())
3901                         <= nWidth)
3902                 {
3903                     aTrailer.insert(0, aSegment);
3904                     bSegment = true;
3905                     pEnd = pSuffixEnd;
3906                 }
3907                 else
3908                     bSuffix = false;
3909                 if (pPrefixBegin > pSuffixEnd)
3910                     pPrefixBegin = pSuffixEnd;
3911                 if (pBegin == pEnd)
3912                     break;
3913             }
3914             if (bPrefix)
3915             {
3916                 sal_Unicode const * p
3917                     = pPrefixBegin
3918                           + (bAuthority && pPrefixBegin == pCoreBegin ? 2 :
3919                                                                         1);
3920                 OSL_ASSERT(p <= pEnd);
3921                 while (p < pEnd && *p != '/')
3922                     ++p;
3923                 if (p == pCoreEnd - 1 && *p == '/')
3924                     ++p;
3925                 rtl::OUString
3926                     aSegment(decode(pPrefixBegin
3927                                         + (pPrefixBegin == pCoreBegin ? 0 :
3928                                                                         1),
3929                                     p == pEnd ? p : p + 1,
3930                                     cEscapePrefix,
3931                                     eMechanism,
3932                                     eCharset));
3933                 pPrefixBegin = p;
3934                 rtl::OUStringBuffer aResult(aBuffer);
3935                 aResult.append(aSegment);
3936                 if (pPrefixBegin != pEnd)
3937                     aResult.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
3938                 aResult.append(aTrailer);
3939                 aResult.append(aRest);
3940                 if (rStringWidth->
3941                             queryStringWidth(aResult.makeStringAndClear())
3942                         <= nWidth)
3943                 {
3944                     aBuffer.append(aSegment);
3945                     bSegment = true;
3946                     pBegin = pPrefixBegin;
3947                 }
3948                 else
3949                     bPrefix = false;
3950                 if (pPrefixBegin > pSuffixEnd)
3951                     pSuffixEnd = pPrefixBegin;
3952                 if (pBegin == pEnd)
3953                     break;
3954             }
3955         }
3956         while (bPrefix || bSuffix);
3957         if (bSegment)
3958         {
3959             if (pPrefixBegin != pBegin || pSuffixEnd != pEnd)
3960                 aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
3961             aBuffer.append(aTrailer);
3962         }
3963     }
3964     if (!bSegment)
3965         aBuffer.append(decode(pCoreBegin,
3966                               pCoreEnd,
3967                               cEscapePrefix,
3968                               eMechanism,
3969                               eCharset));
3970     if (m_aQuery.isPresent())
3971     {
3972         aBuffer.append(static_cast< sal_Unicode >('?'));
3973         aBuffer.append(decode(m_aQuery, cEscapePrefix, eMechanism, eCharset));
3974     }
3975     if (m_aFragment.isPresent())
3976     {
3977         aBuffer.append(static_cast< sal_Unicode >('#'));
3978         aBuffer.
3979             append(decode(m_aFragment, cEscapePrefix, eMechanism, eCharset));
3980     }
3981     if (aBuffer.getLength() != 0)
3982     {
3983         rtl::OUStringBuffer aResult(aBuffer);
3984         if (rStringWidth->queryStringWidth(aResult.makeStringAndClear())
3985                 > nWidth)
3986             for (sal_Int32 i = aBuffer.getLength();;)
3987             {
3988                 if (i == 0)
3989                 {
3990                     aBuffer.setLength(aBuffer.getLength() - 1);
3991                     if (aBuffer.getLength() == 0)
3992                         break;
3993                 }
3994                 else
3995                 {
3996                     aBuffer.setLength(--i);
3997                     aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
3998                 }
3999                 aResult = aBuffer;
4000                 if (rStringWidth->
4001                             queryStringWidth(aResult.makeStringAndClear())
4002                         <= nWidth)
4003                     break;
4004             }
4005     }
4006     return aBuffer.makeStringAndClear();
4007 }
4008 
4009 //============================================================================
operator ==(INetURLObject const & rObject) const4010 bool INetURLObject::operator ==(INetURLObject const & rObject) const
4011 {
4012 	if (m_eScheme != rObject.m_eScheme)
4013 		return false;
4014 	if (m_eScheme == INET_PROT_NOT_VALID)
4015 		return (m_aAbsURIRef == rObject.m_aAbsURIRef) != false;
4016     if ((m_aScheme.compare(
4017              rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef)
4018          != 0)
4019         || GetUser(NO_DECODE) != rObject.GetUser(NO_DECODE)
4020 		|| GetPass(NO_DECODE) != rObject.GetPass(NO_DECODE)
4021 		|| !GetHost(NO_DECODE).equalsIgnoreAsciiCase(
4022 			rObject.GetHost(NO_DECODE))
4023 		|| GetPort() != rObject.GetPort()
4024 		|| HasParam() != rObject.HasParam()
4025 		|| GetParam(NO_DECODE) != rObject.GetParam(NO_DECODE)
4026 		|| GetMsgId(NO_DECODE) != rObject.GetMsgId(NO_DECODE))
4027 		return false;
4028 	rtl::OUString aPath1(GetURLPath(NO_DECODE));
4029 	rtl::OUString aPath2(rObject.GetURLPath(NO_DECODE));
4030 	switch (m_eScheme)
4031 	{
4032 		case INET_PROT_FILE:
4033 		{
4034 			// If the URL paths of two file URLs only differ in that one has a
4035 			// final '/' and the other has not, take the two paths as
4036 			// equivalent (this could be useful for other schemes, too):
4037 			sal_Int32 nLength = aPath1.getLength();
4038 			switch (nLength - aPath2.getLength())
4039 			{
4040 				case -1:
4041 					if (aPath2.getStr()[nLength] != '/')
4042 						return false;
4043 					break;
4044 
4045 				case 0:
4046 					break;
4047 
4048 				case 1:
4049 					if (aPath1.getStr()[--nLength] != '/')
4050 						return false;
4051 					break;
4052 
4053 				default:
4054 					return false;
4055 			}
4056 			return aPath1.compareTo(aPath2, nLength) == 0;
4057 		}
4058 
4059 		default:
4060 			return (aPath1 == aPath2) != false;
4061 	}
4062 }
4063 
4064 //============================================================================
operator <(INetURLObject const & rObject) const4065 bool INetURLObject::operator <(INetURLObject const & rObject) const
4066 {
4067     sal_Int32 nCompare = m_aScheme.compare(
4068         rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef);
4069     if (nCompare < 0) {
4070         return true;
4071     } else if (nCompare > 0) {
4072         return false;
4073     }
4074 	sal_uInt32 nPort1 = GetPort();
4075 	sal_uInt32 nPort2 = rObject.GetPort();
4076 	if (nPort1 < nPort2)
4077 		return true;
4078 	else if (nPort1 > nPort2)
4079 		return false;
4080 	nCompare = GetUser(NO_DECODE).compareTo(rObject.GetUser(NO_DECODE));
4081 	if (nCompare < 0)
4082 		return true;
4083 	else if (nCompare > 0)
4084 		return false;
4085 	nCompare = GetPass(NO_DECODE).compareTo(rObject.GetPass(NO_DECODE));
4086 	if (nCompare < 0)
4087 		return true;
4088 	else if (nCompare > 0)
4089 		return false;
4090 	nCompare = GetHost(NO_DECODE).compareTo(rObject.GetHost(NO_DECODE));
4091 	if (nCompare < 0)
4092 		return true;
4093 	else if (nCompare > 0)
4094 		return false;
4095 	const rtl::OUString &rPath1(GetURLPath(NO_DECODE));
4096 	const rtl::OUString &rPath2(rObject.GetURLPath(NO_DECODE));
4097 	nCompare = rPath1.compareTo(rPath2);
4098 	if (nCompare < 0)
4099 		return true;
4100 	else if (nCompare > 0)
4101 		return false;
4102 	nCompare = GetParam(NO_DECODE).compareTo(rObject.GetParam(NO_DECODE));
4103 	if (nCompare < 0)
4104 		return true;
4105 	else if (nCompare > 0)
4106 		return false;
4107 	return GetMsgId(NO_DECODE).compareTo(rObject.GetMsgId(NO_DECODE)) < 0;
4108 }
4109 
4110 //============================================================================
ConcatData(INetProtocol eTheScheme,rtl::OUString const & rTheUser,rtl::OUString const & rThePassword,rtl::OUString const & rTheHost,sal_uInt32 nThePort,rtl::OUString const & rThePath,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)4111 bool INetURLObject::ConcatData(INetProtocol eTheScheme,
4112 							   rtl::OUString const & rTheUser,
4113 							   rtl::OUString const & rThePassword,
4114 							   rtl::OUString const & rTheHost,
4115 							   sal_uInt32 nThePort,
4116 							   rtl::OUString const & rThePath,
4117 							   EncodeMechanism eMechanism,
4118 							   rtl_TextEncoding eCharset)
4119 {
4120 	setInvalid();
4121 	m_eScheme = eTheScheme;
4122 	if (HasError() || m_eScheme == INET_PROT_GENERIC)
4123 		return false;
4124 	m_aAbsURIRef.setLength(0);
4125 	m_aAbsURIRef.appendAscii(getSchemeInfo().m_pScheme);
4126 	m_aAbsURIRef.append(sal_Unicode(':'));
4127 	if (getSchemeInfo().m_bAuthority)
4128 	{
4129 		m_aAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
4130 		bool bUserInfo = false;
4131 		if (getSchemeInfo().m_bUser)
4132 		{
4133 			if (m_eScheme == INET_PROT_IMAP && rTheUser.getLength() == 0)
4134 			{
4135 				setInvalid();
4136 				return false;
4137 			}
4138 			if (rTheUser.getLength() != 0)
4139 			{
4140 				m_aUser.set(m_aAbsURIRef,
4141 							encodeText(rTheUser, false,
4142 									   m_eScheme == INET_PROT_IMAP ?
4143 										   PART_IMAP_ACHAR :
4144 									   m_eScheme == INET_PROT_VIM ?
4145 										   PART_VIM :
4146 										   PART_USER_PASSWORD,
4147 									   getEscapePrefix(), eMechanism,
4148 									   eCharset, false),
4149 							m_aAbsURIRef.getLength());
4150 				bUserInfo = true;
4151 			}
4152 		}
4153 		else if (rTheUser.getLength() != 0)
4154 		{
4155 			setInvalid();
4156 			return false;
4157 		}
4158 		if (rThePassword.getLength() != 0)
4159         {
4160 			if (getSchemeInfo().m_bPassword)
4161 			{
4162 				m_aAbsURIRef.append(sal_Unicode(':'));
4163 				m_aAuth.set(m_aAbsURIRef,
4164 							encodeText(rThePassword, false,
4165 									   m_eScheme == INET_PROT_VIM ?
4166 										   PART_VIM : PART_USER_PASSWORD,
4167 									   getEscapePrefix(), eMechanism,
4168 									   eCharset, false),
4169 							m_aAbsURIRef.getLength());
4170 				bUserInfo = true;
4171 			}
4172 			else
4173 			{
4174 				setInvalid();
4175 				return false;
4176 			}
4177         }
4178 		if (bUserInfo && getSchemeInfo().m_bHost)
4179 			m_aAbsURIRef.append(sal_Unicode('@'));
4180 		if (getSchemeInfo().m_bHost)
4181 		{
4182 			rtl::OUStringBuffer aSynHost(rTheHost);
4183             bool bNetBiosName = false;
4184 			switch (m_eScheme)
4185 			{
4186 				case INET_PROT_FILE:
4187 					{
4188 				        rtl::OUString sTemp(aSynHost);
4189 				        if (sTemp.equalsIgnoreAsciiCaseAsciiL(
4190 					        RTL_CONSTASCII_STRINGPARAM("localhost")))
4191 						{
4192 						    aSynHost.setLength(0);
4193 						}
4194                         bNetBiosName = true;
4195 					}
4196 					break;
4197 
4198 				case INET_PROT_LDAP:
4199 					if (aSynHost.getLength() == 0 && nThePort != 0)
4200 					{
4201 						setInvalid();
4202 						return false;
4203 					}
4204 					break;
4205 
4206 				default:
4207 					if (aSynHost.getLength() == 0)
4208 					{
4209 						setInvalid();
4210 						return false;
4211 					}
4212 					break;
4213 			}
4214             if (!parseHostOrNetBiosName(
4215                     aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(),
4216                     false, eMechanism, eCharset, bNetBiosName, &aSynHost))
4217             {
4218                 setInvalid();
4219                 return false;
4220             }
4221 			m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear(),
4222 				m_aAbsURIRef.getLength());
4223 			if (nThePort != 0)
4224 			{
4225 				if (getSchemeInfo().m_bPort)
4226 				{
4227 					m_aAbsURIRef.append(sal_Unicode(':'));
4228 					m_aPort.set(m_aAbsURIRef,
4229 								rtl::OUString::valueOf(sal_Int64(nThePort)),
4230 								m_aAbsURIRef.getLength());
4231 				}
4232 				else
4233 				{
4234 					setInvalid();
4235 					return false;
4236 				}
4237 			}
4238 		}
4239 		else if (rTheHost.getLength() != 0 || nThePort != 0)
4240 		{
4241 			setInvalid();
4242 			return false;
4243 		}
4244 	}
4245 	rtl::OUStringBuffer aSynPath;
4246 	sal_Unicode const * p = rThePath.getStr();
4247 	sal_Unicode const * pEnd = p + rThePath.getLength();
4248 	if (!parsePath(m_eScheme, &p, pEnd, false, eMechanism, eCharset, false, '/',
4249 				   0x80000000, 0x80000000, 0x80000000, aSynPath)
4250 		|| p != pEnd)
4251     {
4252         setInvalid();
4253 		return false;
4254     }
4255 	m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear(),
4256 		m_aAbsURIRef.getLength());
4257 	return true;
4258 }
4259 
4260 //============================================================================
4261 // static
GetAbsURL(rtl::OUString const & rTheBaseURIRef,rtl::OUString const & rTheRelURIRef,bool bIgnoreFragment,EncodeMechanism eEncodeMechanism,DecodeMechanism eDecodeMechanism,rtl_TextEncoding eCharset,FSysStyle eStyle)4262 rtl::OUString INetURLObject::GetAbsURL(rtl::OUString const & rTheBaseURIRef,
4263                                        rtl::OUString const & rTheRelURIRef,
4264                                        bool bIgnoreFragment,
4265                                        EncodeMechanism eEncodeMechanism,
4266                                        DecodeMechanism eDecodeMechanism,
4267                                        rtl_TextEncoding eCharset,
4268                                        FSysStyle eStyle)
4269 {
4270 	// Backwards compatibility:
4271 	if (rTheRelURIRef.getLength() == 0 || rTheRelURIRef[0] == '#')
4272 		return rTheRelURIRef;
4273 
4274 	INetURLObject aTheAbsURIRef;
4275 	bool bWasAbsolute;
4276 	return INetURLObject(rTheBaseURIRef, eEncodeMechanism, eCharset).
4277             convertRelToAbs(rTheRelURIRef, false, aTheAbsURIRef,
4278                             bWasAbsolute, eEncodeMechanism,
4279                             eCharset, bIgnoreFragment, false,
4280                             false, eStyle)
4281 		   || eEncodeMechanism != WAS_ENCODED
4282 		   || eDecodeMechanism != DECODE_TO_IURI
4283 		   || eCharset != RTL_TEXTENCODING_UTF8 ?
4284 		       aTheAbsURIRef.GetMainURL(eDecodeMechanism, eCharset) :
4285 		       rTheRelURIRef;
4286 }
4287 
4288 //============================================================================
getExternalURL(DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const4289 rtl::OUString INetURLObject::getExternalURL(DecodeMechanism eMechanism,
4290 										rtl_TextEncoding eCharset) const
4291 {
4292 	rtl::OUString aTheExtURIRef;
4293 	translateToExternal(
4294         rtl::OUString(m_aAbsURIRef), aTheExtURIRef, eMechanism, eCharset);
4295 	return aTheExtURIRef;
4296 }
4297 
4298 //============================================================================
4299 // static
GetScheme(INetProtocol eTheScheme)4300 rtl::OUString INetURLObject::GetScheme(INetProtocol eTheScheme)
4301 {
4302 	return rtl::OUString::createFromAscii(getSchemeInfo(eTheScheme).m_pPrefix);
4303 }
4304 
4305 //============================================================================
4306 // static
CompareProtocolScheme(rtl::OUString const & rTheAbsURIRef)4307 INetProtocol INetURLObject::CompareProtocolScheme(rtl::OUString const &
4308 													  rTheAbsURIRef)
4309 {
4310 	sal_Unicode const * p = rTheAbsURIRef.getStr();
4311 	PrefixInfo const * pPrefix = getPrefix(p, p + rTheAbsURIRef.getLength());
4312 	return pPrefix ? pPrefix->m_eScheme : INET_PROT_NOT_VALID;
4313 }
4314 
4315 //============================================================================
hasPassword() const4316 bool INetURLObject::hasPassword() const
4317 {
4318 	return m_aAuth.isPresent() && getSchemeInfo().m_bPassword;
4319 }
4320 
4321 //============================================================================
makeAuthCanonic()4322 void INetURLObject::makeAuthCanonic()
4323 {
4324 	if (m_eScheme == INET_PROT_IMAP && m_aAuth.getLength() == 1
4325 		&& m_aAbsURIRef.charAt(m_aAuth.getBegin()) == '*')
4326 	{
4327 		lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin()
4328 							   - RTL_CONSTASCII_LENGTH(";AUTH="),
4329 						   RTL_CONSTASCII_LENGTH(";AUTH=*"));
4330 		sal_Int32 nDelta = m_aAuth.clear() - RTL_CONSTASCII_LENGTH(";AUTH=");
4331 		m_aPath += nDelta;
4332 		m_aQuery += nDelta;
4333 		m_aFragment += nDelta;
4334 	}
4335 }
4336 
4337 //============================================================================
GetHostPort(DecodeMechanism eMechanism,rtl_TextEncoding eCharset)4338 rtl::OUString INetURLObject::GetHostPort(DecodeMechanism eMechanism,
4339 									 rtl_TextEncoding eCharset)
4340 {
4341 	// Check because PROT_VND_SUN_STAR_HELP, PROT_VND_SUN_STAR_HIER, and
4342     // PROT_VND_SUN_STAR_PKG misuse m_aHost:
4343 	if (!getSchemeInfo().m_bHost)
4344 		return rtl::OUString();
4345 	rtl::OUStringBuffer aHostPort(decode(m_aHost, getEscapePrefix(),
4346 		eMechanism, eCharset));
4347 	if (m_aPort.isPresent())
4348 	{
4349 		aHostPort.append(sal_Unicode(':'));
4350 		aHostPort.append(decode(m_aPort, getEscapePrefix(),
4351 			eMechanism, eCharset));
4352 	}
4353 	return aHostPort.makeStringAndClear();
4354 }
4355 
4356 //============================================================================
GetPort() const4357 sal_uInt32 INetURLObject::GetPort() const
4358 {
4359 	if (m_aPort.isPresent())
4360 	{
4361 		sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin();
4362 		sal_Unicode const * pEnd = p + m_aPort.getLength();
4363 		sal_uInt32 nThePort;
4364 		if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd)
4365 			return nThePort;
4366 	}
4367 	return 0;
4368 }
4369 
4370 //============================================================================
SetPort(sal_uInt32 nThePort)4371 bool INetURLObject::SetPort(sal_uInt32 nThePort)
4372 {
4373 	if (getSchemeInfo().m_bPort && m_aHost.isPresent())
4374 	{
4375 		rtl::OUString aNewPort(rtl::OUString::valueOf(sal_Int64(nThePort)));
4376 		sal_Int32 nDelta;
4377 		if (m_aPort.isPresent())
4378 			nDelta = m_aPort.set(m_aAbsURIRef, aNewPort);
4379 		else
4380 		{
4381 			m_aAbsURIRef.insert(m_aHost.getEnd(), sal_Unicode(':'));
4382 			nDelta = m_aPort.set(m_aAbsURIRef, aNewPort, m_aHost.getEnd() + 1)
4383 						 + 1;
4384 		}
4385 		m_aPath += nDelta;
4386 		m_aQuery += nDelta;
4387 		m_aFragment += nDelta;
4388 		return true;
4389 	}
4390 	return false;
4391 }
4392 
4393 //============================================================================
makePortCanonic()4394 void INetURLObject::makePortCanonic()
4395 {
4396 	if (m_aPort.isPresent())
4397 	{
4398 		sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin();
4399 		sal_Unicode const * pEnd = p + m_aPort.getLength();
4400 		sal_uInt32 nThePort;
4401 		if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd)
4402 		{
4403 			sal_Int32 nDelta;
4404 			if (nThePort != 0 && nThePort == getSchemeInfo().m_nDefaultPort)
4405 			{
4406 				lcl_Erase(m_aAbsURIRef, m_aPort.getBegin() - 1,
4407 								   m_aPort.getLength() + 1);
4408 				nDelta = m_aPort.clear() - 1;
4409 			}
4410 			else
4411 				nDelta = m_aPort.set(m_aAbsURIRef,
4412 								 rtl::OUString::valueOf(sal_Int64(nThePort)));
4413 			m_aPath += nDelta;
4414 			m_aQuery += nDelta;
4415 			m_aFragment += nDelta;
4416 		}
4417 	}
4418 }
4419 
4420 //============================================================================
getSegmentCount(bool bIgnoreFinalSlash) const4421 sal_Int32 INetURLObject::getSegmentCount(bool bIgnoreFinalSlash) const
4422 {
4423     if (!checkHierarchical())
4424 		return 0;
4425 
4426 	sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
4427 	sal_Unicode const * pEnd = p + m_aPath.getLength();
4428 	if (bIgnoreFinalSlash && pEnd > p && pEnd[-1] == '/')
4429 		--pEnd;
4430 	sal_Int32 n = p == pEnd || *p == '/' ? 0 : 1;
4431 	while (p != pEnd)
4432 		if (*p++ == '/')
4433 			++n;
4434 	return n;
4435 }
4436 
4437 //============================================================================
removeSegment(sal_Int32 nIndex,bool bIgnoreFinalSlash)4438 bool INetURLObject::removeSegment(sal_Int32 nIndex, bool bIgnoreFinalSlash)
4439 {
4440 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4441 	if (!aSegment.isPresent())
4442 		return false;
4443 
4444 	rtl::OUStringBuffer aNewPath;
4445 	aNewPath.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(),
4446 					   aSegment.getBegin() - m_aPath.getBegin());
4447 	if (bIgnoreFinalSlash && aSegment.getEnd() == m_aPath.getEnd())
4448 		aNewPath.append(sal_Unicode('/'));
4449 	else
4450 		aNewPath.append(m_aAbsURIRef.getStr() + aSegment.getEnd(),
4451 						m_aPath.getEnd() - aSegment.getEnd());
4452 	if (aNewPath.getLength() == 0 && !aSegment.isEmpty() &&
4453         m_aAbsURIRef[aSegment.getBegin()] == '/')
4454     {
4455 		aNewPath.append(sal_Unicode('/'));
4456     }
4457 
4458 	return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
4459 		RTL_TEXTENCODING_UTF8);
4460 }
4461 
4462 //============================================================================
getName(sal_Int32 nIndex,bool bIgnoreFinalSlash,DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const4463 rtl::OUString INetURLObject::getName(sal_Int32 nIndex, bool bIgnoreFinalSlash,
4464 								 DecodeMechanism eMechanism,
4465 								 rtl_TextEncoding eCharset) const
4466 {
4467 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4468 	if (!aSegment.isPresent())
4469 		return rtl::OUString();
4470 
4471 	sal_Unicode const * pSegBegin
4472 		= m_aAbsURIRef.getStr() + aSegment.getBegin();
4473 	sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4474 
4475     if (pSegBegin < pSegEnd && *pSegBegin == '/')
4476         ++pSegBegin;
4477 	sal_Unicode const * p = pSegBegin;
4478 	while (p != pSegEnd && *p != ';')
4479 		++p;
4480 
4481 	return decode(pSegBegin, p, getEscapePrefix(), eMechanism, eCharset);
4482 }
4483 
4484 //============================================================================
setName(rtl::OUString const & rTheName,sal_Int32 nIndex,bool bIgnoreFinalSlash,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)4485 bool INetURLObject::setName(rtl::OUString const & rTheName, sal_Int32 nIndex,
4486 							bool bIgnoreFinalSlash,
4487 							EncodeMechanism eMechanism,
4488 							rtl_TextEncoding eCharset)
4489 {
4490 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4491 	if (!aSegment.isPresent())
4492 		return false;
4493 
4494 	sal_Unicode const * pPathBegin
4495 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
4496 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4497 	sal_Unicode const * pSegBegin
4498 		= m_aAbsURIRef.getStr() + aSegment.getBegin();
4499 	sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4500 
4501     if (pSegBegin < pSegEnd && *pSegBegin == '/')
4502         ++pSegBegin;
4503 	sal_Unicode const * p = pSegBegin;
4504 	while (p != pSegEnd && *p != ';')
4505 		++p;
4506 
4507 	rtl::OUStringBuffer aNewPath;
4508 	aNewPath.append(pPathBegin, pSegBegin - pPathBegin);
4509 	aNewPath.append(encodeText(rTheName, false, PART_PCHAR, getEscapePrefix(),
4510 		eMechanism, eCharset, true));
4511 	aNewPath.append(p, pPathEnd - p);
4512 
4513 	return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
4514 		RTL_TEXTENCODING_UTF8);
4515 }
4516 
4517 //============================================================================
hasExtension(sal_Int32 nIndex,bool bIgnoreFinalSlash) const4518 bool INetURLObject::hasExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash)
4519 	const
4520 {
4521 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4522 	if (!aSegment.isPresent())
4523 		return false;
4524 
4525 	sal_Unicode const * pSegBegin
4526 		= m_aAbsURIRef.getStr() + aSegment.getBegin();
4527 	sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4528 
4529     if (pSegBegin < pSegEnd && *pSegBegin == '/')
4530         ++pSegBegin;
4531 	for (sal_Unicode const * p = pSegBegin; p != pSegEnd && *p != ';'; ++p)
4532 		if (*p == '.' && p != pSegBegin)
4533 			return true;
4534 	return false;
4535 }
4536 
4537 //============================================================================
getBase(sal_Int32 nIndex,bool bIgnoreFinalSlash,DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const4538 rtl::OUString INetURLObject::getBase(sal_Int32 nIndex, bool bIgnoreFinalSlash,
4539 								 DecodeMechanism eMechanism,
4540 								 rtl_TextEncoding eCharset) const
4541 {
4542 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4543 	if (!aSegment.isPresent())
4544 		return rtl::OUString();
4545 
4546 	sal_Unicode const * pSegBegin
4547 		= m_aAbsURIRef.getStr() + aSegment.getBegin();
4548 	sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4549 
4550     if (pSegBegin < pSegEnd && *pSegBegin == '/')
4551         ++pSegBegin;
4552 	sal_Unicode const * pExtension = 0;
4553 	sal_Unicode const * p = pSegBegin;
4554 	for (; p != pSegEnd && *p != ';'; ++p)
4555 		if (*p == '.' && p != pSegBegin)
4556 			pExtension = p;
4557 	if (!pExtension)
4558 		pExtension = p;
4559 
4560 	return decode(pSegBegin, pExtension, getEscapePrefix(), eMechanism,
4561 				  eCharset);
4562 }
4563 
4564 //============================================================================
setBase(rtl::OUString const & rTheBase,sal_Int32 nIndex,bool bIgnoreFinalSlash,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)4565 bool INetURLObject::setBase(rtl::OUString const & rTheBase, sal_Int32 nIndex,
4566 							bool bIgnoreFinalSlash,
4567 							EncodeMechanism eMechanism,
4568 							rtl_TextEncoding eCharset)
4569 {
4570 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4571 	if (!aSegment.isPresent())
4572 		return false;
4573 
4574 	sal_Unicode const * pPathBegin
4575 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
4576 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4577 	sal_Unicode const * pSegBegin
4578 		= m_aAbsURIRef.getStr() + aSegment.getBegin();
4579 	sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4580 
4581     if (pSegBegin < pSegEnd && *pSegBegin == '/')
4582         ++pSegBegin;
4583 	sal_Unicode const * pExtension = 0;
4584 	sal_Unicode const * p = pSegBegin;
4585 	for (; p != pSegEnd && *p != ';'; ++p)
4586 		if (*p == '.' && p != pSegBegin)
4587 			pExtension = p;
4588 	if (!pExtension)
4589 		pExtension = p;
4590 
4591 	rtl::OUStringBuffer aNewPath;
4592 	aNewPath.append(pPathBegin, pSegBegin - pPathBegin);
4593 	aNewPath.append(encodeText(rTheBase, false, PART_PCHAR, getEscapePrefix(),
4594 		eMechanism, eCharset, true));
4595 	aNewPath.append(pExtension, pPathEnd - pExtension);
4596 
4597 	return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
4598 		RTL_TEXTENCODING_UTF8);
4599 }
4600 
4601 //============================================================================
getExtension(sal_Int32 nIndex,bool bIgnoreFinalSlash,DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const4602 rtl::OUString INetURLObject::getExtension(sal_Int32 nIndex,
4603 									  bool bIgnoreFinalSlash,
4604 									  DecodeMechanism eMechanism,
4605 									  rtl_TextEncoding eCharset) const
4606 {
4607 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4608 	if (!aSegment.isPresent())
4609 		return rtl::OUString();
4610 
4611 	sal_Unicode const * pSegBegin
4612 		= m_aAbsURIRef.getStr() + aSegment.getBegin();
4613 	sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4614 
4615     if (pSegBegin < pSegEnd && *pSegBegin == '/')
4616         ++pSegBegin;
4617 	sal_Unicode const * pExtension = 0;
4618 	sal_Unicode const * p = pSegBegin;
4619 	for (; p != pSegEnd && *p != ';'; ++p)
4620 		if (*p == '.' && p != pSegBegin)
4621 			pExtension = p;
4622 
4623 	if (!pExtension)
4624 		return rtl::OUString();
4625 
4626 	return decode(pExtension + 1, p, getEscapePrefix(), eMechanism, eCharset);
4627 }
4628 
4629 //============================================================================
setExtension(rtl::OUString const & rTheExtension,sal_Int32 nIndex,bool bIgnoreFinalSlash,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)4630 bool INetURLObject::setExtension(rtl::OUString const & rTheExtension,
4631 								 sal_Int32 nIndex, bool bIgnoreFinalSlash,
4632 								 EncodeMechanism eMechanism,
4633 								 rtl_TextEncoding eCharset)
4634 {
4635 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4636 	if (!aSegment.isPresent())
4637 		return false;
4638 
4639 	sal_Unicode const * pPathBegin
4640 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
4641 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4642 	sal_Unicode const * pSegBegin
4643 		= m_aAbsURIRef.getStr() + aSegment.getBegin();
4644 	sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4645 
4646     if (pSegBegin < pSegEnd && *pSegBegin == '/')
4647         ++pSegBegin;
4648 	sal_Unicode const * pExtension = 0;
4649 	sal_Unicode const * p = pSegBegin;
4650 	for (; p != pSegEnd && *p != ';'; ++p)
4651 		if (*p == '.' && p != pSegBegin)
4652 			pExtension = p;
4653 	if (!pExtension)
4654 		pExtension = p;
4655 
4656 	rtl::OUStringBuffer aNewPath;
4657 	aNewPath.append(pPathBegin, pExtension - pPathBegin);
4658 	aNewPath.append(sal_Unicode('.'));
4659 	aNewPath.append(encodeText(rTheExtension, false, PART_PCHAR,
4660 		getEscapePrefix(), eMechanism, eCharset, true));
4661 	aNewPath.append(p, pPathEnd - p);
4662 
4663 	return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
4664 		RTL_TEXTENCODING_UTF8);
4665 }
4666 
4667 //============================================================================
removeExtension(sal_Int32 nIndex,bool bIgnoreFinalSlash)4668 bool INetURLObject::removeExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash)
4669 {
4670 	SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash));
4671 	if (!aSegment.isPresent())
4672 		return false;
4673 
4674 	sal_Unicode const * pPathBegin
4675 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
4676 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4677 	sal_Unicode const * pSegBegin
4678 		= m_aAbsURIRef.getStr() + aSegment.getBegin();
4679 	sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength();
4680 
4681     if (pSegBegin < pSegEnd && *pSegBegin == '/')
4682         ++pSegBegin;
4683 	sal_Unicode const * pExtension = 0;
4684 	sal_Unicode const * p = pSegBegin;
4685 	for (; p != pSegEnd && *p != ';'; ++p)
4686 		if (*p == '.' && p != pSegBegin)
4687 			pExtension = p;
4688 	if (!pExtension)
4689 		return true;
4690 
4691 	rtl::OUStringBuffer aNewPath;
4692 	aNewPath.append(pPathBegin, pExtension - pPathBegin);
4693 	aNewPath.append(p, pPathEnd - p);
4694 
4695 	return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
4696 		RTL_TEXTENCODING_UTF8);
4697 }
4698 
4699 //============================================================================
hasFinalSlash() const4700 bool INetURLObject::hasFinalSlash() const
4701 {
4702 	if (!checkHierarchical())
4703 		return false;
4704 
4705 	sal_Unicode const * pPathBegin
4706 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
4707 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4708     return pPathEnd > pPathBegin && pPathEnd[-1] == '/';
4709 }
4710 
4711 //============================================================================
setFinalSlash()4712 bool INetURLObject::setFinalSlash()
4713 {
4714 	if (!checkHierarchical())
4715 		return false;
4716 
4717 	sal_Unicode const * pPathBegin
4718 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
4719 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4720 	if (pPathEnd > pPathBegin && pPathEnd[-1] == '/')
4721 		return true;
4722 
4723 	rtl::OUStringBuffer aNewPath;
4724 	aNewPath.append(pPathBegin, pPathEnd - pPathBegin);
4725 	aNewPath.append(sal_Unicode('/'));
4726 
4727 	return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC,
4728 		RTL_TEXTENCODING_UTF8);
4729 }
4730 
4731 //============================================================================
removeFinalSlash()4732 bool INetURLObject::removeFinalSlash()
4733 {
4734 	if (!checkHierarchical())
4735 		return false;
4736 
4737 	sal_Unicode const * pPathBegin
4738 		= m_aAbsURIRef.getStr() + m_aPath.getBegin();
4739 	sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength();
4740 	if (pPathEnd <= pPathBegin || pPathEnd[-1] != '/')
4741 		return true;
4742 
4743 	--pPathEnd;
4744 	if (pPathEnd == pPathBegin && *pPathBegin == '/')
4745 		return false;
4746 	rtl::OUString aNewPath(pPathBegin, pPathEnd - pPathBegin);
4747 
4748 	return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8);
4749 }
4750 
4751 //============================================================================
4752 // static
createFragment(rtl::OUString const & rText)4753 rtl::OUString INetURLObject::createFragment(rtl::OUString const & rText)
4754 {
4755 	rtl::OUString aFragment(rText);
4756 	for (sal_Int32 i = 0; i < aFragment.getLength();)
4757 	{
4758 		sal_Unicode c = aFragment.getStr()[i];
4759 		if (mustEncode(c, PART_CREATEFRAGMENT))
4760 			aFragment = aFragment.replaceAt(i, 1, rtl::OUString());
4761 		else
4762 			++i;
4763 	}
4764 	return aFragment;
4765 }
4766 
4767 //============================================================================
setFSysPath(rtl::OUString const & rFSysPath,FSysStyle eStyle)4768 bool INetURLObject::setFSysPath(rtl::OUString const & rFSysPath,
4769 	FSysStyle eStyle)
4770 {
4771 	sal_Unicode const * pFSysBegin = rFSysPath.getStr();
4772 	sal_Unicode const * pFSysEnd = pFSysBegin + rFSysPath.getLength();
4773 
4774 	switch ((eStyle & FSYS_VOS ? 1 : 0)
4775 			    + (eStyle & FSYS_UNX ? 1 : 0)
4776 			    + (eStyle & FSYS_DOS ? 1 : 0)
4777 			    + (eStyle & FSYS_MAC ? 1 : 0))
4778 	{
4779 		case 0:
4780 			return false;
4781 
4782 		case 1:
4783 			break;
4784 
4785 		default:
4786 			if (eStyle & FSYS_VOS
4787 				&& pFSysEnd - pFSysBegin >= 2
4788 				&& pFSysBegin[0] == '/'
4789 				&& pFSysBegin[1] == '/')
4790 			{
4791 				if (pFSysEnd - pFSysBegin >= 3
4792 					&& pFSysBegin[2] == '.'
4793 					&& (pFSysEnd - pFSysBegin == 3 || pFSysBegin[3] == '/'))
4794 				{
4795 					eStyle = FSYS_VOS; // Production T1
4796 					break;
4797 				}
4798 
4799 				sal_Unicode const * p = pFSysBegin + 2;
4800 				rtl::OUString aHost;
4801 				if (parseHost(p, pFSysEnd, aHost)
4802 					&& (p == pFSysEnd || *p == '/'))
4803 				{
4804 					eStyle = FSYS_VOS; // Production T2
4805 					break;
4806 				}
4807 			}
4808 
4809 			if (eStyle & FSYS_DOS
4810 				&& pFSysEnd - pFSysBegin >= 2
4811 				&& pFSysBegin[0] == '\\'
4812 				&& pFSysBegin[1] == '\\')
4813 			{
4814 				sal_Unicode const * p = pFSysBegin + 2;
4815 				rtl::OUString aHost;
4816 				if (parseHost(p, pFSysEnd, aHost)
4817 					&& (p == pFSysEnd || *p == '\\'))
4818 				{
4819 					eStyle = FSYS_DOS; // Production T3
4820 					break;
4821 				}
4822 			}
4823 
4824 			if (eStyle & FSYS_DOS
4825 				&& pFSysEnd - pFSysBegin >= 2
4826 				&& INetMIME::isAlpha(pFSysBegin[0])
4827 				&& pFSysBegin[1] == ':'
4828 				&& (pFSysEnd - pFSysBegin == 2
4829                     || pFSysBegin[2] == '/'
4830                     || pFSysBegin[2] == '\\'))
4831 			{
4832 				eStyle = FSYS_DOS; // Productions T4, T5
4833 				break;
4834 			}
4835 
4836 			if (!(eStyle & (FSYS_UNX | FSYS_DOS | FSYS_MAC)))
4837 				return false;
4838 
4839 			eStyle = guessFSysStyleByCounting(pFSysBegin, pFSysEnd, eStyle);
4840 			    // Production T6
4841 			break;
4842 	}
4843 
4844 	rtl::OUStringBuffer aSynAbsURIRef(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("file://")));
4845 
4846 	switch (eStyle)
4847 	{
4848 		case FSYS_VOS:
4849 		{
4850 			sal_Unicode const * p = pFSysBegin;
4851 			if (pFSysEnd - p < 2 || *p++ != '/' || *p++ != '/')
4852 				return false;
4853 			if (p != pFSysEnd && *p == '.'
4854 				&& (pFSysEnd - p == 1 || p[1] == '/'))
4855 				++p;
4856 			for (; p != pFSysEnd; ++p)
4857 				switch (*p)
4858 				{
4859 					case '#':
4860 					case '%':
4861 						appendEscape(aSynAbsURIRef, '%', *p);
4862 						break;
4863 
4864 					default:
4865 						aSynAbsURIRef.append(*p);
4866 						break;
4867 				}
4868 			break;
4869 		}
4870 
4871 		case FSYS_UNX:
4872 		{
4873 			sal_Unicode const * p = pFSysBegin;
4874 			if (p != pFSysEnd && *p != '/')
4875 				return false;
4876 			for (; p != pFSysEnd; ++p)
4877 				switch (*p)
4878 				{
4879 					case '|':
4880 					case '#':
4881 					case '%':
4882 						appendEscape(aSynAbsURIRef, '%', *p);
4883 						break;
4884 
4885 					default:
4886 						aSynAbsURIRef.append(*p);
4887 						break;
4888 				}
4889 			break;
4890 		}
4891 
4892 		case FSYS_DOS:
4893 		{
4894 			sal_uInt32 nAltDelimiter = 0x80000000;
4895 			sal_Unicode const * p = pFSysBegin;
4896 			if (pFSysEnd - p >= 3 && p[0] == '\\' && p[1] == '\\')
4897 				p += 2;
4898 			else
4899 			{
4900 				aSynAbsURIRef.append(sal_Unicode('/'));
4901 				if (pFSysEnd - p >= 2
4902                     && INetMIME::isAlpha(p[0])
4903 					&& p[1] == ':'
4904                     && (pFSysEnd - p == 2 || p[2] == '\\' || p[2] == '/'))
4905 					nAltDelimiter = '/';
4906 			}
4907 			for (; p != pFSysEnd; ++p)
4908 				if (*p == '\\' || *p == nAltDelimiter)
4909 					aSynAbsURIRef.append(sal_Unicode('/'));
4910 				else
4911 					switch (*p)
4912 					{
4913 						case '/':
4914 						case '#':
4915 						case '%':
4916 							appendEscape(aSynAbsURIRef, '%', *p);
4917 							break;
4918 
4919 						default:
4920 							aSynAbsURIRef.append(*p);
4921 							break;
4922 					}
4923 			break;
4924 		}
4925 
4926 		case FSYS_MAC:
4927 			aSynAbsURIRef.append(sal_Unicode('/'));
4928 			{for (sal_Unicode const * p = pFSysBegin; p != pFSysEnd; ++p)
4929 				switch (*p)
4930 				{
4931 					case ':':
4932 						aSynAbsURIRef.append(sal_Unicode('/'));
4933 						break;
4934 
4935 					case '/':
4936 					case '|':
4937 					case '#':
4938 					case '%':
4939 						appendEscape(aSynAbsURIRef, '%', *p);
4940 						break;
4941 
4942 					default:
4943 						aSynAbsURIRef.append(*p);
4944 						break;
4945 				}
4946 			}
4947 			break;
4948 
4949         default:
4950             OSL_ASSERT(false);
4951             break;
4952 	}
4953 
4954 	INetURLObject aTemp(aSynAbsURIRef.makeStringAndClear(), WAS_ENCODED,
4955 		RTL_TEXTENCODING_UTF8);
4956 	if (aTemp.HasError())
4957 		return false;
4958 
4959 	*this = aTemp;
4960 	return true;
4961 }
4962 
4963 //============================================================================
getFSysPath(FSysStyle eStyle,sal_Unicode * pDelimiter) const4964 rtl::OUString INetURLObject::getFSysPath(FSysStyle eStyle,
4965 									 sal_Unicode * pDelimiter) const
4966 {
4967 	if (m_eScheme != INET_PROT_FILE)
4968 		return rtl::OUString();
4969 
4970 	if ((eStyle & FSYS_VOS ? 1 : 0)
4971 		        + (eStyle & FSYS_UNX ? 1 : 0)
4972 			    + (eStyle & FSYS_DOS ? 1 : 0)
4973 		        + (eStyle & FSYS_MAC ? 1 : 0)
4974 		    > 1)
4975 	{
4976 		eStyle = eStyle & FSYS_VOS
4977 			     && m_aHost.isPresent()
4978 			     && m_aHost.getLength() > 0 ?
4979 			         FSYS_VOS :
4980 				 hasDosVolume(eStyle)
4981                  || ((eStyle & FSYS_DOS) != 0
4982                     && m_aHost.isPresent()
4983                     && m_aHost.getLength() > 0) ?
4984 				     FSYS_DOS :
4985 			     eStyle & FSYS_UNX
4986 			     && (!m_aHost.isPresent() || m_aHost.getLength() == 0) ?
4987 			         FSYS_UNX :
4988 			         FSysStyle(0);
4989 	}
4990 
4991 	switch (eStyle)
4992 	{
4993 		case FSYS_VOS:
4994 		{
4995 			if (pDelimiter)
4996 				*pDelimiter = '/';
4997 
4998 			rtl::OUStringBuffer aSynFSysPath;
4999 			aSynFSysPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
5000 			if (m_aHost.isPresent() && m_aHost.getLength() > 0)
5001 				aSynFSysPath.append(decode(m_aHost, '%', DECODE_WITH_CHARSET,
5002 									   RTL_TEXTENCODING_UTF8));
5003 			else
5004 				aSynFSysPath.append(sal_Unicode('.'));
5005 			aSynFSysPath.append(decode(m_aPath, '%', DECODE_WITH_CHARSET,
5006 								   RTL_TEXTENCODING_UTF8));
5007 			return aSynFSysPath.makeStringAndClear();
5008 		}
5009 
5010 		case FSYS_UNX:
5011 		{
5012 			if (m_aHost.isPresent() && m_aHost.getLength() > 0)
5013 				return rtl::OUString();
5014 
5015 			if (pDelimiter)
5016 				*pDelimiter = '/';
5017 
5018 			return decode(m_aPath, '%', DECODE_WITH_CHARSET,
5019 						  RTL_TEXTENCODING_UTF8);
5020 		}
5021 
5022 		case FSYS_DOS:
5023 		{
5024 			if (pDelimiter)
5025 				*pDelimiter = '\\';
5026 
5027 			rtl::OUStringBuffer aSynFSysPath;
5028 			if (m_aHost.isPresent() && m_aHost.getLength() > 0)
5029 			{
5030 				aSynFSysPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("\\\\"));
5031 				aSynFSysPath.append(decode(m_aHost, '%', DECODE_WITH_CHARSET,
5032 									   RTL_TEXTENCODING_UTF8));
5033 				aSynFSysPath.append(sal_Unicode('\\'));
5034 			}
5035 			sal_Unicode const * p
5036 				= m_aAbsURIRef.getStr() + m_aPath.getBegin();
5037 			sal_Unicode const * pEnd = p + m_aPath.getLength();
5038 			DBG_ASSERT(p < pEnd && *p == '/',
5039 					   "INetURLObject::getFSysPath(): Bad path");
5040 			++p;
5041 			while (p < pEnd)
5042 			{
5043 				EscapeType eEscapeType;
5044 				sal_uInt32 nUTF32 = getUTF32(p, pEnd, false, '%', WAS_ENCODED,
5045 											 RTL_TEXTENCODING_UTF8,
5046 											 eEscapeType);
5047 				if (eEscapeType == ESCAPE_NO && nUTF32 == '/')
5048 					aSynFSysPath.append(sal_Unicode('\\'));
5049 				else
5050 					aSynFSysPath.appendUtf32(nUTF32);
5051 			}
5052 			return aSynFSysPath.makeStringAndClear();
5053 		}
5054 
5055 		case FSYS_MAC:
5056 		{
5057 			if (m_aHost.isPresent() && m_aHost.getLength() > 0)
5058 				return rtl::OUString();
5059 
5060 			if (pDelimiter)
5061 				*pDelimiter = ':';
5062 
5063 			rtl::OUStringBuffer aSynFSysPath;
5064 			sal_Unicode const * p
5065 				= m_aAbsURIRef.getStr() + m_aPath.getBegin();
5066 			sal_Unicode const * pEnd = p + m_aPath.getLength();
5067 			DBG_ASSERT(p < pEnd && *p == '/',
5068 					   "INetURLObject::getFSysPath(): Bad path");
5069 			++p;
5070 			while (p < pEnd)
5071 			{
5072 				EscapeType eEscapeType;
5073 				sal_uInt32 nUTF32 = getUTF32(p, pEnd, false, '%', WAS_ENCODED,
5074 											 RTL_TEXTENCODING_UTF8,
5075 											 eEscapeType);
5076 				if (eEscapeType == ESCAPE_NO && nUTF32 == '/')
5077 					aSynFSysPath.append(sal_Unicode(':'));
5078 				else
5079 					aSynFSysPath.appendUtf32(nUTF32);
5080 			}
5081 			return aSynFSysPath.makeStringAndClear();
5082 		}
5083 
5084         default:
5085             return rtl::OUString();
5086 	}
5087 }
5088 
5089 //============================================================================
HasMsgId() const5090 bool INetURLObject::HasMsgId() const
5091 {
5092 	if (m_eScheme != INET_PROT_POP3)
5093 		return false;
5094 	sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
5095 	sal_Unicode const * pEnd = p + m_aPath.getLength();
5096 	for (; p < pEnd; ++p)
5097 		if (*p == '<')
5098 			return true;
5099 	return false;
5100 }
5101 
5102 //============================================================================
GetMsgId(DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const5103 rtl::OUString INetURLObject::GetMsgId(DecodeMechanism eMechanism,
5104 								  rtl_TextEncoding eCharset) const
5105 {
5106 	if (m_eScheme != INET_PROT_POP3)
5107 		return rtl::OUString();
5108 	sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin();
5109 	sal_Unicode const * pEnd = p + m_aPath.getLength();
5110 	for (; p < pEnd; ++p)
5111 		if (*p == '<')
5112 			return decode(p, pEnd, getEscapePrefix(), eMechanism, eCharset);
5113 	return rtl::OUString();
5114 }
5115 
5116 //============================================================================
5117 // static
appendUCS4Escape(rtl::OUStringBuffer & rTheText,sal_Char cEscapePrefix,sal_uInt32 nUCS4)5118 void INetURLObject::appendUCS4Escape(rtl::OUStringBuffer & rTheText,
5119 									 sal_Char cEscapePrefix, sal_uInt32 nUCS4)
5120 {
5121 	DBG_ASSERT(nUCS4 < 0x80000000,
5122 			   "INetURLObject::appendUCS4Escape(): Bad char");
5123 	if (nUCS4 < 0x80)
5124 		appendEscape(rTheText, cEscapePrefix, nUCS4);
5125 	else if (nUCS4 < 0x800)
5126 	{
5127 		appendEscape(rTheText, cEscapePrefix, nUCS4 >> 6 | 0xC0);
5128 		appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
5129 	}
5130 	else if (nUCS4 < 0x10000)
5131 	{
5132 		appendEscape(rTheText, cEscapePrefix, nUCS4 >> 12 | 0xE0);
5133 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80);
5134 		appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
5135 	}
5136 	else if (nUCS4 < 0x200000)
5137 	{
5138 		appendEscape(rTheText, cEscapePrefix, nUCS4 >> 18 | 0xF0);
5139 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80);
5140 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80);
5141 		appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
5142 	}
5143 	else if (nUCS4 < 0x4000000)
5144 	{
5145 		appendEscape(rTheText, cEscapePrefix, nUCS4 >> 24 | 0xF8);
5146 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 18 & 0x3F) | 0x80);
5147 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80);
5148 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80);
5149 		appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
5150 	}
5151 	else
5152 	{
5153 		appendEscape(rTheText, cEscapePrefix, nUCS4 >> 30 | 0xFC);
5154 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 24 & 0x3F) | 0x80);
5155 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 18 & 0x3F) | 0x80);
5156 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80);
5157 		appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80);
5158 		appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80);
5159 	}
5160 }
5161 
5162 //============================================================================
5163 // static
appendUCS4(rtl::OUStringBuffer & rTheText,sal_uInt32 nUCS4,EscapeType eEscapeType,bool bOctets,Part ePart,sal_Char cEscapePrefix,rtl_TextEncoding eCharset,bool bKeepVisibleEscapes)5164 void INetURLObject::appendUCS4(rtl::OUStringBuffer& rTheText, sal_uInt32 nUCS4,
5165 							   EscapeType eEscapeType, bool bOctets,
5166 							   Part ePart, sal_Char cEscapePrefix,
5167 							   rtl_TextEncoding eCharset,
5168 							   bool bKeepVisibleEscapes)
5169 {
5170 	bool bEscape;
5171 	rtl_TextEncoding eTargetCharset = RTL_TEXTENCODING_DONTKNOW;
5172 	switch (eEscapeType)
5173 	{
5174 		case ESCAPE_NO:
5175 			if (mustEncode(nUCS4, ePart))
5176 			{
5177 				bEscape = true;
5178 				eTargetCharset = bOctets ? RTL_TEXTENCODING_ISO_8859_1 :
5179 										   RTL_TEXTENCODING_UTF8;
5180 			}
5181 			else
5182 				bEscape = false;
5183 			break;
5184 
5185 		case ESCAPE_OCTET:
5186 			bEscape = true;
5187 			eTargetCharset = RTL_TEXTENCODING_ISO_8859_1;
5188 			break;
5189 
5190 		case ESCAPE_UTF32:
5191 			if (mustEncode(nUCS4, ePart))
5192 			{
5193 				bEscape = true;
5194 				eTargetCharset = eCharset;
5195 			}
5196 			else if (bKeepVisibleEscapes && INetMIME::isVisible(nUCS4))
5197 			{
5198 				bEscape = true;
5199 				eTargetCharset = RTL_TEXTENCODING_ASCII_US;
5200 			}
5201 			else
5202 				bEscape = false;
5203 			break;
5204 		default:
5205 			bEscape = false;
5206 	}
5207 
5208 	if (bEscape)
5209 	{
5210 		switch (eTargetCharset)
5211 		{
5212 			default:
5213 				DBG_ERROR("INetURLObject::appendUCS4(): Unsupported charset");
5214 			case RTL_TEXTENCODING_ASCII_US:
5215 			case RTL_TEXTENCODING_ISO_8859_1:
5216 				appendEscape(rTheText, cEscapePrefix, nUCS4);
5217 				break;
5218 
5219 			case RTL_TEXTENCODING_UTF8:
5220 				appendUCS4Escape(rTheText, cEscapePrefix, nUCS4);
5221 				break;
5222 		}
5223 	}
5224 	else
5225 		rTheText.append(sal_Unicode(nUCS4));
5226 }
5227 
5228 //============================================================================
5229 // static
getUTF32(sal_Unicode const * & rBegin,sal_Unicode const * pEnd,bool bOctets,sal_Char cEscapePrefix,EncodeMechanism eMechanism,rtl_TextEncoding eCharset,EscapeType & rEscapeType)5230 sal_uInt32 INetURLObject::getUTF32(sal_Unicode const *& rBegin,
5231 								   sal_Unicode const * pEnd, bool bOctets,
5232 								   sal_Char cEscapePrefix,
5233 								   EncodeMechanism eMechanism,
5234 								   rtl_TextEncoding eCharset,
5235 								   EscapeType & rEscapeType)
5236 {
5237 	DBG_ASSERT(rBegin < pEnd, "INetURLObject::getUTF32(): Bad sequence");
5238 	sal_uInt32 nUTF32 = bOctets ? *rBegin++ :
5239 								  INetMIME::getUTF32Character(rBegin, pEnd);
5240 	switch (eMechanism)
5241 	{
5242 		case ENCODE_ALL:
5243 			rEscapeType = ESCAPE_NO;
5244 			break;
5245 
5246 		case WAS_ENCODED:
5247 		{
5248 			int nWeight1;
5249 			int nWeight2;
5250 			if (nUTF32 == sal_uChar(cEscapePrefix) && rBegin + 1 < pEnd
5251 				&& (nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0
5252 				&& (nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0)
5253 			{
5254 				rBegin += 2;
5255 				nUTF32 = nWeight1 << 4 | nWeight2;
5256 				switch (eCharset)
5257 				{
5258 					default:
5259 						DBG_ERROR(
5260 							"INetURLObject::getUTF32(): Unsupported charset");
5261 					case RTL_TEXTENCODING_ASCII_US:
5262 						rEscapeType = INetMIME::isUSASCII(nUTF32) ?
5263 										  ESCAPE_UTF32 : ESCAPE_OCTET;
5264 						break;
5265 
5266 					case RTL_TEXTENCODING_ISO_8859_1:
5267 						rEscapeType = ESCAPE_UTF32;
5268 						break;
5269 
5270 					case RTL_TEXTENCODING_UTF8:
5271 						if (INetMIME::isUSASCII(nUTF32))
5272 							rEscapeType = ESCAPE_UTF32;
5273 						else
5274 						{
5275 							if (nUTF32 >= 0xC0 && nUTF32 <= 0xF4)
5276 							{
5277 								sal_uInt32 nEncoded;
5278 								int nShift;
5279 								sal_uInt32 nMin;
5280 								if (nUTF32 <= 0xDF)
5281 								{
5282 									nEncoded = (nUTF32 & 0x1F) << 6;
5283 									nShift = 0;
5284 									nMin = 0x80;
5285 								}
5286 								else if (nUTF32 <= 0xEF)
5287 								{
5288 									nEncoded = (nUTF32 & 0x0F) << 12;
5289 									nShift = 6;
5290 									nMin = 0x800;
5291 								}
5292 								else
5293 								{
5294 									nEncoded = (nUTF32 & 0x07) << 18;
5295 									nShift = 12;
5296 									nMin = 0x10000;
5297 								}
5298 								sal_Unicode const * p = rBegin;
5299 								bool bUTF8 = true;
5300 								for (;;)
5301 								{
5302 									if (pEnd - p < 3
5303 										|| p[0] != cEscapePrefix
5304 										|| (nWeight1
5305 											   = INetMIME::getHexWeight(p[1]))
5306 											   < 8
5307 										|| nWeight1 > 11
5308 										|| (nWeight2
5309 											   = INetMIME::getHexWeight(p[2]))
5310 										       < 0)
5311 									{
5312 										bUTF8 = false;
5313 										break;
5314 									}
5315 									p += 3;
5316 									nEncoded
5317 										|= ((nWeight1 & 3) << 4 | nWeight2)
5318 											   << nShift;
5319 									if (nShift == 0)
5320 										break;
5321 									nShift -= 6;
5322 								}
5323 								if (bUTF8 && nEncoded >= nMin
5324 									&& !INetMIME::isHighSurrogate(nEncoded)
5325 									&& !INetMIME::isLowSurrogate(nEncoded)
5326 									&& nEncoded <= 0x10FFFF)
5327 								{
5328 									rBegin = p;
5329 									nUTF32 = nEncoded;
5330 									rEscapeType = ESCAPE_UTF32;
5331 									break;
5332 								}
5333 							}
5334 							rEscapeType = ESCAPE_OCTET;
5335 						}
5336 						break;
5337 				}
5338 			}
5339 			else
5340 				rEscapeType = ESCAPE_NO;
5341 			break;
5342 		}
5343 
5344 		case NOT_CANONIC:
5345 		{
5346 			int nWeight1;
5347 			int nWeight2;
5348 			if (nUTF32 == sal_uChar(cEscapePrefix) && rBegin + 1 < pEnd
5349 				&& ((nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0)
5350 				&& ((nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0))
5351 			{
5352 				rBegin += 2;
5353 				nUTF32 = nWeight1 << 4 | nWeight2;
5354 				rEscapeType = ESCAPE_OCTET;
5355 			}
5356 			else
5357 				rEscapeType = ESCAPE_NO;
5358 			break;
5359 		}
5360 	}
5361 	return nUTF32;
5362 }
5363 
5364 //============================================================================
5365 // static
scanDomain(sal_Unicode const * & rBegin,sal_Unicode const * pEnd,bool bEager)5366 sal_uInt32 INetURLObject::scanDomain(sal_Unicode const *& rBegin,
5367 									 sal_Unicode const * pEnd,
5368 									 bool bEager)
5369 {
5370 	enum State { STATE_DOT, STATE_LABEL, STATE_HYPHEN };
5371 	State eState = STATE_DOT;
5372 	sal_Int32 nLabels = 0;
5373 	sal_Unicode const * pLastAlphanumeric = 0;
5374 	for (sal_Unicode const * p = rBegin;; ++p)
5375 		switch (eState)
5376 		{
5377 			case STATE_DOT:
5378 				if (p != pEnd && INetMIME::isAlphanumeric(*p))
5379 				{
5380 					++nLabels;
5381 					eState = STATE_LABEL;
5382 					break;
5383 				}
5384 				if (bEager || nLabels == 0)
5385 					return 0;
5386 				rBegin = p - 1;
5387 				return nLabels;
5388 
5389 			case STATE_LABEL:
5390 				if (p != pEnd)
5391                 {
5392 					if (INetMIME::isAlphanumeric(*p))
5393 						break;
5394 					else if (*p == '.')
5395 					{
5396 						eState = STATE_DOT;
5397 						break;
5398 					}
5399 					else if (*p == '-')
5400 					{
5401 						pLastAlphanumeric = p;
5402 						eState = STATE_HYPHEN;
5403 						break;
5404 					}
5405                 }
5406 				rBegin = p;
5407 				return nLabels;
5408 
5409 			case STATE_HYPHEN:
5410 				if (p != pEnd)
5411                 {
5412 					if (INetMIME::isAlphanumeric(*p))
5413 					{
5414 						eState = STATE_LABEL;
5415 						break;
5416 					}
5417 					else if (*p == '-')
5418 						break;
5419                 }
5420 				if (bEager)
5421 					return 0;
5422 				rBegin = pLastAlphanumeric;
5423 				return nLabels;
5424 		}
5425 }
5426 
5427 //============================================================================
5428 // static
scanIPv6reference(sal_Unicode const * & rBegin,sal_Unicode const * pEnd)5429 bool INetURLObject::scanIPv6reference(sal_Unicode const *& rBegin,
5430 									  sal_Unicode const * pEnd)
5431 {
5432     if (rBegin != pEnd && *rBegin == '[') {
5433         sal_Unicode const * p = rBegin + 1;
5434         //TODO: check for valid IPv6address (RFC 2373):
5435         while (p != pEnd && (INetMIME::isHexDigit(*p) || *p == ':' || *p == '.'))
5436         {
5437             ++p;
5438         }
5439         if (p != pEnd && *p == ']') {
5440             rBegin = p + 1;
5441             return true;
5442         }
5443     }
5444     return false;
5445 }
5446 
5447 //============================================================================
GetPartBeforeLastName(DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const5448 rtl::OUString INetURLObject::GetPartBeforeLastName(DecodeMechanism eMechanism,
5449 											   rtl_TextEncoding eCharset)
5450 	const
5451 {
5452 	if (!checkHierarchical())
5453 		return rtl::OUString();
5454 	INetURLObject aTemp(*this);
5455 	aTemp.clearFragment();
5456 	aTemp.clearQuery();
5457 	aTemp.removeSegment(LAST_SEGMENT, false);
5458 	aTemp.setFinalSlash();
5459 	return aTemp.GetMainURL(eMechanism, eCharset);
5460 }
5461 
5462 //============================================================================
GetLastName(DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const5463 rtl::OUString INetURLObject::GetLastName(DecodeMechanism eMechanism,
5464 									 rtl_TextEncoding eCharset) const
5465 {
5466 	return getName(LAST_SEGMENT, true, eMechanism, eCharset);
5467 }
5468 
5469 //============================================================================
GetFileExtension(DecodeMechanism eMechanism,rtl_TextEncoding eCharset) const5470 rtl::OUString INetURLObject::GetFileExtension(DecodeMechanism eMechanism,
5471 										  rtl_TextEncoding eCharset) const
5472 {
5473 	return getExtension(LAST_SEGMENT, false, eMechanism, eCharset);
5474 }
5475 
5476 //============================================================================
CutLastName()5477 bool INetURLObject::CutLastName()
5478 {
5479 	INetURLObject aTemp(*this);
5480 	aTemp.clearFragment();
5481 	aTemp.clearQuery();
5482 	if (!aTemp.removeSegment(LAST_SEGMENT, false))
5483 		return false;
5484 	*this = aTemp;
5485 	return true;
5486 }
5487 
5488 //============================================================================
PathToFileName() const5489 rtl::OUString INetURLObject::PathToFileName() const
5490 {
5491 	if (m_eScheme != INET_PROT_FILE)
5492 		return rtl::OUString();
5493 	rtl::OUString aSystemPath;
5494 	if (osl::FileBase::getSystemPathFromFileURL(
5495 				decode(m_aAbsURIRef.getStr(),
5496 					   m_aAbsURIRef.getStr() + m_aPath.getEnd(),
5497 					   getEscapePrefix(), NO_DECODE, RTL_TEXTENCODING_UTF8),
5498 				aSystemPath)
5499 			!= osl::FileBase::E_None)
5500 		return rtl::OUString();
5501     return aSystemPath;
5502 }
5503 
5504 //============================================================================
GetFull() const5505 rtl::OUString INetURLObject::GetFull() const
5506 {
5507 	INetURLObject aTemp(*this);
5508 	aTemp.removeFinalSlash();
5509 	return aTemp.PathToFileName();
5510 }
5511 
5512 //============================================================================
GetPath() const5513 rtl::OUString INetURLObject::GetPath() const
5514 {
5515 	INetURLObject aTemp(*this);
5516 	aTemp.removeSegment(LAST_SEGMENT, true);
5517 	aTemp.removeFinalSlash();
5518 	return aTemp.PathToFileName();
5519 }
5520 
5521 //============================================================================
SetBase(rtl::OUString const & rTheBase)5522 void INetURLObject::SetBase(rtl::OUString const & rTheBase)
5523 {
5524 	setBase(rTheBase, LAST_SEGMENT, true, ENCODE_ALL);
5525 }
5526 
5527 //============================================================================
GetBase() const5528 rtl::OUString INetURLObject::GetBase() const
5529 {
5530 	return getBase(LAST_SEGMENT, true, DECODE_WITH_CHARSET);
5531 }
5532 
5533 //============================================================================
SetName(rtl::OUString const & rTheName,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)5534 void INetURLObject::SetName(rtl::OUString const & rTheName,
5535 							EncodeMechanism eMechanism,
5536 							rtl_TextEncoding eCharset)
5537 {
5538 	INetURLObject aTemp(*this);
5539 	if (aTemp.removeSegment(LAST_SEGMENT, true)
5540 		&& aTemp.insertName(rTheName, false, LAST_SEGMENT, true, eMechanism,
5541 							eCharset))
5542 		*this = aTemp;
5543 }
5544 
5545 //============================================================================
CutName(DecodeMechanism eMechanism,rtl_TextEncoding eCharset)5546 rtl::OUString INetURLObject::CutName(DecodeMechanism eMechanism,
5547 								 rtl_TextEncoding eCharset)
5548 {
5549 	rtl::OUString aTheName(getName(LAST_SEGMENT, true, eMechanism, eCharset));
5550 	return removeSegment(LAST_SEGMENT, true) ? aTheName : rtl::OUString();
5551 }
5552 
5553 //============================================================================
SetExtension(rtl::OUString const & rTheExtension,EncodeMechanism eMechanism,rtl_TextEncoding eCharset)5554 void INetURLObject::SetExtension(rtl::OUString const & rTheExtension,
5555 								 EncodeMechanism eMechanism,
5556 								 rtl_TextEncoding eCharset)
5557 {
5558 	setExtension(rTheExtension, LAST_SEGMENT, false, eMechanism, eCharset);
5559 }
5560 
5561 //============================================================================
CutExtension(DecodeMechanism eMechanism,rtl_TextEncoding eCharset)5562 rtl::OUString INetURLObject::CutExtension(DecodeMechanism eMechanism,
5563 									  rtl_TextEncoding eCharset)
5564 {
5565 	rtl::OUString aTheExtension(getExtension(LAST_SEGMENT, false, eMechanism,
5566 										 eCharset));
5567 	return removeExtension(LAST_SEGMENT, false)
5568 		? aTheExtension : rtl::OUString();
5569 }
5570 
5571 //============================================================================
IsCaseSensitive() const5572 bool INetURLObject::IsCaseSensitive() const
5573 {
5574 	return true;
5575 }
5576