From 254dc29c1d7c12f0d9d6fb1725d3cbda98cf6a49 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 21 Oct 2021 10:50:43 +0200 Subject: [PATCH] backport more to java 1.8 #32 --- pom.xml | 5 + .../data/commands/parser/RangeParser.java | 5 +- .../data/commands/parser/StringParser.java | 3 +- .../parser/minosoft/VersionParser.java | 3 +- .../data/registries/versions/Versions.java | 2 +- .../hotbar/HotbarProtectionElement.kt | 2 +- .../gui/rendering/util/JavaBackport.java | 124 ++++++++++++++++++ .../network/socket/BlockingSocketNetwork.java | 3 +- .../protocol/protocol/PacketSender.java | 3 +- .../de/bixilon/minosoft/terminal/CLI.java | 5 +- .../java/de/bixilon/minosoft/util/Util.java | 10 +- 11 files changed, 152 insertions(+), 13 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/util/JavaBackport.java diff --git a/pom.xml b/pom.xml index 7bc023972..44170866a 100644 --- a/pom.xml +++ b/pom.xml @@ -360,5 +360,10 @@ ikonli-javafx 12.2.0 + + org.apache.commons + commons-lang3 + 3.12.0 + diff --git a/src/main/java/de/bixilon/minosoft/data/commands/parser/RangeParser.java b/src/main/java/de/bixilon/minosoft/data/commands/parser/RangeParser.java index 3386a8215..f5270c0af 100644 --- a/src/main/java/de/bixilon/minosoft/data/commands/parser/RangeParser.java +++ b/src/main/java/de/bixilon/minosoft/data/commands/parser/RangeParser.java @@ -22,6 +22,7 @@ import de.bixilon.minosoft.data.commands.parser.properties.ParserProperties; import de.bixilon.minosoft.data.commands.parser.properties.RangeParserProperties; import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection; import de.bixilon.minosoft.protocol.protocol.InByteBuffer; +import org.apache.commons.lang3.StringUtils; public class RangeParser extends CommandParser { public static final RangeParser RANGE_PARSER = new RangeParser(); @@ -35,12 +36,12 @@ public class RangeParser extends CommandParser { } double from; double to; - if (split[0].isBlank()) { + if (StringUtils.isBlank(split[0])) { from = minValue; } else { from = parseValue(stringReader, argument, split[0], allowDecimal); } - if (split[1].isBlank()) { + if (StringUtils.isBlank(split[1])) { to = maxValue; } else { to = parseValue(stringReader, argument, split[1], allowDecimal); diff --git a/src/main/java/de/bixilon/minosoft/data/commands/parser/StringParser.java b/src/main/java/de/bixilon/minosoft/data/commands/parser/StringParser.java index 7e41fd5ac..7f701f931 100644 --- a/src/main/java/de/bixilon/minosoft/data/commands/parser/StringParser.java +++ b/src/main/java/de/bixilon/minosoft/data/commands/parser/StringParser.java @@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.commands.parser.properties.ParserProperties; import de.bixilon.minosoft.data.commands.parser.properties.StringParserProperties; import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection; import de.bixilon.minosoft.protocol.protocol.InByteBuffer; +import org.apache.commons.lang3.StringUtils; public class StringParser extends CommandParser { public static final StringParser STRING_PARSER = new StringParser(); @@ -47,7 +48,7 @@ public class StringParser extends CommandParser { throw new IllegalStateException(); } - if (!stringParserProperties.isAllowEmptyString() && string.isBlank()) { + if (!stringParserProperties.isAllowEmptyString() && StringUtils.isBlank(string)) { throw new BlankStringCommandParseException(stringReader, string); } return string; diff --git a/src/main/java/de/bixilon/minosoft/data/commands/parser/minosoft/VersionParser.java b/src/main/java/de/bixilon/minosoft/data/commands/parser/minosoft/VersionParser.java index 777fa2185..4b8f5c61c 100644 --- a/src/main/java/de/bixilon/minosoft/data/commands/parser/minosoft/VersionParser.java +++ b/src/main/java/de/bixilon/minosoft/data/commands/parser/minosoft/VersionParser.java @@ -22,6 +22,7 @@ import de.bixilon.minosoft.data.commands.parser.properties.ParserProperties; import de.bixilon.minosoft.data.registries.versions.Version; import de.bixilon.minosoft.data.registries.versions.Versions; import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection; +import org.apache.commons.lang3.StringUtils; import javax.annotation.Nullable; @@ -31,7 +32,7 @@ public class VersionParser extends CommandParser { @Override public Object parse(PlayConnection connection, @Nullable ParserProperties properties, CommandStringReader stringReader) throws CommandParseException { String rawVersionName = stringReader.readString(); - if (rawVersionName.isBlank()) { + if (StringUtils.isBlank(rawVersionName)) { throw new BlankStringCommandParseException(stringReader, rawVersionName); } Version version = Versions.getVersionByName(rawVersionName); diff --git a/src/main/java/de/bixilon/minosoft/data/registries/versions/Versions.java b/src/main/java/de/bixilon/minosoft/data/registries/versions/Versions.java index 95c275a67..4e9632565 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/versions/Versions.java +++ b/src/main/java/de/bixilon/minosoft/data/registries/versions/Versions.java @@ -26,7 +26,7 @@ import java.util.Map; @Deprecated public class Versions { - public static final Version AUTOMATIC_VERSION = new Version("Automatic", -1, -1, Map.of(), Map.of()); + public static final Version AUTOMATIC_VERSION = new Version("Automatic", -1, -1, new HashMap<>(), new HashMap<>()); public static final HashBiMap VERSION_ID_MAP = HashBiMap.create(500); private static final HashBiMap VERSION_PROTOCOL_ID_MAP = HashBiMap.create(500); private static final HashBiMap VERSION_NAME_MAP = HashBiMap.create(500); diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarProtectionElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarProtectionElement.kt index d803c62f0..057fd21e1 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarProtectionElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarProtectionElement.kt @@ -70,7 +70,7 @@ class HotbarProtectionElement(hudRenderer: HUDRenderer) : Element(hudRenderer), } override fun forceSilentApply() { - _size = if (protection <= 0.0f) { // ToDo: This notifies the parent, should we really notify it in silentApply? + _size = if (protection <= 0.0f) { Vec2i.EMPTY } else { SIZE diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/JavaBackport.java b/src/main/java/de/bixilon/minosoft/gui/rendering/util/JavaBackport.java new file mode 100644 index 000000000..c96fe8e4d --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/JavaBackport.java @@ -0,0 +1,124 @@ +package de.bixilon.minosoft.gui.rendering.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class JavaBackport { + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; + private static final int DEFAULT_BUFFER_SIZE = 8192; + + /** + * Reads up to a specified number of bytes from the input stream. This + * method blocks until the requested number of bytes has been read, end + * of stream is detected, or an exception is thrown. This method does not + * close the input stream. + * + *

