440 lines
12 KiB
Java
440 lines
12 KiB
Java
package tk.valoeghese.sod;
|
|
|
|
import java.io.*;
|
|
import java.util.*;
|
|
|
|
import tk.valoeghese.sod.exception.SODParseException;
|
|
|
|
final class Parser
|
|
{
|
|
@SuppressWarnings(
|
|
{
|
|
"deprecation", "rawtypes", "unchecked"
|
|
})
|
|
static BinaryData parse(DataInputStream input) throws IOException, SODParseException
|
|
{
|
|
BinaryData data = new BinaryData();
|
|
DataType dataType;
|
|
DataType sectionType;
|
|
dataType = DataType.of(input.readByte());
|
|
sectionType = dataType;
|
|
BaseDataSection currentSection;
|
|
int arraySizeCountdown = 0;
|
|
try
|
|
{
|
|
currentSection = dataType.createSection();
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new SODParseException("Data must be segregated into sections!");
|
|
}
|
|
data.put(input.readUTF(), currentSection);
|
|
while (input.available() > 0)
|
|
{
|
|
switch (sectionType)
|
|
{
|
|
case BYTE_ARRAY_SECTION:
|
|
while (arraySizeCountdown-- > 0)
|
|
{ currentSection.writeForParser(input.readByte()); }
|
|
// create new section if available
|
|
if (input.available() > 0)
|
|
{
|
|
try
|
|
{
|
|
dataType = DataType.of(input.readByte());
|
|
sectionType = dataType;
|
|
currentSection = dataType.createSection();
|
|
data.put(input.readUTF(), currentSection);
|
|
// set countdown
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
|
}
|
|
}
|
|
break;
|
|
case SHORT_ARRAY_SECTION:
|
|
while (arraySizeCountdown-- > 0)
|
|
{ currentSection.writeForParser(input.readShort()); }
|
|
// create new section if available
|
|
if (input.available() > 0)
|
|
{
|
|
try
|
|
{
|
|
dataType = DataType.of(input.readByte());
|
|
sectionType = dataType;
|
|
currentSection = dataType.createSection();
|
|
data.put(input.readUTF(), currentSection);
|
|
// set countdown
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
|
}
|
|
}
|
|
break;
|
|
case INT_ARRAY_SECTION:
|
|
while (arraySizeCountdown-- > 0)
|
|
{ currentSection.writeForParser(input.readInt()); }
|
|
// create new section if available
|
|
if (input.available() > 0)
|
|
{
|
|
try
|
|
{
|
|
dataType = DataType.of(input.readByte());
|
|
sectionType = dataType;
|
|
currentSection = dataType.createSection();
|
|
data.put(input.readUTF(), currentSection);
|
|
// set countdown
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
|
}
|
|
}
|
|
break;
|
|
case LONG_ARRAY_SECTION:
|
|
while (arraySizeCountdown-- > 0)
|
|
{ currentSection.writeForParser(input.readLong()); }
|
|
// create new section if available
|
|
if (input.available() > 0)
|
|
{
|
|
try
|
|
{
|
|
dataType = DataType.of(input.readByte());
|
|
sectionType = dataType;
|
|
currentSection = dataType.createSection();
|
|
data.put(input.readUTF(), currentSection);
|
|
// set countdown
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
|
}
|
|
}
|
|
break;
|
|
case FLOAT_ARRAY_SECTION:
|
|
while (arraySizeCountdown-- > 0)
|
|
{ currentSection.writeForParser(input.readFloat()); }
|
|
// create new section if available
|
|
if (input.available() > 0)
|
|
{
|
|
try
|
|
{
|
|
dataType = DataType.of(input.readByte());
|
|
sectionType = dataType;
|
|
currentSection = dataType.createSection();
|
|
data.put(input.readUTF(), currentSection);
|
|
// set countdown
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
|
}
|
|
}
|
|
break;
|
|
case DOUBLE_ARRAY_SECTION:
|
|
while (arraySizeCountdown-- > 0)
|
|
{ currentSection.writeForParser(input.readDouble()); }
|
|
// create new section if available
|
|
if (input.available() > 0)
|
|
{
|
|
try
|
|
{
|
|
dataType = DataType.of(input.readByte());
|
|
sectionType = dataType;
|
|
currentSection = dataType.createSection();
|
|
data.put(input.readUTF(), currentSection);
|
|
// set countdown
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
|
}
|
|
}
|
|
break;
|
|
case STRING_ARRAY_SECTION:
|
|
while (arraySizeCountdown-- > 0)
|
|
{ currentSection.writeForParser(input.readUTF()); }
|
|
// create new section if available
|
|
if (input.available() > 0)
|
|
{
|
|
try
|
|
{
|
|
dataType = DataType.of(input.readByte());
|
|
sectionType = dataType;
|
|
currentSection = dataType.createSection();
|
|
data.put(input.readUTF(), currentSection);
|
|
// set countdown
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
|
}
|
|
}
|
|
break;
|
|
case SECTION:
|
|
default:
|
|
dataType = DataType.of(input.readByte());
|
|
switch (dataType)
|
|
{
|
|
case BYTE:
|
|
currentSection.writeForParser(input.readByte());
|
|
break;
|
|
case DOUBLE:
|
|
currentSection.writeForParser(input.readDouble());
|
|
break;
|
|
case FLOAT:
|
|
currentSection.writeForParser(input.readFloat());
|
|
break;
|
|
case INT:
|
|
currentSection.writeForParser(input.readInt());
|
|
break;
|
|
case LONG:
|
|
currentSection.writeForParser(input.readLong());
|
|
break;
|
|
case SHORT:
|
|
currentSection.writeForParser(input.readShort());
|
|
break;
|
|
case STRING:
|
|
currentSection.writeForParser(input.readUTF());
|
|
break;
|
|
default:
|
|
try
|
|
{
|
|
currentSection = dataType.createSection();
|
|
sectionType = dataType;
|
|
data.put(input.readUTF(), currentSection);
|
|
if (dataType != DataType.SECTION)
|
|
{ arraySizeCountdown = input.readInt(); }
|
|
}
|
|
catch (SODParseException e)
|
|
{
|
|
throw new RuntimeException("This error should never be thrown! If this error occurs, the parser is not properly dealing with a most-likely-invalid data type.");
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
@SuppressWarnings("rawtypes")
|
|
static void write(BinaryData data, DataOutputStream dos) throws IOException
|
|
{
|
|
dos.writeLong(0xA77D1E);
|
|
Iterator<Map.Entry<String, BaseDataSection>> sectionStream = data.iterator();
|
|
while (sectionStream.hasNext())
|
|
{
|
|
Map.Entry<String, BaseDataSection> entry = sectionStream.next();
|
|
BaseDataSection section = entry.getValue();
|
|
if (section instanceof DataSection)
|
|
{
|
|
dos.writeByte(DataType.SECTION.id);
|
|
dos.writeUTF(entry.getKey());
|
|
Iterator<Object> dataStream = ((DataSection) section).iterator();
|
|
while (dataStream.hasNext())
|
|
{
|
|
Object o = dataStream.next();
|
|
if (o instanceof Byte)
|
|
{
|
|
dos.writeByte(DataType.BYTE.id);
|
|
dos.writeByte((byte) o);
|
|
}
|
|
else if (o instanceof Short)
|
|
{
|
|
dos.writeByte(DataType.SHORT.id);
|
|
dos.writeShort((short) o);
|
|
}
|
|
else if (o instanceof Integer)
|
|
{
|
|
dos.writeByte(DataType.INT.id);
|
|
dos.writeInt((int) o);
|
|
}
|
|
else if (o instanceof Long)
|
|
{
|
|
dos.writeByte(DataType.LONG.id);
|
|
dos.writeLong((long) o);
|
|
}
|
|
else if (o instanceof Float)
|
|
{
|
|
dos.writeByte(DataType.FLOAT.id);
|
|
dos.writeFloat((float) o);
|
|
}
|
|
else if (o instanceof Double)
|
|
{
|
|
dos.writeByte(DataType.DOUBLE.id);
|
|
dos.writeDouble((double) o);
|
|
}
|
|
else if (o instanceof String)
|
|
{
|
|
dos.writeByte(DataType.STRING.id);
|
|
dos.writeUTF((String) o);
|
|
}
|
|
}
|
|
}
|
|
else if (section instanceof ByteArrayDataSection)
|
|
{ // byte array
|
|
dos.writeByte(DataType.BYTE_ARRAY_SECTION.id);
|
|
dos.writeUTF(entry.getKey());
|
|
dos.writeInt(((ByteArrayDataSection) section).size());
|
|
for (byte b : (ByteArrayDataSection) section)
|
|
{ dos.writeByte(b); }
|
|
}
|
|
else if (section instanceof ShortArrayDataSection)
|
|
{ // short array
|
|
dos.writeByte(DataType.SHORT_ARRAY_SECTION.id);
|
|
dos.writeUTF(entry.getKey());
|
|
dos.writeInt(((ShortArrayDataSection) section).size());
|
|
for (short s : (ShortArrayDataSection) section)
|
|
{ dos.writeShort(s); }
|
|
}
|
|
else if (section instanceof IntArrayDataSection)
|
|
{ // int array
|
|
dos.writeByte(DataType.INT_ARRAY_SECTION.id);
|
|
dos.writeUTF(entry.getKey());
|
|
dos.writeInt(((IntArrayDataSection) section).size());
|
|
for (int i : (IntArrayDataSection) section)
|
|
{ dos.writeInt(i); }
|
|
}
|
|
else if (section instanceof LongArrayDataSection)
|
|
{ // long array
|
|
dos.writeByte(DataType.LONG_ARRAY_SECTION.id);
|
|
dos.writeUTF(entry.getKey());
|
|
dos.writeInt(((LongArrayDataSection) section).size());
|
|
for (long l : (LongArrayDataSection) section)
|
|
{ dos.writeLong(l); }
|
|
}
|
|
else if (section instanceof FloatArrayDataSection)
|
|
{ // float array
|
|
dos.writeByte(DataType.FLOAT_ARRAY_SECTION.id);
|
|
dos.writeUTF(entry.getKey());
|
|
dos.writeInt(((FloatArrayDataSection) section).size());
|
|
for (float f : (FloatArrayDataSection) section)
|
|
{ dos.writeFloat(f); }
|
|
}
|
|
else if (section instanceof DoubleArrayDataSection)
|
|
{ // double array
|
|
dos.writeByte(DataType.DOUBLE_ARRAY_SECTION.id);
|
|
dos.writeUTF(entry.getKey());
|
|
dos.writeInt(((DoubleArrayDataSection) section).size());
|
|
for (double d : (DoubleArrayDataSection) section)
|
|
{ dos.writeDouble(d); }
|
|
}
|
|
else if (section instanceof StringArrayDataSection)
|
|
{ // string array
|
|
dos.writeByte(DataType.STRING_ARRAY_SECTION.id);
|
|
dos.writeUTF(entry.getKey());
|
|
dos.writeInt(((StringArrayDataSection) section).size());
|
|
for (String s : (StringArrayDataSection) section)
|
|
{ dos.writeUTF(s); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enum DataType
|
|
{
|
|
SECTION(0),
|
|
BYTE(1),
|
|
SHORT(2),
|
|
INT(3),
|
|
LONG(4),
|
|
FLOAT(5),
|
|
DOUBLE(6),
|
|
STRING(7),
|
|
BYTE_ARRAY_SECTION(8),
|
|
SHORT_ARRAY_SECTION(9),
|
|
INT_ARRAY_SECTION(10),
|
|
LONG_ARRAY_SECTION(11),
|
|
FLOAT_ARRAY_SECTION(12),
|
|
DOUBLE_ARRAY_SECTION(13),
|
|
STRING_ARRAY_SECTION(14);
|
|
|
|
private DataType(int id)
|
|
{ this.id = (byte) id; }
|
|
|
|
public final byte id;
|
|
|
|
public static DataType of(byte id) throws SODParseException
|
|
{
|
|
switch (id)
|
|
{
|
|
case 0:
|
|
return SECTION;
|
|
case 1:
|
|
return BYTE;
|
|
case 2:
|
|
return SHORT;
|
|
case 3:
|
|
return INT;
|
|
case 4:
|
|
return LONG;
|
|
case 5:
|
|
return FLOAT;
|
|
case 6:
|
|
return DOUBLE;
|
|
case 7:
|
|
return STRING;
|
|
case 8:
|
|
return BYTE_ARRAY_SECTION;
|
|
case 9:
|
|
return SHORT_ARRAY_SECTION;
|
|
case 10:
|
|
return INT_ARRAY_SECTION;
|
|
case 11:
|
|
return LONG_ARRAY_SECTION;
|
|
case 12:
|
|
return FLOAT_ARRAY_SECTION;
|
|
case 13:
|
|
return DOUBLE_ARRAY_SECTION;
|
|
case 14:
|
|
return STRING_ARRAY_SECTION;
|
|
default:
|
|
throw new SODParseException("Unknown data type " + String.valueOf(id));
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("rawtypes")
|
|
BaseDataSection createSection()
|
|
{
|
|
switch (this)
|
|
{
|
|
case SECTION:
|
|
return new DataSection();
|
|
case BYTE_ARRAY_SECTION:
|
|
return new ByteArrayDataSection();
|
|
case DOUBLE_ARRAY_SECTION:
|
|
return new DoubleArrayDataSection();
|
|
case FLOAT_ARRAY_SECTION:
|
|
return new FloatArrayDataSection();
|
|
case INT_ARRAY_SECTION:
|
|
return new IntArrayDataSection();
|
|
case LONG_ARRAY_SECTION:
|
|
return new LongArrayDataSection();
|
|
case SHORT_ARRAY_SECTION:
|
|
return new ShortArrayDataSection();
|
|
case STRING_ARRAY_SECTION:
|
|
return new StringArrayDataSection();
|
|
default:
|
|
throw new SODParseException("Tried to create section from non-section data type!");
|
|
}
|
|
}
|
|
} |