NBT: вносим правки в библиотеку flow-nbt
В используемой версии отсутствует Tag_Long_Array
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package com.flowpowered.nbt;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class LongArrayTag extends Tag<long[]> {
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private final long[] value;
|
||||
|
||||
/**
|
||||
* Creates the tag.
|
||||
*
|
||||
* @param name The name.
|
||||
* @param value The value.
|
||||
*/
|
||||
public LongArrayTag(String name, long[] value) {
|
||||
super(TagType.TAG_LONG_ARRAY, name);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder hex = new StringBuilder();
|
||||
for (long s : value) {
|
||||
String hexDigits = Long.toHexString(s).toUpperCase();
|
||||
if (hexDigits.length() == 1) {
|
||||
hex.append("0");
|
||||
}
|
||||
hex.append(hexDigits).append(" ");
|
||||
}
|
||||
|
||||
String name = getName();
|
||||
String append = "";
|
||||
if (name != null && !name.equals("")) {
|
||||
append = "(\"" + this.getName() + "\")";
|
||||
}
|
||||
return "TAG_Long_Array" + append + ": " + hex.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongArrayTag clone() {
|
||||
long[] clonedArray = cloneArray(value);
|
||||
|
||||
return new LongArrayTag(getName(), clonedArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof IntArrayTag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LongArrayTag tag = (LongArrayTag) other;
|
||||
return Arrays.equals(value, tag.value) && getName().equals(tag.getName());
|
||||
}
|
||||
|
||||
private long[] cloneArray(long[] longArray) {
|
||||
if (longArray == null) {
|
||||
return null;
|
||||
} else {
|
||||
int length = longArray.length;
|
||||
byte[] newArray = new byte[length];
|
||||
System.arraycopy(longArray, 0, newArray, 0, length);
|
||||
return longArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.flowpowered.nbt;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* A class which holds constant values.
|
||||
*/
|
||||
public final class NBTConstants {
|
||||
/**
|
||||
* The character set used by NBT (UTF-8).
|
||||
*/
|
||||
public static final Charset CHARSET = Charset.forName("UTF-8");
|
||||
/**
|
||||
* Tag type constants.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int TYPE_END = TagType.TAG_END.getId(),
|
||||
TYPE_BYTE = TagType.TAG_BYTE.getId(),
|
||||
TYPE_SHORT = TagType.TAG_SHORT.getId(),
|
||||
TYPE_INT = TagType.TAG_INT.getId(),
|
||||
TYPE_LONG = TagType.TAG_LONG.getId(),
|
||||
TYPE_FLOAT = TagType.TAG_FLOAT.getId(),
|
||||
TYPE_DOUBLE = TagType.TAG_DOUBLE.getId(),
|
||||
TYPE_BYTE_ARRAY = TagType.TAG_BYTE_ARRAY.getId(),
|
||||
TYPE_STRING = TagType.TAG_STRING.getId(),
|
||||
TYPE_LIST = TagType.TAG_LIST.getId(),
|
||||
TYPE_COMPOUND = TagType.TAG_COMPOUND.getId(),
|
||||
TYPE_INT_ARRAY = TagType.TAG_INT_ARRAY.getId(),
|
||||
TYPE_SHORT_ARRAY = TagType.TAG_SHORT_ARRAY.getId(),
|
||||
TYPE_LONG_ARRAY = TagType.TAG_LONG_ARRAY.getId();
|
||||
|
||||
/**
|
||||
* Default private constructor.
|
||||
*/
|
||||
private NBTConstants() {
|
||||
}
|
||||
}
|
||||
|
||||
92
anvil-loader/src/main/java/com/flowpowered/nbt/TagType.java
Normal file
92
anvil-loader/src/main/java/com/flowpowered/nbt/TagType.java
Normal file
@@ -0,0 +1,92 @@
|
||||
package com.flowpowered.nbt;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum TagType {
|
||||
TAG_END(EndTag.class, "TAG_End", 0),
|
||||
TAG_BYTE(ByteTag.class, "TAG_Byte", 1),
|
||||
TAG_SHORT(ShortTag.class, "TAG_Short", 2),
|
||||
TAG_INT(IntTag.class, "TAG_Int", 3),
|
||||
TAG_LONG(LongTag.class, "TAG_Long", 4),
|
||||
TAG_FLOAT(FloatTag.class, "TAG_Float", 5),
|
||||
TAG_DOUBLE(DoubleTag.class, "TAG_Double", 6),
|
||||
TAG_BYTE_ARRAY(ByteArrayTag.class, "TAG_Byte_Array", 7),
|
||||
TAG_STRING(StringTag.class, "TAG_String", 8),
|
||||
TAG_LIST((Class) ListTag.class, "TAG_List", 9),
|
||||
// Java generics, y u so suck
|
||||
TAG_COMPOUND(CompoundTag.class, "TAG_Compound", 10),
|
||||
TAG_INT_ARRAY(IntArrayTag.class, "TAG_Int_Array", 11),
|
||||
TAG_LONG_ARRAY(LongArrayTag.class, "TAG_Long_Array", 12),
|
||||
TAG_SHORT_ARRAY(ShortArrayTag.class, "TAG_Short_Array", 100),;
|
||||
private static final Map<Class<? extends Tag<?>>, TagType> BY_CLASS = new HashMap<Class<? extends Tag<?>>, TagType>();
|
||||
private static final Map<String, TagType> BY_NAME = new HashMap<String, TagType>();
|
||||
private static final TagType[] BY_ID;
|
||||
|
||||
static {
|
||||
BY_ID = new TagType[BaseData.maxId + 1];
|
||||
for (TagType type : TagType.values()) {
|
||||
BY_CLASS.put(type.getTagClass(), type);
|
||||
BY_NAME.put(type.getTypeName(), type);
|
||||
BY_ID[type.getId()] = type;
|
||||
}
|
||||
}
|
||||
|
||||
private final Class<? extends Tag<?>> tagClass;
|
||||
private final String typeName;
|
||||
private final int id;
|
||||
|
||||
private TagType(Class<? extends Tag<?>> tagClass, String typeName, int id) {
|
||||
this.tagClass = tagClass;
|
||||
this.typeName = typeName;
|
||||
this.id = id;
|
||||
// Such a hack, shame that Java makes this such a pain
|
||||
if (this.id > BaseData.maxId) {
|
||||
BaseData.maxId = this.id;
|
||||
}
|
||||
}
|
||||
|
||||
public Class<? extends Tag<?>> getTagClass() {
|
||||
return tagClass;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static TagType getByTagClass(Class<? extends Tag<?>> clazz) {
|
||||
TagType ret = BY_CLASS.get(clazz);
|
||||
if (ret == null) {
|
||||
throw new IllegalArgumentException("Tag type " + clazz + " is unknown!");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static TagType getByTypeName(String typeName) {
|
||||
TagType ret = BY_NAME.get(typeName);
|
||||
if (ret == null) {
|
||||
throw new IllegalArgumentException("Tag type " + typeName + " is unknown!");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static TagType getById(int id) {
|
||||
if (id >= 0 && id < BY_ID.length) {
|
||||
TagType ret = BY_ID[id];
|
||||
if (ret == null) {
|
||||
throw new IllegalArgumentException("Tag type id " + id + " is unknown!");
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException("Tag type id " + id + " is out of bounds!");
|
||||
}
|
||||
}
|
||||
|
||||
private static class BaseData {
|
||||
private static int maxId = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package com.flowpowered.nbt.stream;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import com.flowpowered.nbt.*;
|
||||
|
||||
/**
|
||||
* This class reads NBT, or Named Binary Tag streams, and produces an object graph of subclasses of the {@link Tag} object. <p /> The NBT format was created by Markus Persson, and the specification
|
||||
* may be found at <a href="https://flowpowered.com/nbt/spec.txt"> https://flowpowered.com/nbt/spec.txt</a>.
|
||||
*/
|
||||
public final class NBTInputStream implements Closeable {
|
||||
/**
|
||||
* The data input stream.
|
||||
*/
|
||||
private final EndianSwitchableInputStream is;
|
||||
|
||||
/**
|
||||
* Creates a new {@link NBTInputStream}, which will source its data from the specified input stream. This assumes the stream is compressed.
|
||||
*
|
||||
* @param is The input stream.
|
||||
* @throws java.io.IOException if an I/O error occurs.
|
||||
*/
|
||||
public NBTInputStream(InputStream is) throws IOException {
|
||||
this(is, true, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link NBTInputStream}, which sources its data from the specified input stream. A flag must be passed which indicates if the stream is compressed with GZIP or not. This assumes the
|
||||
* stream uses big endian encoding.
|
||||
*
|
||||
* @param is The input stream.
|
||||
* @param compressed A flag indicating if the stream is compressed.
|
||||
* @throws java.io.IOException if an I/O error occurs.
|
||||
*/
|
||||
public NBTInputStream(InputStream is, boolean compressed) throws IOException {
|
||||
this(is, compressed, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link NBTInputStream}, which sources its data from the specified input stream. A flag must be passed which indicates if the stream is compressed with GZIP or not.
|
||||
*
|
||||
* @param is The input stream.
|
||||
* @param compressed A flag indicating if the stream is compressed.
|
||||
* @param endianness Whether to read numbers from the InputStream with little endian encoding.
|
||||
* @throws java.io.IOException if an I/O error occurs.
|
||||
*/
|
||||
public NBTInputStream(InputStream is, boolean compressed, ByteOrder endianness) throws IOException {
|
||||
this.is = new EndianSwitchableInputStream(compressed ? new GZIPInputStream(is) : is, endianness);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an NBT {@link Tag} from the stream.
|
||||
*
|
||||
* @return The tag that was read.
|
||||
* @throws java.io.IOException if an I/O error occurs.
|
||||
*/
|
||||
public Tag readTag() throws IOException {
|
||||
return readTag(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an NBT {@link Tag} from the stream.
|
||||
*
|
||||
* @param depth The depth of this tag.
|
||||
* @return The tag that was read.
|
||||
* @throws java.io.IOException if an I/O error occurs.
|
||||
*/
|
||||
private Tag readTag(int depth) throws IOException {
|
||||
int typeId = is.readByte() & 0xFF;
|
||||
TagType type = TagType.getById(typeId);
|
||||
|
||||
String name;
|
||||
if (type != TagType.TAG_END) {
|
||||
int nameLength = is.readShort() & 0xFFFF;
|
||||
byte[] nameBytes = new byte[nameLength];
|
||||
is.readFully(nameBytes);
|
||||
name = new String(nameBytes, NBTConstants.CHARSET.name());
|
||||
} else {
|
||||
name = "";
|
||||
}
|
||||
|
||||
return readTagPayload(type, name, depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the payload of a {@link Tag}, given the name and type.
|
||||
*
|
||||
* @param type The type.
|
||||
* @param name The name.
|
||||
* @param depth The depth.
|
||||
* @return The tag.
|
||||
* @throws java.io.IOException if an I/O error occurs.
|
||||
*/
|
||||
@SuppressWarnings ({"unchecked", "rawtypes"})
|
||||
private Tag readTagPayload(TagType type, String name, int depth) throws IOException {
|
||||
switch (type) {
|
||||
case TAG_END:
|
||||
if (depth == 0) {
|
||||
throw new IOException("TAG_End found without a TAG_Compound/TAG_List tag preceding it.");
|
||||
} else {
|
||||
return new EndTag();
|
||||
}
|
||||
|
||||
case TAG_BYTE:
|
||||
return new ByteTag(name, is.readByte());
|
||||
|
||||
case TAG_SHORT:
|
||||
return new ShortTag(name, is.readShort());
|
||||
|
||||
case TAG_INT:
|
||||
return new IntTag(name, is.readInt());
|
||||
|
||||
case TAG_LONG:
|
||||
return new LongTag(name, is.readLong());
|
||||
|
||||
case TAG_FLOAT:
|
||||
return new FloatTag(name, is.readFloat());
|
||||
|
||||
case TAG_DOUBLE:
|
||||
return new DoubleTag(name, is.readDouble());
|
||||
|
||||
case TAG_BYTE_ARRAY:
|
||||
int length = is.readInt();
|
||||
byte[] bytes = new byte[length];
|
||||
is.readFully(bytes);
|
||||
return new ByteArrayTag(name, bytes);
|
||||
|
||||
case TAG_STRING:
|
||||
length = is.readShort();
|
||||
bytes = new byte[length];
|
||||
is.readFully(bytes);
|
||||
return new StringTag(name, new String(bytes, NBTConstants.CHARSET.name()));
|
||||
|
||||
case TAG_LIST:
|
||||
TagType childType = TagType.getById(is.readByte());
|
||||
length = is.readInt();
|
||||
|
||||
Class<? extends Tag> clazz = childType.getTagClass();
|
||||
List<Tag> tagList = new ArrayList<Tag>(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Tag tag = readTagPayload(childType, "", depth + 1);
|
||||
if (tag instanceof EndTag) {
|
||||
throw new IOException("TAG_End not permitted in a list.");
|
||||
} else if (!clazz.isInstance(tag)) {
|
||||
throw new IOException("Mixed tag types within a list.");
|
||||
}
|
||||
tagList.add(tag);
|
||||
}
|
||||
|
||||
return new ListTag(name, clazz, tagList);
|
||||
|
||||
case TAG_COMPOUND:
|
||||
CompoundMap compoundTagList = new CompoundMap();
|
||||
while (true) {
|
||||
Tag tag = readTag(depth + 1);
|
||||
if (tag instanceof EndTag) {
|
||||
break;
|
||||
} else {
|
||||
compoundTagList.put(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return new CompoundTag(name, compoundTagList);
|
||||
|
||||
case TAG_INT_ARRAY:
|
||||
length = is.readInt();
|
||||
int[] ints = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
ints[i] = is.readInt();
|
||||
}
|
||||
return new IntArrayTag(name, ints);
|
||||
|
||||
case TAG_SHORT_ARRAY:
|
||||
length = is.readInt();
|
||||
short[] shorts = new short[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
shorts[i] = is.readShort();
|
||||
}
|
||||
return new ShortArrayTag(name, shorts);
|
||||
|
||||
case TAG_LONG_ARRAY:
|
||||
length = is.readInt();
|
||||
long[] longs = new long[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
longs[i] = is.readLong();
|
||||
}
|
||||
return new LongArrayTag(name, longs);
|
||||
|
||||
default:
|
||||
throw new IOException("Invalid tag type: " + type + ".");
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
is.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this NBTInputStream reads numbers in little-endian format.
|
||||
*/
|
||||
public ByteOrder getByteOrder() {
|
||||
return is.getEndianness();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user