Search in sources :

Example 1 with TlvType

use of org.eclipse.leshan.tlv.Tlv.TlvType in project leshan by eclipse.

the class TlvDecoder method decode.

public static Tlv[] decode(ByteBuffer input) throws TlvException {
    try {
        List<Tlv> tlvs = new ArrayList<>();
        while (input.remaining() > 0) {
            input.order(ByteOrder.BIG_ENDIAN);
            // decode type
            int typeByte = input.get() & 0xFF;
            TlvType type;
            switch(typeByte & 0b1100_0000) {
                case 0b0000_0000:
                    type = TlvType.OBJECT_INSTANCE;
                    break;
                case 0b0100_0000:
                    type = TlvType.RESOURCE_INSTANCE;
                    break;
                case 0b1000_0000:
                    type = TlvType.MULTIPLE_RESOURCE;
                    break;
                case 0b1100_0000:
                    type = TlvType.RESOURCE_VALUE;
                    break;
                default:
                    throw new TlvException("unknown type: " + (typeByte & 0b1100_0000));
            }
            // decode identifier
            int identifier;
            try {
                if ((typeByte & 0b0010_0000) == 0) {
                    identifier = input.get() & 0xFF;
                } else {
                    identifier = input.getShort() & 0xFFFF;
                }
            } catch (BufferUnderflowException e) {
                throw new TlvException("Invalid 'identifier' length", e);
            }
            LOG.trace("decoding {} {}", type, identifier);
            // decode length
            int length;
            int lengthType = typeByte & 0b0001_1000;
            try {
                switch(lengthType) {
                    case 0b0000_0000:
                        // 2 bit length
                        length = typeByte & 0b0000_0111;
                        break;
                    case 0b0000_1000:
                        // 8 bit length
                        length = input.get() & 0xFF;
                        break;
                    case 0b0001_0000:
                        // 16 bit length
                        length = input.getShort() & 0xFFFF;
                        break;
                    case 0b0001_1000:
                        // 24 bit length
                        int b = input.get() & 0x000000FF;
                        int s = input.getShort() & 0x0000FFFF;
                        length = (b << 16) | s;
                        break;
                    default:
                        throw new TlvException("unknown length type: " + (typeByte & 0b0001_1000));
                }
            } catch (BufferUnderflowException e) {
                throw new TlvException("Invalid 'length' length", e);
            }
            LOG.trace("length: {} (length type: {})", length, lengthType);
            // decode value
            if (type == TlvType.RESOURCE_VALUE || type == TlvType.RESOURCE_INSTANCE) {
                try {
                    byte[] payload = new byte[length];
                    input.get(payload);
                    tlvs.add(new Tlv(type, null, payload, identifier));
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("payload value: {}", Hex.encodeHexString(payload));
                    }
                } catch (BufferOverflowException e) {
                    throw new TlvException("Invalid 'value' length", e);
                }
            } else {
                try {
                    // create a view of the contained TLVs
                    ByteBuffer slice = input.slice();
                    slice.limit(length);
                    Tlv[] children = decode(slice);
                    // skip the children, it will be decoded by the view
                    input.position(input.position() + length);
                    Tlv tlv = new Tlv(type, children, null, identifier);
                    tlvs.add(tlv);
                } catch (IllegalArgumentException e) {
                    throw new TlvException("Invalid 'value' length", e);
                }
            }
        }
        return tlvs.toArray(new Tlv[] {});
    } catch (TlvException ex) {
        String printHexBinary = Hex.encodeHexString(input.array());
        throw new TlvException("Impossible to parse TLV: \n" + printHexBinary, ex);
    } catch (RuntimeException ex) {
        String printHexBinary = Hex.encodeHexString(input.array());
        throw new TlvException("Unexpected TLV parse error: \n" + printHexBinary, ex);
    }
}
Also used : TlvType(org.eclipse.leshan.tlv.Tlv.TlvType) ArrayList(java.util.ArrayList) ByteBuffer(java.nio.ByteBuffer) BufferOverflowException(java.nio.BufferOverflowException) BufferUnderflowException(java.nio.BufferUnderflowException)

Aggregations

BufferOverflowException (java.nio.BufferOverflowException)1 BufferUnderflowException (java.nio.BufferUnderflowException)1 ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 TlvType (org.eclipse.leshan.tlv.Tlv.TlvType)1