Here is the logging utility I have been working on. Thanks goes out to Myndfyre for the original idea. I hope someone finds this useful. Please post any suggestions/comments you may have.
ConnectionType.java:
/**
* A type safe enum used to represent the different connection types on
* Battle.net. Thanks goes out to Myndfyre for the original idea.
*
* @author Tuberload
* @version 1.0
*/
import java.util.*;
public final class ConnectionType
{
// static definitions for all blizzard games
public static final ConnectionType STARCRAFT_SHAREWARE
= new ConnectionType ("Starcraft Shareware", "SSHR", 0xA5);
public static final ConnectionType STARCRAFT_JAPANESE
= new ConnectionType ("Starcraft Japanese", "JSTR", 0xA9);
public static final ConnectionType STARCRAFT
= new ConnectionType ("Starcraft", "STAR", 0xC7);
public static final ConnectionType STARCRAFT_BROODWAR
= new ConnectionType ("Starcraft Broodwar", "SEXP", 0xC7);
public static final ConnectionType DIABLO_SHAREWARE
= new ConnectionType ("Diablo Shareware", "DSHR", 0x2A);
public static final ConnectionType DIABLO
= new ConnectionType ("Diablo I", "DRTL", 0x2A);
public static final ConnectionType DIABLO_II
= new ConnectionType ("Diablo II", "D2DV", 0x0A);
public static final ConnectionType DIABLO_II_LOD
= new ConnectionType ("Diablo II: Lord of Destruction", "D2XP", 0x0A);
public static final ConnectionType WARCRAFT_II
= new ConnectionType ("Warcraft II", "W2BN", 0x4F);
public static final ConnectionType WARCRAFT_III
= new ConnectionType ("Warcraft III", "WAR3", 0x0D);
public static final ConnectionType WARCRAFT_III_TFT
= new ConnectionType ("Warcraft II: The Frozen Throne", "W3XP", 0x0D);
// static definitions for all other valid connection types.
public static final ConnectionType CHAT
= new ConnectionType ("Chat Gateway", "CHAT", 0x0);
public static final ConnectionType VL_BOTNET
= new ConnectionType ("vL Botnet", "VLBN", 0x0);
public static final ConnectionType BNLS
= new ConnectionType ("Battle.net Logon System", "BNLS", 0x0);
private static final ConnectionType[] TYPES = { STARCRAFT_SHAREWARE,
STARCRAFT_JAPANESE, STARCRAFT, STARCRAFT_BROODWAR, DIABLO_SHAREWARE,
DIABLO, DIABLO_II, DIABLO_II_LOD, WARCRAFT_II, WARCRAFT_III,
WARCRAFT_III_TFT, CHAT, VL_BOTNET, BNLS, CHAT};
// instance variables for enum values
private final String product;
private final String product_id;
private final int version;
/**
* CONNECTION_TYPES is an unmodifiable list of connection types
* available.
*/
public static final List CONNECTION_TYPES = Collections.unmodifiableList
(Arrays.asList (TYPES));
/**
* Return information on the specific connection type.
*/
public String toString()
{
StringBuffer buf1 = new StringBuffer();
if (version != 0x0)
buf1.append (product + "(" + product_id + "): version " +
formatVersion (version));
else buf1.append (product + "(" + product_id + ")");
return buf1.toString();
}
/**
* Pad product versions.
*/
private static String formatVersion (int version)
{
StringBuffer buf1 = new StringBuffer();
String tmp = Integer.toHexString (version);
buf1.append ("0x");
if (tmp.length() < 2)
buf1.append ("0");
buf1.append (tmp);
return buf1.toString();
}
/**
* Prevent outside instantiation of the object.
*/
private ConnectionType (String product, String id, int version)
{
this.product = product;
this.product_id = id;
this.version = version;
}
}
CharBuffer.java:
/**
* A character buffer. Allows data to be inserted in a hexadecimal dump
* format. Thanks goes out to Myndfyre for his original logger that gave me
* this idea.
*
* @author Tuberload
* @version 1.0
*/
public class CharBuffer
{
private char[] buffer;
private int size;
private int position;
/**
* Initialize the character buffer with an initial capacity.
*/
public CharBuffer (int capacity)
{
if (capacity > 0) size = capacity;
else size = 255;
buffer = new char[size];
position = 0;
}
/**
* Initialize the character buffer with the default capacity.
*/
public CharBuffer()
{
buffer = new char[255];
size = 255;
position = 0;
}
/**
* Reset the buffer using the previously determined size.
*/
public void reset()
{
buffer = new char[size];
position = 0;
}
/**
* Reset the buffer using a new size.
*/
public void reset (int capacity)
{
if (capacity > 0) size = capacity;
else size = 255;
buffer = new char[size];
position = 0;
}
/**
* Insert a string into the character buffer.
*/
public void insertString (String string)
{
if (string == null) throw new NullPointerException();
insureCapacity (string.length());
string.getChars (0, string.length(), buffer, position);
position += string.length();
}
/**
* Insert a character array.
*/
public void insertCharArray (char[] char_array)
{
if (char_array == null) throw new NullPointerException();
insureCapacity (char_array.length+position);
System.arraycopy (char_array, 0, buffer, position, char_array.length);
position += char_array.length;
}
/**
* Insert an integer array formated to look like hexadecimal output.
*/
public void insertHexDump (int[] data)
{
if (data == null) throw new NullPointerException();
StringBuffer buf1 = new StringBuffer();
for (int i = 0; i < data.length; i += 16)
{
buf1.append (formatOffset (i));
buf1.append (" ");
int length = (data.length - i) > 16 ? 16 : data.length-i;
int[] tmp1 = new int[length];
System.arraycopy (data, i, tmp1, 0, tmp1.length);
StringBuffer tmp2 = new StringBuffer (formatIntArray (tmp1));
while (tmp2.length() < 59) tmp2.append (" ");
buf1.append (tmp2);
buf1.append (formatIntToString (tmp1));
buf1.append ("\r\n");
}
insertString (buf1.toString());
/*char[] insert = new char[buf1.length()];
buf1.getChars (0, buf1.length(), insert, 0);
insertCharArray (insert);*/
}
/**
* Insert a new line into the buffer.
*/
public void insertNewLine()
{
insureCapacity (1);
buffer[position] = '\r';
buffer[position+1] = '\n';
position += 2;
}
/**
* Return a character array representation of the buffer.
*/
/*public char[] getCharArray()
{
return buffer;
}*/
/**
* Return the character buffer as a String. Makes sure empty characters
* are not included.
*/
public String toString()
{
String tmp = String.valueOf (buffer).trim() + "\r\n";
return tmp;
}
/**
* Format the integer array into a string.
*/
private String formatIntToString(int[] data)
{
char tmp;
if (data.length > 16) throw new IllegalArgumentException
("When formatting a int array, the data cannot exceed 16.");
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++)
{
tmp = (char)data[i];
if (Character.isISOControl (tmp)) buf.append (".");
else buf.append ((char)data[i]);
}
return buf.toString();
}
/**
* Format an array of integers to look like hexadecimal output.
*/
private String formatIntArray (int[] data)
{
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++)
{
buf.append (formatInt (data[i]));
buf.append (" ");
if (((i+1) % 8) == 0) buf.append (" ");
}
return buf.toString();
}
/**
* Format an integer to look like hexadecimal output.
*/
private String formatInt (int integer)
{
StringBuffer buf = new StringBuffer (Integer.toHexString (integer));
while (buf.length() < 2) buf.insert (0, "0");
return buf.toString();
}
/**
* Format an integer to look like the offset in a hexadecimal dump.
*/
private String formatOffset (int offset)
{
StringBuffer buf = new StringBuffer (Integer.toHexString (offset));
while (buf.length() < 4) buf.insert (0, "0");
return buf.toString();
}
/**
* Insure the capacity of the buffer is large enough to handle data.
*/
private void insureCapacity (int length)
{
if ((position+length) >= buffer.length)
{
char[] tmp = new char[buffer.length];
System.arraycopy (buffer, 0, tmp, 0, buffer.length);
buffer = new char[buffer.length + (length+1)];
System.arraycopy (tmp, 0, buffer, 0, tmp.length);
}
}
}
RawLog.java:
/**
* A simple character logger. Thanks goes out to Myndfyre for giving me
* the idea to create this.
*
* @author Tuberload
* @version 1.0
*/
import java.io.*;
public class RawLog
{
protected static RawLog log;
protected static BufferedWriter out_stream;
protected static String path;
/**
* Initialize the logger by specifying the path to the log file.
*/
public static void init (String path) throws IOException
{
log = new RawLog (path);
}
/**
* Closed the stream to the log file.
*/
public static void close() throws IOException
{
out_stream.flush();
out_stream.close();
}
/**
* Places an entry into the log file.
*/
public static void log (CharBuffer buffer) throws IOException
{
out_stream.write (buffer.toString());
out_stream.newLine();
}
/**
* Places a string into the log file.
*/
public static void log (String data) throws IOException
{
out_stream.write (data);
out_stream.newLine();
}
/**
* Constructor is made protected to insure only one instance can be,
* created, and allows subclasses to be created.
*/
protected RawLog (String path) throws IOException
{
this.path = path;
File file = new File (path);
if (!file.exists())
file.createNewFile();
out_stream = new BufferedWriter (new FileWriter (file, true));
}
}
BNETLogger.java:
/**
* A utility for logging Battle.net and Battle.net related data. Thanks
* goes out to Myndfyre for the idea.
*
* @author Tuberload
* @version 1.0
*/
import java.io.*;
import java.util.Calendar;
import java.text.DateFormat;
public class BNETLogger
{
/**
* Initialize the logging utility.
*/
public static void init (String path) throws IOException
{
RawLog.init (path);
}
/**
* Add an entry to the log file.
*/
public static void log (int[] data, ConnectionType type,
boolean incoming) throws IOException
{
Calendar cal = Calendar.getInstance();
DateFormat d_format = DateFormat.getDateTimeInstance (DateFormat.LONG,
DateFormat.LONG);
String time = d_format.format (cal.getTime());
StringBuffer buf2 = new StringBuffer();
CharBuffer buf = new CharBuffer();
buf.insertHexDump (data);
buf.insertNewLine();
if (incoming) buf2.append ("Incoming data recieved ");
else buf2.append ("Outgoing data sent ");
buf2.append (time);
buf2.append (" via ");
buf2.append (type.toString());
RawLog.log (buf2.toString());
RawLog.log (buf);
}
/**
* Close the log file.
*/
public static void close() throws IOException
{
RawLog.close();
}
/**
* Make sure only one instance of the logging utility can be created.
*/
private BNETLogger() {}
}
Here is an example of how to use the utility:
import java.io.*;
public class test
{
public static void main (String[] args)
{
int[] data = { 0x17, 0x00, 0x03, 0xdf, 0xd1, 0x13, 0x8b, 0x97 , 0x41,
0x0c, 0x67, 0x96, 0x8d, 0x48, 0x0e, 0x5d, 0x3c, 0x56, 0x7e, 0x16,
0x70, 0xd5, 0x0d };
int[] data2 = { 0x0b, 0x00, 0x0e, 0x41, 0x72, 0x6d, 0x61, 0x42, 0x6f,
0x74, 0x00 };
try
{
BNETLogger.init ("test.txt");
BNETLogger.log (data, ConnectionType.DIABLO_II, true);
BNETLogger.log (data2, ConnectionType.BNLS, false);
BNETLogger.close();
} catch (IOException exc) {System.out.println (exc);}
}
}