tools/qa/cppunit/test_urlobj.cxx |   20 ++++++++
 tools/source/fsys/urlobj.cxx     |   94 +++++++++++++++++++++++++++++++--------
 2 files changed, 97 insertions(+), 17 deletions(-)

New commits:
commit 9f1289f1e3c9b4a5f2be7a7187877db6b5015973
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Nov 1 00:37:19 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Wed Nov 1 10:24:21 2023 +0100

    tdf#157820: handle \\?\ prefixes in INetURLObject
    
    They are already handled in osl file URL functions.
    
    Change-Id: Id0c224bdb79963e7ce52abde57bf05b0a6a81ff5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158741
    Reviewed-by: Stephan Bergmann <sberg...@redhat.com>
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/tools/qa/cppunit/test_urlobj.cxx b/tools/qa/cppunit/test_urlobj.cxx
index 2c8ae1a36a25..fff77e41f5e7 100644
--- a/tools/qa/cppunit/test_urlobj.cxx
+++ b/tools/qa/cppunit/test_urlobj.cxx
@@ -332,6 +332,26 @@ namespace tools_urlobj
                 CPPUNIT_ASSERT_EQUAL(OUString(""), obj.GetHost());
                 CPPUNIT_ASSERT_EQUAL(OUString("80a0/foo"), obj.GetURLPath());
             }
