Util.Buffer

From SkullSecurity
Revision as of 13:29, 29 February 2008 by Ron (talk | contribs) (New page: package util; /** Buffer.java * This class makes it easy for the programmer to create an array of bytes * of a specific format. It'll support these major types:<BR> * DWord - 4 bytes<...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

package util;

/** Buffer.java

* This class makes it easy for the programmer to create an array of bytes
* of a specific format.  It'll support these major types:
* DWord - 4 bytes
* Word - 2 bytes
* Byte - 1 byte
* NTString - Any number of bytes, interpreted as characters, terminated by a null.

*

* This is a pretty standard buffer in terms of everything else. I've used it extensively * and have complete confidence in it. * * @author Ron */ public class Buffer { /** The starting length of the buffer */ public final int defaultLength = 32; /** The actual buffer which will hold the data */ protected byte[] buffer; /** The current length of the buffer */ private int currentLength; /** The maximum length of the buffer */ private int maxLength; /** Initializes the variables */ public Buffer() { buffer = new byte[defaultLength]; currentLength = 0; maxLength = defaultLength; } /** Initialize the buffer to an array of bytes. * @param b The initial value. */ public Buffer(byte[] b) { this(); addBytes(b); } /** Initializes the buffer to another buffer. Note that it makes a copy, it doesn't share * the data. * @param b The original buffer. */ public Buffer(Buffer b) { this(); addBytes(b.getBytes()); } public Buffer(char []c) { this(); for(int i = 0; i < c.length; i++) addByte((byte) c[i]); } /** Returns the size of the buffer */ public int size() { return currentLength; } /** Returns the entire buffer as an array of bytes. * @return The entire buffer as an array of bytes. */ public byte[] getBytes() { byte[] ret = new byte[currentLength]; System.arraycopy(buffer, 0, ret, 0, currentLength); return ret; } /** Ensures that there is enough length to store the specified number of bytes. If there * isn't, enough extra room is allocated so we can. * * @param bytes The number of bytes we'return adding to it. */ private void verifyLength(int bytes) { // If we already have enough, just return if((currentLength + bytes) <= maxLength) return; while((currentLength + bytes) > maxLength) { maxLength = maxLength * 2; } // Create a new buffer byte[] newBuffer = new byte[maxLength]; // Copy the old buffer into the new buffer System.arraycopy(buffer, 0, newBuffer, 0, currentLength); // Set the current buffer to the new buffer buffer = newBuffer; } /** Shifts all data back by the requested number of bytes, and returns the * bytes that were shifted off. * * @param number The number of bytes to pull off the beginning. * @return The bytes that were pulled off. */ protected byte[] remove(int number) { byte[] ret = new byte[number]; System.arraycopy(buffer, 0, ret, 0, number); System.arraycopy(buffer, number, buffer, 0, currentLength - number); currentLength -= number; return ret; } /** Adds a single byte to the end of the buffer . * @param b The byte to add. */ public void addByte(byte b) { verifyLength(1); buffer[currentLength++] = b; } /** Removes a single byte from the beginning of the buffer. * @return The byte that was removed. * @throws IndexOutOfBoundsException If there isn't enough room in the buffer to accomidate the * requested removal. */ public byte removeByte() throws IndexOutOfBoundsException { if(currentLength == 0) throw new IndexOutOfBoundsException("Attempted to remove data from the buffer that wasn't there."); return remove(1)[0]; } /** Returns the byte at a specific location. * @param index The location to get the byte at. * @return The byte at location "index". */ public byte byteAt(int index) { return buffer[index]; } /** Adds a word to the buffer (2 bytes, little endian). * @param w The word to add. */ public void addWord(short w) { addByte((byte)((w & 0x00FF) >> 0)); addByte((byte)((w & 0xFF00) >> 8)); } /** Removes and returns a single word (2 bytes). * @return The word that was removed. * @throws IndexOutOfBoundsException If there isn't enough room in the buffer to accomidate the * requested removal. */ public short removeWord() throws IndexOutOfBoundsException { int ret = ((removeByte() << 0) & 0x000000FF) | ((removeByte() << 8) & 0x0000FF00); return (short)(ret & 0x0000FFFF); } /** Adds a dword to the buffer (4 bytes, little endian). * @param d The dword to add. */ public void addDWord(int d) { addByte((byte)((d & 0x000000FF) >> 0)); addByte((byte)((d & 0x0000FF00) >> 8)); addByte((byte)((d & 0x00FF0000) >> 16)); addByte((byte)((d & 0xFF000000) >> 24)); } public void addArray(int []a) { for(int i = 0; i < a.length; i++) addDWord(a[i]); } /** Removes and returns a single dword (4 bytes). * @return The DWord that was removed. * @throws IndexOutOfBoundsException If there isn't enough room in the buffer to accomidate the * requested removal. */ public int removeDWord() throws IndexOutOfBoundsException { return ((removeByte() << 0) & 0x000000FF) | ((removeByte() << 8) & 0x0000FF00) | ((removeByte() << 16) & 0x00FF0000) | ((removeByte() << 24) & 0xFF000000); } /** Adds a QWord to the buffer (8 bytes, little endian) * @param l The value to add. */ public void addLong(long l) { addByte((byte)((l & 0x00000000000000FFl) >> 0l)); addByte((byte)((l & 0x000000000000FF00l) >> 8l)); addByte((byte)((l & 0x0000000000FF0000l) >> 16l)); addByte((byte)((l & 0x00000000FF000000l) >> 24l)); addByte((byte)((l & 0x000000FF00000000l) >> 32l)); addByte((byte)((l & 0x0000FF0000000000l) >> 40l)); addByte((byte)((l & 0x00FF000000000000l) >> 48l)); addByte((byte)((l & 0xFF00000000000000l) >> 56l)); } /** Removes and returns a single dword (8 bytes). * @return The long at the beginning of the buffer. * @throws IndexOutOfBoundsException If there isn't enough room in the buffer to accomidate the * requested removal. */ public long removeLong() throws IndexOutOfBoundsException { return (((long)removeByte() << 0L) & 0x00000000000000FFL) | (((long)removeByte() << 8L) & 0x000000000000FF00L) | (((long)removeByte() << 16L) & 0x0000000000FF0000L) | (((long)removeByte() << 24L) & 0x00000000FF000000L) | (((long)removeByte() << 32L) & 0x000000FF00000000L) | (((long)removeByte() << 40L) & 0x0000FF0000000000L) | (((long)removeByte() << 48L) & 0x00FF000000000000L) | (((long)removeByte() << 56L) & 0xFF00000000000000L); } /** Adds a non-null-terminated string to the buffer * @param s The string to add to the buffer. */ public void addString(String s) { for(int i = 0; i < s.length(); i++) { addByte((byte) s.charAt(i)); } } /** Removes 'i' bytes from the buffer, and returns them as a string * @param i The number of bytes to remove. * @return The bytes removed as a String. * @throws IndexOutOfBoundsException If there isn't enough room in the buffer to accomidate the * requested removal. */ public String removeString(int i) throws IndexOutOfBoundsException { StringBuffer s = new StringBuffer(i + 1); for(int j = 0; j < i; j++) { s.append((char) removeByte()); } return s.toString(); } /** Adds a null-terminated string to the buffer, including the null * @param s The string to add, without the null terminator. */ public void addNTString(String s) { addString(s); addByte((byte) 0x00); } /** Removes and returns a null-terminated string, without the null * @return The first null-terminatred string in the buffer, without the null. * @throws IndexOutOfBoundsException If the buffer ended before finding a Null. */ public String removeNTString() { StringBuffer s = new StringBuffer(); byte b = removeByte(); while(b != (byte) 0x00) { s.append((char) (b & 0x000000FF)); b = removeByte(); } return s.toString(); } /** Adds an array of bytes to the buffer * @param b The bytes to add to the buffer. */ public void addBytes(byte[] b) { for(int i = 0; i < b.length; i++) addByte(b[i]); } /** Removes 'i' bytes from the array and returns them as an array of bytes. * @param i The number of bytes to remove. * @return The bytes that were removed. * @throws IndexOutOfBoundsException If there isn't enough room in the buffer to accomidate the * requested removal. */ public byte[] removeBytes(int i) throws IndexOutOfBoundsException { return remove(i); } /** Adds another buffer to the end of the buffer. All it actually does is add the bytes * of the source to the current buffer. * @param b The buffer to add. */ public void addBuffer(Buffer b) { addBytes(b.getBytes()); } /** Quicly add a byte to the buffer. * @param b The byte to add. */ public void add(byte b) { addByte(b); } /** Quickly add a short to the buffer. * @param s The short to add. */ public void add(short s) { addWord(s); } /** Quickly add an int to the buffer. * @param i The inteter to add. */ public void add(int i) { addDWord(i); } public void add(int []i) { addArray(i); } /** Quickly add a long to the buffer. * @param l The long to add. */ public void add(long l) { addLong(l); } /** Quickly add an array of bytes to the buffer. * @param b The array of bytes. */ public void add(byte[] b) { addBytes(b); } /** Quickly append another buffer to the current buffer. * @param b The source buffer. */ public void add(Buffer b) { addBuffer(b); } /** Gets the buffer, formatted in a pretty way. * @return The formatted string. It might look something like this:
*

     *      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F    ................
     *      69 68 67 66 65 64 63 62 61 61 6A 6B 6C 6D 6E 00    ihgfedcbaajklmn.
     *      41 00                                              A.
     *      Length: 34
     *
    */
   public String toString()
   {
       StringBuffer returnString = new StringBuffer( (currentLength * 3) + // The hex
                                                     (currentLength) +     // The ascii
                                                     (currentLength / 4) + // The tabs/\n's
                                                     30 );                 // The text
       
       //returnString.append("Buffer contents:\n");
       int i, j; // Loop variables
       for(i = 0; i < currentLength; i++)
       {
           if((i != 0) && (i % 16 == 0))
           {
               // If it's a multiple of 16 and i isn't null, show the ascii
               returnString.append('\t');
               for(j = i - 16; j < i; j++)
               {
                   if(buffer[j] < 0x20 || buffer[j] > 0x7F)
                       returnString.append('.');
                   else
                       returnString.append((char)buffer[j]);
               }
               // Add a linefeed after the string
               returnString.append("\n");
           }
   
           returnString.append(Integer.toString((buffer[i] & 0xF0) >> 4, 16) +
                   Integer.toString((buffer[i] & 0x0F) >> 0, 16));
           returnString.append(' ');
       }
       
       // Add padding spaces if it's not a multiple of 16
       if(i != 0 && i % 16 != 0)
       {
           for(j = 0; j < ((16 - (i % 16)) * 3); j++)
           {
               returnString.append(' ');
           }
       }
       // Add the tab for alignment
       returnString.append('\t');
   
       // Add final chararacters at right, after padding
   
       // If it was at the end of a line, print out the full line
       if(i > 0 && (i % 16) == 0)
       {
           j = i - 16;
       }    
       else
       {
           j = (i - (i % 16));
       }
   
       for(; i >= 0 && j < i; j++)
       {
           if(buffer[j] < 0x20 || buffer[j] > 0x7F)
               returnString.append('.');
           else
               returnString.append((char) buffer[j]);
       }
   
       // Finally, tidy it all up with a newline
       returnString.append('\n');
       returnString.append("Length: " + currentLength + '\n');
   
       return returnString.toString();
   }

}