net.kano.joscar
Class BinaryTools

java.lang.Object
  extended bynet.kano.joscar.BinaryTools

public final class BinaryTools
extends java.lang.Object

Provides a set of methods for converting binary data sent over an OSCAR connection to various logical structures.

Note that for all types such that get[type] and write[type] exist, the two methods are inverses: calling getLong on a block written by writeLong will return the original value written.

The methods in this class attempt to be very robust: in the cases of the four-, two-, and one-byte unsigned integers (as in writeUShort(java.io.OutputStream, int)), if the given value is too large to fit into that size a block, it will be wrapped (for example, writeUShort(out, 65537) would be written to the stream as if writeUShort(out, 1) had been called). See UINT_MAX, USHORT_MAX, and UBYTE_MAX for the maximum values such methods can take without wrapping. Note that those values are not appropriate for the right-hand side of of a modulo operation (like 65537 % BinaryTools.USHORT_MAX), as these are maxima. (An appropriate operation, if one were necessary, would be 65537 % (BinaryTools.USHORT_MAX + 1).)

Another area in which the methods attempt to be robust is that except for getLong, none of these methods declare any exceptions. If a get[type](ByteBlock, int) method is passed a byte block that is too small, it simply returns -1 (this is okay because these methods only return unsigned values).

Lastly, it is important to note that all numbers transferred over OSCAR in unsigned format. Why do getLong and writeLong exist, you may ask, when they work with signed longs? Let me start by saying that nowhere in the OSCAR protocol is an eight-byte integer used. Why do these methods exist at all?, you may now ask. The answer is simple: IM and Rendezvous ID's are eight bytes, and are effectively represented as Java's long. Whether these values are read as signed or unsigned matters not, as the long is only an internal representation just as a ByteBlock is an internal representation of a block of bytes. I hope that explanation was clear enough.

See Also:
MiscTools, OscarTools

Field Summary
static short UBYTE_MAX
          Represents the largest value a one-byte unsigned integer can have.
static long UINT_MAX
          Represents the largest value a four-byte unsigned integer can have.
static int USHORT_MAX
          Represents the largest value a two-byte unsigned integer can have.
 
Method Summary
static java.lang.String describeData(ByteBlock data)
          Returns a string describing each byte in the given block in generic unsigned hexadecimal dump notation.
static byte[] getAsciiBytes(java.lang.String string)
          Returns a block of data representing the given US-ASCII string.
static java.lang.String getAsciiString(ByteBlock data)
          Returns a String representing the given block of ASCII characters.
static java.net.Inet4Address getIPFromBytes(ByteBlock data, int pos)
          Returns an IP address stored in the given byte block.
static long getLong(ByteBlock data, int pos)
          Returns the signed long stored in the given data block.
static byte[] getLong(long number)
          Returns a block of eight bytes representing the given signed long in binary format.
static StringBlock getNullPadded(ByteBlock block)
          Reads a null-padded ASCII string from the start of the given block.
static short getUByte(ByteBlock data, int pos)
          Returns an unsigned one-byte integer stored in the given block.
static byte[] getUByte(int number)
          Returns a single-byte block representing the given unsigned value in binary format.
static long getUInt(ByteBlock data, int pos)
          Returns the unsigned integer stored in the given data block.
static byte[] getUInt(long number)
          Returns a four-byte block representing the given unsigned value in binary format.
static int getUShort(ByteBlock data, int pos)
          Returns an unsigned two-byte integer stored in the given block.
static byte[] getUShort(int number)
          Returns a two-byte block representing the given unsigned value in binary format.
static void writeLong(java.io.OutputStream out, long number)
          Writes the given signed long to the given stream.
static void writeNullPadded(java.io.OutputStream out, ByteBlock block, int len)
          Writes the given block to the given stream, padded to a given length with null bytes (0x00).
static void writeUByte(java.io.OutputStream out, int number)
          Writes a single (unsigned) byte representing the given unsigned value to the given stream.
static void writeUInt(java.io.OutputStream out, long number)
          Writes a block of four bytes representing the given unsigned value to the given stream.
static void writeUShort(java.io.OutputStream out, int number)
          Writes a block of two bytes representing the given unsigned value to the given stream.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

UINT_MAX

public static final long UINT_MAX
Represents the largest value a four-byte unsigned integer can have. All numbers sent over OSCAR are unsigned.

See Also:
Constant Field Values

USHORT_MAX

public static final int USHORT_MAX
Represents the largest value a two-byte unsigned integer can have. All numbers sent over OSCAR are unsigned.

