Various optimizations and improvements

* Most notably, move the tag name out the of tags themselves
  * Always read/write CompoundTags in NBTIO
* Don't wrap values given in Tag#setValue / Tag constructors
* Abstract NumberTag class for easier (and primitive) number handling
* Don't use reflection when creating tag instances
* Directly use value in Tag#clone() for number tags
* Implement tag specific equals() methods
* Update to Java 8
* Replace links using http with https in maven pom
* Remove custom nbt types
* Proper checks for non-null values
This commit is contained in:
KennyTV 2021-03-14 15:40:10 +01:00
parent 32aecc1b60
commit 104486c6e1
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
38 changed files with 830 additions and 761 deletions

View File

@ -1,6 +1,17 @@
# OpenNBT
OpenNBT is a library for reading and writing NBT files, with some extra custom tags added to allow the storage of more data types.
This fork contains various improvements and changes specifically made for use in Via plugins, including but not limited to the following list:
* Most notably, move the tag name out the of tags themselves
* Add primitive getter methods to number types
* Don't wrap values given in Tag#setValue / Tag constructors
* Abstract NumberTag class for easier number handling
* Always read/write CompoundTags in NBTIO
* Don't use reflection when creating tag instances
* Directly use value in clone()
* Implement tag specific equals() methods
* Update to Java 8
## Building the Source
OpenNBT uses Maven to manage dependencies. Simply run 'mvn clean install' in the source's directory.

34
pom.xml
View File

@ -3,31 +3,30 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.steveice10</groupId>
<groupId>com.viaversion</groupId>
<artifactId>opennbt</artifactId>
<version>1.4-SNAPSHOT</version>
<version>2.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>OpenNBT</name>
<description>A library for reading and writing NBT files, written in Java.</description>
<url>http://github.com/Steveice10/OpenNBT/</url>
<url>https://github.com/Steveice10/OpenNBT/</url>
<scm>
<connection>scm:git:git@github.com:Steveice10/OpenNBT.git</connection>
<developerConnection>scm:git:git@github.com:Steveice10/OpenNBT.git</developerConnection>
<url>http://github.com/Steveice10/OpenNBT/</url>
<url>https://github.com/Steveice10/OpenNBT/</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.7</jdk.version>
<argLine></argLine>
<jdk.version>1.8</jdk.version>
</properties>
<licenses>
<license>
<name>MIT</name>
<url>http://www.opensource.org/licenses/mit-license.html</url>
<url>https://www.opensource.org/licenses/mit-license.html</url>
<distribution>repo</distribution>
</license>
</licenses>
@ -45,6 +44,27 @@
<url>https://github.com/Steveice10/OpenNBT/issues</url>
</issueManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>20.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>clean install</defaultGoal>
<plugins>

View File

