Util.Buffer
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:<BR> * DWord - 4 bytes<BR> * Word - 2 bytes<BR> * Byte - 1 byte<BR> * NTString - Any number of bytes, interpreted as characters, terminated by a null.<BR> * <P> * 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:<BR> *<PRE> * 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(); }
}