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.ent.data.ControlElement;
import jo.sm.ent.data.ControlElementMap;
import jo.sm.ent.data.ControlSubElement;
import jo.sm.ent.data.Tag;
import jo.sm.ent.data.TagType;
import jo.sm.logic.utils.ByteUtils;
import jo.sm.logic.utils.DebugLogic;
import jo.vecmath.Point3b;
import jo.vecmath.Point3i;
import jo.vecmath.Tuple3b;
import jo.vecmath.Tuple3f;
import jo.vecmath.Tuple3i;
import jo.vecmath.Vector3f;
public class TagLogic {
private static final Logger log = Logger.getLogger(TagLogic.class.getName());
public static Tag readFile(InputStream is, boolean closeStream)
throws IOException {
DebugLogic.setIndent("");
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, (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 Point3i(dis.readInt(),
dis.readInt(), dis.readInt());
break;
case VECTOR3b:
value = new Point3b((byte) dis.read(),
(byte) dis.read(), (byte) 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();
if ((nt & 0xff) == 0xf3) // HACK
{
dis.skip(23);
nt = dis.readByte();
} else if ((nt & 0xff) == 0xff) // HACK
{
dis.skip(2);
nt = dis.readByte();
}
try {
nextType = TagType.values()[nt];
} catch (ArrayIndexOutOfBoundsException e) {
byte[] buf = new byte[128];
buf[0] = nt;
dis.read(buf, 1, 127);
log.log(Level.WARNING, "Bad tag data:\n" + ByteUtils.toStringDump(buf));
throw new IllegalStateException("Unknown tag type '" + 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[inbuf.size()]);
break;
}
case SERIALIZABLE: {
DebugLogic.debug("Reading Serializable");
ControlElementMap map = new ControlElementMap();
map.setFactory(dis.readByte());
int controlElementMapperSize = dis.readInt();
for (int i = 0; i < controlElementMapperSize; i++) {
ControlElement ele = new ControlElement();
short index1 = dis.readShort();
short index2 = dis.readShort();
short index3 = dis.readShort();
ele.setIndex(shortToIndex(index1, index2, index3));
int size2 = dis.readInt();
for (int j = 0; j < size2; j++) {
ControlSubElement sub = new ControlSubElement();
sub.setVal(dis.readShort());
int size3 = dis.readInt();
for (int k = 0; k < size3; k++) {
Point3i p = new Point3i();
p.x = dis.readShort();
p.y = dis.readShort();
p.z = dis.readShort();
sub.getVals().add(p);
}
ele.getElements().add(sub);
}
map.getElements().add(ele);
}
value = map;
break;
}
}
DebugLogic.outdent();
return value;
}
private static short[] indexToShort(long index) {
long l1 = index / 4294705156L;
long l2 = (index -= l1 * 4294705156L) / 65534L;
index -= l2 * 65534L;
short[] ret = new short[3];
ret[0] = (short) (int) (index - 32767L);
ret[1] = (short) (int) (l2 - 32767L);
ret[2] = (short) (int) (l1 - 32767L);
return ret;
}
public static long shortToIndex(int paramInt1, int paramInt2, int paramInt3) {
long l1 = paramInt1 + 32767;
long l2 = paramInt2 + 32767;
long l3;
if ((l3 = (paramInt3 + 32767) * 4294705156L + l2 * 65534L + l1) < 0L) {
throw new IllegalArgumentException("ElementCollection Index out of bounds: " + paramInt1 + ", " + paramInt2 + ", " + paramInt3 + " -> " + l3);
}
return l3;
}
private static void writeValue(Tag tag, DataOutputStream dos)
throws IOException {
switch (tag.getType()) {
case FINISH:
return;
case BYTE:
dos.writeByte(((int) tag.getValue()));
return;
case SHORT:
dos.writeShort(((int) 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(((Tuple3f) tag.getValue()).x);
dos.writeFloat(((Tuple3f) tag.getValue()).y);
dos.writeFloat(((Tuple3f) tag.getValue()).z);
return;
case VECTOR3i:
dos.writeInt(((Tuple3i) tag.getValue()).x);
dos.writeInt(((Tuple3i) tag.getValue()).y);
dos.writeInt(((Tuple3i) tag.getValue()).z);
return;
case VECTOR3b:
dos.write(((Tuple3b) tag.getValue()).x);
dos.write(((Tuple3b) tag.getValue()).y);
dos.write(((Tuple3b) tag.getValue()).z);
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: {
ControlElementMap map = (ControlElementMap) tag.getValue();
dos.writeByte(map.getFactory());
dos.writeInt(map.getElements().size());
for (ControlElement ele : map.getElements()) {
short[] index = indexToShort(ele.getIndex());
dos.writeShort(index[0]);
dos.writeShort(index[1]);
dos.writeShort(index[2]);
dos.writeInt(ele.getElements().size());
for (ControlSubElement sub : ele.getElements()) {
dos.writeShort(sub.getVal());
dos.writeInt(sub.getVals().size());
for (Point3i p : sub.getVals()) {
dos.writeShort(p.x);
dos.writeShort(p.y);
dos.writeShort(p.z);
}
}
}
}
}
}
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 Point3i)) {
throw new IllegalArgumentException();
}
break;
case VECTOR3b:
if (!(value instanceof Point3b)) {
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 ControlElementMap)) {
throw new IllegalArgumentException();
}
break;
default:
throw new IllegalArgumentException();
}
tag.setValue(value);
}
}