| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_tools.hxx" |
| #include <tools/urlobj.hxx> |
| #include <tools/debug.hxx> |
| #include <tools/inetmime.hxx> |
| #include "com/sun/star/uno/Reference.hxx" |
| #include "com/sun/star/util/XStringWidth.hpp" |
| #include "osl/diagnose.h" |
| #include "osl/file.hxx" |
| #include "rtl/string.h" |
| #include "rtl/textenc.h" |
| #include "rtl/ustring.hxx" |
| #include "sal/types.h" |
| |
| #ifndef INCLUDED_ALGORITHM |
| #include <algorithm> |
| #define INCLUDED_ALGORITHM |
| #endif |
| #ifndef INCLUDED_LIMITS |
| #include <limits> |
| #define INCLUDED_LIMITS |
| #endif |
| |
| #include <string.h> |
| |
| namespace unnamed_tools_urlobj {} using namespace unnamed_tools_urlobj; |
| // unnamed namespaces don't work well yet... |
| |
| using namespace com::sun; |
| |
| //============================================================================ |
| // |
| // INetURLObject |
| // |
| //============================================================================ |
| |
| /* The URI grammar (using RFC 2234 conventions). |
| |
| Constructs of the form |
| {reference <rule1> using rule2} |
| stand for a rule matching the given rule1 specified in the given reference, |
| encoded to URI syntax using rule2 (as specified in this URI grammar). |
| |
| |
| ; RFC 1738, RFC 2396, RFC 2732, private |
| login = [user [":" password] "@"] hostport |
| user = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~") |
| password = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ";" / "=" / "_" / "~") |
| hostport = host [":" port] |
| host = incomplete-hostname / hostname / IPv4address / IPv6reference |
| incomplete-hostname = *(domainlabel ".") domainlabel |
| hostname = *(domainlabel ".") toplabel ["."] |
| domainlabel = alphanum [*(alphanum / "-") alphanum] |
| toplabel = ALPHA [*(alphanum / "-") alphanum] |
| IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT |
| IPv6reference = "[" hexpart [":" IPv4address] "]" |
| hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq]) |
| hexseq = hex4 *(":" hex4) |
| hex4 = 1*4HEXDIG |
| port = *DIGIT |
| escaped = "%" HEXDIG HEXDIG |
| reserved = "$" / "&" / "+" / "," / "/" / ":" / ";" / "=" / "?" / "@" / "[" / "]" |
| mark = "!" / "'" / "(" / ")" / "*" / "-" / "." / "_" / "~" |
| alphanum = ALPHA / DIGIT |
| unreserved = alphanum / mark |
| uric = escaped / reserved / unreserved |
| pchar = escaped / unreserved / "$" / "&" / "+" / "," / ":" / "=" / "@" |
| |
| |
| ; RFC 1738, RFC 2396 |
| ftp-url = "FTP://" login ["/" segment *("/" segment) [";TYPE=" ("A" / "D" / "I")]] |
| segment = *pchar |
| |
| |
| ; RFC 1738, RFC 2396 |
| http-url = "HTTP://" hostport ["/" segment *("/" segment) ["?" *uric]] |
| segment = *(pchar / ";") |
| |
| |
| ; RFC 1738, RFC 2396, <http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q188997&> |
| file-url = "FILE://" [host / "LOCALHOST" / netbios-name] ["/" segment *("/" segment)] |
| segment = *pchar |
| netbios-name = 1*{<alphanum / "!" / "#" / "$" / "%" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "^" / "_" / "{" / "}" / "~"> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "-" / "." / "@" / "_" / "~")} |
| |
| |
| ; RFC 2368, RFC 2396 |
| mailto-url = "MAILTO:" [to] [headers] |
| to = {RFC 822 <#mailbox> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} |
| headers = "?" header *("&" header) |
| header = hname "=" hvalue |
| hname = {RFC 822 <field-name> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} / "BODY" |
| hvalue = {RFC 822 <field-body> using *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} |
| |
| |
| ; private (see RFC 1738, RFC 2396) |
| vnd-sun-star-webdav-url = "VND.SUN.STAR.WEBDAV://" hostport ["/" segment *("/" segment) ["?" *uric]] |
| segment = *(pchar / ";") |
| |
| |
| ; RFC 1738, RFC 2396, RFC 2732 |
| news-url = "NEWS:" grouppart |
| grouppart = "*" / group / article |
| group = alpha *(alphanum / "+" / "-" / "." / "_") |
| article = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "?" / "_" / "~") "@" host |
| |
| |
| ; private |
| private-url = "PRIVATE:" path ["?" *uric] |
| path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| |
| ; private |
| vnd-sun-star-help-url = "VND.SUN.STAR.HELP://" name *("/" segment) ["?" *uric] |
| name = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") |
| segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| |
| ; private |
| https-url = "HTTPS://" hostport ["/" segment *("/" segment) ["?" *uric]] |
| segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| |
| ; private |
| slot-url = "SLOT:" path ["?" *uric] |
| path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| |
| ; private |
| macro-url = "MACRO:" path ["?" *uric] |
| path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| |
| ; private |
| javascript-url = "JAVASCRIPT:" *uric |
| |
| |
| ; private (see RFC 2192) |
| imap-url = "IMAP://" user [";AUTH=" auth] "@" hostport "/" segment *("/" segment) ["/;UID=" nz_number] |
| user = 1*{RFC 2060 <CHAR8> using (escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "=" / "_" / "~")} |
| auth = {RFC 2060 <atom> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "+" / "," / "-" / "." / "=" / "_" / "~")} |
| segment = *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / "=" / "@" / "_" / "~") |
| nz_number = {RFC 2060 <nz_number> using *DIGIT} |
| |
| |
| ; private |
| pop3-url = "POP3://" login ["/" ["<" *uric ">"]] |
| |
| |
| ; RFC 2397 |
| data-url = "DATA:" [mediatype] [";BASE64"] "," *uric |
| mediatype = [type "/" subtype] *(";" attribute "=" value) |
| type = {RFC 2045 <type> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} |
| subtype = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} |
| attribute = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} |
| value = {RFC 2045 <subtype> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / ":" / "?" / "@" / "_" / "~")} |
| |
| |
| ; RFC 2392, RFC 2396 |
| cid-url = "CID:" {RFC 822 <addr-spec> using *uric} |
| |
| |
| ; private |
| out-url = "OUT:///~" name ["/" *uric] |
| name = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "?" / "@" / "_" / "~" |
| |
| |
| ; private |
| vnd-sun-star-hier-url = "VND.SUN.STAR.HIER:" ["//"reg_name] *("/" *pchar) |
| reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| ; private |
| vim-url = "VIM://" +vimc [":" *vimc] ["/" [("INBOX" message) / ("NEWSGROUPS" ["/" [+vimc message]])]] |
| message = ["/" [+vimc [":" +DIGIT "." +DIGIT "." +DIGIT]]] |
| vimc = ("=" HEXDIG HEXDIG) / alphanum |
| |
| |
| ; private |
| uno-url = ".UNO:" path ["?" *uric] |
| path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| |
| ; private |
| component-url = ".COMPONENT:" path ["?" *uric] |
| path = *(escaped / alphanum / "!" / "$" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| |
| ; private |
| vnd-sun-star-pkg-url = "VND.SUN.STAR.PKG://" reg_name *("/" *pchar) ["?" *uric] |
| reg_name = 1*(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / ":" / ";" / "=" / "@" / "_" / "~") |
| |
| |
| ; RFC 2255 |
| ldap-url = "LDAP://" [hostport] ["/" [dn ["?" [attrdesct *("," attrdesc)] ["?" ["base" / "one" / "sub"] ["?" [filter] ["?" extension *("," extension)]]]]]] |
| dn = {RFC 2253 <distinguishedName> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} |
| attrdesc = {RFC 2251 <AttributeDescription> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} |
| filter = {RFC 2254 <filter> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} |
| extension = ["!"] ["X-"] extoken ["=" exvalue] |
| extoken = {RFC 2252 <oid> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "@" / "_" / "~")} |
| exvalue = {RFC 2251 <LDAPString> using *(escaped / alphanum / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / ";" / "=" / "@" / "_" / "~")} |
| |
| |
| ; private |
| db-url = "DB:" *uric |
| |
| |
| ; private |
| vnd-sun-star-cmd-url = "VND.SUN.STAR.CMD:" opaque_part |
| opaque_part = uric_no_slash *uric |
| uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," |
| |
| |
| ; private |
| vnd-sun-star-url = "VND.SUN.STAR.ODMA:" ["/" *uric_no_slash] |
| uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," |
| |
| |
| ; RFC 1738 |
| telnet-url = "TELNET://" login ["/"] |
| |
| |
| ; private |
| vnd-sun-star-expand-url = "VND.SUN.STAR.EXPAND:" opaque_part |
| opaque_part = uric_no_slash *uric |
| uric_no_slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," |
| |
| |
| ; private |
| vnd-sun-star-tdoc-url = "VND.SUN.STAR.TDOC:/" segment *("/" segment) |
| segment = *pchar |
| |
| |
| ; private |
| unknown-url = scheme ":" 1*uric |
| scheme = ALPHA *(alphanum / "+" / "-" / ".") |
| |
| |
| ; private (http://ubiqx.org/cifs/Appendix-D.html): |
| smb-url = "SMB://" login ["/" segment *("/" segment) ["?" *uric]] |
| segment = *(pchar / ";") |
| */ |
| |
| //============================================================================ |
| inline sal_Int32 INetURLObject::SubString::clear() |
| { |
| sal_Int32 nDelta = -m_nLength; |
| m_nBegin = -1; |
| m_nLength = 0; |
| return nDelta; |
| } |
| |
| inline sal_Int32 INetURLObject::SubString::set(rtl::OUStringBuffer & rString, |
| rtl::OUString const & rSubString) |
| { |
| rtl::OUString sTemp(rString.makeStringAndClear()); |
| sal_Int32 nDelta = set(sTemp, rSubString); |
| rString.append(sTemp); |
| return nDelta; |
| } |
| |
| inline sal_Int32 INetURLObject::SubString::set(rtl::OUString & rString, |
| rtl::OUString const & rSubString) |
| { |
| sal_Int32 nDelta = rSubString.getLength() - m_nLength; |
| |
| rString = rString.replaceAt(m_nBegin, m_nLength, rSubString); |
| |
| m_nLength = rSubString.getLength(); |
| return nDelta; |
| } |
| |
| inline sal_Int32 INetURLObject::SubString::set(rtl::OUStringBuffer & rString, |
| rtl::OUString const & rSubString, |
| sal_Int32 nTheBegin) |
| { |
| m_nBegin = nTheBegin; |
| return set(rString, rSubString); |
| } |
| |
| //============================================================================ |
| inline void INetURLObject::SubString::operator +=(sal_Int32 nDelta) |
| { |
| if (isPresent()) |
| m_nBegin = m_nBegin + nDelta; |
| } |
| |
| //============================================================================ |
| int INetURLObject::SubString::compare(SubString const & rOther, |
| rtl::OUStringBuffer const & rThisString, |
| rtl::OUStringBuffer const & rOtherString) const |
| { |
| sal_Int32 len = std::min(m_nLength, rOther.m_nLength); |
| sal_Unicode const * p1 = rThisString.getStr() + m_nBegin; |
| sal_Unicode const * end = p1 + len; |
| sal_Unicode const * p2 = rOtherString.getStr() + rOther.m_nBegin; |
| while (p1 != end) { |
| if (*p1 < *p2) { |
| return -1; |
| } else if (*p1 > *p2) { |
| return 1; |
| } |
| ++p1; |
| ++p2; |
| } |
| return m_nLength < rOther.m_nLength ? -1 |
| : m_nLength > rOther.m_nLength ? 1 |
| : 0; |
| } |
| |
| //============================================================================ |
| struct INetURLObject::SchemeInfo |
| { |
| sal_Char const * m_pScheme; |
| sal_Char const * m_pPrefix; |
| sal_uInt16 m_nDefaultPort; |
| bool m_bAuthority; |
| bool m_bUser; |
| bool m_bAuth; |
| bool m_bPassword; |
| bool m_bHost; |
| bool m_bPort; |
| bool m_bHierarchical; |
| bool m_bQuery; |
| }; |
| |
| //============================================================================ |
| struct INetURLObject::PrefixInfo |
| { |
| enum Kind { OFFICIAL, INTERNAL, EXTERNAL, ALIAS }; // order is important! |
| |
| sal_Char const * m_pPrefix; |
| sal_Char const * m_pTranslatedPrefix; |
| INetProtocol m_eScheme; |
| Kind m_eKind; |
| }; |
| |
| //============================================================================ |
| static INetURLObject::SchemeInfo const aSchemeInfoMap[INET_PROT_END] |
| = { { "", "", 0, false, false, false, false, false, false, false, |
| false }, |
| { "ftp", "ftp://", 21, true, true, false, true, true, true, true, |
| false }, |
| { "http", "http://", 80, true, false, false, false, true, true, |
| true, true }, |
| { "file", "file://", 0, true, false, false, false, true, false, |
| true, false }, |
| { "mailto", "mailto:", 0, false, false, false, false, false, |
| false, false, true }, |
| { "vnd.sun.star.webdav", "vnd.sun.star.webdav://", 80, true, false, |
| false, false, true, true, true, true }, |
| { "news", "news:", 0, false, false, false, false, false, false, false, |
| false }, |
| { "private", "private:", 0, false, false, false, false, false, |
| false, false, true }, |
| { "vnd.sun.star.help", "vnd.sun.star.help://", 0, true, false, false, |
| false, false, false, true, true }, |
| { "https", "https://", 443, true, false, false, false, true, true, |
| true, true }, |
| { "slot", "slot:", 0, false, false, false, false, false, false, |
| false, true }, |
| { "macro", "macro:", 0, false, false, false, false, false, false, |
| false, true }, |
| { "javascript", "javascript:", 0, false, false, false, false, |
| false, false, false, false }, |
| { "imap", "imap://", 143, true, true, true, false, true, true, |
| true, false }, |
| { "pop3", "pop3://", 110, true, true, false, true, true, true, |
| false, false }, |
| { "data", "data:", 0, false, false, false, false, false, false, |
| false, false }, |
| { "cid", "cid:", 0, false, false, false, false, false, false, |
| false, false }, |
| { "out", "out://", 0, true, false, false, false, false, false, |
| false, false }, |
| { "vnd.sun.star.hier", "vnd.sun.star.hier:", 0, true, false, false, |
| false, false, false, true, false }, |
| { "vim", "vim://", 0, true, true, false, true, false, false, true, |
| false }, |
| { ".uno", ".uno:", 0, false, false, false, false, false, false, |
| false, true }, |
| { ".component", ".component:", 0, false, false, false, false, |
| false, false, false, true }, |
| { "vnd.sun.star.pkg", "vnd.sun.star.pkg://", 0, true, false, false, |
| false, false, false, true, true }, |
| { "ldap", "ldap://", 389, true, false, false, false, true, true, |
| false, true }, |
| { "db", "db:", 0, false, false, false, false, false, false, false, |
| false }, |
| { "vnd.sun.star.cmd", "vnd.sun.star.cmd:", 0, false, false, false, |
| false, false, false, false, false }, |
| { "vnd.sun.star.odma", "vnd.sun.star.odma:", 0, false, false, false, |
| false, false, false, true, false }, |
| { "telnet", "telnet://", 23, true, true, false, true, true, true, true, |
| false }, |
| { "vnd.sun.star.expand", "vnd.sun.star.expand:", 0, false, false, false, |
| false, false, false, false, false }, |
| { "vnd.sun.star.tdoc", "vnd.sun.star.tdoc:", 0, false, false, false, |
| false, false, false, true, false }, |
| { "", "", 0, false, false, false, false, true, true, true, false }, |
| { "smb", "smb://", 139, true, true, false, true, true, true, true, |
| true }, |
| { "hid", "hid:", 0, false, false, false, false, false, false, |
| false, true } }; |
| |
| // static |
| inline INetURLObject::SchemeInfo const & |
| INetURLObject::getSchemeInfo(INetProtocol eTheScheme) |
| { |
| return aSchemeInfoMap[eTheScheme]; |
| }; |
| |
| //============================================================================ |
| inline INetURLObject::SchemeInfo const & INetURLObject::getSchemeInfo() const |
| { |
| return getSchemeInfo(m_eScheme); |
| } |
| |
| //============================================================================ |
| // static |
| inline void INetURLObject::appendEscape(rtl::OUStringBuffer & rTheText, |
| sal_Char cEscapePrefix, |
| sal_uInt32 nOctet) |
| { |
| rTheText.append(sal_Unicode(cEscapePrefix)); |
| rTheText.append(sal_Unicode(INetMIME::getHexDigit(int(nOctet >> 4)))); |
| rTheText.append(sal_Unicode(INetMIME::getHexDigit(int(nOctet & 15)))); |
| } |
| |
| //============================================================================ |
| namespace unnamed_tools_urlobj { |
| |
| enum |
| { |
| PA = INetURLObject::PART_OBSOLETE_NORMAL, |
| PB = INetURLObject::PART_OBSOLETE_FILE, |
| PC = INetURLObject::PART_OBSOLETE_PARAM, |
| PD = INetURLObject::PART_USER_PASSWORD, |
| PE = INetURLObject::PART_IMAP_ACHAR, |
| PF = INetURLObject::PART_VIM, |
| PG = INetURLObject::PART_HOST_EXTRA, |
| PH = INetURLObject::PART_FPATH, |
| PI = INetURLObject::PART_AUTHORITY, |
| PJ = INetURLObject::PART_PATH_SEGMENTS_EXTRA, |
| PK = INetURLObject::PART_REL_SEGMENT_EXTRA, |
| PL = INetURLObject::PART_URIC, |
| PM = INetURLObject::PART_HTTP_PATH, |
| PN = INetURLObject::PART_FILE_SEGMENT_EXTRA, |
| PO = INetURLObject::PART_MESSAGE_ID, |
| PP = INetURLObject::PART_MESSAGE_ID_PATH, |
| PQ = INetURLObject::PART_MAILTO, |
| PR = INetURLObject::PART_PATH_BEFORE_QUERY, |
| PS = INetURLObject::PART_PCHAR, |
| PT = INetURLObject::PART_FRAGMENT, |
| PU = INetURLObject::PART_VISIBLE, |
| PV = INetURLObject::PART_VISIBLE_NONSPECIAL, |
| PW = INetURLObject::PART_CREATEFRAGMENT, |
| PX = INetURLObject::PART_UNO_PARAM_VALUE, |
| PY = INetURLObject::PART_UNAMBIGUOUS, |
| PZ = INetURLObject::PART_URIC_NO_SLASH, |
| P1 = INetURLObject::PART_HTTP_QUERY, |
| P2 = INetURLObject::PART_NEWS_ARTICLE_LOCALPART |
| }; |
| |
| static sal_uInt32 const aMustEncodeMap[128] |
| = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| /* */ PY, |
| /* ! */ 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, |
| /* " */ PU+PV +PY, |
| /* # */ PU, |
| /* $ */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, |
| /* % */ PU, |
| /* & */ PA+PB+PC+PD+PE +PH+PI+PJ+PK+PL+PM+PN+PO+PP +PR+PS+PT+PU+PV+PW+PX +PZ+P1+P2, |
| /* ' */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, |
| /* ( */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, |
| /* ) */ PD+PE +PG+PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1+P2, |
| /* * */ 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, |
| /* + */ 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, |
| /* , */ 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, |
| /* - */ 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, |
| /* . */ 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, |
| /* / */ PA+PB+PC +PH +PJ +PL+PM +PP+PQ+PR +PT+PU+PV +PX +P2, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* : */ PB+PC +PH+PI+PJ +PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX +PZ+P1+P2, |
| /* ; */ PC+PD +PI+PJ+PK+PL+PM +PO+PP+PQ+PR +PT+PU +PW +PZ+P1+P2, |
| /* < */ PC +PO+PP +PU+PV +PY, |
| /* = */ PA+PB+PC+PD+PE +PH+PI+PJ+PK+PL+PM+PN +PR+PS+PT+PU+PV+PW +PZ+P1+P2, |
| /* > */ PC +PO+PP +PU+PV +PY, |
| /* ? */ PC +PL +PT+PU +PW+PX +PZ +P2, |
| /* @ */ PC +PH+PI+PJ+PK+PL+PM+PN+PO+PP+PQ+PR+PS+PT+PU+PV+PW+PX+PY+PZ+P1, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* [ */ PL +PU+PV +PX, |
| /* \ */ PB +PU+PV +PY, |
| /* ] */ PL +PU+PV +PX, |
| /* ^ */ PU+PV +PY, |
| /* _ */ 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, |
| /* ` */ PU+PV +PY, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* 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, |
| /* { */ PU+PV +PY, |
| /* | */ PB+PC +PN +PT+PU+PV +PY, |
| /* } */ PU+PV +PY, |
| /* ~ */ 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, |
| 0 }; |
| |
| inline bool mustEncode(sal_uInt32 nUTF32, INetURLObject::Part ePart) |
| { |
| return !INetMIME::isUSASCII(nUTF32) || !(aMustEncodeMap[nUTF32] & ePart); |
| } |
| |
| } |
| |
| //============================================================================ |
| void INetURLObject::setInvalid() |
| { |
| m_aAbsURIRef.setLength(0); |
| m_eScheme = INET_PROT_NOT_VALID; |
| m_aScheme.clear(); |
| m_aUser.clear(); |
| m_aAuth.clear(); |
| m_aHost.clear(); |
| m_aPort.clear(); |
| m_aPath.clear(); |
| m_aQuery.clear(); |
| m_aFragment.clear(); |
| } |
| |
| //============================================================================ |
| |
| namespace unnamed_tools_urlobj { |
| |
| INetURLObject::FSysStyle |
| guessFSysStyleByCounting(sal_Unicode const * pBegin, |
| sal_Unicode const * pEnd, |
| INetURLObject::FSysStyle eStyle) |
| { |
| DBG_ASSERT(eStyle |
| & (INetURLObject::FSYS_UNX |
| | INetURLObject::FSYS_DOS |
| | INetURLObject::FSYS_MAC), |
| "guessFSysStyleByCounting(): Bad style"); |
| DBG_ASSERT(std::numeric_limits< sal_Int32 >::min() < pBegin - pEnd |
| && pEnd - pBegin <= std::numeric_limits< sal_Int32 >::max(), |
| "guessFSysStyleByCounting(): Too big"); |
| sal_Int32 nSlashCount |
| = eStyle & INetURLObject::FSYS_UNX ? |
| 0 : std::numeric_limits< sal_Int32 >::min(); |
| sal_Int32 nBackslashCount |
| = eStyle & INetURLObject::FSYS_DOS ? |
| 0 : std::numeric_limits< sal_Int32 >::min(); |
| sal_Int32 nColonCount |
| = eStyle & INetURLObject::FSYS_MAC ? |
| 0 : std::numeric_limits< sal_Int32 >::min(); |
| while (pBegin != pEnd) |
| switch (*pBegin++) |
| { |
| case '/': |
| ++nSlashCount; |
| break; |
| |
| case '\\': |
| ++nBackslashCount; |
| break; |
| |
| case ':': |
| ++nColonCount; |
| break; |
| } |
| return nSlashCount >= nBackslashCount ? |
| nSlashCount >= nColonCount ? |
| INetURLObject::FSYS_UNX : INetURLObject::FSYS_MAC : |
| nBackslashCount >= nColonCount ? |
| INetURLObject::FSYS_DOS : INetURLObject::FSYS_MAC; |
| } |
| |
| rtl::OUString parseScheme( |
| sal_Unicode const ** begin, sal_Unicode const * end, |
| sal_uInt32 fragmentDelimiter) |
| { |
| sal_Unicode const * p = *begin; |
| if (p != end && INetMIME::isAlpha(*p)) { |
| do { |
| ++p; |
| } while (p != end |
| && (INetMIME::isAlphanumeric(*p) || *p == '+' || *p == '-' |
| || *p == '.')); |
| // #i34835# To avoid problems with Windows file paths like "C:\foo", |
| // do not accept generic schemes that are only one character long: |
| if (end - p > 1 && p[0] == ':' && p[1] != fragmentDelimiter |
| && p - *begin >= 2) |
| { |
| rtl::OUString scheme( |
| rtl::OUString(*begin, p - *begin).toAsciiLowerCase()); |
| *begin = p + 1; |
| return scheme; |
| } |
| } |
| return rtl::OUString(); |
| } |
| |
| } |
| |
| bool INetURLObject::setAbsURIRef(rtl::OUString const & rTheAbsURIRef, |
| bool bOctets, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset, |
| bool bSmart, |
| FSysStyle eStyle) |
| { |
| sal_Unicode const * pPos = rTheAbsURIRef.getStr(); |
| sal_Unicode const * pEnd = pPos + rTheAbsURIRef.getLength(); |
| |
| setInvalid(); |
| |
| sal_uInt32 nFragmentDelimiter = '#'; |
| |
| rtl::OUStringBuffer aSynAbsURIRef; |
| |
| // Parse <scheme>: |
| sal_Unicode const * p = pPos; |
| PrefixInfo const * pPrefix = getPrefix(p, pEnd); |
| if (pPrefix) |
| { |
| pPos = p; |
| m_eScheme = pPrefix->m_eScheme; |
| |
| rtl::OUString sTemp(rtl::OUString::createFromAscii(pPrefix->m_eKind |
| >= PrefixInfo::EXTERNAL ? |
| pPrefix->m_pTranslatedPrefix : |
| pPrefix->m_pPrefix)); |
| aSynAbsURIRef.append(sTemp); |
| m_aScheme = SubString( 0, sTemp.indexOf(static_cast< sal_Unicode >(':')) ); |
| } |
| else |
| { |
| if (bSmart) |
| { |
| // For scheme detection, the first (if any) of the following |
| // productions that matches the input string (and for which the |
| // appropriate style bit is set in eStyle, if applicable) |
| // determines the scheme. The productions use the auxiliary rules |
| // |
| // domain = label *("." label) |
| // label = alphanum [*(alphanum / "-") alphanum] |
| // alphanum = ALPHA / DIGIT |
| // IPv6reference = "[" IPv6address "]" |
| // IPv6address = hexpart [":" IPv4address] |
| // IPv4address = 1*3DIGIT 3("." 1*3DIGIT) |
| // hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq]) |
| // hexseq = hex4 *(":" hex4) |
| // hex4 = 1*4HEXDIG |
| // UCS4 = <any UCS4 character> |
| // |
| // 1st Production (known scheme): |
| // <one of the known schemes, ignoring case> ":" *UCS4 |
| // |
| // 2nd Production (mailto): |
| // domain "@" domain |
| // |
| // 3rd Production (ftp): |
| // "FTP" 2*("." label) ["/" *UCS4] |
| // |
| // 4th Production (http): |
| // label 2*("." label) ["/" *UCS4] |
| // |
| // 5th Production (file): |
| // "//" (domain / IPv6reference) ["/" *UCS4] |
| // |
| // 6th Production (Unix file): |
| // "/" *UCS4 |
| // |
| // 7th Production (UNC file; FSYS_DOS only): |
| // "\\" domain ["\" *UCS4] |
| // |
| // 8th Production (Unix-like DOS file; FSYS_DOS only): |
| // ALPHA ":" ["/" *UCS4] |
| // |
| // 9th Production (DOS file; FSYS_DOS only): |
| // ALPHA ":" ["\" *UCS4] |
| // |
| // For the 'non URL' file productions 6--9, the interpretation of |
| // the input as a (degenerate) URI is turned off, i.e., escape |
| // sequences and fragments are never detected as such, but are |
| // taken as literal characters. |
| |
| sal_Unicode const * p1 = pPos; |
| if (eStyle & FSYS_DOS |
| && pEnd - p1 >= 2 |
| && INetMIME::isAlpha(p1[0]) |
| && p1[1] == ':' |
| && (pEnd - p1 == 2 || p1[2] == '/' || p1[2] == '\\')) |
| { |
| m_eScheme = INET_PROT_FILE; // 8th, 9th |
| eMechanism = ENCODE_ALL; |
| nFragmentDelimiter = 0x80000000; |
| } |
| else if (pEnd - p1 >= 2 && p1[0] == '/' && p1[1] == '/') |
| { |
| p1 += 2; |
| if ((scanDomain(p1, pEnd) > 0 || scanIPv6reference(p1, pEnd)) |
| && (p1 == pEnd || *p1 == '/')) |
| m_eScheme = INET_PROT_FILE; // 5th |
| } |
| else if (p1 != pEnd && *p1 == '/') |
| { |
| m_eScheme = INET_PROT_FILE; // 6th |
| eMechanism = ENCODE_ALL; |
| nFragmentDelimiter = 0x80000000; |
| } |
| else if (eStyle & FSYS_DOS |
| && pEnd - p1 >= 2 |
| && p1[0] == '\\' |
| && p1[1] == '\\') |
| { |
| p1 += 2; |
| sal_Int32 n = rtl_ustr_indexOfChar_WithLength( |
| p1, pEnd - p1, '\\'); |
| sal_Unicode const * pe = n == -1 ? pEnd : p1 + n; |
| if ( |
| parseHostOrNetBiosName( |
| p1, pe, bOctets, ENCODE_ALL, RTL_TEXTENCODING_DONTKNOW, |
| true, NULL) || |
| (scanDomain(p1, pe) > 0 && p1 == pe) |
| ) |
| { |
| m_eScheme = INET_PROT_FILE; // 7th |
| eMechanism = ENCODE_ALL; |
| nFragmentDelimiter = 0x80000000; |
| } |
| } |
| else |
| { |
| sal_Unicode const * pDomainEnd = p1; |
| sal_uInt32 nLabels = scanDomain(pDomainEnd, pEnd); |
| if (nLabels > 0 && pDomainEnd != pEnd && *pDomainEnd == '@') |
| { |
| ++pDomainEnd; |
| if (scanDomain(pDomainEnd, pEnd) > 0 |
| && pDomainEnd == pEnd) |
| m_eScheme = INET_PROT_MAILTO; // 2nd |
| } |
| else if (nLabels >= 3 |
| && (pDomainEnd == pEnd || *pDomainEnd == '/')) |
| m_eScheme |
| = pDomainEnd - p1 >= 4 |
| && (p1[0] == 'f' || p1[0] == 'F') |
| && (p1[1] == 't' || p1[1] == 'T') |
| && (p1[2] == 'p' || p1[2] == 'P') |
| && p1[3] == '.' ? |
| INET_PROT_FTP : INET_PROT_HTTP; // 3rd, 4th |
| } |
| } |
| |
| rtl::OUString aSynScheme; |
| if (m_eScheme == INET_PROT_NOT_VALID) { |
| sal_Unicode const * p1 = pPos; |
| aSynScheme = parseScheme(&p1, pEnd, nFragmentDelimiter); |
| if (aSynScheme.getLength() > 0) |
| { |
| m_eScheme = INET_PROT_GENERIC; |
| pPos = p1; |
| } |
| } |
| |
| if (bSmart && m_eScheme == INET_PROT_NOT_VALID && pPos != pEnd |
| && *pPos != nFragmentDelimiter) |
| { |
| m_eScheme = m_eSmartScheme; |
| } |
| |
| if (m_eScheme == INET_PROT_NOT_VALID) |
| { |
| setInvalid(); |
| return false; |
| } |
| |
| if (m_eScheme != INET_PROT_GENERIC) { |
| aSynScheme = rtl::OUString::createFromAscii(getSchemeInfo().m_pScheme); |
| } |
| m_aScheme.set(aSynAbsURIRef, aSynScheme, aSynAbsURIRef.getLength()); |
| aSynAbsURIRef.append(sal_Unicode(':')); |
| } |
| |
| sal_Char cEscapePrefix = getEscapePrefix(); |
| sal_uInt32 nSegmentDelimiter = '/'; |
| sal_uInt32 nAltSegmentDelimiter = 0x80000000; |
| bool bSkippedInitialSlash = false; |
| |
| // Parse //<user>;AUTH=<auth>@<host>:<port> or |
| // //<user>:<password>@<host>:<port> or |
| // //<reg_name> |
| if (getSchemeInfo().m_bAuthority) |
| { |
| sal_Unicode const * pUserInfoBegin = 0; |
| sal_Unicode const * pUserInfoEnd = 0; |
| sal_Unicode const * pHostPortBegin = 0; |
| sal_Unicode const * pHostPortEnd = 0; |
| |
| switch (m_eScheme) |
| { |
| case INET_PROT_VND_SUN_STAR_HELP: |
| { |
| if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/') |
| { |
| setInvalid(); |
| return false; |
| } |
| aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| rtl::OUStringBuffer aSynAuthority; |
| while (pPos < pEnd |
| && *pPos != '/' && *pPos != '?' |
| && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| cEscapePrefix, eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aSynAuthority, nUTF32, eEscapeType, bOctets, |
| PART_AUTHORITY, cEscapePrefix, eCharset, |
| false); |
| } |
| m_aHost.set(aSynAbsURIRef, |
| aSynAuthority.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| // misusing m_aHost to store the authority |
| break; |
| } |
| |
| case INET_PROT_VND_SUN_STAR_HIER: |
| { |
| if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') |
| { |
| pPos += 2; |
| aSynAbsURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| rtl::OUStringBuffer aSynAuthority; |
| while (pPos < pEnd |
| && *pPos != '/' && *pPos != '?' |
| && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, |
| pEnd, |
| bOctets, |
| cEscapePrefix, |
| eMechanism, |
| eCharset, |
| eEscapeType); |
| appendUCS4(aSynAuthority, |
| nUTF32, |
| eEscapeType, |
| bOctets, |
| PART_AUTHORITY, |
| cEscapePrefix, |
| eCharset, |
| false); |
| } |
| if (aSynAuthority.getLength() == 0) |
| { |
| setInvalid(); |
| return false; |
| } |
| m_aHost.set(aSynAbsURIRef, |
| aSynAuthority.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| // misusing m_aHost to store the authority |
| } |
| break; |
| } |
| |
| case INET_PROT_VND_SUN_STAR_PKG: |
| { |
| if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '/') |
| { |
| setInvalid(); |
| return false; |
| } |
| aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| rtl::OUStringBuffer aSynAuthority; |
| while (pPos < pEnd |
| && *pPos != '/' && *pPos != '?' |
| && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| cEscapePrefix, eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aSynAuthority, nUTF32, eEscapeType, bOctets, |
| PART_AUTHORITY, cEscapePrefix, eCharset, |
| false); |
| } |
| if (aSynAuthority.getLength() == 0) |
| { |
| setInvalid(); |
| return false; |
| } |
| m_aHost.set(aSynAbsURIRef, |
| aSynAuthority.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| // misusing m_aHost to store the authority |
| break; |
| } |
| |
| case INET_PROT_FILE: |
| if (bSmart) |
| { |
| // The first of the following seven productions that |
| // matches the rest of the input string (and for which the |
| // appropriate style bit is set in eStyle, if applicable) |
| // determines the used notation. The productions use the |
| // auxiliary rules |
| // |
| // domain = label *("." label) |
| // label = alphanum [*(alphanum / "-") alphanum] |
| // alphanum = ALPHA / DIGIT |
| // IPv6reference = "[" IPv6address "]" |
| // IPv6address = hexpart [":" IPv4address] |
| // IPv4address = 1*3DIGIT 3("." 1*3DIGIT) |
| // hexpart = (hexseq ["::" [hexseq]]) / ("::" [hexseq]) |
| // hexseq = hex4 *(":" hex4) |
| // hex4 = 1*4HEXDIG |
| // path = <any UCS4 character except "#"> |
| // UCS4 = <any UCS4 character> |
| |
| // 1st Production (URL): |
| // "//" [domain / IPv6reference] ["/" *path] |
| // ["#" *UCS4] |
| // becomes |
| // "file://" domain "/" *path ["#" *UCS4] |
| if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') |
| { |
| sal_Unicode const * p1 = pPos + 2; |
| while (p1 != pEnd && *p1 != '/' && |
| *p1 != nFragmentDelimiter) |
| { |
| ++p1; |
| } |
| if (parseHostOrNetBiosName( |
| pPos + 2, p1, bOctets, ENCODE_ALL, |
| RTL_TEXTENCODING_DONTKNOW, true, NULL)) |
| { |
| aSynAbsURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| pHostPortBegin = pPos + 2; |
| pHostPortEnd = p1; |
| pPos = p1; |
| break; |
| } |
| } |
| |
| // 2nd Production (MS IE generated 1; FSYS_DOS only): |
| // "//" ALPHA ":" ["/" *path] ["#" *UCS4] |
| // becomes |
| // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] |
| // replacing "\" by "/" within <*path> |
| // |
| // 3rd Production (MS IE generated 2; FSYS_DOS only): |
| // "//" ALPHA ":" ["\" *path] ["#" *UCS4] |
| // becomes |
| // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] |
| // replacing "\" by "/" within <*path> |
| // |
| // 4th Production (misscounted slashes): |
| // "//" *path ["#" *UCS4] |
| // becomes |
| // "file:///" *path ["#" *UCS4] |
| if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') |
| { |
| aSynAbsURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| pPos += 2; |
| bSkippedInitialSlash = true; |
| if ((eStyle & FSYS_DOS) != 0 |
| && pEnd - pPos >= 2 |
| && INetMIME::isAlpha(pPos[0]) |
| && pPos[1] == ':' |
| && (pEnd - pPos == 2 |
| || pPos[2] == '/' || pPos[2] == '\\')) |
| nAltSegmentDelimiter = '\\'; |
| break; |
| } |
| |
| // 5th Production (Unix): |
| // "/" *path ["#" *UCS4] |
| // becomes |
| // "file:///" *path ["#" *UCS4] |
| if (pPos < pEnd && *pPos == '/') |
| { |
| aSynAbsURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| break; |
| } |
| |
| // 6th Production (UNC; FSYS_DOS only): |
| // "\\" domain ["\" *path] ["#" *UCS4] |
| // becomes |
| // "file://" domain "/" *path ["#" *UCS4] |
| // replacing "\" by "/" within <*path> |
| if (eStyle & FSYS_DOS |
| && pEnd - pPos >= 2 |
| && pPos[0] == '\\' |
| && pPos[1] == '\\') |
| { |
| sal_Unicode const * p1 = pPos + 2; |
| sal_Unicode const * pe = p1; |
| while (pe < pEnd && *pe != '\\' && |
| *pe != nFragmentDelimiter) |
| { |
| ++pe; |
| } |
| if ( |
| parseHostOrNetBiosName( |
| p1, pe, bOctets, ENCODE_ALL, |
| RTL_TEXTENCODING_DONTKNOW, true, NULL) || |
| (scanDomain(p1, pe) > 0 && p1 == pe) |
| ) |
| { |
| aSynAbsURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| pHostPortBegin = pPos + 2; |
| pHostPortEnd = pe; |
| pPos = pe; |
| nSegmentDelimiter = '\\'; |
| break; |
| } |
| } |
| |
| // 7th Production (Unix-like DOS; FSYS_DOS only): |
| // ALPHA ":" ["/" *path] ["#" *UCS4] |
| // becomes |
| // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] |
| // replacing "\" by "/" within <*path> |
| // |
| // 8th Production (DOS; FSYS_DOS only): |
| // ALPHA ":" ["\" *path] ["#" *UCS4] |
| // becomes |
| // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] |
| // replacing "\" by "/" within <*path> |
| if (eStyle & FSYS_DOS |
| && pEnd - pPos >= 2 |
| && INetMIME::isAlpha(pPos[0]) |
| && pPos[1] == ':' |
| && (pEnd - pPos == 2 |
| || pPos[2] == '/' |
| || pPos[2] == '\\')) |
| { |
| aSynAbsURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| nAltSegmentDelimiter = '\\'; |
| bSkippedInitialSlash = true; |
| break; |
| } |
| |
| // 9th Production (any): |
| // *path ["#" *UCS4] |
| // becomes |
| // "file:///" *path ["#" *UCS4] |
| // replacing the delimiter by "/" within <*path>. The |
| // delimiter is that character from the set { "/", "\", |
| // ":" } which appears most often in <*path> (if FSYS_UNX |
| // is not among the style bits, "/" is removed from the |
| // set; if FSYS_DOS is not among the style bits, "\" is |
| // removed from the set; if FSYS_MAC is not among the |
| // style bits, ":" is removed from the set). If two or |
| // more characters appear the same number of times, the |
| // character mentioned first in that set is chosen. If |
| // the first character of <*path> is the delimiter, that |
| // character is not copied. |
| if (eStyle & (FSYS_UNX | FSYS_DOS | FSYS_MAC)) |
| { |
| aSynAbsURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| switch (guessFSysStyleByCounting(pPos, pEnd, eStyle)) |
| { |
| case FSYS_UNX: |
| nSegmentDelimiter = '/'; |
| break; |
| |
| case FSYS_DOS: |
| nSegmentDelimiter = '\\'; |
| break; |
| |
| case FSYS_MAC: |
| nSegmentDelimiter = ':'; |
| break; |
| |
| default: |
| DBG_ERROR( |
| "INetURLObject::setAbsURIRef():" |
| " Bad guessFSysStyleByCounting"); |
| break; |
| } |
| bSkippedInitialSlash |
| = pPos != pEnd && *pPos != nSegmentDelimiter; |
| break; |
| } |
| } |
| default: |
| { |
| // For INET_PROT_FILE, allow an empty authority ("//") to be |
| // missing if the following path starts with an explicit "/" |
| // (Java is notorious in generating such file URLs, so be |
| // liberal here): |
| if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') |
| pPos += 2; |
| else if (!bSmart |
| && !(m_eScheme == INET_PROT_FILE |
| && pPos != pEnd && *pPos == '/')) |
| { |
| setInvalid(); |
| return false; |
| } |
| aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| |
| sal_Unicode const * pAuthority = pPos; |
| sal_uInt32 c = getSchemeInfo().m_bQuery ? '?' : 0x80000000; |
| while (pPos < pEnd && *pPos != '/' && *pPos != c |
| && *pPos != nFragmentDelimiter) |
| ++pPos; |
| if (getSchemeInfo().m_bUser) |
| if (getSchemeInfo().m_bHost) |
| { |
| sal_Unicode const * p1 = pAuthority; |
| while (p1 < pPos && *p1 != '@') |
| ++p1; |
| if (p1 == pPos) |
| { |
| pHostPortBegin = pAuthority; |
| pHostPortEnd = pPos; |
| } |
| else |
| { |
| pUserInfoBegin = pAuthority; |
| pUserInfoEnd = p1; |
| pHostPortBegin = p1 + 1; |
| pHostPortEnd = pPos; |
| } |
| } |
| else |
| { |
| pUserInfoBegin = pAuthority; |
| pUserInfoEnd = pPos; |
| } |
| else if (getSchemeInfo().m_bHost) |
| { |
| pHostPortBegin = pAuthority; |
| pHostPortEnd = pPos; |
| } |
| else if (pPos != pAuthority) |
| { |
| setInvalid(); |
| return false; |
| } |
| break; |
| } |
| } |
| |
| if (pUserInfoBegin) |
| { |
| Part ePart = m_eScheme == INET_PROT_IMAP ? |
| PART_IMAP_ACHAR : |
| m_eScheme == INET_PROT_VIM ? |
| PART_VIM : |
| PART_USER_PASSWORD; |
| bool bSupportsPassword = getSchemeInfo().m_bPassword; |
| bool bSupportsAuth |
| = !bSupportsPassword && getSchemeInfo().m_bAuth; |
| bool bHasAuth = false; |
| rtl::OUStringBuffer aSynUser; |
| sal_Unicode const * p1 = pUserInfoBegin; |
| while (p1 < pUserInfoEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets, |
| cEscapePrefix, eMechanism, |
| eCharset, eEscapeType); |
| if (eEscapeType == ESCAPE_NO) |
| { |
| if (nUTF32 == ':' && bSupportsPassword) |
| { |
| bHasAuth = true; |
| break; |
| } |
| else if (nUTF32 == ';' && bSupportsAuth |
| && pUserInfoEnd - p1 |
| > RTL_CONSTASCII_LENGTH("auth=") |
| && INetMIME::equalIgnoreCase( |
| p1, |
| p1 + RTL_CONSTASCII_LENGTH("auth="), |
| "auth=")) |
| { |
| p1 += RTL_CONSTASCII_LENGTH("auth="); |
| bHasAuth = true; |
| break; |
| } |
| } |
| appendUCS4(aSynUser, nUTF32, eEscapeType, bOctets, ePart, |
| cEscapePrefix, eCharset, false); |
| } |
| m_aUser.set(aSynAbsURIRef, aSynUser.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| if (bHasAuth) |
| { |
| if (bSupportsPassword) |
| { |
| aSynAbsURIRef.append(sal_Unicode(':')); |
| rtl::OUStringBuffer aSynAuth; |
| while (p1 < pUserInfoEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets, |
| cEscapePrefix, |
| eMechanism, eCharset, |
| eEscapeType); |
| appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets, |
| ePart, cEscapePrefix, eCharset, false); |
| } |
| m_aAuth.set(aSynAbsURIRef, aSynAuth.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| } |
| else |
| { |
| aSynAbsURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM(";AUTH=")); |
| rtl::OUStringBuffer aSynAuth; |
| while (p1 < pUserInfoEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(p1, pUserInfoEnd, bOctets, |
| cEscapePrefix, |
| eMechanism, eCharset, |
| eEscapeType); |
| if (!INetMIME::isIMAPAtomChar(nUTF32)) |
| { |
| setInvalid(); |
| return false; |
| } |
| appendUCS4(aSynAuth, nUTF32, eEscapeType, bOctets, |
| ePart, cEscapePrefix, eCharset, false); |
| } |
| m_aAuth.set(aSynAbsURIRef, aSynAuth.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| } |
| } |
| if (pHostPortBegin) |
| aSynAbsURIRef.append(sal_Unicode('@')); |
| } |
| |
| if (pHostPortBegin) |
| { |
| sal_Unicode const * pPort = pHostPortEnd; |
| if ( getSchemeInfo().m_bPort && pHostPortBegin < pHostPortEnd ) |
| { |
| sal_Unicode const * p1 = pHostPortEnd - 1; |
| while (p1 > pHostPortBegin && INetMIME::isDigit(*p1)) |
| --p1; |
| if (*p1 == ':') |
| pPort = p1; |
| } |
| bool bNetBiosName = false; |
| switch (m_eScheme) |
| { |
| case INET_PROT_FILE: |
| // If the host equals "LOCALHOST" (unencoded and ignoring |
| // case), turn it into an empty host: |
| if (INetMIME::equalIgnoreCase(pHostPortBegin, pPort, |
| "localhost")) |
| pHostPortBegin = pPort; |
| bNetBiosName = true; |
| break; |
| |
| case INET_PROT_LDAP: |
| case INET_PROT_SMB: |
| if (pHostPortBegin == pPort && pPort != pHostPortEnd) |
| { |
| setInvalid(); |
| return false; |
| } |
| break; |
| default: |
| if (pHostPortBegin == pPort) |
| { |
| setInvalid(); |
| return false; |
| } |
| break; |
| } |
| rtl::OUStringBuffer aSynHost; |
| if (!parseHostOrNetBiosName( |
| pHostPortBegin, pPort, bOctets, eMechanism, eCharset, |
| bNetBiosName, &aSynHost)) |
| { |
| setInvalid(); |
| return false; |
| } |
| m_aHost.set(aSynAbsURIRef, aSynHost.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| if (pPort != pHostPortEnd) |
| { |
| aSynAbsURIRef.append(sal_Unicode(':')); |
| m_aPort.set(aSynAbsURIRef, |
| rtl::OUString(pPort + 1, pHostPortEnd - (pPort + 1)), |
| aSynAbsURIRef.getLength()); |
| } |
| } |
| } |
| |
| // Parse <path> |
| rtl::OUStringBuffer aSynPath; |
| if (!parsePath(m_eScheme, &pPos, pEnd, bOctets, eMechanism, eCharset, |
| bSkippedInitialSlash, nSegmentDelimiter, |
| nAltSegmentDelimiter, |
| getSchemeInfo().m_bQuery ? '?' : 0x80000000, |
| nFragmentDelimiter, aSynPath)) |
| { |
| setInvalid(); |
| return false; |
| } |
| m_aPath.set(aSynAbsURIRef, aSynPath.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| |
| // Parse ?<query> |
| if (getSchemeInfo().m_bQuery && pPos < pEnd && *pPos == '?') |
| { |
| aSynAbsURIRef.append(sal_Unicode('?')); |
| rtl::OUStringBuffer aSynQuery; |
| for (++pPos; pPos < pEnd && *pPos != nFragmentDelimiter;) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, cEscapePrefix, |
| eMechanism, eCharset, eEscapeType); |
| appendUCS4(aSynQuery, nUTF32, eEscapeType, bOctets, |
| PART_URIC, cEscapePrefix, eCharset, true); |
| } |
| m_aQuery.set(aSynAbsURIRef, aSynQuery.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| } |
| |
| // Parse #<fragment> |
| if (pPos < pEnd && *pPos == nFragmentDelimiter) |
| { |
| aSynAbsURIRef.append(sal_Unicode(nFragmentDelimiter)); |
| rtl::OUStringBuffer aSynFragment; |
| for (++pPos; pPos < pEnd;) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, cEscapePrefix, |
| eMechanism, eCharset, eEscapeType); |
| appendUCS4(aSynFragment, nUTF32, eEscapeType, bOctets, PART_URIC, |
| cEscapePrefix, eCharset, true); |
| } |
| m_aFragment.set(aSynAbsURIRef, aSynFragment.makeStringAndClear(), |
| aSynAbsURIRef.getLength()); |
| } |
| |
| if (pPos != pEnd) |
| { |
| setInvalid(); |
| return false; |
| } |
| |
| m_aAbsURIRef = aSynAbsURIRef; |
| |
| return true; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::convertRelToAbs(rtl::OUString const & rTheRelURIRef, |
| bool bOctets, |
| INetURLObject & rTheAbsURIRef, |
| bool & rWasAbsolute, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset, |
| bool bIgnoreFragment, bool bSmart, |
| bool bRelativeNonURIs, FSysStyle eStyle) |
| const |
| { |
| sal_Unicode const * p = rTheRelURIRef.getStr(); |
| sal_Unicode const * pEnd = p + rTheRelURIRef.getLength(); |
| |
| sal_Unicode const * pPrefixBegin = p; |
| PrefixInfo const * pPrefix = getPrefix(pPrefixBegin, pEnd); |
| bool hasScheme = pPrefix != 0; |
| if (!hasScheme) { |
| pPrefixBegin = p; |
| hasScheme = parseScheme(&pPrefixBegin, pEnd, '#').getLength() > 0; |
| } |
| |
| sal_uInt32 nSegmentDelimiter = '/'; |
| sal_uInt32 nQueryDelimiter |
| = !bSmart || getSchemeInfo().m_bQuery ? '?' : 0x80000000; |
| sal_uInt32 nFragmentDelimiter = '#'; |
| Part ePart = PART_VISIBLE; |
| |
| if (!hasScheme && bSmart) |
| { |
| // If the input matches any of the following productions (for which |
| // the appropriate style bit is set in eStyle), it is assumed to be an |
| // absolute file system path, rather than a relative URI reference. |
| // (This is only a subset of the productions used for scheme detection |
| // in INetURLObject::setAbsURIRef(), because most of those productions |
| // interfere with the syntax of relative URI references.) The |
| // productions use the auxiliary rules |
| // |
| // domain = label *("." label) |
| // label = alphanum [*(alphanum / "-") alphanum] |
| // alphanum = ALPHA / DIGIT |
| // UCS4 = <any UCS4 character> |
| // |
| // 1st Production (UNC file; FSYS_DOS only): |
| // "\\" domain ["\" *UCS4] |
| // |
| // 2nd Production (Unix-like DOS file; FSYS_DOS only): |
| // ALPHA ":" ["/" *UCS4] |
| // |
| // 3rd Production (DOS file; FSYS_DOS only): |
| // ALPHA ":" ["\" *UCS4] |
| if (eStyle & FSYS_DOS) |
| { |
| bool bFSys = false; |
| sal_Unicode const * q = p; |
| if (pEnd - q >= 2 |
| && INetMIME::isAlpha(q[0]) |
| && q[1] == ':' |
| && (pEnd - q == 2 || q[2] == '/' || q[2] == '\\')) |
| bFSys = true; // 2nd, 3rd |
| else if (pEnd - q >= 2 && q[0] == '\\' && q[1] == '\\') |
| { |
| q += 2; |
| sal_Int32 n = rtl_ustr_indexOfChar_WithLength( |
| q, pEnd - q, '\\'); |
| sal_Unicode const * qe = n == -1 ? pEnd : q + n; |
| if (parseHostOrNetBiosName( |
| q, qe, bOctets, ENCODE_ALL, RTL_TEXTENCODING_DONTKNOW, |
| true, NULL)) |
| { |
| bFSys = true; // 1st |
| } |
| } |
| if (bFSys) |
| { |
| INetURLObject aNewURI; |
| aNewURI.setAbsURIRef(rTheRelURIRef, bOctets, eMechanism, |
| eCharset, true, eStyle); |
| if (!aNewURI.HasError()) |
| { |
| rTheAbsURIRef = aNewURI; |
| rWasAbsolute = true; |
| return true; |
| } |
| } |
| } |
| |
| // When the base URL is a file URL, accept relative file system paths |
| // using "\" or ":" as delimiter (and ignoring URI conventions for "%" |
| // and "#"), as well as relative URIs using "/" as delimiter: |
| if (m_eScheme == INET_PROT_FILE) |
| switch (guessFSysStyleByCounting(p, pEnd, eStyle)) |
| { |
| case FSYS_UNX: |
| nSegmentDelimiter = '/'; |
| break; |
| |
| case FSYS_DOS: |
| nSegmentDelimiter = '\\'; |
| bRelativeNonURIs = true; |
| break; |
| |
| case FSYS_MAC: |
| nSegmentDelimiter = ':'; |
| bRelativeNonURIs = true; |
| break; |
| |
| default: |
| DBG_ERROR("INetURLObject::convertRelToAbs():" |
| " Bad guessFSysStyleByCounting"); |
| break; |
| } |
| |
| if (bRelativeNonURIs) |
| { |
| eMechanism = ENCODE_ALL; |
| nQueryDelimiter = 0x80000000; |
| nFragmentDelimiter = 0x80000000; |
| ePart = PART_VISIBLE_NONSPECIAL; |
| } |
| } |
| |
| // If the relative URI has the same scheme as the base URI, and that |
| // scheme is hierarchical, then ignore its presence in the relative |
| // URI in order to be backward compatible (cf. RFC 2396 section 5.2 |
| // step 3): |
| if (pPrefix && pPrefix->m_eScheme == m_eScheme |
| && getSchemeInfo().m_bHierarchical) |
| { |
| hasScheme = false; |
| while (p != pEnd && *p++ != ':') ; |
| } |
| rWasAbsolute = hasScheme; |
| |
| // Fast solution for non-relative URIs: |
| if (hasScheme) |
| { |
| INetURLObject aNewURI(rTheRelURIRef, eMechanism, eCharset); |
| if (aNewURI.HasError()) |
| { |
| rWasAbsolute = false; |
| return false; |
| } |
| |
| if (bIgnoreFragment) |
| aNewURI.clearFragment(); |
| rTheAbsURIRef = aNewURI; |
| return true; |
| } |
| |
| enum State { STATE_AUTH, STATE_ABS_PATH, STATE_REL_PATH, STATE_FRAGMENT, |
| STATE_DONE }; |
| |
| rtl::OUStringBuffer aSynAbsURIRef; |
| // make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme |
| // is empty ("") in that case, so take the scheme from m_aAbsURIRef |
| if (m_eScheme != INET_PROT_GENERIC) |
| { |
| aSynAbsURIRef.appendAscii(getSchemeInfo().m_pScheme); |
| } |
| else |
| { |
| sal_Unicode const * pSchemeBegin |
| = m_aAbsURIRef.getStr(); |
| sal_Unicode const * pSchemeEnd = pSchemeBegin; |
| while (pSchemeEnd[0] != ':') |
| { |
| ++pSchemeEnd; |
| } |
| aSynAbsURIRef.append(pSchemeBegin, pSchemeEnd - pSchemeBegin); |
| } |
| aSynAbsURIRef.append(sal_Unicode(':')); |
| |
| sal_Char cEscapePrefix = getEscapePrefix(); |
| |
| State eState = STATE_AUTH; |
| bool bSameDoc = true; |
| |
| if (getSchemeInfo().m_bAuthority) |
| { |
| if (pEnd - p >= 2 && p[0] == '/' && p[1] == '/') |
| { |
| aSynAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| p += 2; |
| eState = STATE_ABS_PATH; |
| bSameDoc = false; |
| while (p != pEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 |
| = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, |
| eCharset, eEscapeType); |
| if (eEscapeType == ESCAPE_NO) |
| { |
| if (nUTF32 == nSegmentDelimiter) |
| break; |
| else if (nUTF32 == nFragmentDelimiter) |
| { |
| eState = STATE_FRAGMENT; |
| break; |
| } |
| } |
| appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, |
| PART_VISIBLE, cEscapePrefix, eCharset, true); |
| } |
| } |
| else |
| { |
| SubString aAuthority(getAuthority()); |
| aSynAbsURIRef.append(m_aAbsURIRef.getStr() |
| + aAuthority.getBegin(), |
| aAuthority.getLength()); |
| } |
| } |
| |
| if (eState == STATE_AUTH) |
| { |
| if (p == pEnd) |
| eState = STATE_DONE; |
| else if (*p == nFragmentDelimiter) |
| { |
| ++p; |
| eState = STATE_FRAGMENT; |
| } |
| else if (*p == nSegmentDelimiter) |
| { |
| ++p; |
| eState = STATE_ABS_PATH; |
| bSameDoc = false; |
| } |
| else |
| { |
| eState = STATE_REL_PATH; |
| bSameDoc = false; |
| } |
| } |
| |
| if (eState == STATE_ABS_PATH) |
| { |
| aSynAbsURIRef.append(sal_Unicode('/')); |
| eState = STATE_DONE; |
| while (p != pEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 |
| = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, |
| eCharset, eEscapeType); |
| if (eEscapeType == ESCAPE_NO) |
| { |
| if (nUTF32 == nFragmentDelimiter) |
| { |
| eState = STATE_FRAGMENT; |
| break; |
| } |
| else if (nUTF32 == nSegmentDelimiter) |
| nUTF32 = '/'; |
| } |
| appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart, |
| cEscapePrefix, eCharset, true); |
| } |
| } |
| else if (eState == STATE_REL_PATH) |
| { |
| if (!getSchemeInfo().m_bHierarchical) |
| { |
| // Detect cases where a relative input could not be made absolute |
| // because the given base URL is broken (most probably because it is |
| // empty): |
| OSL_ASSERT(!HasError()); |
| rWasAbsolute = false; |
| return false; |
| } |
| |
| sal_Unicode const * pBasePathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pBasePathEnd |
| = pBasePathBegin + m_aPath.getLength(); |
| while (pBasePathEnd != pBasePathBegin) |
| if (*(--pBasePathEnd) == '/') |
| { |
| ++pBasePathEnd; |
| break; |
| } |
| |
| sal_Int32 nPathBegin = aSynAbsURIRef.getLength(); |
| aSynAbsURIRef.append(pBasePathBegin, pBasePathEnd - pBasePathBegin); |
| DBG_ASSERT(aSynAbsURIRef.getLength() > nPathBegin |
| && aSynAbsURIRef.charAt(aSynAbsURIRef.getLength() - 1) == '/', |
| "INetURLObject::convertRelToAbs(): Bad base path"); |
| |
| while (p != pEnd && *p != nQueryDelimiter && *p != nFragmentDelimiter) |
| { |
| if (*p == '.') |
| { |
| if (pEnd - p == 1 |
| || p[1] == nSegmentDelimiter |
| || p[1] == nQueryDelimiter |
| || p[1] == nFragmentDelimiter) |
| { |
| ++p; |
| if (p != pEnd && *p == nSegmentDelimiter) |
| ++p; |
| continue; |
| } |
| else if (pEnd - p >= 2 |
| && p[1] == '.' |
| && (pEnd - p == 2 |
| || p[2] == nSegmentDelimiter |
| || p[2] == nQueryDelimiter |
| || p[2] == nFragmentDelimiter) |
| && aSynAbsURIRef.getLength() - nPathBegin > 1) |
| { |
| p += 2; |
| if (p != pEnd && *p == nSegmentDelimiter) |
| ++p; |
| |
| sal_Int32 i = aSynAbsURIRef.getLength() - 2; |
| while (i > nPathBegin && aSynAbsURIRef.charAt(i) != '/') |
| --i; |
| aSynAbsURIRef.setLength(i + 1); |
| DBG_ASSERT( |
| aSynAbsURIRef.getLength() > nPathBegin |
| && aSynAbsURIRef.charAt(aSynAbsURIRef.getLength() - 1) |
| == '/', |
| "INetURLObject::convertRelToAbs(): Bad base path"); |
| continue; |
| } |
| } |
| |
| while (p != pEnd |
| && *p != nSegmentDelimiter |
| && *p != nQueryDelimiter |
| && *p != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 |
| = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart, |
| cEscapePrefix, eCharset, true); |
| } |
| if (p != pEnd && *p == nSegmentDelimiter) |
| { |
| aSynAbsURIRef.append(sal_Unicode('/')); |
| ++p; |
| } |
| } |
| |
| while (p != pEnd && *p != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 |
| = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, ePart, |
| cEscapePrefix, eCharset, true); |
| } |
| |
| if (p == pEnd) |
| eState = STATE_DONE; |
| else |
| { |
| ++p; |
| eState = STATE_FRAGMENT; |
| } |
| } |
| else if (bSameDoc) |
| { |
| aSynAbsURIRef.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(), |
| m_aPath.getLength()); |
| if (m_aQuery.isPresent()) |
| aSynAbsURIRef.append(m_aAbsURIRef.getStr() |
| + m_aQuery.getBegin() - 1, |
| m_aQuery.getLength() + 1); |
| } |
| |
| if (eState == STATE_FRAGMENT && !bIgnoreFragment) |
| { |
| aSynAbsURIRef.append(sal_Unicode('#')); |
| while (p != pEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 |
| = getUTF32(p, pEnd, bOctets, cEscapePrefix, eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aSynAbsURIRef, nUTF32, eEscapeType, bOctets, |
| PART_VISIBLE, cEscapePrefix, eCharset, true); |
| } |
| } |
| |
| INetURLObject aNewURI(aSynAbsURIRef.makeStringAndClear()); |
| if (aNewURI.HasError()) |
| { |
| // Detect cases where a relative input could not be made absolute |
| // because the given base URL is broken (most probably because it is |
| // empty): |
| OSL_ASSERT(!HasError()); |
| rWasAbsolute = false; |
| return false; |
| } |
| |
| rTheAbsURIRef = aNewURI; |
| return true; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::convertAbsToRel(rtl::OUString const & rTheAbsURIRef, |
| bool bOctets, rtl::OUString & rTheRelURIRef, |
| EncodeMechanism eEncodeMechanism, |
| DecodeMechanism eDecodeMechanism, |
| rtl_TextEncoding eCharset, |
| FSysStyle eStyle) const |
| { |
| // Check for hierarchical base URL: |
| if (!getSchemeInfo().m_bHierarchical) |
| { |
| rTheRelURIRef |
| = decode(rTheAbsURIRef, |
| getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)), |
| eDecodeMechanism, eCharset); |
| return false; |
| } |
| |
| // Convert the input (absolute or relative URI ref) to an absolute URI |
| // ref: |
| INetURLObject aSubject; |
| bool bWasAbsolute; |
| if (!convertRelToAbs(rTheAbsURIRef, bOctets, aSubject, bWasAbsolute, |
| eEncodeMechanism, eCharset, false, false, false, |
| eStyle)) |
| { |
| rTheRelURIRef |
| = decode(rTheAbsURIRef, |
| getEscapePrefix(CompareProtocolScheme(rTheAbsURIRef)), |
| eDecodeMechanism, eCharset); |
| return false; |
| } |
| |
| // Check for differing scheme or authority parts: |
| if ((m_aScheme.compare( |
| aSubject.m_aScheme, m_aAbsURIRef, aSubject.m_aAbsURIRef) |
| != 0) |
| || (m_aUser.compare( |
| aSubject.m_aUser, m_aAbsURIRef, aSubject.m_aAbsURIRef) |
| != 0) |
| || (m_aAuth.compare( |
| aSubject.m_aAuth, m_aAbsURIRef, aSubject.m_aAbsURIRef) |
| != 0) |
| || (m_aHost.compare( |
| aSubject.m_aHost, m_aAbsURIRef, aSubject.m_aAbsURIRef) |
| != 0) |
| || (m_aPort.compare( |
| aSubject.m_aPort, m_aAbsURIRef, aSubject.m_aAbsURIRef) |
| != 0)) |
| { |
| rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset); |
| return false; |
| } |
| |
| sal_Unicode const * pBasePathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pBasePathEnd = pBasePathBegin + m_aPath.getLength(); |
| sal_Unicode const * pSubjectPathBegin |
| = aSubject.m_aAbsURIRef.getStr() + aSubject.m_aPath.getBegin(); |
| sal_Unicode const * pSubjectPathEnd |
| = pSubjectPathBegin + aSubject.m_aPath.getLength(); |
| |
| // Make nMatch point past the last matching slash, or past the end of the |
| // paths, in case they are equal: |
| sal_Unicode const * pSlash = 0; |
| sal_Unicode const * p1 = pBasePathBegin; |
| sal_Unicode const * p2 = pSubjectPathBegin; |
| for (;;) |
| { |
| if (p1 == pBasePathEnd || p2 == pSubjectPathEnd) |
| { |
| if (p1 == pBasePathEnd && p2 == pSubjectPathEnd) |
| pSlash = p1; |
| break; |
| } |
| |
| sal_Unicode c = *p1++; |
| if (c != *p2++) |
| break; |
| if (c == '/') |
| pSlash = p1; |
| } |
| if (!pSlash) |
| { |
| // One of the paths does not start with '/': |
| rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset); |
| return false; |
| } |
| sal_Int32 nMatch = pSlash - pBasePathBegin; |
| |
| // If the two URLs are DOS file URLs starting with different volumes |
| // (e.g., file:///a:/... and file:///b:/...), the subject is not made |
| // relative (it could be, but some people do not like that): |
| if (m_eScheme == INET_PROT_FILE |
| && nMatch <= 1 |
| && hasDosVolume(eStyle) |
| && aSubject.hasDosVolume(eStyle)) //TODO! ok to use eStyle for these? |
| { |
| rTheRelURIRef = aSubject.GetMainURL(eDecodeMechanism, eCharset); |
| return false; |
| } |
| |
| // For every slash in the base path after nMatch, a prefix of "../" is |
| // added to the new relative URL (if the common prefix of the two paths is |
| // only "/"---but see handling of file URLs above---, the complete subject |
| // path could go into the new relative URL instead, but some people don't |
| // like that): |
| rtl::OUStringBuffer aSynRelURIRef; |
| // if (nMatch <= 1) nMatch = 0; else // see comment above |
| for (sal_Unicode const * p = pBasePathBegin + nMatch; p != pBasePathEnd; |
| ++p) |
| { |
| if (*p == '/') |
| aSynRelURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("../")); |
| } |
| |
| // If the new relative URL would start with "//" (i.e., it would be |
| // mistaken for a relative URL starting with an authority part), or if the |
| // new relative URL would neither be empty nor start with <"/"> nor start |
| // with <1*rseg> (i.e., it could be mistaken for an absolute URL starting |
| // with a scheme part), then the new relative URL is prefixed with "./": |
| if (aSynRelURIRef.getLength() == 0) |
| { |
| if (pSubjectPathEnd - pSubjectPathBegin >= nMatch + 2 |
| && pSubjectPathBegin[nMatch] == '/' |
| && pSubjectPathBegin[nMatch + 1] == '/') |
| { |
| aSynRelURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("./")); |
| } |
| else |
| { |
| for (sal_Unicode const * p = pSubjectPathBegin + nMatch; |
| p != pSubjectPathEnd && *p != '/'; ++p) |
| { |
| if (mustEncode(*p, PART_REL_SEGMENT_EXTRA)) |
| { |
| aSynRelURIRef. |
| appendAscii(RTL_CONSTASCII_STRINGPARAM("./")); |
| break; |
| } |
| } |
| } |
| } |
| |
| // The remainder of the subject path, starting at nMatch, is appended to |
| // the new relative URL: |
| sal_Char cEscapePrefix = getEscapePrefix(); |
| aSynRelURIRef.append(decode(pSubjectPathBegin + nMatch, pSubjectPathEnd, |
| cEscapePrefix, eDecodeMechanism, eCharset)); |
| |
| // If the subject has defined query or fragment parts, they are appended |
| // to the new relative URL: |
| if (aSubject.m_aQuery.isPresent()) |
| { |
| aSynRelURIRef.append(sal_Unicode('?')); |
| aSynRelURIRef.append(aSubject.decode(aSubject.m_aQuery, cEscapePrefix, |
| eDecodeMechanism, eCharset)); |
| } |
| if (aSubject.m_aFragment.isPresent()) |
| { |
| aSynRelURIRef.append(sal_Unicode('#')); |
| aSynRelURIRef.append(aSubject.decode(aSubject.m_aFragment, |
| cEscapePrefix, eDecodeMechanism, eCharset)); |
| } |
| |
| rTheRelURIRef = aSynRelURIRef.makeStringAndClear(); |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetURLObject::convertIntToExt(rtl::OUString const & rTheIntURIRef, |
| bool bOctets, rtl::OUString & rTheExtURIRef, |
| DecodeMechanism eDecodeMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| sal_Char cEscapePrefix |
| = getEscapePrefix(CompareProtocolScheme(rTheIntURIRef)); |
| rtl::OUString aSynExtURIRef(encodeText(rTheIntURIRef, bOctets, PART_VISIBLE, |
| cEscapePrefix, NOT_CANONIC, eCharset, |
| true)); |
| sal_Unicode const * pBegin = aSynExtURIRef.getStr(); |
| sal_Unicode const * pEnd = pBegin + aSynExtURIRef.getLength(); |
| sal_Unicode const * p = pBegin; |
| PrefixInfo const * pPrefix = getPrefix(p, pEnd); |
| bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::INTERNAL; |
| if (bConvert) |
| { |
| aSynExtURIRef = |
| aSynExtURIRef.replaceAt(0, p - pBegin, |
| rtl::OUString::createFromAscii(pPrefix->m_pTranslatedPrefix)); |
| } |
| rTheExtURIRef = decode(aSynExtURIRef, cEscapePrefix, eDecodeMechanism, |
| eCharset); |
| return bConvert; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetURLObject::convertExtToInt(rtl::OUString const & rTheExtURIRef, |
| bool bOctets, rtl::OUString & rTheIntURIRef, |
| DecodeMechanism eDecodeMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| sal_Char cEscapePrefix |
| = getEscapePrefix(CompareProtocolScheme(rTheExtURIRef)); |
| rtl::OUString aSynIntURIRef(encodeText(rTheExtURIRef, bOctets, PART_VISIBLE, |
| cEscapePrefix, NOT_CANONIC, eCharset, |
| true)); |
| sal_Unicode const * pBegin = aSynIntURIRef.getStr(); |
| sal_Unicode const * pEnd = pBegin + aSynIntURIRef.getLength(); |
| sal_Unicode const * p = pBegin; |
| PrefixInfo const * pPrefix = getPrefix(p, pEnd); |
| bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::EXTERNAL; |
| if (bConvert) |
| { |
| aSynIntURIRef = |
| aSynIntURIRef.replaceAt(0, p - pBegin, |
| rtl::OUString::createFromAscii(pPrefix->m_pTranslatedPrefix)); |
| } |
| rTheIntURIRef = decode(aSynIntURIRef, cEscapePrefix, eDecodeMechanism, |
| eCharset); |
| return bConvert; |
| } |
| |
| //============================================================================ |
| // static |
| INetURLObject::PrefixInfo const * |
| INetURLObject::getPrefix(sal_Unicode const *& rBegin, |
| sal_Unicode const * pEnd) |
| { |
| static PrefixInfo const aMap[] |
| = { // dummy entry at front needed, because pLast may point here: |
| { 0, 0, INET_PROT_NOT_VALID, PrefixInfo::INTERNAL }, |
| { ".component:", "staroffice.component:", INET_PROT_COMPONENT, |
| PrefixInfo::INTERNAL }, |
| { ".uno:", "staroffice.uno:", INET_PROT_UNO, |
| PrefixInfo::INTERNAL }, |
| { "cid:", 0, INET_PROT_CID, PrefixInfo::OFFICIAL }, |
| { "data:", 0, INET_PROT_DATA, PrefixInfo::OFFICIAL }, |
| { "db:", "staroffice.db:", INET_PROT_DB, PrefixInfo::INTERNAL }, |
| { "file:", 0, INET_PROT_FILE, PrefixInfo::OFFICIAL }, |
| { "ftp:", 0, INET_PROT_FTP, PrefixInfo::OFFICIAL }, |
| { "hid:", "staroffice.hid:", INET_PROT_HID, |
| PrefixInfo::INTERNAL }, |
| { "http:", 0, INET_PROT_HTTP, PrefixInfo::OFFICIAL }, |
| { "https:", 0, INET_PROT_HTTPS, PrefixInfo::OFFICIAL }, |
| { "imap:", 0, INET_PROT_IMAP, PrefixInfo::OFFICIAL }, |
| { "javascript:", 0, INET_PROT_JAVASCRIPT, PrefixInfo::OFFICIAL }, |
| { "ldap:", 0, INET_PROT_LDAP, PrefixInfo::OFFICIAL }, |
| { "macro:", "staroffice.macro:", INET_PROT_MACRO, |
| PrefixInfo::INTERNAL }, |
| { "mailto:", 0, INET_PROT_MAILTO, PrefixInfo::OFFICIAL }, |
| { "news:", 0, INET_PROT_NEWS, PrefixInfo::OFFICIAL }, |
| { "out:", "staroffice.out:", INET_PROT_OUT, |
| PrefixInfo::INTERNAL }, |
| { "pop3:", "staroffice.pop3:", INET_PROT_POP3, |
| PrefixInfo::INTERNAL }, |
| { "private:", "staroffice.private:", INET_PROT_PRIV_SOFFICE, |
| PrefixInfo::INTERNAL }, |
| { "private:factory/", "staroffice.factory:", |
| INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL }, |
| { "private:helpid/", "staroffice.helpid:", INET_PROT_PRIV_SOFFICE, |
| PrefixInfo::INTERNAL }, |
| { "private:java/", "staroffice.java:", INET_PROT_PRIV_SOFFICE, |
| PrefixInfo::INTERNAL }, |
| { "private:searchfolder:", "staroffice.searchfolder:", |
| INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL }, |
| { "private:trashcan:", "staroffice.trashcan:", |
| INET_PROT_PRIV_SOFFICE, PrefixInfo::INTERNAL }, |
| { "slot:", "staroffice.slot:", INET_PROT_SLOT, |
| PrefixInfo::INTERNAL }, |
| { "smb:", 0, INET_PROT_SMB, PrefixInfo::OFFICIAL }, |
| { "staroffice.component:", ".component:", INET_PROT_COMPONENT, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.db:", "db:", INET_PROT_DB, PrefixInfo::EXTERNAL }, |
| { "staroffice.factory:", "private:factory/", |
| INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL }, |
| { "staroffice.helpid:", "private:helpid/", INET_PROT_PRIV_SOFFICE, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.hid:", "hid:", INET_PROT_HID, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.java:", "private:java/", INET_PROT_PRIV_SOFFICE, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.macro:", "macro:", INET_PROT_MACRO, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.out:", "out:", INET_PROT_OUT, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.pop3:", "pop3:", INET_PROT_POP3, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.private:", "private:", INET_PROT_PRIV_SOFFICE, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.searchfolder:", "private:searchfolder:", |
| INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL }, |
| { "staroffice.slot:", "slot:", INET_PROT_SLOT, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.trashcan:", "private:trashcan:", |
| INET_PROT_PRIV_SOFFICE, PrefixInfo::EXTERNAL }, |
| { "staroffice.uno:", ".uno:", INET_PROT_UNO, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice.vim:", "vim:", INET_PROT_VIM, |
| PrefixInfo::EXTERNAL }, |
| { "staroffice:", "private:", INET_PROT_PRIV_SOFFICE, |
| PrefixInfo::EXTERNAL }, |
| { "telnet:", 0, INET_PROT_TELNET, PrefixInfo::OFFICIAL }, |
| { "vim:", "staroffice.vim:", INET_PROT_VIM, |
| PrefixInfo::INTERNAL }, |
| { "vnd.sun.star.cmd:", 0, INET_PROT_VND_SUN_STAR_CMD, |
| PrefixInfo::OFFICIAL }, |
| { "vnd.sun.star.expand:", 0, INET_PROT_VND_SUN_STAR_EXPAND, |
| PrefixInfo::OFFICIAL }, |
| { "vnd.sun.star.help:", 0, INET_PROT_VND_SUN_STAR_HELP, |
| PrefixInfo::OFFICIAL }, |
| { "vnd.sun.star.hier:", 0, INET_PROT_VND_SUN_STAR_HIER, |
| PrefixInfo::OFFICIAL }, |
| { "vnd.sun.star.odma:", 0, INET_PROT_VND_SUN_STAR_ODMA, |
| PrefixInfo::OFFICIAL }, |
| { "vnd.sun.star.pkg:", 0, INET_PROT_VND_SUN_STAR_PKG, |
| PrefixInfo::OFFICIAL }, |
| { "vnd.sun.star.tdoc:", 0, INET_PROT_VND_SUN_STAR_TDOC, |
| PrefixInfo::OFFICIAL }, |
| { "vnd.sun.star.webdav:", 0, INET_PROT_VND_SUN_STAR_WEBDAV, |
| PrefixInfo::OFFICIAL } }; |
| PrefixInfo const * pFirst = aMap + 1; |
| PrefixInfo const * pLast = aMap + sizeof aMap / sizeof (PrefixInfo) - 1; |
| PrefixInfo const * pMatch = 0; |
| sal_Unicode const * pMatched = rBegin; |
| sal_Unicode const * p = rBegin; |
| sal_Int32 i = 0; |
| for (; pFirst < pLast; ++i) |
| { |
| if (pFirst->m_pPrefix[i] == '\0') |
| { |
| pMatch = pFirst++; |
| pMatched = p; |
| } |
| if (p >= pEnd) |
| break; |
| sal_uInt32 nChar = INetMIME::toLowerCase(*p++); |
| while (pFirst <= pLast && sal_uChar(pFirst->m_pPrefix[i]) < nChar) |
| ++pFirst; |
| while (pFirst <= pLast && sal_uChar(pLast->m_pPrefix[i]) > nChar) |
| --pLast; |
| } |
| if (pFirst == pLast) |
| { |
| sal_Char const * q = pFirst->m_pPrefix + i; |
| while (p < pEnd && *q != '\0' |
| && INetMIME::toLowerCase(*p) == sal_uChar(*q)) |
| { |
| ++p; |
| ++q; |
| } |
| if (*q == '\0') |
| { |
| rBegin = p; |
| return pFirst; |
| } |
| } |
| rBegin = pMatched; |
| return pMatch; |
| } |
| |
| //============================================================================ |
| sal_Int32 INetURLObject::getAuthorityBegin() const |
| { |
| DBG_ASSERT(getSchemeInfo().m_bAuthority, |
| "INetURLObject::getAuthority(): Bad scheme"); |
| sal_Int32 nBegin; |
| if (m_aUser.isPresent()) |
| nBegin = m_aUser.getBegin(); |
| else if (m_aHost.isPresent()) |
| nBegin = m_aHost.getBegin(); |
| else |
| nBegin = m_aPath.getBegin(); |
| nBegin -= RTL_CONSTASCII_LENGTH("//"); |
| DBG_ASSERT(m_aAbsURIRef.charAt(nBegin) == '/' |
| && m_aAbsURIRef.charAt(nBegin + 1) == '/', |
| "INetURLObject::getAuthority(): Bad authority"); |
| return nBegin; |
| } |
| |
| //============================================================================ |
| INetURLObject::SubString INetURLObject::getAuthority() const |
| { |
| sal_Int32 nBegin = getAuthorityBegin(); |
| sal_Int32 nEnd = m_aPort.isPresent() ? m_aPort.getEnd() : |
| m_aHost.isPresent() ? m_aHost.getEnd() : |
| m_aAuth.isPresent() ? m_aAuth.getEnd() : |
| m_aUser.isPresent() ? m_aUser.getEnd() : |
| nBegin + RTL_CONSTASCII_LENGTH("//"); |
| return SubString(nBegin, nEnd - nBegin); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setUser(rtl::OUString const & rTheUser, |
| bool bOctets, EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| if ( |
| !getSchemeInfo().m_bUser || |
| (m_eScheme == INET_PROT_IMAP && rTheUser.getLength() == 0) |
| ) |
| { |
| return false; |
| } |
| |
| rtl::OUString aNewUser(encodeText(rTheUser, bOctets, |
| m_eScheme == INET_PROT_IMAP ? |
| PART_IMAP_ACHAR : |
| m_eScheme == INET_PROT_VIM ? |
| PART_VIM : |
| PART_USER_PASSWORD, |
| getEscapePrefix(), eMechanism, eCharset, |
| false)); |
| sal_Int32 nDelta; |
| if (m_aUser.isPresent()) |
| nDelta = m_aUser.set(m_aAbsURIRef, aNewUser); |
| else if (m_aHost.isPresent()) |
| { |
| m_aAbsURIRef.insert(m_aHost.getBegin(), sal_Unicode('@')); |
| nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aHost.getBegin()) + 1; |
| } |
| else if (getSchemeInfo().m_bHost) |
| return false; |
| else |
| nDelta = m_aUser.set(m_aAbsURIRef, aNewUser, m_aPath.getBegin()); |
| m_aAuth += nDelta; |
| m_aHost += nDelta; |
| m_aPort += nDelta; |
| m_aPath += nDelta; |
| m_aQuery += nDelta; |
| m_aFragment += nDelta; |
| return true; |
| } |
| |
| namespace |
| { |
| void lcl_Erase(rtl::OUStringBuffer &rBuf, sal_Int32 index, sal_Int32 count) |
| { |
| rtl::OUString sTemp(rBuf.makeStringAndClear()); |
| rBuf.append(sTemp.replaceAt(index, count, rtl::OUString())); |
| } |
| } |
| |
| //============================================================================ |
| bool INetURLObject::clearPassword() |
| { |
| if (!getSchemeInfo().m_bPassword) |
| return false; |
| if (m_aAuth.isPresent()) |
| { |
| lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin() - 1, |
| m_aAuth.getLength() + 1); |
| sal_Int32 nDelta = m_aAuth.clear() - 1; |
| m_aHost += nDelta; |
| m_aPort += nDelta; |
| m_aPath += nDelta; |
| m_aQuery += nDelta; |
| m_aFragment += nDelta; |
| } |
| return true; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setPassword(rtl::OUString const & rThePassword, |
| bool bOctets, EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| if (!getSchemeInfo().m_bPassword) |
| return false; |
| rtl::OUString aNewAuth(encodeText(rThePassword, bOctets, |
| m_eScheme == INET_PROT_VIM ? |
| PART_VIM : PART_USER_PASSWORD, |
| getEscapePrefix(), eMechanism, eCharset, |
| false)); |
| sal_Int32 nDelta; |
| if (m_aAuth.isPresent()) |
| nDelta = m_aAuth.set(m_aAbsURIRef, aNewAuth); |
| else if (m_aUser.isPresent()) |
| { |
| m_aAbsURIRef.insert(m_aUser.getEnd(), sal_Unicode(':')); |
| nDelta |
| = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aUser.getEnd() + 1) + 1; |
| } |
| else if (m_aHost.isPresent()) |
| { |
| m_aAbsURIRef.insert(m_aHost.getBegin(), |
| rtl::OUString::createFromAscii(":@")); |
| m_aUser.set(m_aAbsURIRef, rtl::OUString(), m_aHost.getBegin()); |
| nDelta |
| = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aHost.getBegin() + 1) + 2; |
| } |
| else if (getSchemeInfo().m_bHost) |
| return false; |
| else |
| { |
| m_aAbsURIRef.insert(m_aPath.getBegin(), sal_Unicode(':')); |
| m_aUser.set(m_aAbsURIRef, rtl::OUString(), m_aPath.getBegin()); |
| nDelta |
| = m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aPath.getBegin() + 1) + 1; |
| } |
| m_aHost += nDelta; |
| m_aPort += nDelta; |
| m_aPath += nDelta; |
| m_aQuery += nDelta; |
| m_aFragment += nDelta; |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetURLObject::parseHost( |
| sal_Unicode const *& rBegin, sal_Unicode const * pEnd, |
| rtl::OUString & rCanonic) |
| { |
| // RFC 2373 is inconsistent about how to write an IPv6 address in which an |
| // IPv4 address directly follows the abbreviating "::". The ABNF in |
| // Appendix B suggests ":::13.1.68.3", while an example in 2.2/3 explicitly |
| // mentions "::13:1.68.3". This algorithm accepts both variants: |
| enum State { STATE_INITIAL, STATE_LABEL, STATE_LABEL_HYPHEN, |
| STATE_LABEL_DOT, STATE_TOPLABEL, STATE_TOPLABEL_HYPHEN, |
| STATE_TOPLABEL_DOT, STATE_IP4, STATE_IP4_DOT, STATE_IP6, |
| STATE_IP6_COLON, STATE_IP6_2COLON, STATE_IP6_3COLON, |
| STATE_IP6_HEXSEQ1, STATE_IP6_HEXSEQ1_COLON, |
| STATE_IP6_HEXSEQ1_MAYBE_IP4, STATE_IP6_HEXSEQ2, |
| STATE_IP6_HEXSEQ2_COLON, STATE_IP6_HEXSEQ2_MAYBE_IP4, |
| STATE_IP6_IP4, STATE_IP6_IP4_DOT, STATE_IP6_DONE }; |
| rtl::OUStringBuffer aTheCanonic; |
| sal_uInt32 nNumber = 0; |
| int nDigits = 0; |
| int nOctets = 0; |
| State eState = STATE_INITIAL; |
| sal_Unicode const * p = rBegin; |
| for (; p != pEnd; ++p) |
| switch (eState) |
| { |
| case STATE_INITIAL: |
| if (*p == '[') |
| { |
| aTheCanonic.append(sal_Unicode('[')); |
| eState = STATE_IP6; |
| } |
| else if (INetMIME::isAlpha(*p)) |
| eState = STATE_TOPLABEL; |
| else if (INetMIME::isDigit(*p)) |
| { |
| nNumber = INetMIME::getWeight(*p); |
| nDigits = 1; |
| nOctets = 1; |
| eState = STATE_IP4; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_LABEL: |
| if (*p == '.') |
| eState = STATE_LABEL_DOT; |
| else if (*p == '-') |
| eState = STATE_LABEL_HYPHEN; |
| else if (!INetMIME::isAlphanumeric(*p)) |
| goto done; |
| break; |
| |
| case STATE_LABEL_HYPHEN: |
| if (INetMIME::isAlphanumeric(*p)) |
| eState = STATE_LABEL; |
| else if (*p != '-') |
| goto done; |
| break; |
| |
| case STATE_LABEL_DOT: |
| if (INetMIME::isAlpha(*p)) |
| eState = STATE_TOPLABEL; |
| else if (INetMIME::isDigit(*p)) |
| eState = STATE_LABEL; |
| else |
| goto done; |
| break; |
| |
| case STATE_TOPLABEL: |
| if (*p == '.') |
| eState = STATE_TOPLABEL_DOT; |
| else if (*p == '-') |
| eState = STATE_TOPLABEL_HYPHEN; |
| else if (!INetMIME::isAlphanumeric(*p)) |
| goto done; |
| break; |
| |
| case STATE_TOPLABEL_HYPHEN: |
| if (INetMIME::isAlphanumeric(*p)) |
| eState = STATE_TOPLABEL; |
| else if (*p != '-') |
| goto done; |
| break; |
| |
| case STATE_TOPLABEL_DOT: |
| if (INetMIME::isAlpha(*p)) |
| eState = STATE_TOPLABEL; |
| else if (INetMIME::isDigit(*p)) |
| eState = STATE_LABEL; |
| else |
| goto done; |
| break; |
| |
| case STATE_IP4: |
| if (*p == '.') |
| if (nOctets < 4) |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber))); |
| aTheCanonic.append(sal_Unicode('.')); |
| ++nOctets; |
| eState = STATE_IP4_DOT; |
| } |
| else |
| eState = STATE_LABEL_DOT; |
| else if (*p == '-') |
| eState = STATE_LABEL_HYPHEN; |
| else if (INetMIME::isAlpha(*p)) |
| eState = STATE_LABEL; |
| else if (INetMIME::isDigit(*p)) |
| if (nDigits < 3) |
| { |
| nNumber = 10 * nNumber + INetMIME::getWeight(*p); |
| ++nDigits; |
| } |
| else |
| eState = STATE_LABEL; |
| else |
| goto done; |
| break; |
| |
| case STATE_IP4_DOT: |
| if (INetMIME::isAlpha(*p)) |
| eState = STATE_TOPLABEL; |
| else if (INetMIME::isDigit(*p)) |
| { |
| nNumber = INetMIME::getWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP4; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6: |
| if (*p == ':') |
| eState = STATE_IP6_COLON; |
| else if (INetMIME::isHexDigit(*p)) |
| { |
| nNumber = INetMIME::getHexWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP6_HEXSEQ1; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_COLON: |
| if (*p == ':') |
| { |
| aTheCanonic.appendAscii(RTL_CONSTASCII_STRINGPARAM("::")); |
| eState = STATE_IP6_2COLON; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_2COLON: |
| if (*p == ']') |
| eState = STATE_IP6_DONE; |
| else if (*p == ':') |
| { |
| aTheCanonic.append(sal_Unicode(':')); |
| eState = STATE_IP6_3COLON; |
| } |
| else if (INetMIME::isDigit(*p)) |
| { |
| nNumber = INetMIME::getWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP6_HEXSEQ2_MAYBE_IP4; |
| } |
| else if (INetMIME::isHexDigit(*p)) |
| { |
| nNumber = INetMIME::getHexWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP6_HEXSEQ2; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_3COLON: |
| if (INetMIME::isDigit(*p)) |
| { |
| nNumber = INetMIME::getWeight(*p); |
| nDigits = 1; |
| nOctets = 1; |
| eState = STATE_IP6_IP4; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_HEXSEQ1: |
| if (*p == ']') |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber), 16)); |
| eState = STATE_IP6_DONE; |
| } |
| else if (*p == ':') |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber), 16)); |
| aTheCanonic.append(sal_Unicode(':')); |
| eState = STATE_IP6_HEXSEQ1_COLON; |
| } |
| else if (INetMIME::isHexDigit(*p) && nDigits < 4) |
| { |
| nNumber = 16 * nNumber + INetMIME::getHexWeight(*p); |
| ++nDigits; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_HEXSEQ1_COLON: |
| if (*p == ':') |
| { |
| aTheCanonic.append(sal_Unicode(':')); |
| eState = STATE_IP6_2COLON; |
| } |
| else if (INetMIME::isDigit(*p)) |
| { |
| nNumber = INetMIME::getWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP6_HEXSEQ1_MAYBE_IP4; |
| } |
| else if (INetMIME::isHexDigit(*p)) |
| { |
| nNumber = INetMIME::getHexWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP6_HEXSEQ1; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_HEXSEQ1_MAYBE_IP4: |
| if (*p == ']') |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber), 16)); |
| eState = STATE_IP6_DONE; |
| } |
| else if (*p == ':') |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber), 16)); |
| aTheCanonic.append(sal_Unicode(':')); |
| eState = STATE_IP6_HEXSEQ1_COLON; |
| } |
| else if (*p == '.') |
| { |
| nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15) |
| + (nNumber & 15); |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber))); |
| aTheCanonic.append(sal_Unicode('.')); |
| nOctets = 2; |
| eState = STATE_IP6_IP4_DOT; |
| } |
| else if (INetMIME::isDigit(*p) && nDigits < 3) |
| { |
| nNumber = 16 * nNumber + INetMIME::getWeight(*p); |
| ++nDigits; |
| } |
| else if (INetMIME::isHexDigit(*p) && nDigits < 4) |
| { |
| nNumber = 16 * nNumber + INetMIME::getHexWeight(*p); |
| ++nDigits; |
| eState = STATE_IP6_HEXSEQ1; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_HEXSEQ2: |
| if (*p == ']') |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber), 16)); |
| eState = STATE_IP6_DONE; |
| } |
| else if (*p == ':') |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber), 16)); |
| aTheCanonic.append(sal_Unicode(':')); |
| eState = STATE_IP6_HEXSEQ2_COLON; |
| } |
| else if (INetMIME::isHexDigit(*p) && nDigits < 4) |
| { |
| nNumber = 16 * nNumber + INetMIME::getHexWeight(*p); |
| ++nDigits; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_HEXSEQ2_COLON: |
| if (INetMIME::isDigit(*p)) |
| { |
| nNumber = INetMIME::getWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP6_HEXSEQ2_MAYBE_IP4; |
| } |
| else if (INetMIME::isHexDigit(*p)) |
| { |
| nNumber = INetMIME::getHexWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP6_HEXSEQ2; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_HEXSEQ2_MAYBE_IP4: |
| if (*p == ']') |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber), 16)); |
| eState = STATE_IP6_DONE; |
| } |
| else if (*p == ':') |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber), 16)); |
| aTheCanonic.append(sal_Unicode(':')); |
| eState = STATE_IP6_HEXSEQ2_COLON; |
| } |
| else if (*p == '.') |
| { |
| nNumber = 100 * (nNumber >> 8) + 10 * (nNumber >> 4 & 15) |
| + (nNumber & 15); |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber))); |
| aTheCanonic.append(sal_Unicode('.')); |
| nOctets = 2; |
| eState = STATE_IP6_IP4_DOT; |
| } |
| else if (INetMIME::isDigit(*p) && nDigits < 3) |
| { |
| nNumber = 16 * nNumber + INetMIME::getWeight(*p); |
| ++nDigits; |
| } |
| else if (INetMIME::isHexDigit(*p) && nDigits < 4) |
| { |
| nNumber = 16 * nNumber + INetMIME::getHexWeight(*p); |
| ++nDigits; |
| eState = STATE_IP6_HEXSEQ2; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_IP4: |
| if (*p == ']') |
| if (nOctets == 4) |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber))); |
| eState = STATE_IP6_DONE; |
| } |
| else |
| goto done; |
| else if (*p == '.') |
| if (nOctets < 4) |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber))); |
| aTheCanonic.append(sal_Unicode('.')); |
| ++nOctets; |
| eState = STATE_IP6_IP4_DOT; |
| } |
| else |
| goto done; |
| else if (INetMIME::isDigit(*p) && nDigits < 3) |
| { |
| nNumber = 10 * nNumber + INetMIME::getWeight(*p); |
| ++nDigits; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_IP4_DOT: |
| if (INetMIME::isDigit(*p)) |
| { |
| nNumber = INetMIME::getWeight(*p); |
| nDigits = 1; |
| eState = STATE_IP6_IP4; |
| } |
| else |
| goto done; |
| break; |
| |
| case STATE_IP6_DONE: |
| goto done; |
| } |
| done: |
| switch (eState) |
| { |
| case STATE_LABEL: |
| case STATE_TOPLABEL: |
| case STATE_TOPLABEL_DOT: |
| aTheCanonic.setLength(0); |
| aTheCanonic.append(rBegin, p - rBegin); |
| rBegin = p; |
| rCanonic = aTheCanonic.makeStringAndClear(); |
| return true; |
| |
| case STATE_IP4: |
| if (nOctets == 4) |
| { |
| aTheCanonic.append( |
| rtl::OUString::valueOf(sal_Int32(nNumber))); |
| rBegin = p; |
| rCanonic = aTheCanonic.makeStringAndClear(); |
| return true; |
| } |
| return false; |
| |
| case STATE_IP6_DONE: |
| aTheCanonic.append(sal_Unicode(']')); |
| rBegin = p; |
| rCanonic = aTheCanonic.makeStringAndClear(); |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| |
| //============================================================================ |
| // static |
| bool INetURLObject::parseHostOrNetBiosName( |
| sal_Unicode const * pBegin, sal_Unicode const * pEnd, bool bOctets, |
| EncodeMechanism eMechanism, rtl_TextEncoding eCharset, bool bNetBiosName, |
| rtl::OUStringBuffer* pCanonic) |
| { |
| rtl::OUString aTheCanonic; |
| if (pBegin < pEnd) |
| { |
| sal_Unicode const * p = pBegin; |
| if (!parseHost(p, pEnd, aTheCanonic) || p != pEnd) |
| { |
| if (bNetBiosName) |
| { |
| rtl::OUStringBuffer buf; |
| while (pBegin < pEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, bOctets, '%', |
| eMechanism, eCharset, |
| eEscapeType); |
| if (!INetMIME::isVisible(nUTF32)) |
| return false; |
| if (!INetMIME::isAlphanumeric(nUTF32)) |
| switch (nUTF32) |
| { |
| case '"': |
| case '*': |
| case '+': |
| case ',': |
| case '/': |
| case ':': |
| case ';': |
| case '<': |
| case '=': |
| case '>': |
| case '?': |
| case '[': |
| case '\\': |
| case ']': |
| case '`': |
| case '|': |
| return false;; |
| } |
| if (pCanonic != NULL) { |
| appendUCS4( |
| buf, nUTF32, eEscapeType, bOctets, PART_URIC, '%', |
| eCharset, true); |
| } |
| } |
| aTheCanonic = buf.makeStringAndClear(); |
| } |
| else |
| return false; |
| } |
| } |
| if (pCanonic != NULL) { |
| *pCanonic = aTheCanonic; |
| } |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| rtl::OUString INetURLObject::encodeHostPort(rtl::OUString const & rTheHostPort, |
| bool bOctets, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| sal_Int32 nPort = rTheHostPort.getLength(); |
| if (nPort != 0) |
| { |
| sal_Int32 i = nPort - 1; |
| while (i != 0 && INetMIME::isDigit(rTheHostPort.getStr()[i])) |
| --i; |
| if (rTheHostPort.getStr()[i] == ':') |
| nPort = i; |
| } |
| rtl::OUString aResult(encodeText(rTheHostPort.copy(0, nPort), bOctets, |
| PART_HOST_EXTRA, '%', eMechanism, eCharset, |
| true)); |
| aResult += rTheHostPort.copy(nPort); |
| return aResult; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setHost(rtl::OUString const & rTheHost, bool bOctets, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| if (!getSchemeInfo().m_bHost) |
| return false; |
| rtl::OUStringBuffer aSynHost(rTheHost); |
| bool bNetBiosName = false; |
| switch (m_eScheme) |
| { |
| case INET_PROT_FILE: |
| { |
| rtl::OUString sTemp(aSynHost); |
| if (sTemp.equalsIgnoreAsciiCaseAsciiL( |
| RTL_CONSTASCII_STRINGPARAM("localhost"))) |
| { |
| aSynHost.setLength(0); |
| } |
| bNetBiosName = true; |
| } |
| break; |
| case INET_PROT_LDAP: |
| if (aSynHost.getLength() == 0 && m_aPort.isPresent()) |
| return false; |
| break; |
| |
| default: |
| if (aSynHost.getLength() == 0) |
| return false; |
| break; |
| } |
| if (!parseHostOrNetBiosName( |
| aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(), |
| bOctets, eMechanism, eCharset, bNetBiosName, &aSynHost)) |
| return false; |
| sal_Int32 nDelta = m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear()); |
| m_aPort += nDelta; |
| m_aPath += nDelta; |
| m_aQuery += nDelta; |
| m_aFragment += nDelta; |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetURLObject::parsePath(INetProtocol eScheme, |
| sal_Unicode const ** pBegin, |
| sal_Unicode const * pEnd, |
| bool bOctets, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset, |
| bool bSkippedInitialSlash, |
| sal_uInt32 nSegmentDelimiter, |
| sal_uInt32 nAltSegmentDelimiter, |
| sal_uInt32 nQueryDelimiter, |
| sal_uInt32 nFragmentDelimiter, |
| rtl::OUStringBuffer &rSynPath) |
| { |
| DBG_ASSERT(pBegin, "INetURLObject::parsePath(): Null output param"); |
| |
| sal_Unicode const * pPos = *pBegin; |
| rtl::OUStringBuffer aTheSynPath; |
| |
| switch (eScheme) |
| { |
| case INET_PROT_NOT_VALID: |
| return false; |
| |
| case INET_PROT_FTP: |
| case INET_PROT_IMAP: |
| if (pPos < pEnd && *pPos != '/') |
| return false; |
| while (pPos < pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_HTTP_PATH, '%', eCharset, true); |
| } |
| if (aTheSynPath.getLength() == 0) |
| aTheSynPath.append(sal_Unicode('/')); |
| break; |
| |
| case INET_PROT_HTTP: |
| case INET_PROT_VND_SUN_STAR_WEBDAV: |
| case INET_PROT_HTTPS: |
| case INET_PROT_SMB: |
| if (pPos < pEnd && *pPos != '/') |
| return false; |
| while (pPos < pEnd && *pPos != nQueryDelimiter |
| && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_HTTP_PATH, '%', eCharset, true); |
| } |
| if (aTheSynPath.getLength() == 0) |
| aTheSynPath.append(sal_Unicode('/')); |
| break; |
| |
| case INET_PROT_FILE: |
| { |
| if (bSkippedInitialSlash) |
| aTheSynPath.append(sal_Unicode('/')); |
| else if (pPos < pEnd |
| && *pPos != nSegmentDelimiter |
| && *pPos != nAltSegmentDelimiter) |
| return false; |
| while (pPos < pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| if (eEscapeType == ESCAPE_NO) |
| { |
| if (nUTF32 == nSegmentDelimiter |
| || nUTF32 == nAltSegmentDelimiter) |
| { |
| aTheSynPath.append(sal_Unicode('/')); |
| continue; |
| } |
| else if (nUTF32 == '|' |
| && (pPos == pEnd |
| || *pPos == nFragmentDelimiter |
| || *pPos == nSegmentDelimiter |
| || *pPos == nAltSegmentDelimiter) |
| && aTheSynPath.getLength() == 2 |
| && INetMIME::isAlpha(aTheSynPath.charAt(1))) |
| { |
| // A first segment of <ALPHA "|"> is translated to |
| // <ALPHA ":">: |
| aTheSynPath.append(sal_Unicode(':')); |
| continue; |
| } |
| } |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_PCHAR, '%', eCharset, true); |
| } |
| if (aTheSynPath.getLength() == 0) |
| aTheSynPath.append(sal_Unicode('/')); |
| break; |
| } |
| |
| case INET_PROT_MAILTO: |
| while (pPos < pEnd && *pPos != nQueryDelimiter |
| && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_MAILTO, '%', eCharset, true); |
| } |
| break; |
| |
| case INET_PROT_NEWS: |
| if (pPos == pEnd || *pPos == nQueryDelimiter |
| || *pPos == nFragmentDelimiter) |
| return false; |
| |
| // Match <"*">: |
| if (*pPos == '*' |
| && (pEnd - pPos == 1 || pPos[1] == nQueryDelimiter |
| || pPos[1] == nFragmentDelimiter)) |
| { |
| ++pPos; |
| aTheSynPath.append(sal_Unicode('*')); |
| break; |
| } |
| |
| // Match <group>: |
| if (INetMIME::isAlpha(*pPos)) |
| for (sal_Unicode const * p = pPos + 1;; ++p) |
| if (p == pEnd || *p == nQueryDelimiter |
| || *p == nFragmentDelimiter) |
| { |
| aTheSynPath.setLength(0); |
| aTheSynPath.append(pPos, p - pPos); |
| pPos = p; |
| goto done; |
| } |
| else if (!INetMIME::isAlphanumeric(*p) && *p != '+' |
| && *p != '-' && *p != '.' && *p != '_') |
| break; |
| |
| // Match <article>: |
| for (;;) |
| { |
| if (pPos == pEnd || *pPos == nQueryDelimiter |
| || *pPos == nFragmentDelimiter) |
| return false; |
| if (*pPos == '@') |
| break; |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, '%', |
| eMechanism, eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_NEWS_ARTICLE_LOCALPART, '%', eCharset, true); |
| } |
| if (aTheSynPath.getLength() == 0) |
| return false; |
| ++pPos; |
| aTheSynPath.append(sal_Unicode('@')); |
| { |
| sal_Unicode const * p = pPos; |
| while (p < pEnd && *pPos != nQueryDelimiter |
| && *pPos != nFragmentDelimiter) |
| ++p; |
| rtl::OUString aCanonic; |
| if (!parseHost(pPos, p, aCanonic)) |
| return false; |
| aTheSynPath.append(aCanonic); |
| } |
| |
| done: |
| break; |
| |
| case INET_PROT_POP3: |
| while (pPos < pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_MESSAGE_ID_PATH, '%', eCharset, |
| true); |
| } |
| break; |
| |
| case INET_PROT_PRIV_SOFFICE: |
| case INET_PROT_SLOT: |
| case INET_PROT_HID: |
| case INET_PROT_MACRO: |
| case INET_PROT_UNO: |
| case INET_PROT_COMPONENT: |
| case INET_PROT_LDAP: |
| while (pPos < pEnd && *pPos != nQueryDelimiter |
| && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_PATH_BEFORE_QUERY, '%', eCharset, |
| true); |
| } |
| break; |
| |
| case INET_PROT_VND_SUN_STAR_HELP: |
| if (pPos == pEnd |
| || *pPos == nQueryDelimiter |
| || *pPos == nFragmentDelimiter) |
| aTheSynPath.append(sal_Unicode('/')); |
| else |
| { |
| if (*pPos != '/') |
| return false; |
| while (pPos < pEnd && *pPos != nQueryDelimiter |
| && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_HTTP_PATH, '%', eCharset, true); |
| } |
| } |
| break; |
| |
| case INET_PROT_JAVASCRIPT: |
| case INET_PROT_DATA: |
| case INET_PROT_CID: |
| case INET_PROT_DB: |
| while (pPos < pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_URIC, '%', eCharset, true); |
| } |
| break; |
| |
| case INET_PROT_OUT: |
| if (pEnd - pPos < 2 || *pPos++ != '/' || *pPos++ != '~') |
| return false; |
| aTheSynPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("/~")); |
| while (pPos < pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_URIC, '%', eCharset, true); |
| } |
| break; |
| |
| case INET_PROT_VND_SUN_STAR_HIER: |
| case INET_PROT_VND_SUN_STAR_PKG: |
| if (pPos < pEnd && *pPos != '/' |
| && *pPos != nQueryDelimiter && *pPos != nFragmentDelimiter) |
| return false; |
| while (pPos < pEnd && *pPos != nQueryDelimiter |
| && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| if (eEscapeType == ESCAPE_NO && nUTF32 == '/') |
| aTheSynPath.append(sal_Unicode('/')); |
| else |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_PCHAR, '%', eCharset, false); |
| } |
| if (aTheSynPath.getLength() == 0) |
| aTheSynPath.append(sal_Unicode('/')); |
| break; |
| |
| case INET_PROT_VIM: |
| { |
| /* test had to be taken out to make parsePath static; ok since INET_PROT_VIM is |
| obsolete, anyway |
| if (m_aUser.isEmpty()) |
| return false; |
| */ |
| sal_Unicode const * pPathEnd = pPos; |
| while (pPathEnd < pEnd && *pPathEnd != nFragmentDelimiter) |
| ++pPathEnd; |
| aTheSynPath.append(sal_Unicode('/')); |
| if (pPos == pPathEnd) |
| break; |
| else if (*pPos++ != '/') |
| return false; |
| if (pPos == pPathEnd) |
| break; |
| while (pPos < pPathEnd && *pPos != '/') |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, |
| '=', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, |
| eEscapeType == ESCAPE_NO ? |
| INetMIME::toLowerCase(nUTF32) : nUTF32, |
| eEscapeType, bOctets, PART_VIM, '=', |
| eCharset, false); |
| } |
| bool bInbox; |
| rtl::OUString sCompare(aTheSynPath); |
| if (sCompare.equalsAscii("/inbox")) |
| bInbox = true; |
| else if (sCompare.equalsAscii("/newsgroups")) |
| bInbox = false; |
| else |
| return false; |
| aTheSynPath.append(sal_Unicode('/')); |
| if (pPos == pPathEnd) |
| break; |
| else if (*pPos++ != '/') |
| return false; |
| if (!bInbox) |
| { |
| bool bEmpty = true; |
| while (pPos < pPathEnd && *pPos != '/') |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, |
| '=', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_VIM, '=', eCharset, false); |
| bEmpty = false; |
| } |
| if (bEmpty) |
| return false; |
| aTheSynPath.append(sal_Unicode('/')); |
| if (pPos == pPathEnd) |
| break; |
| else if (*pPos++ != '/') |
| return false; |
| } |
| bool bEmpty = true; |
| while (pPos < pPathEnd && *pPos != ':') |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, |
| '=', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_VIM, '=', eCharset, false); |
| bEmpty = false; |
| } |
| if (bEmpty) |
| return false; |
| if (pPos == pPathEnd) |
| break; |
| else if (*pPos++ != ':') |
| return false; |
| aTheSynPath.append(sal_Unicode(':')); |
| for (int i = 0; i < 3; ++i) |
| { |
| if (i != 0) |
| { |
| if (pPos == pPathEnd || *pPos++ != '.') |
| return false; |
| aTheSynPath.append(sal_Unicode('.')); |
| } |
| bEmpty = true; |
| while (pPos < pPathEnd && *pPos != '.') |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pPathEnd, bOctets, |
| '=', eMechanism, |
| eCharset, eEscapeType); |
| if (!INetMIME::isDigit(nUTF32)) |
| return false; |
| aTheSynPath.append(sal_Unicode(nUTF32)); |
| bEmpty = false; |
| } |
| if (bEmpty) |
| return false; |
| } |
| if (pPos != pPathEnd) |
| return false; |
| break; |
| } |
| |
| case INET_PROT_VND_SUN_STAR_CMD: |
| case INET_PROT_VND_SUN_STAR_EXPAND: |
| { |
| if (pPos == pEnd || *pPos == nFragmentDelimiter) |
| return false; |
| Part ePart = PART_URIC_NO_SLASH; |
| while (pPos != pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, ePart, |
| '%', eCharset, true); |
| ePart = PART_URIC; |
| } |
| break; |
| } |
| |
| case INET_PROT_VND_SUN_STAR_ODMA: |
| if (pPos < pEnd) |
| { |
| if (*pPos == '/') |
| ++pPos; |
| else |
| return false; |
| } |
| aTheSynPath.append(sal_Unicode('/')); |
| while (pPos < pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_URIC_NO_SLASH, '%', eCharset, true); |
| } |
| break; |
| |
| case INET_PROT_TELNET: |
| if (pPos < pEnd) |
| { |
| if (*pPos != '/' || pEnd - pPos > 1) |
| return false; |
| ++pPos; |
| } |
| aTheSynPath.append(sal_Unicode('/')); |
| break; |
| |
| case INET_PROT_VND_SUN_STAR_TDOC: |
| if (pPos == pEnd || *pPos != '/') |
| return false; |
| while (pPos < pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| if (eEscapeType == ESCAPE_NO && nUTF32 == '/') |
| aTheSynPath.append(sal_Unicode('/')); |
| else |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_PCHAR, '%', eCharset, false); |
| } |
| break; |
| |
| case INET_PROT_GENERIC: |
| while (pPos < pEnd && *pPos != nFragmentDelimiter) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pPos, pEnd, bOctets, |
| '%', eMechanism, |
| eCharset, eEscapeType); |
| appendUCS4(aTheSynPath, nUTF32, eEscapeType, bOctets, |
| PART_URIC, '%', eCharset, true); |
| } |
| if (aTheSynPath.getLength() == 0) |
| return false; |
| break; |
| default: |
| OSL_ASSERT(false); |
| break; |
| } |
| |
| *pBegin = pPos; |
| rSynPath = aTheSynPath; |
| return true; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setPath(rtl::OUString const & rThePath, bool bOctets, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| rtl::OUStringBuffer aSynPath; |
| sal_Unicode const * p = rThePath.getStr(); |
| sal_Unicode const * pEnd = p + rThePath.getLength(); |
| if (!parsePath(m_eScheme, &p, pEnd, bOctets, eMechanism, eCharset, false, |
| '/', 0x80000000, 0x80000000, 0x80000000, aSynPath) |
| || p != pEnd) |
| return false; |
| sal_Int32 nDelta = m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear()); |
| m_aQuery += nDelta; |
| m_aFragment += nDelta; |
| return true; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::checkHierarchical() const { |
| if (m_eScheme == INET_PROT_VND_SUN_STAR_EXPAND) { |
| OSL_ENSURE( |
| false, "INetURLObject::checkHierarchical vnd.sun.star.expand"); |
| return true; |
| } else { |
| return getSchemeInfo().m_bHierarchical; |
| } |
| } |
| |
| //============================================================================ |
| bool INetURLObject::appendSegment(rtl::OUString const & rTheSegment, |
| bool bOctets, EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| return insertName(rTheSegment, bOctets, false, LAST_SEGMENT, true, |
| eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| INetURLObject::SubString INetURLObject::getSegment(sal_Int32 nIndex, |
| bool bIgnoreFinalSlash) |
| const |
| { |
| DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT, |
| "INetURLObject::getSegment(): Bad index"); |
| |
| if (!checkHierarchical()) |
| return SubString(); |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| sal_Unicode const * pSegBegin; |
| sal_Unicode const * pSegEnd; |
| if (nIndex == LAST_SEGMENT) |
| { |
| pSegEnd = pPathEnd; |
| if (bIgnoreFinalSlash && pSegEnd > pPathBegin && pSegEnd[-1] == '/') |
| --pSegEnd; |
| if (pSegEnd <= pPathBegin) |
| return SubString(); |
| pSegBegin = pSegEnd - 1; |
| while (pSegBegin > pPathBegin && *pSegBegin != '/') |
| --pSegBegin; |
| } |
| else |
| { |
| pSegBegin = pPathBegin; |
| while (nIndex-- > 0) |
| do |
| { |
| ++pSegBegin; |
| if (pSegBegin >= pPathEnd) |
| return SubString(); |
| } |
| while (*pSegBegin != '/'); |
| pSegEnd = pSegBegin + 1; |
| while (pSegEnd < pPathEnd && *pSegEnd != '/') |
| ++pSegEnd; |
| } |
| |
| return SubString(pSegBegin - m_aAbsURIRef.getStr(), |
| pSegEnd - pSegBegin); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::insertName(rtl::OUString const & rTheName, bool bOctets, |
| bool bAppendFinalSlash, sal_Int32 nIndex, |
| bool bIgnoreFinalSlash, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| DBG_ASSERT(nIndex >= 0 || nIndex == LAST_SEGMENT, |
| "INetURLObject::insertName(): Bad index"); |
| |
| if (!checkHierarchical()) |
| return false; |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| sal_Unicode const * pPrefixEnd; |
| bool bInsertSlash; |
| sal_Unicode const * pSuffixBegin; |
| if (nIndex == LAST_SEGMENT) |
| { |
| pPrefixEnd = pPathEnd; |
| if (bIgnoreFinalSlash && pPrefixEnd > pPathBegin && |
| pPrefixEnd[-1] == '/') |
| { |
| --pPrefixEnd; |
| } |
| bInsertSlash = bAppendFinalSlash; |
| pSuffixBegin = pPathEnd; |
| } |
| else if (nIndex == 0) |
| { |
| pPrefixEnd = pPathBegin; |
| bInsertSlash = |
| (pPathBegin < pPathEnd && *pPathBegin != '/') || |
| (pPathBegin == pPathEnd && bAppendFinalSlash); |
| pSuffixBegin = |
| (pPathEnd - pPathBegin == 1 && *pPathBegin == '/' && |
| !bAppendFinalSlash && bIgnoreFinalSlash) |
| ? pPathEnd : pPathBegin; |
| } |
| else |
| { |
| pPrefixEnd = pPathBegin; |
| sal_Unicode const * pEnd = pPathEnd; |
| if (bIgnoreFinalSlash && pEnd > pPathBegin && pEnd[-1] == '/') |
| --pEnd; |
| bool bSkip = pPrefixEnd < pEnd && *pPrefixEnd == '/'; |
| bInsertSlash = false; |
| pSuffixBegin = pPathEnd; |
| while (nIndex-- > 0) |
| for (;;) |
| { |
| if (bSkip) |
| ++pPrefixEnd; |
| bSkip = true; |
| if (pPrefixEnd >= pEnd) |
| { |
| if (nIndex == 0) |
| { |
| bInsertSlash = bAppendFinalSlash; |
| break; |
| } |
| else |
| return false; |
| } |
| if (*pPrefixEnd == '/') |
| { |
| pSuffixBegin = pPrefixEnd; |
| break; |
| } |
| } |
| } |
| |
| rtl::OUStringBuffer aNewPath; |
| aNewPath.append(pPathBegin, pPrefixEnd - pPathBegin); |
| aNewPath.append(sal_Unicode('/')); |
| aNewPath.append(encodeText(rTheName, bOctets, PART_PCHAR, getEscapePrefix(), |
| eMechanism, eCharset, true)); |
| if (bInsertSlash) { |
| aNewPath.append(sal_Unicode('/')); |
| } |
| aNewPath.append(pSuffixBegin, pPathEnd - pSuffixBegin); |
| |
| return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::clearQuery() |
| { |
| if (HasError()) |
| return false; |
| if (m_aQuery.isPresent()) |
| { |
| lcl_Erase(m_aAbsURIRef, m_aQuery.getBegin() - 1, |
| m_aQuery.getLength() + 1); |
| m_aFragment += m_aQuery.clear() - 1; |
| } |
| return false; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setQuery(rtl::OUString const & rTheQuery, bool bOctets, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| if (!getSchemeInfo().m_bQuery) |
| return false; |
| rtl::OUString aNewQuery(encodeText(rTheQuery, bOctets, PART_URIC, |
| getEscapePrefix(), eMechanism, eCharset, |
| true)); |
| sal_Int32 nDelta; |
| if (m_aQuery.isPresent()) |
| nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery); |
| else |
| { |
| m_aAbsURIRef.insert(m_aPath.getEnd(), sal_Unicode('?')); |
| nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery, m_aPath.getEnd() + 1) |
| + 1; |
| } |
| m_aFragment += nDelta; |
| return true; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::clearFragment() |
| { |
| if (HasError()) |
| return false; |
| if (m_aFragment.isPresent()) |
| { |
| m_aAbsURIRef.setLength(m_aFragment.getBegin() - 1); |
| m_aFragment.clear(); |
| } |
| return true; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setFragment(rtl::OUString const & rTheFragment, |
| bool bOctets, EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| if (HasError()) |
| return false; |
| rtl::OUString aNewFragment(encodeText(rTheFragment, bOctets, PART_URIC, |
| getEscapePrefix(), eMechanism, |
| eCharset, true)); |
| if (m_aFragment.isPresent()) |
| m_aFragment.set(m_aAbsURIRef, aNewFragment); |
| else |
| { |
| m_aAbsURIRef.append(sal_Unicode('#')); |
| m_aFragment.set(m_aAbsURIRef, aNewFragment, m_aAbsURIRef.getLength()); |
| } |
| return true; |
| } |
| |
| //============================================================================ |
| INetURLObject::FTPType INetURLObject::getFTPType() const |
| { |
| if (m_eScheme == INET_PROT_FTP |
| && m_aPath.getLength() >= RTL_CONSTASCII_LENGTH(";type=") + 1 |
| && rtl::OUString(m_aAbsURIRef).copy( |
| m_aPath.getEnd() - (RTL_CONSTASCII_LENGTH(";type=") + 1), |
| RTL_CONSTASCII_LENGTH(";type=")).equalsIgnoreAsciiCaseAscii(";type=")) |
| switch (m_aAbsURIRef.charAt(m_aPath.getEnd())) |
| { |
| case 'A': |
| case 'a': |
| return FTP_TYPE_A; |
| |
| case 'D': |
| case 'd': |
| return FTP_TYPE_D; |
| |
| case 'I': |
| case 'i': |
| return FTP_TYPE_I; |
| } |
| return FTP_TYPE_NONE; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::hasDosVolume(FSysStyle eStyle) const |
| { |
| sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| return (eStyle & FSYS_DOS) != 0 |
| && m_aPath.getLength() >= 3 |
| && p[0] == '/' |
| && INetMIME::isAlpha(p[1]) |
| && p[2] == ':' |
| && (m_aPath.getLength() == 3 || p[3] == '/'); |
| } |
| |
| //============================================================================ |
| sal_uInt32 INetURLObject::getIMAPUID() const |
| { |
| if (m_eScheme == INET_PROT_IMAP |
| && m_aPath.getLength() >= RTL_CONSTASCII_LENGTH("/;uid=") + 1) |
| { |
| sal_Unicode const * pBegin = m_aAbsURIRef.getStr() |
| + m_aPath.getBegin() |
| + RTL_CONSTASCII_LENGTH("/;uid="); |
| sal_Unicode const * pEnd = pBegin + m_aPath.getLength(); |
| sal_Unicode const * p = pEnd; |
| while (p > pBegin && INetMIME::isDigit(p[-1])) |
| --p; |
| if (p < pEnd && *--p != '0' |
| && rtl::OUString(m_aAbsURIRef).copy( |
| p - RTL_CONSTASCII_LENGTH("/;uid=") - m_aAbsURIRef.getStr(), |
| RTL_CONSTASCII_LENGTH("/;uid=")).equalsIgnoreAsciiCaseAscii("/;uid=") |
| ) |
| { |
| sal_uInt32 nUID; |
| if (INetMIME::scanUnsigned(p, pEnd, false, nUID)) |
| return nUID; |
| } |
| } |
| return 0; |
| } |
| |
| //============================================================================ |
| // static |
| rtl::OUString INetURLObject::encodeText(sal_Unicode const * pBegin, |
| sal_Unicode const * pEnd, bool bOctets, |
| Part ePart, sal_Char cEscapePrefix, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset, |
| bool bKeepVisibleEscapes) |
| { |
| rtl::OUStringBuffer aResult; |
| while (pBegin < pEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, bOctets, cEscapePrefix, |
| eMechanism, eCharset, eEscapeType); |
| appendUCS4(aResult, nUTF32, eEscapeType, bOctets, ePart, |
| cEscapePrefix, eCharset, bKeepVisibleEscapes); |
| } |
| return aResult.makeStringAndClear(); |
| } |
| |
| //============================================================================ |
| // static |
| rtl::OUString INetURLObject::decode(sal_Unicode const * pBegin, |
| sal_Unicode const * pEnd, |
| sal_Char cEscapePrefix, |
| DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| switch (eMechanism) |
| { |
| case NO_DECODE: |
| return rtl::OUString(pBegin, pEnd - pBegin); |
| |
| case DECODE_TO_IURI: |
| eCharset = RTL_TEXTENCODING_UTF8; |
| break; |
| |
| default: |
| break; |
| } |
| rtl::OUStringBuffer aResult; |
| while (pBegin < pEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, false, cEscapePrefix, |
| WAS_ENCODED, eCharset, eEscapeType); |
| switch (eEscapeType) |
| { |
| case ESCAPE_NO: |
| aResult.append(sal_Unicode(nUTF32)); |
| break; |
| |
| case ESCAPE_OCTET: |
| appendEscape(aResult, cEscapePrefix, nUTF32); |
| break; |
| |
| case ESCAPE_UTF32: |
| if ( |
| INetMIME::isUSASCII(nUTF32) && |
| ( |
| eMechanism == DECODE_TO_IURI || |
| ( |
| eMechanism == DECODE_UNAMBIGUOUS && |
| mustEncode(nUTF32, PART_UNAMBIGUOUS) |
| ) |
| ) |
| ) |
| { |
| appendEscape(aResult, cEscapePrefix, nUTF32); |
| } |
| else |
| aResult.append(sal_Unicode(nUTF32)); |
| break; |
| } |
| } |
| return aResult.makeStringAndClear(); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetURLNoPass(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| INetURLObject aTemp(*this); |
| aTemp.clearPassword(); |
| return aTemp.GetMainURL(eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetURLNoMark(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| INetURLObject aTemp(*this); |
| aTemp.clearFragment(); |
| return aTemp.GetMainURL(eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| rtl::OUString |
| INetURLObject::getAbbreviated( |
| star::uno::Reference< star::util::XStringWidth > const & rStringWidth, |
| sal_Int32 nWidth, |
| DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| const |
| { |
| OSL_ENSURE(rStringWidth.is(), "specification violation"); |
| sal_Char cEscapePrefix = getEscapePrefix(); |
| rtl::OUStringBuffer aBuffer; |
| // make sure that the scheme is copied for generic schemes: getSchemeInfo().m_pScheme |
| // is empty ("") in that case, so take the scheme from m_aAbsURIRef |
| if (m_eScheme != INET_PROT_GENERIC) |
| { |
| aBuffer.appendAscii(getSchemeInfo().m_pScheme); |
| } |
| else |
| { |
| if (m_aAbsURIRef) |
| { |
| sal_Unicode const * pSchemeBegin |
| = m_aAbsURIRef.getStr(); |
| sal_Unicode const * pSchemeEnd = pSchemeBegin; |
| |
| while (pSchemeEnd[0] != ':') |
| { |
| ++pSchemeEnd; |
| } |
| aBuffer.append(pSchemeBegin, pSchemeEnd - pSchemeBegin); |
| } |
| } |
| aBuffer.append(static_cast< sal_Unicode >(':')); |
| bool bAuthority = getSchemeInfo().m_bAuthority; |
| sal_Unicode const * pCoreBegin |
| = m_aAbsURIRef.getStr() + (bAuthority ? getAuthorityBegin() : |
| m_aPath.getBegin()); |
| sal_Unicode const * pCoreEnd |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin() + m_aPath.getLength(); |
| bool bSegment = false; |
| if (getSchemeInfo().m_bHierarchical) |
| { |
| rtl::OUString aRest; |
| if (m_aQuery.isPresent()) |
| aRest = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("?...")); |
| else if (m_aFragment.isPresent()) |
| aRest = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("#...")); |
| rtl::OUStringBuffer aTrailer; |
| sal_Unicode const * pBegin = pCoreBegin; |
| sal_Unicode const * pEnd = pCoreEnd; |
| sal_Unicode const * pPrefixBegin = pBegin; |
| sal_Unicode const * pSuffixEnd = pEnd; |
| bool bPrefix = true; |
| bool bSuffix = true; |
| do |
| { |
| if (bSuffix) |
| { |
| sal_Unicode const * p = pSuffixEnd - 1; |
| if (pSuffixEnd == pCoreEnd && *p == '/') |
| --p; |
| while (*p != '/') |
| --p; |
| if (bAuthority && p == pCoreBegin + 1) |
| --p; |
| rtl::OUString |
| aSegment(decode(p + (p == pBegin && pBegin != pCoreBegin ? |
| 1 : 0), |
| pSuffixEnd, |
| cEscapePrefix, |
| eMechanism, |
| eCharset)); |
| pSuffixEnd = p; |
| rtl::OUStringBuffer aResult(aBuffer); |
| if (pSuffixEnd != pBegin) |
| aResult.appendAscii(RTL_CONSTASCII_STRINGPARAM("...")); |
| aResult.append(aSegment); |
| aResult.append(aTrailer); |
| aResult.append(aRest); |
| if (rStringWidth-> |
| queryStringWidth(aResult.makeStringAndClear()) |
| <= nWidth) |
| { |
| aTrailer.insert(0, aSegment); |
| bSegment = true; |
| pEnd = pSuffixEnd; |
| } |
| else |
| bSuffix = false; |
| if (pPrefixBegin > pSuffixEnd) |
| pPrefixBegin = pSuffixEnd; |
| if (pBegin == pEnd) |
| break; |
| } |
| if (bPrefix) |
| { |
| sal_Unicode const * p |
| = pPrefixBegin |
| + (bAuthority && pPrefixBegin == pCoreBegin ? 2 : |
| 1); |
| OSL_ASSERT(p <= pEnd); |
| while (p < pEnd && *p != '/') |
| ++p; |
| if (p == pCoreEnd - 1 && *p == '/') |
| ++p; |
| rtl::OUString |
| aSegment(decode(pPrefixBegin |
| + (pPrefixBegin == pCoreBegin ? 0 : |
| 1), |
| p == pEnd ? p : p + 1, |
| cEscapePrefix, |
| eMechanism, |
| eCharset)); |
| pPrefixBegin = p; |
| rtl::OUStringBuffer aResult(aBuffer); |
| aResult.append(aSegment); |
| if (pPrefixBegin != pEnd) |
| aResult.appendAscii(RTL_CONSTASCII_STRINGPARAM("...")); |
| aResult.append(aTrailer); |
| aResult.append(aRest); |
| if (rStringWidth-> |
| queryStringWidth(aResult.makeStringAndClear()) |
| <= nWidth) |
| { |
| aBuffer.append(aSegment); |
| bSegment = true; |
| pBegin = pPrefixBegin; |
| } |
| else |
| bPrefix = false; |
| if (pPrefixBegin > pSuffixEnd) |
| pSuffixEnd = pPrefixBegin; |
| if (pBegin == pEnd) |
| break; |
| } |
| } |
| while (bPrefix || bSuffix); |
| if (bSegment) |
| { |
| if (pPrefixBegin != pBegin || pSuffixEnd != pEnd) |
| aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("...")); |
| aBuffer.append(aTrailer); |
| } |
| } |
| if (!bSegment) |
| aBuffer.append(decode(pCoreBegin, |
| pCoreEnd, |
| cEscapePrefix, |
| eMechanism, |
| eCharset)); |
| if (m_aQuery.isPresent()) |
| { |
| aBuffer.append(static_cast< sal_Unicode >('?')); |
| aBuffer.append(decode(m_aQuery, cEscapePrefix, eMechanism, eCharset)); |
| } |
| if (m_aFragment.isPresent()) |
| { |
| aBuffer.append(static_cast< sal_Unicode >('#')); |
| aBuffer. |
| append(decode(m_aFragment, cEscapePrefix, eMechanism, eCharset)); |
| } |
| if (aBuffer.getLength() != 0) |
| { |
| rtl::OUStringBuffer aResult(aBuffer); |
| if (rStringWidth->queryStringWidth(aResult.makeStringAndClear()) |
| > nWidth) |
| for (sal_Int32 i = aBuffer.getLength();;) |
| { |
| if (i == 0) |
| { |
| aBuffer.setLength(aBuffer.getLength() - 1); |
| if (aBuffer.getLength() == 0) |
| break; |
| } |
| else |
| { |
| aBuffer.setLength(--i); |
| aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("...")); |
| } |
| aResult = aBuffer; |
| if (rStringWidth-> |
| queryStringWidth(aResult.makeStringAndClear()) |
| <= nWidth) |
| break; |
| } |
| } |
| return aBuffer.makeStringAndClear(); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::operator ==(INetURLObject const & rObject) const |
| { |
| if (m_eScheme != rObject.m_eScheme) |
| return false; |
| if (m_eScheme == INET_PROT_NOT_VALID) |
| return (m_aAbsURIRef == rObject.m_aAbsURIRef) != false; |
| if ((m_aScheme.compare( |
| rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef) |
| != 0) |
| || GetUser(NO_DECODE) != rObject.GetUser(NO_DECODE) |
| || GetPass(NO_DECODE) != rObject.GetPass(NO_DECODE) |
| || !GetHost(NO_DECODE).equalsIgnoreAsciiCase( |
| rObject.GetHost(NO_DECODE)) |
| || GetPort() != rObject.GetPort() |
| || HasParam() != rObject.HasParam() |
| || GetParam(NO_DECODE) != rObject.GetParam(NO_DECODE) |
| || GetMsgId(NO_DECODE) != rObject.GetMsgId(NO_DECODE)) |
| return false; |
| rtl::OUString aPath1(GetURLPath(NO_DECODE)); |
| rtl::OUString aPath2(rObject.GetURLPath(NO_DECODE)); |
| switch (m_eScheme) |
| { |
| case INET_PROT_FILE: |
| { |
| // If the URL paths of two file URLs only differ in that one has a |
| // final '/' and the other has not, take the two paths as |
| // equivalent (this could be useful for other schemes, too): |
| sal_Int32 nLength = aPath1.getLength(); |
| switch (nLength - aPath2.getLength()) |
| { |
| case -1: |
| if (aPath2.getStr()[nLength] != '/') |
| return false; |
| break; |
| |
| case 0: |
| break; |
| |
| case 1: |
| if (aPath1.getStr()[--nLength] != '/') |
| return false; |
| break; |
| |
| default: |
| return false; |
| } |
| return aPath1.compareTo(aPath2, nLength) == 0; |
| } |
| |
| default: |
| return (aPath1 == aPath2) != false; |
| } |
| } |
| |
| //============================================================================ |
| bool INetURLObject::operator <(INetURLObject const & rObject) const |
| { |
| sal_Int32 nCompare = m_aScheme.compare( |
| rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef); |
| if (nCompare < 0) { |
| return true; |
| } else if (nCompare > 0) { |
| return false; |
| } |
| sal_uInt32 nPort1 = GetPort(); |
| sal_uInt32 nPort2 = rObject.GetPort(); |
| if (nPort1 < nPort2) |
| return true; |
| else if (nPort1 > nPort2) |
| return false; |
| nCompare = GetUser(NO_DECODE).compareTo(rObject.GetUser(NO_DECODE)); |
| if (nCompare < 0) |
| return true; |
| else if (nCompare > 0) |
| return false; |
| nCompare = GetPass(NO_DECODE).compareTo(rObject.GetPass(NO_DECODE)); |
| if (nCompare < 0) |
| return true; |
| else if (nCompare > 0) |
| return false; |
| nCompare = GetHost(NO_DECODE).compareTo(rObject.GetHost(NO_DECODE)); |
| if (nCompare < 0) |
| return true; |
| else if (nCompare > 0) |
| return false; |
| const rtl::OUString &rPath1(GetURLPath(NO_DECODE)); |
| const rtl::OUString &rPath2(rObject.GetURLPath(NO_DECODE)); |
| nCompare = rPath1.compareTo(rPath2); |
| if (nCompare < 0) |
| return true; |
| else if (nCompare > 0) |
| return false; |
| nCompare = GetParam(NO_DECODE).compareTo(rObject.GetParam(NO_DECODE)); |
| if (nCompare < 0) |
| return true; |
| else if (nCompare > 0) |
| return false; |
| return GetMsgId(NO_DECODE).compareTo(rObject.GetMsgId(NO_DECODE)) < 0; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::ConcatData(INetProtocol eTheScheme, |
| rtl::OUString const & rTheUser, |
| rtl::OUString const & rThePassword, |
| rtl::OUString const & rTheHost, |
| sal_uInt32 nThePort, |
| rtl::OUString const & rThePath, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| setInvalid(); |
| m_eScheme = eTheScheme; |
| if (HasError() || m_eScheme == INET_PROT_GENERIC) |
| return false; |
| m_aAbsURIRef.setLength(0); |
| m_aAbsURIRef.appendAscii(getSchemeInfo().m_pScheme); |
| m_aAbsURIRef.append(sal_Unicode(':')); |
| if (getSchemeInfo().m_bAuthority) |
| { |
| m_aAbsURIRef.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| bool bUserInfo = false; |
| if (getSchemeInfo().m_bUser) |
| { |
| if (m_eScheme == INET_PROT_IMAP && rTheUser.getLength() == 0) |
| { |
| setInvalid(); |
| return false; |
| } |
| if (rTheUser.getLength() != 0) |
| { |
| m_aUser.set(m_aAbsURIRef, |
| encodeText(rTheUser, false, |
| m_eScheme == INET_PROT_IMAP ? |
| PART_IMAP_ACHAR : |
| m_eScheme == INET_PROT_VIM ? |
| PART_VIM : |
| PART_USER_PASSWORD, |
| getEscapePrefix(), eMechanism, |
| eCharset, false), |
| m_aAbsURIRef.getLength()); |
| bUserInfo = true; |
| } |
| } |
| else if (rTheUser.getLength() != 0) |
| { |
| setInvalid(); |
| return false; |
| } |
| if (rThePassword.getLength() != 0) |
| { |
| if (getSchemeInfo().m_bPassword) |
| { |
| m_aAbsURIRef.append(sal_Unicode(':')); |
| m_aAuth.set(m_aAbsURIRef, |
| encodeText(rThePassword, false, |
| m_eScheme == INET_PROT_VIM ? |
| PART_VIM : PART_USER_PASSWORD, |
| getEscapePrefix(), eMechanism, |
| eCharset, false), |
| m_aAbsURIRef.getLength()); |
| bUserInfo = true; |
| } |
| else |
| { |
| setInvalid(); |
| return false; |
| } |
| } |
| if (bUserInfo && getSchemeInfo().m_bHost) |
| m_aAbsURIRef.append(sal_Unicode('@')); |
| if (getSchemeInfo().m_bHost) |
| { |
| rtl::OUStringBuffer aSynHost(rTheHost); |
| bool bNetBiosName = false; |
| switch (m_eScheme) |
| { |
| case INET_PROT_FILE: |
| { |
| rtl::OUString sTemp(aSynHost); |
| if (sTemp.equalsIgnoreAsciiCaseAsciiL( |
| RTL_CONSTASCII_STRINGPARAM("localhost"))) |
| { |
| aSynHost.setLength(0); |
| } |
| bNetBiosName = true; |
| } |
| break; |
| |
| case INET_PROT_LDAP: |
| if (aSynHost.getLength() == 0 && nThePort != 0) |
| { |
| setInvalid(); |
| return false; |
| } |
| break; |
| |
| default: |
| if (aSynHost.getLength() == 0) |
| { |
| setInvalid(); |
| return false; |
| } |
| break; |
| } |
| if (!parseHostOrNetBiosName( |
| aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(), |
| false, eMechanism, eCharset, bNetBiosName, &aSynHost)) |
| { |
| setInvalid(); |
| return false; |
| } |
| m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear(), |
| m_aAbsURIRef.getLength()); |
| if (nThePort != 0) |
| { |
| if (getSchemeInfo().m_bPort) |
| { |
| m_aAbsURIRef.append(sal_Unicode(':')); |
| m_aPort.set(m_aAbsURIRef, |
| rtl::OUString::valueOf(sal_Int64(nThePort)), |
| m_aAbsURIRef.getLength()); |
| } |
| else |
| { |
| setInvalid(); |
| return false; |
| } |
| } |
| } |
| else if (rTheHost.getLength() != 0 || nThePort != 0) |
| { |
| setInvalid(); |
| return false; |
| } |
| } |
| rtl::OUStringBuffer aSynPath; |
| sal_Unicode const * p = rThePath.getStr(); |
| sal_Unicode const * pEnd = p + rThePath.getLength(); |
| if (!parsePath(m_eScheme, &p, pEnd, false, eMechanism, eCharset, false, '/', |
| 0x80000000, 0x80000000, 0x80000000, aSynPath) |
| || p != pEnd) |
| { |
| setInvalid(); |
| return false; |
| } |
| m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear(), |
| m_aAbsURIRef.getLength()); |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| rtl::OUString INetURLObject::GetAbsURL(rtl::OUString const & rTheBaseURIRef, |
| rtl::OUString const & rTheRelURIRef, |
| bool bIgnoreFragment, |
| EncodeMechanism eEncodeMechanism, |
| DecodeMechanism eDecodeMechanism, |
| rtl_TextEncoding eCharset, |
| FSysStyle eStyle) |
| { |
| // Backwards compatibility: |
| if (rTheRelURIRef.getLength() == 0 || rTheRelURIRef[0] == '#') |
| return rTheRelURIRef; |
| |
| INetURLObject aTheAbsURIRef; |
| bool bWasAbsolute; |
| return INetURLObject(rTheBaseURIRef, eEncodeMechanism, eCharset). |
| convertRelToAbs(rTheRelURIRef, false, aTheAbsURIRef, |
| bWasAbsolute, eEncodeMechanism, |
| eCharset, bIgnoreFragment, false, |
| false, eStyle) |
| || eEncodeMechanism != WAS_ENCODED |
| || eDecodeMechanism != DECODE_TO_IURI |
| || eCharset != RTL_TEXTENCODING_UTF8 ? |
| aTheAbsURIRef.GetMainURL(eDecodeMechanism, eCharset) : |
| rTheRelURIRef; |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::getExternalURL(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| rtl::OUString aTheExtURIRef; |
| translateToExternal( |
| rtl::OUString(m_aAbsURIRef), aTheExtURIRef, eMechanism, eCharset); |
| return aTheExtURIRef; |
| } |
| |
| //============================================================================ |
| // static |
| rtl::OUString INetURLObject::GetScheme(INetProtocol eTheScheme) |
| { |
| return rtl::OUString::createFromAscii(getSchemeInfo(eTheScheme).m_pPrefix); |
| } |
| |
| //============================================================================ |
| // static |
| INetProtocol INetURLObject::CompareProtocolScheme(rtl::OUString const & |
| rTheAbsURIRef) |
| { |
| sal_Unicode const * p = rTheAbsURIRef.getStr(); |
| PrefixInfo const * pPrefix = getPrefix(p, p + rTheAbsURIRef.getLength()); |
| return pPrefix ? pPrefix->m_eScheme : INET_PROT_NOT_VALID; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::hasPassword() const |
| { |
| return m_aAuth.isPresent() && getSchemeInfo().m_bPassword; |
| } |
| |
| //============================================================================ |
| void INetURLObject::makeAuthCanonic() |
| { |
| if (m_eScheme == INET_PROT_IMAP && m_aAuth.getLength() == 1 |
| && m_aAbsURIRef.charAt(m_aAuth.getBegin()) == '*') |
| { |
| lcl_Erase(m_aAbsURIRef, m_aAuth.getBegin() |
| - RTL_CONSTASCII_LENGTH(";AUTH="), |
| RTL_CONSTASCII_LENGTH(";AUTH=*")); |
| sal_Int32 nDelta = m_aAuth.clear() - RTL_CONSTASCII_LENGTH(";AUTH="); |
| m_aPath += nDelta; |
| m_aQuery += nDelta; |
| m_aFragment += nDelta; |
| } |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetHostPort(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| // Check because PROT_VND_SUN_STAR_HELP, PROT_VND_SUN_STAR_HIER, and |
| // PROT_VND_SUN_STAR_PKG misuse m_aHost: |
| if (!getSchemeInfo().m_bHost) |
| return rtl::OUString(); |
| rtl::OUStringBuffer aHostPort(decode(m_aHost, getEscapePrefix(), |
| eMechanism, eCharset)); |
| if (m_aPort.isPresent()) |
| { |
| aHostPort.append(sal_Unicode(':')); |
| aHostPort.append(decode(m_aPort, getEscapePrefix(), |
| eMechanism, eCharset)); |
| } |
| return aHostPort.makeStringAndClear(); |
| } |
| |
| //============================================================================ |
| sal_uInt32 INetURLObject::GetPort() const |
| { |
| if (m_aPort.isPresent()) |
| { |
| sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin(); |
| sal_Unicode const * pEnd = p + m_aPort.getLength(); |
| sal_uInt32 nThePort; |
| if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd) |
| return nThePort; |
| } |
| return 0; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::SetPort(sal_uInt32 nThePort) |
| { |
| if (getSchemeInfo().m_bPort && m_aHost.isPresent()) |
| { |
| rtl::OUString aNewPort(rtl::OUString::valueOf(sal_Int64(nThePort))); |
| sal_Int32 nDelta; |
| if (m_aPort.isPresent()) |
| nDelta = m_aPort.set(m_aAbsURIRef, aNewPort); |
| else |
| { |
| m_aAbsURIRef.insert(m_aHost.getEnd(), sal_Unicode(':')); |
| nDelta = m_aPort.set(m_aAbsURIRef, aNewPort, m_aHost.getEnd() + 1) |
| + 1; |
| } |
| m_aPath += nDelta; |
| m_aQuery += nDelta; |
| m_aFragment += nDelta; |
| return true; |
| } |
| return false; |
| } |
| |
| //============================================================================ |
| void INetURLObject::makePortCanonic() |
| { |
| if (m_aPort.isPresent()) |
| { |
| sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPort.getBegin(); |
| sal_Unicode const * pEnd = p + m_aPort.getLength(); |
| sal_uInt32 nThePort; |
| if (INetMIME::scanUnsigned(p, pEnd, true, nThePort) && p == pEnd) |
| { |
| sal_Int32 nDelta; |
| if (nThePort != 0 && nThePort == getSchemeInfo().m_nDefaultPort) |
| { |
| lcl_Erase(m_aAbsURIRef, m_aPort.getBegin() - 1, |
| m_aPort.getLength() + 1); |
| nDelta = m_aPort.clear() - 1; |
| } |
| else |
| nDelta = m_aPort.set(m_aAbsURIRef, |
| rtl::OUString::valueOf(sal_Int64(nThePort))); |
| m_aPath += nDelta; |
| m_aQuery += nDelta; |
| m_aFragment += nDelta; |
| } |
| } |
| } |
| |
| //============================================================================ |
| sal_Int32 INetURLObject::getSegmentCount(bool bIgnoreFinalSlash) const |
| { |
| if (!checkHierarchical()) |
| return 0; |
| |
| sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pEnd = p + m_aPath.getLength(); |
| if (bIgnoreFinalSlash && pEnd > p && pEnd[-1] == '/') |
| --pEnd; |
| sal_Int32 n = p == pEnd || *p == '/' ? 0 : 1; |
| while (p != pEnd) |
| if (*p++ == '/') |
| ++n; |
| return n; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::removeSegment(sal_Int32 nIndex, bool bIgnoreFinalSlash) |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return false; |
| |
| rtl::OUStringBuffer aNewPath; |
| aNewPath.append(m_aAbsURIRef.getStr() + m_aPath.getBegin(), |
| aSegment.getBegin() - m_aPath.getBegin()); |
| if (bIgnoreFinalSlash && aSegment.getEnd() == m_aPath.getEnd()) |
| aNewPath.append(sal_Unicode('/')); |
| else |
| aNewPath.append(m_aAbsURIRef.getStr() + aSegment.getEnd(), |
| m_aPath.getEnd() - aSegment.getEnd()); |
| if (aNewPath.getLength() == 0 && !aSegment.isEmpty() && |
| m_aAbsURIRef[aSegment.getBegin()] == '/') |
| { |
| aNewPath.append(sal_Unicode('/')); |
| } |
| |
| return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::getName(sal_Int32 nIndex, bool bIgnoreFinalSlash, |
| DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return rtl::OUString(); |
| |
| sal_Unicode const * pSegBegin |
| = m_aAbsURIRef.getStr() + aSegment.getBegin(); |
| sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); |
| |
| if (pSegBegin < pSegEnd && *pSegBegin == '/') |
| ++pSegBegin; |
| sal_Unicode const * p = pSegBegin; |
| while (p != pSegEnd && *p != ';') |
| ++p; |
| |
| return decode(pSegBegin, p, getEscapePrefix(), eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setName(rtl::OUString const & rTheName, sal_Int32 nIndex, |
| bool bIgnoreFinalSlash, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return false; |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| sal_Unicode const * pSegBegin |
| = m_aAbsURIRef.getStr() + aSegment.getBegin(); |
| sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); |
| |
| if (pSegBegin < pSegEnd && *pSegBegin == '/') |
| ++pSegBegin; |
| sal_Unicode const * p = pSegBegin; |
| while (p != pSegEnd && *p != ';') |
| ++p; |
| |
| rtl::OUStringBuffer aNewPath; |
| aNewPath.append(pPathBegin, pSegBegin - pPathBegin); |
| aNewPath.append(encodeText(rTheName, false, PART_PCHAR, getEscapePrefix(), |
| eMechanism, eCharset, true)); |
| aNewPath.append(p, pPathEnd - p); |
| |
| return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::hasExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash) |
| const |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return false; |
| |
| sal_Unicode const * pSegBegin |
| = m_aAbsURIRef.getStr() + aSegment.getBegin(); |
| sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); |
| |
| if (pSegBegin < pSegEnd && *pSegBegin == '/') |
| ++pSegBegin; |
| for (sal_Unicode const * p = pSegBegin; p != pSegEnd && *p != ';'; ++p) |
| if (*p == '.' && p != pSegBegin) |
| return true; |
| return false; |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::getBase(sal_Int32 nIndex, bool bIgnoreFinalSlash, |
| DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return rtl::OUString(); |
| |
| sal_Unicode const * pSegBegin |
| = m_aAbsURIRef.getStr() + aSegment.getBegin(); |
| sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); |
| |
| if (pSegBegin < pSegEnd && *pSegBegin == '/') |
| ++pSegBegin; |
| sal_Unicode const * pExtension = 0; |
| sal_Unicode const * p = pSegBegin; |
| for (; p != pSegEnd && *p != ';'; ++p) |
| if (*p == '.' && p != pSegBegin) |
| pExtension = p; |
| if (!pExtension) |
| pExtension = p; |
| |
| return decode(pSegBegin, pExtension, getEscapePrefix(), eMechanism, |
| eCharset); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setBase(rtl::OUString const & rTheBase, sal_Int32 nIndex, |
| bool bIgnoreFinalSlash, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return false; |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| sal_Unicode const * pSegBegin |
| = m_aAbsURIRef.getStr() + aSegment.getBegin(); |
| sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); |
| |
| if (pSegBegin < pSegEnd && *pSegBegin == '/') |
| ++pSegBegin; |
| sal_Unicode const * pExtension = 0; |
| sal_Unicode const * p = pSegBegin; |
| for (; p != pSegEnd && *p != ';'; ++p) |
| if (*p == '.' && p != pSegBegin) |
| pExtension = p; |
| if (!pExtension) |
| pExtension = p; |
| |
| rtl::OUStringBuffer aNewPath; |
| aNewPath.append(pPathBegin, pSegBegin - pPathBegin); |
| aNewPath.append(encodeText(rTheBase, false, PART_PCHAR, getEscapePrefix(), |
| eMechanism, eCharset, true)); |
| aNewPath.append(pExtension, pPathEnd - pExtension); |
| |
| return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::getExtension(sal_Int32 nIndex, |
| bool bIgnoreFinalSlash, |
| DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return rtl::OUString(); |
| |
| sal_Unicode const * pSegBegin |
| = m_aAbsURIRef.getStr() + aSegment.getBegin(); |
| sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); |
| |
| if (pSegBegin < pSegEnd && *pSegBegin == '/') |
| ++pSegBegin; |
| sal_Unicode const * pExtension = 0; |
| sal_Unicode const * p = pSegBegin; |
| for (; p != pSegEnd && *p != ';'; ++p) |
| if (*p == '.' && p != pSegBegin) |
| pExtension = p; |
| |
| if (!pExtension) |
| return rtl::OUString(); |
| |
| return decode(pExtension + 1, p, getEscapePrefix(), eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setExtension(rtl::OUString const & rTheExtension, |
| sal_Int32 nIndex, bool bIgnoreFinalSlash, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return false; |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| sal_Unicode const * pSegBegin |
| = m_aAbsURIRef.getStr() + aSegment.getBegin(); |
| sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); |
| |
| if (pSegBegin < pSegEnd && *pSegBegin == '/') |
| ++pSegBegin; |
| sal_Unicode const * pExtension = 0; |
| sal_Unicode const * p = pSegBegin; |
| for (; p != pSegEnd && *p != ';'; ++p) |
| if (*p == '.' && p != pSegBegin) |
| pExtension = p; |
| if (!pExtension) |
| pExtension = p; |
| |
| rtl::OUStringBuffer aNewPath; |
| aNewPath.append(pPathBegin, pExtension - pPathBegin); |
| aNewPath.append(sal_Unicode('.')); |
| aNewPath.append(encodeText(rTheExtension, false, PART_PCHAR, |
| getEscapePrefix(), eMechanism, eCharset, true)); |
| aNewPath.append(p, pPathEnd - p); |
| |
| return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::removeExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash) |
| { |
| SubString aSegment(getSegment(nIndex, bIgnoreFinalSlash)); |
| if (!aSegment.isPresent()) |
| return false; |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| sal_Unicode const * pSegBegin |
| = m_aAbsURIRef.getStr() + aSegment.getBegin(); |
| sal_Unicode const * pSegEnd = pSegBegin + aSegment.getLength(); |
| |
| if (pSegBegin < pSegEnd && *pSegBegin == '/') |
| ++pSegBegin; |
| sal_Unicode const * pExtension = 0; |
| sal_Unicode const * p = pSegBegin; |
| for (; p != pSegEnd && *p != ';'; ++p) |
| if (*p == '.' && p != pSegBegin) |
| pExtension = p; |
| if (!pExtension) |
| return true; |
| |
| rtl::OUStringBuffer aNewPath; |
| aNewPath.append(pPathBegin, pExtension - pPathBegin); |
| aNewPath.append(p, pPathEnd - p); |
| |
| return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::hasFinalSlash() const |
| { |
| if (!checkHierarchical()) |
| return false; |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| return pPathEnd > pPathBegin && pPathEnd[-1] == '/'; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setFinalSlash() |
| { |
| if (!checkHierarchical()) |
| return false; |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| if (pPathEnd > pPathBegin && pPathEnd[-1] == '/') |
| return true; |
| |
| rtl::OUStringBuffer aNewPath; |
| aNewPath.append(pPathBegin, pPathEnd - pPathBegin); |
| aNewPath.append(sal_Unicode('/')); |
| |
| return setPath(aNewPath.makeStringAndClear(), false, NOT_CANONIC, |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::removeFinalSlash() |
| { |
| if (!checkHierarchical()) |
| return false; |
| |
| sal_Unicode const * pPathBegin |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pPathEnd = pPathBegin + m_aPath.getLength(); |
| if (pPathEnd <= pPathBegin || pPathEnd[-1] != '/') |
| return true; |
| |
| --pPathEnd; |
| if (pPathEnd == pPathBegin && *pPathBegin == '/') |
| return false; |
| rtl::OUString aNewPath(pPathBegin, pPathEnd - pPathBegin); |
| |
| return setPath(aNewPath, false, NOT_CANONIC, RTL_TEXTENCODING_UTF8); |
| } |
| |
| //============================================================================ |
| // static |
| rtl::OUString INetURLObject::createFragment(rtl::OUString const & rText) |
| { |
| rtl::OUString aFragment(rText); |
| for (sal_Int32 i = 0; i < aFragment.getLength();) |
| { |
| sal_Unicode c = aFragment.getStr()[i]; |
| if (mustEncode(c, PART_CREATEFRAGMENT)) |
| aFragment = aFragment.replaceAt(i, 1, rtl::OUString()); |
| else |
| ++i; |
| } |
| return aFragment; |
| } |
| |
| //============================================================================ |
| bool INetURLObject::setFSysPath(rtl::OUString const & rFSysPath, |
| FSysStyle eStyle) |
| { |
| sal_Unicode const * pFSysBegin = rFSysPath.getStr(); |
| sal_Unicode const * pFSysEnd = pFSysBegin + rFSysPath.getLength(); |
| |
| switch ((eStyle & FSYS_VOS ? 1 : 0) |
| + (eStyle & FSYS_UNX ? 1 : 0) |
| + (eStyle & FSYS_DOS ? 1 : 0) |
| + (eStyle & FSYS_MAC ? 1 : 0)) |
| { |
| case 0: |
| return false; |
| |
| case 1: |
| break; |
| |
| default: |
| if (eStyle & FSYS_VOS |
| && pFSysEnd - pFSysBegin >= 2 |
| && pFSysBegin[0] == '/' |
| && pFSysBegin[1] == '/') |
| { |
| if (pFSysEnd - pFSysBegin >= 3 |
| && pFSysBegin[2] == '.' |
| && (pFSysEnd - pFSysBegin == 3 || pFSysBegin[3] == '/')) |
| { |
| eStyle = FSYS_VOS; // Production T1 |
| break; |
| } |
| |
| sal_Unicode const * p = pFSysBegin + 2; |
| rtl::OUString aHost; |
| if (parseHost(p, pFSysEnd, aHost) |
| && (p == pFSysEnd || *p == '/')) |
| { |
| eStyle = FSYS_VOS; // Production T2 |
| break; |
| } |
| } |
| |
| if (eStyle & FSYS_DOS |
| && pFSysEnd - pFSysBegin >= 2 |
| && pFSysBegin[0] == '\\' |
| && pFSysBegin[1] == '\\') |
| { |
| sal_Unicode const * p = pFSysBegin + 2; |
| rtl::OUString aHost; |
| if (parseHost(p, pFSysEnd, aHost) |
| && (p == pFSysEnd || *p == '\\')) |
| { |
| eStyle = FSYS_DOS; // Production T3 |
| break; |
| } |
| } |
| |
| if (eStyle & FSYS_DOS |
| && pFSysEnd - pFSysBegin >= 2 |
| && INetMIME::isAlpha(pFSysBegin[0]) |
| && pFSysBegin[1] == ':' |
| && (pFSysEnd - pFSysBegin == 2 |
| || pFSysBegin[2] == '/' |
| || pFSysBegin[2] == '\\')) |
| { |
| eStyle = FSYS_DOS; // Productions T4, T5 |
| break; |
| } |
| |
| if (!(eStyle & (FSYS_UNX | FSYS_DOS | FSYS_MAC))) |
| return false; |
| |
| eStyle = guessFSysStyleByCounting(pFSysBegin, pFSysEnd, eStyle); |
| // Production T6 |
| break; |
| } |
| |
| rtl::OUStringBuffer aSynAbsURIRef(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("file://"))); |
| |
| switch (eStyle) |
| { |
| case FSYS_VOS: |
| { |
| sal_Unicode const * p = pFSysBegin; |
| if (pFSysEnd - p < 2 || *p++ != '/' || *p++ != '/') |
| return false; |
| if (p != pFSysEnd && *p == '.' |
| && (pFSysEnd - p == 1 || p[1] == '/')) |
| ++p; |
| for (; p != pFSysEnd; ++p) |
| switch (*p) |
| { |
| case '#': |
| case '%': |
| appendEscape(aSynAbsURIRef, '%', *p); |
| break; |
| |
| default: |
| aSynAbsURIRef.append(*p); |
| break; |
| } |
| break; |
| } |
| |
| case FSYS_UNX: |
| { |
| sal_Unicode const * p = pFSysBegin; |
| if (p != pFSysEnd && *p != '/') |
| return false; |
| for (; p != pFSysEnd; ++p) |
| switch (*p) |
| { |
| case '|': |
| case '#': |
| case '%': |
| appendEscape(aSynAbsURIRef, '%', *p); |
| break; |
| |
| default: |
| aSynAbsURIRef.append(*p); |
| break; |
| } |
| break; |
| } |
| |
| case FSYS_DOS: |
| { |
| sal_uInt32 nAltDelimiter = 0x80000000; |
| sal_Unicode const * p = pFSysBegin; |
| if (pFSysEnd - p >= 3 && p[0] == '\\' && p[1] == '\\') |
| p += 2; |
| else |
| { |
| aSynAbsURIRef.append(sal_Unicode('/')); |
| if (pFSysEnd - p >= 2 |
| && INetMIME::isAlpha(p[0]) |
| && p[1] == ':' |
| && (pFSysEnd - p == 2 || p[2] == '\\' || p[2] == '/')) |
| nAltDelimiter = '/'; |
| } |
| for (; p != pFSysEnd; ++p) |
| if (*p == '\\' || *p == nAltDelimiter) |
| aSynAbsURIRef.append(sal_Unicode('/')); |
| else |
| switch (*p) |
| { |
| case '/': |
| case '#': |
| case '%': |
| appendEscape(aSynAbsURIRef, '%', *p); |
| break; |
| |
| default: |
| aSynAbsURIRef.append(*p); |
| break; |
| } |
| break; |
| } |
| |
| case FSYS_MAC: |
| aSynAbsURIRef.append(sal_Unicode('/')); |
| {for (sal_Unicode const * p = pFSysBegin; p != pFSysEnd; ++p) |
| switch (*p) |
| { |
| case ':': |
| aSynAbsURIRef.append(sal_Unicode('/')); |
| break; |
| |
| case '/': |
| case '|': |
| case '#': |
| case '%': |
| appendEscape(aSynAbsURIRef, '%', *p); |
| break; |
| |
| default: |
| aSynAbsURIRef.append(*p); |
| break; |
| } |
| } |
| break; |
| |
| default: |
| OSL_ASSERT(false); |
| break; |
| } |
| |
| INetURLObject aTemp(aSynAbsURIRef.makeStringAndClear(), WAS_ENCODED, |
| RTL_TEXTENCODING_UTF8); |
| if (aTemp.HasError()) |
| return false; |
| |
| *this = aTemp; |
| return true; |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::getFSysPath(FSysStyle eStyle, |
| sal_Unicode * pDelimiter) const |
| { |
| if (m_eScheme != INET_PROT_FILE) |
| return rtl::OUString(); |
| |
| if ((eStyle & FSYS_VOS ? 1 : 0) |
| + (eStyle & FSYS_UNX ? 1 : 0) |
| + (eStyle & FSYS_DOS ? 1 : 0) |
| + (eStyle & FSYS_MAC ? 1 : 0) |
| > 1) |
| { |
| eStyle = eStyle & FSYS_VOS |
| && m_aHost.isPresent() |
| && m_aHost.getLength() > 0 ? |
| FSYS_VOS : |
| hasDosVolume(eStyle) |
| || ((eStyle & FSYS_DOS) != 0 |
| && m_aHost.isPresent() |
| && m_aHost.getLength() > 0) ? |
| FSYS_DOS : |
| eStyle & FSYS_UNX |
| && (!m_aHost.isPresent() || m_aHost.getLength() == 0) ? |
| FSYS_UNX : |
| FSysStyle(0); |
| } |
| |
| switch (eStyle) |
| { |
| case FSYS_VOS: |
| { |
| if (pDelimiter) |
| *pDelimiter = '/'; |
| |
| rtl::OUStringBuffer aSynFSysPath; |
| aSynFSysPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); |
| if (m_aHost.isPresent() && m_aHost.getLength() > 0) |
| aSynFSysPath.append(decode(m_aHost, '%', DECODE_WITH_CHARSET, |
| RTL_TEXTENCODING_UTF8)); |
| else |
| aSynFSysPath.append(sal_Unicode('.')); |
| aSynFSysPath.append(decode(m_aPath, '%', DECODE_WITH_CHARSET, |
| RTL_TEXTENCODING_UTF8)); |
| return aSynFSysPath.makeStringAndClear(); |
| } |
| |
| case FSYS_UNX: |
| { |
| if (m_aHost.isPresent() && m_aHost.getLength() > 0) |
| return rtl::OUString(); |
| |
| if (pDelimiter) |
| *pDelimiter = '/'; |
| |
| return decode(m_aPath, '%', DECODE_WITH_CHARSET, |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| case FSYS_DOS: |
| { |
| if (pDelimiter) |
| *pDelimiter = '\\'; |
| |
| rtl::OUStringBuffer aSynFSysPath; |
| if (m_aHost.isPresent() && m_aHost.getLength() > 0) |
| { |
| aSynFSysPath.appendAscii(RTL_CONSTASCII_STRINGPARAM("\\\\")); |
| aSynFSysPath.append(decode(m_aHost, '%', DECODE_WITH_CHARSET, |
| RTL_TEXTENCODING_UTF8)); |
| aSynFSysPath.append(sal_Unicode('\\')); |
| } |
| sal_Unicode const * p |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pEnd = p + m_aPath.getLength(); |
| DBG_ASSERT(p < pEnd && *p == '/', |
| "INetURLObject::getFSysPath(): Bad path"); |
| ++p; |
| while (p < pEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(p, pEnd, false, '%', WAS_ENCODED, |
| RTL_TEXTENCODING_UTF8, |
| eEscapeType); |
| if (eEscapeType == ESCAPE_NO && nUTF32 == '/') |
| aSynFSysPath.append(sal_Unicode('\\')); |
| else |
| aSynFSysPath.appendUtf32(nUTF32); |
| } |
| return aSynFSysPath.makeStringAndClear(); |
| } |
| |
| case FSYS_MAC: |
| { |
| if (m_aHost.isPresent() && m_aHost.getLength() > 0) |
| return rtl::OUString(); |
| |
| if (pDelimiter) |
| *pDelimiter = ':'; |
| |
| rtl::OUStringBuffer aSynFSysPath; |
| sal_Unicode const * p |
| = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pEnd = p + m_aPath.getLength(); |
| DBG_ASSERT(p < pEnd && *p == '/', |
| "INetURLObject::getFSysPath(): Bad path"); |
| ++p; |
| while (p < pEnd) |
| { |
| EscapeType eEscapeType; |
| sal_uInt32 nUTF32 = getUTF32(p, pEnd, false, '%', WAS_ENCODED, |
| RTL_TEXTENCODING_UTF8, |
| eEscapeType); |
| if (eEscapeType == ESCAPE_NO && nUTF32 == '/') |
| aSynFSysPath.append(sal_Unicode(':')); |
| else |
| aSynFSysPath.appendUtf32(nUTF32); |
| } |
| return aSynFSysPath.makeStringAndClear(); |
| } |
| |
| default: |
| return rtl::OUString(); |
| } |
| } |
| |
| //============================================================================ |
| bool INetURLObject::HasMsgId() const |
| { |
| if (m_eScheme != INET_PROT_POP3) |
| return false; |
| sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pEnd = p + m_aPath.getLength(); |
| for (; p < pEnd; ++p) |
| if (*p == '<') |
| return true; |
| return false; |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetMsgId(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| if (m_eScheme != INET_PROT_POP3) |
| return rtl::OUString(); |
| sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); |
| sal_Unicode const * pEnd = p + m_aPath.getLength(); |
| for (; p < pEnd; ++p) |
| if (*p == '<') |
| return decode(p, pEnd, getEscapePrefix(), eMechanism, eCharset); |
| return rtl::OUString(); |
| } |
| |
| //============================================================================ |
| // static |
| void INetURLObject::appendUCS4Escape(rtl::OUStringBuffer & rTheText, |
| sal_Char cEscapePrefix, sal_uInt32 nUCS4) |
| { |
| DBG_ASSERT(nUCS4 < 0x80000000, |
| "INetURLObject::appendUCS4Escape(): Bad char"); |
| if (nUCS4 < 0x80) |
| appendEscape(rTheText, cEscapePrefix, nUCS4); |
| else if (nUCS4 < 0x800) |
| { |
| appendEscape(rTheText, cEscapePrefix, nUCS4 >> 6 | 0xC0); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); |
| } |
| else if (nUCS4 < 0x10000) |
| { |
| appendEscape(rTheText, cEscapePrefix, nUCS4 >> 12 | 0xE0); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); |
| } |
| else if (nUCS4 < 0x200000) |
| { |
| appendEscape(rTheText, cEscapePrefix, nUCS4 >> 18 | 0xF0); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); |
| } |
| else if (nUCS4 < 0x4000000) |
| { |
| appendEscape(rTheText, cEscapePrefix, nUCS4 >> 24 | 0xF8); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 18 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); |
| } |
| else |
| { |
| appendEscape(rTheText, cEscapePrefix, nUCS4 >> 30 | 0xFC); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 24 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 18 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 12 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 >> 6 & 0x3F) | 0x80); |
| appendEscape(rTheText, cEscapePrefix, (nUCS4 & 0x3F) | 0x80); |
| } |
| } |
| |
| //============================================================================ |
| // static |
| void INetURLObject::appendUCS4(rtl::OUStringBuffer& rTheText, sal_uInt32 nUCS4, |
| EscapeType eEscapeType, bool bOctets, |
| Part ePart, sal_Char cEscapePrefix, |
| rtl_TextEncoding eCharset, |
| bool bKeepVisibleEscapes) |
| { |
| bool bEscape; |
| rtl_TextEncoding eTargetCharset = RTL_TEXTENCODING_DONTKNOW; |
| switch (eEscapeType) |
| { |
| case ESCAPE_NO: |
| if (mustEncode(nUCS4, ePart)) |
| { |
| bEscape = true; |
| eTargetCharset = bOctets ? RTL_TEXTENCODING_ISO_8859_1 : |
| RTL_TEXTENCODING_UTF8; |
| } |
| else |
| bEscape = false; |
| break; |
| |
| case ESCAPE_OCTET: |
| bEscape = true; |
| eTargetCharset = RTL_TEXTENCODING_ISO_8859_1; |
| break; |
| |
| case ESCAPE_UTF32: |
| if (mustEncode(nUCS4, ePart)) |
| { |
| bEscape = true; |
| eTargetCharset = eCharset; |
| } |
| else if (bKeepVisibleEscapes && INetMIME::isVisible(nUCS4)) |
| { |
| bEscape = true; |
| eTargetCharset = RTL_TEXTENCODING_ASCII_US; |
| } |
| else |
| bEscape = false; |
| break; |
| default: |
| bEscape = false; |
| } |
| |
| if (bEscape) |
| { |
| switch (eTargetCharset) |
| { |
| default: |
| DBG_ERROR("INetURLObject::appendUCS4(): Unsupported charset"); |
| case RTL_TEXTENCODING_ASCII_US: |
| case RTL_TEXTENCODING_ISO_8859_1: |
| appendEscape(rTheText, cEscapePrefix, nUCS4); |
| break; |
| |
| case RTL_TEXTENCODING_UTF8: |
| appendUCS4Escape(rTheText, cEscapePrefix, nUCS4); |
| break; |
| } |
| } |
| else |
| rTheText.append(sal_Unicode(nUCS4)); |
| } |
| |
| //============================================================================ |
| // static |
| sal_uInt32 INetURLObject::getUTF32(sal_Unicode const *& rBegin, |
| sal_Unicode const * pEnd, bool bOctets, |
| sal_Char cEscapePrefix, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset, |
| EscapeType & rEscapeType) |
| { |
| DBG_ASSERT(rBegin < pEnd, "INetURLObject::getUTF32(): Bad sequence"); |
| sal_uInt32 nUTF32 = bOctets ? *rBegin++ : |
| INetMIME::getUTF32Character(rBegin, pEnd); |
| switch (eMechanism) |
| { |
| case ENCODE_ALL: |
| rEscapeType = ESCAPE_NO; |
| break; |
| |
| case WAS_ENCODED: |
| { |
| int nWeight1; |
| int nWeight2; |
| if (nUTF32 == sal_uChar(cEscapePrefix) && rBegin + 1 < pEnd |
| && (nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0 |
| && (nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0) |
| { |
| rBegin += 2; |
| nUTF32 = nWeight1 << 4 | nWeight2; |
| switch (eCharset) |
| { |
| default: |
| DBG_ERROR( |
| "INetURLObject::getUTF32(): Unsupported charset"); |
| case RTL_TEXTENCODING_ASCII_US: |
| rEscapeType = INetMIME::isUSASCII(nUTF32) ? |
| ESCAPE_UTF32 : ESCAPE_OCTET; |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_1: |
| rEscapeType = ESCAPE_UTF32; |
| break; |
| |
| case RTL_TEXTENCODING_UTF8: |
| if (INetMIME::isUSASCII(nUTF32)) |
| rEscapeType = ESCAPE_UTF32; |
| else |
| { |
| if (nUTF32 >= 0xC0 && nUTF32 <= 0xF4) |
| { |
| sal_uInt32 nEncoded; |
| int nShift; |
| sal_uInt32 nMin; |
| if (nUTF32 <= 0xDF) |
| { |
| nEncoded = (nUTF32 & 0x1F) << 6; |
| nShift = 0; |
| nMin = 0x80; |
| } |
| else if (nUTF32 <= 0xEF) |
| { |
| nEncoded = (nUTF32 & 0x0F) << 12; |
| nShift = 6; |
| nMin = 0x800; |
| } |
| else |
| { |
| nEncoded = (nUTF32 & 0x07) << 18; |
| nShift = 12; |
| nMin = 0x10000; |
| } |
| sal_Unicode const * p = rBegin; |
| bool bUTF8 = true; |
| for (;;) |
| { |
| if (pEnd - p < 3 |
| || p[0] != cEscapePrefix |
| || (nWeight1 |
| = INetMIME::getHexWeight(p[1])) |
| < 8 |
| || nWeight1 > 11 |
| || (nWeight2 |
| = INetMIME::getHexWeight(p[2])) |
| < 0) |
| { |
| bUTF8 = false; |
| break; |
| } |
| p += 3; |
| nEncoded |
| |= ((nWeight1 & 3) << 4 | nWeight2) |
| << nShift; |
| if (nShift == 0) |
| break; |
| nShift -= 6; |
| } |
| if (bUTF8 && nEncoded >= nMin |
| && !INetMIME::isHighSurrogate(nEncoded) |
| && !INetMIME::isLowSurrogate(nEncoded) |
| && nEncoded <= 0x10FFFF) |
| { |
| rBegin = p; |
| nUTF32 = nEncoded; |
| rEscapeType = ESCAPE_UTF32; |
| break; |
| } |
| } |
| rEscapeType = ESCAPE_OCTET; |
| } |
| break; |
| } |
| } |
| else |
| rEscapeType = ESCAPE_NO; |
| break; |
| } |
| |
| case NOT_CANONIC: |
| { |
| int nWeight1; |
| int nWeight2; |
| if (nUTF32 == sal_uChar(cEscapePrefix) && rBegin + 1 < pEnd |
| && ((nWeight1 = INetMIME::getHexWeight(rBegin[0])) >= 0) |
| && ((nWeight2 = INetMIME::getHexWeight(rBegin[1])) >= 0)) |
| { |
| rBegin += 2; |
| nUTF32 = nWeight1 << 4 | nWeight2; |
| rEscapeType = ESCAPE_OCTET; |
| } |
| else |
| rEscapeType = ESCAPE_NO; |
| break; |
| } |
| } |
| return nUTF32; |
| } |
| |
| //============================================================================ |
| // static |
| sal_uInt32 INetURLObject::scanDomain(sal_Unicode const *& rBegin, |
| sal_Unicode const * pEnd, |
| bool bEager) |
| { |
| enum State { STATE_DOT, STATE_LABEL, STATE_HYPHEN }; |
| State eState = STATE_DOT; |
| sal_Int32 nLabels = 0; |
| sal_Unicode const * pLastAlphanumeric = 0; |
| for (sal_Unicode const * p = rBegin;; ++p) |
| switch (eState) |
| { |
| case STATE_DOT: |
| if (p != pEnd && INetMIME::isAlphanumeric(*p)) |
| { |
| ++nLabels; |
| eState = STATE_LABEL; |
| break; |
| } |
| if (bEager || nLabels == 0) |
| return 0; |
| rBegin = p - 1; |
| return nLabels; |
| |
| case STATE_LABEL: |
| if (p != pEnd) |
| { |
| if (INetMIME::isAlphanumeric(*p)) |
| break; |
| else if (*p == '.') |
| { |
| eState = STATE_DOT; |
| break; |
| } |
| else if (*p == '-') |
| { |
| pLastAlphanumeric = p; |
| eState = STATE_HYPHEN; |
| break; |
| } |
| } |
| rBegin = p; |
| return nLabels; |
| |
| case STATE_HYPHEN: |
| if (p != pEnd) |
| { |
| if (INetMIME::isAlphanumeric(*p)) |
| { |
| eState = STATE_LABEL; |
| break; |
| } |
| else if (*p == '-') |
| break; |
| } |
| if (bEager) |
| return 0; |
| rBegin = pLastAlphanumeric; |
| return nLabels; |
| } |
| } |
| |
| //============================================================================ |
| // static |
| bool INetURLObject::scanIPv6reference(sal_Unicode const *& rBegin, |
| sal_Unicode const * pEnd) |
| { |
| if (rBegin != pEnd && *rBegin == '[') { |
| sal_Unicode const * p = rBegin + 1; |
| //TODO: check for valid IPv6address (RFC 2373): |
| while (p != pEnd && (INetMIME::isHexDigit(*p) || *p == ':' || *p == '.')) |
| { |
| ++p; |
| } |
| if (p != pEnd && *p == ']') { |
| rBegin = p + 1; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetPartBeforeLastName(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| const |
| { |
| if (!checkHierarchical()) |
| return rtl::OUString(); |
| INetURLObject aTemp(*this); |
| aTemp.clearFragment(); |
| aTemp.clearQuery(); |
| aTemp.removeSegment(LAST_SEGMENT, false); |
| aTemp.setFinalSlash(); |
| return aTemp.GetMainURL(eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetLastName(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| return getName(LAST_SEGMENT, true, eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetFileExtension(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) const |
| { |
| return getExtension(LAST_SEGMENT, false, eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::CutLastName() |
| { |
| INetURLObject aTemp(*this); |
| aTemp.clearFragment(); |
| aTemp.clearQuery(); |
| if (!aTemp.removeSegment(LAST_SEGMENT, false)) |
| return false; |
| *this = aTemp; |
| return true; |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::PathToFileName() const |
| { |
| if (m_eScheme != INET_PROT_FILE) |
| return rtl::OUString(); |
| rtl::OUString aSystemPath; |
| if (osl::FileBase::getSystemPathFromFileURL( |
| decode(m_aAbsURIRef.getStr(), |
| m_aAbsURIRef.getStr() + m_aPath.getEnd(), |
| getEscapePrefix(), NO_DECODE, RTL_TEXTENCODING_UTF8), |
| aSystemPath) |
| != osl::FileBase::E_None) |
| return rtl::OUString(); |
| return aSystemPath; |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetFull() const |
| { |
| INetURLObject aTemp(*this); |
| aTemp.removeFinalSlash(); |
| return aTemp.PathToFileName(); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetPath() const |
| { |
| INetURLObject aTemp(*this); |
| aTemp.removeSegment(LAST_SEGMENT, true); |
| aTemp.removeFinalSlash(); |
| return aTemp.PathToFileName(); |
| } |
| |
| //============================================================================ |
| void INetURLObject::SetBase(rtl::OUString const & rTheBase) |
| { |
| setBase(rTheBase, LAST_SEGMENT, true, ENCODE_ALL); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::GetBase() const |
| { |
| return getBase(LAST_SEGMENT, true, DECODE_WITH_CHARSET); |
| } |
| |
| //============================================================================ |
| void INetURLObject::SetName(rtl::OUString const & rTheName, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| INetURLObject aTemp(*this); |
| if (aTemp.removeSegment(LAST_SEGMENT, true) |
| && aTemp.insertName(rTheName, false, LAST_SEGMENT, true, eMechanism, |
| eCharset)) |
| *this = aTemp; |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::CutName(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| rtl::OUString aTheName(getName(LAST_SEGMENT, true, eMechanism, eCharset)); |
| return removeSegment(LAST_SEGMENT, true) ? aTheName : rtl::OUString(); |
| } |
| |
| //============================================================================ |
| void INetURLObject::SetExtension(rtl::OUString const & rTheExtension, |
| EncodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| setExtension(rTheExtension, LAST_SEGMENT, false, eMechanism, eCharset); |
| } |
| |
| //============================================================================ |
| rtl::OUString INetURLObject::CutExtension(DecodeMechanism eMechanism, |
| rtl_TextEncoding eCharset) |
| { |
| rtl::OUString aTheExtension(getExtension(LAST_SEGMENT, false, eMechanism, |
| eCharset)); |
| return removeExtension(LAST_SEGMENT, false) |
| ? aTheExtension : rtl::OUString(); |
| } |
| |
| //============================================================================ |
| bool INetURLObject::IsCaseSensitive() const |
| { |
| return true; |
| } |