chunks use an int array. Chunk files will take up less memory now

pull/12/head
valoeghese 2020-02-29 11:57:53 +13:00
parent e70f21c81c
commit 159f2133f3
15 changed files with 925 additions and 252 deletions

View File

@ -169,7 +169,7 @@ public class Chunk implements BlockAccess, WorldGenConstants, DataStorage
}
}
//
DataSection blockData = data.get("block");
IntArrayDataSection blockData = data.getIntArray("block");
int index = 0;
//
for (int z = 0; z < CHUNK_SIZE; ++z) // z, y, x order for data saving and loading so we can use incremental pos hashes
@ -207,7 +207,7 @@ public class Chunk implements BlockAccess, WorldGenConstants, DataStorage
{
Object2IntMap<Block> palette = new Object2IntArrayMap<>(); // block to int id
DataSection paletteData = new DataSection();
DataSection blockData = new DataSection();
IntArrayDataSection blockData = new IntArrayDataSection();
int index = 0;
nextId = 0;
ToIntFunction<Block> nextIdProvider = b -> nextId++;

View File

@ -1,6 +1,6 @@
package com.github.halotroop.litecraft.world;
import java.util.*;
import java.util.Random;
import java.util.function.LongConsumer;
import org.joml.Vector3f;

View File

@ -0,0 +1,8 @@
package tk.valoeghese.sod;
interface BaseDataSection<E> extends Iterable<E> {
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
<T> void writeForParser(T data);
}

View File

@ -1,58 +1,97 @@
package tk.valoeghese.sod;
import java.io.*;
import java.util.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import tk.valoeghese.sod.exception.SODParseException;
public class BinaryData implements Iterable<Map.Entry<String, DataSection>>
{
public static BinaryData read(File file) throws SODParseException
{
try (DataInputStream dis = new DataInputStream(new FileInputStream(file)))
{
long magic = dis.readLong();
if (magic != 0xA77D1E)
{ throw new SODParseException("Not a valid SOD file!"); }
return Parser.parse(dis);
@SuppressWarnings("rawtypes")
public class BinaryData implements Iterable<Map.Entry<String, BaseDataSection>> {
public BinaryData() {
this.sections = new HashMap<>();
}
private final Map<String, BaseDataSection> sections;
public DataSection get(String name) {
return (DataSection) this.sections.get(name);
}
public ByteArrayDataSection getByteArray(String name) {
return (ByteArrayDataSection) this.sections.get(name);
}
public ShortArrayDataSection getShortArray(String name) {
return (ShortArrayDataSection) this.sections.get(name);
}
public IntArrayDataSection getIntArray(String name) {
return (IntArrayDataSection) this.sections.get(name);
}
public LongArrayDataSection getLongArray(String name) {
return (LongArrayDataSection) this.sections.get(name);
}
public FloatArrayDataSection getFloatArray(String name) {
return (FloatArrayDataSection) this.sections.get(name);
}
public DoubleArrayDataSection getDoubleArray(String name) {
return (DoubleArrayDataSection) this.sections.get(name);
}
public StringArrayDataSection getStringArray(String name) {
return (StringArrayDataSection) this.sections.get(name);
}
public DataSection getOrCreate(String name) {
return (DataSection) this.sections.computeIfAbsent(name, k -> new DataSection());
}
public void put(String name, BaseDataSection section) {
this.sections.put(name, section);
}
public boolean containsSection(String name) {
return this.sections.containsKey(name);
}
public boolean write(File file) {
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
Parser.write(this, dos);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
catch (IOException e)
{
}
@Override
public Iterator<Map.Entry<String, BaseDataSection>> iterator() {
return this.sections.entrySet().iterator();
}
public static BinaryData read(File file) throws SODParseException {
try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {
long magic = dis.readLong();
if (magic != 0xA77D1E) {
throw new SODParseException("Not a valid SOD file!");
}
return Parser.parse(dis);
} catch (IOException e) {
e.printStackTrace();
//throw new SODParseException("Error in parsing file " + file.toString());
return new BinaryData();
}
}
private final Map<String, DataSection> sections;
public BinaryData()
{ this.sections = new HashMap<>(); }
public DataSection get(String name)
{ return this.sections.get(name); }
public DataSection getOrCreate(String name)
{ return this.sections.computeIfAbsent(name, k -> new DataSection()); }
@Override
public Iterator<Map.Entry<String, DataSection>> iterator()
{ return this.sections.entrySet().iterator(); }
public void put(String name, DataSection section)
{ this.sections.put(name, section); }
public boolean write(File file)
{
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file)))
{
Parser.write(this, dos);
return true;
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
}
}

View File

@ -0,0 +1,43 @@
package tk.valoeghese.sod;
import java.util.Iterator;
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
import it.unimi.dsi.fastutil.bytes.ByteList;
public class ByteArrayDataSection implements BaseDataSection<Byte> {
public ByteArrayDataSection() {
this.array = new ByteArrayList();
}
private final ByteList array;
public void writeByte(byte value) {
this.array.add(value);
}
public int size() {
return array.size();
}
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
@Override
public <T> void writeForParser(T data) throws UnsupportedOperationException {
if (data instanceof Byte) {
this.writeByte((byte) data);
} else {
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
}
}
public byte readByte(int index) {
return this.array.getByte(index);
}
@Override
public Iterator<Byte> iterator() {
return this.array.iterator();
}
}

View File

@ -1,86 +1,120 @@
package tk.valoeghese.sod;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/** Represents a section of SOD data.
*
* @author Valoeghese */
public class DataSection implements Iterable<Object>
{
private final List<Object> data;
/**
* Represents a section of SOD data.
* @author Valoeghese
*/
public class DataSection implements BaseDataSection<Object> {
public DataSection() {
this.data = new ArrayList<>();
}
public DataSection()
{ this.data = new ArrayList<>(); }
private final List<Object> data;
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
@Override
public Iterator<Object> iterator()
{ return this.data.iterator(); }
public <T> void writeForParser(T data) {
this.data.add(data);
}
public boolean readBoolean(int index)
{ return ((byte) this.data.get(index)) != 0; }
public void writeByte(byte data) {
this.data.add(data);
}
public byte readByte(int index)
{ return (byte) this.data.get(index); }
public void writeShort(short data) {
this.data.add(data);
}
public double readDouble(int index)
{ return (double) this.data.get(index); }
public void writeInt(int data) {
this.data.add(data);
}
public <T extends Enum<?>> T readEnum(int index, T[] values)
{
public void writeLong(long data) {
this.data.add(data);
}
public void writeFloat(float data) {
this.data.add(data);
}
public void writeDouble(double data) {
this.data.add(data);
}
public void writeString(String data) {
this.data.add(data);
}
public void writeBoolean(boolean data) {
this.data.add(data ? (byte) 1 : (byte) 0);
}
public <T extends Enum<?>> void writeEnum(T enumValue) {
this.data.add(enumValue.ordinal());
}
public <T extends Enum<?>> void writeEnumAsString(T enumValue) {
this.data.add(enumValue.toString());
}
public int size() {
return this.data.size();
}
public byte readByte(int index) {
return (byte) this.data.get(index);
}
public short readShort(int index) {
return (short) this.data.get(index);
}
public int readInt(int index) {
return (int) this.data.get(index);
}
public long readLong(int index) {
return (long) this.data.get(index);
}
public float readFloat(int index) {
return (float) this.data.get(index);
}
public double readDouble(int index) {
return (double) this.data.get(index);
}
public String readString(int index) {
return (String) this.data.get(index);
}
public boolean readBoolean(int index) {
return ((byte) this.data.get(index)) != 0;
}
public <T extends Enum<T>> T readEnumString(int index, Class<T> type) {
return Enum.valueOf(type, (String) this.data.get(index));
}
public <T extends Enum<?>> T readEnum(int index, T[] values) {
Integer i = (Integer) this.data.get(index);
if (i == null)
{ return null; }
if (i == null) {
return null;
}
return values[i];
}
public <T extends Enum<T>> T readEnumString(int index, Class<T> type)
{ return Enum.valueOf(type, (String) this.data.get(index)); }
public float readFloat(int index)
{ return (float) this.data.get(index); }
public int readInt(int index)
{ return (int) this.data.get(index); }
public long readLong(int index)
{ return (long) this.data.get(index); }
public short readShort(int index)
{ return (short) this.data.get(index); }
public String readString(int index)
{ return (String) this.data.get(index); }
public int size()
{ return this.data.size(); }
public void writeBoolean(boolean data)
{ this.data.add(data ? (byte) 1 : (byte) 0); }
public void writeByte(byte data)
{ this.data.add(data); }
public void writeDouble(double data)
{ this.data.add(data); }
public <T extends Enum<?>> void writeEnum(T enumValue)
{ this.data.add(enumValue.ordinal()); }
public <T extends Enum<?>> void writeEnumAsString(T enumValue)
{ this.data.add(enumValue.toString()); }
public void writeFloat(float data)
{ this.data.add(data); }
public void writeInt(int data)
{ this.data.add(data); }
public void writeLong(long data)
{ this.data.add(data); }
public void writeShort(short data)
{ this.data.add(data); }
public void writeString(String data)
{ this.data.add(data); }
@Override
public Iterator<Object> iterator() {
return this.data.iterator();
}
}

View File

@ -0,0 +1,43 @@
package tk.valoeghese.sod;
import java.util.Iterator;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleList;
public class DoubleArrayDataSection implements BaseDataSection<Double> {
public DoubleArrayDataSection() {
this.array = new DoubleArrayList();
}
private final DoubleList array;
public void writeDouble(double value) {
this.array.add(value);
}
public int size() {
return array.size();
}
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
@Override
public <T> void writeForParser(T data) throws UnsupportedOperationException {
if (data instanceof Double) {
this.writeDouble((double) data);
} else {
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
}
}
public double readDouble(int index) {
return this.array.getDouble(index);
}
@Override
public Iterator<Double> iterator() {
return this.array.iterator();
}
}

View File

@ -0,0 +1,43 @@
package tk.valoeghese.sod;
import java.util.Iterator;
import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.floats.FloatList;
public class FloatArrayDataSection implements BaseDataSection<Float> {
public FloatArrayDataSection() {
this.array = new FloatArrayList();
}
private final FloatList array;
public void writeFloat(float value) {
this.array.add(value);
}
public int size() {
return array.size();
}
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
@Override
public <T> void writeForParser(T data) throws UnsupportedOperationException {
if (data instanceof Float) {
this.writeFloat((float) data);
} else {
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
}
}
public float readFloat(int index) {
return this.array.getFloat(index);
}
@Override
public Iterator<Float> iterator() {
return this.array.iterator();
}
}

View File

@ -0,0 +1,43 @@
package tk.valoeghese.sod;
import java.util.Iterator;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
public class IntArrayDataSection implements BaseDataSection<Integer> {
public IntArrayDataSection() {
this.array = new IntArrayList();
}
private final IntList array;
public void writeInt(int value) {
this.array.add(value);
}
public int size() {
return array.size();
}
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
@Override
public <T> void writeForParser(T data) throws UnsupportedOperationException {
if (data instanceof Integer) {
this.writeInt((int) data);
} else {
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
}
}
public int readInt(int index) {
return this.array.getInt(index);
}
@Override
public Iterator<Integer> iterator() {
return this.array.iterator();
}
}

View File

@ -0,0 +1,43 @@
package tk.valoeghese.sod;
import java.util.Iterator;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
public class LongArrayDataSection implements BaseDataSection<Long> {
public LongArrayDataSection() {
this.array = new LongArrayList();
}
private final LongList array;
public void writeLong(long value) {
this.array.add(value);
}
public int size() {
return array.size();
}
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
@Override
public <T> void writeForParser(T data) throws UnsupportedOperationException {
if (data instanceof Long) {
this.writeLong((long) data);
} else {
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
}
}
public long readLong(int index) {
return this.array.getLong(index);
}
@Override
public Iterator<Long> iterator() {
return this.array.iterator();
}
}

View File

@ -1,12 +1,329 @@
package tk.valoeghese.sod;
import java.io.*;
import java.util.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import tk.valoeghese.sod.exception.SODParseException;
enum DataType
{
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),
@ -14,12 +331,23 @@ enum DataType
LONG(4),
FLOAT(5),
DOUBLE(6),
STRING(7);
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);
public static DataType of(byte id) throws SODParseException
{
switch (id)
{
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:
@ -36,114 +364,46 @@ enum DataType
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));
}
}
public final byte id;
private DataType(int id)
{ this.id = (byte) id; }
}
final class Parser
{
static BinaryData parse(DataInputStream input) throws IOException, SODParseException
{
BinaryData data = new BinaryData();
DataType dataType;
dataType = DataType.of(input.readByte());
if (dataType != DataType.SECTION)
{ throw new SODParseException("Data must be segregated into sections!"); }
DataSection currentSection = new DataSection();
data.put(input.readUTF(), currentSection);
while (input.available() > 0)
{
dataType = DataType.of(input.readByte());
switch (dataType)
{
case BYTE:
currentSection.writeByte(input.readByte());
break;
case DOUBLE:
currentSection.writeDouble(input.readDouble());
break;
case FLOAT:
currentSection.writeFloat(input.readFloat());
break;
case INT:
currentSection.writeInt(input.readInt());
break;
case LONG:
currentSection.writeLong(input.readLong());
break;
case SECTION:
currentSection = new DataSection();
data.put(input.readUTF(), currentSection);
break;
case SHORT:
currentSection.writeShort(input.readShort());
break;
case STRING:
currentSection.writeString(input.readUTF());
break;
default:
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.");
}
}
return data;
}
static void write(BinaryData data, DataOutputStream dos) throws IOException
{
dos.writeLong(0xA77D1E);
Iterator<Map.Entry<String, DataSection>> sectionStream = data.iterator();
while (sectionStream.hasNext())
{
Map.Entry<String, DataSection> section = sectionStream.next();
dos.writeByte(DataType.SECTION.id);
dos.writeUTF(section.getKey());
Iterator<Object> dataStream = section.getValue().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);
}
}
@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!");
}
}
}

