Add separate util class
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
		| @@ -18,9 +18,10 @@ set(SRC | |||||||
|     org/prismlauncher/fix/Fix.java |     org/prismlauncher/fix/Fix.java | ||||||
|     org/prismlauncher/fix/Fixes.java |     org/prismlauncher/fix/Fixes.java | ||||||
|     org/prismlauncher/fix/skins/SkinFix.java |     org/prismlauncher/fix/skins/SkinFix.java | ||||||
|     org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java |     org/prismlauncher/fix/skins/Handler.java | ||||||
|     org/prismlauncher/utils/Parameters.java |     org/prismlauncher/utils/Parameters.java | ||||||
|     org/prismlauncher/utils/ReflectionUtils.java |     org/prismlauncher/utils/ReflectionUtils.java | ||||||
|  |     org/prismlauncher/utils/UrlUtils.java | ||||||
|     org/prismlauncher/utils/logging/Level.java |     org/prismlauncher/utils/logging/Level.java | ||||||
|     org/prismlauncher/utils/logging/Log.java |     org/prismlauncher/utils/logging/Log.java | ||||||
|     net/minecraft/Launcher.java |     net/minecraft/Launcher.java | ||||||
|   | |||||||
| @@ -39,10 +39,25 @@ import org.prismlauncher.utils.Parameters; | |||||||
|  |  | ||||||
| public interface Fix { | public interface Fix { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the name of the fix. If the name isn't passed into the program, the fix | ||||||
|  |      * won't run. | ||||||
|  |      * | ||||||
|  |      * @return The name | ||||||
|  |      */ | ||||||
|     String getName(); |     String getName(); | ||||||
|  |  | ||||||
|     boolean isApplicable(Parameters parameters); |     /** | ||||||
|  |      * Determines whether the fix will be run. This is additional to the name check. | ||||||
|  |      * | ||||||
|  |      * @param params The parameters | ||||||
|  |      * @return <code>true</code> to proceed to applying the fix | ||||||
|  |      */ | ||||||
|  |     boolean isApplicable(Parameters params); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Applies the fix. | ||||||
|  |      */ | ||||||
|     void apply(); |     void apply(); | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -46,9 +46,10 @@ import java.util.Map; | |||||||
| import javax.xml.bind.DatatypeConverter; | import javax.xml.bind.DatatypeConverter; | ||||||
| 
 | 
 | ||||||
| import org.prismlauncher.utils.JsonParser; | import org.prismlauncher.utils.JsonParser; | ||||||
|  | import org.prismlauncher.utils.UrlUtils; | ||||||
| 
 | 
 | ||||||
| @SuppressWarnings("unchecked") | @SuppressWarnings("unchecked") | ||||||
| final class SkinFixUrlStreamHandler extends URLStreamHandler { | final class Handler extends URLStreamHandler { | ||||||
| 
 | 
 | ||||||
|     private URL redirect(URL address) throws IOException { |     private URL redirect(URL address) throws IOException { | ||||||
|         String skinOwner = findSkinOwner(address); |         String skinOwner = findSkinOwner(address); | ||||||
| @@ -67,27 +68,13 @@ final class SkinFixUrlStreamHandler extends URLStreamHandler { | |||||||
|     @Override |     @Override | ||||||
|     protected URLConnection openConnection(URL address) throws IOException { |     protected URLConnection openConnection(URL address) throws IOException { | ||||||
|         address = redirect(address); |         address = redirect(address); | ||||||
| 
 |         return UrlUtils.openHttpConnection(address); | ||||||
|         try { |  | ||||||
|             return SkinFix.openConnection(address); |  | ||||||
|         } catch (RuntimeException | Error e) { |  | ||||||
|             throw e; |  | ||||||
|         } catch (Throwable e) { |  | ||||||
|             throw new IllegalStateException(e); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { |     protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { | ||||||
|         address = redirect(address); |         address = redirect(address); | ||||||
| 
 |         return UrlUtils.openHttpConnection(address, proxy); | ||||||
|         try { |  | ||||||
|             return SkinFix.openConnection(address, proxy); |  | ||||||
|         } catch (RuntimeException | Error e) { |  | ||||||
|             throw e; |  | ||||||
|         } catch (Throwable e) { |  | ||||||
|             throw new IllegalStateException(e); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private URL convertSkin(URL defaultUrl, String owner) throws IOException { |     private URL convertSkin(URL defaultUrl, String owner) throws IOException { | ||||||
| @@ -35,60 +35,55 @@ | |||||||
|  |  | ||||||
| package org.prismlauncher.fix.skins; | package org.prismlauncher.fix.skins; | ||||||
|  |  | ||||||
| import java.lang.invoke.MethodHandle; |  | ||||||
| import java.lang.invoke.MethodHandles; |  | ||||||
| import java.lang.reflect.Method; |  | ||||||
| import java.net.Proxy; |  | ||||||
| import java.net.URL; | import java.net.URL; | ||||||
| import java.net.URLConnection; |  | ||||||
| import java.net.URLStreamHandler; | import java.net.URLStreamHandler; | ||||||
| import java.net.URLStreamHandlerFactory; | import java.net.URLStreamHandlerFactory; | ||||||
|  |  | ||||||
| import org.prismlauncher.fix.Fix; | import org.prismlauncher.fix.Fix; | ||||||
| import org.prismlauncher.utils.Parameters; | import org.prismlauncher.utils.Parameters; | ||||||
|  | import org.prismlauncher.utils.UrlUtils; | ||||||
| import org.prismlauncher.utils.logging.Log; | import org.prismlauncher.utils.logging.Log; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Fixes skins by redirecting to other URLs. | ||||||
|  |  * | ||||||
|  |  * @see {@link Handler} | ||||||
|  |  * @see {@link UrlUtils} | ||||||
|  |  */ | ||||||
| public final class SkinFix implements Fix, URLStreamHandlerFactory { | public final class SkinFix implements Fix, URLStreamHandlerFactory { | ||||||
|  |  | ||||||
|     private static URLStreamHandler http; |  | ||||||
|     private static MethodHandle openConnection; |  | ||||||
|     private static MethodHandle openConnection2; |  | ||||||
|  |  | ||||||
|     static { |  | ||||||
|         try { |  | ||||||
|             Method getURLStreamHandler = URL.class.getDeclaredMethod("getURLStreamHandler", String.class); |  | ||||||
|             getURLStreamHandler.setAccessible(true); |  | ||||||
|             http = (URLStreamHandler) getURLStreamHandler.invoke(null, "http"); |  | ||||||
|  |  | ||||||
|             Method openConnectionReflect = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class); |  | ||||||
|             openConnectionReflect.setAccessible(true); |  | ||||||
|             openConnection = MethodHandles.lookup().unreflect(openConnectionReflect); |  | ||||||
|  |  | ||||||
|             Method openConnectionReflect2 = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, |  | ||||||
|                     Proxy.class); |  | ||||||
|             openConnectionReflect2.setAccessible(true); |  | ||||||
|             openConnection2 = MethodHandles.lookup().unreflect(openConnectionReflect2); |  | ||||||
|         } catch (Throwable e) { |  | ||||||
|             Log.error("Could not perform URL reflection; skin fix will not be availble", e); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static URLConnection openConnection(URL url) throws Throwable { |  | ||||||
|         return (URLConnection) openConnection.invokeExact(http, url); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static URLConnection openConnection(URL url, Proxy proxy) throws Throwable { |  | ||||||
|         return (URLConnection) openConnection2.invokeExact(http, url, proxy); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public String getName() { |     public String getName() { | ||||||
|         return "legacySkinFix"; |         return "legacySkinFix"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public boolean isApplicable(Parameters parameters) { |     public boolean isApplicable(Parameters params) { | ||||||
|         return http != null && openConnection != null; |         if (!isSupported()) { | ||||||
|  |             Log.warning("Using Java 8 will probably fix this"); | ||||||
|  |             Log.warning("Alternatively, turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private boolean isSupported() { | ||||||
|  |         // check for DatatypeConverter first | ||||||
|  |         // most users will just be annoyed by the big stacktrace | ||||||
|  |         try { | ||||||
|  |             Class.forName("javax.xml.bind.DatatypeConverter"); | ||||||
|  |         } catch (ClassNotFoundException e) { | ||||||
|  |             Log.warning("Cannot find DatatypeConverter - required for skin fix"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!UrlUtils.isSupported()) { | ||||||
|  |             Log.warning("Cannot access the necessary Java internals for skin fix"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -99,7 +94,7 @@ public final class SkinFix implements Fix, URLStreamHandlerFactory { | |||||||
|     @Override |     @Override | ||||||
|     public URLStreamHandler createURLStreamHandler(String protocol) { |     public URLStreamHandler createURLStreamHandler(String protocol) { | ||||||
|         if ("http".equals(protocol)) |         if ("http".equals(protocol)) | ||||||
|             return new SkinFixUrlStreamHandler(); |             return new Handler(); | ||||||
|  |  | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										121
									
								
								libraries/launcher/org/prismlauncher/utils/UrlUtils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								libraries/launcher/org/prismlauncher/utils/UrlUtils.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-3.0-only | ||||||
|  | /* | ||||||
|  |  *  Prism Launcher - Minecraft Launcher | ||||||
|  |  *  Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> | ||||||
|  |  * | ||||||
|  |  *  This program is free software: you can redistribute it and/or modify | ||||||
|  |  *  it under the terms of the GNU General Public License as published by | ||||||
|  |  *  the Free Software Foundation, version 3. | ||||||
|  |  * | ||||||
|  |  *  This program is distributed in the hope that it will be useful, | ||||||
|  |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  *  GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  *  Linking this library statically or dynamically with other modules is | ||||||
|  |  *  making a combined work based on this library. Thus, the terms and | ||||||
|  |  *  conditions of the GNU General Public License cover the whole | ||||||
|  |  *  combination. | ||||||
|  |  * | ||||||
|  |  *  As a special exception, the copyright holders of this library give | ||||||
|  |  *  you permission to link this library with independent modules to | ||||||
|  |  *  produce an executable, regardless of the license terms of these | ||||||
|  |  *  independent modules, and to copy and distribute the resulting | ||||||
|  |  *  executable under terms of your choice, provided that you also meet, | ||||||
|  |  *  for each linked independent module, the terms and conditions of the | ||||||
|  |  *  license of that module. An independent module is a module which is | ||||||
|  |  *  not derived from or based on this library. If you modify this | ||||||
|  |  *  library, you may extend this exception to your version of the | ||||||
|  |  *  library, but you are not obliged to do so. If you do not wish to do | ||||||
|  |  *  so, delete this exception statement from your version. | ||||||
|  |  * | ||||||
|  |  *  You should have received a copy of the GNU General Public License | ||||||
|  |  *  along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package org.prismlauncher.utils; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.lang.invoke.MethodHandle; | ||||||
|  | import java.lang.invoke.MethodHandles; | ||||||
|  | import java.lang.reflect.Method; | ||||||
|  | import java.net.Proxy; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.net.URLConnection; | ||||||
|  | import java.net.URLStreamHandler; | ||||||
|  |  | ||||||
|  | import org.prismlauncher.utils.logging.Log; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A utility class for URLs which uses reflection to access hidden methods. | ||||||
|  |  * Unfortunately not supported on newer Java versions. | ||||||
|  |  */ | ||||||
|  | public class UrlUtils { | ||||||
|  |  | ||||||
|  |     private static URLStreamHandler http; | ||||||
|  |     private static MethodHandle openConnection; | ||||||
|  |     private static MethodHandle openConnectionProxied; | ||||||
|  |  | ||||||
|  |     static { | ||||||
|  |         try { | ||||||
|  |             // invoke URL.getURLStreamHandler to obtain some of the default handlers before | ||||||
|  |             // they are overridden | ||||||
|  |             Method getURLStreamHandler = URL.class.getDeclaredMethod("getURLStreamHandler", String.class); | ||||||
|  |             getURLStreamHandler.setAccessible(true); | ||||||
|  |             http = (URLStreamHandler) getURLStreamHandler.invoke(null, "http"); | ||||||
|  |  | ||||||
|  |             // reflection is required due to not having access | ||||||
|  |             // unreflect is used due to the potential frequency of calls | ||||||
|  |             Method openConnectionReflect = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class); | ||||||
|  |             openConnectionReflect.setAccessible(true); | ||||||
|  |             openConnection = MethodHandles.lookup().unreflect(openConnectionReflect); | ||||||
|  |  | ||||||
|  |             // a second method which takes in a proxy is required for a fully-functional | ||||||
|  |             // URLStreamHandler | ||||||
|  |             Method openConnectionReflectProxied = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, | ||||||
|  |                     Proxy.class); | ||||||
|  |             openConnectionReflectProxied.setAccessible(true); | ||||||
|  |             openConnectionProxied = MethodHandles.lookup().unreflect(openConnectionReflectProxied); | ||||||
|  |         } catch (Throwable e) { | ||||||
|  |             Log.error("URL reflection failed - some features may not work", e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Determines whether all the features of this class are available. | ||||||
|  |      * | ||||||
|  |      * @return <code>true</code> if all features can be used | ||||||
|  |      */ | ||||||
|  |     public static boolean isSupported() { | ||||||
|  |         return http != null && openConnection != null && openConnectionProxied != null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static URLConnection openHttpConnection(URL url) throws IOException { | ||||||
|  |         return openConnection(http, url); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static URLConnection openHttpConnection(URL url, Proxy proxy) throws IOException { | ||||||
|  |         return openConnection(http, url, proxy); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static URLConnection openConnection(URLStreamHandler handler, URL url) throws IOException { | ||||||
|  |         try { | ||||||
|  |             return (URLConnection) openConnection.invokeExact(handler, url); | ||||||
|  |         } catch (IOException | Error | RuntimeException e) { | ||||||
|  |             throw e; // rethrow if possible | ||||||
|  |         } catch (Throwable e) { | ||||||
|  |             throw new Error(e); // otherwise, wrap in Error | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static URLConnection openConnection(URLStreamHandler handler, URL url, Proxy proxy) throws IOException { | ||||||
|  |         try { | ||||||
|  |             return (URLConnection) openConnectionProxied.invokeExact(handler, url, proxy); | ||||||
|  |         } catch (IOException | Error | RuntimeException e) { | ||||||
|  |             throw e; | ||||||
|  |         } catch (Throwable e) { | ||||||
|  |             throw new Error(e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 TheKodeToad
					TheKodeToad