Rogue: Savage Rats, a retro-themed dungeon crawler
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
rogue-savage-rats/src/mightypork/gamecore/util/ion/IonInput.java

454 lines
8.3 KiB

package mightypork.gamecore.util.ion;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import mightypork.gamecore.util.error.CorruptDataException;
/**
* Ion input stream
*
* @author MightyPork
*/
public class IonInput {
private final DataInput in;
public IonInput(InputStream in)
{
this.in = new DataInputStream(in);
}
/**
* Read int 0-255. Suitable when the int was written using
* <code>writeIntByte()</code> method.
*
* @return int
* @throws IOException
*/
public int readIntByte() throws IOException
{
return in.readUnsignedByte();
}
/**
* Read an int 0-65535. Suitable when the int was written using
* <code>writeIntShort()</code> method.
*
* @return int
* @throws IOException
*/
public int readIntShort() throws IOException
{
return in.readUnsignedShort();
}
public boolean readBoolean() throws IOException
{
return in.readBoolean();
}
public byte readByte() throws IOException
{
return in.readByte();
}
public short readShort() throws IOException
{
return in.readShort();
}
public char readChar() throws IOException
{
return in.readChar();
}
public int readInt() throws IOException
{
return in.readInt();
}
public long readLong() throws IOException
{
return in.readLong();
}
public float readFloat() throws IOException
{
return in.readFloat();
}
public double readDouble() throws IOException
{
return in.readDouble();
}
public String readString() throws IOException
{
return in.readUTF();
}
public boolean[] readBooleans() throws IOException
{
final int length = readLength();
final boolean[] arr = new boolean[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readBoolean();
}
return arr;
}
public byte[] readBytes() throws IOException
{
final int length = readLength();
final byte[] arr = new byte[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readByte();
}
return arr;
}
public char[] readChars() throws IOException
{
final int length = readLength();
final char[] arr = new char[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readChar();
}
return arr;
}
public short[] readShorts() throws IOException
{
final int length = readLength();
final short[] arr = new short[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readShort();
}
return arr;
}
public int[] readInts() throws IOException
{
final int length = readLength();
final int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readInt();
}
return arr;
}
public long[] readLongs() throws IOException
{
final int length = readLength();
final long[] arr = new long[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readLong();
}
return arr;
}
public float[] readFloats() throws IOException
{
final int length = readLength();
final float[] arr = new float[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readFloat();
}
return arr;
}
public double[] readDoubles() throws IOException
{
final int length = readLength();
final double[] arr = new double[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readDouble();
}
return arr;
}
public String[] readStrings() throws IOException
{
final int length = readLength();
final String[] arr = new String[length];
for (int i = 0; i < length; i++) {
arr[i] = in.readUTF();
}
return arr;
}
public Object[] readObjects() throws IOException
{
final int length = readLength();
final Object[] arr = new Object[length];
for (int i = 0; i < length; i++) {
arr[i] = readObject();
}
return arr;
}
/**
* Read bundle without a mark
*/
public IonBundle readBundle() throws IOException
{
final IonBundle ib = new IonBundle();
ib.load(this);
return ib;
}
/**
* Read bundle without a mark, load into a provided one
*/
public void readBundle(IonBundle filled) throws IOException
{
filled.clear();
filled.load(this);
}
private int readMark() throws IOException
{
return readIntByte();
}
private int readLength() throws IOException
{
return readIntShort();
}
/**
* <p>
* Read object based on mark; if null mark is found, returns default value.
* </p>
* <p>
* If, however, an object of invalid or different type is found, an
* exception will be thrown.
* </p>
*
* @param def default value.
* @return the loaded object
* @throws IOException
*/
@SuppressWarnings("unchecked")
public <T> T readObject(T def) throws IOException
{
try {
final Object o = readObject();
return (T) (o == null ? def : o);
} catch (final Exception e) {
throw new IOException("Could not load object.", e);
}
}
/**
* Read single object, preceded by a mark.
*
* @return the loaded object
* @throws IOException
*/
public Object readObject() throws IOException
{
final int mark = readMark();
if (Ion.isMarkForBinary(mark)) {
IonObjBinary loaded;
try {
loaded = Ion.getClassForMark(mark).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Couldn not load object with mark: " + mark, e);
}
loaded.load(this);
return loaded;
}
switch (mark) {
case Ion.NULL:
return null;
case Ion.BOOLEAN:
return readBoolean();
case Ion.BYTE:
return readByte();
case Ion.CHAR:
return readChar();
case Ion.SHORT:
return readShort();
case Ion.INT:
return readInt();
case Ion.LONG:
return readLong();
case Ion.FLOAT:
return readFloat();
case Ion.DOUBLE:
return readDouble();
case Ion.STRING:
return readString();
case Ion.BOOLEAN_ARRAY:
return readBooleans();
case Ion.BYTE_ARRAY:
return readBytes();
case Ion.CHAR_ARRAY:
return readChars();
case Ion.SHORT_ARRAY:
return readShorts();
case Ion.INT_ARRAY:
return readInts();
case Ion.LONG_ARRAY:
return readLongs();
case Ion.FLOAT_ARRAY:
return readFloats();
case Ion.DOUBLE_ARRAY:
return readDoubles();
case Ion.STRING_ARRAY:
return readStrings();
default:
throw new CorruptDataException("Invalid mark: " + mark);
}
}
/**
* Reads mark and returns true if the mark is ENTRY, false if the mark is
* END. Throws an exception otherwise.
*
* @return mark was ENTRY
* @throws IOException when the mark is neither ENTRY or END.
*/
public boolean hasNextEntry() throws IOException
{
final int mark = readMark();
if (mark == Ion.ENTRY) return true;
if (mark == Ion.END) return false;
throw new CorruptDataException("Unexpected mark in sequence: " + mark);
}
/**
* Read a sequence of elements into an ArrayList
*
* @return the collection
* @throws IOException
*/
public <T> Collection<T> readSequence() throws IOException
{
return readSequence(new ArrayList<T>());
}
/**
* Load entries into a collection. The collection is cleaned first.
*
* @param filled collection to populate
* @return the collection
* @throws IOException
*/
@SuppressWarnings("unchecked")
public <T> Collection<T> readSequence(Collection<T> filled) throws IOException
{
try {
filled.clear();
while (hasNextEntry()) {
filled.add((T) readObject());
}
return filled;
} catch (final ClassCastException e) {
throw new CorruptDataException("Unexpected element type in sequence.", e);
}
}
/**
* Read element pairs into a HashMap
*
* @return the map
* @throws IOException
*/
public <K, V> Map<K, V> readMap() throws IOException
{
return readMap(new HashMap<K, V>());
}
/**
* Load data into a map. The map is cleaned first.
*
* @param filled filled map
* @return the map
* @throws IOException
*/
@SuppressWarnings("unchecked")
public <K, V> Map<K, V> readMap(Map<K, V> filled) throws IOException
{
try {
filled.clear();
while (hasNextEntry()) {
final K key = (K) readObject();
final V value = (V) readObject();
filled.put(key, value);
}
return filled;
} catch (final ClassCastException e) {
throw new CorruptDataException("Unexpected element type in map.", e);
}
}
}