[message] new helper methods to compare bytes in a message (#6068)

This commit adds new helper `Compare` methods in `Message` class to
compare the bytes from the message (at a given offset) with a byte
array or bytes from a (template) object or bytes read from another
message.

This commit also updates the message unit test to cover the behavior
of the newly added methods.
This commit is contained in:
Abtin Keshavarzian
2021-01-15 08:14:39 -08:00
committed by GitHub
parent 4d50cbadbc
commit a77b1a95ae
3 changed files with 127 additions and 1 deletions
+42
View File
@@ -525,6 +525,48 @@ otError Message::Read(uint16_t aOffset, void *aBuf, uint16_t aLength) const
return (ReadBytes(aOffset, aBuf, aLength) == aLength) ? OT_ERROR_NONE : OT_ERROR_PARSE;
}
bool Message::CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength) const
{
uint16_t bytesToCompare = aLength;
const uint8_t *bufPtr = reinterpret_cast<const uint8_t *>(aBuf);
Chunk chunk;
GetFirstChunk(aOffset, aLength, chunk);
while (chunk.GetLength() > 0)
{
VerifyOrExit(memcmp(bufPtr, chunk.GetData(), chunk.GetLength()) == 0);
bufPtr += chunk.GetLength();
bytesToCompare -= chunk.GetLength();
GetNextChunk(aLength, chunk);
}
exit:
return (bytesToCompare == 0);
}
bool Message::CompareBytes(uint16_t aOffset,
const Message &aOtherMessage,
uint16_t aOtherOffset,
uint16_t aLength) const
{
uint16_t bytesToCompare = aLength;
Chunk chunk;
GetFirstChunk(aOffset, aLength, chunk);
while (chunk.GetLength() > 0)
{
VerifyOrExit(aOtherMessage.CompareBytes(aOtherOffset, chunk.GetData(), chunk.GetLength()));
aOtherOffset += chunk.GetLength();
bytesToCompare -= chunk.GetLength();
GetNextChunk(aLength, chunk);
}
exit:
return (bytesToCompare == 0);
}
void Message::WriteBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength)
{
const uint8_t *bufPtr = reinterpret_cast<const uint8_t *>(aBuf);
+54
View File
@@ -710,6 +710,60 @@ public:
return Read(aOffset, &aObject, sizeof(ObjectType));
}
/**
* This method compares the bytes in the message at a given offset with a given byte array.
*
* If there are fewer bytes available in the message than the requested @p aLength, the comparison is treated as
* failure (returns FALSE).
*
* @param[in] aOffset Byte offset within the message to read from for the comparison.
* @param[in] aBuf A pointer to a data buffer to compare with the bytes from message.
* @param[in] aLength Number of bytes in @p aBuf.
*
* @returns TRUE if there are enough bytes available in @p aMessage and they match the bytes from @p aBuf,
* FALSE otherwise.
*
*/
bool CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength) const;
/**
* This method compares the bytes in the message at a given offset with bytes read from another message.
*
* If either message has fewer bytes available than the requested @p aLength, the comparison is treated as failure
* (returns FALSE).
*
* @param[in] aOffset Byte offset within the message to read from for the comparison.
* @param[in] aOtherMessage The other message to compare with.
* @param[in] aOtherOffset Byte offset within @p aOtherMessage to read from for the comparison.
* @param[in] aLength Number of bytes to compare.
*
* @returns TRUE if there are enough bytes available in both messages and they all match. FALSE otherwise.
*
*/
bool CompareBytes(uint16_t aOffset, const Message &aOtherMessage, uint16_t aOtherOffset, uint16_t aLength) const;
/**
* This method compares the bytes in the message at a given offset with an object.
*
* The bytes in the message are compared with the bytes in @p aObject. If there are fewer bytes available in the
* message than the requested object size, it is treated as failed comparison (returns FALSE).
*
* @tparam ObjectType The object type to compare with the bytes in message.
*
* @param[in] aOffset Byte offset within the message to read from for the comparison.
* @param[in] aObject A reference to the object to compare with the message bytes.
*
* @returns TRUE if there are enough bytes available in @p aMessage and they match the bytes in @p aObject,
* FALSE otherwise.
*
*/
template <typename ObjectType> bool Compare(uint16_t aOffset, const ObjectType &aObject) const
{
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
return CompareBytes(aOffset, &aObject, sizeof(ObjectType));
}
/**
* This method writes bytes to the message.
*
+31 -1
View File
@@ -67,6 +67,8 @@ void TestMessage(void)
message->WriteBytes(0, writeBuffer, kMaxSize);
SuccessOrQuit(message->Read(0, readBuffer, kMaxSize), "Message::Read failed");
VerifyOrQuit(memcmp(writeBuffer, readBuffer, kMaxSize) == 0, "Message compare failed");
VerifyOrQuit(message->CompareBytes(0, readBuffer, kMaxSize), "Message::CompareBytes failed");
VerifyOrQuit(message->Compare(0, readBuffer), "Message::Compare failed");
VerifyOrQuit(message->GetLength() == kMaxSize, "Message::GetLength failed");
for (uint16_t offset = 0; offset < kMaxSize; offset++)
@@ -82,11 +84,30 @@ void TestMessage(void)
SuccessOrQuit(message->Read(0, readBuffer, kMaxSize), "Message::Read failed");
VerifyOrQuit(memcmp(writeBuffer, readBuffer, kMaxSize) == 0, "Message compare failed");
VerifyOrQuit(message->Compare(0, writeBuffer), "Message::Compare() failed");
memset(readBuffer, 0, sizeof(readBuffer));
SuccessOrQuit(message->Read(offset, readBuffer, length), "Message::Read failed");
VerifyOrQuit(memcmp(readBuffer, &writeBuffer[offset], length) == 0, "Message compare failed");
VerifyOrQuit(memcmp(&readBuffer[length], zeroBuffer, kMaxSize - length) == 0, "Message read after length");
VerifyOrQuit(message->CompareBytes(offset, &writeBuffer[offset], length), "Message::CompareBytes() failed");
if (length == 0)
{
continue;
}
// Change the first byte, and then last byte, and verify that
// `CompareBytes()` correctly fails.
writeBuffer[offset]++;
VerifyOrQuit(!message->CompareBytes(offset, &writeBuffer[offset], length), "CompareBytes() failed");
writeBuffer[offset]--;
writeBuffer[offset + length - 1]++;
VerifyOrQuit(!message->CompareBytes(offset, &writeBuffer[offset], length), "CompareBytes() failed");
writeBuffer[offset + length - 1]--;
}
// Verify `ReadBytes()` behavior when requested read length goes beyond available bytes in the message.
@@ -97,10 +118,14 @@ void TestMessage(void)
memset(readBuffer, 0, sizeof(readBuffer));
readLength = message->ReadBytes(offset, readBuffer, length);
VerifyOrQuit(readLength <= length, "Message::ReadBytes() returned longer length");
VerifyOrQuit(readLength < length, "Message::ReadBytes() returned longer length");
VerifyOrQuit(readLength == kMaxSize - offset, "Message::Read failed");
VerifyOrQuit(memcmp(readBuffer, &writeBuffer[offset], readLength) == 0, "Message compare failed");
VerifyOrQuit(memcmp(&readBuffer[readLength], zeroBuffer, kMaxSize - readLength) == 0, "read after length");
VerifyOrQuit(!message->CompareBytes(offset, readBuffer, length), "Message::CompareBytes failed");
VerifyOrQuit(message->CompareBytes(offset, readBuffer, readLength), "Message::CompareBytes failed");
}
}
@@ -140,6 +165,11 @@ void TestMessage(void)
VerifyOrQuit(
memcmp(&readBuffer[dstOffset + bytesCopied], zeroBuffer, kMaxSize - bytesCopied - dstOffset) == 0,
"read after length");
VerifyOrQuit(message->CompareBytes(srcOffset, *message2, dstOffset, bytesCopied),
"Message::CompareBytes with two messages failed");
VerifyOrQuit(message2->CompareBytes(dstOffset, *message, srcOffset, bytesCopied),
"Message::CompareBytes with two messages failed");
}
}
}