package com.jinoh.ruby.marshal; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; public class Marshal { public static final byte[] VERSION_INFO = new byte[] {0x04, 0x08}; public static final Map<Symbol, Class<?>> sSymbolToClass = new HashMap<Symbol, Class<?>>(); public static final Map<Class<?>, Symbol> sClassToSymbol = new HashMap<Class<?>, Symbol>(); public static final String[] KEYWORDS = new String[] {"abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", "native", "super", "while"}; static { register(new Object[] { "RPG::Actor", com.eb.rpg.Actor.class, "RPG::Animation", com.eb.rpg.Animation.class, "RPG::Animation::Frame", com.eb.rpg.Animation.Frame.class, "RPG::Animation::Timing", com.eb.rpg.Animation.Timing.class, "RPG::Armor", com.eb.rpg.Armor.class, "RPG::AudioFile", com.eb.rpg.AudioFile.class, "RPG::Class", com.eb.rpg.ClassActor.class, "RPG::Class::Learning", com.eb.rpg.ClassActor.Learning.class, "RPG::CommonEvent", com.eb.rpg.CommonEvent.class, "RPG::Enemy", com.eb.rpg.Enemy.class, "RPG::Enemy::Action", com.eb.rpg.Enemy.Action.class, "RPG::Event", com.eb.rpg.Event.class, "RPG::Event::Page", com.eb.rpg.Event.Page.class, "RPG::Event::Page::Condition", com.eb.rpg.Event.Page.Condition.class, "RPG::Event::Page::Graphic", com.eb.rpg.Event.Page.Graphic.class, "RPG::EventCommand", com.eb.rpg.EventCommand.class, "RPG::Item", com.eb.rpg.Item.class, "RPG::Map", com.eb.rpg.Map.class, "RPG::MapInfo", com.eb.rpg.MapInfo.class, "RPG::MoveCommand", com.eb.rpg.MoveCommand.class, "RPG::MoveRoute", com.eb.rpg.MoveRoute.class, "RPG::Skill", com.eb.rpg.Skill.class, "RPG::State", com.eb.rpg.State.class, "RPG::System", com.eb.rpg.System.class, "RPG::System::TestBattler", com.eb.rpg.System.TestBattler.class, "RPG::System::Words", com.eb.rpg.System.Words.class, "RPG::Tileset", com.eb.rpg.Tileset.class, "RPG::Troop", com.eb.rpg.Troop.class, "RPG::Troop::Member", com.eb.rpg.Troop.Member.class, "RPG::Troop::Page", com.eb.rpg.Troop.Page.class, "RPG::Weapon", com.eb.rpg.Weapon.class, "Color", com.eb.rpg.builtin.Color.class, "Table", com.eb.rpg.builtin.Table.class, }); } public static String ruby2field (Symbol symbol) { String t = symbol.toString(); for (String s : KEYWORDS) if (t.equals(s)) return t + "_"; return t; } public static Symbol field2ruby (String name) { if (name.endsWith("_")) { String t = name.substring(0, name.length() - 1); for (String s : KEYWORDS) if (t.equals(s)) return new Symbol(t); } return new Symbol(name); } public static <T> void register (T[] list) { Symbol s; Class<?> c; for (int i = 0; i < list.length; i += 2) { s = new Symbol(list[i].toString()); c = (Class<?>) list[i+1]; sSymbolToClass.put(s, c); sClassToSymbol.put(c, s); } } public static void register (Symbol name, Class<?> clazz) { sSymbolToClass.put(name, clazz); sClassToSymbol.put(clazz, name); } public static byte[] dump (Object obj) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); dump (baos, obj); return baos.toByteArray(); } public static void dump (OutputStream os, Object obj) throws IOException { os.write(VERSION_INFO); new Marshaler(os).marshalAuto(obj); } public static Object load (byte[] bytes) throws IOException { return loadAs (new ByteArrayInputStream(bytes), null); } public static Object load (InputStream is) throws IOException { return loadAs (is, null); } public static <T> T loadAs (byte[] bytes, Class<T> clazz) throws IOException { return loadAs (new ByteArrayInputStream(bytes), clazz); } @SuppressWarnings("unchecked") public static <T> T loadAs (InputStream is, Class<T> clazz) throws IOException, ClassCastException { int major = is.read(); int minor = is.read(); if (major < 0 || minor < 0) throw new IOException("End of stream"); if ((byte) major != VERSION_INFO[0] || (byte) minor > VERSION_INFO[1]) throw new IOException("Incompatible version"); return (T) (new Unmarshaler(is).unmarshalAuto(clazz)); } }