package swift.net.lfs; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class LFSByteArray extends ByteArray { static public final long UINT_MAX = ((long)1 << 32) - 1; static public final int ACTION_TYPE_STATEMENT_LUA = 105; static public final int ACTION_TYPE_STATEMENT = ACTION_TYPE_STATEMENT_LUA; static public final int LBY_TYPE_BYTE = 1; static public final int LBY_TYPE_UBYTE = -1; static public final int LBY_TYPE_SHORT = 2; static public final int LBY_TYPE_USHORT = 3; static public final int LBY_TYPE_INT = 4; static public final int LBY_TYPE_UINT = 5; static public final int LBY_TYPE_FLOAT = 6; static public final int LBY_TYPE_DOUBLE = 7; static public final int LBY_TYPE_LONG = 8; static public final int LBY_TYPE_STRING = -4; static public final int LBY_TYPE_STRING_BYTES = -5; static public final int LBY_TYPE_BYTES = -3; static public final int LBY_TYPE_BOOLEAN = -2; static public final int LBY_TYPE_NULL = 0; static public final int WRITE_TYPE_NORMAL = 0; static public final int WRITE_TYPE_STREAM_TRY_READ = 1; static public final int WRITE_TYPE_STREAM_TRY_SKIP = 2; public int STRING_TYPE = LBY_TYPE_STRING_BYTES; protected int[] varsMeta; protected int varsLength; protected int messageLength; /** * 系统状态 */ protected int status; /** * 用户状态 */ protected int state; /** * 类型 */ protected int actionType; /** * Server 用时 */ protected double time; /** * 全部用时(含通信用时) */ public long totalTime; public LFSByteArray() { this(32); } /** * @param size */ public LFSByteArray(int size) { super(size); reset(); } public void putByte(int v) { writeByte(LBY_TYPE_BYTE); writeByte(v); varsLength++; } public void putUByte(int v) { writeByte(LBY_TYPE_UBYTE); writeByte(v); varsLength++; } public void putBytes(byte[] v) { writeByte(LBY_TYPE_BYTES); writeInt(v.length); write(v); writeByte(0); varsLength++; } public void putBytes(byte[] v, int off, int len) { writeByte(LBY_TYPE_BYTES); writeInt(len); write(v, off, len); writeByte(0); varsLength++; } public void putBoolean(boolean v) { writeByte(LBY_TYPE_BOOLEAN); writeBoolean(v); varsLength++; } public void putNull() { writeByte(LBY_TYPE_NULL); varsLength++; } public void putShort(int v) { writeByte(LBY_TYPE_SHORT); writeShort(v); varsLength++; } public void putUShort(int v) { writeByte(LBY_TYPE_USHORT); writeShort(v); varsLength++; } public void putChar(int v) { writeByte(LBY_TYPE_SHORT); writeChar(v); varsLength++; } public void putInt(int v) { writeByte(LBY_TYPE_INT); writeInt(v); varsLength++; } public void putUInt(int v) { writeByte(LBY_TYPE_UINT); writeInt(v); varsLength++; } public void putLong(long v) { writeByte(LBY_TYPE_LONG); writeLong(v); varsLength++; } public void putFloat(float v) { writeByte(LBY_TYPE_FLOAT); writeFloat(v); varsLength++; } public void putDouble(double v) { writeByte(LBY_TYPE_DOUBLE); writeDouble(v); varsLength++; } public void putString(String v) { try { byte[] b = v.getBytes("UTF-8"); writeByte(STRING_TYPE); writeInt(b.length); write(b); writeByte(0); varsLength++; } catch (Exception e) {} } public void putStringBytes(String v) { try { byte[] b = v.getBytes("UTF-8"); writeByte(LBY_TYPE_STRING_BYTES); writeInt(b.length); write(b); writeByte(0); varsLength++; } catch (Exception e) {} } public boolean setStatement(String v) throws Exception { if (position == 12) { try { byte[] b = v.getBytes("UTF-8"); writeInt(b.length); write(b); writeByte(0); return true; } catch (Exception e) {} } throw new Exception("Must be the first"); } public void setActionType(int v) { actionType = v; } public void writeTo(OutputStream out) throws IOException { int len = position; switch (actionType) { case ACTION_TYPE_STATEMENT_LUA: position = 8; writeInt(varsLength); break; default: len = 8; break; } position = 0; writeInt(len - 4); writeInt(actionType); position = len; super.writeTo(out); } private void __writeTo(Socket socket) throws IOException { totalTime = System.currentTimeMillis(); writeTo(socket.getOutputStream()); socket.getOutputStream().flush(); InputStream in = socket.getInputStream(); reset(); position = 0; messageLength = 28; ensureCapacity(messageLength, false); int bytesAvalibale = 0; while (position < messageLength) { bytesAvalibale = in.read(buf, position, messageLength - position); if (bytesAvalibale > 0) { position += bytesAvalibale; } else if (bytesAvalibale < 0) { throw new IOException("Broken Pipe"); } } } /** * 写入数据并返回读取的数据 * @param socket * @return status == 0 && state >= 0(方便判断返回结果,通常 state < 0 表示错误,但具体含义由用户自己决定) * @throws IOException */ public boolean writeTo(Socket socket) throws IOException { return writeTo(socket, WRITE_TYPE_NORMAL); } /** * 写入数据并返回读取的数据 * @param socket * @param type <ul><ul> * <li>WRITE_TYPE_NORMAL: 读取全部数据并解析</li> * <li>WRITE_TYPE_STREAM_TRY_READ: 当失败时读取全部数据并解析</li> * <li>WRITE_TYPE_STREAM_TRY_SKIP: 当失败时忽略后续数据</li></ul></ul> * @return status == 0 && state >= 0(方便判断返回结果,通常 state < 0 表示错误,但具体含义由用户自己决定) * @throws IOException */ public boolean writeTo(Socket socket, int type) throws IOException { return writeTo(socket, type, null); } /** * 写入数据并返回读取的数据 * @param socket * @param type <ul><ul> * <li>WRITE_TYPE_NORMAL: 读取全部数据并解析</li> * <li>WRITE_TYPE_STREAM_TRY_READ: 当失败时读取全部数据并解析</li> * <li>WRITE_TYPE_STREAM_TRY_SKIP: 当失败时忽略后续数据</li></ul></ul> * @param streamParse * @return status == 0 && state >= 0(方便判断返回结果,通常 state < 0 表示错误,但具体含义由用户自己决定) * @throws IOException */ public boolean writeTo(Socket socket, int type, IStreamParse streamParse) throws IOException { __writeTo(socket); position = 0; messageLength = readInt() + 4; status = readInt(); actionType = readInt(); state = readInt(); varsLength = readInt(); time = readDouble(); if (type == WRITE_TYPE_NORMAL) { readStream(socket, streamParse); } else if (status != 0 || state < 0) { if (type == WRITE_TYPE_STREAM_TRY_READ) { readStream(socket, streamParse); } else if (type == WRITE_TYPE_STREAM_TRY_SKIP) { socket.getInputStream().skip(messageLength - position); } } else if (null != streamParse) { readStream(socket, streamParse); } return status == 0 && state >= 0; } public void readStream(Socket socket, IStreamParse streamParse) throws IOException { ensureCapacity(messageLength, false); InputStream in = socket.getInputStream(); int bytesAvalibale = 0; while (position < messageLength) { bytesAvalibale = in.read(buf, position, messageLength - position); if (bytesAvalibale > 0) { if (null != streamParse) { streamParse.parseData(buf, bytesAvalibale, position, messageLength); } position += bytesAvalibale; } else if (bytesAvalibale < 0) { throw new IOException("Broken Pipe"); } } initVars(false); totalTime = System.currentTimeMillis() - totalTime; } public int readNext(Socket socket) throws IOException { return readNext(socket.getInputStream(), false); } public int readNext(Socket socket, boolean initVars) throws IOException { return readNext(socket.getInputStream(), initVars); } public int readNext(InputStream in) throws IOException { return readNext(in, false); } public int readNext(InputStream in, boolean initVars) throws IOException { int bytesAvalibale = -1; if (position < messageLength) { bytesAvalibale = in.read(buf, position, messageLength - position); if (bytesAvalibale > 0) { position += bytesAvalibale; if (position == messageLength) { if (initVars == true) { initVars(true); } totalTime = System.currentTimeMillis() - totalTime; } } else if (bytesAvalibale < 0) { throw new IOException("Broken Pipe"); } } return bytesAvalibale; } public int initVars(boolean readHead) { return initVars(readHead, 0, -1); } public int initVars(boolean readHead, int start, int end) { if (readHead == true) { position = 0; messageLength = readInt() + 4; status = readInt(); actionType = readInt(); state = readInt(); varsLength = readInt(); time = readDouble(); } switch (actionType) { case ACTION_TYPE_STATEMENT_LUA: break; default: return -1; } if (null == varsMeta) { varsMeta = new int[varsLength * 3]; } if (end == -1 || end >= varsLength) { end = varsLength - 1; } if (start == 0) { position = 28; } else { position = varsMeta[(start - 1) * 3 + 1] + varsMeta[(start - 1) * 3 + 2]; } int len = buf.length; int t = 0; for (int j = start * 3; start <= end && position < len; start++) { t = read(); varsMeta[j++] = t; varsMeta[j] = position; switch (t) { case LBY_TYPE_BYTE: case LBY_TYPE_INT: case LBY_TYPE_LONG: case LBY_TYPE_SHORT: case LBY_TYPE_NULL: break; case LBY_TYPE_USHORT: t = 2; break; case LBY_TYPE_UINT: case LBY_TYPE_FLOAT: t = 4; break; case LBY_TYPE_DOUBLE: t = 8; break; case LBY_TYPE_UBYTE: case LBY_TYPE_BOOLEAN: t = 1; break; default: if (position + 5 <= len) { t = readInt(); position++; varsMeta[j] += 4; if (position + t > len) { break; } } else { break; } break; } j++; varsMeta[j++] = t; position += t; } return start; } public int getLength(int index) { int length = 0; if (index < varsLength && null != varsMeta) { index = index * 3; length = varsMeta[index + 2]; } return length; } public int getType(int index) { return varsMeta[index * 3]; } public String getTypeString(int index) { if (index < varsLength && null != varsMeta) { switch (varsMeta[index * 3]) { case LBY_TYPE_INT: return "int"; case LBY_TYPE_UINT: return "uint"; case LBY_TYPE_LONG: return "long"; case LBY_TYPE_DOUBLE: return "double"; case LBY_TYPE_FLOAT: return "float"; case LBY_TYPE_SHORT: return "short"; case LBY_TYPE_USHORT: return "ushort"; case LBY_TYPE_BYTE: return "byte"; case LBY_TYPE_UBYTE: return "ubyte"; case LBY_TYPE_BOOLEAN: return "boolean"; case LBY_TYPE_NULL: return "null"; case LBY_TYPE_STRING: return "String"; case LBY_TYPE_STRING_BYTES: return "StringBytes"; default: return "Bytes"; } } return null; } public Object get(int index) { if (index < varsLength && null != varsMeta) { switch (varsMeta[index * 3]) { case LBY_TYPE_INT: return getInt(index); case LBY_TYPE_UINT: return getUInt(index); case LBY_TYPE_LONG: return getLong(index); case LBY_TYPE_DOUBLE: return getDouble(index); case LBY_TYPE_FLOAT: return getFloat(index); case LBY_TYPE_SHORT: return getShort(index); case LBY_TYPE_USHORT: return getUShort(index); case LBY_TYPE_BYTE: return getByte(index); case LBY_TYPE_UBYTE: return getUByte(index); case LBY_TYPE_BOOLEAN: return getBoolean(index); case LBY_TYPE_NULL: return null; case LBY_TYPE_STRING: case LBY_TYPE_STRING_BYTES: return getString(index); default: return getBytes(index); } } return null; } public double getNumber(int index) { if (index < varsLength && null != varsMeta) { switch (varsMeta[index * 3]) { case LBY_TYPE_INT: return getInt(index); case LBY_TYPE_UINT: return getUInt(index); case LBY_TYPE_LONG: return getLong(index); case LBY_TYPE_DOUBLE: return getDouble(index); case LBY_TYPE_FLOAT: return getFloat(index); case LBY_TYPE_SHORT: return getShort(index); case LBY_TYPE_USHORT: return getUShort(index); case LBY_TYPE_BYTE: return getByte(index); case LBY_TYPE_UBYTE: return getUByte(index); } } return 0; } public byte getByte(int index) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_BYTE: case LBY_TYPE_UBYTE: position = varsMeta[++index]; return readByte(); } } return 0; } public int getUByte(int index) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_UBYTE: case LBY_TYPE_BYTE: position = varsMeta[++index]; return readUByte(); } } return 0; } public byte[] getBytes(int index) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_BYTES: case LBY_TYPE_STRING: case LBY_TYPE_STRING_BYTES: position = varsMeta[++index]; index = varsMeta[++index]; if (index > 0) { byte[] b = new byte[index]; read(b); return b; } break; } } return null; } public byte[] getBytes(int index, int len) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_BYTES: case LBY_TYPE_STRING: case LBY_TYPE_STRING_BYTES: position = varsMeta[++index]; index = varsMeta[++index]; if (index > 0 && len > 0) { len = len > index ? index : len; byte[] b = new byte[len]; read(b); return b; } break; } } return null; } public byte[] getByteArray(int index, byte[] b) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_BYTES: case LBY_TYPE_STRING: case LBY_TYPE_STRING_BYTES: position = varsMeta[++index]; index = varsMeta[++index]; if (index > 0) { read(b); return b; } break; } } return null; } public byte[] getByteArray(int index, byte[] b, int off, int len) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_BYTES: case LBY_TYPE_STRING: case LBY_TYPE_STRING_BYTES: position = varsMeta[++index]; index = varsMeta[++index]; if (index > 0 && len > 0) { read(b, off, len); return b; } break; } } return null; } public String getString(int index) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_STRING: case LBY_TYPE_STRING_BYTES: position = varsMeta[++index]; index = varsMeta[++index]; if (index > 0) { byte[] b = new byte[index]; read(b); try { return new String(b, "UTF-8"); } catch (Exception e) {} } return ""; } } return null; } public boolean getBoolean(int index) { if (index < varsLength && null != varsMeta) { index *= 3; if (varsMeta[index] == LBY_TYPE_BOOLEAN) { position = varsMeta[++index]; return readBoolean(); } } return false; } public short getShort(int index) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_SHORT: case LBY_TYPE_USHORT: position = varsMeta[++index]; return readShort(); } } return 0; } public int getUShort(int index) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_USHORT: case LBY_TYPE_SHORT: position = varsMeta[++index]; return readUShort(); } } return 0; } public char getChar(int index) { if (index < varsLength && null != varsMeta) { index *= 3; if (varsMeta[index] == LBY_TYPE_SHORT) { position = varsMeta[++index]; return readChar(); } } return 0; } public int getInt(int index) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_INT: case LBY_TYPE_UINT: position = varsMeta[++index]; return readInt(); } } return 0; } public long getUInt(int index) { if (index < varsLength && null != varsMeta) { index *= 3; switch (varsMeta[index]) { case LBY_TYPE_UINT: case LBY_TYPE_INT: position = varsMeta[++index]; return readUInt(); } } return 0; } public long getLong(int index) { if (index < varsLength && null != varsMeta) { index *= 3; if (varsMeta[index] == LBY_TYPE_LONG) { position = varsMeta[++index]; return readLong(); } } return 0; } public float getFloat(int index) { if (index < varsLength && null != varsMeta) { index *= 3; if (varsMeta[index] == LBY_TYPE_FLOAT) { position = varsMeta[++index]; return readFloat(); } } return 0; } public double getDouble(int index) { if (index < varsLength && null != varsMeta) { index *= 3; if (varsMeta[index] == LBY_TYPE_DOUBLE) { position = varsMeta[++index]; return readDouble(); } } return 0; } public int getMessageLength() { return messageLength > 0 ? messageLength : position; } public int getStatus() { return status; } public int getState() { return state; } public int getActionType() { return actionType; } public int getVarsLength() { return varsLength; } public double getTime() { return time; } public double getTimeSecond() { return time / 1000; } public String getTimeString() { return String.format("%1$.9f", time / 1000); } public String getTimeStringMillis() { return String.format("%1$.6f", time); } public long getTotalTimeMillis() { return totalTime; } public void reset() { position = 12; messageLength = 0; varsLength = 0; actionType = ACTION_TYPE_STATEMENT; varsMeta = null; } public void clear() { super.clear(); varsMeta = null; } static public interface IStreamParse { void parseData(byte[] b, int bytesAvalibale, int position, int messageLength); } }