The length of the returned array equals the number of bytes read + * from the stream. If {@code len} is zero, then no bytes are read and + * an empty byte array is returned. Otherwise, up to {@code len} bytes + * are read from the stream. Fewer than {@code len} bytes may be read if + * end of stream is encountered. + * + *

When this stream reaches end of stream, further invocations of this + * method will return an empty byte array. + * + *

Note that this method is intended for simple cases where it is + * convenient to read the specified number of bytes into a byte array. The + * total amount of memory allocated by this method is proportional to the + * number of bytes read from the stream which is bounded by {@code len}. + * Therefore, the method may be safely called with very large values of + * {@code len} provided sufficient memory is available. + * + *

The behavior for the case where the input stream is asynchronously + * closed, or the thread interrupted during the read, is highly input + * stream specific, and therefore not specified. + * + *

If an I/O error occurs reading from the input stream, then it may do + * so after some, but not all, bytes have been read. Consequently the input + * stream may not be at end of stream and may be in an inconsistent state. + * It is strongly recommended that the stream be promptly closed if an I/O + * error occurs. + * + * @param len the maximum number of bytes to read + * @return a byte array containing the bytes read from this input stream + * @throws IllegalArgumentException if {@code length} is negative + * @throws IOException if an I/O error occurs + * @throws OutOfMemoryError if an array of the required size cannot be + * allocated. + * @implNote The number of bytes allocated to read data from this stream and return + * the result is bounded by {@code 2*(long)len}, inclusive. + * @since 11 + */ + public static byte[] readNBytes(InputStream in, int len) throws IOException { + if (len < 0) { + throw new IllegalArgumentException("len < 0"); + } + + List bufs = null; + byte[] result = null; + int total = 0; + int remaining = len; + int n; + do { + byte[] buf = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)]; + int nread = 0; + + // read to EOF which may read more or less than buffer size + while ((n = in.read(buf, nread, + Math.min(buf.length - nread, remaining))) > 0) { + nread += n; + remaining -= n; + } + + if (nread > 0) { + if (MAX_BUFFER_SIZE - total < nread) { + throw new OutOfMemoryError("Required array size too large"); + } + if (nread < buf.length) { + buf = Arrays.copyOfRange(buf, 0, nread); + } + total += nread; + if (result == null) { + result = buf; + } else { + if (bufs == null) { + bufs = new ArrayList<>(); + bufs.add(result); + } + bufs.add(buf); + } + } + // if the last call to read returned -1 or the number of bytes + // requested have been read then break + } while (n >= 0 && remaining > 0); + + if (bufs == null) { + if (result == null) { + return new byte[0]; + } + return result.length == total ? + result : Arrays.copyOf(result, total); + } + + result = new byte[total]; + int offset = 0; + remaining = total; + for (byte[] b : bufs) { + int count = Math.min(b.length, remaining); + System.arraycopy(b, 0, result, offset, count); + offset += count; + remaining -= count; + } + + return result; + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/socket/BlockingSocketNetwork.java b/src/main/java/de/bixilon/minosoft/protocol/network/socket/BlockingSocketNetwork.java index e7442535c..4d3195730 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/socket/BlockingSocketNetwork.java +++ b/src/main/java/de/bixilon/minosoft/protocol/network/socket/BlockingSocketNetwork.java @@ -13,6 +13,7 @@ package de.bixilon.minosoft.protocol.network.socket; +import de.bixilon.minosoft.gui.rendering.util.JavaBackport; import de.bixilon.minosoft.protocol.exceptions.PacketParseException; import de.bixilon.minosoft.protocol.exceptions.PacketTooLongException; import de.bixilon.minosoft.protocol.network.Network; @@ -233,7 +234,7 @@ public class BlockingSocketNetwork extends Network { throw new PacketTooLongException(packetLength); } - byte[] bytes = this.inputStream.readNBytes(packetLength); + byte[] bytes = JavaBackport.readNBytes(inputStream, packetLength); return super.receiveS2CPacket(bytes); } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketSender.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketSender.java index a02cb02a6..503528f74 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketSender.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketSender.java @@ -23,6 +23,7 @@ import de.bixilon.minosoft.protocol.packets.c2s.play.ChatMessageC2SP; import de.bixilon.minosoft.protocol.packets.c2s.play.ClientActionC2SP; import de.bixilon.minosoft.util.logging.Log; import de.bixilon.minosoft.util.logging.LogMessageType; +import org.apache.commons.lang3.StringUtils; @Deprecated public class PacketSender { @@ -34,7 +35,7 @@ public class PacketSender { } public void sendChatMessage(String message) { - if (message.isBlank()) { + if (StringUtils.isBlank(message)) { // throw new IllegalArgumentException(("Chat message is blank!")); return; } diff --git a/src/main/java/de/bixilon/minosoft/terminal/CLI.java b/src/main/java/de/bixilon/minosoft/terminal/CLI.java index 34482195d..097f430f1 100644 --- a/src/main/java/de/bixilon/minosoft/terminal/CLI.java +++ b/src/main/java/de/bixilon/minosoft/terminal/CLI.java @@ -28,6 +28,7 @@ import de.bixilon.minosoft.util.ShutdownManager; import de.bixilon.minosoft.util.logging.Log; import de.bixilon.minosoft.util.logging.LogLevels; import de.bixilon.minosoft.util.logging.LogMessageType; +import org.apache.commons.lang3.StringUtils; import org.jline.reader.LineReader; import org.jline.reader.LineReaderBuilder; import org.jline.reader.UserInterruptException; @@ -49,7 +50,7 @@ public class CLI { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { for (ClassPath.ClassInfo info : ClassPath.from(classLoader).getTopLevelClasses()) { - if (!info.getName().startsWith(Command.class.getPackageName())) { + if (!info.getName().startsWith(Command.class.getPackage().getName())) { continue; } Class clazz = info.load(); @@ -102,7 +103,7 @@ public class CLI { return; } terminal.flush(); - if (line.isBlank()) { + if (StringUtils.isBlank(line)) { continue; } ROOT_NODE.execute(currentConnection, new CommandStringReader(line), new CommandStack()); diff --git a/src/main/java/de/bixilon/minosoft/util/Util.java b/src/main/java/de/bixilon/minosoft/util/Util.java index e5eb0eaf6..bfd348627 100644 --- a/src/main/java/de/bixilon/minosoft/util/Util.java +++ b/src/main/java/de/bixilon/minosoft/util/Util.java @@ -310,9 +310,13 @@ public final class Util { if (builder.length() != 0) { builder.append("&"); } - builder.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8)); - builder.append("="); - builder.append(URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8)); + try { + builder.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name())); + builder.append("="); + builder.append(URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8.name())); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } } return builder.toString(); }