From 8a6776731af94e768831440f27d3e9e8e81ab7bf Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 22 Nov 2022 16:56:58 +0000 Subject: [PATCH] Use reflection to access DatatypeConverter Signed-off-by: TheKodeToad --- .../org/prismlauncher/fix/skins/SkinFix.java | 3 +- .../org/prismlauncher/utils/Base64.java | 53 +++++++++++++++---- .../org/prismlauncher/utils/url/UrlUtils.java | 6 +++ 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index ab978dc58..66b5fda62 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -40,6 +40,7 @@ import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import org.prismlauncher.fix.Fix; +import org.prismlauncher.utils.Base64; import org.prismlauncher.utils.Parameters; import org.prismlauncher.utils.logging.Log; import org.prismlauncher.utils.url.UrlUtils; @@ -59,7 +60,7 @@ public final class SkinFix implements Fix, URLStreamHandlerFactory { @Override public boolean isApplicable(Parameters params) { - if (!UrlUtils.isSupported()) { + if (!UrlUtils.isSupported() || !Base64.isSupported()) { Log.warning("Cannot access the necessary Java internals for skin fix"); Log.warning("Try adding '--add-opens java.base/java.net=ALL-UNNAMED' to your Java arguments"); Log.warning("Alternatively, turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); diff --git a/libraries/launcher/org/prismlauncher/utils/Base64.java b/libraries/launcher/org/prismlauncher/utils/Base64.java index 20a189f46..508df872d 100644 --- a/libraries/launcher/org/prismlauncher/utils/Base64.java +++ b/libraries/launcher/org/prismlauncher/utils/Base64.java @@ -35,25 +35,60 @@ package org.prismlauncher.utils; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.nio.charset.StandardCharsets; -import javax.xml.bind.DatatypeConverter; +import org.prismlauncher.utils.logging.Log; +/** + * Uses Base64 with Java 8 or later, otherwise DatatypeConverter. In the latter + * case, reflection is used to allow using newer compilers. + */ public final class Base64 { - private static boolean legacy; + private static boolean supported = true; + private static MethodHandle legacy; - public static byte[] decode(String input) { - if (!legacy) { + static { + try { + Class.forName("java.util.Base64"); + } catch (ClassNotFoundException e) { try { - return java.util.Base64.getDecoder().decode(input.getBytes(StandardCharsets.UTF_8)); - } catch (NoClassDefFoundError e) { - legacy = true; + Class datatypeConverter = Class.forName("javax.xml.bind.DatatypeConverter"); + legacy = MethodHandles.lookup().findStatic(datatypeConverter, "parseBase64Binary", + MethodType.methodType(byte[].class, String.class)); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e1) { + Log.error("Base64 not supported", e1); + supported = false; } } + } - // support for Java versions < 8 - return DatatypeConverter.parseBase64Binary(input); + /** + * Determines whether base64 is supported. + * + * @return true if base64 can be parsed + */ + public static boolean isSupported() { + return supported; + } + + public static byte[] decode(String input) { + if (!isSupported()) + throw new UnsupportedOperationException(); + + if (legacy == null) + return java.util.Base64.getDecoder().decode(input.getBytes(StandardCharsets.UTF_8)); + + try { + return (byte[]) legacy.invokeExact(input); + } catch (Error | RuntimeException e) { + throw e; + } catch (Throwable e) { + throw new Error(e); + } } } diff --git a/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java b/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java index 751f833fd..05912d005 100644 --- a/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java +++ b/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java @@ -82,10 +82,16 @@ public final class UrlUtils { } public static URLConnection openHttpConnection(URL url, Proxy proxy) throws IOException { + if (http == null) + throw new UnsupportedOperationException(); + return openConnection(http, url, proxy); } public static URLConnection openConnection(URLStreamHandler handler, URL url, Proxy proxy) throws IOException { + if (openConnection == null) + throw new UnsupportedOperationException(); + try { return (URLConnection) openConnection.invokeExact(handler, url, proxy); } catch (IOException | Error | RuntimeException e) {