View File

@ -0,0 +1,43 @@
package tk.valoeghese.sod;
import java.util.Iterator;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
import it.unimi.dsi.fastutil.shorts.ShortList;
public class ShortArrayDataSection implements BaseDataSection<Short> {
public ShortArrayDataSection() {
this.array = new ShortArrayList();
}
private final ShortList array;
public void writeShort(short value) {
this.array.add(value);
}
public int size() {
return array.size();
}
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
@Override
public <T> void writeForParser(T data) throws UnsupportedOperationException {
if (data instanceof Short) {
this.writeShort((short) data);
} else {
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
}
}
public short readShort(int index) {
return this.array.getShort(index);
}
@Override
public Iterator<Short> iterator() {
return this.array.iterator();
}
}

View File

@ -0,0 +1,42 @@
package tk.valoeghese.sod;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class StringArrayDataSection implements BaseDataSection<String> {
public StringArrayDataSection() {
this.array = new ArrayList<String>();
}
private final List<String> array;
public void writeString(String value) {
this.array.add(value);
}
public int size() {
return array.size();
}
/**
* @deprecated Should only be used by the parser! Please use the type specific methods instead for writing data.
*/
@Override
public <T> void writeForParser(T data) throws UnsupportedOperationException {
if (data instanceof String) {
this.writeString((String) data);
} else {
throw new UnsupportedOperationException("Invalid data type parameter for this data section");
}
}
public String readString(int index) {
return this.array.get(index);
}
@Override
public Iterator<String> iterator() {
return this.array.iterator();
}
}

