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);
}
}
Aggregations