Archived
0

NBT: вносим правки в библиотеку flow-nbt

В используемой версии отсутствует Tag_Long_Array
This commit is contained in:
2018-08-18 17:20:01 +03:00
parent 4404a15650
commit 51b6e5cd8c
4 changed files with 413 additions and 0 deletions

View File

@@ -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;
}
}
}

View File

@@ -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() {
}
}

View 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;
}
}

View File

@@ -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();
}
}