View File

@ -1,45 +1,77 @@
package tk.valoeghese.sod;
import java.io.*;
import java.io.File;
import java.io.IOException;
public class TestMain
{
public static void main(String[] args) throws IOException
{
//writeTest()
class TestMain {
public static void main(String[] args) throws IOException {
writeTest();
readTest();
}
static void readTest() throws IOException
{
static void readTest() throws IOException {
File f = new File("../test.sod");
if (!f.createNewFile())
{
if (!f.createNewFile()) {
BinaryData bd = BinaryData.read(f);
StringArrayDataSection ds0 = bd.getStringArray("StringArray");
for (String s : ds0) {
System.out.println(s);
}
DataSection ds1 = bd.get("DS1");
for (Object i : ds1)
{ System.out.println(i); }
for (Object i : ds1) {
System.out.println(i);
}
DataSection ds2 = bd.get("yeet");
for (Object i : ds2)
{ System.out.println(i); }
for (Object i : ds2) {
System.out.println(i);
}
ByteArrayDataSection ds3 = bd.getByteArray("ByteArray");
for (byte i : ds3) {
System.out.println(i);
}
}
}
static void writeTest() throws IOException
{
static void writeTest() throws IOException {
File f = new File("../test.sod");
f.createNewFile();
BinaryData bd = new BinaryData();
StringArrayDataSection ds0 = new StringArrayDataSection();
ds0.writeString("Once upon a time");
ds0.writeString("There was a programmer who went by the username of \"Valoeghese\"");
ds0.writeString("One day he updated his data format SOD to have array sections");
bd.put("StringArray", ds0);
DataSection ds1 = bd.getOrCreate("DS1");
ds1.writeBoolean(false);
ds1.writeDouble(0.666D);
ds1.writeLong(69696969);
ds1.writeString("yaY33T");
DataSection ds2 = bd.getOrCreate("yeet");
ds2.writeByte((byte) 4);
ds2.writeFloat(1.3F);
ds2.writeString("e");
ds2.writeString("ff");
ByteArrayDataSection ds3 = new ByteArrayDataSection();
ds3.writeByte((byte)0);
ds3.writeByte((byte)9);
ds3.writeByte((byte)-10);
bd.put("ByteArray", ds3);
bd.write(f);
}
}

View File

@ -1,9 +1,9 @@
package tk.valoeghese.sod.exception;
public class SODParseException extends RuntimeException
{
public class SODParseException extends RuntimeException {
private static final long serialVersionUID = -3337517517501006140L;
public SODParseException(String message)
{ super(message); }
public SODParseException(String message) {
super(message);
}
}