/** * Copyright 2014 * SMEdit https://github.com/StarMade/SMEdit * SMTools https://github.com/StarMade/SMTools * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. **/ package jo.sm.ent.logic; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PushbackInputStream; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.GZIPInputStream; import jo.sm.data.Vector3b; import jo.sm.data.Vector3f; import jo.sm.data.Vector3i; import jo.sm.ent.data.Tag; import jo.sm.ent.data.TagType; import jo.sm.logic.utils.DebugLogic; public class EntityLogic { private static final Logger log = Logger.getLogger(EntityLogic.class.getName()); public static Tag readFile(InputStream is, boolean closeStream) throws IOException { DebugLogic.debug("Reading file"); DebugLogic.indent(); if (!(is instanceof PushbackInputStream)) { is = new PushbackInputStream(is, 2); } byte header[] = new byte[2]; is.read(header); ((PushbackInputStream) is).unread(header); DataInputStream dis; if (header[0] == 31 && header[1] == -117) { DebugLogic.debug("Zipped input"); dis = new DataInputStream(new GZIPInputStream(is, 4096)); } else { dis = new DataInputStream(new BufferedInputStream(is, 4096)); dis.readShort(); } byte t = dis.readByte(); TagType type = TagType.values()[t]; Tag input = null; if (type == TagType.FINISH) { input = new Tag(TagType.FINISH, null, ((EntityLogic[]) (null))); } else { String name = dis.readUTF(); DebugLogic.debug("Reading " + name); DebugLogic.indent(); try { Object val = readValue(dis, type); input = new Tag(type, name, val); } catch (IOException e) { log.log(Level.WARNING, "EXCEPTION WHILE READING TAG " + name); throw e; } DebugLogic.outdent(); } if (closeStream) { DebugLogic.debug("Closing"); is.close(); } DebugLogic.outdent(); DebugLogic.debug("Done reading file"); return input; } public static void writeFile(Tag tag, OutputStream os, boolean closeFile) throws IOException { DataOutputStream dos; if (os instanceof DataOutputStream) { dos = (DataOutputStream) os; } else { dos = new DataOutputStream(os); } dos.writeShort(0); dos.writeByte(tag.getType().ordinal()); if (tag.getType() != TagType.FINISH) { dos.writeUTF(tag.getName()); writeValue(tag, dos); } if (closeFile) { dos.close(); } } private static Object readValue(DataInputStream dis, TagType type) throws IOException { DebugLogic.indent(); Object value = null; switch (type) { case FINISH: value = null; break; case BYTE: value = dis.readByte(); break; case SHORT: value = dis.readShort(); break; case INT: value = dis.readInt(); break; case LONG: value = dis.readLong(); break; case FLOAT: value = dis.readFloat(); break; case DOUBLE: value = dis.readDouble(); break; case BYTE_ARRAY: { byte[] buf = new byte[dis.readInt()]; dis.readFully(buf); value = buf; break; } case STRING: value = dis.readUTF(); break; case VECTOR3f: value = new Vector3f(dis.readFloat(), dis.readFloat(), dis.readFloat()); break; case VECTOR3i: value = new Vector3i(dis.readInt(), dis.readInt(), dis.readInt()); break; case VECTOR3b: value = new Vector3b(dis.read(), dis.read(), dis.read()); break; case LIST: { DebugLogic.debug("Reading list"); byte st = dis.readByte(); TagType subtype = TagType.values()[st]; int len = dis.readInt(); Tag tagbuf[] = new Tag[len]; for (int j = 0; j < len; j++) { tagbuf[j] = new Tag(subtype, null, readValue(dis, subtype)); } if (tagbuf.length == 0) { value = subtype; } else { value = tagbuf; } break; } case STRUCT: { DebugLogic.debug("Reading struct"); List<Tag> inbuf = new ArrayList<>(); TagType nextType; do { byte nt = dis.readByte(); nextType = TagType.values()[nt]; String name = null; String msg = "Reading member #" + (inbuf.size() + 1); if (nextType != TagType.FINISH) { name = dis.readUTF(); msg += " " + name; } msg += " (" + nextType + ")"; DebugLogic.debug(msg); Object val = readValue(dis, nextType); Tag t = new Tag(nextType, name, val); inbuf.add(t); } while (nextType != TagType.FINISH); value = inbuf.toArray(new Tag[0]); break; } case SERIALIZABLE: { DebugLogic.debug("Reading Serializable"); List<Tag> tagbuf = new ArrayList<>(); for (;;) { byte st = dis.readByte(); TagType subtype = TagType.values()[st]; if (subtype == TagType.FINISH) { tagbuf.add(new Tag()); break; } String name = dis.readUTF(); DebugLogic.debug("Reading element #" + (tagbuf.size() + 1) + " " + name + " (" + subtype + ")"); Object val = readValue(dis, subtype); Tag t = new Tag(subtype, name, val); tagbuf.add(t); } value = tagbuf.toArray(new Tag[0]); break; } } DebugLogic.outdent(); return value; } private static void writeValue(Tag tag, DataOutputStream dos) throws IOException { switch (tag.getType()) { case FINISH: return; case BYTE: dos.writeByte(((Byte) tag.getValue())); return; case SHORT: dos.writeShort(((Short) tag.getValue())); return; case INT: dos.writeInt(((Integer) tag.getValue())); return; case LONG: dos.writeLong(((Long) tag.getValue())); return; case FLOAT: dos.writeFloat(((Float) tag.getValue())); return; case DOUBLE: dos.writeDouble(((Double) tag.getValue())); return; case BYTE_ARRAY: byte outbuf[] = (byte[]) tag.getValue(); dos.writeInt(outbuf.length); dos.write(outbuf); return; case STRING: dos.writeUTF((String) tag.getValue()); return; case VECTOR3f: dos.writeFloat(((Vector3f) tag.getValue()).x); dos.writeFloat(((Vector3f) tag.getValue()).y); dos.writeFloat(((Vector3f) tag.getValue()).z); return; case VECTOR3i: dos.writeInt(((Vector3i) tag.getValue()).a); dos.writeInt(((Vector3i) tag.getValue()).b); dos.writeInt(((Vector3i) tag.getValue()).c); return; case VECTOR3b: dos.write(((Vector3b) tag.getValue()).a); dos.write(((Vector3b) tag.getValue()).b); dos.write(((Vector3b) tag.getValue()).c); return; case LIST: { Tag[] val = (Tag[]) tag.getValue(); if (val.length > 0) { dos.writeByte(val[0].getType().ordinal()); } else { dos.writeByte(tag.getSubType().ordinal()); } dos.writeInt(val.length); for (Tag v : val) { writeValue(v, dos); } /* * dataoutputstream.writeByte(((Ab)a_java_lang_Object_fld). * getFactoryId()); * ((Ab)a_java_lang_Object_fld).writeToTag(dataoutputstream); */ return; } case STRUCT: { Tag[] tagbuf = (Tag[]) tag.getValue(); for (Tag t : tagbuf) { dos.writeByte(t.getType().ordinal()); if (t.getType() != TagType.FINISH) { dos.writeUTF(t.getName()); } writeValue(t, dos); } /* * Ad aad[] = (Ad[])a_java_lang_Object_fld; * dataoutputstream.writeByte(b.ordinal()); * dataoutputstream.writeInt(aad.length); int i = aad.length; * for(int j = 0; j < i; j++) * aad[j].writeValue(dataoutputstream); */ return; } case SERIALIZABLE: { Tag[] tagbuf = (Tag[]) tag.getValue(); for (Tag t : tagbuf) { dos.writeByte(t.getType().ordinal()); if (t.getType() != TagType.FINISH) { dos.writeUTF(t.getName() == null ? "null" : t.getName()); writeValue(t, dos); } } } } } public static void setValue(Tag tag, Object value) { switch (tag.getType()) { case FINISH: if (value != null) { throw new IllegalArgumentException(); } break; case BYTE: if (!(value instanceof Byte)) { throw new IllegalArgumentException(); } break; case SHORT: if (!(value instanceof Short)) { throw new IllegalArgumentException(); } break; case INT: if (!(value instanceof Integer)) { throw new IllegalArgumentException(); } break; case LONG: if (!(value instanceof Long)) { throw new IllegalArgumentException(); } break; case FLOAT: if (!(value instanceof Float)) { throw new IllegalArgumentException(); } break; case DOUBLE: if (!(value instanceof Double)) { throw new IllegalArgumentException(); } break; case BYTE_ARRAY: if (!(value instanceof byte[])) { throw new IllegalArgumentException(); } break; case STRING: if (!(value instanceof String)) { throw new IllegalArgumentException(); } break; case VECTOR3f: if (!(value instanceof Vector3f)) { throw new IllegalArgumentException(); } break; case VECTOR3i: if (!(value instanceof Vector3i)) { throw new IllegalArgumentException(); } break; case VECTOR3b: if (!(value instanceof Vector3b)) { throw new IllegalArgumentException(); } break; case LIST: if (value instanceof TagType) { tag.setSubType((TagType) value); value = new Tag[0]; break; } if (!(value instanceof Tag[])) { throw new IllegalArgumentException(); } tag.setSubType(((Tag[]) value)[0].getType()); break; case STRUCT: if (!(value instanceof Tag[])) { throw new IllegalArgumentException(); } break; case SERIALIZABLE: if (!(value instanceof Tag[])) { throw new IllegalArgumentException(); } break; default: throw new IllegalArgumentException(); } tag.setValue(value); } }