|
| 1 | +package com.falsepattern.lib.util; |
| 2 | + |
| 3 | +import lombok.val; |
| 4 | + |
| 5 | +import java.io.ByteArrayOutputStream; |
| 6 | +import java.io.FileNotFoundException; |
| 7 | +import java.io.IOException; |
| 8 | +import java.io.InputStream; |
| 9 | +import java.net.URL; |
| 10 | +import java.nio.charset.Charset; |
| 11 | +import java.nio.charset.StandardCharsets; |
| 12 | + |
| 13 | +/** |
| 14 | + * A utility class for reading resources in many ways. |
| 15 | + */ |
| 16 | +public class ResourceUtil { |
| 17 | + |
| 18 | + /** |
| 19 | + * Reads a resource as a string, using the {@link StandardCharsets#UTF_8} charset, from a specific jar file. See {@link #getResourceFromJar(String, Class)}. |
| 20 | + * @param resourcePath The resource to read |
| 21 | + * @param referenceClass The class, from whose jar to get the resource from |
| 22 | + * @return The string from the resource |
| 23 | + * @throws IOException From {@link #readBytes(InputStream)} |
| 24 | + */ |
| 25 | + public static String getResourceStringFromJar(String resourcePath, Class<?> referenceClass) throws IOException { |
| 26 | + return getResourceStringFromJar(resourcePath, referenceClass, StandardCharsets.UTF_8); |
| 27 | + } |
| 28 | + |
| 29 | + |
| 30 | + /** |
| 31 | + * Reads a resource as a string from a specific jar file. See {@link #getResourceFromJar(String, Class)}. |
| 32 | + * @param resourcePath The resource to read |
| 33 | + * @param referenceClass The class, from whose jar to get the resource from |
| 34 | + * @param charset The charset to decode the raw bytes with |
| 35 | + * @return The string from the resource |
| 36 | + * @throws IOException From {@link #readBytes(InputStream)} |
| 37 | + */ |
| 38 | + public static String getResourceStringFromJar(String resourcePath, Class<?> referenceClass, Charset charset) throws IOException { |
| 39 | + return new String(getResourceBytesFromJar(resourcePath, referenceClass), charset); |
| 40 | + } |
| 41 | + |
| 42 | + |
| 43 | + /** |
| 44 | + * Reads a resource as a string, using the {@link StandardCharsets#UTF_8} charset. |
| 45 | + * @param resourcePath The resource to read |
| 46 | + * @return The string from the resource |
| 47 | + * @throws IOException From {@link #readBytes(InputStream)} |
| 48 | + */ |
| 49 | + public static String getResourceString(String resourcePath) throws IOException { |
| 50 | + return getResourceString(resourcePath, StandardCharsets.UTF_8); |
| 51 | + } |
| 52 | + |
| 53 | + /** |
| 54 | + * Reads a resource as a string. |
| 55 | + * @param resourcePath The resource to read |
| 56 | + * @param charset The charset to decode the raw bytes with |
| 57 | + * @return The string from the resource |
| 58 | + * @throws IOException From {@link #readBytes(InputStream)} |
| 59 | + */ |
| 60 | + public static String getResourceString(String resourcePath, Charset charset) throws IOException { |
| 61 | + return new String(getResourceBytes(resourcePath), charset); |
| 62 | + } |
| 63 | + |
| 64 | + /** |
| 65 | + * Reads the raw bytes of a resource in a specific jar file. See {@link #getResourceFromJar(String, Class)}. |
| 66 | + * @param resourcePath The resource to read |
| 67 | + * @param referenceClass The class, from whose jar to get the resource from |
| 68 | + * @return The bytes of the resource |
| 69 | + * @throws IOException From {@link #readBytes(InputStream)} |
| 70 | + */ |
| 71 | + public static byte[] getResourceBytesFromJar(String resourcePath, Class<?> referenceClass) throws IOException { |
| 72 | + return readBytesSafe(getResourceFromJar(resourcePath, referenceClass), resourcePath); |
| 73 | + } |
| 74 | + |
| 75 | + /** |
| 76 | + * Reads the raw bytes of a resource. |
| 77 | + * @param resourcePath The resource to read |
| 78 | + * @return The bytes of the resource |
| 79 | + * @throws IOException From {@link #readBytes(InputStream)} |
| 80 | + */ |
| 81 | + public static byte[] getResourceBytes(String resourcePath) throws IOException { |
| 82 | + return readBytesSafe(ResourceUtil.class.getResourceAsStream(resourcePath), resourcePath); |
| 83 | + } |
| 84 | + |
| 85 | + private static byte[] readBytesSafe(InputStream stream, String resourcePath) throws IOException { |
| 86 | + if (stream == null) { |
| 87 | + throw new FileNotFoundException("Could not find resource at " + resourcePath); |
| 88 | + } |
| 89 | + return readBytes(stream); |
| 90 | + } |
| 91 | + |
| 92 | + /** |
| 93 | + * Fully reads a stream into a byte array. |
| 94 | + * @param stream The stream to read |
| 95 | + * @return The data from the stream |
| 96 | + * @throws IOException From {@link InputStream#read(byte[])} |
| 97 | + */ |
| 98 | + public static byte[] readBytes(InputStream stream) throws IOException { |
| 99 | + val out = new ByteArrayOutputStream(); |
| 100 | + val buf = new byte[4096]; |
| 101 | + int read; |
| 102 | + while ((read = stream.read(buf)) >= 0) { |
| 103 | + out.write(buf, 0, read); |
| 104 | + } |
| 105 | + return out.toByteArray(); |
| 106 | + } |
| 107 | + |
| 108 | + /** |
| 109 | + * Retrieves a resource from the jar file of a specific class. |
| 110 | + * Falls back to {@link Class#getResourceAsStream(String)} if the resource is not found in the jar, or the class is |
| 111 | + * not from a jar file. |
| 112 | + * @param resourcePath The resource to retrieve |
| 113 | + * @param referenceClass The class, from whose jar to get the resource from |
| 114 | + * @return The resource, or null if it was not found. |
| 115 | + */ |
| 116 | + public static InputStream getResourceFromJar(String resourcePath, Class<?> referenceClass) { |
| 117 | + URL classFile = referenceClass.getResource('/' + referenceClass.getName().replace('.', '/') + ".class"); |
| 118 | + lookup: |
| 119 | + { |
| 120 | + if (classFile == null) |
| 121 | + break lookup; |
| 122 | + String file = classFile.getFile(); |
| 123 | + int id = file.indexOf("!"); |
| 124 | + if (!classFile.getProtocol().equals("jar") || id < 0) |
| 125 | + break lookup; |
| 126 | + //Loading from a jar |
| 127 | + try { |
| 128 | + URL resource = new URL("jar:" + file.substring(0, id) + "!" + resourcePath); |
| 129 | + return resource.openStream(); |
| 130 | + } catch (IOException e) { |
| 131 | + System.err.println("Failed to load resource " + resourcePath + " from jar " + file.substring(0, id)); |
| 132 | + e.printStackTrace(); |
| 133 | + } |
| 134 | + } |
| 135 | + //Fallback logic |
| 136 | + System.out.println("Using fallback resource loading logic for " + resourcePath + " with reference to " + referenceClass.getName()); |
| 137 | + return referenceClass.getResourceAsStream(resourcePath); |
| 138 | + } |
| 139 | +} |
0 commit comments