msgbuf: Generalize array extraction and insertion

Build the type-safe and generic behavior on top of memcpy() via a
"private" helper that takes a void pointer.

Change-Id: Iedb8e9237c780735d4cac41fe0a723c3751c64ce
Signed-off-by: Chris Wang <chris.wang.wiwynn@gmail.com>
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/msgbuf.h b/src/msgbuf.h
index 37ad470..e5e91ed 100644
--- a/src/msgbuf.h
+++ b/src/msgbuf.h
@@ -723,7 +723,8 @@
 		real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
 
 __attribute__((always_inline)) static inline int
-pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, void *dst,
 				size_t count)
 {
 	assert(ctx);
@@ -757,9 +758,23 @@
 	return 0;
 }
 
+__attribute__((always_inline)) static inline int
+pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, char *dst, size_t count)
+{
+	return pldm__msgbuf_extract_array_void(ctx, dst, count);
+}
+
+__attribute__((always_inline)) static inline int
+pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
+				size_t count)
+{
+	return pldm__msgbuf_extract_array_void(ctx, dst, count);
+}
+
 #define pldm_msgbuf_extract_array(ctx, dst, count)                             \
-	_Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \
-								     count)
+	_Generic((*(dst)),                                                     \
+		uint8_t: pldm_msgbuf_extract_array_uint8,                      \
+		char: pldm_msgbuf_extract_array_char)(ctx, dst, count)
 
 __attribute__((always_inline)) static inline int
 pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src)
@@ -953,7 +968,8 @@
 		int32_t: pldm_msgbuf_insert_int32)(dst, src)
 
 __attribute__((always_inline)) static inline int
-pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, const void *src,
 			       size_t count)
 {
 	assert(ctx);
@@ -987,9 +1003,24 @@
 	return 0;
 }
 
+__attribute__((always_inline)) static inline int
+pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, const char *src,
+			      size_t count)
+{
+	return pldm__msgbuf_insert_array_void(ctx, src, count);
+}
+
+__attribute__((always_inline)) static inline int
+pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
+			       size_t count)
+{
+	return pldm__msgbuf_insert_array_void(ctx, src, count);
+}
+
 #define pldm_msgbuf_insert_array(dst, src, count)                              \
-	_Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src,  \
-								    count)
+	_Generic((*(src)),                                                     \
+		uint8_t: pldm_msgbuf_insert_array_uint8,                       \
+		char: pldm_msgbuf_insert_array_char)(dst, src, count)
 
 __attribute__((always_inline)) static inline int
 pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required,
diff --git a/tests/msgbuf.cpp b/tests/msgbuf.cpp
index 9db63f6..52d47ae 100644
--- a/tests/msgbuf.cpp
+++ b/tests/msgbuf.cpp
@@ -456,6 +456,56 @@
     ASSERT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, extract_array_char_buf0_req0)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+    char buf[1] = {'\0'};
+    char arr[1] = {'1'};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, 0), 0);
+    EXPECT_EQ(pldm_msgbuf_extract_array_char(ctx, arr, 0), 0);
+    ASSERT_EQ(pldm_msgbuf_destroy(ctx), 0);
+}
+
+TEST(msgbuf, extract_array_char_buf1_req1)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+    char buf[1] = {'\0'};
+    char arr[1] = {'1'};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+    EXPECT_EQ(pldm_msgbuf_extract_array_char(ctx, arr, sizeof(arr)), 0);
+    EXPECT_EQ(arr[0], '\0');
+    ASSERT_EQ(pldm_msgbuf_destroy(ctx), 0);
+}
+
+TEST(msgbuf, extract_array_char_buf1_req2)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+    char buf[1] = {'\0'};
+    char arr[2] = {'1', '2'};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+    EXPECT_NE(pldm_msgbuf_extract_array_char(ctx, arr, sizeof(arr)), 0);
+    ASSERT_EQ(pldm_msgbuf_destroy(ctx), -EOVERFLOW);
+}
+
+TEST(msgbuf, extract_under_array_char)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+    char buf[1] = {'\0'};
+    char arr[1] = {'1'};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, 0), 0);
+    ctx->remaining = INTMAX_MIN;
+    EXPECT_NE(pldm_msgbuf_extract_array_char(ctx, arr, 1), 0);
+    ASSERT_EQ(pldm_msgbuf_destroy(ctx), -EOVERFLOW);
+}
+
 TEST(msgbuf, consumed_under)
 {
     struct pldm_msgbuf _ctx;
@@ -767,6 +817,55 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, pldm_msgbuf_insert_array_char_good)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+    char src[6] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
+    char buf[6] = {};
+    char retBuff[6] = {};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+    EXPECT_EQ(pldm_msgbuf_insert_array_char(ctx, src, sizeof(src)), 0);
+
+    struct pldm_msgbuf _ctxExtract;
+    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
+    EXPECT_EQ(
+        pldm_msgbuf_extract_array_char(ctxExtract, retBuff, sizeof(retBuff)),
+        0);
+
+    EXPECT_EQ(memcmp(src, retBuff, sizeof(retBuff)), 0);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctxExtract), 0);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), 0);
+}
+
+TEST(msgbuf, pldm_msgbuf_insert_array_char_bad)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+    char src[6] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
+    char buf[6] = {};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+    EXPECT_EQ(pldm_msgbuf_insert_array_char(ctx, NULL, sizeof(src)), -EINVAL);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), 0);
+}
+
+TEST(msgbuf, insert_under_array_char)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+    char buf[1] = {};
+    char val[1] = {0};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, 0), 0);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_insert_array_char(ctx, val, sizeof(val)), 0);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), -EOVERFLOW);
+}
+
 TEST(msgbuf, pldm_msgbuf_span_required_good)
 {
     struct pldm_msgbuf _ctx;