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 fc56e34724d1b187c33e471bae81ad5d36c950d8
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Fri Oct 2 21:57:00 2026 +0200

    Fix acceptance of local files
    
    Assisted-By: Claude Opus 5.5 <[email protected]>
    (cherry picked and adapted from commit 
bb3a5a855831b861943c55afcadf2a8cf42eff01)
---
 main/jvmaccess/source/classpath.cxx | 116 ++++++++++++------------------------
 1 file changed, 39 insertions(+), 77 deletions(-)

diff --git a/main/jvmaccess/source/classpath.cxx 
b/main/jvmaccess/source/classpath.cxx
index f0e7d6f001..d14cb52aca 100644
--- a/main/jvmaccess/source/classpath.cxx
+++ b/main/jvmaccess/source/classpath.cxx
@@ -34,10 +34,12 @@
 #include "com/sun/star/uno/XComponentContext.hpp"
 #include "com/sun/star/uno/XInterface.hpp"
 #include "com/sun/star/uri/UriReferenceFactory.hpp"
+#include "com/sun/star/uri/XUriReference.hpp"
+#include "com/sun/star/uri/XUriReferenceFactory.hpp"
 #include "com/sun/star/uri/XVndSunStarExpandUrlReference.hpp"
 #include "com/sun/star/util/XMacroExpander.hpp"
 #include "osl/diagnose.h"
-#include "rtl/ustrbuf.hxx"
+#include "rtl/uri.hxx"
 #include "rtl/ustring.hxx"
 #include "sal/types.h"
 
@@ -50,88 +52,48 @@ 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)
+// Whether a class path entry is a file: URL naming a path on this machine.
+//
+// On Windows, Java opens a file: URL as a UNC path, i.e. a file on another
+// machine, in two cases:
+//
+// - if its authority names a host, e.g. file://host/share/a.jar;
+// - if its path (or opaque part), once percent-decoded and with backslashes
+//   read as slashes, starts with two slashes, e.g. file:////host/share/a.jar,
+//   file:/%5C%5Chost/share/a.jar or file:%5C%5Chost/share/a.jar.
+//
+// com.sun.star.comp.sdbc.Tools enforces the same check on the Java side; keep
+// the two in sync.
+bool isLocalFileUrl(
+    css::uno::Reference< css::uri::XUriReferenceFactory > const & factory,
+    ::rtl::OUString const & url)
 {
-    ::rtl::OUString rest(afterScheme);
-    if (rest.indexOf('\\') != -1) {
+    css::uno::Reference< css::uri::XUriReference > const uriRef(
+        factory->parse(url));
+    if (!uriRef.is()
+        || !uriRef->getScheme().equalsIgnoreAsciiCaseAsciiL(
+            RTL_CONSTASCII_STRINGPARAM("file")))
+    {
         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));
+    // The authority, if any, must be empty or localhost.
+    if (uriRef->hasAuthority()) {
+        ::rtl::OUString const authority(uriRef->getAuthority());
         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; 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)
-{
-    ::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:"));
+    // The decoded path must start with exactly one slash, which also rules out
+    // the opaque form, and must contain no backslash at all.
+    ::rtl::OUString const path(
+        ::rtl::Uri::decode(
+            uriRef->getPath(), rtl_UriDecodeWithCharset,
+            RTL_TEXTENCODING_UTF8));
+    return path.getLength() >= 2 && path[0] == '/' && path[1] != '/'
+        && path.indexOf('\\') == -1;
 }
 #endif
 
@@ -153,14 +115,14 @@ void * ::jvmaccess::ClassPath::doTranslateToUrls(
     if (ctorUrl == 0) {
         return 0;
     }
+    css::uno::Reference< css::uri::XUriReferenceFactory > const factory(
+        css::uri::UriReferenceFactory::create(context));
     ::std::vector< jobject > urls;
     for (::sal_Int32 i = 0; i != -1;) {
         ::rtl::OUString url(classPath.getToken(0, ' ', i));
         if (url.getLength() != 0) {
             css::uno::Reference< css::uri::XVndSunStarExpandUrlReference >
-                expUrl(
-                    css::uri::UriReferenceFactory::create(context)->parse(url),
-                    css::uno::UNO_QUERY);
+                expUrl(factory->parse(url), css::uno::UNO_QUERY);
             if (expUrl.is()) {
                 css::uno::Reference< css::util::XMacroExpander > expander(
                     context->getValueByName(
@@ -181,7 +143,7 @@ void * ::jvmaccess::ClassPath::doTranslateToUrls(
                 }
             }
             // Add only local entries; a non-local one is logged and skipped.
-            if (!isLocalClassPathUrl(url))
+            if (!isLocalFileUrl(factory, url))
             {
                 OSL_TRACE(
                     "jvmaccess::ClassPath: skipping non-local class path"

Reply via email to