List <CoapMessageOption> DecodeOptions(CoapMessageReader reader) { var options = new List <CoapMessageOption>(); if (reader.EndOfStream) { return(options); } var lastNumber = 0; while (!reader.EndOfStream) { var delta = reader.ReadBits(4); var length = reader.ReadBits(4); if ((byte)(delta << 4 | length) == 0xFF) { // Payload marker. break; } if (delta == 13) { delta = reader.ReadBits(8) + 13; } else if (delta == 14) { delta = reader.ReadBits(16) + 269; } if (length == 13) { length = reader.ReadBits(8) + 13; } else if (length == 14) { length = reader.ReadBits(16) + 269; } byte[] value = null; if (length > 0) { value = reader.ReadBytes(length); } var number = lastNumber + delta; lastNumber = number; options.Add(CreateOption((CoapMessageOptionNumber)number, value)); } return(options); }
// TODO: Consider creating "CoapMessageDecodeResult" which has Message (null or set) and "DecodeResult" as INTERFACE with all possible errors (VersionInvalidDecodeResult) etc. public CoapMessage Decode(ArraySegment <byte> buffer) { using (var reader = new CoapMessageReader(buffer)) { var version = reader.ReadBits(2); if (version != 0x1) { throw new CoapProtocolViolationException("Version is not set to 1."); } var type = reader.ReadBits(2); if (type > 2) { throw new CoapProtocolViolationException("Type is invalid."); } var tokenLength = reader.ReadBits(4); var code = (byte)reader.ReadBits(8); var codeClass = (byte)(code >> 5); var codeDetails = (byte)(0x1F & code); var id = reader.ReadByte() << 8; id |= reader.ReadByte(); byte[] token = null; if (tokenLength > 0) { token = reader.ReadBytes(tokenLength); } var options = DecodeOptions(reader); var payload = reader.ReadToEnd(); var message = new CoapMessage { Type = (CoapMessageType)type, Code = new CoapMessageCode(codeClass, codeDetails), Id = (ushort)id, Token = token, Options = options, Payload = payload }; return(message); } }