Entirely rewritten ION, world saving, added map movement etc

This commit is contained in:
Ondřej Hruška
2014-04-22 02:14:45 +02:00
parent 2f26602d15
commit c94cd05da5
49 changed files with 2064 additions and 2086 deletions
@@ -17,7 +17,7 @@ import mightypork.util.math.Easing;
public class VectAnimated extends VectMutable implements Pauseable, Updateable {
private final NumAnimated x, y, z;
private double defaultDuration = 0;
private double defaultDuration = 0.5;
/**
@@ -83,45 +83,30 @@ public class VectAnimated extends VectMutable implements Pauseable, Updateable {
@Override
public void setX(double x)
{
this.x.animate(x, defaultDuration);
this.x.setTo(x);
}
@Override
public void setY(double y)
{
this.y.animate(y, defaultDuration);
this.y.setTo(y);
}
@Override
public void setZ(double z)
{
this.z.animate(z, defaultDuration);
this.z.setTo(z);
}
/**
* Add offset with animation
*
* @param offset added offset
* @param duration animation time (seconds)
*/
public void add(Vect offset, double duration)
{
animate(this.add(offset), duration);
}
/**
* Animate to given coordinates in given amount of time
*
* @param x
* @param y
* @param z
* @param duration animation time (seconds)
* @return this
*/
public VectAnimated animate(double x, double y, double z, double duration)
{
this.x.animate(x, duration);
@@ -131,13 +116,6 @@ public class VectAnimated extends VectMutable implements Pauseable, Updateable {
}
/**
* Animate to given vec in given amount of time.
*
* @param target target (only it's current value will be used)
* @param duration animation time (seconds)
* @return this
*/
public VectAnimated animate(Vect target, double duration)
{
animate(target.x(), target.y(), target.z(), duration);
@@ -145,6 +123,22 @@ public class VectAnimated extends VectMutable implements Pauseable, Updateable {
}
public VectAnimated animate(double x, double y, double z)
{
this.x.animate(x, defaultDuration);
this.y.animate(y, defaultDuration);
this.z.animate(z, defaultDuration);
return this;
}
public VectAnimated animate(Vect target)
{
animate(target.x(), target.y(), target.z());
return this;
}
/**
* @return the default duration (seconds)
*/
File diff suppressed because it is too large Load Diff
@@ -1,58 +0,0 @@
package mightypork.util.files.ion;
import mightypork.util.files.ion.templates.StreamableHashMap;
/**
* <p>
* Data bundle.
* </p>
* <p>
* Storing data in a bundle guarantees that future versions will be compatible
* with the older format. Reading using default values ensures that you will get
* some value even if it was not saved in the file.
* </p>
*
* @author MightyPork
*/
public class IonBundle extends StreamableHashMap<String, Object> implements Ionizable {
/**
* Get an object. If not found, fallback is returned.
*
* @param key key
* @param fallback fallback
* @return element
*/
public <T> T get(String key, T fallback)
{
try {
final T itm = (T) super.get(key);
if (itm == null) return fallback;
return itm;
} catch (final ClassCastException e) {
return fallback;
}
}
/**
* Store an element. It's allowed to store any object, but only primitive
* types, String, their arrays, and Ionizable objects can be successfully
* stored to stream..
*/
@Override
public Object put(String key, Object value)
{
return super.put(key, value);
}
@Override
public short getIonMark()
{
return Ion.DATA_BUNDLE;
}
}
@@ -1,31 +0,0 @@
package mightypork.util.files.ion;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>
* Implicit constructor marked like this is intended to be solely used for ION
* de-serialization.
* </p>
* <p>
* Constructors marked like this should create a functional instance with
* default values.
* </p>
* <p>
* This is a descriptive annotation and has no other function.
* </p>
*
* @author MightyPork
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.CONSTRUCTOR)
@Documented
public @interface IonConstructor {
}
@@ -1,24 +0,0 @@
package mightypork.util.files.ion;
/**
* <p>
* Data object that can be reconstructed by Ion based on it's mark. Such object
* MUST provide an implicit constructor.
* </p>
* <p>
* All {@link Ionizable}s must be registered to {@link Ion}, otherwise they
* can't be written/loaded using the mark.
* </p>
*
* @author MightyPork
*/
public interface Ionizable extends Streamable {
/**
* Get Ion mark byte.
*
* @return Ion mark byte.
*/
public short getIonMark();
}
@@ -1,36 +0,0 @@
package mightypork.util.files.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
*
* Saveable to a stream.
*
*
* @author MightyPork
*/
public interface Streamable {
/**
* Load data from the input stream. Must be compatible with the
* <code>save</code> method.
*
* @param in input stream
* @throws IOException
*/
void load(InputStream in) throws IOException;
/**
* Store data to output stream.
*
* @param out Output stream
* @throws IOException
*/
void save(OutputStream out) throws IOException;
}
@@ -1,28 +0,0 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Streamable;
public class StreamableArrayList<E> extends ArrayList<E> implements Streamable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}
@@ -1,28 +0,0 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Streamable;
public class StreamableHashMap<K, V> extends HashMap<K, V> implements Streamable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readMap(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeMap(out, this);
}
}
@@ -1,28 +0,0 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Streamable;
public abstract class StreamableHashSet<E> extends HashSet<E> implements Streamable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}
@@ -1,28 +0,0 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Streamable;
public class StreamableLinkedHashMap<K, V> extends LinkedHashMap<K, V> implements Streamable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readMap(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeMap(out, this);
}
}
@@ -1,28 +0,0 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Streamable;
public class StreamableLinkedList<E> extends LinkedList<E> implements Streamable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}
@@ -1,28 +0,0 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Stack;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Streamable;
public class StreamableStack<E> extends Stack<E> implements Streamable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}
@@ -1,28 +0,0 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.TreeSet;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Streamable;
public class StreamableTreeSet<E> extends TreeSet<E> implements Streamable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}
+296
View File
@@ -0,0 +1,296 @@
package mightypork.util.ion;
import java.io.*;
import mightypork.util.logging.Log;
/**
* Universal data storage system (main API class)
*
* @author MightyPork
*/
public class Ion {
// marks for object saving
/** Null mark */
static final int NULL = 0;
/** Boolean mark */
static final int BOOLEAN = 1;
/** Byte mark */
static final int BYTE = 2;
/** Character mark */
static final int CHAR = 3;
/** Short mark */
static final int SHORT = 4;
/** Integer mark */
static final int INT = 5;
/** Long mark */
static final int LONG = 6;
/** Float mark */
static final int FLOAT = 7;
/** Double mark */
static final int DOUBLE = 8;
/** String mark */
static final int STRING = 9;
/** Boolean array mark */
static final int BOOLEAN_ARRAY = 10;
/** Byte array mark */
static final int BYTE_ARRAY = 11;
/** Character array mark */
static final int CHAR_ARRAY = 12;
/** Short array mark */
static final int SHORT_ARRAY = 13;
/** Integer array mark */
static final int INT_ARRAY = 14;
/** Long array mark */
static final int LONG_ARRAY = 15;
/** Float array mark */
static final int FLOAT_ARRAY = 16;
/** Double array mark */
static final int DOUBLE_ARRAY = 17;
/** String array mark */
static final int STRING_ARRAY = 18;
/** Entry mark - start of map or sequence entry */
static final int ENTRY = 19;
/** End mark - end of sequence or map */
static final int END = 20;
/** Map mark (built-in data structure) */
static final int DATA_BUNDLE = 21;
/** Sequence wrapper for bundle */
static final int SEQUENCE_WRAPPER = 22;
/** Map wrapper for bundle */
static final int MAP_WRAPPER = 23;
// technical 20..39
/** Ionizables<Mark, Class> */
@SuppressWarnings("rawtypes")
private static Class[] registered = new Class[256];
private static boolean reservedMarkChecking;
static {
reservedMarkChecking = false;
// register built-ins
registerBinary(DATA_BUNDLE, IonBundle.class);
registerBinary(SEQUENCE_WRAPPER, IonSequenceWrapper.class);
registerBinary(MAP_WRAPPER, IonMapWrapper.class);
reservedMarkChecking = true;
}
/**
* Register new {@link IonBinary} class for writing/loading.
*
* @param mark mark to be used 50..255, unless internal
* @param objClass class of the registered object
*/
public static void registerBinary(int mark, Class<? extends IonBinary> objClass)
{
// negative marks are allowed.
if (mark > 255) throw new IllegalArgumentException("Mark must be < 256.");
if (mark < 0) throw new IllegalArgumentException("Mark must be positive.");
if (reservedMarkChecking && mark < 50) {
throw new IllegalArgumentException("Marks 0..49 are reserved.");
}
if (registered[mark] != null) {
throw new IllegalArgumentException("Mark " + mark + " is already in use.");
}
try {
objClass.getConstructor();
} catch (NoSuchMethodException | SecurityException e) {
throw new IllegalArgumentException("Class " + Log.str(objClass) + " doesn't have an implicit constructor.");
}
registered[mark] = objClass;
}
/**
* Load binary from file and cast.
*/
public static <T extends IonBinary> T fromFile(String path) throws IOException
{
return fromFile(new File(path));
}
/**
* Load binary from file and cast.
*/
public static <T extends IonBinary> T fromFile(File file) throws IOException
{
try(InputStream in = new FileInputStream(file)) {
return fromStream(in);
}
}
/**
* Load bundled from file and unwrap.
*/
public static <T extends IonBundled> T fromFile(String path, Class<? extends T> objClass) throws IOException
{
return fromFile(new File(path), objClass);
}
/**
* Load bundled from file and unwrap.
*/
public static <T extends IonBundled> T fromFile(File file, Class<? extends T> objClass) throws IOException
{
try(InputStream in = new FileInputStream(file)) {
return fromStream(in, objClass);
}
}
public static void toFile(String path, IonBundled obj) throws IOException
{
toFile(new File(path), obj);
}
/**
* Wrap bundled and save to file.
*/
public static void toFile(File file, IonBundled obj) throws IOException
{
toFile(file, wrap(obj));
}
/**
* Write binary to file with mark.
*/
public static void toFile(String path, IonBinary obj) throws IOException
{
toFile(new File(path), obj);
}
/**
* Write binary to file with mark.
*/
public static void toFile(File file, IonBinary obj) throws IOException
{
try(OutputStream out = new FileOutputStream(file)) {
toStream(out, obj);
out.flush();
out.close();
} catch (final Exception e) {
throw new IOException("Error writing to ION file.", e);
}
}
/**
* Load object from stream based on mark, try to cast.
*/
public static <T> T fromStream(InputStream in) throws IOException
{
final IonInput inp = new IonInput(in);
return (T) inp.readObject();
}
/**
* Load bundled object from stream, unwrap.
*/
public static <T extends IonBundled> T fromStream(InputStream in, Class<? extends T> objClass) throws IOException
{
return unwrap(new IonInput(in).readBundle(), objClass);
}
/**
* Write object to output with a mark.
*/
public static void toStream(OutputStream out, IonBinary obj) throws IOException
{
new IonOutput(out).writeObject(obj);
}
/**
* Create new bundle and write the object to it.
*/
public static IonBundle wrap(IonBundled content) throws IOException
{
final IonBundle ib = new IonBundle();
content.save(ib);
return ib;
}
/**
* Try to unwrap an object from bundle. The object class must have implicit
* accessible constructor.
*
* @param bundle unwrapped bundle
* @param objClass class of desired object
* @return the object unwrapped
* @throws IOException
*/
public static <T extends IonBundled> T unwrap(IonBundle bundle, Class<? extends T> objClass) throws IOException
{
try {
final T inst = objClass.newInstance();
inst.load(bundle);
return inst;
} catch (InstantiationException | IllegalAccessException e) {
throw new IOException("Could not instantiate " + Log.str(objClass) + ".");
}
}
@SuppressWarnings("unchecked")
static Class<? extends IonBinary> getClassForMark(int mark)
{
return registered[mark];
}
/**
* @return true if the mark is for a registered {@link IonBinary} object
*/
static boolean isMarkForBinary(int mark)
{
return registered[mark] != null;
}
/**
* Make sure object is registered in the table
*
* @throws IOException if not registered or class mismatch
*/
static void assertRegistered(IonBinary obj) throws IOException
{
final int mark = obj.getIonMark();
final Class<? extends IonBinary> clz = Ion.getClassForMark(mark);
if (clz == null) {
throw new IOException("Not registered - mark: " + mark + ", class: " + Log.str(obj.getClass()));
}
if (clz != obj.getClass()) {
throw new IOException("Class mismatch - mark: " + mark + ", class: " + Log.str(obj.getClass()));
}
}
}
+39
View File
@@ -0,0 +1,39 @@
package mightypork.util.ion;
import java.io.IOException;
/**
* Binary ion object
*
* @author MightyPork
*/
public interface IonBinary {
/**
* Load data from the input stream.
*
* @param in input stream
* @throws IOException
*/
void load(IonInput in) throws IOException;
/**
* Store data to output stream (in such way that the load method will later
* be able to read it).
*
* @param out Output stream
* @throws IOException
*/
void save(IonOutput out) throws IOException;
/**
* Get Ion mark byte.
*
* @return Ion mark byte.
*/
public short getIonMark();
}
+284
View File
@@ -0,0 +1,284 @@
package mightypork.util.ion;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* Ion data bundle - simplified Map
*
* @author MightyPork
*/
public class IonBundle implements IonBinary {
private final Map<String, Object> backingMap = new HashMap<>();
public void putBundled(String key, IonBundled saved) throws IOException
{
final IonBundle ib = new IonBundle();
saved.save(ib);
put(key, ib);
}
public <T extends IonBundled> T getBundled(String key, Class<T> objClass) throws IOException
{
return Ion.unwrap(get(key, (IonBundle) null), objClass);
}
public void loadBundled(String key, IonBundled loaded) throws IOException
{
IonBundle ib = get(key, null);
if (ib == null) ib = new IonBundle();
loaded.load(ib);
}
public <K, V> Map<K, V> getMap(String key)
{
final Map<K, V> m = new HashMap<>();
loadMap(key, m);
return m;
}
public <K, V> void loadMap(String key, Map<K, V> map)
{
final IonMapWrapper imw = get(key, null);
if (imw == null) return;
map.clear();
imw.fill(map);
}
public <E> Collection<E> getSequence(String key)
{
final Collection<E> s = new ArrayList<>();
loadSequence(key, s);
return s;
}
public <E> void loadSequence(String key, Collection<E> sequence)
{
final IonSequenceWrapper isw = get(key, null);
if (isw == null) return;
sequence.clear();
isw.fill(sequence);
}
/**
* <p>
* Get an object.
* </p>
* <p>
* If not found or of type incompatible with fallback, fallback is returned.
* </p>
*
* @param key
* @param fallback value
* @return value
*/
public <T> T get(String key, T fallback)
{
try {
final T itm = (T) backingMap.get(key);
if (itm == null) return fallback;
return itm;
} catch (final ClassCastException e) {
return fallback;
}
}
public void put(String key, IonBinary value)
{
if (key == null || value == null) return;
backingMap.put(key, value);
}
public void put(String key, boolean value)
{
backingMap.put(key, value);
}
public void put(String key, char value)
{
backingMap.put(key, value);
}
public void put(String key, short value)
{
backingMap.put(key, value);
}
public void put(String key, int value)
{
backingMap.put(key, value);
}
public void put(String key, long value)
{
backingMap.put(key, value);
}
public void put(String key, double value)
{
backingMap.put(key, value);
}
public void put(String key, float value)
{
backingMap.put(key, value);
}
public void put(String key, String value)
{
backingMap.put(key, value);
}
public void put(String key, boolean[] value)
{
backingMap.put(key, value);
}
public void put(String key, char[] value)
{
backingMap.put(key, value);
}
public void put(String key, short[] value)
{
backingMap.put(key, value);
}
public void put(String key, int[] value)
{
backingMap.put(key, value);
}
public void put(String key, long[] value)
{
backingMap.put(key, value);
}
public void put(String key, double[] value)
{
backingMap.put(key, value);
}
public void put(String key, float[] value)
{
backingMap.put(key, value);
}
public void put(String key, String[] value)
{
backingMap.put(key, value);
}
@SuppressWarnings("rawtypes")
public void putSequence(String key, Collection c)
{
backingMap.put(key, new IonSequenceWrapper(c));
}
@SuppressWarnings("rawtypes")
public void putMap(String key, Map m)
{
backingMap.put(key, new IonMapWrapper(m));
}
@Override
public short getIonMark()
{
return Ion.DATA_BUNDLE;
}
@Override
public void load(IonInput in) throws IOException
{
in.readMap(backingMap);
}
@Override
public void save(IonOutput out) throws IOException
{
out.writeMap(backingMap);
}
public int size()
{
return backingMap.size();
}
public boolean isEmpty()
{
return backingMap.isEmpty();
}
public void clear()
{
backingMap.clear();
}
public Object remove(Object key)
{
return backingMap.remove(key);
}
@Override
public String toString()
{
return backingMap.toString();
}
@Override
public boolean equals(Object o)
{
return backingMap.equals(o);
}
@Override
public int hashCode()
{
return 47 ^ backingMap.hashCode();
}
}
+18
View File
@@ -0,0 +1,18 @@
package mightypork.util.ion;
import java.io.IOException;
/**
* Bundled ion object
*
* @author MightyPork
*/
public interface IonBundled {
void load(IonBundle bundle) throws IOException;
void save(IonBundle bundle) throws IOException;
}
+439
View File
@@ -0,0 +1,439 @@
package mightypork.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.util.error.CorruptedDataException;
/**
* 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;
}
public IonBundle readBundle() throws IOException
{
return (IonBundle) readObject();
}
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)) {
IonBinary 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 CorruptedDataException("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 CorruptedDataException("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 CorruptedDataException("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 CorruptedDataException("Unexpected element type in map.", e);
}
}
}
@@ -0,0 +1,55 @@
package mightypork.util.ion;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class IonMapWrapper implements IonBinary {
private final Map map;
public IonMapWrapper()
{
map = new HashMap();
}
public IonMapWrapper(Map saved)
{
map = saved;
}
@Override
public void load(IonInput in) throws IOException
{
map.clear();
in.readMap(map);
}
@Override
public void save(IonOutput out) throws IOException
{
out.writeMap(map);
}
public void fill(Map o)
{
o.clear();
o.putAll(map);
}
@Override
public short getIonMark()
{
return Ion.MAP_WRAPPER;
}
}
+383
View File
@@ -0,0 +1,383 @@
package mightypork.util.ion;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import mightypork.util.logging.Log;
/**
* Ion output stream
*
* @author MightyPork
*/
public class IonOutput {
private final DataOutput out;
public IonOutput(OutputStream out)
{
this.out = new DataOutputStream(out);
}
public void writeBoolean(boolean a) throws IOException
{
out.writeBoolean(a);
}
public void writeByte(int a) throws IOException
{
out.writeByte(a);
}
public void writeShort(int a) throws IOException
{
out.writeShort(a);
}
public void writeChar(int a) throws IOException
{
out.writeChar(a);
}
public void writeInt(int a) throws IOException
{
out.writeInt(a);
}
public void writeIntShort(int a) throws IOException
{
out.writeShort(a);
}
public void writeIntByte(int a) throws IOException
{
out.writeByte(a);
}
public void writeLong(long a) throws IOException
{
out.writeLong(a);
}
public void writeFloat(float a) throws IOException
{
out.writeFloat(a);
}
public void writeDouble(double a) throws IOException
{
out.writeDouble(a);
}
public void writeBytes(String a) throws IOException
{
out.writeBytes(a);
}
public void writeString(String a) throws IOException
{
out.writeUTF(a);
}
public void writeBooleans(boolean[] arr) throws IOException
{
writeLength(arr.length);
for (final boolean a : arr) {
out.writeBoolean(a);
}
}
public void writeBytes(byte[] arr) throws IOException
{
writeLength(arr.length);
for (final byte a : arr) {
out.writeByte(a);
}
}
public void writeChars(char[] arr) throws IOException
{
writeLength(arr.length);
for (final char a : arr) {
out.writeChar(a);
}
}
public void writeShorts(short[] arr) throws IOException
{
writeLength(arr.length);
for (final short a : arr) {
out.writeShort(a);
}
}
public void writeInts(int[] arr) throws IOException
{
writeLength(arr.length);
for (final int a : arr) {
out.writeInt(a);
}
}
public void writeLongs(long[] arr) throws IOException
{
writeLength(arr.length);
for (final long a : arr) {
out.writeLong(a);
}
}
public void writeFloats(float[] arr) throws IOException
{
writeLength(arr.length);
for (final float a : arr) {
out.writeFloat(a);
}
}
public void writeDoubles(double[] arr) throws IOException
{
writeLength(arr.length);
for (final double a : arr) {
out.writeDouble(a);
}
}
public void writeStrings(String[] arr) throws IOException
{
writeLength(arr.length);
for (final String a : arr) {
out.writeUTF(a);
}
}
public void writeBundle(IonBundle bundle) throws IOException
{
writeObject(bundle);
}
/**
* Write array of objects. Supported are Ionizables, primitive types,
* String, and their arrays.
*
* @param arr array to write
* @throws IOException on IO error or on invalid object type.
*/
public void writeObjects(Object[] arr) throws IOException
{
writeLength(arr.length);
for (final Object a : arr) {
writeObject(a);
}
}
public <T> void writeSequence(Collection<T> sequence) throws IOException
{
for (final T element : sequence) {
writeMark(Ion.ENTRY);
writeObject(element);
}
writeMark(Ion.END);
}
public <K, V> void writeMap(Map<K, V> map) throws IOException
{
for (final Entry<K, V> e : map.entrySet()) {
if (e.getValue() == null) {
continue;
}
writeMark(Ion.ENTRY);
writeObject(e.getKey());
writeObject(e.getValue());
}
writeMark(Ion.END);
}
private void writeMark(int mark) throws IOException
{
writeIntByte(mark);
}
private void writeLength(int length) throws IOException
{
writeIntShort(length);
}
/**
* Write an object. Supported are Ionizable, primitive types, String, and
* their arrays.
*
* @param obj obj to write
* @throws IOException on IO error or invalid object type.
*/
public void writeObject(Object obj) throws IOException
{
if (obj == null) {
writeMark(Ion.NULL);
return;
}
if (obj instanceof IonBinary) {
final IonBinary ionObject = (IonBinary) obj;
Ion.assertRegistered(ionObject);
writeMark(ionObject.getIonMark());
ionObject.save(this);
return;
}
if (obj instanceof IonBundled) {
throw new IOException("Bundled objects cannot be written to ION stream directly.");
}
if (obj instanceof Boolean) {
writeMark(Ion.BOOLEAN);
writeBoolean((Boolean) obj);
return;
}
if (obj instanceof Byte) {
writeMark(Ion.BYTE);
writeByte((Byte) obj);
return;
}
if (obj instanceof Character) {
writeMark(Ion.CHAR);
writeChar((Character) obj);
return;
}
if (obj instanceof Short) {
writeMark(Ion.SHORT);
writeShort((Short) obj);
return;
}
if (obj instanceof Integer) {
writeMark(Ion.INT);
writeInt((Integer) obj);
return;
}
if (obj instanceof Long) {
writeMark(Ion.LONG);
writeLong((Long) obj);
return;
}
if (obj instanceof Float) {
writeMark(Ion.FLOAT);
writeFloat((Float) obj);
return;
}
if (obj instanceof Double) {
writeMark(Ion.DOUBLE);
writeDouble((Double) obj);
return;
}
if (obj instanceof String) {
writeMark(Ion.STRING);
writeString((String) obj);
return;
}
if (obj instanceof boolean[]) {
writeMark(Ion.BOOLEAN_ARRAY);
writeBooleans((boolean[]) obj);
return;
}
if (obj instanceof byte[]) {
writeMark(Ion.BYTE_ARRAY);
writeBytes((byte[]) obj);
return;
}
if (obj instanceof char[]) {
writeMark(Ion.CHAR_ARRAY);
writeChars((char[]) obj);
return;
}
if (obj instanceof short[]) {
writeMark(Ion.SHORT_ARRAY);
writeShorts((short[]) obj);
return;
}
if (obj instanceof int[]) {
writeMark(Ion.INT_ARRAY);
writeInts((int[]) obj);
return;
}
if (obj instanceof long[]) {
writeMark(Ion.LONG_ARRAY);
writeLongs((long[]) obj);
return;
}
if (obj instanceof float[]) {
writeMark(Ion.FLOAT_ARRAY);
writeFloats((float[]) obj);
return;
}
if (obj instanceof double[]) {
writeMark(Ion.DOUBLE_ARRAY);
writeDoubles((double[]) obj);
return;
}
if (obj instanceof String[]) {
writeMark(Ion.STRING_ARRAY);
writeStrings((String[]) obj);
return;
}
throw new IOException("Object " + Log.str(obj) + " could not be be written to stream.");
}
}
@@ -0,0 +1,55 @@
package mightypork.util.ion;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class IonSequenceWrapper implements IonBinary {
private Collection collection = new ArrayList();
public IonSequenceWrapper()
{
collection = new ArrayList();
}
public IonSequenceWrapper(Collection saved)
{
collection = saved;
}
@Override
public void load(IonInput in) throws IOException
{
collection.clear();
in.readSequence(collection);
}
@Override
public void save(IonOutput out) throws IOException
{
out.writeSequence(collection);
}
public void fill(Collection o)
{
o.clear();
o.addAll(collection);
}
@Override
public short getIonMark()
{
return Ion.SEQUENCE_WRAPPER;
}
}