This is an automated email from the ASF dual-hosted git repository.

ardovm pushed a commit to branch AOO41X
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 55a8ef8e3097bc8de5b02d37bbedbcebe84d576b
Author: Peter <[email protected]>
AuthorDate: Sat Sep 26 22:16:29 2026 +0200

    Accept local files
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    (cherry picked and adapted from commit 
06d7e6fcc50631716e4dd8909f5d630a5b1f52c5)
---
 main/jvmaccess/source/classpath.cxx | 87 ++++++++++++++++++++++++++++++++-----
 1 file changed, 77 insertions(+), 10 deletions(-)

diff --git a/main/jvmaccess/source/classpath.cxx 
b/main/jvmaccess/source/classpath.cxx
index c27a530ba7..f0e7d6f001 100644
--- a/main/jvmaccess/source/classpath.cxx
+++ b/main/jvmaccess/source/classpath.cxx
@@ -37,6 +37,7 @@
 #include "com/sun/star/uri/XVndSunStarExpandUrlReference.hpp"
 #include "com/sun/star/util/XMacroExpander.hpp"
 #include "osl/diagnose.h"
+#include "rtl/ustrbuf.hxx"
 #include "rtl/ustring.hxx"
 #include "sal/types.h"
 
@@ -49,22 +50,88 @@ namespace {
 namespace css = ::com::sun::star;
 
 #if defined SOLAR_JAVA
+int hexDigitValue(sal_Unicode c)
+{
+    if (c >= '0' && c <= '9') {
+        return c - '0';
+    }
+    if (c >= 'A' && c <= 'F') {
+        return c - 'A' + 10;
+    }
+    if (c >= 'a' && c <= 'f') {
+        return c - 'a' + 10;
+    }
+    return -1;
+}
+
+// Undoes one level of %HH escapes, as the JDK's file: handler does before it
+// opens a path.  Only the ASCII separators matter to the caller, so each 
escape
+// simply becomes the code unit of its byte value; a malformed escape is kept.
+::rtl::OUString percentDecoded(::rtl::OUString const & s)
+{
+    sal_Int32 const n = s.getLength();
+    ::rtl::OUStringBuffer buf(n);
+    for (sal_Int32 i = 0; i != n; ++i) {
+        sal_Unicode c = s[i];
+        if (c == '%' && n - i > 2) {
+            int const hi = hexDigitValue(s[i + 1]);
+            int const lo = hexDigitValue(s[i + 2]);
+            if (hi != -1 && lo != -1) {
+                c = static_cast< sal_Unicode >(hi * 16 + lo);
+                i += 2;
+            }
+        }
+        buf.append(c);
+    }
+    return buf.makeStringAndClear();
+}
+
+// Whether the part of a file: URL after the scheme names a path on this
+// machine: the authority, if any, must be empty or localhost, and the path 
must
+// not name another machine by itself.  The path is judged decoded, because the
+// JDK's file: handler percent-decodes it and, on Windows, turns slashes into
+// backslashes before opening it -- a leading escaped slash or backslash would
+// otherwise reach the file system as a reference to a share.
+bool isLocalFileLocation(::rtl::OUString const & afterScheme)
+{
+    ::rtl::OUString rest(afterScheme);
+    if (rest.indexOf('\\') != -1) {
+        return false;
+    }
+    if (rest.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("//"))) {
+        sal_Int32 const end = rest.indexOf('/', 2);
+        ::rtl::OUString const authority(
+            end == -1 ? rest.copy(2) : rest.copy(2, end - 2));
+        if (authority.getLength() != 0
+            && !authority.equalsIgnoreAsciiCaseAsciiL(
+                RTL_CONSTASCII_STRINGPARAM("localhost")))
+        {
+            return false;
+        }
+        rest = end == -1 ? ::rtl::OUString() : rest.copy(end);
+    }
+    rest = percentDecoded(rest);
+    return rest.getLength() >= 2 && rest[0] == '/' && rest[1] != '/'
+        && rest.indexOf('\\') == -1;
+}
+
 // URL schemes that resolve to the local file system or the running JVM image,
-// optionally wrapped in a jar: URL.
+// optionally wrapped in a jar: URL; a file: URL must in addition name a path 
on
+// this machine.
 //
 // com.sun.star.comp.sdbc.Tools enforces the same allow-list on the Java side;
 // keep the two in sync.
 bool isLocalClassPathUrl(::rtl::OUString const & url)
 {
-    return url.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("file:"))
-        || url.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("jrt:"))
-        || url.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("jmod:"))
-        || url.matchIgnoreAsciiCaseAsciiL(
-               RTL_CONSTASCII_STRINGPARAM("jar:file:"))
-        || url.matchIgnoreAsciiCaseAsciiL(
-               RTL_CONSTASCII_STRINGPARAM("jar:jrt:"))
-        || url.matchIgnoreAsciiCaseAsciiL(
-               RTL_CONSTASCII_STRINGPARAM("jar:jmod:"));
+    ::rtl::OUString rest(url);
+    if (rest.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("jar:"))) {
+        rest = rest.copy(RTL_CONSTASCII_LENGTH("jar:"));
+    }
+    if (rest.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("file:"))) {
+        return isLocalFileLocation(rest.copy(RTL_CONSTASCII_LENGTH("file:")));
+    }
+    return rest.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("jrt:"))
+        || 
rest.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("jmod:"));
 }
 #endif
 

Reply via email to