msgbuf: Add pldm_msgbuf_span_until()
pldm_msgbuf_span_until() extracts the indirectly-specified range from
the current cursor position until the offset where only `trailer` bytes
remain in the buffer.
Change-Id: Icb70a3af54f21ba1afd311699cb860bf24bb155e
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/msgbuf.h b/src/msgbuf.h
index a0e1204..78ec89a 100644
--- a/src/msgbuf.h
+++ b/src/msgbuf.h
@@ -1141,6 +1141,42 @@
return 0;
}
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE
+int pldm_msgbuf_span_until(struct pldm_msgbuf *ctx, size_t trailer,
+ void **cursor, size_t *length)
+{
+#if INTMAX_MAX < SIZE_MAX
+ if (trailer > INTMAX_MAX) {
+ return pldm__msgbuf_invalidate(ctx);
+ }
+#endif
+
+ if (ctx->remaining >= (intmax_t)trailer) {
+ ptrdiff_t delta;
+
+ assert(ctx->cursor);
+
+ delta = ctx->remaining - (intmax_t)trailer;
+ if (cursor) {
+ *cursor = ctx->cursor;
+ }
+ ctx->cursor += delta;
+ if (length) {
+ *length = delta;
+ }
+ ctx->remaining = (intmax_t)trailer;
+ return 0;
+ }
+
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)trailer) {
+ ctx->remaining = INTMAX_MIN + (intmax_t)trailer;
+ return -EOVERFLOW;
+ }
+
+ return pldm__msgbuf_invalidate(ctx);
+}
+
LIBPLDM_CC_NONNULL
LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_peek_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
diff --git a/tests/msgbuf.cpp b/tests/msgbuf.cpp
index dcf5316..f6dcad5 100644
--- a/tests/msgbuf.cpp
+++ b/tests/msgbuf.cpp
@@ -1248,6 +1248,115 @@
EXPECT_EQ(pldm_msgbuf_complete(ctx), 0);
}
+TEST(msgbuf, pldm_msgbuf_span_until_0_1)
+{
+ struct pldm_msgbuf _ctx;
+ struct pldm_msgbuf* ctx = &_ctx;
+ uint8_t buf[] = {1};
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 0, nullptr, nullptr), 0);
+ ASSERT_EQ(pldm_msgbuf_complete_consumed(ctx), 0);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_until_0_1_p)
+{
+ struct pldm_msgbuf _ctx;
+ struct pldm_msgbuf* ctx = &_ctx;
+ uint8_t buf[] = {1};
+ void* start;
+ size_t len;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 0, &start, &len), 0);
+ ASSERT_EQ(pldm_msgbuf_complete_consumed(ctx), 0);
+ EXPECT_EQ(buf, start);
+ EXPECT_EQ(len, 1);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_until_1_1)
+{
+ struct pldm_msgbuf _ctx;
+ struct pldm_msgbuf* ctx = &_ctx;
+ uint8_t buf[] = {1};
+ uint8_t val;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 1, nullptr, nullptr), 0);
+ ASSERT_EQ(pldm_msgbuf_extract_uint8(ctx, val), 0);
+ ASSERT_EQ(pldm_msgbuf_complete_consumed(ctx), 0);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_until_1_2)
+{
+ struct pldm_msgbuf _ctx;
+ struct pldm_msgbuf* ctx = &_ctx;
+ uint8_t buf[] = {0, 1};
+ uint8_t val;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 1, nullptr, nullptr), 0);
+ ASSERT_EQ(pldm_msgbuf_extract_uint8(ctx, val), 0);
+ ASSERT_EQ(pldm_msgbuf_complete_consumed(ctx), 0);
+ EXPECT_EQ(val, 1);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_until_1_3)
+{
+ struct pldm_msgbuf _ctx;
+ struct pldm_msgbuf* ctx = &_ctx;
+ uint8_t buf[] = {0, 1, 2};
+ uint8_t val;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 1, nullptr, nullptr), 0);
+ ASSERT_EQ(pldm_msgbuf_extract_uint8(ctx, val), 0);
+ ASSERT_EQ(pldm_msgbuf_complete_consumed(ctx), 0);
+ EXPECT_EQ(val, 2);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_until_2_3)
+{
+ struct pldm_msgbuf _ctx;
+ struct pldm_msgbuf* ctx = &_ctx;
+ uint8_t buf[] = {0, 1, 2};
+ uint8_t val0;
+ uint8_t val1;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 2, nullptr, nullptr), 0);
+ ASSERT_EQ(pldm_msgbuf_extract_uint8(ctx, val0), 0);
+ ASSERT_EQ(pldm_msgbuf_extract_uint8(ctx, val1), 0);
+ ASSERT_EQ(pldm_msgbuf_complete_consumed(ctx), 0);
+ EXPECT_EQ(val0, 1);
+ EXPECT_EQ(val1, 2);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_until_short)
+{
+ struct pldm_msgbuf _ctx;
+ struct pldm_msgbuf* ctx = &_ctx;
+ uint8_t buf[] = {1};
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 2, nullptr, nullptr), -EOVERFLOW);
+ ASSERT_EQ(pldm_msgbuf_complete(ctx), -EOVERFLOW);
+}
+
+TEST(msgbuf, pldm_msgbuf_span_until_saturated)
+{
+ struct pldm_msgbuf _ctx;
+ struct pldm_msgbuf* ctx = &_ctx;
+ uint8_t buf[] = {1};
+ uint16_t val;
+
+ ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
+ EXPECT_EQ(pldm_msgbuf_extract_uint16(ctx, val), -EOVERFLOW);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 0, nullptr, nullptr), -EOVERFLOW);
+ EXPECT_EQ(pldm_msgbuf_span_until(ctx, 0, nullptr, nullptr), -EOVERFLOW);
+ ASSERT_EQ(pldm_msgbuf_complete(ctx), -EOVERFLOW);
+}
+
TEST(msgbuf, pldm_msgbuf_copy_good)
{
struct pldm_msgbuf _src;