See Also:
Constant Field Values

UBYTE_MAX

public static final short UBYTE_MAX
Represents the largest value a one-byte unsigned integer can have. All numbers sent over OSCAR are unsigned.

See Also:
Constant Field Values
Method Detail

getLong

public static long getLong(ByteBlock data,
                           int pos)
                    throws java.lang.ArrayIndexOutOfBoundsException
Returns the signed long stored in the given data block. The returned long represents the first eight bytes after index pos of data; that is, the byte at index pos will be the first byte read, and index pos+7 the last.

Parameters:
data - the block of data to read from
pos - the starting index of data to read from
Returns:
a signed long representing the value stored in the first eight bytes of the given data block after the given position
Throws:
java.lang.ArrayIndexOutOfBoundsException - if there are fewer than eight bytes in data
See Also:
writeLong(java.io.OutputStream, long), getLong(long)

getUInt

public static long getUInt(ByteBlock data,
                           int pos)
Returns the unsigned integer stored in the given data block. The returned integer is extracted from the first four bytes of the given block, starting at index pos. If there are fewer than four bytes at pos, -1 is returned.

Note that this is returned as a long because all values of an unsigned four-byte integer cannot be stored in a four-byte signed integer, Java's int.

Parameters:
data - the data block from which to read
pos - the starting index of data to read from
Returns:
the value of the unsigned four-byte integer stored in the given block at the given index, or -1 if fewer than four bytes are present in the block
See Also:
writeUInt(java.io.OutputStream, long), getUInt(long)

getUShort

public static int getUShort(ByteBlock data,
                            int pos)
Returns an unsigned two-byte integer stored in the given block. The returned integer is extracted from the first two bytes of the given block, starting at index pos. If there are fewer than two bytes at pos, -1 is returned.

Note that this is returned as an int because all values of an unsigned two-byte integer cannot be stored in a signed short, Java's short.

Parameters:
data - the data block from which to read
pos - the starting index of data to read from
Returns:
the value of the two-byte integer stored at the given index of the given block, or -1 if fewer than two bytes exist at that index
See Also:
writeUShort(java.io.OutputStream, int), getUShort(int)

getUByte

public static short getUByte(ByteBlock data,
                             int pos)
Returns an unsigned one-byte integer stored in the given block. The returned integer is extracted from the byte of the given block at index pos. If there is no byte at pos, -1 is returned.

Note that this is returned as a short because all values of an unsigned one-byte integer cannot be stored in a signed byte, Java's byte.

Parameters:
data - the data block to read from
pos - the index in data of the byte to read
Returns:
the value of the single-byte integer stored at the given index of the given block, or -1 if there is no byte at that index (that is, if data.getLength() <= pos)
See Also:
writeUByte(java.io.OutputStream, int), getUByte(int)

getIPFromBytes

public static java.net.Inet4Address getIPFromBytes(ByteBlock data,
                                                   int pos)
Returns an IP address stored in the given byte block. The returned IP address is stored in the first four bytes of the given block, starting at pos. If fewer than four bytes exist at the given position, null is returned.

This merely duplicates the behavior of InetAddress.getByAddress(byte[]) (that is, it calls it :) and is only provided for convenience.

Parameters:
data - the data block to read from
pos - the starting index of the IP address block in data
Returns:
the IP address stored in the first four bytes of the given block starting at the given index, or null if fewer than four bytes exist at the given index
See Also:
InetAddress.getByAddress(byte[]), Inet4Address.getAddress()

describeData

public static java.lang.String describeData(ByteBlock data)
Returns a string describing each byte in the given block in generic unsigned hexadecimal dump notation. For example, "00 2f 8a 9b" would be returned if data contained { 0, 138, -118, -101 }.

Parameters:
data - the data block to describe
Returns:
a "hex dump" of the given block

writeLong

public static void writeLong(java.io.OutputStream out,
                             long number)
                      throws java.io.IOException
Writes the given signed long to the given stream. The value is written as an eight-byte signed integer.

Parameters:
out - the stream to write to
number - the value to write to the stream in binary format
Throws:
java.io.IOException - if an I/O error occurs
See Also:
getLong(long), getLong(ByteBlock, int)

writeUInt

public static void writeUInt(java.io.OutputStream out,
                             long number)
                      throws java.io.IOException
Writes a block of four bytes representing the given unsigned value to the given stream.

Parameters:
out - the stream to write to
number - the value to write to the stream in binary format
Throws:
java.io.IOException - if an I/O error occurs
See Also:
getUInt(long), getUInt(ByteBlock, int)

