package DBProxy.MySQL.Protocol; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.DecoderException; import java.util.ArrayList; import org.apache.log4j.Logger; public class Proto { public Logger logger = Logger.getLogger("Proto"); public byte[] packet = null; public int offset = 0; public Proto(byte[] packet) { this.packet = packet; } public Proto(byte[] packet, int offset) { this.packet = packet; this.offset = offset; } public boolean has_remaining_data() { return this.packet.length - this.offset > 0; } public static byte[] build_fixed_int(int size, long value) { byte[] packet = new byte[size]; if (size == 8) { packet[0] = (byte) ((value >> 0) & 0xFF); packet[1] = (byte) ((value >> 8) & 0xFF); packet[2] = (byte) ((value >> 16) & 0xFF); packet[3] = (byte) ((value >> 24) & 0xFF); packet[4] = (byte) ((value >> 32) & 0xFF); packet[5] = (byte) ((value >> 40) & 0xFF); packet[6] = (byte) ((value >> 48) & 0xFF); packet[7] = (byte) ((value >> 56) & 0xFF); } else if (size == 6) { packet[0] = (byte) ((value >> 0) & 0xFF); packet[1] = (byte) ((value >> 8) & 0xFF); packet[2] = (byte) ((value >> 16) & 0xFF); packet[3] = (byte) ((value >> 24) & 0xFF); packet[4] = (byte) ((value >> 32) & 0xFF); packet[5] = (byte) ((value >> 40) & 0xFF); } else if (size == 4) { packet[0] = (byte) ((value >> 0) & 0xFF); packet[1] = (byte) ((value >> 8) & 0xFF); packet[2] = (byte) ((value >> 16) & 0xFF); packet[3] = (byte) ((value >> 24) & 0xFF); } else if (size == 3) { packet[0] = (byte) ((value >> 0) & 0xFF); packet[1] = (byte) ((value >> 8) & 0xFF); packet[2] = (byte) ((value >> 16) & 0xFF); } else if (size == 2) { packet[0] = (byte) ((value >> 0) & 0xFF); packet[1] = (byte) ((value >> 8) & 0xFF); } else if (size == 1) { packet[0] = (byte) ((value >> 0) & 0xFF); } else { Logger.getLogger("MySQL.Proto").fatal("Encoding int["+size+"] "+value+" failed!"); return null; } return packet; } public static byte[] build_lenenc_int(long value) { byte[] packet = null; if (value < 251) { packet = new byte[1]; packet[0] = (byte) ((value >> 0) & 0xFF); } else if (value < 65535) { packet = new byte[3]; packet[0] = (byte) 0xFC; packet[1] = (byte) ((value >> 0) & 0xFF); packet[2] = (byte) ((value >> 8) & 0xFF); } else if (value < 16777215) { packet = new byte[4]; packet[0] = (byte) 0xFD; packet[1] = (byte) ((value >> 0) & 0xFF); packet[2] = (byte) ((value >> 8) & 0xFF); packet[3] = (byte) ((value >> 16) & 0xFF); } else { packet = new byte[9]; packet[0] = (byte) 0xFE; packet[1] = (byte) ((value >> 0) & 0xFF); packet[2] = (byte) ((value >> 8) & 0xFF); packet[3] = (byte) ((value >> 16) & 0xFF); packet[4] = (byte) ((value >> 24) & 0xFF); packet[5] = (byte) ((value >> 32) & 0xFF); packet[6] = (byte) ((value >> 40) & 0xFF); packet[7] = (byte) ((value >> 48) & 0xFF); packet[8] = (byte) ((value >> 56) & 0xFF); } return packet; } public static byte[] build_lenenc_str(String str) { return Proto.build_lenenc_str(str, false); } public static byte[] build_lenenc_str(String str, boolean base64) { if (str.equals("")) { byte[] packet = new byte[1]; packet[0] = 0x00; return packet; } int strsize = str.length(); if (base64) strsize = Base64.decodeBase64(str).length; byte[] size = Proto.build_lenenc_int(strsize); byte[] strByte = Proto.build_fixed_str(strsize, str, base64); byte[] packet = new byte[size.length + strByte.length]; System.arraycopy(size, 0, packet, 0, size.length); System.arraycopy(strByte, 0, packet, size.length, strByte.length); return packet; } public static byte[] build_null_str(String str) { return Proto.build_null_str(str, false); } public static byte[] build_null_str(String str, boolean base64) { int size = str.length() + 1; if (base64) size = Base64.decodeBase64(str).length + 1; return Proto.build_fixed_str(str.length() + 1, str, base64); } public static byte[] build_fixed_str(long size, String str) { return Proto.build_fixed_str((int)size, str); } public static byte[] build_fixed_str(long size, String str, boolean base64) { return Proto.build_fixed_str((int)size, str, base64); } public static byte[] build_fixed_str(int size, String str) { return Proto.build_fixed_str(size, str, false); } public static byte[] build_fixed_str(int size, String str, boolean base64) { byte[] packet = new byte[size]; byte[] strByte = null; if (base64) strByte = Base64.decodeBase64(str); else strByte = str.getBytes(); if (strByte.length < packet.length) size = strByte.length; System.arraycopy(strByte, 0, packet, 0, size); return packet; } public static byte[] build_eop_str(String str) { return Proto.build_eop_str(str, false); } public static byte[] build_eop_str(String str, boolean base64) { int size = str.length(); if (base64) size = Base64.decodeBase64(str).length; return Proto.build_fixed_str(size, str, base64); } public static byte[] build_filler(int len) { return Proto.build_filler(len, (byte)0x00); } public static byte[] build_filler(int len, int filler_value) { return Proto.build_filler(len, (byte)filler_value); } public static byte[] build_filler(int len, byte filler_value) { byte[] filler = new byte[len]; for (int i = 0; i < len; i++) filler[i] = filler_value; return filler; } public static byte[] build_byte(byte value) { byte[] field = new byte[1]; field[0] = value; return field; } public static char int2char(byte i) { return (char)i; } public static byte char2int(char i) { return (byte)i; } public long get_fixed_int(int size) { byte[] bytes = null; if ( this.packet.length < (size + this.offset)) return -1; bytes = new byte[size]; System.arraycopy(packet, offset, bytes, 0, size); this.offset += size; return this.get_fixed_int(bytes); } public static long get_fixed_int(byte[] bytes) { long value = 0; for (int i = bytes.length-1; i > 0; i--) { value |= bytes[i] & 0xFF; value <<= 8; } value |= bytes[0] & 0xFF; return value; } public void get_filler(int size) { this.offset += size; } public long get_lenenc_int() { int size = 0; // 1 byte int if (this.packet[offset] < 251) { size = 1; } // 2 byte int else if (this.packet[offset] == 252) { this.offset += 1; size = 2; } // 3 byte int else if (this.packet[offset] == 253) { this.offset += 1; size = 3; } // 8 byte int else if (this.packet[offset] == 254) { this.offset += 1; size = 8; } if (size == 0) { Logger.getLogger("MySQL.Proto").fatal("Decoding int at offset "+offset+" failed!"); return -1; } return this.get_fixed_int(size); } public String get_fixed_str(long len) { return this.get_fixed_str((int)len); } public String get_fixed_str(long len, boolean base64) { return this.get_fixed_str((int)len, base64); } public String get_fixed_str(int len) { int start = this.offset; int end = this.offset+len; if (end > this.packet.length) { end = this.packet.length; len = end - start; } StringBuilder str = new StringBuilder(len); for (int i = start; i < end; i++) { str.append(Proto.int2char(packet[i])); this.offset += 1; } return str.toString(); } public String get_fixed_str(int len, boolean base64) { int start = this.offset; int end = this.offset+len; if (end > this.packet.length) { end = this.packet.length; len = end - start; } if (!base64) return this.get_fixed_str(len); byte[] chunk = new byte[len]; System.arraycopy(this.packet, start, chunk, 0, len); this.offset += len; return Base64.encodeBase64String(chunk); } public String get_null_str() { return this.get_null_str(false); } public String get_null_str(boolean base64) { int len = 0; for (int i = this.offset; i < this.packet.length; i++) { if (packet[i] == 0x00) break; len += 1; } String str = this.get_fixed_str(len, base64); this.offset += 1; return str; } public String get_eop_str() { return this.get_eop_str(false); } public String get_eop_str(boolean base64) { int len = this.packet.length - this.offset; return this.get_fixed_str(len, base64); } public String get_lenenc_str() { return this.get_lenenc_str(false); } public String get_lenenc_str(boolean base64) { int len = (int)this.get_lenenc_int(); return this.get_fixed_str(len, base64); } public static byte[] arraylist_to_array(ArrayList<byte[]> input) { int size = 0; for (byte[] field: input) size += field.length; byte[] result = new byte[size]; int offset = 0; for (byte[] field: input) { System.arraycopy(field, 0, result, offset, field.length); offset += field.length; } return result; } public static byte[] packet_string_to_bytes(String str) { byte[] res = null; str = str.replaceAll("\\s","").toUpperCase(); try { res = Hex.decodeHex(str.toCharArray()); } catch (DecoderException e) {} return res; } }