FileDocCategorySizeDatePackage
DataElementSerializer.javaAPI DocphoneME MR2 API (J2ME)22464Wed May 02 18:00:32 BST 2007com.sun.kvem.jsr082.bluetooth

DataElementSerializer

public class DataElementSerializer extends Object
Serializes and restores DataElement objects.

Fields Summary
private static final byte
NULL_DATA
NULL data header.
private static final byte
BOOLEAN_DATA
Boolean data header.
private static final byte
INT1_SIGNED
1-byte signed integer header.
private static final byte
INT2_SIGNED
2-byte signed integer header.
private static final byte
INT4_SIGNED
4-byte signed integer header.
private static final byte
INT8_SIGNED
8-byte signed integer header.
private static final byte
INT16_SIGNED
16-byte signed integer header.
private static final byte
INT1_UNSIGNED
1-byte unsigned integer header.
private static final byte
INT2_UNSIGNED
2-byte unsigned integer header.
private static final byte
INT4_UNSIGNED
4-byte unsigned integer header.
private static final byte
INT8_UNSIGNED
8-byte unsigned integer header.
private static final byte
INT16_UNSIGNED
16-byte unsigned integer header.
private static final byte
UUID_2
16-bit UUID header.
private static final byte
UUID_4
32-bit UUID header.
private static final byte
UUID_16
128-bit UUID header.
private static final byte
TYPE_MASK
Mask to get type tag from header.
private static final byte
SIZE_MASK
Mask to get size of data size field from header.
private static final byte
STRING_TYPE
Tag for string type.
private static final byte
SEQUENCE_TYPE
Tag for sequence type.
private static final byte
ALTERNATIVE_TYPE
Tag for an alternative type.
private static final byte
SHORT_SIZE
Tag that identifies that size of data size field is 2 bytes.
private static final byte
NORMAL_SIZE
Tag that identifies that size of data size field is 4 bytes.
private static final byte
LONG_SIZE
Tag that identifies that size of data size field is 8 bytes.
protected byte[]
writeBuffer
Destination buffer which collects binary data of a data element.
protected byte[]
readBuffer
Source buffer which contains binary data of a data element.
protected long
writePos
Current position at the destination buffer.
protected long
readPos
Current position at the source buffer.
private Stack
readPosStack
Allows to store and retrieve positions at the source buffer.
Constructors Summary
DataElementSerializer()
Constructs the serializer object.


             
     
    
Methods Summary
longgetDataSize(javax.bluetooth.DataElement data)
Returns the size of DataElement with service information to get the total size required to work with this DataElement.

param
data the data element to get packet size for
return
number of bytes needed to store given data element

        int type = data.getDataType();
        long size = getPureDataSize(data);
        if ((type == DataElement.NULL) || (type == DataElement.BOOL)
                || (type == DataElement.INT_1) || (type == DataElement.U_INT_1)
                || (type == DataElement.INT_2) || (type == DataElement.U_INT_2)
                || (type == DataElement.INT_4) || (type == DataElement.U_INT_4)
                || (type == DataElement.INT_8) || (type == DataElement.U_INT_8)
                || (type == DataElement.INT_16)
                || (type == DataElement.U_INT_16)
                || (type == DataElement.UUID)) {
            return size + 1;
        } else if ((type == DataElement.DATSEQ)
                || (type == DataElement.DATALT) || (type == DataElement.STRING)
                || (type == DataElement.URL)) {
            if (size <= 0xffL) {
                return size + 2;
            } else if (size <= 0xffffL) {
                return size + 3;
            } else if (size <= 0xffffffffL) {
                return size + 5;
            } else {
                throw new RuntimeException("Data size is too large.");
            }
        } else {
            throw new RuntimeException("Unexpected data type.");
        }
    
longgetPureDataSize(javax.bluetooth.DataElement data)
Returns the size of DataElement without service information.

param
data the data element to get pure data size for
return
pure data size in bytes

        switch (data.getDataType()) {
            case DataElement.NULL:
                return 0;
            case DataElement.BOOL:
            case DataElement.INT_1:
            case DataElement.U_INT_1:
                return 1;
            case DataElement.INT_2:
            case DataElement.U_INT_2:
                return 2;
            case DataElement.INT_4:
            case DataElement.U_INT_4:
                return 4;
            case DataElement.INT_8:
            case DataElement.U_INT_8:
                return 8;
            case DataElement.INT_16:
            case DataElement.U_INT_16:
                return 16;
            case DataElement.DATSEQ:
            case DataElement.DATALT:
                long size = 0;
                Enumeration elements = (Enumeration)data.getValue();
                while (elements.hasMoreElements()) {
                    size += getDataSize((DataElement)elements.nextElement());
                }
                return size;
            case DataElement.STRING:
            case DataElement.URL:
                return ((String)data.getValue()).length();
            case DataElement.UUID:
                return 16;
            default:
                throw new RuntimeException("Unknown data type.");
        }
    
