mirror of
https://github.com/filoghost/ChestCommands.git
synced 2024-11-23 02:25:26 +01:00
Add NBT library by Eisenwave
This commit is contained in:
parent
88e9b13741
commit
7220e1e4f8
@ -0,0 +1,58 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Byte} tag.
|
||||
*/
|
||||
public final class NBTByte extends NBTTag implements Cloneable {
|
||||
|
||||
private byte value;
|
||||
|
||||
public NBTByte(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setByteValue(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.BYTE;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTByte && equals((NBTByte) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTByte tag) {
|
||||
return this.value == tag.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Byte.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
return Byte.toUnsignedInt(value)+"b";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTByte clone() {
|
||||
return new NBTByte(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Byte_Array} tag.
|
||||
*/
|
||||
public final class NBTByteArray extends NBTTag {
|
||||
|
||||
private final byte[] value;
|
||||
|
||||
public NBTByteArray(byte[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NBTByteArray(Number[] numbers) {
|
||||
this.value = new byte[numbers.length];
|
||||
for (int i = 0; i < numbers.length; i++)
|
||||
value[i] = numbers[i].byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of this array.
|
||||
*
|
||||
* @return the length of this array
|
||||
*/
|
||||
public int length() {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.BYTE_ARRAY;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTByteArray && equals((NBTByteArray) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTByteArray tag) {
|
||||
return Arrays.equals(this.value, tag.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
StringBuilder stringbuilder = new StringBuilder("[B;");
|
||||
for (int i = 0; i < this.value.length; i++) {
|
||||
if (i != 0) {
|
||||
stringbuilder.append(',');
|
||||
}
|
||||
stringbuilder.append(this.value[i]).append('B');
|
||||
}
|
||||
return stringbuilder.append(']').toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,436 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Compound} tag.
|
||||
*/
|
||||
public final class NBTCompound extends NBTTag {
|
||||
|
||||
private static final Pattern SIMPLE_STRING = Pattern.compile("[A-Za-z0-9._+-]+");
|
||||
|
||||
private final Map<String, NBTTag> value;
|
||||
|
||||
public NBTCompound(Map<String, NBTTag> value) {
|
||||
this.value = new LinkedHashMap<String, NBTTag>(value);
|
||||
}
|
||||
|
||||
public NBTCompound() {
|
||||
this.value = new LinkedHashMap<String, NBTTag>();
|
||||
}
|
||||
|
||||
// GETTERS
|
||||
|
||||
/**
|
||||
* Returns the size of this compound.
|
||||
*
|
||||
* @return the size of this compound
|
||||
*/
|
||||
public int size() {
|
||||
return value.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, NBTTag> getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.COMPOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tag named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a byte
|
||||
* @throws NoSuchElementException if there is no tag with given name
|
||||
*/
|
||||
public NBTTag getTag(String key) {
|
||||
if (!hasKey(key)) throw new NoSuchElementException(key);
|
||||
return value.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a byte
|
||||
* @throws NoSuchElementException if there is no byte with given name
|
||||
*/
|
||||
public byte getByte(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTByte)) throw new NoSuchElementException(key);
|
||||
return ((NBTByte) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an short named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return an short
|
||||
* @throws NoSuchElementException if there is no short with given name
|
||||
*/
|
||||
public short getShort(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTShort)) throw new NoSuchElementException(key);
|
||||
return ((NBTShort) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return an int
|
||||
* @throws NoSuchElementException if there is no int with given name
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTInt)) throw new NoSuchElementException(key);
|
||||
return ((NBTInt) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an long named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return an long
|
||||
* @throws NoSuchElementException if there is no long with given name
|
||||
*/
|
||||
public long getLong(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTLong)) throw new NoSuchElementException(key);
|
||||
return ((NBTLong) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns float named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a float
|
||||
* @throws NoSuchElementException if there is no float with given name
|
||||
*/
|
||||
public float getFloat(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTFloat)) throw new NoSuchElementException(key);
|
||||
return ((NBTFloat) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a double named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a double
|
||||
* @throws NoSuchElementException if there is no int with given name
|
||||
*/
|
||||
public double getDouble(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTDouble)) throw new NoSuchElementException(key);
|
||||
return ((NBTDouble) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a byte array
|
||||
* @throws NoSuchElementException if there is no int with given name
|
||||
*/
|
||||
public byte[] getByteArray(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTByteArray)) throw new NoSuchElementException(key);
|
||||
return ((NBTByteArray) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a string
|
||||
* @throws NoSuchElementException if there is no int with given name
|
||||
*/
|
||||
public String getString(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTString)) throw new NoSuchElementException(key);
|
||||
return ((NBTString) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a list
|
||||
* @throws NoSuchElementException if there is no int with given name
|
||||
*/
|
||||
public List<NBTTag> getList(String key) {
|
||||
return getTagList(key).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a list
|
||||
* @throws NoSuchElementException if there is no list with given name
|
||||
*/
|
||||
public NBTList getTagList(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTList)) throw new NoSuchElementException(key);
|
||||
return (NBTList) tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a list
|
||||
* @throws NoSuchElementException if there is no compound with given name
|
||||
*/
|
||||
public Map<String, NBTTag> getCompound(String key) {
|
||||
return getCompoundTag(key).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a compound named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a compound
|
||||
* @throws NoSuchElementException if there is no compound with given name
|
||||
*/
|
||||
public NBTCompound getCompoundTag(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTCompound)) throw new NoSuchElementException(key);
|
||||
return (NBTCompound) tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int array named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a int array
|
||||
* @throws NoSuchElementException if there is no int array with given name
|
||||
*/
|
||||
public int[] getIntArray(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTIntArray)) throw new NoSuchElementException(key);
|
||||
return ((NBTIntArray) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a long array named with the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return a int array
|
||||
* @throws NoSuchElementException if there is no int array with given name
|
||||
*/
|
||||
public long[] getLongArray(String key) {
|
||||
NBTTag tag = value.get(key);
|
||||
if (!(tag instanceof NBTLongArray)) throw new NoSuchElementException(key);
|
||||
return ((NBTLongArray) tag).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing all the keys in this compound.
|
||||
*
|
||||
* @return an immutable set
|
||||
*/
|
||||
public Set<String> getKeys() {
|
||||
return Collections.unmodifiableSet(value.keySet());
|
||||
}
|
||||
|
||||
// PREDICATES
|
||||
|
||||
/**
|
||||
* Returns whether this compound is empty.
|
||||
*
|
||||
* @return whether this compound is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return value.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this compound tag contains the given key.
|
||||
*
|
||||
* @param key the given key
|
||||
* @return true if the tag contains the given key
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
return value.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this compound tag contains the given key and its value is of a given type.
|
||||
*
|
||||
* @param key the given key
|
||||
* @param type the type of the value
|
||||
* @return true if the tag contains an entry with given key and of given type
|
||||
*/
|
||||
public boolean hasKeyOfType(String key, NBTType type) {
|
||||
Objects.requireNonNull(type);
|
||||
return value.containsKey(key) && value.get(key).getType() == type;
|
||||
}
|
||||
|
||||
// MUTATORS
|
||||
|
||||
/**
|
||||
* Put the given name and its corresponding tag into the compound tag.
|
||||
*
|
||||
* @param name the tag name
|
||||
* @param tag the tag value
|
||||
*/
|
||||
public void put(String name, NBTTag tag) {
|
||||
this.value.put(name, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putByteArray(String key, byte[] value) {
|
||||
put(key, new NBTByteArray(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putByte(String key, byte value) {
|
||||
put(key, new NBTByte(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putDouble(String key, double value) {
|
||||
put(key, new NBTDouble(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putFloat(String key, float value) {
|
||||
put(key, new NBTFloat(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putIntArray(String key, int[] value) {
|
||||
put(key, new NBTIntArray(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putLongArray(String key, long[] value) {
|
||||
put(key, new NBTLongArray(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the valu
|
||||
*/
|
||||
public void putInt(String key, int value) {
|
||||
put(key, new NBTInt(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putLong(String key, long value) {
|
||||
put(key, new NBTLong(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putShort(String key, short value) {
|
||||
put(key, new NBTShort(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the given key and value into the compound tag.
|
||||
*
|
||||
* @param key they key
|
||||
* @param value the value
|
||||
*/
|
||||
public void putString(String key, String value) {
|
||||
put(key, new NBTString(value));
|
||||
}
|
||||
|
||||
// ITERATION
|
||||
|
||||
/**
|
||||
* Performs an action for every pair of keys and tags.
|
||||
*
|
||||
* @param action the action
|
||||
*/
|
||||
public void forEach(BiConsumer<String, ? super NBTTag> action) {
|
||||
this.value.forEach(action);
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTCompound && equals((NBTCompound) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTCompound tag) {
|
||||
return this.isEmpty() && tag.isEmpty()
|
||||
|| this.value.equals(tag.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
StringBuilder builder = new StringBuilder("{");
|
||||
Set<String> keys = this.value.keySet();
|
||||
|
||||
for (String key : keys) {
|
||||
if (builder.length() > 1) {
|
||||
builder.append(',');
|
||||
}
|
||||
builder
|
||||
.append(SIMPLE_STRING.matcher(key).matches()? key : NBTString.toMSONString(key))
|
||||
.append(':')
|
||||
.append(this.value.get(key).toMSONString());
|
||||
}
|
||||
|
||||
return builder.append("}").toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Double} tag.
|
||||
*
|
||||
*/
|
||||
public final class NBTDouble extends NBTTag implements Cloneable {
|
||||
|
||||
private double value;
|
||||
|
||||
public NBTDouble(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public double getDoubleValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setDoubleValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.DOUBLE;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTDouble && equals((NBTDouble) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTDouble tag) {
|
||||
return this.value == tag.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Double.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
return value+"d";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDouble clone() {
|
||||
return new NBTDouble(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Float} tag.
|
||||
*/
|
||||
public final class NBTFloat extends NBTTag implements Cloneable {
|
||||
|
||||
private float value;
|
||||
|
||||
public NBTFloat(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public float getFloatValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setFloatValue(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.FLOAT;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTFloat && equals((NBTFloat) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTFloat tag) {
|
||||
return this.value == tag.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Float.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
return value+"f";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTFloat clone() {
|
||||
return new NBTFloat(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Int} tag.
|
||||
*/
|
||||
public final class NBTInt extends NBTTag implements Cloneable {
|
||||
|
||||
private int value;
|
||||
|
||||
public NBTInt(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setIntValue(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.INT;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTInt && equals((NBTInt) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTInt tag) {
|
||||
return this.value == tag.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Integer.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTInt clone() {
|
||||
return new NBTInt(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Int_Array} tag.
|
||||
*/
|
||||
public final class NBTIntArray extends NBTTag implements Cloneable {
|
||||
|
||||
private final int[] value;
|
||||
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public NBTIntArray(int[] value) {
|
||||
this.value = Objects.requireNonNull(value);
|
||||
}
|
||||
|
||||
public NBTIntArray(Number[] numbers) {
|
||||
this.value = new int[numbers.length];
|
||||
for (int i = 0; i < numbers.length; i++)
|
||||
value[i] = numbers[i].intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of this array.
|
||||
*
|
||||
* @return the length of this array
|
||||
*/
|
||||
public int length() {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.INT_ARRAY;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTIntArray && equals((NBTIntArray) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTIntArray tag) {
|
||||
return Arrays.equals(this.value, tag.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
StringBuilder stringbuilder = new StringBuilder("[I;");
|
||||
for (int i = 0; i < this.value.length; i++) {
|
||||
if (i != 0) {
|
||||
stringbuilder.append(',');
|
||||
}
|
||||
stringbuilder.append(this.value[i]);
|
||||
}
|
||||
return stringbuilder.append(']').toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTIntArray clone() {
|
||||
return new NBTIntArray(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The {@code TAG_List} tag.
|
||||
*/
|
||||
public final class NBTList extends NBTTag implements Iterable<NBTTag>, Cloneable {
|
||||
|
||||
private NBTType type;
|
||||
|
||||
private final List<NBTTag> list = new ArrayList<NBTTag>();
|
||||
|
||||
/**
|
||||
* Creates the list with a type and a series of elements.
|
||||
*
|
||||
* @param type the type of tag
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public NBTList(NBTType type, List<? extends NBTTag> value) {
|
||||
this.type = type;
|
||||
for (NBTTag entry : value) {
|
||||
this.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the list with a type and a series of elements.
|
||||
*
|
||||
* @param type the type of tag
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public NBTList(NBTType type, NBTTag... value) {
|
||||
this(type, Arrays.asList(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty list with a type.
|
||||
*
|
||||
* @param type the type of tag or null if the list has no type yet
|
||||
*/
|
||||
public NBTList(NBTType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty list without a type.
|
||||
*/
|
||||
public NBTList() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
// GETTERS
|
||||
|
||||
/**
|
||||
* Returns the size of this list.
|
||||
*
|
||||
* @return the size of this list
|
||||
*/
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NBTTag> getValue() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.LIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of elements in this list.
|
||||
*
|
||||
* @return The type of elements in this list.
|
||||
*/
|
||||
public NBTType getElementType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tag named with the given index.
|
||||
*
|
||||
* @param index the index
|
||||
* @return a byte
|
||||
* @throws NoSuchElementException if there is no tag with given index
|
||||
*/
|
||||
public NBTTag get(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
// PREDICATES
|
||||
|
||||
/**
|
||||
* Returns whether this list is empty.
|
||||
*
|
||||
* @return whether this list is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
// MUTATORS
|
||||
|
||||
/**
|
||||
* Add the given tag.
|
||||
*
|
||||
* @param value the tag
|
||||
*/
|
||||
public void add(NBTTag value) {
|
||||
if (this.type == null)
|
||||
this.type = value.getType();
|
||||
else if (this.type != value.getType())
|
||||
throw new IllegalArgumentException(value.getType() + " is not of expected type " + type);
|
||||
list.add(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given tag at the given index in the list.
|
||||
*
|
||||
* @param value the tag
|
||||
*/
|
||||
public void add(int index, NBTTag value) {
|
||||
if (index < 0 || index >= list.size())
|
||||
throw new IndexOutOfBoundsException(Integer.toString(index));
|
||||
if (this.type == null)
|
||||
this.type = value.getType();
|
||||
else if (this.type != value.getType())
|
||||
throw new IllegalArgumentException(value.getType() + " is not of expected type " + type);
|
||||
list.add(index, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all the tags in the given list.
|
||||
*
|
||||
* @param values a list of tags
|
||||
*/
|
||||
public void addAll(Collection<? extends NBTTag> values) {
|
||||
for (NBTTag entry : values) {
|
||||
this.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTList && equals((NBTList) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTList tag) {
|
||||
return this.isEmpty() && tag.isEmpty()
|
||||
|| this.type == tag.type && this.list.equals(tag.list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<NBTTag> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
StringBuilder builder = new StringBuilder("[");
|
||||
Iterator<NBTTag> iter = iterator();
|
||||
|
||||
boolean first = true;
|
||||
while (iter.hasNext()) {
|
||||
if (first) first = false;
|
||||
else builder.append(',');
|
||||
builder.append(iter.next().toMSONString());
|
||||
}
|
||||
|
||||
return builder.append("]").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTList clone() {
|
||||
return new NBTList(type, list);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Long} tag.
|
||||
*/
|
||||
public final class NBTLong extends NBTTag implements Cloneable {
|
||||
|
||||
private long value;
|
||||
|
||||
public NBTLong(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public long getLongValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setLongValue(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.LONG;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTLong && equals((NBTLong) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTLong tag) {
|
||||
return this.value == tag.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
return value+"L";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTLong clone() {
|
||||
return new NBTLong(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Long_Array} tag.
|
||||
*/
|
||||
public final class NBTLongArray extends NBTTag {
|
||||
|
||||
private final long[] value;
|
||||
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public NBTLongArray(long... value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NBTLongArray(Number[] numbers) {
|
||||
this.value = new long[numbers.length];
|
||||
for (int i = 0; i < numbers.length; i++)
|
||||
value[i] = numbers[i].longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of this array.
|
||||
*
|
||||
* @return the length of this array
|
||||
*/
|
||||
public int length() {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.LONG_ARRAY;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTLongArray && equals((NBTLongArray) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTLongArray tag) {
|
||||
return Arrays.equals(this.value, tag.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
StringBuilder stringbuilder = new StringBuilder("[I;");
|
||||
for (int i = 0; i < this.value.length; i++) {
|
||||
if (i != 0) {
|
||||
stringbuilder.append(',');
|
||||
}
|
||||
stringbuilder.append(this.value[i]);
|
||||
}
|
||||
return stringbuilder.append(']').toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Short} tag.
|
||||
*/
|
||||
public final class NBTShort extends NBTTag implements Cloneable {
|
||||
|
||||
private short value;
|
||||
|
||||
public NBTShort(short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public short getShortValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setShortValue(short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.SHORT;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof NBTShort && equals((NBTShort) obj);
|
||||
}
|
||||
|
||||
public boolean equals(NBTShort tag) {
|
||||
return this.value == tag.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Short.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
return value+"s";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTShort clone() {
|
||||
return new NBTShort(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* The {@code TAG_String} tag.
|
||||
*/
|
||||
public final class NBTString extends NBTTag implements Cloneable {
|
||||
|
||||
private String value;
|
||||
|
||||
public NBTString(String value) {
|
||||
setValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType getType() {
|
||||
return NBTType.STRING;
|
||||
}
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMSONString() {
|
||||
return toMSONString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTString clone() {
|
||||
return new NBTString(value);
|
||||
}
|
||||
|
||||
// UTIL
|
||||
|
||||
/**
|
||||
* Converts a regular string into a Mojangson string by surrounding it with quotes and escaping backslashes and
|
||||
* quotes inside it.
|
||||
*
|
||||
* @param str the string
|
||||
* @return the Mojangson string
|
||||
*/
|
||||
public static String toMSONString(String str) {
|
||||
StringBuilder builder = new StringBuilder("\"");
|
||||
char[] chars = str.toCharArray();
|
||||
for (char c : chars) {
|
||||
if ((c == '\\') || (c == '"')) {
|
||||
builder.append('\\');
|
||||
}
|
||||
builder.append(c);
|
||||
}
|
||||
return builder.append('\"').toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* An abstract NBT-Tag.
|
||||
*/
|
||||
public abstract class NBTTag {
|
||||
|
||||
/**
|
||||
* Gets the value of this tag.
|
||||
*
|
||||
* @return the value of this tag
|
||||
*/
|
||||
public abstract Object getValue();
|
||||
|
||||
/**
|
||||
* Returns the type of this tag.
|
||||
*
|
||||
* @return the type of this tag
|
||||
*/
|
||||
public abstract NBTType getType();
|
||||
|
||||
/**
|
||||
* Convenience method for getting the id of this tag's type.
|
||||
*
|
||||
* @return the type id
|
||||
*/
|
||||
public byte getTypeId() {
|
||||
return getType().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Mojangson string depicting this NBT tag.
|
||||
*
|
||||
* @return a Mojangson string depicting this NBT tag
|
||||
*/
|
||||
public abstract String toMSONString();
|
||||
|
||||
// MISC
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof NBTTag) {
|
||||
NBTTag tag = (NBTTag) obj;
|
||||
return this.getType() == tag.getType()
|
||||
&& this.getValue().equals(tag.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getValue().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toMSONString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The type of an NBTTag.
|
||||
* </p>
|
||||
* <p>
|
||||
* This enum may be prone to further additions, such as the {@link #LONG_ARRAY} which has been added by Mojang
|
||||
* in NBT Version 19133. (second NBT version)
|
||||
* </p>
|
||||
* <p>
|
||||
* For a community maintained documentation of the NBT format and its types, visit the
|
||||
* <a href=https://minecraft.gamepedia.com/NBT_format>Minecraft Wiki</a>
|
||||
* </p>
|
||||
*/
|
||||
public enum NBTType {
|
||||
/**
|
||||
* Used to mark the end of compounds tags. May also be the type of empty list tags.
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
END("TAG_End", false, false, false),
|
||||
|
||||
/**
|
||||
* A signed integer (8 bits). Sometimes used for booleans. (-128 to 127)
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
BYTE("TAG_Byte", true, true, false),
|
||||
|
||||
/**
|
||||
* A signed integer (16 bits). (-2<sup>15</sup> to 2<sup>15</sup>-1)
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
SHORT("TAG_Short", true, true, false),
|
||||
|
||||
/**
|
||||
* A signed integer (32 bits). (-2<sup>31</sup> to 2<sup>31</sup>-1)
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
INT("TAG_Int", true, true, false),
|
||||
|
||||
/**
|
||||
* A signed integer (64 bits). (-2<sup>63</sup> to 2<sup>63</sup>-1)
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
LONG("TAG_Long", true, true, false),
|
||||
|
||||
/**
|
||||
* A signed (IEEE 754-2008) floating point number (32 bits).
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
FLOAT("TAG_Float", true, true, false),
|
||||
|
||||
/**
|
||||
* A signed (IEEE 754-2008) floating point number (64 bits).
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
DOUBLE("TAG_Double", true, true, false),
|
||||
|
||||
/**
|
||||
* An array of {@link #BYTE} with maximum length of {@link Integer#MAX_VALUE}.
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
BYTE_ARRAY("TAG_Byte_Array", false, false, true),
|
||||
|
||||
/**
|
||||
* UTF-8 encoded string.
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
STRING("TAG_String", true, false, false),
|
||||
|
||||
/**
|
||||
* A list of unnamed tags of equal type.
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
LIST("TAG_List", false, false, false),
|
||||
|
||||
/**
|
||||
* Compound of named tags followed by {@link #END}.
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
COMPOUND("TAG_Compound", false, false, false),
|
||||
|
||||
/**
|
||||
* An array of {@link #BYTE} with maximum length of {@link Integer#MAX_VALUE}.
|
||||
* @since NBT Version 19132
|
||||
*/
|
||||
INT_ARRAY("TAG_Int_Array", false, false, true),
|
||||
|
||||
/**
|
||||
* An array of {@link #LONG} with maximum length of {@link Integer#MAX_VALUE}.
|
||||
* @since NBT Version 19133
|
||||
*/
|
||||
LONG_ARRAY("TAG_Long_Array", false, false, true);
|
||||
|
||||
private final String name;
|
||||
private final boolean numeric, primitive, array;
|
||||
private final byte id;
|
||||
|
||||
NBTType(String name, boolean primitive, boolean numeric, boolean array) {
|
||||
this.name = name;
|
||||
this.id = (byte) ordinal();
|
||||
this.numeric = numeric;
|
||||
this.primitive = primitive;
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type with the given id.
|
||||
*
|
||||
* @param id the id
|
||||
* @return the type
|
||||
*/
|
||||
public static NBTType getById(byte id) {
|
||||
return values()[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the id of this tag type.
|
||||
* </p>
|
||||
* <p>
|
||||
* Although this method is currently equivalent to {@link #ordinal()}, it should always be used in its stead,
|
||||
* since it is not guaranteed that this behavior will remain consistent.
|
||||
* </p>
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public byte getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this type.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns whether this tag type is numeric.
|
||||
* </p>
|
||||
* <p>
|
||||
* All tag types with payloads that are representable as a {@link Number} are compliant with this definition.
|
||||
* </p>
|
||||
*
|
||||
* @return whether this type is numeric
|
||||
*/
|
||||
public boolean isNumeric() {
|
||||
return numeric;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this tag type is primitive, meaning that it is not a {@link NBTByteArray}, {@link NBTIntArray},
|
||||
* {@link NBTList}, {@link NBTCompound} or {@link NBTEnd}.
|
||||
*
|
||||
* @return whether this type is numeric
|
||||
*/
|
||||
public boolean isPrimitive() {
|
||||
return primitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this tag type is is an array type such as {@link NBTByteArray} or {@link NBTIntArray}.
|
||||
*
|
||||
* @return whether this type is an array type
|
||||
*/
|
||||
public boolean isArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class MojangsonParseException extends IOException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public MojangsonParseException(String msg, String content, int index) {
|
||||
super(msg + " at character " + index + ": " + printErrorLoc(content, index));
|
||||
}
|
||||
|
||||
private static String printErrorLoc(String content, int index) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int i = Math.min(content.length(), index);
|
||||
if (i > 35) {
|
||||
builder.append("...");
|
||||
}
|
||||
builder.append(content.substring(Math.max(0, i - 35), i));
|
||||
builder.append(ChatColor.GOLD + "<--[HERE]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,364 @@
|
||||
package com.gmail.filoghost.chestcommands.util.nbt.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.gmail.filoghost.chestcommands.util.nbt.*;
|
||||
|
||||
public final class MojangsonParser {
|
||||
|
||||
private static final Pattern
|
||||
DOUBLE_NS = Pattern.compile("[-+]?(?:[0-9]+[.]|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?", Pattern.CASE_INSENSITIVE),
|
||||
DOUBLE_S = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", Pattern.CASE_INSENSITIVE),
|
||||
FLOAT = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?f", Pattern.CASE_INSENSITIVE),
|
||||
BYTE = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)b", Pattern.CASE_INSENSITIVE),
|
||||
LONG = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)l", Pattern.CASE_INSENSITIVE),
|
||||
SHORT = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)s", Pattern.CASE_INSENSITIVE),
|
||||
INT = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)");
|
||||
|
||||
|
||||
private final String str;
|
||||
private int index;
|
||||
|
||||
public static NBTCompound parse(String mson) throws MojangsonParseException {
|
||||
return new MojangsonParser(mson).parseRootCompound();
|
||||
}
|
||||
|
||||
private MojangsonParser(String str) {
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
// PARSE
|
||||
|
||||
private NBTCompound parseRootCompound() throws MojangsonParseException {
|
||||
skipWhitespace();
|
||||
NBTCompound result = parseCompound();
|
||||
expectNoTrail();
|
||||
return result;
|
||||
}
|
||||
|
||||
private String parseCompoundKey() throws MojangsonParseException {
|
||||
skipWhitespace();
|
||||
if (!hasNext()) {
|
||||
throw parseException("Expected key");
|
||||
}
|
||||
return currentChar() == '"' ? parseQuotedString() : parseSimpleString();
|
||||
}
|
||||
|
||||
private NBTTag parseStringOrLiteral() throws MojangsonParseException {
|
||||
skipWhitespace();
|
||||
if (currentChar() == '"')
|
||||
return new NBTString(parseQuotedString());
|
||||
String str = parseSimpleString();
|
||||
if (str.isEmpty())
|
||||
throw parseException("Expected value");
|
||||
return parseLiteral(str);
|
||||
}
|
||||
|
||||
private NBTTag parseLiteral(String str) {
|
||||
try {
|
||||
if (FLOAT.matcher(str).matches()) {
|
||||
return new NBTFloat(Float.parseFloat(str.substring(0, str.length() - 1)));
|
||||
}
|
||||
if (BYTE.matcher(str).matches()) {
|
||||
return new NBTByte(Byte.parseByte(str.substring(0, str.length() - 1)));
|
||||
}
|
||||
if (LONG.matcher(str).matches()) {
|
||||
return new NBTLong(Long.parseLong(str.substring(0, str.length() - 1)));
|
||||
}
|
||||
if (SHORT.matcher(str).matches()) {
|
||||
return new NBTShort(Short.parseShort(str.substring(0, str.length() - 1)));
|
||||
}
|
||||
if (INT.matcher(str).matches()) {
|
||||
return new NBTInt(Integer.parseInt(str));
|
||||
}
|
||||
if (DOUBLE_S.matcher(str).matches()) {
|
||||
return new NBTDouble(Double.parseDouble(str.substring(0, str.length() - 1)));
|
||||
}
|
||||
if (DOUBLE_NS.matcher(str).matches()) {
|
||||
return new NBTDouble(Double.parseDouble(str));
|
||||
}
|
||||
if ("true".equalsIgnoreCase(str)) {
|
||||
return new NBTByte((byte)1);
|
||||
}
|
||||
if ("false".equalsIgnoreCase(str)) {
|
||||
return new NBTByte((byte)0);
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
return new NBTString(str);
|
||||
}
|
||||
return new NBTString(str);
|
||||
}
|
||||
|
||||
private String parseQuotedString() throws MojangsonParseException {
|
||||
int j = ++this.index;
|
||||
StringBuilder builder = null;
|
||||
boolean escape = false;
|
||||
|
||||
while (hasNext()) {
|
||||
char c = nextChar();
|
||||
if (escape) {
|
||||
if ((c != '\\') && (c != '"')) {
|
||||
throw parseException("Invalid escape of '" + c + "'");
|
||||
}
|
||||
escape = false;
|
||||
}
|
||||
else {
|
||||
if (c == '\\') {
|
||||
escape = true;
|
||||
if (builder != null) {
|
||||
continue;
|
||||
}
|
||||
builder = new StringBuilder(this.str.substring(j, this.index - 1)); continue;
|
||||
}
|
||||
if (c == '"') {
|
||||
return builder == null ? this.str.substring(j, this.index - 1) : builder.toString();
|
||||
}
|
||||
}
|
||||
if (builder != null) {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
throw parseException("Missing termination quote");
|
||||
}
|
||||
|
||||
private String parseSimpleString() {
|
||||
int j = this.index;
|
||||
while (hasNext() && isSimpleChar(currentChar())) {
|
||||
this.index += 1;
|
||||
}
|
||||
return this.str.substring(j, this.index);
|
||||
}
|
||||
|
||||
private NBTTag parseAnything() throws MojangsonParseException {
|
||||
skipWhitespace();
|
||||
if (!hasNext())
|
||||
throw parseException("Expected value");
|
||||
|
||||
int c = currentChar();
|
||||
if (c == '{')
|
||||
return parseCompound();
|
||||
else if (c == '[')
|
||||
return parseDetectedArray();
|
||||
else
|
||||
return parseStringOrLiteral();
|
||||
}
|
||||
|
||||
private NBTTag parseDetectedArray() throws MojangsonParseException {
|
||||
if (hasCharsLeft(2) && getChar(1) != '"' && getChar(2) == ';') {
|
||||
return parseNumArray();
|
||||
}
|
||||
return parseList();
|
||||
}
|
||||
|
||||
private NBTCompound parseCompound() throws MojangsonParseException {
|
||||
expectChar('{');
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
|
||||
skipWhitespace();
|
||||
while ((hasNext()) && (currentChar() != '}'))
|
||||
{
|
||||
String str = parseCompoundKey();
|
||||
if (str.isEmpty()) {
|
||||
throw parseException("Expected non-empty key");
|
||||
}
|
||||
expectChar(':');
|
||||
|
||||
compound.put(str, parseAnything());
|
||||
if (!advanceToNextArrayElement()) {
|
||||
break;
|
||||
}
|
||||
if (!hasNext()) {
|
||||
throw parseException("Expected key");
|
||||
}
|
||||
}
|
||||
expectChar('}');
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
private NBTList parseList() throws MojangsonParseException {
|
||||
expectChar('[');
|
||||
|
||||
skipWhitespace();
|
||||
if (!hasNext()) {
|
||||
throw parseException("Expected value");
|
||||
}
|
||||
NBTList list = new NBTList();
|
||||
NBTType listType = null;
|
||||
|
||||
while (currentChar() != ']') {
|
||||
NBTTag element = parseAnything();
|
||||
NBTType elementType = element.getType();
|
||||
|
||||
if (listType == null) {
|
||||
listType = elementType;
|
||||
} else if (elementType != listType) {
|
||||
throw parseException("Unable to insert " + elementType + " into ListTag of type " + listType);
|
||||
}
|
||||
list.add(element);
|
||||
if (!advanceToNextArrayElement()) {
|
||||
break;
|
||||
}
|
||||
if (!hasNext()) {
|
||||
throw parseException("Expected value");
|
||||
}
|
||||
}
|
||||
expectChar(']');
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private NBTTag parseNumArray() throws MojangsonParseException {
|
||||
expectChar('[');
|
||||
char arrayType = nextChar();
|
||||
expectChar(';');
|
||||
//nextChar(); semicolon ignored by Mojang
|
||||
|
||||
skipWhitespace();
|
||||
if (!hasNext()) {
|
||||
throw parseException("Expected value");
|
||||
}
|
||||
if (arrayType == 'B')
|
||||
return new NBTByteArray(parseNumArray(NBTType.BYTE_ARRAY, NBTType.BYTE));
|
||||
else if (arrayType == 'L')
|
||||
return new NBTLongArray(parseNumArray(NBTType.LONG_ARRAY, NBTType.LONG));
|
||||
else if (arrayType == 'I')
|
||||
return new NBTIntArray(parseNumArray(NBTType.INT_ARRAY, NBTType.INT));
|
||||
throw parseException("Invalid array type '" + arrayType + "' found");
|
||||
}
|
||||
|
||||
private Number[] parseNumArray(NBTType arrayType, NBTType primType) throws MojangsonParseException {
|
||||
List<Number> result = new ArrayList<Number>();
|
||||
while (currentChar() != ']') {
|
||||
NBTTag element = parseAnything();
|
||||
NBTType elementType = element.getType();
|
||||
|
||||
if (elementType != primType) {
|
||||
throw parseException("Unable to insert " + elementType + " into " + arrayType);
|
||||
}
|
||||
if (primType == NBTType.BYTE) {
|
||||
result.add(((NBTByte) element).getValue());
|
||||
} else if (primType == NBTType.LONG) {
|
||||
result.add(((NBTLong) element).getValue());
|
||||
} else {
|
||||
result.add(((NBTInt) element).getValue());
|
||||
}
|
||||
if (!advanceToNextArrayElement()) {
|
||||
break;
|
||||
}
|
||||
if (!hasNext()) {
|
||||
throw parseException("Expected value");
|
||||
}
|
||||
}
|
||||
expectChar(']');
|
||||
|
||||
return result.toArray(new Number[result.size()]);
|
||||
}
|
||||
|
||||
// CHARACTER NAVIGATION
|
||||
|
||||
private boolean advanceToNextArrayElement() {
|
||||
skipWhitespace();
|
||||
if (hasNext() && currentChar() == ',') {
|
||||
this.index += 1;
|
||||
skipWhitespace();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void skipWhitespace() {
|
||||
while (hasNext() && Character.isWhitespace(currentChar())) {
|
||||
this.index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasCharsLeft(int paramInt) {
|
||||
return this.index + paramInt < this.str.length();
|
||||
}
|
||||
|
||||
private boolean hasNext() {
|
||||
return hasCharsLeft(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character in the string at the current index plus a given offset.
|
||||
*
|
||||
* @param offset the offset
|
||||
* @return the character at the offset
|
||||
*/
|
||||
private char getChar(int offset) {
|
||||
return this.str.charAt(this.index + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current character.
|
||||
*
|
||||
* @return the current character
|
||||
*/
|
||||
private char currentChar() {
|
||||
return getChar(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current character and increments the index.
|
||||
*
|
||||
* @return the current character
|
||||
*/
|
||||
private char nextChar() {
|
||||
return this.str.charAt(this.index++);
|
||||
}
|
||||
|
||||
// UTIL
|
||||
|
||||
/**
|
||||
* Verifies whether the current character is of given value and whether the parser can advance. If these conditions
|
||||
* are met, the parser advances by one. If these conditions are not met, an exception is thrown.
|
||||
*
|
||||
* @param c the expected character
|
||||
* @throws MojangsonParseException if {@link #currentChar()} does not equal {@code c} or if {@link #hasNext()}
|
||||
* returns false
|
||||
*/
|
||||
private void expectChar(char c) throws MojangsonParseException {
|
||||
skipWhitespace();
|
||||
|
||||
boolean hasNext = hasNext();
|
||||
if (hasNext && currentChar() == c) {
|
||||
this.index += 1;
|
||||
return;
|
||||
}
|
||||
throw new MojangsonParseException("Expected '" + c + "' but got '" + (hasNext ? Character.valueOf(currentChar()) : "<End of string>") + "'", this.str, this.index + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the string has ended or that all characters from the next character on only consists of whitespace.
|
||||
*
|
||||
* @throws MojangsonParseException if the following characters contain a non-whitespace character
|
||||
*/
|
||||
private void expectNoTrail() throws MojangsonParseException {
|
||||
skipWhitespace();
|
||||
if (hasNext()) {
|
||||
this.index++;
|
||||
throw parseException("Trailing data found");
|
||||
}
|
||||
}
|
||||
|
||||
private MojangsonParseException parseException(String paramString) {
|
||||
return new MojangsonParseException(paramString, this.str, this.index);
|
||||
}
|
||||
|
||||
private static boolean isSimpleChar(char paramChar) {
|
||||
return (paramChar >= '0' && paramChar <= '9')
|
||||
|| (paramChar >= 'A' && paramChar <= 'Z')
|
||||
|| (paramChar >= 'a' && paramChar <= 'z')
|
||||
|| paramChar == '_'
|
||||
|| paramChar == '-'
|
||||
|| paramChar == '.'
|
||||
|| paramChar == '+';
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user