331 lines
9.2 KiB
Java
331 lines
9.2 KiB
Java
package speiger.src.coreengine.utils.io.dataTag.parsing;
|
|
|
|
import java.io.IOException;
|
|
import java.util.function.Consumer;
|
|
import java.util.regex.Pattern;
|
|
|
|
import speiger.src.collections.bytes.lists.ByteArrayList;
|
|
import speiger.src.collections.bytes.lists.ByteList;
|
|
import speiger.src.collections.doubles.lists.DoubleArrayList;
|
|
import speiger.src.collections.doubles.lists.DoubleList;
|
|
import speiger.src.collections.floats.lists.FloatArrayList;
|
|
import speiger.src.collections.floats.lists.FloatList;
|
|
import speiger.src.collections.ints.lists.IntArrayList;
|
|
import speiger.src.collections.ints.lists.IntList;
|
|
import speiger.src.collections.longs.lists.LongArrayList;
|
|
import speiger.src.collections.longs.lists.LongList;
|
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
|
import speiger.src.collections.objects.lists.ObjectList;
|
|
import speiger.src.collections.shorts.lists.ShortArrayList;
|
|
import speiger.src.collections.shorts.lists.ShortList;
|
|
import speiger.src.coreengine.utils.io.dataTag.DataTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.array.ByteArrayTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.array.DoubleArrayTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.array.FloatArrayTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.array.IntArrayTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.array.LongArrayTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.array.MediumArrayTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.array.ShortArrayTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.array.StringArrayTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.ByteTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.DoubleTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.FloatTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.IntTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.LongTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.MediumTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.PrimitiveTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.ShortTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.simple.StringTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.special.ListTag;
|
|
import speiger.src.coreengine.utils.io.dataTag.special.MapTag;
|
|
import speiger.src.coreengine.utils.io.streams.StringReader;
|
|
|
|
public class DataTagParser
|
|
{
|
|
private static final Pattern BYTE_TYPE = Pattern.compile("[-+]?(?:[0-9]+)b", 2);
|
|
private static final Pattern SHORT_TYPE = Pattern.compile("[-+]?(?:[0-9]+)s", 2);
|
|
private static final Pattern MEDIUM_TYPE = Pattern.compile("[-+]?(?:[0-9]+)m", 2);
|
|
private static final Pattern INT_TYPE = Pattern.compile("[-+]?(?:[0-9]+)i", 2);
|
|
private static final Pattern INT_TYPE_DEFAULT = Pattern.compile("[-+]?(?:[0-9]+)");
|
|
private static final Pattern LONG_TYPE = Pattern.compile("[-+]?(?:[0-9]+)l", 2);
|
|
private static final Pattern FLOAT_TYPE = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?f", 2);
|
|
private static final Pattern DOUBLE_TYPE = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", 2);
|
|
private static final Pattern DOUBLE_TYPE_DEFAULT = Pattern.compile("[-+]?(?:[0-9]+[.]|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?", 2);
|
|
StringReader reader;
|
|
|
|
public DataTagParser(String s)
|
|
{
|
|
reader = new StringReader(s.replaceAll("\\§\\<(.*?)\\>", ""));
|
|
}
|
|
|
|
public DataTag readTagSave()
|
|
{
|
|
try
|
|
{
|
|
return readTag();
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public DataTag readTag() throws IOException
|
|
{
|
|
reader.skipEmpty();
|
|
if(!reader.canRead())
|
|
{
|
|
throw new IOException("Nothing to parse found");
|
|
}
|
|
else
|
|
{
|
|
char c0 = reader.peek();
|
|
if(c0 == '{')
|
|
{
|
|
return readMap();
|
|
}
|
|
else
|
|
{
|
|
return c0 == '[' ? readList() : readTagType();
|
|
}
|
|
}
|
|
}
|
|
|
|
public MapTag readMap() throws IOException
|
|
{
|
|
requirePresent('{');
|
|
reader.skipEmpty();
|
|
MapTag map = new MapTag();
|
|
while(reader.canRead() && reader.peek() != '}')
|
|
{
|
|
reader.skipEmpty();
|
|
int last = reader.getIndex();
|
|
String s = reader.readString();
|
|
if(s.isEmpty())
|
|
{
|
|
throw new IOException("Expected Key at " + last);
|
|
}
|
|
requirePresent(':');
|
|
map.putTag(s, readTag());
|
|
reader.skipEmpty();
|
|
if(!reader.isPresent(','))
|
|
{
|
|
break;
|
|
}
|
|
reader.skipEmpty();
|
|
}
|
|
requirePresent('}');
|
|
return map;
|
|
}
|
|
|
|
protected DataTag readList() throws IOException
|
|
{
|
|
return reader.canRead(3) && !StringReader.isQuoteCharacter(reader.peek(1)) && reader.peek(2) == ';' ? readArrayTag() : readListTag();
|
|
}
|
|
|
|
protected DataTag readTagType() throws IOException
|
|
{
|
|
reader.skipEmpty();
|
|
int last = reader.getIndex();
|
|
if(StringReader.isQuoteCharacter(reader.peek()))
|
|
{
|
|
return new StringTag(reader.readQuotedText());
|
|
}
|
|
else
|
|
{
|
|
String s = reader.readString();
|
|
if(s.isEmpty())
|
|
{
|
|
throw new IOException("Expected Value at " + last);
|
|
}
|
|
else
|
|
{
|
|
return tag(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
public ListTag readListTag() throws IOException
|
|
{
|
|
requirePresent('[');
|
|
reader.skipEmpty();
|
|
if(!reader.canRead())
|
|
{
|
|
throw new IOException("Expected List Data");
|
|
}
|
|
else
|
|
{
|
|
ListTag list = new ListTag();
|
|
while(reader.peek() != ']')
|
|
{
|
|
list.add(readTag());
|
|
if(!reader.isPresent(','))
|
|
{
|
|
break;
|
|
}
|
|
reader.skipEmpty();
|
|
if(!reader.canRead())
|
|
{
|
|
throw new IOException("Expected Another Element");
|
|
}
|
|
}
|
|
|
|
requirePresent(']');
|
|
return list;
|
|
}
|
|
}
|
|
|
|
protected DataTag readArrayTag() throws IOException
|
|
{
|
|
requirePresent('[');
|
|
char type = reader.pull();
|
|
reader.skip();
|
|
reader.skipEmpty();
|
|
if(!reader.canRead())
|
|
{
|
|
throw new IOException("Out of Data!");
|
|
}
|
|
else if(type == 'B')
|
|
{
|
|
ByteList list = new ByteArrayList();
|
|
readArray(T -> list.add(T.asByte()), 1, PrimitiveTag.class);
|
|
return new ByteArrayTag(list.toByteArray());
|
|
}
|
|
else if(type == 'S')
|
|
{
|
|
ShortList list = new ShortArrayList();
|
|
readArray(T -> list.add(T.asShort()), 2, PrimitiveTag.class);
|
|
return new ShortArrayTag(list.toShortArray());
|
|
}
|
|
else if(type == 'M')
|
|
{
|
|
IntList list = new IntArrayList();
|
|
readArray(T -> list.add(T.asInt()), 3, PrimitiveTag.class);
|
|
return new MediumArrayTag(list.toIntArray());
|
|
}
|
|
else if(type == 'I')
|
|
{
|
|
IntList list = new IntArrayList();
|
|
readArray(T -> list.add(T.asInt()), 4, PrimitiveTag.class);
|
|
return new IntArrayTag(list.toIntArray());
|
|
}
|
|
else if(type == 'L')
|
|
{
|
|
LongList list = new LongArrayList();
|
|
readArray(T -> list.add(T.asLong()), 5, PrimitiveTag.class);
|
|
return new LongArrayTag(list.toLongArray());
|
|
}
|
|
else if(type == 'F')
|
|
{
|
|
FloatList list = new FloatArrayList();
|
|
readArray(T -> list.add(T.asFloat()), 6, PrimitiveTag.class);
|
|
return new FloatArrayTag(list.toFloatArray());
|
|
}
|
|
else if(type == 'D')
|
|
{
|
|
DoubleList list = new DoubleArrayList();
|
|
readArray(T -> list.add(T.asDouble()), 7, PrimitiveTag.class);
|
|
return new DoubleArrayTag(list.toDoubleArray());
|
|
}
|
|
else if(type == 'A')
|
|
{
|
|
ObjectList<String> list = new ObjectArrayList<String>();
|
|
readArray(T -> list.add(T.get()), 8, StringTag.class);
|
|
return new StringArrayTag(list.toArray(new String[list.size()]));
|
|
}
|
|
else
|
|
{
|
|
throw new IOException("Invalid Data Type: [Received=" + type + ", Valid=[B, S, M, I, L, F, D, A]");
|
|
}
|
|
}
|
|
|
|
protected <T extends DataTag> void readArray(Consumer<T> result, int type, Class<T> clz) throws IOException
|
|
{
|
|
while(true)
|
|
{
|
|
if(reader.peek() != ']')
|
|
{
|
|
DataTag tag = readTag();
|
|
if(tag.getId() != type)
|
|
{
|
|
throw new IOException("Mixing of ArrayTypes [Expected=" + DataTag.create((byte)type).getTypeName() + ", Present=" + tag.getTypeName() + "]");
|
|
}
|
|
result.accept(tag.cast());
|
|
reader.skipEmpty();
|
|
if(reader.isPresent(','))
|
|
{
|
|
reader.skipEmpty();
|
|
if(!reader.canRead())
|
|
{
|
|
throw new IOException("Expected Another Element");
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
requirePresent(']');
|
|
return;
|
|
}
|
|
}
|
|
|
|
protected DataTag tag(String s)
|
|
{
|
|
try
|
|
{
|
|
if(FLOAT_TYPE.matcher(s).matches())
|
|
{
|
|
return new FloatTag(Float.parseFloat(s.substring(0, s.length() - 1)));
|
|
}
|
|
if(BYTE_TYPE.matcher(s).matches())
|
|
{
|
|
return new ByteTag(Byte.parseByte(s.substring(0, s.length() - 1)));
|
|
}
|
|
if(LONG_TYPE.matcher(s).matches())
|
|
{
|
|
return new LongTag(Long.parseLong(s.substring(0, s.length() - 1)));
|
|
}
|
|
if(SHORT_TYPE.matcher(s).matches())
|
|
{
|
|
return new ShortTag(Short.parseShort(s.substring(0, s.length() - 1)));
|
|
}
|
|
if(MEDIUM_TYPE.matcher(s).matches())
|
|
{
|
|
return new MediumTag(Integer.parseInt(s.substring(0, s.length() - 1)));
|
|
}
|
|
if(INT_TYPE.matcher(s).matches())
|
|
{
|
|
return new IntTag(Integer.parseInt(s.substring(0, s.length() - 1)));
|
|
}
|
|
if(DOUBLE_TYPE.matcher(s).matches())
|
|
{
|
|
return new DoubleTag(Double.parseDouble(s.substring(0, s.length() - 1)));
|
|
}
|
|
if(DOUBLE_TYPE_DEFAULT.matcher(s).matches())
|
|
{
|
|
return new DoubleTag(Double.parseDouble(s));
|
|
}
|
|
if(INT_TYPE_DEFAULT.matcher(s).matches())
|
|
{
|
|
return new IntTag(Integer.parseInt(s));
|
|
}
|
|
if("true".equalsIgnoreCase(s))
|
|
{
|
|
return new ByteTag((byte)1);
|
|
}
|
|
if("false".equalsIgnoreCase(s))
|
|
{
|
|
return new ByteTag((byte)0);
|
|
}
|
|
}
|
|
catch(NumberFormatException e)
|
|
{
|
|
}
|
|
return new StringTag(s);
|
|
}
|
|
|
|
protected void requirePresent(char value)
|
|
{
|
|
reader.skipEmpty();
|
|
reader.requirePresent(value);
|
|
}
|
|
}
|