From 11a01e22ec596fbd3045cf228f21d965b20f8365 Mon Sep 17 00:00:00 2001 From: Querz Date: Thu, 3 Jan 2019 10:24:14 +0100 Subject: [PATCH 01/25] compareTo should throw exception when comparing two incompatible types --- src/main/java/net/querz/nbt/CompoundTag.java | 2 +- src/main/java/net/querz/nbt/ListTag.java | 3 ++- src/test/java/net/querz/nbt/CompoundTagTest.java | 2 +- src/test/java/net/querz/nbt/ListTagTest.java | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/querz/nbt/CompoundTag.java b/src/main/java/net/querz/nbt/CompoundTag.java index a51e5256..7d6ccef6 100644 --- a/src/main/java/net/querz/nbt/CompoundTag.java +++ b/src/main/java/net/querz/nbt/CompoundTag.java @@ -287,7 +287,7 @@ public boolean equals(Object other) { @Override public int compareTo(Tag>> o) { if (!(o instanceof CompoundTag)) { - return 0; + throw new IllegalArgumentException("cannot compare " + getClass().getSimpleName() + " and " + (o == null ? "null" : o.getClass().getSimpleName())); } return Integer.compare(size(), o.getValue().size()); } diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index 03bd5387..334aa7cf 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -309,7 +309,8 @@ public int hashCode() { @Override public int compareTo(Tag> o) { if (!(o instanceof ListTag)) { - return 0; + throw new IllegalArgumentException( + "cannot compare " + getClass().getSimpleName() + "and" + (o == null ? "null" : o.getClass().getSimpleName())); } return Integer.compare(size(), o.getValue().size()); } diff --git a/src/test/java/net/querz/nbt/CompoundTagTest.java b/src/test/java/net/querz/nbt/CompoundTagTest.java index f28d06cc..4120f31b 100644 --- a/src/test/java/net/querz/nbt/CompoundTagTest.java +++ b/src/test/java/net/querz/nbt/CompoundTagTest.java @@ -262,7 +262,7 @@ public void testCompareTo() { co.remove("five"); co.remove("four"); assertEquals(1, ci.compareTo(co)); - assertEquals(0, ci.compareTo(null)); + assertThrowsRuntimeException(() -> ci.compareTo(null), IllegalArgumentException.class); } public void testMaxDepth() { diff --git a/src/test/java/net/querz/nbt/ListTagTest.java b/src/test/java/net/querz/nbt/ListTagTest.java index 3f8a340f..6adab634 100644 --- a/src/test/java/net/querz/nbt/ListTagTest.java +++ b/src/test/java/net/querz/nbt/ListTagTest.java @@ -218,7 +218,7 @@ public void testCompareTo() { lo.remove(2); lo.remove(1); assertEquals(1, li.compareTo(lo)); - assertEquals(0, li.compareTo(null)); + assertThrowsRuntimeException(() -> li.compareTo(null), IllegalArgumentException.class); } public void testMaxDepth() { From 4156b50f435cdd07b695c86adf228a03ad5edef3 Mon Sep 17 00:00:00 2001 From: Querz Date: Thu, 3 Jan 2019 10:26:43 +0100 Subject: [PATCH 02/25] CompoundTag and ListTag should clear their original value during deserialisation --- src/main/java/net/querz/nbt/CompoundTag.java | 1 + src/main/java/net/querz/nbt/ListTag.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/querz/nbt/CompoundTag.java b/src/main/java/net/querz/nbt/CompoundTag.java index 7d6ccef6..08d33f29 100644 --- a/src/main/java/net/querz/nbt/CompoundTag.java +++ b/src/main/java/net/querz/nbt/CompoundTag.java @@ -231,6 +231,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { @Override public void deserializeValue(DataInputStream dis, int depth) throws IOException { + clear(); for (int id = dis.readByte() & 0xFF; id != 0; id = dis.readByte() & 0xFF) { Tag tag = TagFactory.fromID(id); String name = dis.readUTF(); diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index 334aa7cf..18e2d80f 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -255,8 +255,8 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException typeClass = TagFactory.classFromID(typeID); } int size = dis.readInt(); + setValue(new ArrayList<>(size)); if (size != 0) { - setValue(new ArrayList<>(size)); for (int i = 0; i < size; i++) { Tag tag = TagFactory.fromID(typeID); tag.deserializeValue(dis, incrementDepth(depth)); From 84f13eabe2fc868579b3bed0a2fc0e71ac07c49b Mon Sep 17 00:00:00 2001 From: Querz Date: Thu, 3 Jan 2019 10:42:25 +0100 Subject: [PATCH 03/25] handle negative ListTag and StructTag size --- src/main/java/net/querz/nbt/ListTag.java | 1 + src/main/java/net/querz/nbt/custom/StructTag.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index 18e2d80f..8ae537db 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -255,6 +255,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException typeClass = TagFactory.classFromID(typeID); } int size = dis.readInt(); + size = size < 0 ? 0 : size; setValue(new ArrayList<>(size)); if (size != 0) { for (int i = 0; i < size; i++) { diff --git a/src/main/java/net/querz/nbt/custom/StructTag.java b/src/main/java/net/querz/nbt/custom/StructTag.java index 27a5a200..a7849046 100644 --- a/src/main/java/net/querz/nbt/custom/StructTag.java +++ b/src/main/java/net/querz/nbt/custom/StructTag.java @@ -237,6 +237,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { @Override public void deserializeValue(DataInputStream dis, int depth) throws IOException { int size = dis.readInt(); + size = size < 0 ? 0 : size; setValue(new ArrayList<>(size)); for (int i = 0; i < size; i++) { Tag tag = TagFactory.fromID(dis.readByte()); From 92c478ede827aa34b9afcd9c2b94263d8b18c79c Mon Sep 17 00:00:00 2001 From: Querz Date: Thu, 3 Jan 2019 10:56:38 +0100 Subject: [PATCH 04/25] make toString() and toTagString() final to force child classes to use the depth parameter --- src/main/java/net/querz/nbt/Tag.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/querz/nbt/Tag.java b/src/main/java/net/querz/nbt/Tag.java index a137a7f5..ea75c36f 100644 --- a/src/main/java/net/querz/nbt/Tag.java +++ b/src/main/java/net/querz/nbt/Tag.java @@ -147,7 +147,7 @@ public static Tag deserialize(DataInputStream dis, int depth) throws IOExcept * @see Tag#toString(int) * */ @Override - public String toString() { + public final String toString() { return toString(0); } @@ -175,7 +175,7 @@ public String toString(int depth) { * @see Tag#toTagString(int) * @return The JSON-like string representation of this Tag. * */ - public String toTagString() { + public final String toTagString() { return toTagString(0); } From eafa5b1f618565b70342aa61abdd76f7e64aada2 Mon Sep 17 00:00:00 2001 From: Querz Date: Wed, 9 Jan 2019 15:08:54 +0100 Subject: [PATCH 05/25] invert max depth calculation --- src/main/java/net/querz/nbt/CompoundTag.java | 8 ++-- src/main/java/net/querz/nbt/ListTag.java | 8 ++-- src/main/java/net/querz/nbt/NBTUtil.java | 22 +++++----- src/main/java/net/querz/nbt/Tag.java | 42 +++++++++---------- .../java/net/querz/nbt/custom/StructTag.java | 8 ++-- src/main/java/net/querz/nbt/mca/Chunk.java | 4 +- .../java/net/querz/nbt/CompoundTagTest.java | 8 ++-- src/test/java/net/querz/nbt/ListTagTest.java | 6 +-- src/test/java/net/querz/nbt/NBTTestCase.java | 6 +-- 9 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/main/java/net/querz/nbt/CompoundTag.java b/src/main/java/net/querz/nbt/CompoundTag.java index 08d33f29..83081e76 100644 --- a/src/main/java/net/querz/nbt/CompoundTag.java +++ b/src/main/java/net/querz/nbt/CompoundTag.java @@ -224,7 +224,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { for (Map.Entry> e : getValue().entrySet()) { dos.writeByte(e.getValue().getID()); dos.writeUTF(e.getKey()); - e.getValue().serializeValue(dos, incrementDepth(depth)); + e.getValue().serializeValue(dos, decrementDepth(depth)); } EndTag.INSTANCE.serialize(dos, depth); } @@ -235,7 +235,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException for (int id = dis.readByte() & 0xFF; id != 0; id = dis.readByte() & 0xFF) { Tag tag = TagFactory.fromID(id); String name = dis.readUTF(); - tag.deserializeValue(dis, incrementDepth(depth)); + tag.deserializeValue(dis, decrementDepth(depth)); put(name, tag); } } @@ -247,7 +247,7 @@ public String valueToString(int depth) { for (Map.Entry> e : getValue().entrySet()) { sb.append(first ? "" : ",") .append(escapeString(e.getKey(), false)).append(":") - .append(e.getValue().toString(incrementDepth(depth))); + .append(e.getValue().toString(decrementDepth(depth))); first = false; } sb.append("}"); @@ -261,7 +261,7 @@ public String valueToTagString(int depth) { for (Map.Entry> e : getValue().entrySet()) { sb.append(first ? "" : ",") .append(escapeString(e.getKey(), true)).append(":") - .append(e.getValue().valueToTagString(incrementDepth(depth))); + .append(e.getValue().valueToTagString(decrementDepth(depth))); first = false; } sb.append("}"); diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index 8ae537db..28ad9f35 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -242,7 +242,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { dos.writeInt(size()); if (size() != 0) { for (T t : getValue()) { - t.serializeValue(dos, incrementDepth(depth)); + t.serializeValue(dos, decrementDepth(depth)); } } } @@ -260,7 +260,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException if (size != 0) { for (int i = 0; i < size; i++) { Tag tag = TagFactory.fromID(typeID); - tag.deserializeValue(dis, incrementDepth(depth)); + tag.deserializeValue(dis, decrementDepth(depth)); add((T) tag); } } @@ -270,7 +270,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException public String valueToString(int depth) { StringBuilder sb = new StringBuilder("{\"type\":\"").append(getTypeClass().getSimpleName()).append("\",\"list\":["); for (int i = 0; i < size(); i++) { - sb.append(i > 0 ? "," : "").append(get(i).valueToString(incrementDepth(depth))); + sb.append(i > 0 ? "," : "").append(get(i).valueToString(decrementDepth(depth))); } sb.append("]}"); return sb.toString(); @@ -280,7 +280,7 @@ public String valueToString(int depth) { public String valueToTagString(int depth) { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < size(); i++) { - sb.append(i > 0 ? "," : "").append(get(i).valueToTagString(incrementDepth(depth))); + sb.append(i > 0 ? "," : "").append(get(i).valueToTagString(decrementDepth(depth))); } sb.append("]"); return sb.toString(); diff --git a/src/main/java/net/querz/nbt/NBTUtil.java b/src/main/java/net/querz/nbt/NBTUtil.java index 661ed42a..b885e20a 100644 --- a/src/main/java/net/querz/nbt/NBTUtil.java +++ b/src/main/java/net/querz/nbt/NBTUtil.java @@ -26,7 +26,7 @@ private NBTUtil() {} * @param file The file to write {@code tag} into. * @throws IOException If something during the serialization goes wrong. * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String file) throws IOException { writeTag(tag, "", new File(file), true); @@ -39,7 +39,7 @@ public static void writeTag(Tag tag, String file) throws IOException { * @param file The file to write {@code tag} into. * @throws IOException If something during the serialization goes wrong. * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, File file) throws IOException { writeTag(tag, "", file, true); @@ -53,7 +53,7 @@ public static void writeTag(Tag tag, File file) throws IOException { * @param compressed {@code true} if the file should be GZIP compressed, {@code false} if not. * @throws IOException If something during the serialization goes wrong. * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String file, boolean compressed) throws IOException { writeTag(tag, "", new File(file), compressed); @@ -67,7 +67,7 @@ public static void writeTag(Tag tag, String file, boolean compressed) throws * @param compressed {@code true} if the file should be GZIP compressed, {@code false} if not. * @throws IOException If something during the serialization goes wrong. * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public static void writeTag(Tag tag, File file, boolean compressed) throws IOException { writeTag(tag, "", file, compressed); @@ -80,7 +80,7 @@ public static void writeTag(Tag tag, File file, boolean compressed) throws IO * @param file The file to write {@code tag} into. * @throws IOException If something during the serialization goes wrong. * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String name, String file) throws IOException { writeTag(tag, name, new File(file), true); @@ -94,7 +94,7 @@ public static void writeTag(Tag tag, String name, String file) throws IOExcep * @param file The file to write {@code tag} into. * @throws IOException If something during the serialization goes wrong. * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String name, File file) throws IOException { writeTag(tag, name, file, true); @@ -108,7 +108,7 @@ public static void writeTag(Tag tag, String name, File file) throws IOExcepti * @param compressed {@code true} if the file should be GZIP compressed, {@code false} if not. * @throws IOException If something during the serialization goes wrong. * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String name, String file, boolean compressed) throws IOException { writeTag(tag, name, new File(file), compressed); @@ -123,14 +123,14 @@ public static void writeTag(Tag tag, String name, String file, boolean compre * @param compressed {@code true} if the file should be GZIP compressed, {@code false} if not. * @throws IOException If something during the serialization goes wrong. * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String name, File file, boolean compressed) throws IOException { try ( DataOutputStream dos = new DataOutputStream( compressed ? new GZIPOutputStream(new FileOutputStream(file)) : new FileOutputStream(file)) ) { - tag.serialize(dos, name, 0); + tag.serialize(dos, name, Tag.DEFAULT_MAX_DEPTH); } } @@ -151,11 +151,11 @@ public static Tag readTag(String file) throws IOException { * @return The tag read from the file. * @throws IOException If something during deserialization goes wrong. * @throws NullPointerException If {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public static Tag readTag(File file) throws IOException { try (DataInputStream dis = new DataInputStream(applyDecompression(new FileInputStream(file)))) { - return Tag.deserialize(dis, 0); + return Tag.deserialize(dis, Tag.DEFAULT_MAX_DEPTH); } } diff --git a/src/main/java/net/querz/nbt/Tag.java b/src/main/java/net/querz/nbt/Tag.java index ea75c36f..79925484 100644 --- a/src/main/java/net/querz/nbt/Tag.java +++ b/src/main/java/net/querz/nbt/Tag.java @@ -14,7 +14,7 @@ public abstract class Tag implements Comparable>, Cloneable { /** * The maximum depth of the NBT structure. * */ - public static final int MAX_DEPTH = 512; + public static final int DEFAULT_MAX_DEPTH = 512; private static final Map ESCAPE_CHARACTERS; static { @@ -94,7 +94,7 @@ public final void serialize(DataOutputStream dos, int depth) throws IOException * @param depth The current depth of the structure. * @throws IOException If something went wrong during serialization. * @exception NullPointerException If {@code dos} or {@code name} is {@code null}. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public final void serialize(DataOutputStream dos, String name, int depth) throws IOException { dos.writeByte(getID()); @@ -111,7 +111,7 @@ public final void serialize(DataOutputStream dos, String name, int depth) throws * @param depth The current depth of the structure. * @throws IOException If something went wrong during deserialization. * @exception NullPointerException If {@code dis} is {@code null}. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * @return The deserialized NBT structure. * */ public static Tag deserialize(DataInputStream dis, int depth) throws IOException { @@ -129,7 +129,7 @@ public static Tag deserialize(DataInputStream dis, int depth) throws IOExcept * @param dos The DataOutputStream to write to. * @param depth The current depth of the structure. * @throws IOException If something went wrong during serialization. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public abstract void serializeValue(DataOutputStream dos, int depth) throws IOException; @@ -138,7 +138,7 @@ public static Tag deserialize(DataInputStream dis, int depth) throws IOExcept * @param dis The DataInputStream to read from. * @param depth The current depth of the structure. * @throws IOException If something went wrong during deserialization. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public abstract void deserializeValue(DataInputStream dis, int depth) throws IOException; @@ -148,14 +148,14 @@ public static Tag deserialize(DataInputStream dis, int depth) throws IOExcept * */ @Override public final String toString() { - return toString(0); + return toString(DEFAULT_MAX_DEPTH); } /** * Creates a string representation of this Tag in a valid JSON format. * @param depth The current depth of the structure. * @return The string representation of this Tag. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public String toString(int depth) { return "{\"type\":\""+ getClass().getSimpleName() + "\"," + @@ -166,7 +166,7 @@ public String toString(int depth) { * Returns a JSON representation of the value of this Tag. * @param depth The current depth of the structure. * @return The string representation of the value of this Tag. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public abstract String valueToString(int depth); @@ -176,14 +176,14 @@ public String toString(int depth) { * @return The JSON-like string representation of this Tag. * */ public final String toTagString() { - return toTagString(0); + return toTagString(DEFAULT_MAX_DEPTH); } /** * Returns a JSON-like representation of the value of this Tag, usually used for Minecraft commands. * @param depth The current depth of the structure. * @return The JSON-like string representation of this Tag. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public String toTagString(int depth) { return valueToTagString(depth); @@ -193,7 +193,7 @@ public String toTagString(int depth) { * Returns a JSON-like representation of the value of this Tag. * @param depth The current depth of the structure. * @return The JSON-like string representation of the value of this Tag. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#MAX_DEPTH}. + * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public abstract String valueToTagString(int depth); @@ -242,20 +242,16 @@ protected V checkNull(V v) { } /** - * Increments {@code depth} by {@code 1}. - * @param depth The value to increment. - * @return The incremented value. - * @exception MaxDepthReachedException If {@code depth} is {@code >=} {@link Tag#MAX_DEPTH}. - * @exception IllegalArgumentException If {@code depth} is {@code <} {@code 0} + * Decrements {@code depth} by {@code 1}. + * @param depth The value to decrement. + * @return The decremented value. + * @exception MaxDepthReachedException If {@code depth <= 0}. * */ - protected int incrementDepth(int depth) { - if (depth >= MAX_DEPTH) { - throw new MaxDepthReachedException("reached maximum depth (" + Tag.MAX_DEPTH + ") of NBT structure"); + protected int decrementDepth(int depth) { + if (depth <= 0) { + throw new MaxDepthReachedException("reached maximum depth of NBT structure"); } - if (depth < 0) { - throw new IllegalArgumentException("initial depth cannot be negative"); - } - return ++depth; + return --depth; } /** diff --git a/src/main/java/net/querz/nbt/custom/StructTag.java b/src/main/java/net/querz/nbt/custom/StructTag.java index a7849046..37da0a2d 100644 --- a/src/main/java/net/querz/nbt/custom/StructTag.java +++ b/src/main/java/net/querz/nbt/custom/StructTag.java @@ -230,7 +230,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { dos.writeInt(size()); for (Tag tag : getValue()) { dos.writeByte(tag.getID()); - tag.serializeValue(dos, incrementDepth(depth)); + tag.serializeValue(dos, decrementDepth(depth)); } } @@ -241,7 +241,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException setValue(new ArrayList<>(size)); for (int i = 0; i < size; i++) { Tag tag = TagFactory.fromID(dis.readByte()); - tag.deserializeValue(dis, incrementDepth(depth)); + tag.deserializeValue(dis, decrementDepth(depth)); add(tag); } } @@ -250,7 +250,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException public String valueToString(int depth) { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < size(); i++) { - sb.append(i > 0 ? "," : "").append(get(i).toString(incrementDepth(depth))); + sb.append(i > 0 ? "," : "").append(get(i).toString(decrementDepth(depth))); } sb.append("]"); return sb.toString(); @@ -260,7 +260,7 @@ public String valueToString(int depth) { public String valueToTagString(int depth) { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < size(); i++) { - sb.append(i > 0 ? "," : "").append(get(i).valueToTagString(incrementDepth(depth))); + sb.append(i > 0 ? "," : "").append(get(i).valueToTagString(decrementDepth(depth))); } sb.append("]"); return sb.toString(); diff --git a/src/main/java/net/querz/nbt/mca/Chunk.java b/src/main/java/net/querz/nbt/mca/Chunk.java index b56a7a57..3f0ae94d 100644 --- a/src/main/java/net/querz/nbt/mca/Chunk.java +++ b/src/main/java/net/querz/nbt/mca/Chunk.java @@ -81,7 +81,7 @@ private void initReferences() { public int serialize(RandomAccessFile raf, int xPos, int zPos) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); try (DataOutputStream nbtOut = new DataOutputStream(new BufferedOutputStream(CompressionType.ZLIB.compress(baos)))) { - updateHandle(xPos, zPos).serialize(nbtOut, 0); + updateHandle(xPos, zPos).serialize(nbtOut, Tag.DEFAULT_MAX_DEPTH); } byte[] rawData = baos.toByteArray(); raf.writeInt(rawData.length); @@ -97,7 +97,7 @@ public void deserialize(RandomAccessFile raf) throws IOException { throw new IOException("invalid compression type " + compressionTypeByte); } DataInputStream dis = new DataInputStream(new BufferedInputStream(compressionType.decompress(new FileInputStream(raf.getFD())))); - Tag tag = Tag.deserialize(dis, 0); + Tag tag = Tag.deserialize(dis, Tag.DEFAULT_MAX_DEPTH); if (tag instanceof CompoundTag) { data = (CompoundTag) tag; initReferences(); diff --git a/src/test/java/net/querz/nbt/CompoundTagTest.java b/src/test/java/net/querz/nbt/CompoundTagTest.java index 4120f31b..f77e5789 100644 --- a/src/test/java/net/querz/nbt/CompoundTagTest.java +++ b/src/test/java/net/querz/nbt/CompoundTagTest.java @@ -268,17 +268,19 @@ public void testCompareTo() { public void testMaxDepth() { CompoundTag root = new CompoundTag(); CompoundTag rec = root; - for (int i = 0; i < Tag.MAX_DEPTH + 1; i++) { + for (int i = 0; i < Tag.DEFAULT_MAX_DEPTH + 1; i++) { CompoundTag c = new CompoundTag(); rec.put("c" + i, c); rec = c; } assertThrowsRuntimeException(() -> serialize(root), MaxDepthReachedException.class); assertThrowsRuntimeException(() -> deserializeFromFile("max_depth_reached.dat"), MaxDepthReachedException.class); + assertThrowsNoRuntimeException(() -> root.toString(Tag.DEFAULT_MAX_DEPTH + 1)); assertThrowsRuntimeException(root::toString, MaxDepthReachedException.class); + assertThrowsNoRuntimeException(() -> root.toTagString(Tag.DEFAULT_MAX_DEPTH + 1)); assertThrowsRuntimeException(root::toTagString, MaxDepthReachedException.class); - assertThrowsRuntimeException(() -> root.valueToString(-1), IllegalArgumentException.class); - assertThrowsRuntimeException(() -> root.valueToTagString(-1), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> root.valueToString(-1), MaxDepthReachedException.class); + assertThrowsRuntimeException(() -> root.valueToTagString(-1), MaxDepthReachedException.class); } public void testRecursion() { diff --git a/src/test/java/net/querz/nbt/ListTagTest.java b/src/test/java/net/querz/nbt/ListTagTest.java index 6adab634..6c5e1fa4 100644 --- a/src/test/java/net/querz/nbt/ListTagTest.java +++ b/src/test/java/net/querz/nbt/ListTagTest.java @@ -224,7 +224,7 @@ public void testCompareTo() { public void testMaxDepth() { ListTag> root = new ListTag<>(ListTag.class); ListTag> rec = root; - for (int i = 0; i < Tag.MAX_DEPTH + 1; i++) { + for (int i = 0; i < Tag.DEFAULT_MAX_DEPTH + 1; i++) { ListTag> l = new ListTag<>(ListTag.class); rec.add(l); rec = l; @@ -233,8 +233,8 @@ public void testMaxDepth() { assertThrowsRuntimeException(() -> deserializeFromFile("max_depth_reached.dat"), MaxDepthReachedException.class); assertThrowsRuntimeException(root::toString, MaxDepthReachedException.class); assertThrowsRuntimeException(root::toTagString, MaxDepthReachedException.class); - assertThrowsRuntimeException(() -> root.valueToString(-1), IllegalArgumentException.class); - assertThrowsRuntimeException(() -> root.valueToTagString(-1), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> root.valueToString(-1), MaxDepthReachedException.class); + assertThrowsRuntimeException(() -> root.valueToTagString(-1), MaxDepthReachedException.class); } public void testRecursion() { diff --git a/src/test/java/net/querz/nbt/NBTTestCase.java b/src/test/java/net/querz/nbt/NBTTestCase.java index 33582b50..52d00aa5 100644 --- a/src/test/java/net/querz/nbt/NBTTestCase.java +++ b/src/test/java/net/querz/nbt/NBTTestCase.java @@ -34,7 +34,7 @@ public void tearDown() throws Exception { protected byte[] serialize(Tag tag) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream dos = new DataOutputStream(baos)) { - tag.serialize(dos, 0); + tag.serialize(dos, Tag.DEFAULT_MAX_DEPTH); } catch (IOException ex) { ex.printStackTrace(); fail(ex.getMessage()); @@ -44,7 +44,7 @@ protected byte[] serialize(Tag tag) { protected Tag deserialize(byte[] data) { try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data))) { - return Tag.deserialize(dis, 0); + return Tag.deserialize(dis, Tag.DEFAULT_MAX_DEPTH); } catch (IOException ex) { ex.printStackTrace(); fail(ex.getMessage()); @@ -60,7 +60,7 @@ protected File getResourceFile(String name) { protected Tag deserializeFromFile(String f) { try (DataInputStream dis = new DataInputStream(new FileInputStream(getResourceFile(f)))) { - return Tag.deserialize(dis, 0); + return Tag.deserialize(dis, Tag.DEFAULT_MAX_DEPTH); } catch (IOException ex) { ex.printStackTrace(); fail(ex.getMessage()); From eddc18f420782a12b3c9abef1c889193819bc065 Mon Sep 17 00:00:00 2001 From: Querz Date: Fri, 11 Jan 2019 11:04:04 +0100 Subject: [PATCH 06/25] compareTo should throw a NPE when comparing to null / add sort to ListTag --- src/main/java/net/querz/nbt/ArrayTag.java | 2 +- src/main/java/net/querz/nbt/ListTag.java | 5 +++++ src/main/java/net/querz/nbt/NumberTag.java | 2 +- src/main/java/net/querz/nbt/custom/StructTag.java | 4 ++++ src/test/java/net/querz/nbt/ByteArrayTagTest.java | 2 +- src/test/java/net/querz/nbt/ByteTagTest.java | 2 +- src/test/java/net/querz/nbt/DoubleTagTest.java | 2 +- src/test/java/net/querz/nbt/FloatTagTest.java | 2 +- src/test/java/net/querz/nbt/IntArrayTagTest.java | 2 +- src/test/java/net/querz/nbt/IntTagTest.java | 2 +- src/test/java/net/querz/nbt/LongArrayTagTest.java | 2 +- src/test/java/net/querz/nbt/LongTagTest.java | 2 +- src/test/java/net/querz/nbt/ShortTagTest.java | 2 +- src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java | 2 +- 14 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/querz/nbt/ArrayTag.java b/src/main/java/net/querz/nbt/ArrayTag.java index 46016a78..32a87bce 100644 --- a/src/main/java/net/querz/nbt/ArrayTag.java +++ b/src/main/java/net/querz/nbt/ArrayTag.java @@ -37,7 +37,7 @@ public String valueToString(int depth) { @Override public int compareTo(Tag other) { - if (!(other instanceof ArrayTag) || this.getClass() != other.getClass()) { + if (this.getClass() != other.getClass()) { throw new IllegalArgumentException("array types are incompatible"); } return Integer.compare(Array.getLength(getValue()), Array.getLength(other.getValue())); diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index 28ad9f35..fd4e42d1 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; @@ -82,6 +83,10 @@ public void sort(Comparator comparator) { getValue().sort(comparator); } + public void sort() { + Collections.sort(getValue()); + } + @Override public Iterator iterator() { return getValue().iterator(); diff --git a/src/main/java/net/querz/nbt/NumberTag.java b/src/main/java/net/querz/nbt/NumberTag.java index 01a608b9..bea895dc 100644 --- a/src/main/java/net/querz/nbt/NumberTag.java +++ b/src/main/java/net/querz/nbt/NumberTag.java @@ -39,7 +39,7 @@ public String valueToString(int depth) { @Override public int compareTo(Tag other) { - if (!(other instanceof NumberTag) || this.getClass() != other.getClass()) { + if (this.getClass() != other.getClass()) { throw new IllegalArgumentException("number types are incompatible"); } return getValue().compareTo(other.getValue()); diff --git a/src/main/java/net/querz/nbt/custom/StructTag.java b/src/main/java/net/querz/nbt/custom/StructTag.java index 37da0a2d..ef34852c 100644 --- a/src/main/java/net/querz/nbt/custom/StructTag.java +++ b/src/main/java/net/querz/nbt/custom/StructTag.java @@ -57,6 +57,10 @@ public boolean containsAll(Collection> tags) { return getValue().containsAll(tags); } + public void sort(Comparator> comparator) { + getValue().sort(comparator); + } + @Override public Iterator> iterator() { return getValue().iterator(); diff --git a/src/test/java/net/querz/nbt/ByteArrayTagTest.java b/src/test/java/net/querz/nbt/ByteArrayTagTest.java index 157ba3cb..1058154f 100644 --- a/src/test/java/net/querz/nbt/ByteArrayTagTest.java +++ b/src/test/java/net/querz/nbt/ByteArrayTagTest.java @@ -47,7 +47,7 @@ public void testCompareTo() { assertEquals(0, t.compareTo(t3)); assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); - assertThrowsRuntimeException(() -> t.compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); } public void testInvalidType() { diff --git a/src/test/java/net/querz/nbt/ByteTagTest.java b/src/test/java/net/querz/nbt/ByteTagTest.java index e25d2b7a..de8b604a 100644 --- a/src/test/java/net/querz/nbt/ByteTagTest.java +++ b/src/test/java/net/querz/nbt/ByteTagTest.java @@ -42,7 +42,7 @@ public void testCompareTo() { assertEquals(0, new ByteTag((byte) 5).compareTo(new ByteTag((byte) 5))); assertTrue(0 < new ByteTag((byte) 7).compareTo(new ByteTag((byte) 5))); assertTrue(0 > new ByteTag((byte) 5).compareTo(new ByteTag((byte) 7))); - assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(null), NullPointerException.class); } public void testBoolean() { diff --git a/src/test/java/net/querz/nbt/DoubleTagTest.java b/src/test/java/net/querz/nbt/DoubleTagTest.java index c4a68bfb..2444aebc 100644 --- a/src/test/java/net/querz/nbt/DoubleTagTest.java +++ b/src/test/java/net/querz/nbt/DoubleTagTest.java @@ -39,6 +39,6 @@ public void testCompareTo() { assertEquals(0, new DoubleTag(5).compareTo(new DoubleTag(5))); assertTrue(0 < new DoubleTag(7).compareTo(new DoubleTag(5))); assertTrue(0 > new DoubleTag(5).compareTo(new DoubleTag(7))); - assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(null), NullPointerException.class); } } diff --git a/src/test/java/net/querz/nbt/FloatTagTest.java b/src/test/java/net/querz/nbt/FloatTagTest.java index 92b47a09..1d6e8172 100644 --- a/src/test/java/net/querz/nbt/FloatTagTest.java +++ b/src/test/java/net/querz/nbt/FloatTagTest.java @@ -39,6 +39,6 @@ public void testCompareTo() { assertEquals(0, new FloatTag(5).compareTo(new FloatTag(5))); assertTrue(0 < new FloatTag(7).compareTo(new FloatTag(5))); assertTrue(0 > new FloatTag(5).compareTo(new FloatTag(7))); - assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(null), NullPointerException.class); } } diff --git a/src/test/java/net/querz/nbt/IntArrayTagTest.java b/src/test/java/net/querz/nbt/IntArrayTagTest.java index e369896e..e02c686e 100644 --- a/src/test/java/net/querz/nbt/IntArrayTagTest.java +++ b/src/test/java/net/querz/nbt/IntArrayTagTest.java @@ -45,6 +45,6 @@ public void testCompareTo() { assertEquals(0, t.compareTo(t3)); assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); - assertThrowsRuntimeException(() -> t.compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); } } diff --git a/src/test/java/net/querz/nbt/IntTagTest.java b/src/test/java/net/querz/nbt/IntTagTest.java index 305f7670..d62ad42e 100644 --- a/src/test/java/net/querz/nbt/IntTagTest.java +++ b/src/test/java/net/querz/nbt/IntTagTest.java @@ -40,6 +40,6 @@ public void testCompareTo() { assertEquals(0, new IntTag(5).compareTo(new IntTag(5))); assertTrue(0 < new IntTag(7).compareTo(new IntTag(5))); assertTrue(0 > new IntTag(5).compareTo(new IntTag(7))); - assertThrowsRuntimeException(() -> new IntTag(5).compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new IntTag(5).compareTo(null), NullPointerException.class); } } diff --git a/src/test/java/net/querz/nbt/LongArrayTagTest.java b/src/test/java/net/querz/nbt/LongArrayTagTest.java index 8d8e92bc..a2fe39c4 100644 --- a/src/test/java/net/querz/nbt/LongArrayTagTest.java +++ b/src/test/java/net/querz/nbt/LongArrayTagTest.java @@ -45,6 +45,6 @@ public void testCompareTo() { assertEquals(0, t.compareTo(t3)); assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); - assertThrowsRuntimeException(() -> t.compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); } } diff --git a/src/test/java/net/querz/nbt/LongTagTest.java b/src/test/java/net/querz/nbt/LongTagTest.java index 3d2ccef4..6d9ea1e1 100644 --- a/src/test/java/net/querz/nbt/LongTagTest.java +++ b/src/test/java/net/querz/nbt/LongTagTest.java @@ -39,6 +39,6 @@ public void testCompareTo() { assertEquals(0, new LongTag(5).compareTo(new LongTag(5))); assertTrue(0 < new LongTag(7).compareTo(new LongTag(5))); assertTrue(0 > new LongTag(5).compareTo(new LongTag(7))); - assertThrowsRuntimeException(() -> new LongTag(5).compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new LongTag(5).compareTo(null), NullPointerException.class); } } diff --git a/src/test/java/net/querz/nbt/ShortTagTest.java b/src/test/java/net/querz/nbt/ShortTagTest.java index 20017a0b..ec039a7d 100644 --- a/src/test/java/net/querz/nbt/ShortTagTest.java +++ b/src/test/java/net/querz/nbt/ShortTagTest.java @@ -41,6 +41,6 @@ public void testCompareTo() { assertEquals(0, new ShortTag((short) 5).compareTo(new ShortTag((short) 5))); assertTrue(0 < new ShortTag((short) 7).compareTo(new ShortTag((short) 5))); assertTrue(0 > new ShortTag((short) 5).compareTo(new ShortTag((short) 7))); - assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(null), NullPointerException.class); } } diff --git a/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java b/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java index 924104ee..b4a7fd5b 100644 --- a/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java +++ b/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java @@ -56,6 +56,6 @@ public void testCompareTo() { assertEquals(0, t.compareTo(t3)); assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); - assertThrowsRuntimeException(() -> t.compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); } } From fa1687d5cf04a47633285027164a85f9b5ee6b70 Mon Sep 17 00:00:00 2001 From: Querz Date: Fri, 11 Jan 2019 11:47:38 +0100 Subject: [PATCH 07/25] update unit tests for compareTo / remove StructTag#sort() --- .../java/net/querz/nbt/custom/StructTag.java | 4 -- .../java/net/querz/nbt/ByteArrayTagTest.java | 1 + src/test/java/net/querz/nbt/ByteTagTest.java | 1 + .../java/net/querz/nbt/DoubleTagTest.java | 1 + .../java/net/querz/nbt/DummyArrayTag.java | 37 +++++++++++++++++++ .../java/net/querz/nbt/DummyNumberTag.java | 33 +++++++++++++++++ src/test/java/net/querz/nbt/FloatTagTest.java | 1 + .../java/net/querz/nbt/IntArrayTagTest.java | 1 + src/test/java/net/querz/nbt/IntTagTest.java | 1 + src/test/java/net/querz/nbt/ListTagTest.java | 6 +++ .../java/net/querz/nbt/LongArrayTagTest.java | 1 + src/test/java/net/querz/nbt/LongTagTest.java | 1 + src/test/java/net/querz/nbt/ShortTagTest.java | 1 + .../querz/nbt/custom/ShortArrayTagTest.java | 2 + 14 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 src/test/java/net/querz/nbt/DummyArrayTag.java create mode 100644 src/test/java/net/querz/nbt/DummyNumberTag.java diff --git a/src/main/java/net/querz/nbt/custom/StructTag.java b/src/main/java/net/querz/nbt/custom/StructTag.java index ef34852c..37da0a2d 100644 --- a/src/main/java/net/querz/nbt/custom/StructTag.java +++ b/src/main/java/net/querz/nbt/custom/StructTag.java @@ -57,10 +57,6 @@ public boolean containsAll(Collection> tags) { return getValue().containsAll(tags); } - public void sort(Comparator> comparator) { - getValue().sort(comparator); - } - @Override public Iterator> iterator() { return getValue().iterator(); diff --git a/src/test/java/net/querz/nbt/ByteArrayTagTest.java b/src/test/java/net/querz/nbt/ByteArrayTagTest.java index 1058154f..3cfb0230 100644 --- a/src/test/java/net/querz/nbt/ByteArrayTagTest.java +++ b/src/test/java/net/querz/nbt/ByteArrayTagTest.java @@ -48,6 +48,7 @@ public void testCompareTo() { assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> t.compareTo(new DummyArrayTag<>(new byte[0])), IllegalArgumentException.class); } public void testInvalidType() { diff --git a/src/test/java/net/querz/nbt/ByteTagTest.java b/src/test/java/net/querz/nbt/ByteTagTest.java index de8b604a..c203b121 100644 --- a/src/test/java/net/querz/nbt/ByteTagTest.java +++ b/src/test/java/net/querz/nbt/ByteTagTest.java @@ -43,6 +43,7 @@ public void testCompareTo() { assertTrue(0 < new ByteTag((byte) 7).compareTo(new ByteTag((byte) 5))); assertTrue(0 > new ByteTag((byte) 5).compareTo(new ByteTag((byte) 7))); assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); } public void testBoolean() { diff --git a/src/test/java/net/querz/nbt/DoubleTagTest.java b/src/test/java/net/querz/nbt/DoubleTagTest.java index 2444aebc..63680bf5 100644 --- a/src/test/java/net/querz/nbt/DoubleTagTest.java +++ b/src/test/java/net/querz/nbt/DoubleTagTest.java @@ -40,5 +40,6 @@ public void testCompareTo() { assertTrue(0 < new DoubleTag(7).compareTo(new DoubleTag(5))); assertTrue(0 > new DoubleTag(5).compareTo(new DoubleTag(7))); assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/DummyArrayTag.java b/src/test/java/net/querz/nbt/DummyArrayTag.java new file mode 100644 index 00000000..c230d76d --- /dev/null +++ b/src/test/java/net/querz/nbt/DummyArrayTag.java @@ -0,0 +1,37 @@ +package net.querz.nbt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class DummyArrayTag extends ArrayTag { + + public DummyArrayTag(T value) { + super(value); + } + + @Override + protected T getEmptyValue() { + return null; + } + + @Override + public void serializeValue(DataOutputStream dos, int depth) throws IOException { + + } + + @Override + public void deserializeValue(DataInputStream dis, int depth) throws IOException { + + } + + @Override + public String valueToTagString(int depth) { + return null; + } + + @Override + public Tag clone() { + return null; + } +} diff --git a/src/test/java/net/querz/nbt/DummyNumberTag.java b/src/test/java/net/querz/nbt/DummyNumberTag.java new file mode 100644 index 00000000..4b598173 --- /dev/null +++ b/src/test/java/net/querz/nbt/DummyNumberTag.java @@ -0,0 +1,33 @@ +package net.querz.nbt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class DummyNumberTag> extends NumberTag { + + @Override + protected T getEmptyValue() { + return null; + } + + @Override + public void serializeValue(DataOutputStream dos, int depth) throws IOException { + + } + + @Override + public void deserializeValue(DataInputStream dis, int depth) throws IOException { + + } + + @Override + public String valueToTagString(int depth) { + return null; + } + + @Override + public Tag clone() { + return null; + } +} diff --git a/src/test/java/net/querz/nbt/FloatTagTest.java b/src/test/java/net/querz/nbt/FloatTagTest.java index 1d6e8172..7566274d 100644 --- a/src/test/java/net/querz/nbt/FloatTagTest.java +++ b/src/test/java/net/querz/nbt/FloatTagTest.java @@ -40,5 +40,6 @@ public void testCompareTo() { assertTrue(0 < new FloatTag(7).compareTo(new FloatTag(5))); assertTrue(0 > new FloatTag(5).compareTo(new FloatTag(7))); assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/IntArrayTagTest.java b/src/test/java/net/querz/nbt/IntArrayTagTest.java index e02c686e..9db957b4 100644 --- a/src/test/java/net/querz/nbt/IntArrayTagTest.java +++ b/src/test/java/net/querz/nbt/IntArrayTagTest.java @@ -46,5 +46,6 @@ public void testCompareTo() { assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> t.compareTo(new DummyArrayTag<>(new int[0])), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/IntTagTest.java b/src/test/java/net/querz/nbt/IntTagTest.java index d62ad42e..2c35775d 100644 --- a/src/test/java/net/querz/nbt/IntTagTest.java +++ b/src/test/java/net/querz/nbt/IntTagTest.java @@ -41,5 +41,6 @@ public void testCompareTo() { assertTrue(0 < new IntTag(7).compareTo(new IntTag(5))); assertTrue(0 > new IntTag(5).compareTo(new IntTag(7))); assertThrowsRuntimeException(() -> new IntTag(5).compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> new IntTag(5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/ListTagTest.java b/src/test/java/net/querz/nbt/ListTagTest.java index 6c5e1fa4..f907a503 100644 --- a/src/test/java/net/querz/nbt/ListTagTest.java +++ b/src/test/java/net/querz/nbt/ListTagTest.java @@ -262,6 +262,12 @@ public void testSort() { l.sort(Comparator.comparingInt(NumberTag::asInt)); assertEquals(1, l.get(0).asInt()); assertEquals(2, l.get(1).asInt()); + ListTag l2 = new ListTag<>(IntTag.class); + l2.addInt(2); + l2.addInt(1); + l2.sort(); + assertEquals(1, l.get(0).asInt()); + assertEquals(2, l.get(1).asInt()); } public void testIterator() { diff --git a/src/test/java/net/querz/nbt/LongArrayTagTest.java b/src/test/java/net/querz/nbt/LongArrayTagTest.java index a2fe39c4..0a10b57e 100644 --- a/src/test/java/net/querz/nbt/LongArrayTagTest.java +++ b/src/test/java/net/querz/nbt/LongArrayTagTest.java @@ -46,5 +46,6 @@ public void testCompareTo() { assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> t.compareTo(new DummyArrayTag<>(new long[0])), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/LongTagTest.java b/src/test/java/net/querz/nbt/LongTagTest.java index 6d9ea1e1..73fab16f 100644 --- a/src/test/java/net/querz/nbt/LongTagTest.java +++ b/src/test/java/net/querz/nbt/LongTagTest.java @@ -40,5 +40,6 @@ public void testCompareTo() { assertTrue(0 < new LongTag(7).compareTo(new LongTag(5))); assertTrue(0 > new LongTag(5).compareTo(new LongTag(7))); assertThrowsRuntimeException(() -> new LongTag(5).compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> new LongTag(5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/ShortTagTest.java b/src/test/java/net/querz/nbt/ShortTagTest.java index ec039a7d..e56c7bcb 100644 --- a/src/test/java/net/querz/nbt/ShortTagTest.java +++ b/src/test/java/net/querz/nbt/ShortTagTest.java @@ -42,5 +42,6 @@ public void testCompareTo() { assertTrue(0 < new ShortTag((short) 7).compareTo(new ShortTag((short) 5))); assertTrue(0 > new ShortTag((short) 5).compareTo(new ShortTag((short) 7))); assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java b/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java index b4a7fd5b..0a606d96 100644 --- a/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java +++ b/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java @@ -1,5 +1,6 @@ package net.querz.nbt.custom; +import net.querz.nbt.DummyArrayTag; import net.querz.nbt.NBTTestCase; import java.util.Arrays; import static org.junit.Assert.assertNotEquals; @@ -57,5 +58,6 @@ public void testCompareTo() { assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); + assertThrowsRuntimeException(() -> t.compareTo(new DummyArrayTag<>(new short[0])), IllegalArgumentException.class); } } From 664f597c2ab864e4f5ba1fe357f3a5e0dfea3512 Mon Sep 17 00:00:00 2001 From: Querz Date: Mon, 21 Jan 2019 16:07:01 +0100 Subject: [PATCH 08/25] remove Tag#getEmptyValue() --- src/main/java/net/querz/nbt/ArrayTag.java | 2 +- src/main/java/net/querz/nbt/ByteArrayTag.java | 9 ++--- src/main/java/net/querz/nbt/ByteTag.java | 11 +++--- src/main/java/net/querz/nbt/CompoundTag.java | 37 ++++++++++--------- src/main/java/net/querz/nbt/DoubleTag.java | 11 +++--- src/main/java/net/querz/nbt/EndTag.java | 5 --- src/main/java/net/querz/nbt/FloatTag.java | 11 +++--- src/main/java/net/querz/nbt/IntArrayTag.java | 9 ++--- src/main/java/net/querz/nbt/IntTag.java | 11 +++--- src/main/java/net/querz/nbt/ListTag.java | 33 ++++++++++------- src/main/java/net/querz/nbt/LongArrayTag.java | 9 ++--- src/main/java/net/querz/nbt/LongTag.java | 11 +++--- src/main/java/net/querz/nbt/ShortTag.java | 11 +++--- src/main/java/net/querz/nbt/StringTag.java | 13 +++---- src/main/java/net/querz/nbt/Tag.java | 33 ++++------------- .../java/net/querz/nbt/custom/CharTag.java | 11 +++--- .../java/net/querz/nbt/custom/ObjectTag.java | 27 +++++++++----- .../net/querz/nbt/custom/ShortArrayTag.java | 9 ++--- .../java/net/querz/nbt/custom/StructTag.java | 27 ++++++++------ .../java/net/querz/nbt/ByteArrayTagTest.java | 5 --- .../java/net/querz/nbt/DummyArrayTag.java | 5 --- .../java/net/querz/nbt/DummyNumberTag.java | 5 --- 22 files changed, 133 insertions(+), 172 deletions(-) diff --git a/src/main/java/net/querz/nbt/ArrayTag.java b/src/main/java/net/querz/nbt/ArrayTag.java index 32a87bce..93bfabc5 100644 --- a/src/main/java/net/querz/nbt/ArrayTag.java +++ b/src/main/java/net/querz/nbt/ArrayTag.java @@ -27,7 +27,7 @@ public T getValue() { @Override public void setValue(T value) { - super.setValue(checkNull(value)); + super.setValue(value); } @Override diff --git a/src/main/java/net/querz/nbt/ByteArrayTag.java b/src/main/java/net/querz/nbt/ByteArrayTag.java index 1a306659..2a5d7e40 100644 --- a/src/main/java/net/querz/nbt/ByteArrayTag.java +++ b/src/main/java/net/querz/nbt/ByteArrayTag.java @@ -7,19 +7,16 @@ public class ByteArrayTag extends ArrayTag { + public static final byte[] ZERO_VALUE = new byte[0]; + public ByteArrayTag() { - super(new byte[0]); + super(ZERO_VALUE); } public ByteArrayTag(byte[] value) { super(value); } - @Override - protected byte[] getEmptyValue() { - return new byte[0]; - } - @Override public void serializeValue(DataOutputStream dos, int depth) throws IOException { dos.writeInt(length()); diff --git a/src/main/java/net/querz/nbt/ByteTag.java b/src/main/java/net/querz/nbt/ByteTag.java index 6a7a4631..e60894be 100644 --- a/src/main/java/net/querz/nbt/ByteTag.java +++ b/src/main/java/net/querz/nbt/ByteTag.java @@ -6,7 +6,11 @@ public class ByteTag extends NumberTag { - public ByteTag() {} + public static final byte ZERO_VALUE = 0; + + public ByteTag() { + super(ZERO_VALUE); + } public ByteTag(byte value) { super(value); @@ -16,11 +20,6 @@ public ByteTag(boolean value) { super((byte) (value ? 1 : 0)); } - @Override - protected Byte getEmptyValue() { - return 0; - } - public boolean asBoolean() { return getValue() > 0; } diff --git a/src/main/java/net/querz/nbt/CompoundTag.java b/src/main/java/net/querz/nbt/CompoundTag.java index 83081e76..2e693ec0 100644 --- a/src/main/java/net/querz/nbt/CompoundTag.java +++ b/src/main/java/net/querz/nbt/CompoundTag.java @@ -8,10 +8,11 @@ public class CompoundTag extends Tag>> implements Iterable>> { - public CompoundTag() {} + public CompoundTag() { + setValue(createEmptyValue()); + } - @Override - protected Map> getEmptyValue() { + private Map> createEmptyValue() { return new HashMap<>(8); } @@ -123,56 +124,56 @@ public boolean getBoolean(String key) { public byte getByte(String key) { ByteTag t = getByteTag(key); - return t == null ? new ByteTag().getEmptyValue() : t.asByte(); + return t == null ? ByteTag.ZERO_VALUE : t.asByte(); } public short getShort(String key) { ShortTag t = getShortTag(key); - return t == null ? new ShortTag().getEmptyValue() : t.asShort(); + return t == null ? ShortTag.ZERO_VALUE : t.asShort(); } public int getInt(String key) { IntTag t = getIntTag(key); - return t == null ? new IntTag().getEmptyValue() : t.asInt(); + return t == null ? IntTag.ZERO_VALUE : t.asInt(); } public long getLong(String key) { LongTag t = getLongTag(key); - return t == null ? new LongTag().getEmptyValue() : t.asLong(); + return t == null ? LongTag.ZERO_VALUE : t.asLong(); } public float getFloat(String key) { FloatTag t = getFloatTag(key); - return t == null ? new FloatTag().getEmptyValue() : t.asFloat(); + return t == null ? FloatTag.ZERO_VALUE : t.asFloat(); } public double getDouble(String key) { DoubleTag t = getDoubleTag(key); - return t == null ? new DoubleTag().getEmptyValue() : t.asDouble(); + return t == null ? DoubleTag.ZERO_VALUE : t.asDouble(); } public String getString(String key) { StringTag t = getStringTag(key); - return t == null ? new StringTag().getEmptyValue() : t.getValue(); + return t == null ? StringTag.ZERO_VALUE : t.getValue(); } public byte[] getByteArray(String key) { ByteArrayTag t = getByteArrayTag(key); - return t == null ? new ByteArrayTag().getEmptyValue() : t.getValue(); + return t == null ? ByteArrayTag.ZERO_VALUE : t.getValue(); } public int[] getIntArray(String key) { IntArrayTag t = getIntArrayTag(key); - return t == null ? new IntArrayTag().getEmptyValue() : t.getValue(); + return t == null ? IntArrayTag.ZERO_VALUE : t.getValue(); } public long[] getLongArray(String key) { LongArrayTag t = getLongArrayTag(key); - return t == null ? new LongArrayTag().getEmptyValue() : t.getValue(); + return t == null ? LongArrayTag.ZERO_VALUE : t.getValue(); } public Tag put(String key, Tag tag) { - return getValue().put(checkNull(key), checkNull(tag)); + return getValue().put(Objects.requireNonNull(key), Objects.requireNonNull(tag)); } public Tag putBoolean(String key, boolean value) { @@ -204,19 +205,19 @@ public Tag putDouble(String key, double value) { } public Tag putString(String key, String value) { - return put(key, new StringTag(checkNull(value))); + return put(key, new StringTag(value)); } public Tag putByteArray(String key, byte[] value) { - return put(key, new ByteArrayTag(checkNull(value))); + return put(key, new ByteArrayTag(value)); } public Tag putIntArray(String key, int[] value) { - return put(key, new IntArrayTag(checkNull(value))); + return put(key, new IntArrayTag(value)); } public Tag putLongArray(String key, long[] value) { - return put(key, new LongArrayTag(checkNull(value))); + return put(key, new LongArrayTag(value)); } @Override diff --git a/src/main/java/net/querz/nbt/DoubleTag.java b/src/main/java/net/querz/nbt/DoubleTag.java index 2b9f4293..7de6c3b7 100644 --- a/src/main/java/net/querz/nbt/DoubleTag.java +++ b/src/main/java/net/querz/nbt/DoubleTag.java @@ -6,15 +6,14 @@ public class DoubleTag extends NumberTag { - public DoubleTag() {} + public static final double ZERO_VALUE = 0.0D; - public DoubleTag(double value) { - super(value); + public DoubleTag() { + super(ZERO_VALUE); } - @Override - protected Double getEmptyValue() { - return 0.0d; + public DoubleTag(double value) { + super(value); } public void setValue(double value) { diff --git a/src/main/java/net/querz/nbt/EndTag.java b/src/main/java/net/querz/nbt/EndTag.java index 7b4ade40..4a74f651 100644 --- a/src/main/java/net/querz/nbt/EndTag.java +++ b/src/main/java/net/querz/nbt/EndTag.java @@ -9,11 +9,6 @@ public final class EndTag extends Tag { private EndTag() {} - @Override - protected Void getEmptyValue() { - return null; - } - @Override public void serializeValue(DataOutputStream dos, int depth) { //nothing to do diff --git a/src/main/java/net/querz/nbt/FloatTag.java b/src/main/java/net/querz/nbt/FloatTag.java index 101a0919..9a706651 100644 --- a/src/main/java/net/querz/nbt/FloatTag.java +++ b/src/main/java/net/querz/nbt/FloatTag.java @@ -6,15 +6,14 @@ public class FloatTag extends NumberTag { - public FloatTag() {} + public static final float ZERO_VALUE = 0.0F; - public FloatTag(float value) { - super(value); + public FloatTag() { + super(ZERO_VALUE); } - @Override - protected Float getEmptyValue() { - return 0.0f; + public FloatTag(float value) { + super(value); } public void setValue(float value) { diff --git a/src/main/java/net/querz/nbt/IntArrayTag.java b/src/main/java/net/querz/nbt/IntArrayTag.java index afbfe8ba..f5bbb798 100644 --- a/src/main/java/net/querz/nbt/IntArrayTag.java +++ b/src/main/java/net/querz/nbt/IntArrayTag.java @@ -7,19 +7,16 @@ public class IntArrayTag extends ArrayTag { + public static final int[] ZERO_VALUE = new int[0]; + public IntArrayTag() { - super(new int[0]); + super(ZERO_VALUE); } public IntArrayTag(int[] value) { super(value); } - @Override - protected int[] getEmptyValue() { - return new int[0]; - } - @Override public void serializeValue(DataOutputStream dos, int depth) throws IOException { dos.writeInt(length()); diff --git a/src/main/java/net/querz/nbt/IntTag.java b/src/main/java/net/querz/nbt/IntTag.java index a0b513bf..23ccdd93 100644 --- a/src/main/java/net/querz/nbt/IntTag.java +++ b/src/main/java/net/querz/nbt/IntTag.java @@ -6,15 +6,14 @@ public class IntTag extends NumberTag { - public IntTag() {} + public static final int ZERO_VALUE = 0; - public IntTag(int value) { - super(value); + public IntTag() { + super(ZERO_VALUE); } - @Override - protected Integer getEmptyValue() { - return 0; + public IntTag(int value) { + super(value); } public void setValue(int value) { diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index fd4e42d1..cf4eefa7 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -23,7 +23,9 @@ public class ListTag> extends Tag> implements Iterable< private Class typeClass = null; - private ListTag() {} + private ListTag() { + setValue(createEmptyValue()); + } /** *

Creates a non-type-safe ListTag. Its element type will be set after the first @@ -38,27 +40,32 @@ protected static ListTag createUnchecked() { return new ListTag<>(); } + /** + *

Creates an empty typed value for this ListTag

+ * + * @return A typed instance of {@link java.util.List} with an initial capacity of 3 + * */ + private List createEmptyValue() { + return new ArrayList<>(3); + } + /** * @param typeClass The exact class of the elements * @throws IllegalArgumentException When {@code typeClass} is {@link EndTag}{@code .class} * @throws NullPointerException When {@code typeClass} is {@code null} */ public ListTag(Class typeClass) throws IllegalArgumentException, NullPointerException { + super(new ArrayList<>(3)); if (typeClass == EndTag.class) { throw new IllegalArgumentException("cannot create ListTag with EndTag elements"); } - this.typeClass = checkNull(typeClass); + this.typeClass = Objects.requireNonNull(typeClass); } public Class getTypeClass() { return typeClass == null ? EndTag.class : typeClass; } - @Override - protected List getEmptyValue() { - return new ArrayList<>(3); - } - public int size() { return getValue().size(); } @@ -98,7 +105,7 @@ public void forEach(Consumer action) { } public T set(int index, T t) { - return getValue().set(index, checkNull(t)); + return getValue().set(index, Objects.requireNonNull(t)); } /** @@ -110,7 +117,7 @@ public void add(T t) { } public void add(int index, T t) { - checkNull(t); + Objects.requireNonNull(t); getValue().add(index, t); if (typeClass == null) { typeClass = t.getClass(); @@ -160,19 +167,19 @@ public void addDouble(double value) { } public void addString(String value) { - addUnchecked(new StringTag(checkNull(value))); + addUnchecked(new StringTag(value)); } public void addByteArray(byte[] value) { - addUnchecked(new ByteArrayTag(checkNull(value))); + addUnchecked(new ByteArrayTag(value)); } public void addIntArray(int[] value) { - addUnchecked(new IntArrayTag(checkNull(value))); + addUnchecked(new IntArrayTag(value)); } public void addLongArray(long[] value) { - addUnchecked(new LongArrayTag(checkNull(value))); + addUnchecked(new LongArrayTag(value)); } public T get(int index) { diff --git a/src/main/java/net/querz/nbt/LongArrayTag.java b/src/main/java/net/querz/nbt/LongArrayTag.java index 39d24e57..b2d6931c 100644 --- a/src/main/java/net/querz/nbt/LongArrayTag.java +++ b/src/main/java/net/querz/nbt/LongArrayTag.java @@ -7,19 +7,16 @@ public class LongArrayTag extends ArrayTag { + public static final long[] ZERO_VALUE = new long[0]; + public LongArrayTag() { - super(new long[0]); + super(ZERO_VALUE); } public LongArrayTag(long[] value) { super(value); } - @Override - protected long[] getEmptyValue() { - return new long[0]; - } - @Override public void serializeValue(DataOutputStream dos, int depth) throws IOException { dos.writeInt(length()); diff --git a/src/main/java/net/querz/nbt/LongTag.java b/src/main/java/net/querz/nbt/LongTag.java index 125615cb..3b2cde2d 100644 --- a/src/main/java/net/querz/nbt/LongTag.java +++ b/src/main/java/net/querz/nbt/LongTag.java @@ -6,15 +6,14 @@ public class LongTag extends NumberTag { - public LongTag() {} + public static final long ZERO_VALUE = 0L; - public LongTag(long value) { - super(value); + public LongTag() { + super(ZERO_VALUE); } - @Override - protected Long getEmptyValue() { - return 0L; + public LongTag(long value) { + super(value); } public void setValue(long value) { diff --git a/src/main/java/net/querz/nbt/ShortTag.java b/src/main/java/net/querz/nbt/ShortTag.java index 7976c208..f26efe5a 100644 --- a/src/main/java/net/querz/nbt/ShortTag.java +++ b/src/main/java/net/querz/nbt/ShortTag.java @@ -6,15 +6,14 @@ public class ShortTag extends NumberTag { - public ShortTag() {} + public static final short ZERO_VALUE = 0; - public ShortTag(short value) { - super(value); + public ShortTag() { + super(ZERO_VALUE); } - @Override - protected Short getEmptyValue() { - return 0; + public ShortTag(short value) { + super(value); } public void setValue(short value) { diff --git a/src/main/java/net/querz/nbt/StringTag.java b/src/main/java/net/querz/nbt/StringTag.java index 6da10b78..abab9f6c 100644 --- a/src/main/java/net/querz/nbt/StringTag.java +++ b/src/main/java/net/querz/nbt/StringTag.java @@ -6,15 +6,14 @@ public class StringTag extends Tag { - public StringTag() {} + public static final String ZERO_VALUE = ""; - public StringTag(String value) { - super(value); + public StringTag() { + super(ZERO_VALUE); } - @Override - protected String getEmptyValue() { - return ""; + public StringTag(String value) { + super(value); } @Override @@ -24,7 +23,7 @@ public String getValue() { @Override public void setValue(String value) { - super.setValue(checkNull(value)); + super.setValue(value); } @Override diff --git a/src/main/java/net/querz/nbt/Tag.java b/src/main/java/net/querz/nbt/Tag.java index 79925484..0620dcdc 100644 --- a/src/main/java/net/querz/nbt/Tag.java +++ b/src/main/java/net/querz/nbt/Tag.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,18 +36,17 @@ public abstract class Tag implements Comparable>, Cloneable { /** * Initializes this Tag with a {@code null} value. */ - public Tag() { - this(null); + protected Tag() { + value = null; } /** - * Initializes this Tag with some value. If the value is {@code null}, it will call - * this Tag's implementation of {@link Tag#getEmptyValue()} to set as the default value. + * Initializes this Tag with some value. If the value is {@code null}, it will + * throw a {@code NullPointerException} * @param value The value to be set for this Tag. * */ public Tag(T value) { - //the value of a tag can never be null - this.value = value == null ? getEmptyValue() : value; + setValue(value); } /** @@ -56,11 +56,6 @@ public byte getID() { return TagFactory.idFromClass(getClass()); } - /** - * @return A default value for this Tag. - * */ - protected abstract T getEmptyValue(); - /** * @return The value of this Tag. * */ @@ -73,7 +68,7 @@ protected T getValue() { * @param value The value to be set. * */ protected void setValue(T value) { - this.value = value; + this.value = Objects.requireNonNull(value); } /** @@ -227,20 +222,6 @@ public int hashCode() { @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException") public abstract Tag clone(); - /** - * A utility method to check if some value is {@code null}. - * @param Any type that should be checked for being {@code null} - * @param v The value to check. - * @return {@code v}, if it's not {@code null}. - * @exception NullPointerException If {@code v} is {@code null}. - * */ - protected V checkNull(V v) { - if (v == null) { - throw new NullPointerException(getClass().getSimpleName() + " does not allow setting null"); - } - return v; - } - /** * Decrements {@code depth} by {@code 1}. * @param depth The value to decrement. diff --git a/src/main/java/net/querz/nbt/custom/CharTag.java b/src/main/java/net/querz/nbt/custom/CharTag.java index 9adaa4cf..d84822e1 100644 --- a/src/main/java/net/querz/nbt/custom/CharTag.java +++ b/src/main/java/net/querz/nbt/custom/CharTag.java @@ -8,21 +8,20 @@ public class CharTag extends Tag { + public static final char ZERO_VALUE = '\u0000'; + public static void register() { TagFactory.registerCustomTag(110, CharTag::new, CharTag.class); } - public CharTag() {} + public CharTag() { + super(ZERO_VALUE); + } public CharTag(char value) { super(value); } - @Override - protected Character getEmptyValue() { - return 0; - } - @Override public Character getValue() { return super.getValue(); diff --git a/src/main/java/net/querz/nbt/custom/ObjectTag.java b/src/main/java/net/querz/nbt/custom/ObjectTag.java index a31d76e6..70855256 100644 --- a/src/main/java/net/querz/nbt/custom/ObjectTag.java +++ b/src/main/java/net/querz/nbt/custom/ObjectTag.java @@ -2,8 +2,13 @@ import net.querz.nbt.Tag; import net.querz.nbt.TagFactory; - -import java.io.*; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.util.Objects; @@ -13,15 +18,14 @@ public static void register() { TagFactory.registerCustomTag(90, ObjectTag::new, ObjectTag.class); } - public ObjectTag() {} - - public ObjectTag(T value) { - super(value); + public ObjectTag() { + // ObjectTag can have a null value, so we don't initialize anything here } - @Override - protected T getEmptyValue() { - return null; + public ObjectTag(T value) { + if (value != null) { + setValue(value); + } } @Override @@ -49,7 +53,10 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { @Override public void deserializeValue(DataInputStream dis, int depth) throws IOException { try { - setValue((T) new ObjectInputStream(dis).readObject()); + T obj = (T) new ObjectInputStream(dis).readObject(); + if (obj != null) { + setValue(obj); + } } catch (InvalidClassException | ClassNotFoundException e) { throw new IOException(e.getCause()); } diff --git a/src/main/java/net/querz/nbt/custom/ShortArrayTag.java b/src/main/java/net/querz/nbt/custom/ShortArrayTag.java index 7c98bf60..52197c5d 100644 --- a/src/main/java/net/querz/nbt/custom/ShortArrayTag.java +++ b/src/main/java/net/querz/nbt/custom/ShortArrayTag.java @@ -9,23 +9,20 @@ public class ShortArrayTag extends ArrayTag { + public static final short[] ZERO_VALUE = new short[0]; + public static void register() { TagFactory.registerCustomTag(100, ShortArrayTag::new, ShortArrayTag.class); } public ShortArrayTag() { - super(new short[0]); + super(ZERO_VALUE); } public ShortArrayTag(short[] value) { super(value); } - @Override - protected short[] getEmptyValue() { - return new short[0]; - } - @Override public void serializeValue(DataOutputStream dos, int depth) throws IOException { dos.writeInt(length()); diff --git a/src/main/java/net/querz/nbt/custom/StructTag.java b/src/main/java/net/querz/nbt/custom/StructTag.java index 37da0a2d..ba6a3e29 100644 --- a/src/main/java/net/querz/nbt/custom/StructTag.java +++ b/src/main/java/net/querz/nbt/custom/StructTag.java @@ -17,7 +17,11 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; import java.util.function.Consumer; public class StructTag extends Tag>> implements Iterable> { @@ -26,10 +30,11 @@ public static void register() { TagFactory.registerCustomTag(120, StructTag::new, StructTag.class); } - public StructTag() {} + public StructTag() { + setValue(createEmptyValue()); + } - @Override - protected List> getEmptyValue() { + private List> createEmptyValue() { return new ArrayList<>(3); } @@ -170,15 +175,15 @@ public long[] getLongArray(int index) { } public Tag set(int index, Tag tag) { - return getValue().set(index, checkNull(tag)); + return getValue().set(index, Objects.requireNonNull(tag)); } public void add(Tag tag) { - getValue().add(checkNull(tag)); + getValue().add(Objects.requireNonNull(tag)); } public void add(int index, Tag tag) { - getValue().add(index, checkNull(tag)); + getValue().add(index, Objects.requireNonNull(tag)); } public void addBoolean(boolean value) { @@ -210,19 +215,19 @@ public void addDouble(double value) { } public void addString(String value) { - add(new StringTag(checkNull(value))); + add(new StringTag(value)); } public void addByteArray(byte[] value) { - add(new ByteArrayTag(checkNull(value))); + add(new ByteArrayTag(value)); } public void addIntArray(int[] value) { - add(new IntArrayTag(checkNull(value))); + add(new IntArrayTag(value)); } public void addLongArray(long[] value) { - add(new LongArrayTag(checkNull(value))); + add(new LongArrayTag(value)); } @Override diff --git a/src/test/java/net/querz/nbt/ByteArrayTagTest.java b/src/test/java/net/querz/nbt/ByteArrayTagTest.java index 3cfb0230..25e4304e 100644 --- a/src/test/java/net/querz/nbt/ByteArrayTagTest.java +++ b/src/test/java/net/querz/nbt/ByteArrayTagTest.java @@ -66,11 +66,6 @@ public NotAnArrayTag(String value) { super(value); } - @Override - protected String getEmptyValue() { - return ""; - } - @Override public void serializeValue(DataOutputStream dos, int depth) { throw new UnsupportedOperationException("goddammit, this is a test class, you don't want to save it."); diff --git a/src/test/java/net/querz/nbt/DummyArrayTag.java b/src/test/java/net/querz/nbt/DummyArrayTag.java index c230d76d..949930c8 100644 --- a/src/test/java/net/querz/nbt/DummyArrayTag.java +++ b/src/test/java/net/querz/nbt/DummyArrayTag.java @@ -10,11 +10,6 @@ public DummyArrayTag(T value) { super(value); } - @Override - protected T getEmptyValue() { - return null; - } - @Override public void serializeValue(DataOutputStream dos, int depth) throws IOException { diff --git a/src/test/java/net/querz/nbt/DummyNumberTag.java b/src/test/java/net/querz/nbt/DummyNumberTag.java index 4b598173..33649aa0 100644 --- a/src/test/java/net/querz/nbt/DummyNumberTag.java +++ b/src/test/java/net/querz/nbt/DummyNumberTag.java @@ -6,11 +6,6 @@ public class DummyNumberTag> extends NumberTag { - @Override - protected T getEmptyValue() { - return null; - } - @Override public void serializeValue(DataOutputStream dos, int depth) throws IOException { From 88515875e768ca01575cda6b475bb605ea2e0d3d Mon Sep 17 00:00:00 2001 From: Querz Date: Mon, 21 Jan 2019 16:12:45 +0100 Subject: [PATCH 09/25] remove unnecessary null value assignment in Tag constructor --- src/main/java/net/querz/nbt/Tag.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/net/querz/nbt/Tag.java b/src/main/java/net/querz/nbt/Tag.java index 0620dcdc..a9f95945 100644 --- a/src/main/java/net/querz/nbt/Tag.java +++ b/src/main/java/net/querz/nbt/Tag.java @@ -36,9 +36,7 @@ public abstract class Tag implements Comparable>, Cloneable { /** * Initializes this Tag with a {@code null} value. */ - protected Tag() { - value = null; - } + protected Tag() {} /** * Initializes this Tag with some value. If the value is {@code null}, it will From f681b8719083af0c3dbad27d4656ee79b69c805a Mon Sep 17 00:00:00 2001 From: Querz Date: Mon, 21 Jan 2019 16:27:05 +0100 Subject: [PATCH 10/25] remove no-args constructor from NumberTag --- src/main/java/net/querz/nbt/NumberTag.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/net/querz/nbt/NumberTag.java b/src/main/java/net/querz/nbt/NumberTag.java index bea895dc..980d521f 100644 --- a/src/main/java/net/querz/nbt/NumberTag.java +++ b/src/main/java/net/querz/nbt/NumberTag.java @@ -2,8 +2,6 @@ public abstract class NumberTag> extends Tag { - public NumberTag() {} - public NumberTag(T value) { super(value); } From a79cfdf6b189f3a10145a26048c764db7335b954 Mon Sep 17 00:00:00 2001 From: Querz Date: Mon, 21 Jan 2019 16:32:21 +0100 Subject: [PATCH 11/25] fix unit test DummyNumberTag --- src/test/java/net/querz/nbt/ByteTagTest.java | 2 +- src/test/java/net/querz/nbt/DoubleTagTest.java | 2 +- src/test/java/net/querz/nbt/DummyNumberTag.java | 4 ++++ src/test/java/net/querz/nbt/FloatTagTest.java | 2 +- src/test/java/net/querz/nbt/IntTagTest.java | 2 +- src/test/java/net/querz/nbt/LongTagTest.java | 2 +- src/test/java/net/querz/nbt/ShortTagTest.java | 2 +- 7 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/test/java/net/querz/nbt/ByteTagTest.java b/src/test/java/net/querz/nbt/ByteTagTest.java index c203b121..6c4acba7 100644 --- a/src/test/java/net/querz/nbt/ByteTagTest.java +++ b/src/test/java/net/querz/nbt/ByteTagTest.java @@ -43,7 +43,7 @@ public void testCompareTo() { assertTrue(0 < new ByteTag((byte) 7).compareTo(new ByteTag((byte) 5))); assertTrue(0 > new ByteTag((byte) 5).compareTo(new ByteTag((byte) 7))); assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(new DummyNumberTag<>((byte) 0)), IllegalArgumentException.class); } public void testBoolean() { diff --git a/src/test/java/net/querz/nbt/DoubleTagTest.java b/src/test/java/net/querz/nbt/DoubleTagTest.java index 63680bf5..08d1dcba 100644 --- a/src/test/java/net/querz/nbt/DoubleTagTest.java +++ b/src/test/java/net/querz/nbt/DoubleTagTest.java @@ -40,6 +40,6 @@ public void testCompareTo() { assertTrue(0 < new DoubleTag(7).compareTo(new DoubleTag(5))); assertTrue(0 > new DoubleTag(5).compareTo(new DoubleTag(7))); assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(new DummyNumberTag<>(0.0D)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/DummyNumberTag.java b/src/test/java/net/querz/nbt/DummyNumberTag.java index 33649aa0..8f4d582b 100644 --- a/src/test/java/net/querz/nbt/DummyNumberTag.java +++ b/src/test/java/net/querz/nbt/DummyNumberTag.java @@ -6,6 +6,10 @@ public class DummyNumberTag> extends NumberTag { + public DummyNumberTag(T value) { + super(value); + } + @Override public void serializeValue(DataOutputStream dos, int depth) throws IOException { diff --git a/src/test/java/net/querz/nbt/FloatTagTest.java b/src/test/java/net/querz/nbt/FloatTagTest.java index 7566274d..f58b7f24 100644 --- a/src/test/java/net/querz/nbt/FloatTagTest.java +++ b/src/test/java/net/querz/nbt/FloatTagTest.java @@ -40,6 +40,6 @@ public void testCompareTo() { assertTrue(0 < new FloatTag(7).compareTo(new FloatTag(5))); assertTrue(0 > new FloatTag(5).compareTo(new FloatTag(7))); assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(new DummyNumberTag<>(0.0F)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/IntTagTest.java b/src/test/java/net/querz/nbt/IntTagTest.java index 2c35775d..4f0e412a 100644 --- a/src/test/java/net/querz/nbt/IntTagTest.java +++ b/src/test/java/net/querz/nbt/IntTagTest.java @@ -41,6 +41,6 @@ public void testCompareTo() { assertTrue(0 < new IntTag(7).compareTo(new IntTag(5))); assertTrue(0 > new IntTag(5).compareTo(new IntTag(7))); assertThrowsRuntimeException(() -> new IntTag(5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new IntTag(5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new IntTag(5).compareTo(new DummyNumberTag<>(0)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/LongTagTest.java b/src/test/java/net/querz/nbt/LongTagTest.java index 73fab16f..f295c315 100644 --- a/src/test/java/net/querz/nbt/LongTagTest.java +++ b/src/test/java/net/querz/nbt/LongTagTest.java @@ -40,6 +40,6 @@ public void testCompareTo() { assertTrue(0 < new LongTag(7).compareTo(new LongTag(5))); assertTrue(0 > new LongTag(5).compareTo(new LongTag(7))); assertThrowsRuntimeException(() -> new LongTag(5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new LongTag(5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new LongTag(5).compareTo(new DummyNumberTag<>(0L)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/ShortTagTest.java b/src/test/java/net/querz/nbt/ShortTagTest.java index e56c7bcb..66161565 100644 --- a/src/test/java/net/querz/nbt/ShortTagTest.java +++ b/src/test/java/net/querz/nbt/ShortTagTest.java @@ -42,6 +42,6 @@ public void testCompareTo() { assertTrue(0 < new ShortTag((short) 7).compareTo(new ShortTag((short) 5))); assertTrue(0 > new ShortTag((short) 5).compareTo(new ShortTag((short) 7))); assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(new DummyNumberTag<>()), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(new DummyNumberTag<>((short) 0)), IllegalArgumentException.class); } } From ea1cf0d0d37456143a0ac14c3a4ab0604cfb8c48 Mon Sep 17 00:00:00 2001 From: Querz Date: Mon, 21 Jan 2019 16:48:42 +0100 Subject: [PATCH 12/25] implement Comparable only where needed --- src/main/java/net/querz/nbt/ArrayTag.java | 4 ++-- src/main/java/net/querz/nbt/CompoundTag.java | 7 ++----- src/main/java/net/querz/nbt/EndTag.java | 5 ----- src/main/java/net/querz/nbt/ListTag.java | 13 ++----------- src/main/java/net/querz/nbt/NumberTag.java | 4 ++-- src/main/java/net/querz/nbt/StringTag.java | 7 ++----- src/main/java/net/querz/nbt/Tag.java | 2 +- src/main/java/net/querz/nbt/custom/CharTag.java | 6 +++--- src/main/java/net/querz/nbt/custom/ObjectTag.java | 9 ++++----- src/main/java/net/querz/nbt/custom/StructTag.java | 9 +++------ src/test/java/net/querz/nbt/CompoundTagTest.java | 2 +- src/test/java/net/querz/nbt/EndTagTest.java | 5 ----- src/test/java/net/querz/nbt/ListTagTest.java | 8 +------- src/test/java/net/querz/nbt/StringTagTest.java | 2 +- .../java/net/querz/nbt/custom/StructTagTest.java | 2 +- 15 files changed, 25 insertions(+), 60 deletions(-) diff --git a/src/main/java/net/querz/nbt/ArrayTag.java b/src/main/java/net/querz/nbt/ArrayTag.java index 93bfabc5..1b1d203d 100644 --- a/src/main/java/net/querz/nbt/ArrayTag.java +++ b/src/main/java/net/querz/nbt/ArrayTag.java @@ -7,7 +7,7 @@ * For implementations see {@link ByteArrayTag}, {@link IntArrayTag}, {@link LongArrayTag}. * @param The array type. * */ -public abstract class ArrayTag extends Tag { +public abstract class ArrayTag extends Tag implements Comparable> { public ArrayTag(T value) { if (!value.getClass().isArray()) { @@ -36,7 +36,7 @@ public String valueToString(int depth) { } @Override - public int compareTo(Tag other) { + public int compareTo(ArrayTag other) { if (this.getClass() != other.getClass()) { throw new IllegalArgumentException("array types are incompatible"); } diff --git a/src/main/java/net/querz/nbt/CompoundTag.java b/src/main/java/net/querz/nbt/CompoundTag.java index 2e693ec0..61b7a0fd 100644 --- a/src/main/java/net/querz/nbt/CompoundTag.java +++ b/src/main/java/net/querz/nbt/CompoundTag.java @@ -6,7 +6,7 @@ import java.util.*; import java.util.function.BiConsumer; -public class CompoundTag extends Tag>> implements Iterable>> { +public class CompoundTag extends Tag>> implements Iterable>>, Comparable { public CompoundTag() { setValue(createEmptyValue()); @@ -287,10 +287,7 @@ public boolean equals(Object other) { } @Override - public int compareTo(Tag>> o) { - if (!(o instanceof CompoundTag)) { - throw new IllegalArgumentException("cannot compare " + getClass().getSimpleName() + " and " + (o == null ? "null" : o.getClass().getSimpleName())); - } + public int compareTo(CompoundTag o) { return Integer.compare(size(), o.getValue().size()); } diff --git a/src/main/java/net/querz/nbt/EndTag.java b/src/main/java/net/querz/nbt/EndTag.java index 4a74f651..db042fb2 100644 --- a/src/main/java/net/querz/nbt/EndTag.java +++ b/src/main/java/net/querz/nbt/EndTag.java @@ -29,11 +29,6 @@ public String valueToTagString(int depth) { throw new UnsupportedOperationException("EndTag cannot be turned into a String"); } - @Override - public int compareTo(Tag o) { - return 0; - } - @Override public EndTag clone() { return INSTANCE; diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index cf4eefa7..278b4b6f 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; @@ -19,7 +18,7 @@ * The type of an empty untyped {@link ListTag} can be set by using any of the {@code add()} * methods or any of the {@code as...List()} methods. * */ -public class ListTag> extends Tag> implements Iterable { +public class ListTag> extends Tag> implements Iterable, Comparable> { private Class typeClass = null; @@ -90,10 +89,6 @@ public void sort(Comparator comparator) { getValue().sort(comparator); } - public void sort() { - Collections.sort(getValue()); - } - @Override public Iterator iterator() { return getValue().iterator(); @@ -320,11 +315,7 @@ public int hashCode() { } @Override - public int compareTo(Tag> o) { - if (!(o instanceof ListTag)) { - throw new IllegalArgumentException( - "cannot compare " + getClass().getSimpleName() + "and" + (o == null ? "null" : o.getClass().getSimpleName())); - } + public int compareTo(ListTag o) { return Integer.compare(size(), o.getValue().size()); } diff --git a/src/main/java/net/querz/nbt/NumberTag.java b/src/main/java/net/querz/nbt/NumberTag.java index 980d521f..03b44500 100644 --- a/src/main/java/net/querz/nbt/NumberTag.java +++ b/src/main/java/net/querz/nbt/NumberTag.java @@ -1,6 +1,6 @@ package net.querz.nbt; -public abstract class NumberTag> extends Tag { +public abstract class NumberTag> extends Tag implements Comparable> { public NumberTag(T value) { super(value); @@ -36,7 +36,7 @@ public String valueToString(int depth) { } @Override - public int compareTo(Tag other) { + public int compareTo(NumberTag other) { if (this.getClass() != other.getClass()) { throw new IllegalArgumentException("number types are incompatible"); } diff --git a/src/main/java/net/querz/nbt/StringTag.java b/src/main/java/net/querz/nbt/StringTag.java index abab9f6c..8e526ce5 100644 --- a/src/main/java/net/querz/nbt/StringTag.java +++ b/src/main/java/net/querz/nbt/StringTag.java @@ -4,7 +4,7 @@ import java.io.DataOutputStream; import java.io.IOException; -public class StringTag extends Tag { +public class StringTag extends Tag implements Comparable { public static final String ZERO_VALUE = ""; @@ -52,10 +52,7 @@ public boolean equals(Object other) { } @Override - public int compareTo(Tag o) { - if (o == null || o.getClass() != getClass()) { - throw new IllegalArgumentException("incompatible string types"); - } + public int compareTo(StringTag o) { return getValue().compareTo(o.getValue()); } diff --git a/src/main/java/net/querz/nbt/Tag.java b/src/main/java/net/querz/nbt/Tag.java index a9f95945..4a2688ac 100644 --- a/src/main/java/net/querz/nbt/Tag.java +++ b/src/main/java/net/querz/nbt/Tag.java @@ -10,7 +10,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public abstract class Tag implements Comparable>, Cloneable { +public abstract class Tag implements Cloneable { /** * The maximum depth of the NBT structure. diff --git a/src/main/java/net/querz/nbt/custom/CharTag.java b/src/main/java/net/querz/nbt/custom/CharTag.java index d84822e1..3070a84d 100644 --- a/src/main/java/net/querz/nbt/custom/CharTag.java +++ b/src/main/java/net/querz/nbt/custom/CharTag.java @@ -6,7 +6,7 @@ import java.io.DataOutputStream; import java.io.IOException; -public class CharTag extends Tag { +public class CharTag extends Tag implements Comparable { public static final char ZERO_VALUE = '\u0000'; @@ -57,8 +57,8 @@ public boolean equals(Object other) { } @Override - public int compareTo(Tag o) { - return Character.compare(getValue(), ((CharTag) o).getValue()); + public int compareTo(CharTag o) { + return Character.compare(getValue(), o.getValue()); } @Override diff --git a/src/main/java/net/querz/nbt/custom/ObjectTag.java b/src/main/java/net/querz/nbt/custom/ObjectTag.java index 70855256..ee3baf04 100644 --- a/src/main/java/net/querz/nbt/custom/ObjectTag.java +++ b/src/main/java/net/querz/nbt/custom/ObjectTag.java @@ -12,7 +12,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.Objects; -public class ObjectTag extends Tag { +public class ObjectTag extends Tag implements Comparable> { public static void register() { TagFactory.registerCustomTag(90, ObjectTag::new, ObjectTag.class); @@ -84,10 +84,9 @@ public int hashCode() { @SuppressWarnings("unchecked") @Override - public int compareTo(Tag o) { - ObjectTag oo = (ObjectTag) o; - if (oo.getValue() instanceof Comparable && getValue() instanceof Comparable) { - return ((Comparable) getValue()).compareTo(oo.getValue()); + public int compareTo(ObjectTag o) { + if (o.getValue() instanceof Comparable && getValue() instanceof Comparable) { + return ((Comparable) getValue()).compareTo(o.getValue()); } return 0; } diff --git a/src/main/java/net/querz/nbt/custom/StructTag.java b/src/main/java/net/querz/nbt/custom/StructTag.java index ba6a3e29..d51c6ea8 100644 --- a/src/main/java/net/querz/nbt/custom/StructTag.java +++ b/src/main/java/net/querz/nbt/custom/StructTag.java @@ -24,7 +24,7 @@ import java.util.Objects; import java.util.function.Consumer; -public class StructTag extends Tag>> implements Iterable> { +public class StructTag extends Tag>> implements Iterable>, Comparable { public static void register() { TagFactory.registerCustomTag(120, StructTag::new, StructTag.class); @@ -290,11 +290,8 @@ public int hashCode() { } @Override - public int compareTo(Tag>> o) { - if (!(o instanceof StructTag)) { - return 0; - } - return Integer.compare(size(), ((StructTag) o).size()); + public int compareTo(StructTag o) { + return Integer.compare(size(), o.size()); } @Override diff --git a/src/test/java/net/querz/nbt/CompoundTagTest.java b/src/test/java/net/querz/nbt/CompoundTagTest.java index f77e5789..f8ec4c7e 100644 --- a/src/test/java/net/querz/nbt/CompoundTagTest.java +++ b/src/test/java/net/querz/nbt/CompoundTagTest.java @@ -262,7 +262,7 @@ public void testCompareTo() { co.remove("five"); co.remove("four"); assertEquals(1, ci.compareTo(co)); - assertThrowsRuntimeException(() -> ci.compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> ci.compareTo(null), NullPointerException.class); } public void testMaxDepth() { diff --git a/src/test/java/net/querz/nbt/EndTagTest.java b/src/test/java/net/querz/nbt/EndTagTest.java index e537f2f5..72c538b5 100644 --- a/src/test/java/net/querz/nbt/EndTagTest.java +++ b/src/test/java/net/querz/nbt/EndTagTest.java @@ -18,9 +18,4 @@ public void testSerializeDeserialize() { assertThrowsNoRuntimeException(() -> EndTag.INSTANCE.serializeValue(null, 0)); assertThrowsNoRuntimeException(() -> EndTag.INSTANCE.deserializeValue(null, 0)); } - - public void testCompareTo() { - assertEquals(0, EndTag.INSTANCE.compareTo(EndTag.INSTANCE.clone())); - assertEquals(0, EndTag.INSTANCE.compareTo(null)); - } } diff --git a/src/test/java/net/querz/nbt/ListTagTest.java b/src/test/java/net/querz/nbt/ListTagTest.java index f907a503..ddc5def2 100644 --- a/src/test/java/net/querz/nbt/ListTagTest.java +++ b/src/test/java/net/querz/nbt/ListTagTest.java @@ -218,7 +218,7 @@ public void testCompareTo() { lo.remove(2); lo.remove(1); assertEquals(1, li.compareTo(lo)); - assertThrowsRuntimeException(() -> li.compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> li.compareTo(null), NullPointerException.class); } public void testMaxDepth() { @@ -262,12 +262,6 @@ public void testSort() { l.sort(Comparator.comparingInt(NumberTag::asInt)); assertEquals(1, l.get(0).asInt()); assertEquals(2, l.get(1).asInt()); - ListTag l2 = new ListTag<>(IntTag.class); - l2.addInt(2); - l2.addInt(1); - l2.sort(); - assertEquals(1, l.get(0).asInt()); - assertEquals(2, l.get(1).asInt()); } public void testIterator() { diff --git a/src/test/java/net/querz/nbt/StringTagTest.java b/src/test/java/net/querz/nbt/StringTagTest.java index caddbf7a..da6b39fb 100644 --- a/src/test/java/net/querz/nbt/StringTagTest.java +++ b/src/test/java/net/querz/nbt/StringTagTest.java @@ -56,6 +56,6 @@ public void testCompareTo() { assertEquals(0, t.compareTo(t2)); assertTrue(0 > t.compareTo(t3)); assertTrue(0 < t3.compareTo(t)); - assertThrowsRuntimeException(() -> t.compareTo(null), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); } } diff --git a/src/test/java/net/querz/nbt/custom/StructTagTest.java b/src/test/java/net/querz/nbt/custom/StructTagTest.java index f1c03855..77c8cfbc 100644 --- a/src/test/java/net/querz/nbt/custom/StructTagTest.java +++ b/src/test/java/net/querz/nbt/custom/StructTagTest.java @@ -86,7 +86,7 @@ public void testCompareTo() { so.remove(2); so.remove(1); assertEquals(1, st.compareTo(so)); - assertEquals(0, st.compareTo(null)); + assertThrowsRuntimeException(() -> st.compareTo(null), NullPointerException.class); } public void testContains() { From 26ab4847e8b703dc484d59bcefacd578b4fc0735 Mon Sep 17 00:00:00 2001 From: Querz Date: Tue, 22 Jan 2019 13:00:55 +0100 Subject: [PATCH 13/25] Make ArrayTag and NumberTag implementations implement their own Comparable Make createEmptyValue static Adjust JavaDoc Fix ObjectTag and EndTag null value Throw IllegalArgumentException when negative depth is used Remove no-args constructor in Tag --- src/main/java/net/querz/nbt/ArrayTag.java | 12 ++----- src/main/java/net/querz/nbt/ByteArrayTag.java | 8 ++++- src/main/java/net/querz/nbt/ByteTag.java | 7 +++- src/main/java/net/querz/nbt/CompoundTag.java | 11 +++++-- src/main/java/net/querz/nbt/DoubleTag.java | 7 +++- src/main/java/net/querz/nbt/EndTag.java | 9 +++++- src/main/java/net/querz/nbt/FloatTag.java | 7 +++- src/main/java/net/querz/nbt/IntArrayTag.java | 7 +++- src/main/java/net/querz/nbt/IntTag.java | 7 +++- src/main/java/net/querz/nbt/ListTag.java | 15 +++++---- src/main/java/net/querz/nbt/LongArrayTag.java | 7 +++- src/main/java/net/querz/nbt/LongTag.java | 7 +++- src/main/java/net/querz/nbt/NumberTag.java | 10 +----- src/main/java/net/querz/nbt/ShortTag.java | 7 +++- src/main/java/net/querz/nbt/Tag.java | 22 +++++++++---- .../java/net/querz/nbt/custom/ObjectTag.java | 16 +++++----- .../net/querz/nbt/custom/ShortArrayTag.java | 7 +++- .../java/net/querz/nbt/custom/StructTag.java | 4 +-- .../java/net/querz/nbt/ByteArrayTagTest.java | 1 - src/test/java/net/querz/nbt/ByteTagTest.java | 1 - .../java/net/querz/nbt/CompoundTagTest.java | 4 +-- .../java/net/querz/nbt/DoubleTagTest.java | 1 - .../java/net/querz/nbt/DummyArrayTag.java | 32 ------------------- .../java/net/querz/nbt/DummyNumberTag.java | 32 ------------------- src/test/java/net/querz/nbt/FloatTagTest.java | 1 - .../java/net/querz/nbt/IntArrayTagTest.java | 1 - src/test/java/net/querz/nbt/IntTagTest.java | 1 - src/test/java/net/querz/nbt/ListTagTest.java | 4 +-- .../java/net/querz/nbt/LongArrayTagTest.java | 1 - src/test/java/net/querz/nbt/LongTagTest.java | 1 - src/test/java/net/querz/nbt/ShortTagTest.java | 1 - .../querz/nbt/custom/ShortArrayTagTest.java | 2 -- 32 files changed, 117 insertions(+), 136 deletions(-) delete mode 100644 src/test/java/net/querz/nbt/DummyArrayTag.java delete mode 100644 src/test/java/net/querz/nbt/DummyNumberTag.java diff --git a/src/main/java/net/querz/nbt/ArrayTag.java b/src/main/java/net/querz/nbt/ArrayTag.java index 1b1d203d..ae5ade57 100644 --- a/src/main/java/net/querz/nbt/ArrayTag.java +++ b/src/main/java/net/querz/nbt/ArrayTag.java @@ -7,13 +7,13 @@ * For implementations see {@link ByteArrayTag}, {@link IntArrayTag}, {@link LongArrayTag}. * @param The array type. * */ -public abstract class ArrayTag extends Tag implements Comparable> { +public abstract class ArrayTag extends Tag { public ArrayTag(T value) { + super(value); if (!value.getClass().isArray()) { throw new UnsupportedOperationException("type of array tag must be an array"); } - setValue(value); } public int length() { @@ -35,14 +35,6 @@ public String valueToString(int depth) { return arrayToString("", ""); } - @Override - public int compareTo(ArrayTag other) { - if (this.getClass() != other.getClass()) { - throw new IllegalArgumentException("array types are incompatible"); - } - return Integer.compare(Array.getLength(getValue()), Array.getLength(other.getValue())); - } - protected String arrayToString(String prefix, String suffix) { StringBuilder sb = new StringBuilder("[").append(prefix).append("".equals(prefix) ? "" : ";"); for (int i = 0; i < length(); i++) { diff --git a/src/main/java/net/querz/nbt/ByteArrayTag.java b/src/main/java/net/querz/nbt/ByteArrayTag.java index 2a5d7e40..99c69765 100644 --- a/src/main/java/net/querz/nbt/ByteArrayTag.java +++ b/src/main/java/net/querz/nbt/ByteArrayTag.java @@ -3,9 +3,10 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.lang.reflect.Array; import java.util.Arrays; -public class ByteArrayTag extends ArrayTag { +public class ByteArrayTag extends ArrayTag implements Comparable { public static final byte[] ZERO_VALUE = new byte[0]; @@ -45,6 +46,11 @@ public int hashCode() { return Arrays.hashCode(getValue()); } + @Override + public int compareTo(ByteArrayTag other) { + return Integer.compare(length(), other.length()); + } + @Override public ByteArrayTag clone() { return new ByteArrayTag(Arrays.copyOf(getValue(), length())); diff --git a/src/main/java/net/querz/nbt/ByteTag.java b/src/main/java/net/querz/nbt/ByteTag.java index e60894be..9655bb57 100644 --- a/src/main/java/net/querz/nbt/ByteTag.java +++ b/src/main/java/net/querz/nbt/ByteTag.java @@ -4,7 +4,7 @@ import java.io.DataOutputStream; import java.io.IOException; -public class ByteTag extends NumberTag { +public class ByteTag extends NumberTag implements Comparable { public static final byte ZERO_VALUE = 0; @@ -48,6 +48,11 @@ public boolean equals(Object other) { return super.equals(other) && asByte() == ((ByteTag) other).asByte(); } + @Override + public int compareTo(ByteTag other) { + return getValue().compareTo(other.getValue()); + } + @Override public ByteTag clone() { return new ByteTag(getValue()); diff --git a/src/main/java/net/querz/nbt/CompoundTag.java b/src/main/java/net/querz/nbt/CompoundTag.java index 61b7a0fd..86097830 100644 --- a/src/main/java/net/querz/nbt/CompoundTag.java +++ b/src/main/java/net/querz/nbt/CompoundTag.java @@ -3,16 +3,21 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.function.BiConsumer; public class CompoundTag extends Tag>> implements Iterable>>, Comparable { public CompoundTag() { - setValue(createEmptyValue()); + super(createEmptyValue()); } - private Map> createEmptyValue() { + private static Map> createEmptyValue() { return new HashMap<>(8); } diff --git a/src/main/java/net/querz/nbt/DoubleTag.java b/src/main/java/net/querz/nbt/DoubleTag.java index 7de6c3b7..d9eedec1 100644 --- a/src/main/java/net/querz/nbt/DoubleTag.java +++ b/src/main/java/net/querz/nbt/DoubleTag.java @@ -4,7 +4,7 @@ import java.io.DataOutputStream; import java.io.IOException; -public class DoubleTag extends NumberTag { +public class DoubleTag extends NumberTag implements Comparable { public static final double ZERO_VALUE = 0.0D; @@ -40,6 +40,11 @@ public boolean equals(Object other) { return super.equals(other) && getValue().equals(((DoubleTag) other).getValue()); } + @Override + public int compareTo(DoubleTag other) { + return getValue().compareTo(other.getValue()); + } + @Override public DoubleTag clone() { return new DoubleTag(getValue()); diff --git a/src/main/java/net/querz/nbt/EndTag.java b/src/main/java/net/querz/nbt/EndTag.java index db042fb2..3172fe7f 100644 --- a/src/main/java/net/querz/nbt/EndTag.java +++ b/src/main/java/net/querz/nbt/EndTag.java @@ -7,7 +7,14 @@ public final class EndTag extends Tag { static final EndTag INSTANCE = new EndTag(); - private EndTag() {} + private EndTag() { + super(null); + } + + @Override + protected Void checkValue(Void value) { + return value; + } @Override public void serializeValue(DataOutputStream dos, int depth) { diff --git a/src/main/java/net/querz/nbt/FloatTag.java b/src/main/java/net/querz/nbt/FloatTag.java index 9a706651..4c6b1873 100644 --- a/src/main/java/net/querz/nbt/FloatTag.java +++ b/src/main/java/net/querz/nbt/FloatTag.java @@ -4,7 +4,7 @@ import java.io.DataOutputStream; import java.io.IOException; -public class FloatTag extends NumberTag { +public class FloatTag extends NumberTag implements Comparable { public static final float ZERO_VALUE = 0.0F; @@ -40,6 +40,11 @@ public boolean equals(Object other) { return super.equals(other) && getValue().equals(((FloatTag) other).getValue()); } + @Override + public int compareTo(FloatTag other) { + return getValue().compareTo(other.getValue()); + } + @Override public FloatTag clone() { return new FloatTag(getValue()); diff --git a/src/main/java/net/querz/nbt/IntArrayTag.java b/src/main/java/net/querz/nbt/IntArrayTag.java index f5bbb798..760833e9 100644 --- a/src/main/java/net/querz/nbt/IntArrayTag.java +++ b/src/main/java/net/querz/nbt/IntArrayTag.java @@ -5,7 +5,7 @@ import java.io.IOException; import java.util.Arrays; -public class IntArrayTag extends ArrayTag { +public class IntArrayTag extends ArrayTag implements Comparable { public static final int[] ZERO_VALUE = new int[0]; @@ -49,6 +49,11 @@ public int hashCode() { return Arrays.hashCode(getValue()); } + @Override + public int compareTo(IntArrayTag other) { + return Integer.compare(length(), other.length()); + } + @Override public IntArrayTag clone() { return new IntArrayTag(Arrays.copyOf(getValue(), length())); diff --git a/src/main/java/net/querz/nbt/IntTag.java b/src/main/java/net/querz/nbt/IntTag.java index 23ccdd93..04e25d50 100644 --- a/src/main/java/net/querz/nbt/IntTag.java +++ b/src/main/java/net/querz/nbt/IntTag.java @@ -4,7 +4,7 @@ import java.io.DataOutputStream; import java.io.IOException; -public class IntTag extends NumberTag { +public class IntTag extends NumberTag implements Comparable { public static final int ZERO_VALUE = 0; @@ -40,6 +40,11 @@ public boolean equals(Object other) { return super.equals(other) && asInt() == ((IntTag) other).asInt(); } + @Override + public int compareTo(IntTag other) { + return getValue().compareTo(other.getValue()); + } + @Override public IntTag clone() { return new IntTag(getValue()); diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index 278b4b6f..3de7c772 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -23,7 +23,7 @@ public class ListTag> extends Tag> implements Iterable< private Class typeClass = null; private ListTag() { - setValue(createEmptyValue()); + super(createEmptyValue(3)); } /** @@ -40,12 +40,13 @@ protected static ListTag createUnchecked() { } /** - *

Creates an empty typed value for this ListTag

+ *

Creates an empty mutable list to be used as empty value of ListTags.

* - * @return A typed instance of {@link java.util.List} with an initial capacity of 3 + * @param Type of the list elements + * @return An instance of {@link java.util.List} with an initial capacity of 3 * */ - private List createEmptyValue() { - return new ArrayList<>(3); + private static List createEmptyValue(int initialCapacity) { + return new ArrayList<>(initialCapacity); } /** @@ -54,7 +55,7 @@ private List createEmptyValue() { * @throws NullPointerException When {@code typeClass} is {@code null} */ public ListTag(Class typeClass) throws IllegalArgumentException, NullPointerException { - super(new ArrayList<>(3)); + super(createEmptyValue(3)); if (typeClass == EndTag.class) { throw new IllegalArgumentException("cannot create ListTag with EndTag elements"); } @@ -263,7 +264,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException } int size = dis.readInt(); size = size < 0 ? 0 : size; - setValue(new ArrayList<>(size)); + setValue(createEmptyValue(size)); if (size != 0) { for (int i = 0; i < size; i++) { Tag tag = TagFactory.fromID(typeID); diff --git a/src/main/java/net/querz/nbt/LongArrayTag.java b/src/main/java/net/querz/nbt/LongArrayTag.java index b2d6931c..f24aab9a 100644 --- a/src/main/java/net/querz/nbt/LongArrayTag.java +++ b/src/main/java/net/querz/nbt/LongArrayTag.java @@ -5,7 +5,7 @@ import java.io.IOException; import java.util.Arrays; -public class LongArrayTag extends ArrayTag { +public class LongArrayTag extends ArrayTag implements Comparable { public static final long[] ZERO_VALUE = new long[0]; @@ -49,6 +49,11 @@ public int hashCode() { return Arrays.hashCode(getValue()); } + @Override + public int compareTo(LongArrayTag other) { + return Integer.compare(length(), other.length()); + } + @Override public LongArrayTag clone() { return new LongArrayTag(Arrays.copyOf(getValue(), length())); diff --git a/src/main/java/net/querz/nbt/LongTag.java b/src/main/java/net/querz/nbt/LongTag.java index 3b2cde2d..9ca84054 100644 --- a/src/main/java/net/querz/nbt/LongTag.java +++ b/src/main/java/net/querz/nbt/LongTag.java @@ -4,7 +4,7 @@ import java.io.DataOutputStream; import java.io.IOException; -public class LongTag extends NumberTag { +public class LongTag extends NumberTag implements Comparable { public static final long ZERO_VALUE = 0L; @@ -40,6 +40,11 @@ public boolean equals(Object other) { return super.equals(other) && asLong() == ((LongTag) other).asLong(); } + @Override + public int compareTo(LongTag other) { + return getValue().compareTo(other.getValue()); + } + @Override public LongTag clone() { return new LongTag(getValue()); diff --git a/src/main/java/net/querz/nbt/NumberTag.java b/src/main/java/net/querz/nbt/NumberTag.java index 03b44500..dcd97f35 100644 --- a/src/main/java/net/querz/nbt/NumberTag.java +++ b/src/main/java/net/querz/nbt/NumberTag.java @@ -1,6 +1,6 @@ package net.querz.nbt; -public abstract class NumberTag> extends Tag implements Comparable> { +public abstract class NumberTag> extends Tag { public NumberTag(T value) { super(value); @@ -34,12 +34,4 @@ public double asDouble() { public String valueToString(int depth) { return getValue().toString(); } - - @Override - public int compareTo(NumberTag other) { - if (this.getClass() != other.getClass()) { - throw new IllegalArgumentException("number types are incompatible"); - } - return getValue().compareTo(other.getValue()); - } } diff --git a/src/main/java/net/querz/nbt/ShortTag.java b/src/main/java/net/querz/nbt/ShortTag.java index f26efe5a..81661f3d 100644 --- a/src/main/java/net/querz/nbt/ShortTag.java +++ b/src/main/java/net/querz/nbt/ShortTag.java @@ -4,7 +4,7 @@ import java.io.DataOutputStream; import java.io.IOException; -public class ShortTag extends NumberTag { +public class ShortTag extends NumberTag implements Comparable { public static final short ZERO_VALUE = 0; @@ -40,6 +40,11 @@ public boolean equals(Object other) { return super.equals(other) && asShort() == ((ShortTag) other).asShort(); } + @Override + public int compareTo(ShortTag other) { + return getValue().compareTo(other.getValue()); + } + @Override public ShortTag clone() { return new ShortTag(getValue()); diff --git a/src/main/java/net/querz/nbt/Tag.java b/src/main/java/net/querz/nbt/Tag.java index 4a2688ac..e0b28e4a 100644 --- a/src/main/java/net/querz/nbt/Tag.java +++ b/src/main/java/net/querz/nbt/Tag.java @@ -33,11 +33,6 @@ public abstract class Tag implements Cloneable { private T value; - /** - * Initializes this Tag with a {@code null} value. - */ - protected Tag() {} - /** * Initializes this Tag with some value. If the value is {@code null}, it will * throw a {@code NullPointerException} @@ -64,9 +59,20 @@ protected T getValue() { /** * Sets the value for this Tag directly. * @param value The value to be set. + * @throws NullPointerException If the value is null * */ protected void setValue(T value) { - this.value = Objects.requireNonNull(value); + this.value = checkValue(value); + } + + /** + * Checks if the value {@code value} is {@code null}. + * @param value The value to check + * @throws NullPointerException If {@code value} was {@code null} + * @return The parameter {@code value} + * */ + protected T checkValue(T value) { + return Objects.requireNonNull(value); } /** @@ -227,7 +233,9 @@ public int hashCode() { * @exception MaxDepthReachedException If {@code depth <= 0}. * */ protected int decrementDepth(int depth) { - if (depth <= 0) { + if (depth < 0) { + throw new IllegalArgumentException("negative depth is not allowed"); + } else if (depth == 0) { throw new MaxDepthReachedException("reached maximum depth of NBT structure"); } return --depth; diff --git a/src/main/java/net/querz/nbt/custom/ObjectTag.java b/src/main/java/net/querz/nbt/custom/ObjectTag.java index ee3baf04..e94645ae 100644 --- a/src/main/java/net/querz/nbt/custom/ObjectTag.java +++ b/src/main/java/net/querz/nbt/custom/ObjectTag.java @@ -19,13 +19,16 @@ public static void register() { } public ObjectTag() { - // ObjectTag can have a null value, so we don't initialize anything here + super(null); } public ObjectTag(T value) { - if (value != null) { - setValue(value); - } + super(value); + } + + @Override + protected T checkValue(T value) { + return value; } @Override @@ -53,10 +56,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { @Override public void deserializeValue(DataInputStream dis, int depth) throws IOException { try { - T obj = (T) new ObjectInputStream(dis).readObject(); - if (obj != null) { - setValue(obj); - } + setValue((T) new ObjectInputStream(dis).readObject()); } catch (InvalidClassException | ClassNotFoundException e) { throw new IOException(e.getCause()); } diff --git a/src/main/java/net/querz/nbt/custom/ShortArrayTag.java b/src/main/java/net/querz/nbt/custom/ShortArrayTag.java index 52197c5d..970cbf1c 100644 --- a/src/main/java/net/querz/nbt/custom/ShortArrayTag.java +++ b/src/main/java/net/querz/nbt/custom/ShortArrayTag.java @@ -7,7 +7,7 @@ import java.io.IOException; import java.util.Arrays; -public class ShortArrayTag extends ArrayTag { +public class ShortArrayTag extends ArrayTag implements Comparable { public static final short[] ZERO_VALUE = new short[0]; @@ -58,6 +58,11 @@ public int hashCode() { return Arrays.hashCode(getValue()); } + @Override + public int compareTo(ShortArrayTag other) { + return Integer.compare(length(), other.length()); + } + @Override public ShortArrayTag clone() { return new ShortArrayTag(Arrays.copyOf(getValue(), length())); diff --git a/src/main/java/net/querz/nbt/custom/StructTag.java b/src/main/java/net/querz/nbt/custom/StructTag.java index d51c6ea8..4757fa3e 100644 --- a/src/main/java/net/querz/nbt/custom/StructTag.java +++ b/src/main/java/net/querz/nbt/custom/StructTag.java @@ -31,10 +31,10 @@ public static void register() { } public StructTag() { - setValue(createEmptyValue()); + super(createEmptyValue()); } - private List> createEmptyValue() { + private static List> createEmptyValue() { return new ArrayList<>(3); } diff --git a/src/test/java/net/querz/nbt/ByteArrayTagTest.java b/src/test/java/net/querz/nbt/ByteArrayTagTest.java index 25e4304e..8de2f590 100644 --- a/src/test/java/net/querz/nbt/ByteArrayTagTest.java +++ b/src/test/java/net/querz/nbt/ByteArrayTagTest.java @@ -48,7 +48,6 @@ public void testCompareTo() { assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> t.compareTo(new DummyArrayTag<>(new byte[0])), IllegalArgumentException.class); } public void testInvalidType() { diff --git a/src/test/java/net/querz/nbt/ByteTagTest.java b/src/test/java/net/querz/nbt/ByteTagTest.java index 6c4acba7..de8b604a 100644 --- a/src/test/java/net/querz/nbt/ByteTagTest.java +++ b/src/test/java/net/querz/nbt/ByteTagTest.java @@ -43,7 +43,6 @@ public void testCompareTo() { assertTrue(0 < new ByteTag((byte) 7).compareTo(new ByteTag((byte) 5))); assertTrue(0 > new ByteTag((byte) 5).compareTo(new ByteTag((byte) 7))); assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new ByteTag((byte) 5).compareTo(new DummyNumberTag<>((byte) 0)), IllegalArgumentException.class); } public void testBoolean() { diff --git a/src/test/java/net/querz/nbt/CompoundTagTest.java b/src/test/java/net/querz/nbt/CompoundTagTest.java index f8ec4c7e..b511a335 100644 --- a/src/test/java/net/querz/nbt/CompoundTagTest.java +++ b/src/test/java/net/querz/nbt/CompoundTagTest.java @@ -279,8 +279,8 @@ public void testMaxDepth() { assertThrowsRuntimeException(root::toString, MaxDepthReachedException.class); assertThrowsNoRuntimeException(() -> root.toTagString(Tag.DEFAULT_MAX_DEPTH + 1)); assertThrowsRuntimeException(root::toTagString, MaxDepthReachedException.class); - assertThrowsRuntimeException(() -> root.valueToString(-1), MaxDepthReachedException.class); - assertThrowsRuntimeException(() -> root.valueToTagString(-1), MaxDepthReachedException.class); + assertThrowsRuntimeException(() -> root.valueToString(-1), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> root.valueToTagString(-1), IllegalArgumentException.class); } public void testRecursion() { diff --git a/src/test/java/net/querz/nbt/DoubleTagTest.java b/src/test/java/net/querz/nbt/DoubleTagTest.java index 08d1dcba..2444aebc 100644 --- a/src/test/java/net/querz/nbt/DoubleTagTest.java +++ b/src/test/java/net/querz/nbt/DoubleTagTest.java @@ -40,6 +40,5 @@ public void testCompareTo() { assertTrue(0 < new DoubleTag(7).compareTo(new DoubleTag(5))); assertTrue(0 > new DoubleTag(5).compareTo(new DoubleTag(7))); assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new DoubleTag(5).compareTo(new DummyNumberTag<>(0.0D)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/DummyArrayTag.java b/src/test/java/net/querz/nbt/DummyArrayTag.java deleted file mode 100644 index 949930c8..00000000 --- a/src/test/java/net/querz/nbt/DummyArrayTag.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.querz.nbt; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public class DummyArrayTag extends ArrayTag { - - public DummyArrayTag(T value) { - super(value); - } - - @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { - - } - - @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { - - } - - @Override - public String valueToTagString(int depth) { - return null; - } - - @Override - public Tag clone() { - return null; - } -} diff --git a/src/test/java/net/querz/nbt/DummyNumberTag.java b/src/test/java/net/querz/nbt/DummyNumberTag.java deleted file mode 100644 index 8f4d582b..00000000 --- a/src/test/java/net/querz/nbt/DummyNumberTag.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.querz.nbt; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public class DummyNumberTag> extends NumberTag { - - public DummyNumberTag(T value) { - super(value); - } - - @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { - - } - - @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { - - } - - @Override - public String valueToTagString(int depth) { - return null; - } - - @Override - public Tag clone() { - return null; - } -} diff --git a/src/test/java/net/querz/nbt/FloatTagTest.java b/src/test/java/net/querz/nbt/FloatTagTest.java index f58b7f24..1d6e8172 100644 --- a/src/test/java/net/querz/nbt/FloatTagTest.java +++ b/src/test/java/net/querz/nbt/FloatTagTest.java @@ -40,6 +40,5 @@ public void testCompareTo() { assertTrue(0 < new FloatTag(7).compareTo(new FloatTag(5))); assertTrue(0 > new FloatTag(5).compareTo(new FloatTag(7))); assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new FloatTag(5).compareTo(new DummyNumberTag<>(0.0F)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/IntArrayTagTest.java b/src/test/java/net/querz/nbt/IntArrayTagTest.java index 9db957b4..e02c686e 100644 --- a/src/test/java/net/querz/nbt/IntArrayTagTest.java +++ b/src/test/java/net/querz/nbt/IntArrayTagTest.java @@ -46,6 +46,5 @@ public void testCompareTo() { assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> t.compareTo(new DummyArrayTag<>(new int[0])), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/IntTagTest.java b/src/test/java/net/querz/nbt/IntTagTest.java index 4f0e412a..d62ad42e 100644 --- a/src/test/java/net/querz/nbt/IntTagTest.java +++ b/src/test/java/net/querz/nbt/IntTagTest.java @@ -41,6 +41,5 @@ public void testCompareTo() { assertTrue(0 < new IntTag(7).compareTo(new IntTag(5))); assertTrue(0 > new IntTag(5).compareTo(new IntTag(7))); assertThrowsRuntimeException(() -> new IntTag(5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new IntTag(5).compareTo(new DummyNumberTag<>(0)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/ListTagTest.java b/src/test/java/net/querz/nbt/ListTagTest.java index ddc5def2..40602c13 100644 --- a/src/test/java/net/querz/nbt/ListTagTest.java +++ b/src/test/java/net/querz/nbt/ListTagTest.java @@ -233,8 +233,8 @@ public void testMaxDepth() { assertThrowsRuntimeException(() -> deserializeFromFile("max_depth_reached.dat"), MaxDepthReachedException.class); assertThrowsRuntimeException(root::toString, MaxDepthReachedException.class); assertThrowsRuntimeException(root::toTagString, MaxDepthReachedException.class); - assertThrowsRuntimeException(() -> root.valueToString(-1), MaxDepthReachedException.class); - assertThrowsRuntimeException(() -> root.valueToTagString(-1), MaxDepthReachedException.class); + assertThrowsRuntimeException(() -> root.valueToString(-1), IllegalArgumentException.class); + assertThrowsRuntimeException(() -> root.valueToTagString(-1), IllegalArgumentException.class); } public void testRecursion() { diff --git a/src/test/java/net/querz/nbt/LongArrayTagTest.java b/src/test/java/net/querz/nbt/LongArrayTagTest.java index 0a10b57e..a2fe39c4 100644 --- a/src/test/java/net/querz/nbt/LongArrayTagTest.java +++ b/src/test/java/net/querz/nbt/LongArrayTagTest.java @@ -46,6 +46,5 @@ public void testCompareTo() { assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> t.compareTo(new DummyArrayTag<>(new long[0])), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/LongTagTest.java b/src/test/java/net/querz/nbt/LongTagTest.java index f295c315..6d9ea1e1 100644 --- a/src/test/java/net/querz/nbt/LongTagTest.java +++ b/src/test/java/net/querz/nbt/LongTagTest.java @@ -40,6 +40,5 @@ public void testCompareTo() { assertTrue(0 < new LongTag(7).compareTo(new LongTag(5))); assertTrue(0 > new LongTag(5).compareTo(new LongTag(7))); assertThrowsRuntimeException(() -> new LongTag(5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new LongTag(5).compareTo(new DummyNumberTag<>(0L)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/ShortTagTest.java b/src/test/java/net/querz/nbt/ShortTagTest.java index 66161565..ec039a7d 100644 --- a/src/test/java/net/querz/nbt/ShortTagTest.java +++ b/src/test/java/net/querz/nbt/ShortTagTest.java @@ -42,6 +42,5 @@ public void testCompareTo() { assertTrue(0 < new ShortTag((short) 7).compareTo(new ShortTag((short) 5))); assertTrue(0 > new ShortTag((short) 5).compareTo(new ShortTag((short) 7))); assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> new ShortTag((short) 5).compareTo(new DummyNumberTag<>((short) 0)), IllegalArgumentException.class); } } diff --git a/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java b/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java index 0a606d96..b4a7fd5b 100644 --- a/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java +++ b/src/test/java/net/querz/nbt/custom/ShortArrayTagTest.java @@ -1,6 +1,5 @@ package net.querz.nbt.custom; -import net.querz.nbt.DummyArrayTag; import net.querz.nbt.NBTTestCase; import java.util.Arrays; import static org.junit.Assert.assertNotEquals; @@ -58,6 +57,5 @@ public void testCompareTo() { assertTrue(0 < t.compareTo(t4)); assertTrue(0 > t4.compareTo(t)); assertThrowsRuntimeException(() -> t.compareTo(null), NullPointerException.class); - assertThrowsRuntimeException(() -> t.compareTo(new DummyArrayTag<>(new short[0])), IllegalArgumentException.class); } } From 0c1b1e6d1889b3ba51dc6d7704b358e463105c73 Mon Sep 17 00:00:00 2001 From: Querz Date: Tue, 22 Jan 2019 13:04:24 +0100 Subject: [PATCH 14/25] add missing javadoc parameter description --- src/main/java/net/querz/nbt/ListTag.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index 3de7c772..bbfebbc8 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -43,6 +43,7 @@ protected static ListTag createUnchecked() { *

Creates an empty mutable list to be used as empty value of ListTags.

* * @param Type of the list elements + * @param initialCapacity The initial capacity of the returned List * @return An instance of {@link java.util.List} with an initial capacity of 3 * */ private static List createEmptyValue(int initialCapacity) { From 5e64dd1d89b0bf949f611b5fd178630b2c4cfa6a Mon Sep 17 00:00:00 2001 From: Querz Date: Tue, 22 Jan 2019 15:33:00 +0100 Subject: [PATCH 15/25] fix ObjectTag throwing NPE with null value --- src/main/java/net/querz/nbt/custom/ObjectTag.java | 15 ++++++++++++++- .../java/net/querz/nbt/custom/ObjectTagTest.java | 13 +++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/querz/nbt/custom/ObjectTag.java b/src/main/java/net/querz/nbt/custom/ObjectTag.java index e94645ae..40608c6b 100644 --- a/src/main/java/net/querz/nbt/custom/ObjectTag.java +++ b/src/main/java/net/querz/nbt/custom/ObjectTag.java @@ -79,6 +79,9 @@ public boolean equals(Object other) { @Override public int hashCode() { + if (getValue() == null) { + return 0; + } return getValue().hashCode(); } @@ -87,6 +90,13 @@ public int hashCode() { public int compareTo(ObjectTag o) { if (o.getValue() instanceof Comparable && getValue() instanceof Comparable) { return ((Comparable) getValue()).compareTo(o.getValue()); + } else if (o.getValue() == getValue()) { + return 0; + } else if (getValue() == null) { + // sort a null value to the end + return -1; + } else if (o.getValue() == null) { + return 1; } return 0; } @@ -94,9 +104,12 @@ public int compareTo(ObjectTag o) { @SuppressWarnings("unchecked") @Override public ObjectTag clone() { + if (getValue() == null) { + return new ObjectTag<>(); + } try { return new ObjectTag<>((T) getValue().getClass().getMethod("clone").invoke(getValue())); - } catch (NullPointerException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { return new ObjectTag<>(getValue()); } } diff --git a/src/test/java/net/querz/nbt/custom/ObjectTagTest.java b/src/test/java/net/querz/nbt/custom/ObjectTagTest.java index 2cda492b..8dab3e59 100644 --- a/src/test/java/net/querz/nbt/custom/ObjectTagTest.java +++ b/src/test/java/net/querz/nbt/custom/ObjectTagTest.java @@ -38,6 +38,7 @@ public void testHashCode() { ObjectTag o2 = new ObjectTag<>(d2); assertNotEquals(o.hashCode(), o2.hashCode()); assertEquals(o.hashCode(), o.clone().hashCode()); + assertEquals(0, new ObjectTag().hashCode()); } public void testClone() { @@ -112,6 +113,18 @@ public void testCompareTo() { ObjectTag d4 = new ObjectTag<>("abd"); assertTrue(0 > d3.compareTo(d4)); assertTrue(0 < d4.compareTo(d3)); + + ObjectTag d5 = new ObjectTag<>("abc"); + assertEquals(0, d3.compareTo(d5)); + + DummyObject o = new DummyObject(); + ObjectTag d6 = new ObjectTag<>(o); + ObjectTag d7 = new ObjectTag<>(o); + assertEquals(0, d6.compareTo(d7)); + + ObjectTag d8 = new ObjectTag<>(); + assertEquals(-1, d8.compareTo(d7)); + assertEquals(1, d7.compareTo(d8)); } public void testUnknownObject() { From c4487d61e7d1d9d3d900824f2cfdfc8e2ef2ef0a Mon Sep 17 00:00:00 2001 From: Querz Date: Tue, 22 Jan 2019 15:38:01 +0100 Subject: [PATCH 16/25] add another null case to ObjecTag#compareTo unit test --- src/test/java/net/querz/nbt/custom/ObjectTagTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/net/querz/nbt/custom/ObjectTagTest.java b/src/test/java/net/querz/nbt/custom/ObjectTagTest.java index 8dab3e59..d3156bb9 100644 --- a/src/test/java/net/querz/nbt/custom/ObjectTagTest.java +++ b/src/test/java/net/querz/nbt/custom/ObjectTagTest.java @@ -125,6 +125,9 @@ public void testCompareTo() { ObjectTag d8 = new ObjectTag<>(); assertEquals(-1, d8.compareTo(d7)); assertEquals(1, d7.compareTo(d8)); + + ObjectTag d9 = new ObjectTag<>(); + assertEquals(0, d8.compareTo(d9)); } public void testUnknownObject() { From 1da4f5ba6fbc6e643b8b9fde0bbe25721c190305 Mon Sep 17 00:00:00 2001 From: Querz Date: Tue, 22 Jan 2019 17:18:02 +0100 Subject: [PATCH 17/25] ObjectTag with value null should be sorted to the end --- src/main/java/net/querz/nbt/custom/ObjectTag.java | 4 ++-- .../java/net/querz/nbt/custom/ObjectTagTest.java | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/querz/nbt/custom/ObjectTag.java b/src/main/java/net/querz/nbt/custom/ObjectTag.java index 40608c6b..5bb06b60 100644 --- a/src/main/java/net/querz/nbt/custom/ObjectTag.java +++ b/src/main/java/net/querz/nbt/custom/ObjectTag.java @@ -94,9 +94,9 @@ public int compareTo(ObjectTag o) { return 0; } else if (getValue() == null) { // sort a null value to the end - return -1; - } else if (o.getValue() == null) { return 1; + } else if (o.getValue() == null) { + return -1; } return 0; } diff --git a/src/test/java/net/querz/nbt/custom/ObjectTagTest.java b/src/test/java/net/querz/nbt/custom/ObjectTagTest.java index d3156bb9..e069d88c 100644 --- a/src/test/java/net/querz/nbt/custom/ObjectTagTest.java +++ b/src/test/java/net/querz/nbt/custom/ObjectTagTest.java @@ -6,6 +6,9 @@ import static org.junit.Assert.assertNotEquals; import java.io.IOException; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; import java.util.Objects; import java.util.Random; @@ -123,11 +126,18 @@ public void testCompareTo() { assertEquals(0, d6.compareTo(d7)); ObjectTag d8 = new ObjectTag<>(); - assertEquals(-1, d8.compareTo(d7)); - assertEquals(1, d7.compareTo(d8)); + assertEquals(1, d8.compareTo(d7)); + assertEquals(-1, d7.compareTo(d8)); ObjectTag d9 = new ObjectTag<>(); assertEquals(0, d8.compareTo(d9)); + + List> l = new ArrayList<>(); + l.add(d); + l.add(d9); + l.add(d2); + l.sort(Comparator.naturalOrder()); + assertEquals(d9, l.get(2)); } public void testUnknownObject() { From db5fffae49da8c4240941db6c0647fa713474040 Mon Sep 17 00:00:00 2001 From: Querz Date: Tue, 22 Jan 2019 17:29:33 +0100 Subject: [PATCH 18/25] update version to 4.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 52784b49..aee3f244 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ apply plugin: 'jacoco' group = 'net.querz.nbt' archivesBaseName = 'nbt' -version = '3.0' +version = '4.0' sourceCompatibility = '1.8' targetCompatibility = '1.8' compileJava.options.encoding = 'UTF-8' From 7e75cdbe55950f95fa3d5fab3261ea88d468218f Mon Sep 17 00:00:00 2001 From: Querz Date: Mon, 28 Jan 2019 08:32:55 +0100 Subject: [PATCH 19/25] simplify CompoundTag serialization code --- src/main/java/net/querz/nbt/CompoundTag.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/net/querz/nbt/CompoundTag.java b/src/main/java/net/querz/nbt/CompoundTag.java index 86097830..6f92676d 100644 --- a/src/main/java/net/querz/nbt/CompoundTag.java +++ b/src/main/java/net/querz/nbt/CompoundTag.java @@ -228,9 +228,7 @@ public Tag putLongArray(String key, long[] value) { @Override public void serializeValue(DataOutputStream dos, int depth) throws IOException { for (Map.Entry> e : getValue().entrySet()) { - dos.writeByte(e.getValue().getID()); - dos.writeUTF(e.getKey()); - e.getValue().serializeValue(dos, decrementDepth(depth)); + e.getValue().serialize(dos, e.getKey(), decrementDepth(depth)); } EndTag.INSTANCE.serialize(dos, depth); } From a7bc3c99d85fd1e1fb5f9ee4c62cbdb720d9fe3b Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 28 Jan 2019 15:28:49 +0100 Subject: [PATCH 20/25] Removed unused import --- src/main/java/net/querz/nbt/ByteArrayTag.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/net/querz/nbt/ByteArrayTag.java b/src/main/java/net/querz/nbt/ByteArrayTag.java index 99c69765..53ec62d9 100644 --- a/src/main/java/net/querz/nbt/ByteArrayTag.java +++ b/src/main/java/net/querz/nbt/ByteArrayTag.java @@ -3,7 +3,6 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.lang.reflect.Array; import java.util.Arrays; public class ByteArrayTag extends ArrayTag implements Comparable { From 7cd8d13d3d5d1f9b7e6c13eb7273f9feafd2085f Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 28 Jan 2019 15:29:31 +0100 Subject: [PATCH 21/25] Suppressed warning and added small doc --- src/main/java/net/querz/nbt/MaxDepthReachedException.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/querz/nbt/MaxDepthReachedException.java b/src/main/java/net/querz/nbt/MaxDepthReachedException.java index db827cf4..3b3dfb71 100644 --- a/src/main/java/net/querz/nbt/MaxDepthReachedException.java +++ b/src/main/java/net/querz/nbt/MaxDepthReachedException.java @@ -1,7 +1,10 @@ package net.querz.nbt; +/** + * Exception indicating that the maximum (de-)serialization depth has been reached. + */ +@SuppressWarnings("serial") public class MaxDepthReachedException extends RuntimeException { - public MaxDepthReachedException(String msg) { super(msg); } From e88a572e3457fd6c8ce7e71e5460e03133a1c954 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 28 Jan 2019 16:20:59 +0100 Subject: [PATCH 22/25] Updated documentation to describe new maxDepth behavior --- src/main/java/net/querz/nbt/ArrayTag.java | 2 +- src/main/java/net/querz/nbt/ByteArrayTag.java | 6 +- src/main/java/net/querz/nbt/ByteTag.java | 6 +- src/main/java/net/querz/nbt/CompoundTag.java | 18 +-- src/main/java/net/querz/nbt/DoubleTag.java | 6 +- src/main/java/net/querz/nbt/EndTag.java | 8 +- src/main/java/net/querz/nbt/FloatTag.java | 6 +- src/main/java/net/querz/nbt/IntArrayTag.java | 6 +- src/main/java/net/querz/nbt/IntTag.java | 6 +- src/main/java/net/querz/nbt/ListTag.java | 16 +-- src/main/java/net/querz/nbt/LongArrayTag.java | 6 +- src/main/java/net/querz/nbt/LongTag.java | 6 +- src/main/java/net/querz/nbt/NumberTag.java | 2 +- src/main/java/net/querz/nbt/ShortTag.java | 6 +- src/main/java/net/querz/nbt/StringTag.java | 8 +- src/main/java/net/querz/nbt/Tag.java | 119 +++++++++++------- .../java/net/querz/nbt/custom/CharTag.java | 8 +- .../java/net/querz/nbt/custom/ObjectTag.java | 8 +- .../net/querz/nbt/custom/ShortArrayTag.java | 6 +- .../java/net/querz/nbt/custom/StructTag.java | 16 +-- 20 files changed, 148 insertions(+), 117 deletions(-) diff --git a/src/main/java/net/querz/nbt/ArrayTag.java b/src/main/java/net/querz/nbt/ArrayTag.java index ae5ade57..b08d9fc8 100644 --- a/src/main/java/net/querz/nbt/ArrayTag.java +++ b/src/main/java/net/querz/nbt/ArrayTag.java @@ -31,7 +31,7 @@ public void setValue(T value) { } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { return arrayToString("", ""); } diff --git a/src/main/java/net/querz/nbt/ByteArrayTag.java b/src/main/java/net/querz/nbt/ByteArrayTag.java index 53ec62d9..f73aae56 100644 --- a/src/main/java/net/querz/nbt/ByteArrayTag.java +++ b/src/main/java/net/querz/nbt/ByteArrayTag.java @@ -18,20 +18,20 @@ public ByteArrayTag(byte[] value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeInt(length()); dos.write(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { int length = dis.readInt(); setValue(new byte[length]); dis.readFully(getValue()); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return arrayToString("B", "b"); } diff --git a/src/main/java/net/querz/nbt/ByteTag.java b/src/main/java/net/querz/nbt/ByteTag.java index 9655bb57..5d12e558 100644 --- a/src/main/java/net/querz/nbt/ByteTag.java +++ b/src/main/java/net/querz/nbt/ByteTag.java @@ -29,17 +29,17 @@ public void setValue(byte value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeByte(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { setValue(dis.readByte()); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return getValue() + "b"; } diff --git a/src/main/java/net/querz/nbt/CompoundTag.java b/src/main/java/net/querz/nbt/CompoundTag.java index 6f92676d..adbf18b1 100644 --- a/src/main/java/net/querz/nbt/CompoundTag.java +++ b/src/main/java/net/querz/nbt/CompoundTag.java @@ -226,32 +226,32 @@ public Tag putLongArray(String key, long[] value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { for (Map.Entry> e : getValue().entrySet()) { - e.getValue().serialize(dos, e.getKey(), decrementDepth(depth)); + e.getValue().serialize(dos, e.getKey(), decrementMaxDepth(maxDepth)); } - EndTag.INSTANCE.serialize(dos, depth); + EndTag.INSTANCE.serialize(dos, maxDepth); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { clear(); for (int id = dis.readByte() & 0xFF; id != 0; id = dis.readByte() & 0xFF) { Tag tag = TagFactory.fromID(id); String name = dis.readUTF(); - tag.deserializeValue(dis, decrementDepth(depth)); + tag.deserializeValue(dis, decrementMaxDepth(maxDepth)); put(name, tag); } } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { StringBuilder sb = new StringBuilder("{"); boolean first = true; for (Map.Entry> e : getValue().entrySet()) { sb.append(first ? "" : ",") .append(escapeString(e.getKey(), false)).append(":") - .append(e.getValue().toString(decrementDepth(depth))); + .append(e.getValue().toString(decrementMaxDepth(maxDepth))); first = false; } sb.append("}"); @@ -259,13 +259,13 @@ public String valueToString(int depth) { } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { StringBuilder sb = new StringBuilder("{"); boolean first = true; for (Map.Entry> e : getValue().entrySet()) { sb.append(first ? "" : ",") .append(escapeString(e.getKey(), true)).append(":") - .append(e.getValue().valueToTagString(decrementDepth(depth))); + .append(e.getValue().valueToTagString(decrementMaxDepth(maxDepth))); first = false; } sb.append("}"); diff --git a/src/main/java/net/querz/nbt/DoubleTag.java b/src/main/java/net/querz/nbt/DoubleTag.java index d9eedec1..5057941a 100644 --- a/src/main/java/net/querz/nbt/DoubleTag.java +++ b/src/main/java/net/querz/nbt/DoubleTag.java @@ -21,17 +21,17 @@ public void setValue(double value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeDouble(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { setValue(dis.readDouble()); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return getValue() + "d"; } diff --git a/src/main/java/net/querz/nbt/EndTag.java b/src/main/java/net/querz/nbt/EndTag.java index 3172fe7f..b07a8af4 100644 --- a/src/main/java/net/querz/nbt/EndTag.java +++ b/src/main/java/net/querz/nbt/EndTag.java @@ -17,22 +17,22 @@ protected Void checkValue(Void value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) { + public void serializeValue(DataOutputStream dos, int maxDepth) { //nothing to do } @Override - public void deserializeValue(DataInputStream dis, int depth) { + public void deserializeValue(DataInputStream dis, int maxDepth) { //nothing to do } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { return "\"end\""; } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { throw new UnsupportedOperationException("EndTag cannot be turned into a String"); } diff --git a/src/main/java/net/querz/nbt/FloatTag.java b/src/main/java/net/querz/nbt/FloatTag.java index 4c6b1873..ff248e3f 100644 --- a/src/main/java/net/querz/nbt/FloatTag.java +++ b/src/main/java/net/querz/nbt/FloatTag.java @@ -21,17 +21,17 @@ public void setValue(float value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeFloat(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { setValue(dis.readFloat()); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return getValue() + "f"; } diff --git a/src/main/java/net/querz/nbt/IntArrayTag.java b/src/main/java/net/querz/nbt/IntArrayTag.java index 760833e9..694c3192 100644 --- a/src/main/java/net/querz/nbt/IntArrayTag.java +++ b/src/main/java/net/querz/nbt/IntArrayTag.java @@ -18,7 +18,7 @@ public IntArrayTag(int[] value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeInt(length()); for (int i : getValue()) { dos.writeInt(i); @@ -26,7 +26,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { int length = dis.readInt(); setValue(new int[length]); for (int i = 0; i < length; i++) { @@ -35,7 +35,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return arrayToString("I", ""); } diff --git a/src/main/java/net/querz/nbt/IntTag.java b/src/main/java/net/querz/nbt/IntTag.java index 04e25d50..dcd6e8e3 100644 --- a/src/main/java/net/querz/nbt/IntTag.java +++ b/src/main/java/net/querz/nbt/IntTag.java @@ -21,17 +21,17 @@ public void setValue(int value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeInt(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { setValue(dis.readInt()); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return getValue() + ""; } diff --git a/src/main/java/net/querz/nbt/ListTag.java b/src/main/java/net/querz/nbt/ListTag.java index bbfebbc8..454b3aab 100644 --- a/src/main/java/net/querz/nbt/ListTag.java +++ b/src/main/java/net/querz/nbt/ListTag.java @@ -246,19 +246,19 @@ public ListTag asCompoundTagList() { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeByte(TagFactory.idFromClass(getTypeClass())); dos.writeInt(size()); if (size() != 0) { for (T t : getValue()) { - t.serializeValue(dos, decrementDepth(depth)); + t.serializeValue(dos, decrementMaxDepth(maxDepth)); } } } @SuppressWarnings("unchecked") @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { int typeID = dis.readByte(); if (typeID != 0) { typeClass = TagFactory.classFromID(typeID); @@ -269,27 +269,27 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException if (size != 0) { for (int i = 0; i < size; i++) { Tag tag = TagFactory.fromID(typeID); - tag.deserializeValue(dis, decrementDepth(depth)); + tag.deserializeValue(dis, decrementMaxDepth(maxDepth)); add((T) tag); } } } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { StringBuilder sb = new StringBuilder("{\"type\":\"").append(getTypeClass().getSimpleName()).append("\",\"list\":["); for (int i = 0; i < size(); i++) { - sb.append(i > 0 ? "," : "").append(get(i).valueToString(decrementDepth(depth))); + sb.append(i > 0 ? "," : "").append(get(i).valueToString(decrementMaxDepth(maxDepth))); } sb.append("]}"); return sb.toString(); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < size(); i++) { - sb.append(i > 0 ? "," : "").append(get(i).valueToTagString(decrementDepth(depth))); + sb.append(i > 0 ? "," : "").append(get(i).valueToTagString(decrementMaxDepth(maxDepth))); } sb.append("]"); return sb.toString(); diff --git a/src/main/java/net/querz/nbt/LongArrayTag.java b/src/main/java/net/querz/nbt/LongArrayTag.java index f24aab9a..ec5452d7 100644 --- a/src/main/java/net/querz/nbt/LongArrayTag.java +++ b/src/main/java/net/querz/nbt/LongArrayTag.java @@ -18,7 +18,7 @@ public LongArrayTag(long[] value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeInt(length()); for (long i : getValue()) { dos.writeLong(i); @@ -26,7 +26,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { int length = dis.readInt(); setValue(new long[length]); for (int i = 0; i < length; i++) { @@ -35,7 +35,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return arrayToString("L", "l"); } diff --git a/src/main/java/net/querz/nbt/LongTag.java b/src/main/java/net/querz/nbt/LongTag.java index 9ca84054..38a7e9f2 100644 --- a/src/main/java/net/querz/nbt/LongTag.java +++ b/src/main/java/net/querz/nbt/LongTag.java @@ -21,17 +21,17 @@ public void setValue(long value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeLong(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { setValue(dis.readLong()); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return getValue() + "l"; } diff --git a/src/main/java/net/querz/nbt/NumberTag.java b/src/main/java/net/querz/nbt/NumberTag.java index dcd97f35..d2fd9ec6 100644 --- a/src/main/java/net/querz/nbt/NumberTag.java +++ b/src/main/java/net/querz/nbt/NumberTag.java @@ -31,7 +31,7 @@ public double asDouble() { } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { return getValue().toString(); } } diff --git a/src/main/java/net/querz/nbt/ShortTag.java b/src/main/java/net/querz/nbt/ShortTag.java index 81661f3d..3534b217 100644 --- a/src/main/java/net/querz/nbt/ShortTag.java +++ b/src/main/java/net/querz/nbt/ShortTag.java @@ -21,17 +21,17 @@ public void setValue(short value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeShort(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { setValue(dis.readShort()); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return getValue() + "s"; } diff --git a/src/main/java/net/querz/nbt/StringTag.java b/src/main/java/net/querz/nbt/StringTag.java index 8e526ce5..8350f518 100644 --- a/src/main/java/net/querz/nbt/StringTag.java +++ b/src/main/java/net/querz/nbt/StringTag.java @@ -27,22 +27,22 @@ public void setValue(String value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeUTF(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { setValue(dis.readUTF()); } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { return escapeString(getValue(), false); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return escapeString(getValue(), true); } diff --git a/src/main/java/net/querz/nbt/Tag.java b/src/main/java/net/querz/nbt/Tag.java index e0b28e4a..2a92c042 100644 --- a/src/main/java/net/querz/nbt/Tag.java +++ b/src/main/java/net/querz/nbt/Tag.java @@ -10,10 +10,34 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +/** + * Base class for all NBT tags. + * + *

Nesting

+ *

All methods serializing instances or deserializing data track the nesting levels to prevent + * circular references or malicious data which could, when deserialized, result in thousands + * of instances causing a denial of service.

+ * + *

These methods have a parameter for the maximum nesting depth they are allowed to traverse. A + * value of {@code 0} means that only the object itself, but no nested objects may be processed. + * If an instance is nested further than allowed, a {@link MaxDepthReachedException} will be thrown. + * Providing a negative maximum nesting depth will cause an {@code IllegalArgumentException} + * to be thrown.

+ * + *

Some methods do not provide a parameter to specify the maximum nesting depth, but instead use + * {@link #DEFAULT_MAX_DEPTH}, which is also the maximum used by Minecraft. This is documented for + * the respective methods.

+ * + *

If custom NBT tags contain objects other than NBT tags, which can be nested as well, then there + * is no guarantee that {@code MaxDepthReachedException}s are thrown for them. The respective class + * will document this behavior accordingly.

+ * + * @param The type of the contained value + * */ public abstract class Tag implements Cloneable { /** - * The maximum depth of the NBT structure. + * The default maximum depth of the NBT structure. * */ public static final int DEFAULT_MAX_DEPTH = 512; @@ -79,46 +103,48 @@ protected T checkValue(T value) { * Calls {@link Tag#serialize(DataOutputStream, String, int)} with an empty name. * @see Tag#serialize(DataOutputStream, String, int) * @param dos The DataOutputStream to write to - * @param depth The current depth of the structure - * @throws IOException If something went wrong during serialization + * @param maxDepth The maximum nesting depth + * @throws IOException If something went wrong during serialization. + * @throws NullPointerException If {@code dos} is {@code null}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * */ - public final void serialize(DataOutputStream dos, int depth) throws IOException { - serialize(dos, "", depth); + public final void serialize(DataOutputStream dos, int maxDepth) throws IOException { + serialize(dos, "", maxDepth); } /** * Serializes this Tag starting at the gives depth. * @param dos The DataOutputStream to write to. * @param name The name of this Tag, if this is the root Tag. - * @param depth The current depth of the structure. + * @param maxDepth The maximum nesting depth * @throws IOException If something went wrong during serialization. - * @exception NullPointerException If {@code dos} or {@code name} is {@code null}. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code dos} or {@code name} is {@code null}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * */ - public final void serialize(DataOutputStream dos, String name, int depth) throws IOException { + public final void serialize(DataOutputStream dos, String name, int maxDepth) throws IOException { dos.writeByte(getID()); if (getID() != 0) { dos.writeUTF(name); } - serializeValue(dos, depth); + serializeValue(dos, maxDepth); } /** * Deserializes this Tag starting at the given depth. * The name of the root Tag is ignored. * @param dis The DataInputStream to read from. - * @param depth The current depth of the structure. + * @param maxDepth The maximum nesting depth. * @throws IOException If something went wrong during deserialization. - * @exception NullPointerException If {@code dis} is {@code null}. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code dis} is {@code null}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * @return The deserialized NBT structure. * */ - public static Tag deserialize(DataInputStream dis, int depth) throws IOException { + public static Tag deserialize(DataInputStream dis, int maxDepth) throws IOException { int id = dis.readByte() & 0xFF; Tag tag = TagFactory.fromID(id); if (id != 0) { dis.readUTF(); - tag.deserializeValue(dis, depth); + tag.deserializeValue(dis, maxDepth); } return tag; } @@ -126,24 +152,25 @@ public static Tag deserialize(DataInputStream dis, int depth) throws IOExcept /** * Serializes only the value of this Tag. * @param dos The DataOutputStream to write to. - * @param depth The current depth of the structure. + * @param maxDepth The maximum nesting depth. * @throws IOException If something went wrong during serialization. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * */ - public abstract void serializeValue(DataOutputStream dos, int depth) throws IOException; + public abstract void serializeValue(DataOutputStream dos, int maxDepth) throws IOException; /** * Deserializes only the value of this Tag. * @param dis The DataInputStream to read from. - * @param depth The current depth of the structure. + * @param maxDepth The maximum nesting depth. * @throws IOException If something went wrong during deserialization. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded * */ - public abstract void deserializeValue(DataInputStream dis, int depth) throws IOException; + public abstract void deserializeValue(DataInputStream dis, int maxDepth) throws IOException; /** * Calls {@link Tag#toString(int)} with an initial depth of {@code 0}. * @see Tag#toString(int) + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * */ @Override public final String toString() { @@ -152,25 +179,25 @@ public final String toString() { /** * Creates a string representation of this Tag in a valid JSON format. - * @param depth The current depth of the structure. + * @param maxDepth The maximum nesting depth. * @return The string representation of this Tag. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * */ - public String toString(int depth) { + public String toString(int maxDepth) { return "{\"type\":\""+ getClass().getSimpleName() + "\"," + - "\"value\":" + valueToString(depth) + "}"; + "\"value\":" + valueToString(maxDepth) + "}"; } /** * Returns a JSON representation of the value of this Tag. - * @param depth The current depth of the structure. + * @param maxDepth The maximum nesting depth. * @return The string representation of the value of this Tag. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * */ - public abstract String valueToString(int depth); + public abstract String valueToString(int maxDepth); /** - * Calls {@link Tag#toTagString(int)} with an initial depth of {@code 0}. + * Calls {@link Tag#toTagString(int)} with {@link #DEFAULT_MAX_DEPTH}. * @see Tag#toTagString(int) * @return The JSON-like string representation of this Tag. * */ @@ -180,21 +207,21 @@ public final String toTagString() { /** * Returns a JSON-like representation of the value of this Tag, usually used for Minecraft commands. - * @param depth The current depth of the structure. + * @param maxDepth The maximum nesting depth. * @return The JSON-like string representation of this Tag. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * */ - public String toTagString(int depth) { - return valueToTagString(depth); + public String toTagString(int maxDepth) { + return valueToTagString(maxDepth); } /** * Returns a JSON-like representation of the value of this Tag. - * @param depth The current depth of the structure. + * @param maxDepth The maximum nesting depth. * @return The JSON-like string representation of the value of this Tag. - * @exception MaxDepthReachedException If the structure depth exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. * */ - public abstract String valueToTagString(int depth); + public abstract String valueToTagString(int maxDepth); /** * Returns whether this Tag and some other Tag are equal. @@ -227,18 +254,22 @@ public int hashCode() { public abstract Tag clone(); /** - * Decrements {@code depth} by {@code 1}. - * @param depth The value to decrement. + * Decrements {@code maxDepth} by {@code 1}. This method has to be used when a tag is + * (de-)serialized and contains nested tags. Their respective methods are then called + * with {@code decrementMaxDepth(maxDepth)} as maximum nesting depth. + * + * @param maxDepth The value to decrement. * @return The decremented value. - * @exception MaxDepthReachedException If {@code depth <= 0}. + * @throws MaxDepthReachedException If {@code maxDepth == 0}. + * @throws IllegalArgumentException If {@code maxDepth < 0}. * */ - protected int decrementDepth(int depth) { - if (depth < 0) { - throw new IllegalArgumentException("negative depth is not allowed"); - } else if (depth == 0) { + protected int decrementMaxDepth(int maxDepth) { + if (maxDepth < 0) { + throw new IllegalArgumentException("negative maximum depth is not allowed"); + } else if (maxDepth == 0) { throw new MaxDepthReachedException("reached maximum depth of NBT structure"); } - return --depth; + return --maxDepth; } /** diff --git a/src/main/java/net/querz/nbt/custom/CharTag.java b/src/main/java/net/querz/nbt/custom/CharTag.java index 3070a84d..cba9654c 100644 --- a/src/main/java/net/querz/nbt/custom/CharTag.java +++ b/src/main/java/net/querz/nbt/custom/CharTag.java @@ -32,22 +32,22 @@ public void setValue(char value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeChar(getValue()); } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { setValue(dis.readChar()); } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { return escapeString(getValue() + "", false); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return escapeString(getValue() + "", true); } diff --git a/src/main/java/net/querz/nbt/custom/ObjectTag.java b/src/main/java/net/querz/nbt/custom/ObjectTag.java index 5bb06b60..92ea5624 100644 --- a/src/main/java/net/querz/nbt/custom/ObjectTag.java +++ b/src/main/java/net/querz/nbt/custom/ObjectTag.java @@ -48,13 +48,13 @@ public ObjectTag asTypedObjectTag(Class type) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { new ObjectOutputStream(dos).writeObject(getValue()); } @SuppressWarnings("unchecked") @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { try { setValue((T) new ObjectInputStream(dis).readObject()); } catch (InvalidClassException | ClassNotFoundException e) { @@ -63,12 +63,12 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { return getValue() == null ? "null" : escapeString(getValue().toString(), false); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return getValue() == null ? "null" : escapeString(getValue().toString(), true); } diff --git a/src/main/java/net/querz/nbt/custom/ShortArrayTag.java b/src/main/java/net/querz/nbt/custom/ShortArrayTag.java index 970cbf1c..ba46d33e 100644 --- a/src/main/java/net/querz/nbt/custom/ShortArrayTag.java +++ b/src/main/java/net/querz/nbt/custom/ShortArrayTag.java @@ -24,7 +24,7 @@ public ShortArrayTag(short[] value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeInt(length()); for (int i : getValue()) { dos.writeShort(i); @@ -32,7 +32,7 @@ public void serializeValue(DataOutputStream dos, int depth) throws IOException { } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { int length = dis.readInt(); setValue(new short[length]); for (int i = 0; i < length; i++) { @@ -41,7 +41,7 @@ public void deserializeValue(DataInputStream dis, int depth) throws IOException } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { return arrayToString("S", "s"); } diff --git a/src/main/java/net/querz/nbt/custom/StructTag.java b/src/main/java/net/querz/nbt/custom/StructTag.java index 4757fa3e..47c7215c 100644 --- a/src/main/java/net/querz/nbt/custom/StructTag.java +++ b/src/main/java/net/querz/nbt/custom/StructTag.java @@ -231,41 +231,41 @@ public void addLongArray(long[] value) { } @Override - public void serializeValue(DataOutputStream dos, int depth) throws IOException { + public void serializeValue(DataOutputStream dos, int maxDepth) throws IOException { dos.writeInt(size()); for (Tag tag : getValue()) { dos.writeByte(tag.getID()); - tag.serializeValue(dos, decrementDepth(depth)); + tag.serializeValue(dos, decrementMaxDepth(maxDepth)); } } @Override - public void deserializeValue(DataInputStream dis, int depth) throws IOException { + public void deserializeValue(DataInputStream dis, int maxDepth) throws IOException { int size = dis.readInt(); size = size < 0 ? 0 : size; setValue(new ArrayList<>(size)); for (int i = 0; i < size; i++) { Tag tag = TagFactory.fromID(dis.readByte()); - tag.deserializeValue(dis, decrementDepth(depth)); + tag.deserializeValue(dis, decrementMaxDepth(maxDepth)); add(tag); } } @Override - public String valueToString(int depth) { + public String valueToString(int maxDepth) { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < size(); i++) { - sb.append(i > 0 ? "," : "").append(get(i).toString(decrementDepth(depth))); + sb.append(i > 0 ? "," : "").append(get(i).toString(decrementMaxDepth(maxDepth))); } sb.append("]"); return sb.toString(); } @Override - public String valueToTagString(int depth) { + public String valueToTagString(int maxDepth) { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < size(); i++) { - sb.append(i > 0 ? "," : "").append(get(i).valueToTagString(decrementDepth(depth))); + sb.append(i > 0 ? "," : "").append(get(i).valueToTagString(decrementMaxDepth(maxDepth))); } sb.append("]"); return sb.toString(); From e7d7613aa85856ded97c9ad5c348890bb9d5f4f5 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 28 Jan 2019 16:25:05 +0100 Subject: [PATCH 23/25] wrong javadoc for decrementDepth Co-Authored-By: Querz --- src/main/java/net/querz/nbt/Tag.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/querz/nbt/Tag.java b/src/main/java/net/querz/nbt/Tag.java index e0b28e4a..7f0bfc79 100644 --- a/src/main/java/net/querz/nbt/Tag.java +++ b/src/main/java/net/querz/nbt/Tag.java @@ -230,7 +230,8 @@ public int hashCode() { * Decrements {@code depth} by {@code 1}. * @param depth The value to decrement. * @return The decremented value. - * @exception MaxDepthReachedException If {@code depth <= 0}. + * @exception MaxDepthReachedException If {@code depth == 0}. + * @exception IllegalArgumentException If {@code depth < 0}. * */ protected int decrementDepth(int depth) { if (depth < 0) { From bbc25800f09fda10e0a91d68f9c1c2cac30d1ff1 Mon Sep 17 00:00:00 2001 From: Querz Date: Mon, 28 Jan 2019 17:19:38 +0100 Subject: [PATCH 24/25] add nesting description to readme --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 6de60cbf..004c51a2 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,16 @@ ListTag fl = new ListTag<>(FloatTag.class); fl.add(new FloatTag(1.234f); fl.addFloat(5.678f); ``` + +#### Nesting +All methods serializing instances or deserializing data track the nesting levels to prevent circular references or malicious data which could, when deserialized, result in thousands of instances causing a denial of service. + +These methods have a parameter for the maximum nesting depth they are allowed to traverse. A value of `0` means that only the object itself, but no nested object may be processed. + +If an instance is nested further than allowed, a [MaxDepthReachedException](src/main/java/net/querz/nbt/MaxDepthReachedException.java) will be thrown. A negative maximum depth will cause an `IllegalArgumentException`. + +Some methods do not provide a parameter to specify the maximum depth, but instead use `Tag.DEFAULT_MAX_DEPTH` (`512`) which is also the maximum used in Minecraft. + --- ### Utility There are several utility methods to make your life easier if you use this library. @@ -124,3 +134,8 @@ To be able to use a custom tag with deserialization, a `Supplier` and the custom ```java TagFactory.registerCustomTag(90, ObjectTag::new, ObjectTag.class); ``` + +#### Nesting +As mentioned before, serialization and deserialization methods are provided with a parameter indicating the maximum processing depth of the structure. This is not guaranteed when using custom tags, it is the responsibility of the creator of that custom tag to call `Tag#decrementMaxDepth(int)` to correctly update the nesting depth. + +It is also highly encouraged to document the custom tag behaviour when it does so to make users aware of the possible exceptions thrown by `Tag#decrementMaxDepth(int)`. \ No newline at end of file From 7cae36d1b5f64d4d82a574739814544b3e238d84 Mon Sep 17 00:00:00 2001 From: Querz Date: Mon, 28 Jan 2019 17:20:16 +0100 Subject: [PATCH 25/25] always use @throws in javadoc --- src/main/java/net/querz/nbt/NBTUtil.java | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/querz/nbt/NBTUtil.java b/src/main/java/net/querz/nbt/NBTUtil.java index b885e20a..3779e795 100644 --- a/src/main/java/net/querz/nbt/NBTUtil.java +++ b/src/main/java/net/querz/nbt/NBTUtil.java @@ -25,8 +25,8 @@ private NBTUtil() {} * @param tag The tag to be written to the file. * @param file The file to write {@code tag} into. * @throws IOException If something during the serialization goes wrong. - * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String file) throws IOException { writeTag(tag, "", new File(file), true); @@ -38,8 +38,8 @@ public static void writeTag(Tag tag, String file) throws IOException { * @param tag The tag to be written to the file. * @param file The file to write {@code tag} into. * @throws IOException If something during the serialization goes wrong. - * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, File file) throws IOException { writeTag(tag, "", file, true); @@ -52,8 +52,8 @@ public static void writeTag(Tag tag, File file) throws IOException { * @param file The file to write {@code tag} into. * @param compressed {@code true} if the file should be GZIP compressed, {@code false} if not. * @throws IOException If something during the serialization goes wrong. - * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String file, boolean compressed) throws IOException { writeTag(tag, "", new File(file), compressed); @@ -66,8 +66,8 @@ public static void writeTag(Tag tag, String file, boolean compressed) throws * @param file The file to write {@code tag} into. * @param compressed {@code true} if the file should be GZIP compressed, {@code false} if not. * @throws IOException If something during the serialization goes wrong. - * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public static void writeTag(Tag tag, File file, boolean compressed) throws IOException { writeTag(tag, "", file, compressed); @@ -79,8 +79,8 @@ public static void writeTag(Tag tag, File file, boolean compressed) throws IO * @param name The name of the root tag. * @param file The file to write {@code tag} into. * @throws IOException If something during the serialization goes wrong. - * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String name, String file) throws IOException { writeTag(tag, name, new File(file), true); @@ -93,8 +93,8 @@ public static void writeTag(Tag tag, String name, String file) throws IOExcep * @param name The name of the root tag. * @param file The file to write {@code tag} into. * @throws IOException If something during the serialization goes wrong. - * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String name, File file) throws IOException { writeTag(tag, name, file, true); @@ -107,8 +107,8 @@ public static void writeTag(Tag tag, String name, File file) throws IOExcepti * @param file The file to write {@code tag} into. * @param compressed {@code true} if the file should be GZIP compressed, {@code false} if not. * @throws IOException If something during the serialization goes wrong. - * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String name, String file, boolean compressed) throws IOException { writeTag(tag, name, new File(file), compressed); @@ -122,8 +122,8 @@ public static void writeTag(Tag tag, String name, String file, boolean compre * @param file The file to write {@code tag} into. * @param compressed {@code true} if the file should be GZIP compressed, {@code false} if not. * @throws IOException If something during the serialization goes wrong. - * @exception NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws NullPointerException If {@code tag}, {@code name} or {@code file} is {@code null}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. */ public static void writeTag(Tag tag, String name, File file, boolean compressed) throws IOException { try ( @@ -151,7 +151,7 @@ public static Tag readTag(String file) throws IOException { * @return The tag read from the file. * @throws IOException If something during deserialization goes wrong. * @throws NullPointerException If {@code file} is {@code null}. - * @exception MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. + * @throws MaxDepthReachedException If the NBT structure exceeds {@link Tag#DEFAULT_MAX_DEPTH}. * */ public static Tag readTag(File file) throws IOException { try (DataInputStream dis = new DataInputStream(applyDecompression(new FileInputStream(file)))) {