mirror of
https://github.com/espressif/openthread.git
synced 2026-09-01 14:59:54 +00:00
[frame-builder] add Insert(), Remove() and other helper methods (#7964)
This commit adds `Insert()` and `Remove()` methods in `FrameBuilder`. `Insert` can be used to insert new content in the frame at a given offset moving any previously written content forward. `Remove()` can be used to remove previously appended content from the frame moving any content after the removed bytes backward. This commit also adds `GetRemainingLength()` to get the remaining length (number of bytes that can be appended) in the frame buffer, and `SetMaxLength()`. Unit test `test_frame_builder` is also updated to validate all the newly added methods.
This commit is contained in:
committed by
Jonathan Hui
parent
7af484f49f
commit
e3f157402c
@@ -96,4 +96,26 @@ void FrameBuilder::WriteBytes(uint16_t aOffset, const void *aBuffer, uint16_t aL
|
||||
memcpy(mBuffer + aOffset, aBuffer, aLength);
|
||||
}
|
||||
|
||||
Error FrameBuilder::InsertBytes(uint16_t aOffset, const void *aBuffer, uint16_t aLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
OT_ASSERT(aOffset <= mLength);
|
||||
|
||||
VerifyOrExit(CanAppend(aLength), error = kErrorNoBufs);
|
||||
|
||||
memmove(mBuffer + aOffset + aLength, mBuffer + aOffset, mLength - aOffset);
|
||||
memcpy(mBuffer + aOffset, aBuffer, aLength);
|
||||
mLength += aLength;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void FrameBuilder::RemoveBytes(uint16_t aOffset, uint16_t aLength)
|
||||
{
|
||||
memmove(mBuffer + aOffset, mBuffer + aOffset + aLength, mLength - aOffset - aLength);
|
||||
mLength -= aLength;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
@@ -77,13 +77,32 @@ public:
|
||||
uint16_t GetLength(void) const { return mLength; }
|
||||
|
||||
/**
|
||||
* This method returns the maximum length of frame.
|
||||
* This method returns the maximum length of the frame.
|
||||
*
|
||||
* @returns The maximum frame length (max number of bytes in the frame buffer).
|
||||
*
|
||||
*/
|
||||
uint16_t GetMaxLength(void) const { return mMaxLength; }
|
||||
|
||||
/**
|
||||
* This method sets the maximum length of the frame.
|
||||
*
|
||||
* This method does not perform any checks on the new given length. The caller MUST ensure that the specified max
|
||||
* length is valid for the frame buffer.
|
||||
*
|
||||
* @param[in] aLength The maximum frame length.
|
||||
*
|
||||
*/
|
||||
void SetMaxLength(uint16_t aLength) { mMaxLength = aLength; }
|
||||
|
||||
/**
|
||||
* This method returns the remaining length (number of bytes that can be appended) in the frame.
|
||||
*
|
||||
* @returns The remaining length.
|
||||
*
|
||||
*/
|
||||
uint16_t GetRemainingLength(void) const { return mMaxLength - mLength; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not there are enough bytes remaining in the `FrameBuilder` buffer to append a
|
||||
* given number of bytes.
|
||||
@@ -227,6 +246,57 @@ public:
|
||||
WriteBytes(aOffset, &aObject, sizeof(ObjectType));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inserts bytes in `FrameBuilder` at a given offset, moving previous content forward.
|
||||
*
|
||||
* The caller MUST ensure that @p aOffset is within the current frame length (from 0 up to and including
|
||||
* `GetLength()`). Otherwise the behavior of this method is undefined.
|
||||
*
|
||||
* @param[in] aOffset The offset to insert bytes.
|
||||
* @param[in] aBuffer A pointer to a data buffer to insert.
|
||||
* @param[in] aLength Number of bytes in @p aBuffer.
|
||||
*
|
||||
* @retval kErrorNone Successfully inserted the bytes.
|
||||
* @retval kErrorNoBufs Insufficient available buffers to insert the bytes.
|
||||
*
|
||||
*/
|
||||
Error InsertBytes(uint16_t aOffset, const void *aBuffer, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* This method inserts an object in `FrameBuilder` at a given offset, moving previous content forward.
|
||||
*
|
||||
* The caller MUST ensure that @p aOffset is within the current frame length (from 0 up to and including
|
||||
* `GetLength()`). Otherwise the behavior of this method is undefined.
|
||||
*
|
||||
* @tparam ObjectType The object type to insert.
|
||||
*
|
||||
* @param[in] aOffset The offset to insert bytes.
|
||||
* @param[in] aObject A reference to the object to insert.
|
||||
*
|
||||
* @retval kErrorNone Successfully inserted the bytes.
|
||||
* @retval kErrorNoBufs Insufficient available buffers to insert the bytes.
|
||||
*
|
||||
*/
|
||||
template <typename ObjectType> Error Insert(uint16_t aOffset, const ObjectType &aObject)
|
||||
{
|
||||
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
|
||||
|
||||
return InsertBytes(aOffset, &aObject, sizeof(ObjectType));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method removes a given number of bytes in `FrameBuilder` at a given offset, moving existing content
|
||||
* after removed bytes backward.
|
||||
*
|
||||
* This method does not perform any bound checks. The caller MUST ensure that the given length and offset fits
|
||||
* within the previously appended content. Otherwise the behavior of this method is undefined.
|
||||
*
|
||||
* @param[in] aOffset The offset to remove bytes from.
|
||||
* @param[in] aLength The number of bytes to remove.
|
||||
*
|
||||
*/
|
||||
void RemoveBytes(uint16_t aOffset, uint16_t aLength);
|
||||
|
||||
private:
|
||||
uint8_t *mBuffer;
|
||||
uint16_t mLength;
|
||||
|
||||
@@ -39,6 +39,7 @@ void TestFrameBuilder(void)
|
||||
{
|
||||
const uint8_t kData1[] = {0x01, 0x02, 0x03, 0x04, 0x05};
|
||||
const uint8_t kData2[] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa};
|
||||
const uint8_t kData3[] = {0xca, 0xfe, 0xbe, 0xef};
|
||||
|
||||
static constexpr uint16_t kMaxBufferSize = sizeof(kData1) * 2 + sizeof(kData2);
|
||||
|
||||
@@ -72,12 +73,25 @@ void TestFrameBuilder(void)
|
||||
VerifyOrQuit(frameBuilder.CanAppend(sizeof(buffer)));
|
||||
VerifyOrQuit(!frameBuilder.CanAppend(sizeof(buffer) + 1));
|
||||
|
||||
frameBuilder.SetMaxLength(sizeof(kData1));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(frameBuilder.GetLength() == 0);
|
||||
VerifyOrQuit(frameBuilder.GetMaxLength() == sizeof(kData1));
|
||||
VerifyOrQuit(memcmp(buffer, zeroBuffer, sizeof(buffer)) == 0);
|
||||
VerifyOrQuit(frameBuilder.CanAppend(sizeof(kData1)));
|
||||
VerifyOrQuit(!frameBuilder.CanAppend(sizeof(kData1) + 1));
|
||||
|
||||
SuccessOrQuit(frameBuilder.Append(kData1));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData1), zeroBuffer, sizeof(buffer) - sizeof(kData1)) == 0);
|
||||
|
||||
frameBuilder.SetMaxLength(sizeof(buffer));
|
||||
VerifyOrQuit(frameBuilder.GetMaxLength() == sizeof(buffer));
|
||||
VerifyOrQuit(frameBuilder.CanAppend(sizeof(buffer) - sizeof(kData1)));
|
||||
VerifyOrQuit(!frameBuilder.CanAppend(sizeof(buffer) - sizeof(kData1) + 1));
|
||||
|
||||
SuccessOrQuit(frameBuilder.AppendUint8(0x01));
|
||||
SuccessOrQuit(frameBuilder.AppendBigEndianUint16(0x0203));
|
||||
SuccessOrQuit(frameBuilder.AppendLittleEndianUint16(0x0504));
|
||||
@@ -135,6 +149,66 @@ void TestFrameBuilder(void)
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData1), kData2, sizeof(kData2)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData1) + sizeof(kData2), kData1, sizeof(kData1)) == 0);
|
||||
|
||||
frameBuilder.Init(buffer, sizeof(buffer));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(frameBuilder.GetLength() == 0);
|
||||
VerifyOrQuit(frameBuilder.GetMaxLength() == sizeof(buffer));
|
||||
|
||||
offset = 0;
|
||||
SuccessOrQuit(frameBuilder.Insert(offset, kData1));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
|
||||
|
||||
offset = 0;
|
||||
SuccessOrQuit(frameBuilder.Insert(offset, kData2));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1) + sizeof(kData2));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(memcmp(buffer, kData2, sizeof(kData2)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData2), kData1, sizeof(kData1)) == 0);
|
||||
|
||||
offset = sizeof(kData2);
|
||||
SuccessOrQuit(frameBuilder.InsertBytes(offset, kData3, sizeof(kData3)));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1) + sizeof(kData2) + sizeof(kData3));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(memcmp(buffer, kData2, sizeof(kData2)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData2), kData3, sizeof(kData3)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData2) + sizeof(kData3), kData1, sizeof(kData1)) == 0);
|
||||
|
||||
offset = frameBuilder.GetLength();
|
||||
SuccessOrQuit(frameBuilder.Insert<uint8_t>(offset, 0x77));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1) + sizeof(kData2) + sizeof(kData3) + sizeof(uint8_t));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(memcmp(buffer, kData2, sizeof(kData2)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData2), kData3, sizeof(kData3)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData2) + sizeof(kData3), kData1, sizeof(kData1)) == 0);
|
||||
VerifyOrQuit(buffer[sizeof(kData2) + sizeof(kData3) + sizeof(kData1)] == 0x77);
|
||||
|
||||
offset = frameBuilder.GetLength() - 1;
|
||||
frameBuilder.RemoveBytes(offset, sizeof(uint8_t));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1) + sizeof(kData2) + sizeof(kData3));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(memcmp(buffer, kData2, sizeof(kData2)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData2), kData3, sizeof(kData3)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData2) + sizeof(kData3), kData1, sizeof(kData1)) == 0);
|
||||
|
||||
offset = sizeof(kData2);
|
||||
frameBuilder.RemoveBytes(offset, sizeof(kData3));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1) + sizeof(kData2));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(memcmp(buffer, kData2, sizeof(kData2)) == 0);
|
||||
VerifyOrQuit(memcmp(buffer + sizeof(kData2), kData1, sizeof(kData1)) == 0);
|
||||
|
||||
offset = 0;
|
||||
frameBuilder.RemoveBytes(offset, sizeof(kData2));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == sizeof(kData1));
|
||||
VerifyOrQuit(frameBuilder.GetBytes() == buffer);
|
||||
VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0);
|
||||
|
||||
offset = 0;
|
||||
frameBuilder.RemoveBytes(offset, sizeof(kData1));
|
||||
VerifyOrQuit(frameBuilder.GetLength() == 0);
|
||||
|
||||
message->Free();
|
||||
testFreeInstance(instance);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user