Valhalla Legends Forums Archive | Battle.net Bot Development | Battle.net logging utility

AuthorMessageTime
Tuberload
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:
[code]/**
*      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;
   }   
}[/code]

CharBuffer.java:
[code]/**
*      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);
      }
   }
}[/code]

RawLog.java:
[code]/**
*      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));
   }
}[/code]

BNETLogger.java:
[code]/**
*      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() {}
}[/code]

Here is an example of how to use the utility:
[code]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);}
   }
}[/code]
April 9, 2004, 11:32 PM

Search