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