msgbuf: Add pldm_msgbuf_span_string_ascii()
Add pldm_msgbuf_span_string_ascii() API to find the start of the ascii
string in the message buffer.
```
pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
size_t *length)
```
The API returns the start pointer of ascii string in the message buffer
and length of that ascii string includes Terminator.
The `cursor` and `length` are optional. Input NULL to `cursor` and
`length` will cause the message buffer cursor points to remaining data.
The caller can ignore `length` option by input NULL if they don't care
about the size of ascii string.
Change-Id: I4a73b7425ee1e4e5621eb16de6e16189efdf202b
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/msgbuf.h b/src/msgbuf.h
index e5e91ed..ef65be2 100644
--- a/src/msgbuf.h
+++ b/src/msgbuf.h
@@ -1054,6 +1054,61 @@
}
__attribute__((always_inline)) static inline int
+pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
+ size_t *length)
+{
+ intmax_t measured;
+
+ assert(ctx);
+
+ if (!ctx->cursor || (cursor && *cursor)) {
+ return pldm_msgbuf_status(ctx, EINVAL);
+ }
+
+ if (ctx->remaining < 0) {
+ /* Tracking the amount of overflow gets disturbed here */
+ return pldm_msgbuf_status(ctx, EOVERFLOW);
+ }
+
+ measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
+ if (measured == ctx->remaining) {
+ /*
+ * We have hit the end of the buffer prior to the NUL terminator.
+ * Optimistically, the NUL terminator was one-beyond-the-end. Setting
+ * ctx->remaining negative ensures the `pldm_msgbuf_destroy*()` APIs also
+ * return an error.
+ */
+ ctx->remaining = -1;
+ return pldm_msgbuf_status(ctx, EOVERFLOW);
+ }
+
+ /* Include the NUL terminator in the span length, as spans are opaque */
+ measured++;
+
+ if (ctx->remaining < INTMAX_MIN + measured) {
+ return pldm_msgbuf_status(ctx, EOVERFLOW);
+ }
+
+ ctx->remaining -= measured;
+ assert(ctx->remaining >= 0);
+ if (ctx->remaining < 0) {
+ return pldm_msgbuf_status(ctx, EOVERFLOW);
+ }
+
+ if (cursor) {
+ *cursor = ctx->cursor;
+ }
+
+ ctx->cursor += measured;
+
+ if (length) {
+ *length = measured;
+ }
+
+ return 0;
+}
+
+__attribute__((always_inline)) static inline int
pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
{
assert(ctx);
diff --git a/tests/msgbuf.cpp b/tests/msgbuf.cpp
index 52d47ae..714243f 100644
--- a/tests/msgbuf.cpp
+++ b/tests/msgbuf.cpp
@@ -936,6 +936,103 @@
EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
}
+TEST(msgbuf, pldm_msgbuf_span_string_ascii_good)
+{
+ struct pldm_msgbuf _ctxExtract;
+ struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+ uint8_t src[9] = {0x11, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x77};
+ constexpr size_t required = 6;
+ const char expectData[required] = {0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00};
+ uint16_t testVal;
+ uint8_t testVal1;
+ char* retBuff = NULL;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
+ EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, &testVal), 0);
+ EXPECT_EQ(0x2211, testVal);
+ EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&retBuff, NULL),
+ 0);
+ EXPECT_EQ(pldm_msgbuf_extract_uint8(ctxExtract, &testVal1), 0);
+ EXPECT_EQ(0x77, testVal1);
+
+ EXPECT_EQ(required, strlen(retBuff) + 1);
+ EXPECT_EQ(strncmp(expectData, retBuff, strlen(retBuff) + 1), 0);
+ EXPECT_EQ(pldm_msgbuf_destroy(ctxExtract), 0);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_string_ascii_good_with_length)
+{
+ struct pldm_msgbuf _ctxExtract;
+ struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+ uint8_t src[9] = {0x11, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x77};
+ constexpr size_t required = 6;
+ const char expectData[required] = {0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00};
+ uint16_t testVal;
+ uint8_t testVal1;
+ char* retBuff = NULL;
+ size_t length;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
+ EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, &testVal), 0);
+ EXPECT_EQ(0x2211, testVal);
+ EXPECT_EQ(
+ pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&retBuff, &length),
+ 0);
+ EXPECT_EQ(pldm_msgbuf_extract_uint8(ctxExtract, &testVal1), 0);
+ EXPECT_EQ(0x77, testVal1);
+
+ EXPECT_EQ(required, strlen(retBuff) + 1);
+ EXPECT_EQ(length, strlen(retBuff) + 1);
+ EXPECT_EQ(required, length);
+ EXPECT_EQ(strncmp(expectData, retBuff, strlen(retBuff) + 1), 0);
+ EXPECT_EQ(pldm_msgbuf_destroy(ctxExtract), 0);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_string_ascii_allow_null_args)
+{
+ struct pldm_msgbuf _ctxExtract;
+ struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+ uint8_t src[8] = {0x11, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00};
+ uint16_t testVal;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
+ EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, &testVal), 0);
+ EXPECT_EQ(0x2211, testVal);
+ EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, NULL, NULL), 0);
+ EXPECT_EQ(pldm_msgbuf_destroy(ctxExtract), 0);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_string_ascii_bad_no_terminator)
+{
+ struct pldm_msgbuf _ctxExtract;
+ struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+ uint8_t src[8] = {0x11, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77};
+ uint16_t testVal;
+ char* retBuff = NULL;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
+ EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, &testVal), 0);
+ EXPECT_EQ(0x2211, testVal);
+ EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&retBuff, NULL),
+ -EOVERFLOW);
+ EXPECT_EQ(pldm_msgbuf_destroy(ctxExtract), -EOVERFLOW);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_string_ascii_under)
+{
+ struct pldm_msgbuf _ctxExtract;
+ struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+
+ uint8_t src[1] = {};
+ char* retBuff = NULL;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, 0), 0);
+ ctxExtract->remaining = INTMAX_MIN;
+ EXPECT_NE(pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&retBuff, NULL),
+ 0);
+ EXPECT_EQ(pldm_msgbuf_destroy(ctxExtract), -EOVERFLOW);
+}
+
TEST(msgbuf, pldm_msgbuf_span_remaining_good)
{
struct pldm_msgbuf _ctx;