Files
FalsePatternLib/src/main/java/com/falsepattern/lib/util/ResourceUtil.java
T

193 lines
7.0 KiB
Java
Raw Normal View History

2022-07-31 20:41:56 +02:00
/*
2024-04-17 17:23:43 +02:00
* This file is part of FalsePatternLib.
*
2025-05-24 19:29:12 +02:00
* Copyright (C) 2022-2025 FalsePattern
2022-07-30 15:21:11 +02:00
* All Rights Reserved
*
2024-04-17 17:23:43 +02:00
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
2022-07-30 15:21:11 +02:00
*
2024-04-17 17:23:43 +02:00
* FalsePatternLib is free software: you can redistribute it and/or modify
2022-07-30 15:21:11 +02:00
* it under the terms of the GNU Lesser General Public License as published by
2025-05-24 19:29:12 +02:00
* the Free Software Foundation, only version 3 of the License.
2022-07-30 15:21:11 +02:00
*
2024-04-17 17:23:43 +02:00
* FalsePatternLib is distributed in the hope that it will be useful,
2022-07-30 15:21:11 +02:00
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2024-04-17 17:23:43 +02:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
2022-07-30 15:21:11 +02:00
*
* You should have received a copy of the GNU Lesser General Public License
2024-04-17 17:23:43 +02:00
* along with FalsePatternLib. If not, see <https://www.gnu.org/licenses/>.
2022-07-30 15:21:11 +02:00
*/
2022-05-06 13:27:30 +02:00
package com.falsepattern.lib.util;
2024-05-16 21:21:36 +01:00
import com.falsepattern.lib.internal.FPLog;
2023-06-30 10:57:30 +01:00
import lombok.experimental.UtilityClass;
2022-07-31 20:41:56 +02:00
import lombok.val;
import org.jetbrains.annotations.ApiStatus;
2022-07-31 20:41:56 +02:00
2022-05-06 13:27:30 +02:00
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* A utility class for reading resources in many ways.
*/
@ApiStatus.AvailableSince("0.6.0")
2023-06-30 10:57:30 +01:00
@UtilityClass
public final class ResourceUtil {
2022-05-06 13:27:30 +02:00
/**
2022-06-08 16:01:06 +02:00
* Reads a resource as a string, using the {@link StandardCharsets#UTF_8} charset, from a specific jar file. See
* {@link #getResourceFromJar(String, Class)}.
*
* @param resourcePath The resource to read
2022-05-06 13:27:30 +02:00
* @param referenceClass The class, from whose jar to get the resource from
2022-06-08 16:01:06 +02:00
*
2022-05-06 13:27:30 +02:00
* @return The string from the resource
2022-06-08 16:01:06 +02:00
*
2022-05-06 13:27:30 +02:00
* @throws IOException From {@link #readBytes(InputStream)}
*/
public static String getResourceStringFromJar(String resourcePath, Class<?> referenceClass) throws IOException {
return getResourceStringFromJar(resourcePath, referenceClass, StandardCharsets.UTF_8);
}
/**
* Reads a resource as a string from a specific jar file. See {@link #getResourceFromJar(String, Class)}.
2022-06-08 16:01:06 +02:00
*
* @param resourcePath The resource to read
2022-05-06 13:27:30 +02:00
* @param referenceClass The class, from whose jar to get the resource from
2022-06-08 16:01:06 +02:00
* @param charset The charset to decode the raw bytes with
*
2022-05-06 13:27:30 +02:00
* @return The string from the resource
2022-06-08 16:01:06 +02:00
*
2022-05-06 13:27:30 +02:00
* @throws IOException From {@link #readBytes(InputStream)}
*/
2022-06-08 16:01:06 +02:00
public static String getResourceStringFromJar(String resourcePath, Class<?> referenceClass, Charset charset)
throws IOException {
2022-05-06 13:27:30 +02:00
return new String(getResourceBytesFromJar(resourcePath, referenceClass), charset);
}
/**
* Reads the raw bytes of a resource in a specific jar file. See {@link #getResourceFromJar(String, Class)}.
2022-06-08 16:01:06 +02:00
*
* @param resourcePath The resource to read
2022-05-06 13:27:30 +02:00
* @param referenceClass The class, from whose jar to get the resource from
2022-06-08 16:01:06 +02:00
*
2022-05-06 13:27:30 +02:00
* @return The bytes of the resource
2022-06-08 16:01:06 +02:00
*
2022-05-06 13:27:30 +02:00
* @throws IOException From {@link #readBytes(InputStream)}
*/
public static byte[] getResourceBytesFromJar(String resourcePath, Class<?> referenceClass) throws IOException {
return readBytesSafe(getResourceFromJar(resourcePath, referenceClass), resourcePath);
}
private static byte[] readBytesSafe(InputStream stream, String resourcePath) throws IOException {
if (stream == null) {
throw new FileNotFoundException("Could not find resource at " + resourcePath);
}
return readBytes(stream);
}
/**
2022-06-08 16:01:06 +02:00
* Retrieves a resource from the jar file of a specific class. Falls back to
* {@link Class#getResourceAsStream(String)} if the resource is not found in the jar, or the class is not from a jar
* file.
*
* @param resourcePath The resource to retrieve
2022-05-06 13:27:30 +02:00
* @param referenceClass The class, from whose jar to get the resource from
2022-06-08 16:01:06 +02:00
*
2022-05-06 13:27:30 +02:00
* @return The resource, or null if it was not found.
*/
public static InputStream getResourceFromJar(String resourcePath, Class<?> referenceClass) {
URL classFile = referenceClass.getResource('/' + referenceClass.getName().replace('.', '/') + ".class");
lookup:
{
2022-06-08 16:01:06 +02:00
if (classFile == null) {
2022-05-06 13:27:30 +02:00
break lookup;
2022-06-08 16:01:06 +02:00
}
2022-05-06 13:27:30 +02:00
String file = classFile.getFile();
int id = file.indexOf("!");
2022-06-08 16:01:06 +02:00
if (!classFile.getProtocol().equals("jar") || id < 0) {
2022-05-06 13:27:30 +02:00
break lookup;
2022-06-08 16:01:06 +02:00
}
2022-05-06 13:27:30 +02:00
//Loading from a jar
try {
URL resource = new URL("jar:" + file.substring(0, id) + "!" + resourcePath);
return resource.openStream();
} catch (IOException e) {
2024-05-16 21:21:36 +01:00
FPLog.LOG.error("Failed to load resource " + resourcePath + " from jar " + file.substring(0, id), e);
2022-05-06 13:27:30 +02:00
}
}
//Fallback logic
2024-05-16 21:21:36 +01:00
FPLog.LOG.warn("Using fallback resource loading logic for "
+ resourcePath
+ " with reference to "
+ referenceClass.getName());
2022-05-06 13:27:30 +02:00
return referenceClass.getResourceAsStream(resourcePath);
}
2022-06-08 16:01:06 +02:00
/**
* Fully reads a stream into a byte array.
*
* @param stream The stream to read
*
* @return The data from the stream
*
* @throws IOException From {@link InputStream#read(byte[])}
*/
public static byte[] readBytes(InputStream stream) throws IOException {
val out = new ByteArrayOutputStream();
val buf = new byte[4096];
int read;
while ((read = stream.read(buf)) >= 0) {
out.write(buf, 0, read);
}
return out.toByteArray();
}
/**
* Reads a resource as a string, using the {@link StandardCharsets#UTF_8} charset.
*
* @param resourcePath The resource to read
*
* @return The string from the resource
*
* @throws IOException From {@link #readBytes(InputStream)}
*/
public static String getResourceString(String resourcePath) throws IOException {
return getResourceString(resourcePath, StandardCharsets.UTF_8);
}
/**
* Reads a resource as a string.
*
* @param resourcePath The resource to read
* @param charset The charset to decode the raw bytes with
*
* @return The string from the resource
*
* @throws IOException From {@link #readBytes(InputStream)}
*/
public static String getResourceString(String resourcePath, Charset charset) throws IOException {
return new String(getResourceBytes(resourcePath), charset);
}
/**
* Reads the raw bytes of a resource.
*
* @param resourcePath The resource to read
*
* @return The bytes of the resource
*
* @throws IOException From {@link #readBytes(InputStream)}
*/
public static byte[] getResourceBytes(String resourcePath) throws IOException {
return readBytesSafe(ResourceUtil.class.getResourceAsStream(resourcePath), resourcePath);
}
2022-05-06 13:27:30 +02:00
}