forked from LupusNobilis/java-org.hwo
499 lines
12 KiB
Java
499 lines
12 KiB
Java
package org.hwo.serialize;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
public class DatabaseField {
|
|
//FORMAT:
|
|
//[4] String FieldID (DFLD)
|
|
//[1] Byte FieldType
|
|
//[2] Short NameLength
|
|
//[NameLength] String Name
|
|
// if type==string [2] Short ValueLength
|
|
//[TypeLength] Value
|
|
|
|
//second nibble == type, first nibble == type if array
|
|
public static final byte BYTE = 0x00;
|
|
public static final byte SHORT = 0x01;
|
|
public static final byte INT = 0x02;
|
|
public static final byte LONG = 0x03;
|
|
public static final byte FLOAT = 0x06;
|
|
public static final byte STRING = 0x04;
|
|
public static final byte OBJECT = 0x05;
|
|
public static final byte ARRAY = 0x0F;
|
|
|
|
private static final String FIELD_ID = "DFLD";
|
|
|
|
public enum Type {
|
|
BYTE,
|
|
SHORT,
|
|
INT,
|
|
LONG,
|
|
FLOAT,
|
|
STRING,
|
|
OBJECT,
|
|
ARRAY
|
|
}
|
|
|
|
private class _valueType<T>{
|
|
private T value;
|
|
|
|
public _valueType(T value) {
|
|
this.value = value;
|
|
}
|
|
|
|
@SuppressWarnings("unused")
|
|
public void setValue(T value) {
|
|
this.value = value;
|
|
}
|
|
|
|
public T getValue() {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
private byte type;
|
|
private String name;
|
|
@SuppressWarnings("rawtypes")
|
|
private _valueType value;
|
|
private List<?> arrayValue;
|
|
private int sizeInBytes;
|
|
|
|
|
|
//+++++++++++CONSTRUCTORS+++++++++++++++//
|
|
public DatabaseField(byte type, String name) {
|
|
this.type = type;
|
|
this.name = name;
|
|
}
|
|
|
|
public DatabaseField(byte type, String name, Object value, boolean array) {
|
|
if(array) {
|
|
this.type = ARRAY;
|
|
this.type |= type << 4;
|
|
this.name = name;
|
|
this.arrayValue = (ArrayList<?>)value;
|
|
}
|
|
else {
|
|
this.type = type;
|
|
this.name = name;
|
|
initialize(value);
|
|
}
|
|
|
|
}
|
|
|
|
private void initialize(Object value) {
|
|
switch(_byteToType(this.type)) {
|
|
case BYTE:
|
|
setValue((byte)value);
|
|
break;
|
|
case SHORT:
|
|
setValue((short)value);
|
|
break;
|
|
case INT:
|
|
setValue((int)value);
|
|
break;
|
|
case LONG:
|
|
setValue((long)value);
|
|
break;
|
|
case FLOAT:
|
|
setValue((float)value);
|
|
break;
|
|
case STRING:
|
|
setValue((String)value);
|
|
break;
|
|
case OBJECT:
|
|
setValue((DatabaseObject)value);
|
|
break;
|
|
case ARRAY:
|
|
//setValue((List<?>)value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public Type getType() {
|
|
return _byteToType(this.type);
|
|
}
|
|
|
|
private static Type _byteToType(byte t) {
|
|
switch(t) {
|
|
case 0x00:
|
|
return Type.BYTE;
|
|
case 0x01:
|
|
return Type.SHORT;
|
|
case 0x02:
|
|
return Type.INT;
|
|
case 0x03:
|
|
return Type.LONG;
|
|
case 0x04:
|
|
return Type.STRING;
|
|
case 0x05:
|
|
return Type.OBJECT;
|
|
case 0x06:
|
|
return Type.FLOAT;
|
|
default:
|
|
break;
|
|
}
|
|
if(t >= 0x0F)
|
|
return Type.ARRAY;
|
|
return null;
|
|
}
|
|
|
|
private static byte _typeToByte(Type t) {
|
|
switch(t) {
|
|
case BYTE:
|
|
return 0x00;
|
|
case SHORT:
|
|
return 0x01;
|
|
case INT:
|
|
return 0x02;
|
|
case LONG:
|
|
return 0x03;
|
|
case STRING:
|
|
return 0x04;
|
|
case OBJECT:
|
|
return 0x05;
|
|
case FLOAT:
|
|
return 0x06;
|
|
case ARRAY:
|
|
return 0x0F;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public String getName() {
|
|
return this.name;
|
|
}
|
|
|
|
private<T> void _setValue(T value) {
|
|
this.value = new _valueType<T>(value);
|
|
}
|
|
|
|
public void setValue(byte value) { _setValue(value); }
|
|
public void setValue(short value) { _setValue(value); }
|
|
public void setValue(int value) { _setValue(value); }
|
|
public void setValue(long value) { _setValue(value); }
|
|
public void setValue(float value) { _setValue(value); }
|
|
public void setValue(String value) { _setValue(value); }
|
|
public void setValue(DatabaseObject value) { _setValue(value); }
|
|
public void setValue(List<?> value) { this.arrayValue = value; }
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public<T> T getValue(){
|
|
|
|
if(this.type >= 0x0F)
|
|
return (T)this.arrayValue;
|
|
return (T)this.value.getValue();
|
|
}
|
|
|
|
public int getSizeInBytes() {
|
|
if(this.sizeInBytes <= 0)
|
|
this.sizeInBytes = 11 + typeSize(_byteToType(this.type)) + this.name.length();
|
|
|
|
return this.sizeInBytes;
|
|
}
|
|
|
|
private int typeSize(Type t) {
|
|
switch(t) {
|
|
case BYTE:
|
|
return Byte.BYTES;
|
|
case SHORT:
|
|
return Short.BYTES;
|
|
case INT:
|
|
return Integer.BYTES;
|
|
case LONG:
|
|
return Long.BYTES;
|
|
case FLOAT:
|
|
return Float.BYTES;
|
|
case STRING:
|
|
return ((String)(this.value.getValue())).length();
|
|
case OBJECT:
|
|
return ((DatabaseObject)(this.value.getValue())).getSizeInBytes();
|
|
case ARRAY:
|
|
return 0; //TODO:
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public String toString(int indendation) {
|
|
String indend = new String();
|
|
String result = new String();
|
|
for(int i = 0; i < indendation; i++)
|
|
indend += " ";
|
|
|
|
result += indend + "Field " + this.name + "\n";
|
|
result += indend + "Type: " + _byteToType(this.type) + "\n";
|
|
if(_byteToType(this.type) == Type.OBJECT)
|
|
result += indend + "Value " + ((DatabaseObject)getValue()).toString(indendation + 5);
|
|
else if(_byteToType(this.type) == Type.ARRAY) {
|
|
result += indend + "Value: \n";
|
|
result += indend;
|
|
for(int i = 0; i < arrayValue.size(); i++) {
|
|
result += "[" + i + "]" + " ";
|
|
//TODO: print values!
|
|
switch(_byteToType((byte)(this.type >> 4))) {
|
|
case BYTE:
|
|
result += ((ArrayList<Byte>)arrayValue).get(i) + " ";
|
|
break;
|
|
case SHORT:
|
|
result += ((ArrayList<Short>)arrayValue).get(i) + " ";
|
|
break;
|
|
case INT:
|
|
result += ((ArrayList<Integer>)arrayValue).get(i) + " ";
|
|
break;
|
|
case LONG:
|
|
result += ((ArrayList<Long>)arrayValue).get(i) + " ";
|
|
break;
|
|
case FLOAT:
|
|
result += ((ArrayList<Float>)arrayValue).get(i) + " ";
|
|
case STRING:
|
|
//result += (String)((List<Object>)getValue()).get(i) + " ";
|
|
break;
|
|
case OBJECT:
|
|
//result += indend + ((DatabaseObject)((List<Object>)getValue()).get(i)).toString(indendation + 5);
|
|
break;
|
|
case ARRAY:
|
|
break;
|
|
}
|
|
if((i % 5) == 4)
|
|
result += "\n" + indend;
|
|
}
|
|
}
|
|
else
|
|
result += indend + "Value: " + getValue() + "\n";
|
|
result += "\n";
|
|
|
|
return result;
|
|
}
|
|
|
|
public String toString() {
|
|
return toString(0);
|
|
}
|
|
|
|
public void print(int indendation) {
|
|
System.out.print(this.toString(indendation));
|
|
}
|
|
|
|
public void print() {
|
|
print(0);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public byte[] serialize() {
|
|
List<Byte> bytes = new ArrayList<Byte>();
|
|
|
|
BinaryParser.writeBytes(bytes, FIELD_ID);
|
|
BinaryParser.writeBytes(bytes, this.type);
|
|
BinaryParser.writeBytes(bytes, (short)this.name.length());
|
|
BinaryParser.writeBytes(bytes, this.name);
|
|
|
|
switch(getType()) {
|
|
case BYTE:
|
|
BinaryParser.writeBytes(bytes, (int)Byte.BYTES);
|
|
BinaryParser.writeBytes(bytes, (byte)getValue());
|
|
break;
|
|
case SHORT:
|
|
BinaryParser.writeBytes(bytes, (int)Short.BYTES);
|
|
BinaryParser.writeBytes(bytes, (short)getValue());
|
|
break;
|
|
case INT:
|
|
BinaryParser.writeBytes(bytes, (int)Integer.BYTES);
|
|
BinaryParser.writeBytes(bytes, (int)getValue());
|
|
break;
|
|
case LONG:
|
|
BinaryParser.writeBytes(bytes, (int)Long.BYTES);
|
|
BinaryParser.writeBytes(bytes, (long)getValue());
|
|
break;
|
|
case FLOAT:
|
|
BinaryParser.writeBytes(bytes, (int)Float.BYTES);
|
|
BinaryParser.writeBytes(bytes, (float)getValue());
|
|
break;
|
|
case STRING:
|
|
BinaryParser.writeBytes(bytes, (int)((String)getValue()).length());
|
|
BinaryParser.writeBytes(bytes, (String)getValue());
|
|
break;
|
|
case OBJECT:
|
|
BinaryParser.writeBytes(bytes, (int)(((DatabaseObject)getValue()).getSizeInBytes()));
|
|
byte[] temp = ((DatabaseObject)getValue()).serialize();
|
|
for(byte b : temp)
|
|
bytes.add(b);
|
|
case ARRAY:
|
|
break;
|
|
}
|
|
|
|
//serialize array
|
|
if(this.type >= 0x0F) {
|
|
int arrLen = arrayValue.size();
|
|
|
|
switch(_byteToType((byte)(this.type >> 4))) {
|
|
case BYTE:
|
|
BinaryParser.writeBytes(bytes, (int)(Byte.BYTES * arrLen));
|
|
for(int i = 0; i < arrLen; i++)
|
|
BinaryParser.writeBytes(bytes, ((List<Byte>)arrayValue).get(i));
|
|
break;
|
|
case SHORT:
|
|
BinaryParser.writeBytes(bytes, (int)(Short.BYTES * arrLen));
|
|
for(int i = 0; i < arrLen; i++)
|
|
BinaryParser.writeBytes(bytes, ((List<Short>)arrayValue).get(i));
|
|
break;
|
|
case INT:
|
|
BinaryParser.writeBytes(bytes, (int)(Integer.BYTES * arrLen));
|
|
for(int i = 0; i < arrLen; i++)
|
|
BinaryParser.writeBytes(bytes,((List<Integer>)arrayValue).get(i));
|
|
break;
|
|
case LONG:
|
|
BinaryParser.writeBytes(bytes, (int)(Long.BYTES * arrLen));
|
|
for(int i = 0; i < arrLen; i++)
|
|
BinaryParser.writeBytes(bytes, ((List<Long>)arrayValue).get(i));
|
|
break;
|
|
case FLOAT:
|
|
BinaryParser.writeBytes(bytes, (int)(Float.BYTES * arrLen));
|
|
for(int i = 0; i < arrLen; i++)
|
|
BinaryParser.writeBytes(bytes, ((List<Float>)arrayValue).get(i));
|
|
case STRING:
|
|
break;
|
|
case OBJECT:
|
|
break;
|
|
case ARRAY:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
byte[] result = new byte[bytes.size()];
|
|
for(int i = 0; i < bytes.size(); i++)
|
|
result[i] = bytes.get(i);
|
|
|
|
this.sizeInBytes = result.length;
|
|
|
|
bytes = null;
|
|
return result;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static DatabaseField deserialize(byte[] src, int ptr) {
|
|
String tid;
|
|
byte ttype;
|
|
short tnameLen;
|
|
String tname;
|
|
int tvalueLen = 0;
|
|
Object tvalue = null;
|
|
|
|
DatabaseField result = null;
|
|
|
|
tid = BinaryParser.readString(src, 4, ptr);
|
|
ptr += 4;
|
|
if(!tid.equals(FIELD_ID)) {
|
|
//throw new Exception();
|
|
System.out.println("Field to deserialize is not of type Field! \nID read: " + tid);
|
|
return null;
|
|
}
|
|
|
|
ttype = BinaryParser.readByte(src, ptr);
|
|
ptr += 1;
|
|
|
|
tnameLen = BinaryParser.readShort(src, ptr);
|
|
ptr += 2;
|
|
|
|
tname = BinaryParser.readString(src, tnameLen, ptr);
|
|
ptr += tnameLen;
|
|
|
|
tvalueLen = BinaryParser.readInt(src, ptr);
|
|
ptr += 4;
|
|
|
|
//Length = 11 + NameLength + TypeLength
|
|
switch(_byteToType(ttype)) {
|
|
case BYTE:
|
|
tvalue = BinaryParser.readByte(src, ptr);
|
|
result = new DatabaseField(ttype, tname, (byte)tvalue, false);
|
|
break;
|
|
case SHORT:
|
|
tvalue = BinaryParser.readShort(src, ptr);
|
|
result = new DatabaseField(ttype, tname, (short)tvalue, false);
|
|
break;
|
|
case INT:
|
|
tvalue = BinaryParser.readInt(src, ptr);
|
|
result = new DatabaseField(ttype, tname, (int)tvalue, false);
|
|
break;
|
|
case LONG:
|
|
tvalue = BinaryParser.readLong(src, ptr);
|
|
result = new DatabaseField(ttype, tname, (long)tvalue, false);
|
|
break;
|
|
case FLOAT:
|
|
tvalue = BinaryParser.readFloat(src, ptr);
|
|
result = new DatabaseField(ttype, tname, (float)tvalue, false);
|
|
case STRING:
|
|
tvalue = BinaryParser.readString(src, tvalueLen, ptr);
|
|
result = new DatabaseField(ttype, tname, (String)tvalue, false);
|
|
break;
|
|
case OBJECT:
|
|
tvalue = DatabaseObject.deserialize(src, ptr);
|
|
result = new DatabaseField(ttype, tname, (DatabaseObject)tvalue, false);
|
|
break;
|
|
case ARRAY:
|
|
break;
|
|
}
|
|
|
|
//Array Type
|
|
if(ttype >= 0x06) {
|
|
switch(_byteToType((byte)(ttype >> 4))) {
|
|
case BYTE:
|
|
tvalue = new ArrayList<Byte>();
|
|
for(int i = 0; i < (tvalueLen / Byte.BYTES); i++) {
|
|
((ArrayList<Byte>)tvalue).add(BinaryParser.readByte(src, ptr));
|
|
ptr += Byte.BYTES;
|
|
}
|
|
result = new DatabaseField((byte)(ttype >> 4), tname, (ArrayList<Byte>)tvalue, true);
|
|
break;
|
|
case SHORT:
|
|
tvalue = new ArrayList<Short>();
|
|
for(int i = 0; i < (tvalueLen / Short.BYTES); i++) {
|
|
((ArrayList<Short>)tvalue).add(BinaryParser.readShort(src, ptr));
|
|
ptr += Short.BYTES;
|
|
}
|
|
result = new DatabaseField((byte)(ttype >> 4), tname, (ArrayList<Short>)tvalue, true);
|
|
break;
|
|
case INT:
|
|
tvalue = new ArrayList<Integer>();
|
|
for(int i = 0; i < (tvalueLen / Integer.BYTES); i++) {
|
|
((ArrayList<Integer>)tvalue).add(BinaryParser.readInt(src, ptr));
|
|
ptr += Integer.BYTES;
|
|
}
|
|
result = new DatabaseField((byte)(ttype >> 4), tname, (ArrayList<Integer>)tvalue, true);
|
|
break;
|
|
case LONG:
|
|
tvalue = new ArrayList<Long>();
|
|
for(int i = 0; i < (tvalueLen / Long.BYTES); i++) {
|
|
((ArrayList<Long>)tvalue).add(BinaryParser.readLong(src, ptr));
|
|
ptr += Long.BYTES;
|
|
}
|
|
result = new DatabaseField((byte)(ttype >> 4), tname, (ArrayList<Long>)tvalue, true);
|
|
break;
|
|
case FLOAT:
|
|
tvalue = new ArrayList<Float>();
|
|
for(int i = 0; i < (tvalueLen / Float.BYTES); i++) {
|
|
((ArrayList<Float>)tvalue).add(BinaryParser.readFloat(src, ptr));
|
|
ptr += Float.BYTES;
|
|
}
|
|
result = new DatabaseField((byte)(ttype >> 4), tname, (ArrayList<Float>)tvalue, true);
|
|
break;
|
|
case STRING:
|
|
break;
|
|
case OBJECT:
|
|
break;
|
|
case ARRAY:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//result.sizeInBytes = 11 + tnameLen + tvalueLen;
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
}
|