// Copyright 2018-2019 - Omar Sandoval // SPDX-License-Identifier: GPL-3.0+ /** * @file * * Serialization and deserialization to and from memory. * * See @ref SerializationDeserialization. */ #ifndef DRGN_SERIALIZE_H #define DRGN_SERIALIZE_H #include #include /** * @ingroup Internals * * @defgroup SerializationDeserialization Serialization/deserialization * * Serialization and deserialization of bits to and from memory. * * @{ */ /** Copy the @p bit_size%th bit to the more-significant bits in an integer. */ static inline int64_t sign_extend(int64_t svalue, uint64_t bit_size) { if (bit_size < 64) { int64_t mask; mask = INT64_C(1) << (bit_size - 1); svalue = (svalue ^ mask) - mask; } return svalue; } /** Truncate a signed integer to @p bit_size bits. */ static inline int64_t truncate_signed(int64_t svalue, uint64_t bit_size) { if (bit_size < 64) { /* INT64_C(1) << 63 is undefined, so this must be UINT64_C. */ svalue &= (UINT64_C(1) << bit_size) - 1; } return sign_extend(svalue, bit_size); } /** Truncate an unsigned integer to @p bit_size bits. */ static inline uint64_t truncate_unsigned(uint64_t uvalue, uint64_t bit_size) { if (bit_size < 64) uvalue &= (UINT64_C(1) << bit_size) - 1; return uvalue; } /** * Serialize bits to a memory buffer. * * Note that this does not perform any bounds checking, so the caller must check * that bit_offset + bit_size is within the buffer. * * @param[in] buf Memory buffer to write to. * @param[in] bit_offset Offset in bits from the beginning of @p buf to where to * write. This is interpreted differently based on @p little_endian. * @param[in] uvalue Bits to write, in host order. * @param[in] bit_size Number of bits in @p uvalue. This must be grather than * zero and no more than 64. Note that this is not checked or truncated, so if * @p uvalue has more than this many bits, the results will likely be incorrect. * @param[in] little_endian Whether the bits should be written out in * little-endian order. */ void serialize_bits(void *buf, uint64_t bit_offset, uint64_t uvalue, uint8_t bit_size, bool little_endian); /** * Deserialize bits from a memory buffer. * * Note that this does not perform any bounds checking, so the caller must check * that bit_offset + bit_size is within the buffer. * * @param[in] buf Memory buffer to read from. * @param[in] bit_offset Offset in bits from the beginning of @p buf to where to * read from. This is interpreted differently based on @p little_endian. * @param[in] bit_size Number of bits to read. This must be grather than zero * and no more than 64. * @param[in] little_endian Whether the bits should be interpreted in * little-endian order. * @return The read bits in host order. */ uint64_t deserialize_bits(const void *buf, uint64_t bit_offset, uint8_t bit_size, bool little_endian); /** @} */ #endif /* DRGN_SERIALIZE_H */