@ -1,6 +1,5 @@
package com.github.steveice10.opennbt;
import com.github.steveice10.opennbt.tag.TagCreateException;
import com.github.steveice10.opennbt.tag.TagRegistry;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
@ -18,6 +17,7 @@ import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@ -152,7 +152,7 @@ public class NBTIO {
* @return The read tag, or null if the tag is an end tag.
* @throws java.io.IOException If an I/O error occurs.
*/
public static Tag readTag(InputStream in) throws IOException {
public static CompoundTag readTag(InputStream in) throws IOException {
return readTag(in, false);
}
@ -164,7 +164,7 @@ public class NBTIO {
* @return The read tag, or null if the tag is an end tag.
* @throws java.io.IOException If an I/O error occurs.
*/
public static Tag readTag(InputStream in, boolean littleEndian) throws IOException {
public static CompoundTag readTag(InputStream in, boolean littleEndian) throws IOException {
return readTag((DataInput) (littleEndian ? new LittleEndianDataInputStream(in) : new DataInputStream(in)));
}
@ -175,21 +175,16 @@ public class NBTIO {
* @return The read tag, or null if the tag is an end tag.
* @throws java.io.IOException If an I/O error occurs.
*/
public static Tag readTag(DataInput in) throws IOException {
int id = in.readUnsignedByte();
if(id == 0) {
return null;
public static CompoundTag readTag(DataInput in) throws IOException {
int id = in.readByte();
if(id != CompoundTag.ID) {
throw new IOException(String.format("Expected root tag to be a CompoundTag, was %s", id));
}
String name = in.readUTF();
Tag tag;
try {
tag = TagRegistry.createInstance(id, name);
} catch(TagCreateException e) {
throw new IOException("Failed to create tag.", e);
}
// Empty name
in.skipBytes(in.readUnsignedShort());
CompoundTag tag = new CompoundTag();
tag.read(in);
return tag;
}
@ -201,7 +196,7 @@ public class NBTIO {
* @param tag Tag to write.
* @throws java.io.IOException If an I/O error occurs.
*/
public static void writeTag(OutputStream out, Tag tag) throws IOException {
public static void writeTag(OutputStream out, CompoundTag tag) throws IOException {
writeTag(out, tag, false);
}
@ -213,7 +208,7 @@ public class NBTIO {
* @param littleEndian Whether to write little endian NBT.
* @throws java.io.IOException If an I/O error occurs.
*/
public static void writeTag(OutputStream out, Tag tag, boolean littleEndian) throws IOException {
public static void writeTag(OutputStream out, CompoundTag tag, boolean littleEndian) throws IOException {
writeTag((DataOutput) (littleEndian ? new LittleEndianDataOutputStream(out) : new DataOutputStream(out)), tag);
}
@ -224,18 +219,15 @@ public class NBTIO {
* @param tag Tag to write.
* @throws java.io.IOException If an I/O error occurs.
*/
public static void writeTag(DataOutput out, Tag tag) throws IOException {
if(tag != null) {
out.writeByte(TagRegistry.getIdFor(tag.getClass()));
out.writeUTF(tag.getName());
tag.write(out);
} else {
out.writeByte(0);
}
public static void writeTag(DataOutput out, CompoundTag tag) throws IOException {
out.writeByte(CompoundTag.ID);
out.writeUTF(""); // Empty name
tag.write(out);
}
private static class LittleEndianDataInputStream extends FilterInputStream implements DataInput {
public LittleEndianDataInputStream(InputStream in) {
private static final class LittleEndianDataInputStream extends FilterInputStream implements DataInput {
private LittleEndianDataInputStream(InputStream in) {
super(in);
}
@ -394,12 +386,13 @@ public class NBTIO {
byte[] bytes = new byte[this.readUnsignedShort()];
this.readFully(bytes);
return new String(bytes, "UTF-8");
return new String(bytes, StandardCharsets.UTF_8);
}
}
private static class LittleEndianDataOutputStream extends FilterOutputStream implements DataOutput {
public LittleEndianDataOutputStream(OutputStream out) {
private static final class LittleEndianDataOutputStream extends FilterOutputStream implements DataOutput {
private LittleEndianDataOutputStream(OutputStream out) {
super(out);
}
@ -490,7 +483,7 @@ public class NBTIO {
@Override
public void writeUTF(String s) throws IOException {
byte[] bytes = s.getBytes("UTF-8");
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
this.writeShort(bytes.length);
this.write(bytes);

View File

@ -1,9 +1,6 @@
package com.github.steveice10.opennbt.conversion;
import com.github.steveice10.opennbt.conversion.builtin.*;
import com.github.steveice10.opennbt.conversion.builtin.custom.DoubleArrayTagConverter;
import com.github.steveice10.opennbt.conversion.builtin.custom.FloatArrayTagConverter;
import com.github.steveice10.opennbt.conversion.builtin.custom.ShortArrayTagConverter;
import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
@ -16,10 +13,7 @@ import com.github.steveice10.opennbt.tag.builtin.LongTag;
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.github.steveice10.opennbt.tag.builtin.custom.DoubleArrayTag;
import com.github.steveice10.opennbt.tag.builtin.custom.FloatArrayTag;
import com.github.steveice10.opennbt.tag.builtin.LongArrayTag;
import com.github.steveice10.opennbt.tag.builtin.custom.ShortArrayTag;
import java.io.Serializable;
import java.util.HashMap;
@ -49,10 +43,6 @@ public class ConverterRegistry {
register(CompoundTag.class, Map.class, new CompoundTagConverter());
register(IntArrayTag.class, int[].class, new IntArrayTagConverter());
register(LongArrayTag.class, long[].class, new LongArrayTagConverter());
register(DoubleArrayTag.class, double[].class, new DoubleArrayTagConverter());
register(FloatArrayTag.class, float[].class, new FloatArrayTagConverter());
register(ShortArrayTag.class, short[].class, new ShortArrayTagConverter());
}
/**
@ -118,12 +108,11 @@ public class ConverterRegistry {
*
* @param <V> Value type to convert from.
* @param <T> Tag type to convert to.
* @param name Name of the resulting tag.
* @param value Value to convert.
* @return The converted tag.
* @throws ConversionException If a suitable converter could not be found.
*/
public static <V, T extends Tag> T convertToTag(String name, V value) throws ConversionException {
public static <V, T extends Tag> T convertToTag(V value) throws ConversionException {
if(value == null) {
return null;
}
@ -145,7 +134,7 @@ public class ConverterRegistry {
throw new ConversionException("Value type " + value.getClass().getName() + " has no converter.");
}
return converter.convert(name, value);
return converter.convert(value);
}
private static Set<Class<?>> getAllClasses(Class<?> clazz) {

View File

@ -20,9 +20,8 @@ public interface TagConverter<T extends Tag, V> {
/**
* Converts a value to a tag.
*
* @param name Name of the tag.
* @param value Value to convert.
* @return The converted tag.
*/
public T convert(String name, V value);
public T convert(V value);
}

View File

@ -13,7 +13,7 @@ public class ByteArrayTagConverter implements TagConverter<ByteArrayTag, byte[]>
}
@Override
public ByteArrayTag convert(String name, byte[] value) {
return new ByteArrayTag(name, value);
public ByteArrayTag convert(byte[] value) {
return new ByteArrayTag(value);
}
}

View File

@ -13,7 +13,7 @@ public class ByteTagConverter implements TagConverter<ByteTag, Byte> {
}
@Override
public ByteTag convert(String name, Byte value) {
return new ByteTag(name, value);
public ByteTag convert(Byte value) {
return new ByteTag(value);
}
}

View File

@ -14,24 +14,23 @@ import java.util.Map;
public class CompoundTagConverter implements TagConverter<CompoundTag, Map> {
@Override
public Map convert(CompoundTag tag) {
Map<String, Object> ret = new HashMap<String, Object>();
Map<String, Object> ret = new HashMap<>();
Map<String, Tag> tags = tag.getValue();
for(String name : tags.keySet()) {
Tag t = tags.get(name);
ret.put(t.getName(), ConverterRegistry.convertToValue(t));
for(Map.Entry<String, Tag> entry : tags.entrySet()) {
ret.put(entry.getKey(), ConverterRegistry.convertToValue(entry.getValue()));
}
return ret;
}
@Override
public CompoundTag convert(String name, Map value) {
Map<String, Tag> tags = new HashMap<String, Tag>();
public CompoundTag convert(Map value) {
Map<String, Tag> tags = new HashMap<>();
for(Object na : value.keySet()) {
String n = (String) na;
tags.put(n, ConverterRegistry.convertToTag(n, value.get(n)));
tags.put(n, ConverterRegistry.convertToTag(value.get(n)));
}
return new CompoundTag(name, tags);
return new CompoundTag(tags);
}
}

View File

@ -13,7 +13,7 @@ public class DoubleTagConverter implements TagConverter<DoubleTag, Double> {
}
@Override
public DoubleTag convert(String name, Double value) {
return new DoubleTag(name, value);
public DoubleTag convert(Double value) {
return new DoubleTag(value);
}
}

View File

@ -13,7 +13,7 @@ public class FloatTagConverter implements TagConverter<FloatTag, Float> {
}
@Override
public FloatTag convert(String name, Float value) {
return new FloatTag(name, value);
public FloatTag convert(Float value) {
return new FloatTag(value);
}
}

View File

@ -13,7 +13,7 @@ public class IntArrayTagConverter implements TagConverter<IntArrayTag, int[]> {
}
@Override
public IntArrayTag convert(String name, int[] value) {
return new IntArrayTag(name, value);
public IntArrayTag convert(int[] value) {
return new IntArrayTag(value);
}
}

View File

@ -13,7 +13,7 @@ public class IntTagConverter implements TagConverter<IntTag, Integer> {
}
@Override
public IntTag convert(String name, Integer value) {
return new IntTag(name, value);
public IntTag convert(Integer value) {
return new IntTag(value);
}
}

View File

@ -14,7 +14,7 @@ import java.util.List;
public class ListTagConverter implements TagConverter<ListTag, List> {
@Override
public List convert(ListTag tag) {
List<Object> ret = new ArrayList<Object>();
List<Object> ret = new ArrayList<>();
List<? extends Tag> tags = tag.getValue();
for(Tag t : tags) {
ret.add(ConverterRegistry.convertToValue(t));
@ -24,12 +24,12 @@ public class ListTagConverter implements TagConverter<ListTag, List> {
}
@Override
public ListTag convert(String name, List value) {
List<Tag> tags = new ArrayList<Tag>();
public ListTag convert(List value) {
List<Tag> tags = new ArrayList<>();
for(Object o : value) {
tags.add(ConverterRegistry.convertToTag("", o));
tags.add(ConverterRegistry.convertToTag(o));
}
return new ListTag(name, tags);
return new ListTag(tags);
}
}

View File

@ -13,7 +13,7 @@ public class LongArrayTagConverter implements TagConverter<LongArrayTag, long[]>
}
@Override
public LongArrayTag convert(String name, long[] value) {
return new LongArrayTag(name, value);
public LongArrayTag convert(long[] value) {
return new LongArrayTag(value);
}
}

View File

@ -13,7 +13,7 @@ public class LongTagConverter implements TagConverter<LongTag, Long> {
}
@Override
public LongTag convert(String name, Long value) {
return new LongTag(name, value);
public LongTag convert(Long value) {
return new LongTag(value);
}
}

View File

@ -13,7 +13,7 @@ public class ShortTagConverter implements TagConverter<ShortTag, Short> {
}
@Override
public ShortTag convert(String name, Short value) {
return new ShortTag(name, value);
public ShortTag convert(Short value) {
return new ShortTag(value);
}
}

View File

@ -13,7 +13,7 @@ public class StringTagConverter implements TagConverter<StringTag, String> {
}
@Override
public StringTag convert(String name, String value) {
return new StringTag(name, value);
public StringTag convert(String value) {
return new StringTag(value);
}
}

View File

@ -1,19 +0,0 @@
package com.github.steveice10.opennbt.conversion.builtin.custom;
import com.github.steveice10.opennbt.conversion.TagConverter;
import com.github.steveice10.opennbt.tag.builtin.custom.DoubleArrayTag;
/**
* A converter that converts between DoubleArrayTag and double[].
*/
public class DoubleArrayTagConverter implements TagConverter<DoubleArrayTag, double[]> {
@Override
public double[] convert(DoubleArrayTag tag) {
return tag.getValue();
}
@Override
public DoubleArrayTag convert(String name, double[] value) {
return new DoubleArrayTag(name, value);
}
}

View File

@ -1,19 +0,0 @@
package com.github.steveice10.opennbt.conversion.builtin.custom;
import com.github.steveice10.opennbt.conversion.TagConverter;
import com.github.steveice10.opennbt.tag.builtin.custom.FloatArrayTag;
/**
* A converter that converts between FloatArrayTag and float[].
*/
public class FloatArrayTagConverter implements TagConverter<FloatArrayTag, float[]> {
@Override
public float[] convert(FloatArrayTag tag) {
return tag.getValue();
}
@Override
public FloatArrayTag convert(String name, float[] value) {
return new FloatArrayTag(name, value);
}
}

View File

@ -1,19 +0,0 @@
package com.github.steveice10.opennbt.conversion.builtin.custom;
import com.github.steveice10.opennbt.conversion.TagConverter;
import com.github.steveice10.opennbt.tag.builtin.custom.ShortArrayTag;
/**
* A converter that converts between ShortArrayTag and short[].
*/
public class ShortArrayTagConverter implements TagConverter<ShortArrayTag, short[]> {
@Override
public short[] convert(ShortArrayTag tag) {
return tag.getValue();
}
@Override
public ShortArrayTag convert(String name, short[] value) {
return new ShortArrayTag(name, value);
}
}

View File

@ -8,43 +8,43 @@ import com.github.steveice10.opennbt.tag.builtin.FloatTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.LongArrayTag;
import com.github.steveice10.opennbt.tag.builtin.LongTag;
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.github.steveice10.opennbt.tag.builtin.custom.DoubleArrayTag;
import com.github.steveice10.opennbt.tag.builtin.custom.FloatArrayTag;
import com.github.steveice10.opennbt.tag.builtin.LongArrayTag;
import com.github.steveice10.opennbt.tag.builtin.custom.ShortArrayTag;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
/**
* A registry containing different tag classes.
*/
public class TagRegistry {
private static final Map<Integer, Class<? extends Tag>> idToTag = new HashMap<Integer, Class<? extends Tag>>();
private static final Map<Class<? extends Tag>, Integer> tagToId = new HashMap<Class<? extends Tag>, Integer>();
private static final Int2ObjectMap<Class<? extends Tag>> idToTag = new Int2ObjectOpenHashMap<>();
private static final Object2IntMap<Class<? extends Tag>> tagToId = new Object2IntOpenHashMap<>();
private static final Int2ObjectMap<Supplier<? extends Tag>> instanceSuppliers = new Int2ObjectOpenHashMap<>();
static {
register(1, ByteTag.class);
register(2, ShortTag.class);
register(3, IntTag.class);
register(4, LongTag.class);
register(5, FloatTag.class);
register(6, DoubleTag.class);
register(7, ByteArrayTag.class);
register(8, StringTag.class);
register(9, ListTag.class);
register(10, CompoundTag.class);
register(11, IntArrayTag.class);
register(12, LongArrayTag.class);
tagToId.defaultReturnValue(-1);
register(60, DoubleArrayTag.class);
register(61, FloatArrayTag.class);
register(65, ShortArrayTag.class);
register(ByteTag.ID, ByteTag.class, ByteTag::new);
register(ShortTag.ID, ShortTag.class, ShortTag::new);
register(IntTag.ID, IntTag.class, IntTag::new);
register(LongTag.ID, LongTag.class, LongTag::new);
register(FloatTag.ID, FloatTag.class, FloatTag::new);
register(DoubleTag.ID, DoubleTag.class, DoubleTag::new);
register(ByteArrayTag.ID, ByteArrayTag.class, ByteArrayTag::new);
register(StringTag.ID, StringTag.class, StringTag::new);
register(ListTag.ID, ListTag.class, ListTag::new);
register(CompoundTag.ID, CompoundTag.class, CompoundTag::new);
register(IntArrayTag.ID, IntArrayTag.class, IntArrayTag::new);
register(LongArrayTag.ID, LongArrayTag.class, LongArrayTag::new);
}
/**
@ -54,7 +54,7 @@ public class TagRegistry {
* @param tag Tag class to register.
* @throws TagRegisterException If an error occurs while registering the tag.
*/
public static void register(int id, Class<? extends Tag> tag) throws TagRegisterException {
public static void register(int id, Class<? extends Tag> tag, Supplier<? extends Tag> supplier) throws TagRegisterException {
if(idToTag.containsKey(id)) {
throw new TagRegisterException("Tag ID \"" + id + "\" is already in use.");
}
@ -63,6 +63,7 @@ public class TagRegistry {
throw new TagRegisterException("Tag \"" + tag.getSimpleName() + "\" is already registered.");
}
instanceSuppliers.put(id, supplier);
idToTag.put(id, tag);
tagToId.put(tag, id);
}
@ -73,7 +74,7 @@ public class TagRegistry {
* @param id ID of the tag to unregister.
*/
public static void unregister(int id) {
tagToId.remove(getClassFor(id));
tagToId.removeInt(getClassFor(id));
idToTag.remove(id);
}
@ -83,11 +84,8 @@ public class TagRegistry {
* @param id Id of the tag.
* @return The tag class with the given id, or null if it cannot be found.
*/
@Nullable
public static Class<? extends Tag> getClassFor(int id) {
if(!idToTag.containsKey(id)) {
return null;
}
return idToTag.get(id);
}
@ -98,33 +96,22 @@ public class TagRegistry {
* @return The id of the given tag class, or -1 if it cannot be found.
*/
public static int getIdFor(Class<? extends Tag> clazz) {
if(!tagToId.containsKey(clazz)) {
return -1;
}
return tagToId.get(clazz);
return tagToId.getInt(clazz);
}
/**
* Creates an instance of the tag with the given id, using the String constructor.
*
* @param id Id of the tag.
* @param tagName Name to give the tag.
* @param id Id of the tag.
* @return The created tag.
* @throws TagCreateException If an error occurs while creating the tag.
*/
public static Tag createInstance(int id, String tagName) throws TagCreateException {
Class<? extends Tag> clazz = idToTag.get(id);
if(clazz == null) {
public static Tag createInstance(int id) throws TagCreateException {
Supplier<? extends Tag> supplier = instanceSuppliers.get(id);
if(supplier == null) {
throw new TagCreateException("Could not find tag with ID \"" + id + "\".");
}
try {
Constructor<? extends Tag> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
return constructor.newInstance(tagName);
} catch(Exception e) {
throw new TagCreateException("Failed to create instance of tag \"" + clazz.getSimpleName() + "\".", e);
}
return supplier.get();
}
}

View File

@ -3,36 +3,34 @@ package com.github.steveice10.opennbt.tag.builtin;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
/**
* A tag containing a byte array.
*/
public class ByteArrayTag extends Tag {
public static final int ID = 7;
private byte[] value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public ByteArrayTag(String name) {
this(name, new byte[0]);
public ByteArrayTag() {
this(new byte[0]);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public ByteArrayTag(String name, byte[] value) {
super(name);
public ByteArrayTag(byte[] value) {
this.value = value;
}
@Override
public byte[] getValue() {
return this.value.clone();
return this.value;
}
/**
@ -45,7 +43,7 @@ public class ByteArrayTag extends Tag {
return;
}
this.value = value.clone();
this.value = value;
}
/**
@ -90,7 +88,25 @@ public class ByteArrayTag extends Tag {
}
@Override
public ByteArrayTag clone() {
return new ByteArrayTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ByteArrayTag that = (ByteArrayTag) o;
return Arrays.equals(this.value, that.value);
}
@Override
public int hashCode() {
return Arrays.hashCode(this.value);
}
@Override
public final ByteArrayTag clone() {
return new ByteArrayTag(this.value);
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -7,30 +7,31 @@ import java.io.IOException;
/**
* A tag containing a byte.
*/
public class ByteTag extends Tag {
public class ByteTag extends NumberTag {
public static final int ID = 1;
private byte value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public ByteTag(String name) {
this(name, (byte) 0);
public ByteTag() {
this((byte) 0);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public ByteTag(String name, byte value) {
super(name);
public ByteTag(byte value) {
this.value = value;
}
/**
* @deprecated use {@link #asByte()}
*/
@Override
@Deprecated
public Byte getValue() {
return this.value;
}
@ -55,7 +56,55 @@ public class ByteTag extends Tag {
}
@Override
public ByteTag clone() {
return new ByteTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ByteTag byteTag = (ByteTag) o;
return this.value == byteTag.value;
}
@Override
public int hashCode() {
return value;
}
@Override
public final ByteTag clone() {
return new ByteTag(this.value);
}
@Override
public byte asByte() {
return this.value;
}
@Override
public short asShort() {
return this.value;
}
@Override
public int asInt() {
return this.value;
}
@Override
public long asLong() {
return this.value;
}
@Override
public float asFloat() {
return this.value;
}
@Override
public double asDouble() {
return this.value;
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -1,16 +1,17 @@
package com.github.steveice10.opennbt.tag.builtin;
import com.github.steveice10.opennbt.NBTIO;
import com.github.steveice10.opennbt.tag.TagCreateException;
import com.github.steveice10.opennbt.tag.TagRegistry;
import com.google.common.base.Preconditions;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@ -18,32 +19,39 @@ import java.util.Set;
/**
* A compound tag containing other tags.
*/
public class CompoundTag extends Tag implements Iterable<Tag> {
public class CompoundTag extends Tag implements Iterable<Entry<String, Tag>> {
public static final int ID = 10;
private Map<String, Tag> value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public CompoundTag(String name) {
this(name, new LinkedHashMap<String, Tag>());
public CompoundTag() {
this(new LinkedHashMap<>());
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public CompoundTag(String name, Map<String, Tag> value) {
super(name);
this.value = new LinkedHashMap<String, Tag>(value);
public CompoundTag(Map<String, Tag> value) {
this.value = new LinkedHashMap<>(value);
}
/**
* Creates a tag without wrapping the map.
*
* @param value The value of the tag.
*/
public CompoundTag(LinkedHashMap<String, Tag> value) {
Preconditions.checkNotNull(value);
this.value = value;
}
@Override
public Map<String, Tag> getValue() {
return new LinkedHashMap<String, Tag>(this.value);
return this.value;
}
/**
@ -52,7 +60,18 @@ public class CompoundTag extends Tag implements Iterable<Tag> {
* @param value New value of this tag.
*/
public void setValue(Map<String, Tag> value) {
this.value = new LinkedHashMap<String, Tag>(value);
Preconditions.checkNotNull(value);
this.value = new LinkedHashMap<>(value);
}
/**
* Sets the value of this tag without wrapping the map.
*
* @param value New value of this tag.
*/
public void setValue(LinkedHashMap<String, Tag> value) {
Preconditions.checkNotNull(value);
this.value = value;
}
/**
@ -65,22 +84,23 @@ public class CompoundTag extends Tag implements Iterable<Tag> {
}
/**
* Checks whether the compound tag contains a tag with the specified name.
* Checks whether the compound tag contains a tag.
*
* @param tagName Name of the tag to check for.
* @return Whether the compound tag contains a tag with the specified name.
* @return Whether the compound tag contains a tag.
*/
public boolean contains(String tagName) {
return this.value.containsKey(tagName);
}
/**
* Gets the tag with the specified name.
* Gets the tag.
*
* @param <T> Type of tag to get.
* @param tagName Name of the tag.
* @return The tag with the specified name.
* @return The tag.
*/
@Nullable
public <T extends Tag> T get(String tagName) {
return (T) this.value.get(tagName);
}
@ -88,12 +108,14 @@ public class CompoundTag extends Tag implements Iterable<Tag> {
/**
* Puts the tag into this compound tag.
*
* @param <T> Type of tag to put.
* @param tag Tag to put into this compound tag.
* @param <T> Type of tag to put.
* @param tagName Name of the tag.
* @param tag Tag to put into this compound tag.
* @return The previous tag associated with its name, or null if there wasn't one.
*/
public <T extends Tag> T put(T tag) {
return (T) this.value.put(tag.getName(), tag);
@Nullable
public <T extends Tag> T put(String tagName, T tag) {
return (T) this.value.put(tagName, tag);
}
/**
@ -103,6 +125,7 @@ public class CompoundTag extends Tag implements Iterable<Tag> {
* @param tagName Name of the tag to remove.
* @return The removed tag.
*/
@Nullable
public <T extends Tag> T remove(String tagName) {
return (T) this.value.remove(tagName);
}
@ -125,6 +148,15 @@ public class CompoundTag extends Tag implements Iterable<Tag> {
return this.value.values();
}
/**
* Gets the entry set of this compound tag.
*
* @return The compound tag's entry set.
*/
public Set<Entry<String, Tag>> entrySet() {
return this.value.entrySet();
}
/**
* Gets the number of tags in this compound tag.
*
@ -142,43 +174,71 @@ public class CompoundTag extends Tag implements Iterable<Tag> {
}
@Override
public Iterator<Tag> iterator() {
return this.values().iterator();
public Iterator<Entry<String, Tag>> iterator() {
return this.value.entrySet().iterator();
}
@Override
public void read(DataInput in) throws IOException {
List<Tag> tags = new ArrayList<Tag>();
try {
Tag tag;
while((tag = NBTIO.readTag(in)) != null) {
tags.add(tag);
}
} catch(EOFException e) {
throw new IOException("Closing EndTag was not found!");
}
int id;
while (true) {
id = in.readByte();
if (id == 0) {
// End tag
break;
}
for(Tag tag : tags) {
this.put(tag);
String name = in.readUTF();
Tag tag = TagRegistry.createInstance(id);
tag.read(in);
this.value.put(name, tag);
}
} catch(TagCreateException e) {
throw new IOException("Failed to create tag.", e);
} catch(EOFException e) {
throw new IOException("Closing tag was not found!");
}
}
@Override
public void write(DataOutput out) throws IOException {
for(Tag tag : this.value.values()) {
NBTIO.writeTag(out, tag);
for(Entry<String, Tag> entry : this.value.entrySet()) {
Tag tag = entry.getValue();
out.writeByte(tag.getTagId());
out.writeUTF(entry.getKey());
tag.write(out);
}
// End
out.writeByte(0);
}
@Override
public CompoundTag clone() {
Map<String, Tag> newMap = new LinkedHashMap<String, Tag>();
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CompoundTag tags = (CompoundTag) o;
return this.value.equals(tags.value);
}
@Override
public int hashCode() {
return value.hashCode();
}
@Override
public final CompoundTag clone() {
LinkedHashMap<String, Tag> newMap = new LinkedHashMap<>();
for(Entry<String, Tag> entry : this.value.entrySet()) {
newMap.put(entry.getKey(), entry.getValue().clone());
}
return new CompoundTag(this.getName(), newMap);
return new CompoundTag(newMap);
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -7,30 +7,31 @@ import java.io.IOException;
/**
* A tag containing a double.
*/
public class DoubleTag extends Tag {
public class DoubleTag extends NumberTag {
public static final int ID = 6;
private double value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public DoubleTag(String name) {
this(name, 0);
public DoubleTag() {
this(0);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public DoubleTag(String name, double value) {
super(name);
public DoubleTag(double value) {
this.value = value;
}
/**
* @deprecated use {@link #asDouble()}
*/
@Override
@Deprecated
public Double getValue() {
return this.value;
}
@ -55,7 +56,55 @@ public class DoubleTag extends Tag {
}
@Override
public DoubleTag clone() {
return new DoubleTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DoubleTag doubleTag = (DoubleTag) o;
return this.value == doubleTag.value;
}
@Override
public int hashCode() {
return Double.hashCode(this.value);
}
@Override
public final DoubleTag clone() {
return new DoubleTag(this.value);
}
@Override
public byte asByte() {
return (byte) this.value;
}
@Override
public short asShort() {
return (short) this.value;
}
@Override
public int asInt() {
return (int) this.value;
}
@Override
public long asLong() {
return (long) this.value;
}
@Override
public float asFloat() {
return (float) this.value;
}
@Override
public double asDouble() {
return this.value;
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -7,30 +7,31 @@ import java.io.IOException;
/**
* A tag containing a float.
*/
public class FloatTag extends Tag {
public class FloatTag extends NumberTag {
public static final int ID = 5;
private float value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public FloatTag(String name) {
this(name, 0);
public FloatTag() {
this(0);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public FloatTag(String name, float value) {
super(name);
public FloatTag(float value) {
this.value = value;
}
/**
* @deprecated use {@link #asFloat()}
*/
@Override
@Deprecated
public Float getValue() {
return this.value;
}
@ -55,7 +56,55 @@ public class FloatTag extends Tag {
}
@Override
public FloatTag clone() {
return new FloatTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FloatTag floatTag = (FloatTag) o;
return this.value == floatTag.value;
}
@Override
public int hashCode() {
return Float.hashCode(this.value);
}
@Override
public final FloatTag clone() {
return new FloatTag(this.value);
}
@Override
public byte asByte() {
return (byte) this.value;
}
@Override
public short asShort() {
return (short) this.value;
}
@Override
public int asInt() {
return (int) this.value;
}
@Override
public long asLong() {
return (long) this.value;
}
@Override
public float asFloat() {
return this.value;
}
@Override
public double asDouble() {
return this.value;
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -1,38 +1,39 @@
package com.github.steveice10.opennbt.tag.builtin;
import com.google.common.base.Preconditions;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
/**
* A tag containing an integer array.
*/
public class IntArrayTag extends Tag {
public static final int ID = 11;
private int[] value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public IntArrayTag(String name) {
this(name, new int[0]);
public IntArrayTag() {
this(new int[0]);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public IntArrayTag(String name, int[] value) {
super(name);
public IntArrayTag(int[] value) {
Preconditions.checkNotNull(value);
this.value = value;
}
@Override
public int[] getValue() {
return this.value.clone();
return this.value;
}
/**
@ -41,11 +42,8 @@ public class IntArrayTag extends Tag {
* @param value New value of this tag.
*/
public void setValue(int[] value) {
if(value == null) {
return;
}
this.value = value.clone();
Preconditions.checkNotNull(value);
this.value = value;
}
/**
@ -88,13 +86,31 @@ public class IntArrayTag extends Tag {
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(this.value.length);
for(int index = 0; index < this.value.length; index++) {
out.writeInt(this.value[index]);
for (int i : this.value) {
out.writeInt(i);
}
}
@Override
public IntArrayTag clone() {
return new IntArrayTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IntArrayTag that = (IntArrayTag) o;
return Arrays.equals(this.value, that.value);
}
@Override
public int hashCode() {
return Arrays.hashCode(this.value);
}
@Override
public final IntArrayTag clone() {
return new IntArrayTag(this.value.clone());
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -7,30 +7,31 @@ import java.io.IOException;
/**
* A tag containing an integer.
*/
public class IntTag extends Tag {
public class IntTag extends NumberTag {
public static final int ID = 3;
private int value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public IntTag(String name) {
this(name, 0);
public IntTag() {
this(0);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public IntTag(String name, int value) {
super(name);
public IntTag(int value) {
this.value = value;
}
/**
* @deprecated use {@link #asInt()}
*/
@Override
@Deprecated
public Integer getValue() {
return this.value;
}
@ -55,7 +56,55 @@ public class IntTag extends Tag {
}
@Override
public IntTag clone() {
return new IntTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IntTag intTag = (IntTag) o;
return this.value == intTag.value;
}
@Override
public int hashCode() {
return this.value;
}
@Override
public final IntTag clone() {
return new IntTag(this.value);
}
@Override
public byte asByte() {
return (byte) this.value;
}
@Override
public short asShort() {
return (short) this.value;
}
@Override
public int asInt() {
return this.value;
}
@Override
public long asLong() {
return this.value;
}
@Override
public float asFloat() {
return this.value;
}
@Override
public double asDouble() {
return this.value;
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -2,6 +2,8 @@ package com.github.steveice10.opennbt.tag.builtin;
import com.github.steveice10.opennbt.tag.TagCreateException;
import com.github.steveice10.opennbt.tag.TagRegistry;
import com.google.common.base.Preconditions;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput;
import java.io.DataOutput;
@ -9,55 +11,47 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
/**
* A tag containing a list of tags.
*/
public class ListTag extends Tag implements Iterable<Tag> {
public static final int ID = 9;
private final List<Tag> value;
private Class<? extends Tag> type;
private List<Tag> value;
/**
* Creates an empty list tag with the specified name and no defined type.
*
* @param name The name of the tag.
* Creates an empty list tag and no defined type.
*/
public ListTag(String name) {
super(name);
this.type = null;
this.value = new ArrayList<Tag>();
public ListTag() {
this.value = new ArrayList<>();
}
/**
* Creates an empty list tag with the specified name and type.
*
* @param name The name of the tag.
* Creates an empty list tag and type.
* @param type Tag type of the list.
*/
public ListTag(String name, Class<? extends Tag> type) {
this(name);
public ListTag(@Nullable Class<? extends Tag> type) {
this.type = type;
this.value = new ArrayList<>();
}
/**
* Creates a list tag with the specified name and value.
* Creates a list tag and value.
* The list tag's type will be set to that of the first tag being added, or null if the given list is empty.
*
* @param name The name of the tag.
* @param value The value of the tag.
* @throws IllegalArgumentException If all tags in the list are not of the same type.
*/
public ListTag(String name, List<Tag> value) throws IllegalArgumentException {
this(name);
public ListTag(List<Tag> value) throws IllegalArgumentException {
this.value = new ArrayList<>(value.size());
this.setValue(value);
}
@Override
public List<Tag> getValue() {
return new ArrayList<Tag>(this.value);
return this.value;
}
/**
@ -68,6 +62,8 @@ public class ListTag extends Tag implements Iterable<Tag> {
* @throws IllegalArgumentException If all tags in the list are not of the same type.
*/
public void setValue(List<Tag> value) throws IllegalArgumentException {
Preconditions.checkNotNull(value);
this.type = null;
this.value.clear();
@ -94,9 +90,7 @@ public class ListTag extends Tag implements Iterable<Tag> {
* @throws IllegalArgumentException If the tag's type differs from the list tag's type.
*/
public boolean add(Tag tag) throws IllegalArgumentException {
if(tag == null) {
return false;
}
Preconditions.checkNotNull(tag);
// If empty list, use this as tag type.
if(this.type == null) {
@ -146,9 +140,8 @@ public class ListTag extends Tag implements Iterable<Tag> {
@Override
public void read(DataInput in) throws IOException {
this.type = null;
this.value.clear();
int id = in.readUnsignedByte();
int id = in.readByte();
if(id != 0) {
this.type = TagRegistry.getClassFor(id);
if(this.type == null) {
@ -158,9 +151,9 @@ public class ListTag extends Tag implements Iterable<Tag> {
int count = in.readInt();
for(int index = 0; index < count; index++) {
Tag tag = null;
Tag tag;
try {
tag = TagRegistry.createInstance(id, "");
tag = TagRegistry.createInstance(id);
} catch(TagCreateException e) {
throw new IOException("Failed to create tag.", e);
}
@ -190,12 +183,33 @@ public class ListTag extends Tag implements Iterable<Tag> {
}
@Override
public ListTag clone() {
List<Tag> newList = new ArrayList<Tag>();
public final ListTag clone() {
List<Tag> newList = new ArrayList<>();
for(Tag value : this.value) {
newList.add(value.clone());
}
return new ListTag(this.getName(), newList);
return new ListTag(newList);
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ListTag tags = (ListTag) o;
if (!Objects.equals(this.type, tags.type)) return false;
return this.value.equals(tags.value);
}
@Override
public int hashCode() {
int result = this.type != null ? this.type.hashCode() : 0;
result = 31 * result + this.value.hashCode();
return result;
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -1,38 +1,39 @@
package com.github.steveice10.opennbt.tag.builtin;
import com.google.common.base.Preconditions;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
/**
* A tag containing a long array.
*/
public class LongArrayTag extends Tag {
public static final int ID = 12;
private long[] value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public LongArrayTag(String name) {
this(name, new long[0]);
public LongArrayTag() {
this(new long[0]);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public LongArrayTag(String name, long[] value) {
super(name);
public LongArrayTag(long[] value) {
Preconditions.checkNotNull(value);
this.value = value;
}
@Override
public long[] getValue() {
return this.value.clone();
return this.value;
}
/**
@ -41,11 +42,8 @@ public class LongArrayTag extends Tag {
* @param value New value of this tag.
*/
public void setValue(long[] value) {
if(value == null) {
return;
}
this.value = value.clone();
Preconditions.checkNotNull(value);
this.value = value;
}
/**
@ -88,13 +86,31 @@ public class LongArrayTag extends Tag {
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(this.value.length);
for(int index = 0; index < this.value.length; index++) {
out.writeLong(this.value[index]);
for (long l : this.value) {
out.writeLong(l);
}
}
@Override
public LongArrayTag clone() {
return new LongArrayTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LongArrayTag that = (LongArrayTag) o;
return Arrays.equals(this.value, that.value);
}
@Override
public int hashCode() {
return Arrays.hashCode(this.value);
}
@Override
public final LongArrayTag clone() {
return new LongArrayTag(this.value.clone());
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -7,30 +7,31 @@ import java.io.IOException;
/**
* A tag containing a long.
*/
public class LongTag extends Tag {
public class LongTag extends NumberTag {
public static final int ID = 4;
private long value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public LongTag(String name) {
this(name, 0);
public LongTag() {
this(0);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public LongTag(String name, long value) {
super(name);
public LongTag(long value) {
this.value = value;
}
/**
* @deprecated use {@link #asLong()}
*/
@Override
@Deprecated
public Long getValue() {
return this.value;
}
@ -55,7 +56,55 @@ public class LongTag extends Tag {
}
@Override
public LongTag clone() {
return new LongTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LongTag longTag = (LongTag) o;
return this.value == longTag.value;
}
@Override
public int hashCode() {
return Long.hashCode(this.value);
}
@Override
public final LongTag clone() {
return new LongTag(this.value);
}
@Override
public byte asByte() {
return (byte) this.value;
}
@Override
public short asShort() {
return (short) this.value;
}
@Override
public int asInt() {
return (int) this.value;
}
@Override
public long asLong() {
return this.value;
}
@Override
public float asFloat() {
return this.value;
}
@Override
public double asDouble() {
return this.value;
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -0,0 +1,49 @@
package com.github.steveice10.opennbt.tag.builtin;
/**
* Abstract class representing a number tag, containing methods to return primitive number types.
*/
public abstract class NumberTag extends Tag {
/**
* Gets the byte value of this tag.
*
* @return Byte value of this tag.
*/
public abstract byte asByte();
/**
* Gets the short value of this tag.
*
* @return Short value of this tag.
*/
public abstract short asShort();
/**
* Gets the int value of this tag.
*
* @return Int value of this tag.
*/
public abstract int asInt();
/**
* Gets the long value of this tag.
*
* @return Long value of this tag.
*/
public abstract long asLong();
/**
* Gets the float value of this tag.
*
* @return Float value of this tag.
*/
public abstract float asFloat();
/**
* Gets the double value of this tag.
*
* @return Double value of this tag.
*/
public abstract double asDouble();
}

View File

@ -7,30 +7,31 @@ import java.io.IOException;
/**
* A tag containing a short.
*/
public class ShortTag extends Tag {
public class ShortTag extends NumberTag {
public static final int ID = 2;
private short value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public ShortTag(String name) {
this(name, (short) 0);
public ShortTag() {
this((short) 0);
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public ShortTag(String name, short value) {
super(name);
public ShortTag(short value) {
this.value = value;
}
/**
* @deprecated use {@link #asShort()}
*/
@Override
@Deprecated
public Short getValue() {
return this.value;
}
@ -55,7 +56,55 @@ public class ShortTag extends Tag {
}
@Override
public ShortTag clone() {
return new ShortTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ShortTag shortTag = (ShortTag) o;
return this.value == shortTag.value;
}
@Override
public int hashCode() {
return this.value;
}
@Override
public final ShortTag clone() {
return new ShortTag(this.value);
}
@Override
public byte asByte() {
return (byte) this.value;
}
@Override
public short asShort() {
return this.value;
}
@Override
public int asInt() {
return this.value;
}
@Override
public long asLong() {
return this.value;
}
@Override
public float asFloat() {
return this.value;
}
@Override
public double asDouble() {
return this.value;
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -1,5 +1,7 @@
package com.github.steveice10.opennbt.tag.builtin;
import com.google.common.base.Preconditions;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
@ -8,25 +10,23 @@ import java.io.IOException;
* A tag containing a string.
*/
public class StringTag extends Tag {
public static final int ID = 8;
private String value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* Creates a tag.
*/
public StringTag(String name) {
this(name, "");
public StringTag() {
this("");
}
/**
* Creates a tag with the specified name.
* Creates a tag.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public StringTag(String name, String value) {
super(name);
public StringTag(String value) {
Preconditions.checkNotNull(value);
this.value = value;
}
@ -41,6 +41,7 @@ public class StringTag extends Tag {
* @param value New value of this tag.
*/
public void setValue(String value) {
Preconditions.checkNotNull(value);
this.value = value;
}
@ -55,7 +56,25 @@ public class StringTag extends Tag {
}
@Override
public StringTag clone() {
return new StringTag(this.getName(), this.getValue());
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StringTag stringTag = (StringTag) o;
return this.value.equals(stringTag.value);
}
@Override
public int hashCode() {
return this.value.hashCode();
}
@Override
public final StringTag clone() {
return new StringTag(this.value);
}
@Override
public int getTagId() {
return ID;
}
}

View File

@ -8,29 +8,9 @@ import java.lang.reflect.Array;
/**
* Represents an NBT tag.
* <p>
* All tags must have a constructor with a single string parameter for reading tags (can be any visibility).
* Tags should also have setter methods specific to their value types.
*/
public abstract class Tag implements Cloneable {
private String name;
/**
* Creates a tag with the specified name.
*
* @param name The name.
*/
public Tag(String name) {
this.name = name;
}
/**
* Gets the name of this tag.
*
* @return The name of this tag.
*/
public final String getName() {
return this.name;
}
/**
* Gets the value of this tag.
@ -55,49 +35,19 @@ public abstract class Tag implements Cloneable {
*/
public abstract void write(DataOutput out) throws IOException;
/**
* Returns the NBT tag id of this tag type, used in I/O.
*
* @return Id of the tag this class represents
*/
public abstract int getTagId();
@Override
public abstract Tag clone();
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Tag)) {
return false;
}
Tag tag = (Tag) obj;
if(!this.getName().equals(tag.getName())) {
return false;
}
if(this.getValue() == null) {
return tag.getValue() == null;
} else if(tag.getValue() == null) {
return false;
}
if(this.getValue().getClass().isArray() && tag.getValue().getClass().isArray()) {
int length = Array.getLength(this.getValue());
if(Array.getLength(tag.getValue()) != length) {
return false;
}
for(int index = 0; index < length; index++) {
Object o = Array.get(this.getValue(), index);
Object other = Array.get(tag.getValue(), index);
if(o == null && other != null || o != null && !o.equals(other)) {
return false;
}
}
return true;
}
return this.getValue().equals(tag.getValue());
}
@Override
public String toString() {
String name = this.getName() != null && !this.getName().equals("") ? "(" + this.getName() + ")" : "";
//TODO cleanup/push down
String value = "";
if(this.getValue() != null) {
value = this.getValue().toString();
@ -117,6 +67,6 @@ public abstract class Tag implements Cloneable {
}
}
return this.getClass().getSimpleName() + name + " { " + value + " }";
return this.getClass().getSimpleName() + " { " + value + " }";
}
}

View File

@ -1,102 +0,0 @@
package com.github.steveice10.opennbt.tag.builtin.custom;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* A tag containing a double array.
*/
public class DoubleArrayTag extends Tag {
private double[] value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
*/
public DoubleArrayTag(String name) {
this(name, new double[0]);
}
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public DoubleArrayTag(String name, double[] value) {
super(name);
this.value = value;
}
@Override
public double[] getValue() {
return this.value.clone();
}
/**
* Sets the value of this tag.
*
* @param value New value of this tag.
*/
public void setValue(double[] value) {
if(value == null) {
return;
}
this.value = value.clone();
}
/**
* Gets a value in this tag's array.
*
* @param index Index of the value.
* @return The value at the given index.
*/
public double getValue(int index) {
return this.value[index];
}
/**
* Sets a value in this tag's array.
*
* @param index Index of the value.
* @param value Value to set.
*/
public void setValue(int index, double value) {
this.value[index] = value;
}
/**
* Gets the length of this tag's array.
*
* @return This tag's array length.
*/
public int length() {
return this.value.length;
}
@Override
public void read(DataInput in) throws IOException {
this.value = new double[in.readInt()];
for(int index = 0; index < this.value.length; index++) {
this.value[index] = in.readDouble();
}
}
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(this.value.length);
for(int index = 0; index < this.value.length; index++) {
out.writeDouble(this.value[index]);
}
}
@Override
public DoubleArrayTag clone() {
return new DoubleArrayTag(this.getName(), this.getValue());
}
}

View File

@ -1,102 +0,0 @@
package com.github.steveice10.opennbt.tag.builtin.custom;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* A tag containing a float array.
*/
public class FloatArrayTag extends Tag {
private float[] value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
*/
public FloatArrayTag(String name) {
this(name, new float[0]);
}
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public FloatArrayTag(String name, float[] value) {
super(name);
this.value = value;
}
@Override
public float[] getValue() {
return this.value.clone();
}
/**
* Sets the value of this tag.
*
* @param value New value of this tag.
*/
public void setValue(float[] value) {
if(value == null) {
return;
}
this.value = value.clone();
}
/**
* Gets a value in this tag's array.
*
* @param index Index of the value.
* @return The value at the given index.
*/
public float getValue(int index) {
return this.value[index];
}
/**
* Sets a value in this tag's array.
*
* @param index Index of the value.
* @param value Value to set.
*/
public void setValue(int index, float value) {
this.value[index] = value;
}
/**
* Gets the length of this tag's array.
*
* @return This tag's array length.
*/
public int length() {
return this.value.length;
}
@Override
public void read(DataInput in) throws IOException {
this.value = new float[in.readInt()];
for(int index = 0; index < this.value.length; index++) {
this.value[index] = in.readFloat();
}
}
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(this.value.length);
for(int index = 0; index < this.value.length; index++) {
out.writeFloat(this.value[index]);
}
}
@Override
public FloatArrayTag clone() {
return new FloatArrayTag(this.getName(), this.getValue());
}
}

View File

@ -1,102 +0,0 @@
package com.github.steveice10.opennbt.tag.builtin.custom;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* A tag containing a short array.
*/
public class ShortArrayTag extends Tag {
private short[] value;
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
*/
public ShortArrayTag(String name) {
this(name, new short[0]);
}
/**
* Creates a tag with the specified name.
*
* @param name The name of the tag.
* @param value The value of the tag.
*/
public ShortArrayTag(String name, short[] value) {
super(name);
this.value = value;
}
@Override
public short[] getValue() {
return this.value.clone();
}
/**
* Sets the value of this tag.
*
* @param value New value of this tag.
*/
public void setValue(short[] value) {
if(value == null) {
return;
}
this.value = value.clone();
}
/**
* Gets a value in this tag's array.
*
* @param index Index of the value.
* @return The value at the given index.
*/
public short getValue(int index) {
return this.value[index];
}
/**
* Sets a value in this tag's array.
*
* @param index Index of the value.
* @param value Value to set.
*/
public void setValue(int index, short value) {
this.value[index] = value;
}
/**
* Gets the length of this tag's array.
*
* @return This tag's array length.
*/
public int length() {
return this.value.length;
}
@Override
public void read(DataInput in) throws IOException {
this.value = new short[in.readInt()];
for(int index = 0; index < this.value.length; index++) {
this.value[index] = in.readShort();
}
}
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(this.value.length);
for(int index = 0; index < this.value.length; index++) {
out.writeShort(this.value[index]);
}
}
@Override
public ShortArrayTag clone() {
return new ShortArrayTag(this.getName(), this.getValue());
}
}