Reworked ION

v5stable
Ondřej Hruška 11 years ago
parent e83047ff38
commit 035aa58847
  1. 81
      src/mightypork/util/files/ion/AbstractIonList.java
  2. 100
      src/mightypork/util/files/ion/AbstractIonMap.java
  3. 235
      src/mightypork/util/files/ion/BinaryUtils.java
  4. 547
      src/mightypork/util/files/ion/Ion.java
  5. 157
      src/mightypork/util/files/ion/IonDataBundle.java
  6. 169
      src/mightypork/util/files/ion/IonDataList.java
  7. 25
      src/mightypork/util/files/ion/IonException.java
  8. 169
      src/mightypork/util/files/ion/IonList.java
  9. 170
      src/mightypork/util/files/ion/IonMap.java
  10. 57
      src/mightypork/util/files/ion/IonMarks.java
  11. 13
      src/mightypork/util/files/ion/Ionizable.java
  12. 17
      src/mightypork/util/files/ion/IonizableOptional.java

@ -1,81 +0,0 @@
package mightypork.util.files.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
/**
* Ionizable Arraylist
*
* @author MightyPork
* @param <T>
*/
public abstract class AbstractIonList<T> extends ArrayList<T> implements Ionizable {
@Override
public void ionRead(InputStream in) throws IonException
{
try {
while (true) {
final byte b = BinaryUtils.readByte(in);
if (b == IonMarks.ENTRY) {
final T value = (T) Ion.readObject(in);
add(value);
} else if (b == IonMarks.END) {
break;
} else {
throw new IonException("Unexpected mark in IonList: " + Integer.toHexString(b));
}
}
ionReadCustomData(in);
} catch (final IOException e) {
throw new IonException("Error reading ion list", e);
}
}
@Override
public void ionWrite(OutputStream out) throws IonException
{
try {
for (final T entry : this) {
if (entry instanceof IonizableOptional && !((IonizableOptional) entry).ionShouldSave()) continue;
BinaryUtils.writeByte(out, IonMarks.ENTRY);
Ion.writeObject(out, entry);
}
BinaryUtils.writeByte(out, IonMarks.END);
ionWriteCustomData(out);
} catch (final IOException e) {
throw new IonException("Error reading ion map", e);
}
}
/**
* Read custom data of this AbstractIonList implementation
*
* @param in input stream
*/
public void ionReadCustomData(InputStream in)
{
}
/**
* Write custom data of this AbstractIonList implementation
*
* @param out output stream
*/
public void ionWriteCustomData(OutputStream out)
{
}
@Override
public abstract byte ionMark();
}

@ -1,100 +0,0 @@
package mightypork.util.files.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
/**
* Ionizable HashMap
*
* @author MightyPork
* @param <V>
*/
public abstract class AbstractIonMap<V> extends LinkedHashMap<String, V> implements Ionizable {
@Override
public V get(Object key)
{
return super.get(key);
}
@Override
public V put(String key, V value)
{
return super.put(key, value);
}
@Override
public void ionRead(InputStream in) throws IonException
{
try {
while (true) {
final byte b = BinaryUtils.readByte(in);
if (b == IonMarks.ENTRY) {
final String key = BinaryUtils.readString(in);
final V value = (V) Ion.readObject(in);
put(key, value);
} else if (b == IonMarks.END) {
break;
} else {
throw new RuntimeException("Unexpected mark in IonMap: " + Integer.toHexString(b));
}
}
ionReadCustomData(in);
} catch (final IOException e) {
throw new IonException("Error reading ion map", e);
}
}
@Override
public void ionWrite(OutputStream out) throws IonException
{
try {
for (final java.util.Map.Entry<String, V> entry : entrySet()) {
BinaryUtils.writeByte(out, IonMarks.ENTRY);
BinaryUtils.writeString(out, entry.getKey());
Ion.writeObject(out, entry.getValue());
}
BinaryUtils.writeByte(out, IonMarks.END);
ionWriteCustomData(out);
} catch (final IOException e) {
throw new IonException("Error reading ion map", e);
}
}
/**
* Read custom data of this AbstractIonMap implementation
*
* @param in input stream
*/
public void ionReadCustomData(InputStream in)
{
}
/**
* Write custom data of this AbstractIonMap implementation
*
* @param out output stream
*/
public void ionWriteCustomData(OutputStream out)
{
}
@Override
public byte ionMark()
{
return IonMarks.MAP;
}
}

