blob: c14a288fde0cf9a4b913ef9e780939efde1318a6 [file] [log] [blame] [raw]
package net.querz.nbt.io;
import net.querz.io.ExceptionBiFunction;
import net.querz.io.MaxDepthIO;
import net.querz.nbt.tag.ByteArrayTag;
import net.querz.nbt.tag.ByteTag;
import net.querz.nbt.tag.CompoundTag;
import net.querz.nbt.tag.DoubleTag;
import net.querz.nbt.tag.EndTag;
import net.querz.nbt.tag.FloatTag;
import net.querz.nbt.tag.IntArrayTag;
import net.querz.nbt.tag.IntTag;
import net.querz.nbt.tag.ListTag;
import net.querz.nbt.tag.LongArrayTag;
import net.querz.nbt.tag.LongTag;
import net.querz.nbt.tag.ShortTag;
import net.querz.nbt.tag.StringTag;
import net.querz.nbt.tag.Tag;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class NBTInputStream extends DataInputStream implements MaxDepthIO {
private static Map<Byte, ExceptionBiFunction<NBTInputStream, Integer, ? extends Tag<?>, IOException>> readers = new HashMap<>();
private static Map<Byte, Class<?>> idClassMapping = new HashMap<>();
static {
put(EndTag.ID, (i, d) -> EndTag.INSTANCE, EndTag.class);
put(ByteTag.ID, (i, d) -> readByte(i), ByteTag.class);
put(ShortTag.ID, (i, d) -> readShort(i), ShortTag.class);
put(IntTag.ID, (i, d) -> readInt(i), IntTag.class);
put(LongTag.ID, (i, d) -> readLong(i), LongTag.class);
put(FloatTag.ID, (i, d) -> readFloat(i), FloatTag.class);
put(DoubleTag.ID, (i, d) -> readDouble(i), DoubleTag.class);
put(ByteArrayTag.ID, (i, d) -> readByteArray(i), ByteArrayTag.class);
put(StringTag.ID, (i, d) -> readString(i), StringTag.class);
put(ListTag.ID, NBTInputStream::readListTag, ListTag.class);
put(CompoundTag.ID, NBTInputStream::readCompound, CompoundTag.class);
put(IntArrayTag.ID, (i, d) -> readIntArray(i), IntArrayTag.class);
put(LongArrayTag.ID, (i, d) -> readLongArray(i), LongArrayTag.class);
}
private static void put(byte id, ExceptionBiFunction<NBTInputStream, Integer, ? extends Tag<?>, IOException> reader, Class<?> clazz) {
readers.put(id, reader);
idClassMapping.put(id, clazz);
}
public NBTInputStream(InputStream in) {
super(in);
}
public NamedTag readTag(int maxDepth) throws IOException {
byte id = readByte();
return new NamedTag(readUTF(), readTag(id, maxDepth));
}
public Tag<?> readRawTag(int maxDepth) throws IOException {
byte id = readByte();
return readTag(id, maxDepth);
}
private Tag<?> readTag(byte type, int maxDepth) throws IOException {
ExceptionBiFunction<NBTInputStream, Integer, ? extends Tag<?>, IOException> f;
if ((f = readers.get(type)) == null) {
throw new IOException("invalid tag id \"" + type + "\"");
}
return f.accept(this, maxDepth);
}
static <T extends Tag<?>> void registerCustomTag(byte id, ExceptionBiFunction<NBTInputStream, Integer, T, IOException> f) {
if (readers.containsKey(id)) {
throw new IllegalArgumentException("custom tag already registered");
}
readers.put(id, f);
}
static void unregisterCustomTag(byte id) {
readers.remove(id);
}
private static ByteTag readByte(NBTInputStream in) throws IOException {
return new ByteTag(in.readByte());
}
private static ShortTag readShort(NBTInputStream in) throws IOException {
return new ShortTag(in.readShort());
}
private static IntTag readInt(NBTInputStream in) throws IOException {
return new IntTag(in.readInt());
}
private static LongTag readLong(NBTInputStream in) throws IOException {
return new LongTag(in.readLong());
}
private static FloatTag readFloat(NBTInputStream in) throws IOException {
return new FloatTag(in.readFloat());
}
private static DoubleTag readDouble(NBTInputStream in) throws IOException {
return new DoubleTag(in.readDouble());
}
private static StringTag readString(NBTInputStream in) throws IOException {
return new StringTag(in.readUTF());
}
private static ByteArrayTag readByteArray(NBTInputStream in) throws IOException {
ByteArrayTag bat = new ByteArrayTag(new byte[in.readInt()]);
in.readFully(bat.getValue());
return bat;
}
private static IntArrayTag readIntArray(NBTInputStream in) throws IOException {
IntArrayTag iat = new IntArrayTag(new int[in.readInt()]);
for (int i = 0; i < iat.length(); i++) {
iat.getValue()[i] = in.readInt();
}
return iat;
}
private static LongArrayTag readLongArray(NBTInputStream in) throws IOException {
LongArrayTag iat = new LongArrayTag(new long[in.readInt()]);
for (int i = 0; i < iat.length(); i++) {
iat.getValue()[i] = in.readLong();
}
return iat;
}
private static ListTag<?> readListTag(NBTInputStream in, int maxDepth) throws IOException {
byte listType = in.readByte();
ListTag<?> list = ListTag.createUnchecked(idClassMapping.get(listType));
int length = in.readInt();
if (length < 0) {
length = 0;
}
for (int i = 0; i < length; i++) {
list.addUnchecked(in.readTag(listType, in.decrementMaxDepth(maxDepth)));
}
return list;
}
private static CompoundTag readCompound(NBTInputStream in, int maxDepth) throws IOException {
CompoundTag comp = new CompoundTag();
for (int id = in.readByte() & 0xFF; id != 0; id = in.readByte() & 0xFF) {
String key = in.readUTF();
Tag<?> element = in.readTag((byte) id, in.decrementMaxDepth(maxDepth));
comp.put(key, element);
}
return comp;
}
}