Ginger3D/src/main/java/tk/valoeghese/sod/Parser.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!");
}
}
}