@ -1,235 +0,0 @@
package mightypork.util.files.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/**
* Utilities to store and load objects to streams.
*
* @author MightyPork
*/
public class BinaryUtils {
private static ByteBuffer bi = ByteBuffer.allocate(Integer.SIZE / 8);
private static ByteBuffer bd = ByteBuffer.allocate(Double.SIZE / 8);
private static ByteBuffer bf = ByteBuffer.allocate(Float.SIZE / 8);
private static ByteBuffer bc = ByteBuffer.allocate(Character.SIZE / 8);
private static ByteBuffer bl = ByteBuffer.allocate(Long.SIZE / 8);
private static ByteBuffer bs = ByteBuffer.allocate(Short.SIZE / 8);
private static byte[] ai = new byte[Integer.SIZE / 8];
private static byte[] ad = new byte[Double.SIZE / 8];
private static byte[] af = new byte[Float.SIZE / 8];
private static byte[] ac = new byte[Character.SIZE / 8];
private static byte[] al = new byte[Long.SIZE / 8];
private static byte[] as = new byte[Short.SIZE / 8];
// CONVERSIONS
public static byte[] getBytesBool(boolean bool)
{
return new byte[] { (byte) (bool ? 1 : 0) };
}
public static byte[] getBytesByte(byte num)
{
return new byte[] { num };
}
public static byte[] getBytesChar(char num)
{
bc.clear();
bc.putChar(num);
return bc.array();
}
public static byte[] getBytesShort(short num)
{
bs.clear();
bs.putShort(num);
return bs.array();
}
public static byte[] getBytesInt(int num)
{
bi.clear();
bi.putInt(num);
return bi.array();
}
public static byte[] getBytesLong(long num)
{
bl.clear();
bl.putLong(num);
return bl.array();
}
public static byte[] getBytesFloat(float num)
{
bf.clear();
bf.putFloat(num);
return bf.array();
}
public static byte[] getBytesDouble(double num)
{
bd.clear();
bd.putDouble(num);
return bd.array();
}
public static byte[] getBytesString(String str)
{
final char[] chars = str.toCharArray();
final ByteBuffer bstr = ByteBuffer.allocate((Character.SIZE / 8) * chars.length + (Character.SIZE / 8));
for (final char c : chars) {
bstr.putChar(c);
}
bstr.putChar((char) 0);
return bstr.array();
}
public static void writeBoolean(OutputStream out, boolean num) throws IOException
{
out.write(getBytesBool(num));
}
public static void writeByte(OutputStream out, byte num) throws IOException
{
out.write(getBytesByte(num));
}
public static void writeChar(OutputStream out, char num) throws IOException
{
out.write(getBytesChar(num));
}
public static void writeShort(OutputStream out, short num) throws IOException
{
out.write(getBytesShort(num));
}
public static void writeInt(OutputStream out, int num) throws IOException
{
out.write(getBytesInt(num));
}
public static void writeLong(OutputStream out, long num) throws IOException
{
out.write(getBytesLong(num));
}
public static void writeFloat(OutputStream out, float num) throws IOException
{
out.write(getBytesFloat(num));
}
public static void writeDouble(OutputStream out, double num) throws IOException
{
out.write(getBytesDouble(num));
}
public static void writeString(OutputStream out, String str) throws IOException
{
out.write(getBytesString(str));
}
// READING
public static boolean readBoolean(InputStream in) throws IOException
{
return in.read() > 0;
}
public static byte readByte(InputStream in) throws IOException
{
return (byte) in.read();
}
public static char readChar(InputStream in) throws IOException
{
if (-1 == in.read(ac, 0, ac.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(ac);
return buf.getChar();
}
public static short readShort(InputStream in) throws IOException
{
if (-1 == in.read(as, 0, as.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(as);
return buf.getShort();
}
public static long readLong(InputStream in) throws IOException
{
if (-1 == in.read(al, 0, al.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(al);
return buf.getLong();
}
public static int readInt(InputStream in) throws IOException
{
if (-1 == in.read(ai, 0, ai.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(ai);
return buf.getInt();
}
public static float readFloat(InputStream in) throws IOException
{
if (-1 == in.read(af, 0, af.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(af);
return buf.getFloat();
}
public static double readDouble(InputStream in) throws IOException
{
if (-1 == in.read(ad, 0, ad.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(ad);
return buf.getDouble();
}
public static String readString(InputStream in) throws IOException
{
String s = "";
char c;
while ((c = readChar(in)) > 0) {
s += c;
}
return s;
}
}

@ -2,10 +2,11 @@ package mightypork.util.files.ion;
import java.io.*; import java.io.*;
import java.nio.ByteBuffer;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import mightypork.util.math.Calc; import mightypork.util.logging.Log;
/** /**
@ -15,46 +16,117 @@ import mightypork.util.math.Calc;
*/ */
public class Ion { public class Ion {
/*
* 0-29 ... primitive and Java built-in types
* 30-59 ... technical marks
* 60-99 ... built-in ION types
*/
// primitives
/** Null mark (for internal use) */
private static final short NULL = 0;
/** Boolean mark (for internal use) */
private static final short BOOLEAN = 1;
/** Byte mark (for internal use) */
private static final short BYTE = 2;
/** Character mark (for internal use) */
private static final short CHAR = 3;
/** Short mark (for internal use) */
private static final short SHORT = 4;
/** Integer mark (for internal use) */
private static final short INT = 5;
/** Long mark (for internal use) */
private static final short LONG = 6;
/** Float mark (for internal use) */
private static final short FLOAT = 7;
/** Double mark (for internal use) */
private static final short DOUBLE = 8;
/** String mark (for internal use) */
private static final short STRING = 9;
// technical
/**
* Entry mark - general purpose, marks an entry in sequence of objects. Used
* to indicate that the sequence continues wityh another element.
*/
public static final short ENTRY = 30;
/**
* Start mark - general purpose, marks start of a sequence of stored
* objects.
*/
public static final short START = 31;
/**
* End mark - general purpose, marks end of sequence of stored objects.
*/
public static final short END = 32;
/**
* Length mark, indicating length of something (such as array) - general
* purpose
*/
public static final short LENGTH = 33;
// built in
/** Map mark (built-in data structure) */
static final short DATA_BUNDLE = 60;
/** List mark (built-in data structure) */
static final short DATA_LIST = 61;
/** Ionizables<Mark, Class> */ /** Ionizables<Mark, Class> */
private static Map<Byte, Class<?>> customIonizables = new HashMap<>(); private static Map<Short, Class<?>> customIonizables = new HashMap<>();
// buffers and helper arrays for storing to streams.
private static ByteBuffer bi = ByteBuffer.allocate(Integer.SIZE / 8);
private static ByteBuffer bd = ByteBuffer.allocate(Double.SIZE / 8);
private static ByteBuffer bf = ByteBuffer.allocate(Float.SIZE / 8);
private static ByteBuffer bc = ByteBuffer.allocate(Character.SIZE / 8);
private static ByteBuffer bl = ByteBuffer.allocate(Long.SIZE / 8);
private static ByteBuffer bs = ByteBuffer.allocate(Short.SIZE / 8);
private static byte[] ai = new byte[Integer.SIZE / 8];
private static byte[] ad = new byte[Double.SIZE / 8];
private static byte[] af = new byte[Float.SIZE / 8];
private static byte[] ac = new byte[Character.SIZE / 8];
private static byte[] al = new byte[Long.SIZE / 8];
private static byte[] as = new byte[Short.SIZE / 8];
/**
* Indicates whether range checking should be performed when registering
* marks.
*/
private static boolean safety;
// register default ionizables
static { static {
try { // register default ionizables
registerIonizable(IonMarks.MAP, IonMap.class); safety = false;
registerIonizable(IonMarks.LIST, IonList.class); registerIonizable(Ion.DATA_BUNDLE, IonDataBundle.class);
} catch (final IonException e) { registerIonizable(Ion.DATA_LIST, IonDataList.class);
e.printStackTrace(); safety = true;
}
} }
/** /**
* Register new Ionizable for direct reconstructing. * Register new Ionizable for direct reconstructing.
* *
* @param mark byte mark to be used, see {@link IonMarks} for reference. * @param mark mark to be used. Numbers 0..99 are reserved.
* @param objClass class of the registered Ionizable * @param objClass class of the registered Ionizable
* @throws IonException
*/ */
public static void registerIonizable(byte mark, Class<?> objClass) throws IonException public static void registerIonizable(short mark, Class<?> objClass)
{ {
if (customIonizables.containsKey(mark)) { // negative marks are allowed.
throw new IonException("IonMark " + mark + " is already used.");
} if (safety && mark >= 0 && mark < 100) {
customIonizables.put(mark, objClass); throw new RuntimeException("Marks 0..99 are reserved.");
} }
if (customIonizables.containsKey(mark)) {
throw new RuntimeException("Mark " + mark + " is already in use.");
}
/** customIonizables.put(mark, objClass);
* Load Ion object from file.
*
* @param file file path
* @return the loaded object
* @throws IonException
*/
public static Object fromFile(String file) throws IonException
{
return fromFile(new File(file));
} }
@ -63,9 +135,9 @@ public class Ion {
* *
* @param file file * @param file file
* @return the loaded object * @return the loaded object
* @throws IonException on failure * @throws IOException on failure
*/ */
public static Object fromFile(File file) throws IonException public static Object fromFile(File file) throws IOException
{ {
try(InputStream in = new FileInputStream(file)) { try(InputStream in = new FileInputStream(file)) {
@ -73,7 +145,7 @@ public class Ion {
return obj; return obj;
} catch (final IOException e) { } catch (final IOException e) {
throw new IonException("Error loading ION file.", e); throw new IOException("Error loading ION file.", e);
} }
} }
@ -83,9 +155,9 @@ public class Ion {
* *
* @param in input stream * @param in input stream
* @return the loaded object * @return the loaded object
* @throws IonException * @throws IOException
*/ */
public static Object fromStream(InputStream in) throws IonException public static Object fromStream(InputStream in) throws IOException
{ {
return readObject(in); return readObject(in);
} }
@ -96,22 +168,9 @@ public class Ion {
* *
* @param path file path * @param path file path
* @param obj object to store * @param obj object to store
* @throws IonException * @throws IOException
*/
public static void toFile(String path, Object obj) throws IonException
{
toFile(new File(path), obj);
}
/**
* Store Ion object to file.
*
* @param path file path
* @param obj object to store
* @throws IonException
*/ */
public static void toFile(File path, Object obj) throws IonException public static void toFile(File path, Object obj) throws IOException
{ {
try(OutputStream out = new FileOutputStream(path)) { try(OutputStream out = new FileOutputStream(path)) {
final String f = path.toString(); final String f = path.toString();
@ -119,81 +178,95 @@ public class Ion {
if (!dir.mkdirs()) throw new IOException("Could not create file."); if (!dir.mkdirs()) throw new IOException("Could not create file.");
toStream(out, obj); writeObject(out, obj);
out.flush(); out.flush();
out.close(); out.close();
} catch (final Exception e) { } catch (final Exception e) {
throw new IonException("Error writing to ION file.", e); throw new IOException("Error writing to ION file.", e);
} }
} }
/** /**
* Store Ion object to output stream. * Read single object from input stream
*
* @param out output stream *
* @param obj object to store
* @throws IonException
*/
public static void toStream(OutputStream out, Object obj) throws IonException
{
writeObject(out, obj);
}
/**
* Read single ionizable or primitive object from input stream
* *
* @param in input stream * @param in input stream
* @return the loaded object * @return the loaded object
* @throws IonException * @throws IOException
*/ */
public static Object readObject(InputStream in) throws IonException public static Object readObject(InputStream in) throws IOException
{ {
try { try {
final int bi = in.read(); final short mark = readMark(in);
if (bi == -1) throw new IonException("Unexpected end of stream."); if (customIonizables.containsKey(mark)) {
final byte b = (byte) bi; Ionizable ionObj;
if (customIonizables.containsKey(b)) {
Ionizable ion;
try { try {
ion = ((Ionizable) customIonizables.get(b).newInstance()); ionObj = ((Ionizable) customIonizables.get(mark).newInstance());
} catch (final InstantiationException e) { } catch (InstantiationException | IllegalAccessException e) {
throw new IonException("Cound not instantiate " + customIonizables.get(b).getSimpleName(), e); throw new IOException("Cound not instantiate: " + Log.str(customIonizables.get(mark)), e);
} catch (final IllegalAccessException e) { }
throw new IonException("Cound not instantiate " + customIonizables.get(b).getSimpleName(), e);
} ionObj.loadFrom(in);
ion.ionRead(in); return ionObj;
return ion; }
}
switch (mark) {
switch (b) { case Ion.NULL:
case IonMarks.BOOLEAN: return null;
return BinaryUtils.readBoolean(in);
case IonMarks.BYTE: case Ion.BOOLEAN:
return BinaryUtils.readByte(in); return readBoolean(in);
case IonMarks.CHAR:
return BinaryUtils.readChar(in); case Ion.BYTE:
case IonMarks.SHORT: return readByte(in);
return BinaryUtils.readShort(in);
case IonMarks.INT: case Ion.CHAR:
return BinaryUtils.readInt(in); return readChar(in);
case IonMarks.LONG:
return BinaryUtils.readLong(in); case Ion.SHORT:
case IonMarks.FLOAT: return readShort(in);
return BinaryUtils.readFloat(in);
case IonMarks.DOUBLE: case Ion.INT:
return BinaryUtils.readDouble(in); return readInt(in);
case IonMarks.STRING:
final String s = BinaryUtils.readString(in); case Ion.LONG:
return readLong(in);
case Ion.FLOAT:
return readFloat(in);
case Ion.DOUBLE:
return readDouble(in);
case Ion.STRING:
final String s = readString(in);
return s; return s;
default: default:
throw new IonException("Invalid Ion mark " + Integer.toHexString(bi)); throw new IOException("Invalid Ion mark: " + mark);
} }
} catch (final IOException e) { } catch (final IOException e) {
throw new IonException("Error loading ION file: ", e); throw new IOException("Error loading ION file: ", e);
}
}
public static void expect(InputStream in, short mark) throws IOException
{
if (readMark(in) != mark) throw new IOException("Unexpected mark in ION stream.");
}
public static short readMark(InputStream in) throws IOException
{
return readShort(in);
} }
public static void writeMark(OutputStream out, short mark) throws IOException
{
writeShort(out, mark);
} }
@ -202,76 +275,302 @@ public class Ion {
* *
* @param out output stream * @param out output stream
* @param obj stored object * @param obj stored object
* @throws IonException * @throws IOException
*/ */
public static void writeObject(OutputStream out, Object obj) throws IonException public static void writeObject(OutputStream out, Object obj) throws IOException
{ {
try { try {
if (obj instanceof Ionizable) { if (obj instanceof Ionizable) {
out.write(((Ionizable) obj).ionMark()); writeMark(out, ((Ionizable) obj).getIonMark());
((Ionizable) obj).ionWrite(out); ((Ionizable) obj).saveTo(out);
return; return;
} }
if (obj instanceof Boolean) { if (obj instanceof Boolean) {
out.write(IonMarks.BOOLEAN); writeMark(out, Ion.BOOLEAN);
BinaryUtils.writeBoolean(out, (Boolean) obj); writeBoolean(out, (Boolean) obj);
return; return;
} }
if (obj instanceof Byte) { if (obj instanceof Byte) {
out.write(IonMarks.BYTE); writeMark(out, Ion.BYTE);
BinaryUtils.writeByte(out, (Byte) obj); writeByte(out, (Byte) obj);
return; return;
} }
if (obj instanceof Character) { if (obj instanceof Character) {
out.write(IonMarks.CHAR); writeMark(out, Ion.CHAR);
BinaryUtils.writeChar(out, (Character) obj); writeChar(out, (Character) obj);
return; return;
} }
if (obj instanceof Short) { if (obj instanceof Short) {
out.write(IonMarks.SHORT); writeMark(out, Ion.SHORT);
BinaryUtils.writeShort(out, (Short) obj); writeShort(out, (Short) obj);
return; return;
} }
if (obj instanceof Integer) { if (obj instanceof Integer) {
out.write(IonMarks.INT); writeMark(out, Ion.INT);
BinaryUtils.writeInt(out, (Integer) obj); writeInt(out, (Integer) obj);
return; return;
} }
if (obj instanceof Long) { if (obj instanceof Long) {
out.write(IonMarks.LONG); writeMark(out, Ion.LONG);
BinaryUtils.writeLong(out, (Long) obj); writeLong(out, (Long) obj);
return; return;
} }
if (obj instanceof Float) { if (obj instanceof Float) {
out.write(IonMarks.FLOAT); writeMark(out, Ion.FLOAT);
BinaryUtils.writeFloat(out, (Float) obj); writeFloat(out, (Float) obj);
return; return;
} }
if (obj instanceof Double) { if (obj instanceof Double) {
out.write(IonMarks.DOUBLE); writeMark(out, Ion.DOUBLE);
BinaryUtils.writeDouble(out, (Double) obj); writeDouble(out, (Double) obj);
return; return;
} }
if (obj instanceof String) { if (obj instanceof String) {
out.write(IonMarks.STRING); writeMark(out, Ion.STRING);
BinaryUtils.writeString(out, (String) obj); writeString(out, (String) obj);
return; return;
} }
throw new IonException(Calc.cname(obj) + " can't be stored in Ion storage."); throw new IOException("Object " + Log.str(obj) + " could not be be ionized.");
} catch (final IOException e) { } catch (final IOException e) {
throw new IonException("Could not store " + obj, e); throw new IOException("Could not store: " + obj, e);
}
}
private static byte[] getBytesBool(boolean bool)
{
return new byte[] { (byte) (bool ? 1 : 0) };
}
private static byte[] getBytesByte(byte num)
{
return new byte[] { num };
}
private static byte[] getBytesChar(char num)
{
synchronized (bc) {
bc.clear();
bc.putChar(num);
return bc.array();
}
}
private static byte[] getBytesShort(short num)
{
synchronized (bs) {
bs.clear();
bs.putShort(num);
return bs.array();
}
}
private static byte[] getBytesInt(int num)
{
synchronized (bi) {
bi.clear();
bi.putInt(num);
return bi.array();
}
}
private static byte[] getBytesLong(long num)
{
synchronized (bl) {
bl.clear();
bl.putLong(num);
return bl.array();
} }
} }
private static byte[] getBytesFloat(float num)
{
synchronized (bf) {
bf.clear();
bf.putFloat(num);
return bf.array();
}
}
private static byte[] getBytesDouble(double num)
{
synchronized (bd) {
bd.clear();
bd.putDouble(num);
return bd.array();
}
}
private static byte[] getBytesString(String str)
{
final char[] chars = str.toCharArray();
final ByteBuffer bstr = ByteBuffer.allocate((Character.SIZE / 8) * chars.length + (Character.SIZE / 8));
for (final char c : chars) {
bstr.putChar(c);
}
bstr.putChar((char) 0);
return bstr.array();
}
public static void writeBoolean(OutputStream out, boolean bool) throws IOException
{
out.write(getBytesBool(bool));
}
public static void writeByte(OutputStream out, byte b) throws IOException
{
out.write(getBytesByte(b));
}
public static void writeChar(OutputStream out, char c) throws IOException
{
out.write(getBytesChar(c));
}
public static void writeShort(OutputStream out, short s) throws IOException
{
out.write(getBytesShort(s));
}
public static void writeInt(OutputStream out, int i) throws IOException
{
out.write(getBytesInt(i));
}
public static void writeLong(OutputStream out, long l) throws IOException
{
out.write(getBytesLong(l));
}
public static void writeFloat(OutputStream out, float f) throws IOException
{
out.write(getBytesFloat(f));
}
public static void writeDouble(OutputStream out, double d) throws IOException
{
out.write(getBytesDouble(d));
}
public static void writeString(OutputStream out, String str) throws IOException
{
out.write(getBytesString(str));
}
public static boolean readBoolean(InputStream in) throws IOException
{
return readByte(in) > 0;
}
public static byte readByte(InputStream in) throws IOException
{
int b = in.read();
if (-1 == b) throw new IOException("End of stream.");
return (byte) b;
}
public static char readChar(InputStream in) throws IOException
{
synchronized (ac) {
if (-1 == in.read(ac, 0, ac.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(ac);
return buf.getChar();
}
}
public static short readShort(InputStream in) throws IOException
{
synchronized (as) {
if (-1 == in.read(as, 0, as.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(as);
return buf.getShort();
}
}
public static long readLong(InputStream in) throws IOException
{
synchronized (al) {
if (-1 == in.read(al, 0, al.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(al);
return buf.getLong();
}
}
public static int readInt(InputStream in) throws IOException
{
synchronized (ai) {
if (-1 == in.read(ai, 0, ai.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(ai);
return buf.getInt();
}
}
public static float readFloat(InputStream in) throws IOException
{
synchronized (af) {
if (-1 == in.read(af, 0, af.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(af);
return buf.getFloat();
}
}
public static double readDouble(InputStream in) throws IOException
{
synchronized (ad) {
if (-1 == in.read(ad, 0, ad.length)) throw new IOException("End of stream.");
final ByteBuffer buf = ByteBuffer.wrap(ad);
return buf.getDouble();
}
}
public static String readString(InputStream in) throws IOException
{
String s = "";
char c;
while ((c = readChar(in)) > 0) {
s += c;
}
return s;
}
} }

@ -0,0 +1,157 @@
package mightypork.util.files.ion;
/**
* Ionizable HashMap
*
* @author MightyPork
*/
public class IonDataBundle extends IonMap<String, Object> {
public boolean getBoolean(String key)
{
return (Boolean) get(key);
}
public boolean getBool(String key)
{
return (Boolean) get(key);
}
public byte getByte(String key)
{
return (Byte) get(key);
}
public char getChar(String key)
{
return (Character) get(key);
}
public short getShort(String key)
{
return (Short) get(key);
}
public int getInt(String key)
{
return (Integer) get(key);
}
public long getLong(String key)
{
return (Long) get(key);
}
public float getFloat(String key)
{
return (Float) get(key);
}
public double getDouble(String key)
{
return (Double) get(key);
}
public String getString(String key)
{
return (String) get(key);
}
@Override
public Object get(Object arg0)
{
return super.get(arg0);
}
public void putBoolean(String key, boolean num)
{
put(key, num);
}
public void putBool(String key, boolean num)
{
put(key, num);
}
public void putByte(String key, int num)
{
put(key, (byte) num);
}
public void putChar(String key, char num)
{
put(key, num);
}
public void putCharacter(String key, char num)
{
put(key, num);
}
public void putShort(String key, int num)
{
put(key, num);
}
public void putInt(String key, int num)
{
put(key, num);
}
public void putInteger(String key, int num)
{
put(key, num);
}
public void putLong(String key, long num)
{
put(key, num);
}
public void putFloat(String key, double num)
{
put(key, (float) num);
}
public void putDouble(String key, double num)
{
put(key, num);
}
public void putString(String key, String num)
{
put(key, num);
}
@Override
public short getIonMark()
{
return Ion.DATA_BUNDLE;
}
}

@ -0,0 +1,169 @@
package mightypork.util.files.ion;
import java.io.IOException;
/**
* Ionizable Arraylist
*
* @author MightyPork
*/
public class IonDataList extends IonList<Object> {
public Ionizable getIonizable(int index) throws IOException
{
return (Ionizable) getOfType(index, Ionizable.class);
}
public boolean getBoolean(int index) throws IOException
{
return (Boolean) getOfType(index, Boolean.class);
}
public byte getByte(int index) throws IOException
{
return (Byte) getOfType(index, Byte.class);
}
public char getChar(int index) throws IOException
{
return (Character) getOfType(index, Character.class);
}
public short getShort(int index) throws IOException
{
return (Short) getOfType(index, Short.class);
}
public int getInt(int index) throws IOException
{
return (Integer) getOfType(index, Integer.class);
}
public long getLong(int index) throws IOException
{
return (Long) getOfType(index, Long.class);
}
public float getFloat(int index) throws IOException
{
return (Float) getOfType(index, Float.class);
}
public double getDouble(int index) throws IOException
{
return (Double) getOfType(index, Double.class);
}
public String getString(int index) throws IOException
{
return (String) getOfType(index, String.class);
}
public void addIonizable(Ionizable o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addBoolean(boolean o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addByte(byte o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addChar(char o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addShort(short o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addInt(int o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addLong(long o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addFloat(float o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addDouble(double o) throws IOException
{
assertNotNull(o);
add(o);
}
public void addString(String o) throws IOException
{
assertNotNull(o);
add(o);
}
public Object getOfType(int index, Class<?> type) throws IOException
{
try {
final Object o = super.get(index);
if (o == null || !o.getClass().isAssignableFrom(type)) {
throw new IOException("Incorrect object type");
}
return o;
} catch (final IndexOutOfBoundsException e) {
throw new IOException("Out of bounds");
}
}
private static void assertNotNull(Object o) throws IOException
{
if (o == null) throw new IOException("Cannot store null");
}
@Override
public short getIonMark()
{
return Ion.DATA_LIST;
}
}

@ -1,25 +0,0 @@
package mightypork.util.files.ion;
public class IonException extends Exception {
public IonException() {
super();
}
public IonException(String message, Throwable cause) {
super(message, cause);
}
public IonException(String message) {
super(message);
}
public IonException(Throwable cause) {
super(cause);
}
}

@ -1,157 +1,80 @@
package mightypork.util.files.ion; package mightypork.util.files.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
/** /**
* Ionizable Arraylist * Ionizable Arraylist
* *
* @author MightyPork * @author MightyPork
* @param <T>
*/ */
public class IonList extends AbstractIonList<Object> { public abstract class IonList<T> extends ArrayList<T> implements Ionizable {
public Ionizable getIonizable(int index) throws IonException
{
return (Ionizable) getCheckType(index, Ionizable.class);
}
public boolean getBoolean(int index) throws IonException
{
return (Boolean) getCheckType(index, Boolean.class);
}
public byte getByte(int index) throws IonException
{
return (Byte) getCheckType(index, Byte.class);
}
public char getChar(int index) throws IonException
{
return (Character) getCheckType(index, Character.class);
}
public short getShort(int index) throws IonException
{
return (Short) getCheckType(index, Short.class);
}
public int getInt(int index) throws IonException
{
return (Integer) getCheckType(index, Integer.class);
}
public long getLong(int index) throws IonException
{
return (Long) getCheckType(index, Long.class);
}
public float getFloat(int index) throws IonException
{
return (Float) getCheckType(index, Float.class);
}
public double getDouble(int index) throws IonException
{
return (Double) getCheckType(index, Double.class);
}
public String getString(int index) throws IonException
{
return (String) getCheckType(index, String.class);
}
public void addIonizable(Ionizable o) throws IonException @Override
public void loadFrom(InputStream in) throws IOException
{ {
assertNotNull(o); try {
} while (true) {
final short mark = Ion.readMark(in);
public void addBoolean(boolean o) throws IonException if (mark == Ion.ENTRY) {
{ final T value = (T) Ion.readObject(in);
assertNotNull(o); add(value);
} else if (mark == Ion.END) {
break;
} else {
throw new IOException("Unexpected mark in IonList: " + mark);
} }
public void addByte(byte o) throws IonException
{
assertNotNull(o);
} }
readCustomData(in);
} catch (final IOException e) {
public void addChar(char o) throws IonException throw new IOException("Error reading ion list", e);
{
assertNotNull(o);
} }
public void addShort(short o) throws IonException
{
assertNotNull(o);
}
public void addInt(int o) throws IonException
{
assertNotNull(o);
} }
public void addLong(long o) throws IonException @Override
{ public void saveTo(OutputStream out) throws IOException
assertNotNull(o);
}
public void addFloat(float o) throws IonException
{ {
assertNotNull(o); try {
for (final T entry : this) {
Ion.writeMark(out, Ion.ENTRY);
Ion.writeObject(out, entry);
} }
Ion.writeMark(out, Ion.END);
writeCustomData(out);
public void addDouble(double o) throws IonException } catch (final IOException e) {
{ throw new IOException("Error reading ion map", e);
assertNotNull(o);
} }
public void addString(String o) throws IonException
{
assertNotNull(o);
} }
public Object getCheckType(int index, Class<?> type) throws IonException /**
* Read custom data of this AbstractIonList implementation
*
* @param in input stream
*/
public void readCustomData(InputStream in)
{ {
try {
final Object o = super.get(index);
if (o == null || !o.getClass().isAssignableFrom(type)) {
throw new IonException("Incorrect object type");
}
return o;
} catch (final IndexOutOfBoundsException e) {
throw new IonException("Out of bounds");
}
} }
private static void assertNotNull(Object o) throws IonException /**
* Write custom data of this AbstractIonList implementation
*
* @param out output stream
*/
public void writeCustomData(OutputStream out)
{ {
if (o == null) throw new IonException("Cannot store null");
} }
@Override @Override
public byte ionMark() public abstract short getIonMark();
{
return IonMarks.LIST;
}
} }

@ -1,156 +1,104 @@
package mightypork.util.files.ion; package mightypork.util.files.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import mightypork.util.annotations.DefaultImpl;
/** /**
* Ionizable HashMap * Ionizable HashMap
* *
* @author MightyPork * @author MightyPork
* @param <K> key
* @param <V> value
*/ */
public class IonMap extends AbstractIonMap<Object> { public abstract class IonMap<K, V> extends LinkedHashMap<K, V> implements Ionizable {
public boolean getBoolean(String key)
{
return (Boolean) get(key);
}
public boolean getBool(String key)
{
return (Boolean) get(key);
}
public byte getByte(String key)
{
return (Byte) get(key);
}
public char getChar(String key)
{
return (Character) get(key);
}
public short getShort(String key)
{
return (Short) get(key);
}
public int getInt(String key)
{
return (Integer) get(key);
}
public long getLong(String key)
{
return (Long) get(key);
}
public float getFloat(String key)
{
return (Float) get(key);
}
public double getDouble(String key)
{
return (Double) get(key);
}
public String getString(String key) @Override
public V get(Object key)
{ {
return (String) get(key); return super.get(key);
} }
@Override @Override
public Object get(Object arg0) public V put(K key, V value)
{ {
return super.get(arg0); return super.put(key, value);
} }
public void putBoolean(String key, boolean num) @Override
public void loadFrom(InputStream in) throws IOException
{ {
put(key, num); try {
} while (true) {
final short mark = Ion.readMark(in);
if (mark == Ion.ENTRY) {
final K key = (K) Ion.readObject(in);
final V value = (V) Ion.readObject(in);
put(key, value);
} else if (mark == Ion.END) {
public void putBool(String key, boolean num) break;
{ } else {
put(key, num); throw new RuntimeException("Unexpected mark in IonMap: " + mark);
} }
public void putByte(String key, int num)
{
put(key, (byte) num);
} }
readCustomData(in);
} catch (final IOException | ClassCastException e) {
public void putChar(String key, char num) throw new IOException("Error reading ion map", e);
{
put(key, num);
} }
public void putCharacter(String key, char num)
{
put(key, num);
} }
public void putShort(String key, int num) @Override
{ public void saveTo(OutputStream out) throws IOException
put(key, num);
}
public void putInt(String key, int num)
{
put(key, num);
}
public void putInteger(String key, int num)
{ {
put(key, num); try {
for (final java.util.Map.Entry<K, V> entry : entrySet()) {
Ion.writeMark(out, Ion.ENTRY);
Ion.writeObject(out, entry.getKey());
Ion.writeObject(out, entry.getValue());
} }
Ion.writeMark(out, Ion.END);
writeCustomData(out);
public void putLong(String key, long num) } catch (final IOException e) {
{ throw new IOException("Error writing ion map", e);
put(key, num);
} }
public void putFloat(String key, double num)
{
put(key, (float) num);
} }
public void putDouble(String key, double num) /**
* Read custom data of this AbstractIonMap implementation
*
* @param in input stream
*/
@DefaultImpl
public void readCustomData(InputStream in)
{ {
put(key, num);
} }
public void putString(String key, String num) /**
* Write custom data of this AbstractIonMap implementation
*
* @param out output stream
*/
@DefaultImpl
public void writeCustomData(OutputStream out)
{ {
put(key, num);
} }
@Override @Override
public byte ionMark() public short getIonMark()
{ {
return IonMarks.MAP; return Ion.DATA_BUNDLE;
} }
} }

@ -1,57 +0,0 @@
package mightypork.util.files.ion;
/**
* Byte marks used to structure data in Ion files.
*
* @author MightyPork
*/
public class IonMarks {
/** Null value */
public static final byte NULL = 0;
/** Boolean value */
public static final byte BOOLEAN = 1;
/** Byte value */
public static final byte BYTE = 2;
/** Character value */
public static final byte CHAR = 3;
/** Short value */
public static final byte SHORT = 4;
/** Integer value */
public static final byte INT = 5;
/** Long value */
public static final byte LONG = 6;
/** Float value */
public static final byte FLOAT = 7;
/** Double value */
public static final byte DOUBLE = 8;
/** String value */
public static final byte STRING = 9;
/** List value (begin) - contains entries, ends with END */
public static final byte LIST = 10;
/** Map value (begin) - contains entries, ends with END */
public static final byte MAP = 11;
/**
* List / Map entry<br>
* In list directly followed by entry value. In map followed by (string) key
* and the entry value.
*/
public static final byte ENTRY = 12;
/** End of List / Map */
public static final byte END = 13;
}

@ -1,6 +1,7 @@
package mightypork.util.files.ion; package mightypork.util.files.ion;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -19,19 +20,19 @@ public interface Ionizable {
* reading right after it. * reading right after it.
* *
* @param in input stream * @param in input stream
* @throws IonException * @throws IOException
*/ */
public void ionRead(InputStream in) throws IonException; void loadFrom(InputStream in) throws IOException;
/** /**
* Store data to output stream. mark has already been written, begin right * Store data to output stream. Mark has already been written, begin right
* after it. * after it.
* *
* @param out Output stream * @param out Output stream
* @throws IonException * @throws IOException
*/ */
public void ionWrite(OutputStream out) throws IonException; void saveTo(OutputStream out) throws IOException;
/** /**
@ -39,5 +40,5 @@ public interface Ionizable {
* *
* @return Ion mark byte. * @return Ion mark byte.
*/ */
public byte ionMark(); public short getIonMark();
} }

@ -1,17 +0,0 @@
package mightypork.util.files.ion;
/**
* Optional ionizable
*
* @author MightyPork
*/
public interface IonizableOptional extends Ionizable {
/**
* Get if this ionizable should be saved to a list
*
* @return should save
*/
public boolean ionShouldSave();
}
Loading…
Cancel
Save