private longpopReadPos()
Extracts saved read position.

        return ((Long)readPosStack.pop()).longValue();
    
private voidpushReadPos()
Saves the current read position.

        readPosStack.push(new Long(readPos));
    
booleanreadBoolean()
Reads boolean value from the connection.

return
boolean value recieved.
throws
IOException if an I/O error occurs

        return (readByte() != 0);
    
bytereadByte()
Reads 1-byte value from the connection.

return
byte recieved.
throws
IOException if an I/O error occurs

        if (readPos < 0 || readPos >= readBuffer.length) {
            throw new IndexOutOfBoundsException();
        }
        return readBuffer[(int)readPos++];
    
byte[]readBytes(int size)
Reads given number of bytes from the connection.

param
size number of bytes to read.
return
array of bytes read.
throws
IOException if an I/O error occurs

        byte[] data = new byte[size];
        int dataPos = 0;
        if (readPos < 0 || readPos + data.length > readBuffer.length) {
            throw new IndexOutOfBoundsException();
        }
        System.arraycopy(readBuffer, (int)readPos, data, 0, data.length);
        readPos += data.length;
        return data;
    
javax.bluetooth.DataElementreadDataElement()
Creates a data element from the binary data in the read buffer.

return
DataElement read
throws
IOException if an I/O error occurs

        byte header = readByte();
        if ((header == NULL_DATA) || (header == BOOLEAN_DATA)
                || (header == INT1_SIGNED) || (header == INT1_UNSIGNED)
                || (header == INT2_SIGNED) || (header == INT2_UNSIGNED)
                || (header == INT4_SIGNED) || (header == INT4_UNSIGNED)
                || (header == INT8_SIGNED) || (header == INT8_UNSIGNED)
                || (header == INT16_SIGNED) || (header == INT16_UNSIGNED)) {
            switch (header) {
            case NULL_DATA:
                return new DataElement(DataElement.NULL);
            case BOOLEAN_DATA:
                return new DataElement(readBoolean());
            case INT1_SIGNED:
                return new DataElement(DataElement.INT_1, readByte());
            case INT1_UNSIGNED:
                return new DataElement(DataElement.U_INT_1,
                        (readByte() & 0xffL));
            case INT2_SIGNED:
                return new DataElement(DataElement.INT_2, readShort());
            case INT2_UNSIGNED:
                return new DataElement(DataElement.U_INT_2,
                        (readShort() & 0xffffL));
            case INT4_SIGNED:
                return new DataElement(DataElement.INT_4, readInteger());
            case INT4_UNSIGNED:
                return new DataElement(DataElement.U_INT_4,
                        (readInteger() & 0xffffffffL));
            case INT8_SIGNED:
                return new DataElement(DataElement.INT_8, readLong());
            case INT8_UNSIGNED:
                return new DataElement(DataElement.U_INT_8, readBytes(8));
            case INT16_SIGNED:
                return new DataElement(DataElement.INT_16, readBytes(16));
            case INT16_UNSIGNED:
                return new DataElement(DataElement.U_INT_16, readBytes(16));
            }
        } else if (((header & TYPE_MASK) == STRING_TYPE)
                || ((header & TYPE_MASK) == SEQUENCE_TYPE)
                || ((header & TYPE_MASK) == ALTERNATIVE_TYPE)) {
            long size = 0;
            if ((header & SIZE_MASK) == SHORT_SIZE) {
                size = readByte() & 0xffL;
            } else if ((header & SIZE_MASK) == NORMAL_SIZE) {
                size = readShort() & 0xffffL;
            } else if ((header & SIZE_MASK) == LONG_SIZE) {
                size = readInteger() & 0xffffffffL;
            } else {
                System.err.println("Unknown size mask.");
            }
            if ((header & TYPE_MASK) == STRING_TYPE) {
                return new DataElement(DataElement.STRING,
                        new String(readBytes((int)size)));
            } else {
                DataElement data = null;
                DataElement dataElement = null;
                long dataPos = 0;
                if ((header & TYPE_MASK) == SEQUENCE_TYPE) {
                    data = new DataElement(DataElement.DATSEQ);
                } else {
                    data = new DataElement(DataElement.DATALT);
                }
                while (dataPos < size) {
                    pushReadPos();
                    dataElement = readDataElement();
                    dataPos += readPos - popReadPos();
                    data.addElement(dataElement);
                }
                return data;
            }
        } else if (header == UUID_2) {
            return new DataElement(DataElement.UUID, readUUID(2));
        } else if (header == UUID_4) {
            return new DataElement(DataElement.UUID, readUUID(4));
        } else if (header == UUID_16) {
            return new DataElement(DataElement.UUID, readUUID(16));
        } else {
            throw new RuntimeException("Unknown data type.");
        }
        return null;
    
