)
/** @} */
+/** @name copy data from dbuff
+ * @{
+ */
+
+static inline ssize_t _fr_dbuff_memcpy_out(uint8_t *out, fr_dbuff_t *dbuff, size_t outlen)
+{
+ FR_DBUFF_EXTEND_LOWAT_OR_RETURN(dbuff, outlen);
+
+ memcpy(out, dbuff->p, outlen);
+
+ return _fr_dbuff_set(dbuff, dbuff->p + outlen);
+}
+
+static inline ssize_t _fr_dbuff_memcpy_out_dbuff(fr_dbuff_t *out, fr_dbuff_t *in, size_t outlen)
+{
+ if (outlen > fr_dbuff_remaining(in)) outlen = fr_dbuff_remaining(in);
+
+ /*
+ * If there's too many bytes, then
+ * return how many additional bytes
+ * we would have needed.
+ */
+ FR_DBUFF_EXTEND_LOWAT_OR_RETURN(out, outlen);
+
+ (void)_fr_dbuff_memcpy_out(out->p, in, outlen);
+
+ return _fr_dbuff_set(out, out->p + outlen);
+}
+
+#define FR_DBUFF_MEMCPY_OUT_RETURN(_out, _dbuff, _outlen) FR_DBUFF_RETURN(fr_dbuff_memcpy_out, _out, _dbuff, _outlen)
+
+/** Copy outlen bytes from the dbuff
+ *
+ * If _out is a dbuff, it will be advanced by the number of bytes
+ * copied from _in.
+ *
+ * If _out is a dbuff and _outlen is greater than the
+ * number of bytes available in _out, then the copy operation will
+ * be truncated, so that we don't write off the end of the buffer.
+ *
+ * @param[in] _out to copy data to.
+ * @param[in] _in Data to copy to dbuff.
+ * @param[in] _outlen How much data we need to copy.
+ * If _out is a char * or dbuff * and SIZE_MAX
+ * is passed, then _inlen will be substituted
+ * for the length of the buffer.
+ * @return
+ * - 0 no data copied.
+ * - >0 the number of bytes copied.
+ * - <0 the number of bytes we would have needed
+ * to complete the copy operation.
+ */
+#define fr_dbuff_memcpy_out(_out, _in, _outlen) \
+ _Generic((_out), \
+ uint8_t * : _fr_dbuff_memcpy_out((uint8_t *)(_out), _in, _outlen), \
+ int8_t * : _fr_dbuff_memcpy_out((uint8_t *)(_out), _in, _outlen), \
+ fr_dbuff_t * : _fr_dbuff_memcpy_out_dbuff((fr_dbuff_t *)_out, _in, _outlen) \
+ )
+
+#define FR_DBUFF_OUT_DEF(_type) \
+static inline ssize_t fr_dbuff_##_type##_out(_type##_t *num, fr_dbuff_t *dbuff) \
+{ \
+ fr_assert(num); \
+ FR_DBUFF_EXTEND_LOWAT_OR_RETURN(dbuff, sizeof(_type##_t)); \
+ *num = fr_net_to_##_type(dbuff->p); \
+ return fr_dbuff_advance(dbuff, sizeof(_type##_t)); \
+}
+
+FR_DBUFF_OUT_DEF(uint16)
+FR_DBUFF_OUT_DEF(uint32)
+FR_DBUFF_OUT_DEF(uint64)
+FR_DBUFF_OUT_DEF(int16)
+FR_DBUFF_OUT_DEF(int32)
+FR_DBUFF_OUT_DEF(int64)
+
+#define fr_dbuff_out(_value, _dbuff) \
+ _Generic((_value), \
+ uint16_t * : fr_dbuff_uint16_out((uint16_t *)(_value), _dbuff), \
+ uint32_t * : fr_dbuff_uint32_out((uint32_t *)(_value), _dbuff), \
+ uint64_t * : fr_dbuff_uint64_out((uint64_t *)(_value), _dbuff), \
+ int16_t * : fr_dbuff_int16_out((int16_t *)(_value), _dbuff), \
+ int32_t * : fr_dbuff_int32_out((int32_t *)(_value), _dbuff), \
+ int64_t * : fr_dbuff_int64_out((int64_t *)(_value), _dbuff) \
+ )
+#define FR_DBUFF_OUT_RETURN(_value, _dbuff) FR_DBUFF_RETURN(fr_dbuff_out, _value, _dbuff)
+
+/** @} */
+
#ifdef __cplusplus
}
#endif
TEST_CHECK(fr_dbuff_in(&dbuff2, (uint64_t) 0x123456789abcdef0) == -8);
}
+/** Test functions that read from dbuffs.
+ *
+ */
+static void test_dbuff_out(void)
+{
+ uint8_t const buff1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ uint8_t buff2[8];
+ uint8_t buff3[8];
+ fr_dbuff_t dbuff1;
+ fr_dbuff_t dbuff2;
+ uint16_t u16val = 0;
+ uint32_t u32val = 0;
+ uint64_t u64val = 0;
+ int16_t i16val = 0;
+ int32_t i32val = 0;
+ int64_t i64val = 0;
+
+ fr_dbuff_init(&dbuff1, buff1, sizeof(buff1));
+ fr_dbuff_init(&dbuff2, buff2, sizeof(buff2));
+
+ TEST_CASE("Check dbuff reads of unsigned integers");
+ TEST_CHECK(fr_dbuff_out(&u16val, &dbuff1) == 2);
+ TEST_CHECK(u16val == 0x0123);
+ TEST_CHECK(fr_dbuff_out(&u32val, &dbuff1) == 4);
+ TEST_CHECK(u32val == 0x456789ab);
+ fr_dbuff_set_to_start(&dbuff1);
+ TEST_CHECK(fr_dbuff_out(&u64val, &dbuff1) == 8);
+ TEST_CHECK(u64val == 0x0123456789abcdef);
+
+ TEST_CASE("Don't walk off the end of the buffer");
+ TEST_CHECK(fr_dbuff_out(&u32val, &dbuff1) == -4);
+
+ TEST_CASE("Check dbuff reads of signed integers");
+ fr_dbuff_set_to_start(&dbuff1);
+ TEST_CHECK(fr_dbuff_out(&i16val, &dbuff1) == 2);
+ TEST_CHECK(i16val == 0x0123);
+ TEST_CHECK(fr_dbuff_out(&i32val, &dbuff1) == 4);
+ TEST_CHECK(i32val == 0x456789ab);
+ fr_dbuff_set_to_start(&dbuff1);
+ TEST_CHECK(fr_dbuff_out(&i64val, &dbuff1) == 8);
+ TEST_CHECK(i64val == 0x0123456789abcdef);
+
+ TEST_CASE("fr_dbuff_memcpy_out");
+ fr_dbuff_set_to_start(&dbuff1);
+ memset(buff3, 0, sizeof(buff3));
+ TEST_CHECK(fr_dbuff_memcpy_out(buff3, &dbuff1, 7) == 7);
+ TEST_CHECK(memcmp(buff3, fr_dbuff_start(&dbuff1), 7) == 0 && buff3[7] == 0);
+ fr_dbuff_set_to_start(&dbuff1);
+ TEST_CHECK(fr_dbuff_memcpy_out(&dbuff2, &dbuff1, 4) == 4);
+ fr_dbuff_set_to_start(&dbuff1);
+ fr_dbuff_advance(&dbuff1, 3);
+ TEST_CHECK(fr_dbuff_memcpy_out(&dbuff2, &dbuff1, 4) == 4);
+ TEST_CHECK(memcmp(fr_dbuff_start(&dbuff2), fr_dbuff_start(&dbuff1), 4) == 0 &&
+ memcmp(fr_dbuff_start(&dbuff2) + 4, fr_dbuff_start(&dbuff1) + 3, 4) == 0);
+}
TEST_LIST = {
/*
{ "fr_dbuff_move", test_dbuff_move },
{ "fr_dbuff_talloc_extend", test_dbuff_talloc_extend },
{ "fr_dbuff_talloc_extend_multi_level", test_dbuff_talloc_extend_multi_level },
+ { "fr_dbff_out", test_dbuff_out },
{ NULL }