package mightypork.utils.files.ion; import java.io.*; import java.util.HashMap; import java.util.Map; import mightypork.utils.math.Calc; /** * Universal data storage system * * @author MightyPork */ public class Ion { /** Ionizables */ private static Map> customIonizables = new HashMap>(); // register default ionizables static { try { registerIonizable(IonMarks.MAP, IonMap.class); registerIonizable(IonMarks.LIST, IonList.class); } catch (IonException e) { e.printStackTrace(); } } /** * Register new Ionizable for direct reconstructing. * * @param mark byte mark to be used, see {@link IonMarks} for reference. * @param objClass class of the registered Ionizable * @throws IonException */ public static void registerIonizable(byte mark, Class objClass) throws IonException { if (customIonizables.containsKey(mark)) { throw new IonException("IonMark " + mark + " is already used."); } 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)); } /** * Load Ion object from file. * * @param file file * @return the loaded object * @throws IonException on failure */ public static Object fromFile(File file) throws IonException { InputStream in = null; try { in = new FileInputStream(file); Object obj = fromStream(in); return obj; } catch (IOException e) { throw new IonException("Error loading ION file.", e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * Load Ion object from stream. * * @param in input stream * @return the loaded object * @throws IonException */ public static Object fromStream(InputStream in) throws IonException { return readObject(in); } /** * Store Ion object to file. * * @param path file path * @param obj object to store * @throws IonException */ 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 { OutputStream out = null; try { String f = path.toString(); File dir = new File(f.substring(0, f.lastIndexOf(File.separator))); dir.mkdirs(); out = new FileOutputStream(path); toStream(out, obj); out.flush(); out.close(); } catch (Exception e) { throw new IonException("Error writing to ION file.", e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * Store Ion object to output 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 * @return the loaded object * @throws IonException */ public static Object readObject(InputStream in) throws IonException { try { int bi = in.read(); if (bi == -1) throw new IonException("Unexpected end of stream."); byte b = (byte) bi; if (customIonizables.containsKey(b)) { Ionizable ion; try { ion = ((Ionizable) customIonizables.get(b).newInstance()); } catch (InstantiationException e) { throw new IonException("Cound not instantiate " + customIonizables.get(b).getSimpleName(), e); } catch (IllegalAccessException e) { throw new IonException("Cound not instantiate " + customIonizables.get(b).getSimpleName(), e); } ion.ionRead(in); return ion; } switch (b) { case IonMarks.BOOLEAN: return StreamUtils.readBoolean(in); case IonMarks.BYTE: return StreamUtils.readByte(in); case IonMarks.CHAR: return StreamUtils.readChar(in); case IonMarks.SHORT: return StreamUtils.readShort(in); case IonMarks.INT: return StreamUtils.readInt(in); case IonMarks.LONG: return StreamUtils.readLong(in); case IonMarks.FLOAT: return StreamUtils.readFloat(in); case IonMarks.DOUBLE: return StreamUtils.readDouble(in); case IonMarks.STRING: String s = StreamUtils.readString(in); return s; default: throw new IonException("Invalid Ion mark " + Integer.toHexString(bi)); } } catch (IOException e) { throw new IonException("Error loading ION file: ", e); } } /** * Write single ionizable or primitive object to output stream * * @param out output stream * @param obj stored object * @throws IonException */ public static void writeObject(OutputStream out, Object obj) throws IonException { try { if (obj instanceof Ionizable) { out.write(((Ionizable) obj).ionMark()); ((Ionizable) obj).ionWrite(out); return; } if (obj instanceof Boolean) { out.write(IonMarks.BOOLEAN); StreamUtils.writeBoolean(out, (Boolean) obj); return; } if (obj instanceof Byte) { out.write(IonMarks.BYTE); StreamUtils.writeByte(out, (Byte) obj); return; } if (obj instanceof Character) { out.write(IonMarks.CHAR); StreamUtils.writeChar(out, (Character) obj); return; } if (obj instanceof Short) { out.write(IonMarks.SHORT); StreamUtils.writeShort(out, (Short) obj); return; } if (obj instanceof Integer) { out.write(IonMarks.INT); StreamUtils.writeInt(out, (Integer) obj); return; } if (obj instanceof Long) { out.write(IonMarks.LONG); StreamUtils.writeLong(out, (Long) obj); return; } if (obj instanceof Float) { out.write(IonMarks.FLOAT); StreamUtils.writeFloat(out, (Float) obj); return; } if (obj instanceof Double) { out.write(IonMarks.DOUBLE); StreamUtils.writeDouble(out, (Double) obj); return; } if (obj instanceof String) { out.write(IonMarks.STRING); StreamUtils.writeString(out, (String) obj); return; } throw new IonException(Calc.cname(obj) + " can't be stored in Ion storage."); } catch (IOException e) { throw new IonException("Could not store " + obj, e); } } }