intreadInteger()
Reads 4-byte value from the connection.

return
int which is the 4 bytes read.
throws
IOException if an I/O error occurs

        int data1 = ((int)readShort()) & 0xffff;
        int data2 = ((int)readShort()) & 0xffff;
        return ((data1 << 16) + (data2 << 0));
    
longreadLong()
Reads 8-byte value from the connection.

return
long which is the 8 bytes read.
throws
IOException if an I/O error occurs

        long data1 = ((long)readInteger()) & 0xffffffffL;
        long data2 = ((long)readInteger()) & 0xffffffffL;
        return ((data1 << 32) + (data2 << 0));
    
shortreadShort()
Reads 2-byte value from the connection.

return
short which is the 2 bytes read.
throws
IOException if an I/O error occurs

        int data1 = ((int)readByte()) & 0xff;
        int data2 = ((int)readByte()) & 0xff;
        return (short)((data1 << 8) + (data2 << 0));
    
javax.bluetooth.UUIDreadUUID(int len)
Reads UUID of a given size.

param
len number of bytes to read
return
UUID created from len bytes
throws
IOException if an I/O error occurs

        String uuid = "";
        for (int i = 0; i < len; i++) {
            String digit = Integer.toHexString(readByte() & 0xff);
            if (digit.length() == 1) digit = '0" + digit;
            uuid += digit;
        }
        return new UUID(uuid, len < 16);
    
public synchronized javax.bluetooth.DataElementrestore(byte[] data)
Constructs DataElement from byte array containing the element in serialized form.

param
data byte array containing the element in serialized form
return
DataElement constructed from the binary data
throws
IOException if an I/O error occurs

        readBuffer = data;
        readPos = 0;
        DataElement result = readDataElement();
        readBuffer = null;
        return result;
    
public synchronized byte[]serialize(javax.bluetooth.DataElement data)
Serializes given DataElement object, i.e. creates an array of bytes representing DataElement as described in Bluetooth Specification Version 1.2, vol 3, page 127.

param
data the data element to serialize
return
an array containing the serialized data element
throws
IOException if an I/O error occurs

        writeBuffer = new byte[(int)getDataSize(data)];
        writePos = 0;
        writeDataElement(data);
        byte[] result = writeBuffer;
        writeBuffer = null;
        return result;
    
voidwriteBoolean(boolean data)
Writes boolean data to the buffer. Writes only value given itself. Note that boolean data header should be written before.

param
data boolean value to write.
throws
IOException if an I/O error occurs

        writeByte(data ? 1 : 0);
    
voidwriteByte(long data)
Writes 1-byte data to the buffer.

param
data byte value to write.
throws
IOException if an I/O error occurs

        if (writePos < 0 || writePos >= writeBuffer.length) {
            throw new IndexOutOfBoundsException();
        }
        writeBuffer[(int)writePos++] = (byte)data;
    
voidwriteBytes(byte[] data)
Writes given data to the connection.

param
data bytes to write.
throws
IOException if an I/O error occurs

        if (writePos < 0 || writePos + data.length > writeBuffer.length) {
            throw new IndexOutOfBoundsException();
        }
        System.arraycopy(data, 0, writeBuffer, (int)writePos, data.length);
        writePos += data.length;
    
voidwriteDataElement(javax.bluetooth.DataElement data)
Writes given data element into the write buffer.

