[cmd-parser] simplify ParseAsHexString() & Cli::UdpExample::ProcessSend() (#6726)

This commit enhances `CmdLineParser` methods that parse a hex string
adding a new version which allows a (longer) hex string to be parsed
in short segments sequentially. The unit test `test_cmd_line_parser`
is also updated to verify the behavior of the newly added method.

This commit also updates CLI `UdpExample` implementation to use the
new method for parsing message payload data from input hex string and
simplifies how `ProcessSend()` parses different arguments indicating
message payload options.
This commit is contained in:
Abtin Keshavarzian
2021-06-17 10:23:25 -07:00
committed by GitHub
parent d47a3fa9ad
commit e66b9a3958
5 changed files with 274 additions and 187 deletions
+82 -71
View File
@@ -114,88 +114,70 @@ otError UdpExample::ProcessOpen(uint8_t aArgsLength, Arg aArgs[])
otError UdpExample::ProcessSend(uint8_t aArgsLength, Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otError error = OT_ERROR_NONE;
otMessage * message = nullptr;
otMessageInfo messageInfo;
otMessage * message = nullptr;
uint8_t curArg = 0;
uint16_t payloadLength = 0;
PayloadType payloadType = kTypeText;
uint8_t argIndex = 0;
otMessageSettings messageSettings = {mLinkSecurityEnabled, OT_MESSAGE_PRIORITY_NORMAL};
memset(&messageInfo, 0, sizeof(messageInfo));
// Possible argument formats:
//
// send <text>
// send <type> <value>
// send <ip> <port> <text>
// send <ip> <port> <type> <value>
VerifyOrExit(aArgsLength >= 1 && aArgsLength <= 4, error = OT_ERROR_INVALID_ARGS);
if (aArgsLength > 2)
{
SuccessOrExit(error = aArgs[curArg++].ParseAsIp6Address(messageInfo.mPeerAddr));
SuccessOrExit(error = aArgs[curArg++].ParseAsUint16(messageInfo.mPeerPort));
}
if (aArgsLength == 2 || aArgsLength == 4)
{
uint8_t typePos = curArg++;
if (aArgs[typePos] == "-s")
{
payloadType = kTypeAutoSize;
SuccessOrExit(error = aArgs[curArg].ParseAsUint16(payloadLength));
}
else if (aArgs[typePos] == "-x")
{
payloadLength = aArgs[curArg].GetLength();
payloadType = kTypeHexString;
}
else if (aArgs[typePos] == "-t")
{
payloadType = kTypeText;
}
SuccessOrExit(error = aArgs[argIndex++].ParseAsIp6Address(messageInfo.mPeerAddr));
SuccessOrExit(error = aArgs[argIndex++].ParseAsUint16(messageInfo.mPeerPort));
}
message = otUdpNewMessage(mInterpreter.mInstance, &messageSettings);
VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
switch (payloadType)
if (aArgs[argIndex] == "-s")
{
case kTypeText:
SuccessOrExit(error = otMessageAppend(message, aArgs[curArg].GetCString(), aArgs[curArg].GetLength()));
break;
case kTypeAutoSize:
SuccessOrExit(error = WriteCharToBuffer(message, payloadLength));
break;
case kTypeHexString:
{
uint8_t buf[50];
uint16_t bufLen;
uint16_t conversionLength = 0;
const char *hexString = aArgs[curArg].GetCString();
// Auto-generated payload with a given length
while (payloadLength > 0)
uint16_t payloadLength;
argIndex++;
VerifyOrExit(argIndex < aArgsLength, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = aArgs[argIndex].ParseAsUint16(payloadLength));
SuccessOrExit(error = PrepareAutoGeneratedPayload(*message, payloadLength));
}
else if (aArgs[argIndex] == "-x")
{
// Binary hex data payload
argIndex++;
VerifyOrExit(argIndex < aArgsLength, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = PrepareHexStringPaylod(*message, aArgs[argIndex].GetCString()));
}
else
{
// Text payload (same as without specifying the type)
if (aArgs[argIndex] == "-t")
{
bufLen = sizeof(buf);
SuccessOrExit(error = ParseAsHexString(hexString, bufLen, buf, Utils::CmdLineParser::kAllowTruncate));
VerifyOrExit(bufLen > 0, error = OT_ERROR_INVALID_ARGS);
conversionLength = static_cast<uint16_t>(bufLen * 2);
if ((payloadLength & 0x01) != 0)
{
conversionLength -= 1;
}
hexString += conversionLength;
payloadLength -= conversionLength;
SuccessOrExit(error = otMessageAppend(message, buf, bufLen));
argIndex++;
}
break;
}
VerifyOrExit(argIndex < aArgsLength, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = otMessageAppend(message, aArgs[argIndex].GetCString(), aArgs[argIndex].GetLength()));
}
error = otUdpSend(mInterpreter.mInstance, &mSocket, message, &messageInfo);
SuccessOrExit(error = otUdpSend(mInterpreter.mInstance, &mSocket, message, &messageInfo));
message = nullptr;
exit:
if (error != OT_ERROR_NONE && message != nullptr)
if (message != nullptr)
{
otMessageFree(message);
}
@@ -219,26 +201,28 @@ otError UdpExample::ProcessLinkSecurity(uint8_t aArgsLength, Arg aArgs[])
return error;
}
otError UdpExample::WriteCharToBuffer(otMessage *aMessage, uint16_t aMessageSize)
otError UdpExample::PrepareAutoGeneratedPayload(otMessage &aMessage, uint16_t aPayloadLength)
{
otError error = OT_ERROR_NONE;
uint8_t character = 0x30; // 0
uint8_t character = '0';
for (uint16_t index = 0; index < aMessageSize; index++)
for (; aPayloadLength != 0; aPayloadLength--)
{
SuccessOrExit(error = otMessageAppend(aMessage, &character, 1));
character++;
SuccessOrExit(error = otMessageAppend(&aMessage, &character, sizeof(character)));
switch (character)
{
case 0x3A: // 9
character = 0x41; // A
case '9':
character = 'A';
break;
case 0x5B: // Z
character = 0x61; // a
case 'Z':
character = 'a';
break;
case 0x7B: // z
character = 0x30; // 0
case 'z':
character = '0';
break;
default:
character++;
break;
}
}
@@ -247,6 +231,33 @@ exit:
return error;
}
otError UdpExample::PrepareHexStringPaylod(otMessage &aMessage, const char *aHexString)
{
enum : uint8_t
{
kBufferSize = 50,
};
otError error;
uint8_t buf[kBufferSize];
uint16_t length;
bool done = false;
while (!done)
{
length = sizeof(buf);
error = Utils::CmdLineParser::ParseAsHexStringSegment(aHexString, length, buf);
VerifyOrExit((error == OT_ERROR_NONE) || (error == OT_ERROR_PENDING));
done = (error == OT_ERROR_NONE);
SuccessOrExit(error = otMessageAppend(&aMessage, buf, length));
}
exit:
return error;
}
otError UdpExample::Process(uint8_t aArgsLength, Arg aArgs[])
{
otError error = OT_ERROR_INVALID_ARGS;
+3 -8
View File
@@ -79,13 +79,6 @@ private:
otError (UdpExample::*mHandler)(uint8_t aArgsLength, Arg aArgs[]);
};
enum PayloadType
{
kTypeText = 0,
kTypeAutoSize = 1,
kTypeHexString = 2,
};
otError ProcessHelp(uint8_t aArgsLength, Arg aArgs[]);
otError ProcessBind(uint8_t aArgsLength, Arg aArgs[]);
otError ProcessClose(uint8_t aArgsLength, Arg aArgs[]);
@@ -93,7 +86,9 @@ private:
otError ProcessOpen(uint8_t aArgsLength, Arg aArgs[]);
otError ProcessSend(uint8_t aArgsLength, Arg aArgs[]);
otError ProcessLinkSecurity(uint8_t aArgsLength, Arg aArgs[]);
otError WriteCharToBuffer(otMessage *aMessage, uint16_t aMessageSize);
static otError PrepareAutoGeneratedPayload(otMessage &aMessage, uint16_t aPayloadLength);
static otError PrepareHexStringPaylod(otMessage &aMessage, const char *aHexString);
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
void HandleUdpReceive(otMessage *aMessage, const otMessageInfo *aMessageInfo);
+72 -51
View File
@@ -275,67 +275,88 @@ exit:
}
#endif // #if OPENTHREAD_FTD || OPENTHREAD_MTD
Error ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize)
enum HexStringParseMode
{
Error error;
uint16_t readSize = aSize;
kModeExtactSize, // Parse hex string expecting an exact size (number of bytes when parsed).
kModeUpToSize, // Parse hex string expecting less than or equal a given size.
kModeAllowPartial, // Allow parsing of partial segments.
};
SuccessOrExit(error = ParseAsHexString(aString, readSize, aBuffer, kDisallowTruncate));
VerifyOrExit(readSize == aSize, error = kErrorInvalidArgs);
static Error ParseHexString(const char *&aString, uint16_t &aSize, uint8_t *aBuffer, HexStringParseMode aMode)
{
Error error = kErrorNone;
size_t stringLength = strlen(aString);
size_t expectedSize = (stringLength + 1) / 2;
size_t parsedSize = 0;
bool skipFirstDigit;
switch (aMode)
{
case kModeExtactSize:
VerifyOrExit(expectedSize == aSize, error = kErrorInvalidArgs);
break;
case kModeUpToSize:
VerifyOrExit(expectedSize <= aSize, error = kErrorInvalidArgs);
break;
case kModeAllowPartial:
break;
}
// If number of chars in hex string is odd, we skip parsing
// the first digit.
skipFirstDigit = ((stringLength & 1) != 0);
while (parsedSize < expectedSize)
{
uint8_t digit;
if ((aMode == kModeAllowPartial) && (parsedSize == aSize))
{
// If partial parse mode is allowed, stop once we read the
// requested size.
ExitNow(error = kErrorPending);
}
if (skipFirstDigit)
{
*aBuffer = 0;
skipFirstDigit = false;
}
else
{
SuccessOrExit(error = ParseHexDigit(*aString, digit));
aString++;
*aBuffer = static_cast<uint8_t>(digit << 4);
}
SuccessOrExit(error = ParseHexDigit(*aString, digit));
aString++;
*aBuffer |= digit;
aBuffer++;
parsedSize++;
}
aSize = static_cast<uint16_t>(parsedSize);
exit:
return error;
}
Error ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer, HexStringParseMode aMode)
Error ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize)
{
Error error = kErrorNone;
uint8_t byte = 0;
uint16_t readBytes = 0;
const char *hex = aString;
size_t hexLength = strlen(aString);
uint8_t numChars;
return ParseHexString(aString, aSize, aBuffer, kModeExtactSize);
}
if (aMode == kDisallowTruncate)
{
VerifyOrExit((hexLength + 1) / 2 <= aSize, error = kErrorInvalidArgs);
}
Error ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer)
{
return ParseHexString(aString, aSize, aBuffer, kModeUpToSize);
}
// Handle the case where number of chars in hex string is odd.
numChars = hexLength & 1;
while (*hex != '\0')
{
uint8_t digit;
SuccessOrExit(error = ParseHexDigit(*hex, digit));
byte |= digit;
hex++;
numChars++;
if (numChars >= 2)
{
numChars = 0;
*aBuffer++ = byte;
byte = 0;
readBytes++;
if (readBytes == aSize)
{
ExitNow();
}
}
else
{
byte <<= 4;
}
}
aSize = readBytes;
exit:
return error;
Error ParseAsHexStringSegment(const char *&aString, uint16_t &aSize, uint8_t *aBuffer)
{
return ParseHexString(aString, aSize, aBuffer, kModeAllowPartial);
}
void Arg::CopyArgsToStringArray(Arg aArgs[], uint8_t aArgsLength, char *aStrings[])
+42 -29
View File
@@ -53,16 +53,6 @@ namespace CmdLineParser {
* @{
*/
/**
* This enumeration type represents the parse mode value used as a parameter in `ParseAsHexString()`.
*
*/
enum HexStringParseMode : uint8_t
{
kDisallowTruncate, // Disallow truncation of hex string.
kAllowTruncate, // Allow truncation of hex string.
};
/**
* This function parses a string as a `uint8_t` value.
*
@@ -217,6 +207,9 @@ otError ParseAsIp6Prefix(const char *aString, otIp6Prefix &aPrefix);
* there are fewer or more bytes in hex string that @p aSize, the parsed bytes (up to @p aSize) are copied into the
* `aBuffer` and `kErrorInvalidArgs` is returned.
*
* This function correctly handles hex strings with even or odd length. For example, "AABBCCDD" (with even length) is
* parsed as {0xaa, 0xbb, 0xcc, 0xdd} and "123" (with odd length) is parsed as {0x01, 0x23}.
*
* @param[in] aString The string to parse.
* @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence.
* @param[in] aSize The expected size of byte sequence (number of bytes after parsing).
@@ -234,6 +227,9 @@ otError ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize);
* If there are fewer or more bytes in hex string that @p kBufferSize, the parsed bytes (up to @p kBufferSize) are
* copied into the `aBuffer` and `kErrorInvalidArgs` is returned.
*
* This function correctly handles hex strings with even or odd length. For example, "AABBCCDD" (with even length) is
* parsed as {0xaa, 0xbb, 0xcc, 0xdd} and "123" (with odd length) is parsed as {0x01, 0x23}.
*
* @tparam kBufferSize The byte array size (number of bytes).
*
* @param[in] aString The string to parse.
@@ -251,24 +247,45 @@ template <uint16_t kBufferSize> static otError ParseAsHexString(const char *aStr
/**
* This function parses a hex string into a byte array.
*
* If @p aMode disallows truncation (`kDisallowTruncate`), this function verifies that parses hex string bytes fit in
* @p aBuffer with its given size in @aSize. Otherwise when @p aMode allows truncation, extra bytes after @p aSize bytes
* are ignored.
* This function verifies that the parsed hex string bytes fit in @p aBuffer with its given @p aSize.
*
* This function correctly handles hex strings with even or odd length. For example, "AABBCCDD" (with even length) is
* parsed as {0xaa, 0xbb, 0xcc, 0xdd} and "123" (with odd length) is parsed as {0x01, 0x23}.
*
* @param[in] aString The string to parse.
* @param[inout] aSize On entry indicates the number of bytes in @p aBuffer (max size of @p aBuffer).
* On exit provides number of bytes parsed and copied into @p aBuffer
* On exit provides number of bytes parsed and copied into @p aBuffer.
* @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence.
* @param[in] aMode Indicates parsing mode whether to allow truncation or not.
*
* @retval kErrorNone The string was parsed successfully.
* @retval kErrorInvalidArgs The string does not contain valid format or too many bytes (if truncation not allowed)
* @retval kErrorInvalidArgs The string does not contain valid format or too many bytes.
*
*/
otError ParseAsHexString(const char * aString,
uint16_t & aSize,
uint8_t * aBuffer,
HexStringParseMode aMode = kDisallowTruncate);
otError ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer);
/**
* This function parses a segment of a hex string up to a given size.
*
* This function allows a longer hex string to be parsed and read in smaller segments into a given buffer. If the
* entire hex string bytes can fit in the given @p aBuffer with its @p aSize, they are copied into @p aBuffer and
* function returns `kErrorNone`. Otherwise, @p aSize bytes are read and copied and function returns `kErrorPending`
* to indicate that there are more bytes to parse. The @p aString is also updated to skip over the parsed segment.
*
* This function correctly handles hex strings with even or odd length. For example, "AABBCCDD" (with even length) is
* parsed as {0xaa, 0xbb, 0xcc, 0xdd} and "123" (with odd length) is parsed as {0x01, 0x23}.
*
* @param[inout] aString A reference to string to parse. On successful parse, updated to skip parsed digits.
* @param[inout] aSize On entry indicates the segment size (number of bytes in @p aBuffer).
* On exit provides number of bytes parsed and copied into @p aBuffer.
* @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence.
*
* @retval kErrorNone The string was parsed successfully to the end of string.
* @retval kErrorPedning The string segment was parsed successfully, but there are additional bytes remaining
* to be parsed.
* @retval kErrorInvalidArgs The string does not contain valid format hex digits.
*
*/
otError ParseAsHexStringSegment(const char *&aString, uint16_t &aSize, uint8_t *aBuffer);
/**
* This class represents a single argument from an argument list.
@@ -523,23 +540,19 @@ public:
/**
* This method parses the argument as a hex string into a byte array.
*
* If @p aMode disallows truncation (`kDisallowTruncate`), this method verifies that parses hex string bytes fit in
* @p aBuffer with its given size in @aSize. Otherwise when @p aMode allows truncation, extra bytes after @p aSize
* bytes are ignored.
* This method verifies that the parsed hex string bytes fit in @p aBuffer with its given @p aSize.
*
* @param[inout] aSize On entry indicates the number of bytes in @p aBuffer (max size of @p aBuffer).
* On exit provides number of bytes parsed and copied into @p aBuffer
* On exit provides number of bytes parsed and copied into @p aBuffer.
* @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence.
* @param[in] aMode Indicates parsing mode whether to allow truncation or not.
*
* @retval kErrorNone The argument was parsed successfully.
* @retval kErrorInvalidArgs The argument does not contain valid format or too many bytes (if truncation not
* allowed)
* @retval kErrorInvalidArgs The argument does not contain valid format or too many bytes.
*
*/
otError ParseAsHexString(uint16_t &aSize, uint8_t *aBuffer, HexStringParseMode aMode = kDisallowTruncate)
otError ParseAsHexString(uint16_t &aSize, uint8_t *aBuffer)
{
return CmdLineParser::ParseAsHexString(mString, aSize, aBuffer, aMode);
return CmdLineParser::ParseAsHexString(mString, aSize, aBuffer);
}
/**
+75 -28
View File
@@ -35,10 +35,11 @@
#include "common/instance.hpp"
#include "utils/parse_cmdline.hpp"
#include "test_util.h"
#include "test_util.hpp"
using ot::Utils::CmdLineParser::ParseAsBool;
using ot::Utils::CmdLineParser::ParseAsHexString;
using ot::Utils::CmdLineParser::ParseAsHexStringSegment;
using ot::Utils::CmdLineParser::ParseAsInt16;
using ot::Utils::CmdLineParser::ParseAsInt32;
using ot::Utils::CmdLineParser::ParseAsInt8;
@@ -242,12 +243,17 @@ void TestParsingInts(void)
void TestParsingHexStrings(void)
{
const char kHexString[] = "DeadBeefCafeBabe";
const uint8_t kParsedArray[] = {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe};
const char kEvenHexString[] = "DeadBeefCafeBabe";
const uint8_t kEvenParsedArray[] = {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe};
uint8_t buffer[sizeof(kParsedArray)];
uint8_t buf3[3];
uint16_t len;
const char kOddHexString[] = "abcdef9876543";
const uint8_t kOddParsedArray[] = {0xa, 0xbc, 0xde, 0xf9, 0x87, 0x65, 0x43};
uint8_t buffer[sizeof(kEvenParsedArray)];
uint8_t buf3[3];
uint16_t len;
const char * string;
const uint8_t *bufPtr;
// Verify `ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize)`
@@ -272,37 +278,78 @@ void TestParsingHexStrings(void)
VerifyOrQuit(ParseAsHexString("1122334", buf3) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input");
VerifyOrQuit(ParseAsHexString("11223344", buf3) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input");
SuccessOrQuit(ParseAsHexString("abbade", buf3), "ParseAsHexString() failed");
VerifyOrQuit(buf3[0] == 0xab && buf3[1] == 0xba && buf3[2] == 0xde, "ParseAsHexString() parsed incorrectly");
SuccessOrQuit(ParseAsHexString("012345", buf3), "ParseAsHexString() failed");
VerifyOrQuit(buf3[0] == 0x01 && buf3[1] == 0x23 && buf3[2] == 0x45, "ParseAsHexString() parsed incorrectly");
SuccessOrQuit(ParseAsHexString("12345", buf3), "ParseAsHexString() failed with odd length");
VerifyOrQuit(buf3[0] == 0x01 && buf3[1] == 0x23 && buf3[2] == 0x45, "ParseAsHexString() parsed incorrectly");
SuccessOrQuit(ParseAsHexString(kHexString, buffer), "ParseAsHexString failed");
VerifyOrQuit(memcmp(buffer, kParsedArray, sizeof(buffer)) == 0, "ParseAsHexString() parsed incorrectly");
SuccessOrQuit(ParseAsHexString(kEvenHexString, buffer), "ParseAsHexString failed");
VerifyOrQuit(memcmp(buffer, kEvenParsedArray, sizeof(buffer)) == 0, "ParseAsHexString() parsed incorrectly");
// Verify truncation
// Verify `ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer)`
printf("----------------------------------------------------------\n");
len = sizeof(buffer);
SuccessOrQuit(ParseAsHexString(kHexString, len, buffer), "ParseAsHexString failed");
VerifyOrQuit(len == sizeof(kParsedArray), "ParseAsHexString() parsed incorrectly");
VerifyOrQuit(memcmp(buffer, kParsedArray, len) == 0, "ParseAsHexString() parsed incorrectly");
SuccessOrQuit(ParseAsHexString(kEvenHexString, len, buffer), "ParseAsHexString() failed");
VerifyOrQuit(len == sizeof(kEvenParsedArray), "ParseAsHexString() parsed incorrectly");
VerifyOrQuit(memcmp(buffer, kEvenParsedArray, len) == 0, "ParseAsHexString() parsed incorrectly");
DumpBuffer(kEvenHexString, buffer, len);
SuccessOrQuit(ParseAsHexString(kHexString + 1, len, buffer), "ParseAsHexString failed");
VerifyOrQuit(len == sizeof(kParsedArray), "ParseAsHexString() parsed incorrectly");
VerifyOrQuit(memcmp(buffer + 1, kParsedArray + 1, len - 1) == 0, "ParseAsHexString() parsed incorrectly");
VerifyOrQuit(buffer[0] == 0xe, "ParseAsHexString() parsed incorrectly");
SuccessOrQuit(ParseAsHexString(kOddHexString, len, buffer), "ParseAsHexString() failed");
VerifyOrQuit(len == sizeof(kOddParsedArray), "ParseAsHexString() parsed incorrectly");
VerifyOrQuit(memcmp(buffer, kOddParsedArray, len) == 0, "ParseAsHexString() parsed incorrectly");
DumpBuffer(kOddHexString, buffer, len);
SuccessOrQuit(ParseAsHexString(kHexString + 2, len, buffer), "ParseAsHexString failed");
VerifyOrQuit(len == sizeof(kParsedArray) - 1, "ParseAsHexString() parsed incorrectly");
VerifyOrQuit(memcmp(buffer, kParsedArray + 1, len) == 0, "ParseAsHexString() parsed incorrectly");
// Verify `ParseAsHexStringSegement()`
len = sizeof(buffer) - 1;
VerifyOrQuit(ParseAsHexString(kHexString, len, buffer, ot::Utils::CmdLineParser::kDisallowTruncate) !=
OT_ERROR_NONE,
"ParseAsHexString passed with bad input");
len = sizeof(buffer) - 1;
SuccessOrQuit(ParseAsHexString(kHexString, len, buffer, ot::Utils::CmdLineParser::kAllowTruncate),
"ParseAsHexString failed");
VerifyOrQuit(len == sizeof(buffer) - 1, "ParseAsHexString() parsed incorrectly");
VerifyOrQuit(memcmp(buffer, kParsedArray, len) == 0, "ParseAsHexString() parsed incorrectly");
printf("----------------------------------------------------------\n");
for (uint8_t testIter = 0; testIter <= 1; testIter++)
{
for (uint8_t segmentLen = 1; segmentLen <= sizeof(buffer); segmentLen++)
{
if (testIter == 0)
{
string = kEvenHexString;
bufPtr = kEvenParsedArray;
}
else
{
string = kOddHexString;
bufPtr = kOddParsedArray;
}
len = segmentLen;
printf("\"%s\" segLen:%d -> ", string, segmentLen);
while (true)
{
otError error = ParseAsHexStringSegment(string, len, buffer);
printf("%d (\"%s\") ", len, string);
if (error == OT_ERROR_NONE)
{
VerifyOrQuit(len <= segmentLen, "ParseAsHexStringSegment() parsed incorrectly");
VerifyOrQuit(memcmp(buffer, bufPtr, len) == 0, "ParseAsHexStringSegment() parsed incorrectly");
VerifyOrQuit(*string == '\0',
"ParseAsHexStringSegment() failed to update string pointer correctly");
break;
}
VerifyOrQuit(error == OT_ERROR_PENDING, "ParseAsHexStringSegment() failed");
VerifyOrQuit(len == segmentLen, "ParseAsHexStringSegment() parsed incorrectly");
VerifyOrQuit(memcmp(buffer, bufPtr, len) == 0, "ParseAsHexStringSegment() parsed incorrectly");
bufPtr += len;
}
printf("\n");
}
}
}
int main(void)