+            {
+                // Test Windows \\?\C:... long path scheme
+                INetURLObject base(u"file:///C:/foo"); // set up base path
+                bool bWasAbsolute = false;
+                INetURLObject obj
+                    = base.smartRel2Abs(u"\\\\?\\D:\\bar\\baz.ext"_ustr, 
bWasAbsolute);
+                CPPUNIT_ASSERT(bWasAbsolute);
+                CPPUNIT_ASSERT_EQUAL(u"file:///D:/bar/baz.ext"_ustr,
+                                     
obj.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+            }
+            {
+                // Test Windows \\?\UNC\Server... long path scheme
+                INetURLObject base(u"file://ServerFoo/fooShare"); // set up 
base path
+                bool bWasAbsolute = false;
+                INetURLObject obj = base.smartRel2Abs(
+                    u"\\\\?\\UNC\\ServerBar\\barShare\\baz.ext"_ustr, 
bWasAbsolute);
+                CPPUNIT_ASSERT(bWasAbsolute);
+                CPPUNIT_ASSERT_EQUAL(u"file://ServerBar/barShare/baz.ext"_ustr,
+                                     
obj.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+            }
         }
 
         // Change the following lines only, if you add, remove or rename
diff --git a/tools/source/fsys/urlobj.cxx b/tools/source/fsys/urlobj.cxx
index 3c54eea3d664..a97af83bad81 100644
--- a/tools/source/fsys/urlobj.cxx
+++ b/tools/source/fsys/urlobj.cxx
@@ -809,6 +809,17 @@ bool INetURLObject::setAbsURIRef(std::u16string_view 
rTheAbsURIRef,
                 eMechanism = EncodeMechanism::All;
                 nFragmentDelimiter = 0x80000000;
             }
+            else if (eStyle & FSysStyle::Dos
+                && pEnd - p1 >= 6
+                && p1[0] == '\\' && p1[1] == '\\' && p1[2] == '?' && p1[3] == 
'\\'
+                && rtl::isAsciiAlpha(p1[4])
+                && p1[5] == ':'
+                && (pEnd - p1 == 6 || p1[6] == '/' || p1[6] == '\\'))
+            {
+                m_eScheme = INetProtocol::File; // 8th, 9th
+                eMechanism = EncodeMechanism::All;
+                nFragmentDelimiter = 0x80000000;
+            }
             else if (pEnd - p1 >= 2 && p1[0] == '/' && p1[1] == '/')
             {
                 p1 += 2;
@@ -828,6 +839,14 @@ bool INetURLObject::setAbsURIRef(std::u16string_view 
rTheAbsURIRef,
                      && p1[1] == '\\')
             {
                 p1 += 2;
+                if (pEnd - p1 >= 6 && p1[0] == '?' && p1[1] == '\\' && p1[5] 
== '\\'
+                    && rtl::toAsciiLowerCase(p1[2]) == 'u'
+                    && rtl::toAsciiLowerCase(p1[3]) == 'n'
+                    && rtl::toAsciiLowerCase(p1[4]) == 'c')
+                {
+                    p1 += 6; // "\\?\UNC\Servername\..."
+                }
+
                 sal_Int32 n = rtl_ustr_indexOfChar_WithLength(
                     p1, pEnd - p1, '\\');
                 sal_Unicode const * pe = n == -1 ? pEnd : p1 + n;
@@ -1161,6 +1180,16 @@ bool INetURLObject::setAbsURIRef(std::u16string_view 
rTheAbsURIRef,
                         && pPos[1] == '\\')
                     {
                         sal_Unicode const * p1 = pPos + 2;
+                        sal_Unicode const * pHostPortTentativeBegin = p1;
+                        if (pEnd - p1 >= 6 && p1[0] == '?' && p1[1] == '\\' && 
p1[5] == '\\'
+                            && rtl::toAsciiLowerCase(p1[2]) == 'u'
+                            && rtl::toAsciiLowerCase(p1[3]) == 'n'
+                            && rtl::toAsciiLowerCase(p1[4]) == 'c')
+                        {
+                            p1 += 6; // "\\?\UNC\Servername\..."
+                            pHostPortTentativeBegin = p1;
+                        }
+
                         sal_Unicode const * pe = p1;
                         while (pe < pEnd && *pe != '\\' &&
                                *pe != nFragmentDelimiter)
@@ -1175,7 +1204,7 @@ bool INetURLObject::setAbsURIRef(std::u16string_view 
rTheAbsURIRef,
                            )
                         {
                             m_aAbsURIRef.append("//");
-                            pHostPortBegin = pPos + 2;
+                            pHostPortBegin = pHostPortTentativeBegin;
                             pHostPortEnd = pe;
                             pPos = pe;
                             nSegmentDelimiter = '\\';
@@ -1193,18 +1222,26 @@ bool INetURLObject::setAbsURIRef(std::u16string_view 
rTheAbsURIRef,
                     //  becomes
                     //    "file:///" ALPHA ":" ["/" *path] ["#" *UCS4]
                     //  replacing "\" by "/" within <*path>
-                    if (eStyle & FSysStyle::Dos
-                        && pEnd - pPos >= 2
-                        && rtl::isAsciiAlpha(pPos[0])
-                        && pPos[1] == ':'
-                        && (pEnd - pPos == 2
-                            || pPos[2] == '/'
-                            || pPos[2] == '\\'))
+                    if (eStyle & FSysStyle::Dos)
                     {
-                        m_aAbsURIRef.append("//");
-                        nAltSegmentDelimiter = '\\';
-                        bSkippedInitialSlash = true;
-                        break;
+                        sal_Unicode const* p1 = pPos;
+                        if (pEnd - p1 >= 4 && p1[0] == '\\' && p1[1] == '\\' 
&& p1[2] == '?'
+                            && p1[3] == '\\')
+                            p1 += 4; // "\\?\c:\..."
+
+                        if (pEnd - p1 >= 2
+                            && rtl::isAsciiAlpha(p1[0])
+                            && p1[1] == ':'
+                            && (pEnd - p1 == 2
+                                || p1[2] == '/'
+                                || p1[2] == '\\'))
+                        {
+                            pPos = p1;
+                            m_aAbsURIRef.append("//");
+                            nAltSegmentDelimiter = '\\';
+                            bSkippedInitialSlash = true;
+                            break;
+                        }
                     }
 
                     // 9th Production (any):
@@ -1581,12 +1618,35 @@ bool INetURLObject::convertRelToAbs(OUString const & 
rTheRelURIRef,
                 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, EncodeMechanism::All, RTL_TEXTENCODING_DONTKNOW,
-                        true, nullptr))
+                if (n == 1 && q[0] == '?')
                 {
-                    bFSys = true; // 1st
+                    // "\\?\c:\..." or "\\?\UNC\servername\..."
+                    q += 2;
+                    if (pEnd - q >= 2
+                        && rtl::isAsciiAlpha(q[0])
+                        && q[1] == ':'
+                        && (pEnd - q == 2 || q[2] == '/' || q[2] == '\\'))
+                    {
+                        bFSys = true; // 2nd, 3rd
+                    }
+                    else if (pEnd - q >= 4
+                        && q[3] == '\\'
+                        && rtl::toAsciiLowerCase(q[0]) == 'u'
+                        && rtl::toAsciiLowerCase(q[1]) == 'n'
+                        && rtl::toAsciiLowerCase(q[2]) == 'c')
+                    {
+                        q += 4; // Check if it's 1st below
+                    }
+                }
+                if (!bFSys)
+                {
+                    sal_Unicode const * qe = n == -1 ? pEnd : q + n;
+                    if (parseHostOrNetBiosName(
+                            q, qe, EncodeMechanism::All, 
RTL_TEXTENCODING_DONTKNOW,
+                            true, nullptr))
+                    {
+                        bFSys = true; // 1st
+                    }
                 }
             }
             if (bFSys)

Reply via email to