param
data the data element to write
throws
IOException if an I/O error occurs

        long size = getPureDataSize(data);
        int type = data.getDataType();
        byte typeBits = 0x00;
        if ((type == DataElement.NULL) || (type == DataElement.BOOL)
                || (type == DataElement.INT_1) || (type == DataElement.U_INT_1)
                || (type == DataElement.INT_2) || (type == DataElement.U_INT_2)
                || (type == DataElement.INT_4) || (type == DataElement.U_INT_4)
                || (type == DataElement.INT_8) || (type == DataElement.U_INT_8)
                || (type == DataElement.INT_16)
                || (type == DataElement.U_INT_16)) {
            switch (type) {
                case DataElement.NULL:
                    writeByte(NULL_DATA);
                    break;
                case DataElement.BOOL:
                    writeByte(BOOLEAN_DATA);
                    writeBoolean(data.getBoolean());
                    break;
                case DataElement.INT_1:
                    writeByte(INT1_SIGNED);
                    writeByte((byte)data.getLong());
                    break;
                case DataElement.U_INT_1:
                    writeByte(INT1_UNSIGNED);
                    writeByte((byte)data.getLong());
                    break;
                case DataElement.INT_2:
                    writeByte(INT2_SIGNED);
                    writeShort((short)data.getLong());
                    break;
                case DataElement.U_INT_2:
                    writeByte(INT2_UNSIGNED);
                    writeShort((short)data.getLong());
                    break;
                case DataElement.INT_4:
                    writeByte(INT4_SIGNED);
                    writeInteger((int)data.getLong());
                    break;
                case DataElement.U_INT_4:
                    writeByte(INT4_UNSIGNED);
                    writeInteger((int)data.getLong());
                    break;
                case DataElement.INT_8:
                    writeByte(INT8_SIGNED);
                    writeLong(data.getLong());
                    break;
                case DataElement.U_INT_8:
                    writeByte(INT8_UNSIGNED);
                    writeBytes((byte[])data.getValue());
                    break;
                case DataElement.INT_16:
                    writeByte(INT16_SIGNED);
                    writeBytes((byte[])data.getValue());
                    break;
                case DataElement.U_INT_16:
                    writeByte(INT16_UNSIGNED);
                    writeBytes((byte[])data.getValue());
                    break;
            }
        } else if ((type == DataElement.DATSEQ)
                || (type == DataElement.DATALT) || (type == DataElement.STRING)
                || (type == DataElement.URL)) {
            switch (type) {
                case DataElement.DATSEQ:
                    typeBits = (TYPE_MASK & SEQUENCE_TYPE);
                    break;
                case DataElement.DATALT:
                    typeBits = (TYPE_MASK & ALTERNATIVE_TYPE);
                    break;
                case DataElement.STRING:
                case DataElement.URL:
                    typeBits = (TYPE_MASK & STRING_TYPE);
                    break;
            }
            if (size <= 0xff) {
                writeByte(typeBits | (SIZE_MASK & SHORT_SIZE));
                writeByte((byte)size);
            } else if (size <= 0xffff) {
                writeByte(typeBits | (SIZE_MASK & NORMAL_SIZE));
                writeShort((short)size);
            } else {
                writeByte(typeBits | (SIZE_MASK & LONG_SIZE));
                writeInteger((int)size);
            }
            if ((type == DataElement.DATSEQ) || (type == DataElement.DATALT)) {
                Enumeration elements = (Enumeration) data.getValue();
                while (elements.hasMoreElements()) {
                    writeDataElement((DataElement)elements.nextElement());
                }
            } else {
                writeBytes(((String)data.getValue()).getBytes());
            }
        } else if (type == DataElement.UUID) {
            writeByte(UUID_16);
            String uuid = ((UUID)data.getValue()).toString();
            while (uuid.length() < 32) {
                uuid = '0" + uuid;
            }
            for (int i = 0; i < 16; i++) {
                writeByte(Integer.parseInt(
                        uuid.substring(i * 2, i * 2 + 2), 16));
            }
        } else {
            throw new RuntimeException("Unknown data type.");
        }
    
voidwriteInteger(int data)
Writes 4-byte data to the connection.

param
data 4-byte value to write.
throws
IOException if an I/O error occurs

        writeShort((short)((data >>> 16) & 0xffff));
        writeShort((short)((data >>> 0) & 0xffff));
    
voidwriteLong(long data)
Writes 8-byte data to the connection.

param
data 8-byte value to write.
throws
IOException if an I/O error occurs

        writeInteger((int)((data >>> 32) & 0xffffffff));
        writeInteger((int)((data >>> 0) & 0xffffffff));
    
voidwriteShort(short data)
Writes 2-byte data to the buffer.

param
data 2-byte value to write.
throws
IOException if an I/O error occurs

        writeByte((byte)((data >>> 8) & 0xff));
        writeByte((byte)((data >>> 0) & 0xff));