writeUShort

public static void writeUShort(java.io.OutputStream out,
                               int number)
                        throws java.io.IOException
Writes a block of two bytes representing the given unsigned value to the given stream.

Parameters:
out - the stream to write to
number - the value to write to the stream in binary format
Throws:
java.io.IOException - if an I/O error occurs
See Also:
getUShort(int), getUShort(ByteBlock, int)

writeUByte

public static void writeUByte(java.io.OutputStream out,
                              int number)
                       throws java.io.IOException
Writes a single (unsigned) byte representing the given unsigned value to the given stream.

Parameters:
out - the stream to write to
number - the value to write to the stream in binary format
Throws:
java.io.IOException - if an I/O error occurs
See Also:
getUByte(int), getUByte(ByteBlock, int)

getLong

public static byte[] getLong(long number)
Returns a block of eight bytes representing the given signed long in binary format.

Parameters:
number - the value to be written to the returned array
Returns:
an eight-byte block representing the given signed value
See Also:
writeLong(java.io.OutputStream, long), getLong(ByteBlock, int)

getUInt

public static byte[] getUInt(long number)
Returns a four-byte block representing the given unsigned value in binary format.

Parameters:
number - the value to be written to the returned array
Returns:
a four-byte binary representation of the given unsigned value
See Also:
writeUInt(java.io.OutputStream, long), getUInt(ByteBlock, int)

getUShort

public static byte[] getUShort(int number)
Returns a two-byte block representing the given unsigned value in binary format.

Parameters:
number - the value to be written to the returned array
Returns:
a two-byte binary representation of the given unsigned value
See Also:
writeUShort(java.io.OutputStream, int), getUShort(ByteBlock, int)

getUByte

public static byte[] getUByte(int number)
Returns a single-byte block representing the given unsigned value in binary format.

Parameters:
number - the value to be written to the returned array
Returns:
a one-byte binary representation of the given unsigned value
See Also:
writeUByte(java.io.OutputStream, int), getUByte(ByteBlock, int)

getAsciiBytes

public static byte[] getAsciiBytes(java.lang.String string)
Returns a block of data representing the given US-ASCII string. There is no need to ensure the given string is actually pure US-ASCII, as the charset encoder will encode any string as US-ASCII, replacing non-ASCII characters with '?'.

Many values sent over OSCAR connections are implicitly US-ASCII; for those unfamiliar with Unicode and character encodings, writing the returned byte block to an output stream is essentially the equivalent of simply writing a char[] or char* in C/C++ to a stream.

Parameters:
string - the string to be encoded in the returned array
Returns:
the given string converted to US-ASCII
See Also:
getAsciiString(net.kano.joscar.ByteBlock), String.getBytes(String)

getAsciiString

public static java.lang.String getAsciiString(ByteBlock data)
Returns a String representing the given block of ASCII characters.

Many values sent over OSCAR connections are implicitly US-ASCII; for those unfamiliar with Unicode and character encodings, calling this method on data read from a stream is essentially the equivalent of reading a char[] or char* in C/C++ from a stream.

Parameters:
data - the block of ASCII characters
Returns:
a String containing the (US-ASCII) characters in the given block
See Also:
getAsciiBytes(java.lang.String), String.String(byte[], String)

getNullPadded

public static StringBlock getNullPadded(ByteBlock block)
Reads a null-padded ASCII string from the start of the given block. The returned StringBlock contains an ASCII string formed from all of the bytes in the given block before the first null byte (0x00) or the end of the block. Note that the totalSize field of the returned StringBlock is the length of the string without the null byte. This is to avoid confusion when reading strings padded with more than one null byte or those not padded at all (that is, when the block consists only of an ASCII string with no null bytes).

Parameters:
block - a block of data containing an ASCII string followed by zero or more null (0x00) bytes
Returns:
a StringBlock containing the string extracted from the given block and the size of the string without the null byte(s) extracted, in bytes
See Also:
getAsciiString(net.kano.joscar.ByteBlock)

writeNullPadded

public static void writeNullPadded(java.io.OutputStream out,
                                   ByteBlock block,
                                   int len)
                            throws java.io.IOException
Writes the given block to the given stream, padded to a given length with null bytes (0x00). This method is guaranteed to write exactly len bytes to the given stream, only writing the first len bytes of the given block (and no null bytes) if block.getLength() > len.

Parameters:
out - a stream to which to write
block - the block to write to the given stream
len - the total number of bytes to write to the given stream
Throws:
java.io.IOException - if an I/O error occurs