#ifndef buffer_h__included #define buffer_h__included #include #include #include #include #include "mqtt.h" typedef struct { char *data; /**< Pointer to data */ size_t len; /**< Allocated space in data */ size_t position; /**< current cursor position in buffer */ } Buffer; /** * Copy data from current buffer position into dest * * This advances the internal buffer position * * @param src: Source buffer * @param dest: Destination memory area * @param len: Number of bytes to copy * @returns: Actual number of bytes copied */ static inline size_t buffer_copy_out(Buffer *src, char *dest, size_t len) { size_t sz = (len > src->len - src->position) ? src->len - src->position : len; memcpy(dest, src->data + src->position, sz); src->position += sz; return sz; } /** * Copy data into the buffer * * This advances the internal buffer position * * @param src: Source memory area * @param dest: Destination buffer * @param len: Number of bytes to copy * @returns: Actual number of bytes copied */ static inline size_t buffer_copy_in(char *src, Buffer *dest, size_t len) { size_t sz = (len > dest->len - dest->position) ? dest->len - dest->position : len; memcpy(dest->data + dest->position, src, sz); dest->position += sz; return sz; } /** * Get free space in buffer * * @param buffer: Buffer to check * @returns: Number of free bytes in buffer */ static inline size_t buffer_free_space(Buffer *buffer) { return buffer->len - buffer->position; } /** * Check if the internal position is at the end of the buffer * * @param buffer; Buffer to check * @returns: True if end of buffer reached */ static inline bool buffer_eof(Buffer *buffer) { return buffer->position == buffer->len; } /** * Reset internal position of buffer * * @param buffer: Buffer to reset */ static inline void buffer_reset(Buffer *buffer) { buffer->position = 0; } /** * Allocate a new buffer * * @param len: Size of new buffer * @returns: New buffer or NULL if out of memory */ static inline Buffer *buffer_allocate(size_t len) { Buffer *buffer = (Buffer *)malloc(sizeof(Buffer)); if (buffer == NULL) { return NULL; } buffer->len = len; buffer->position = 0; buffer->data = (char *)calloc(1, len); if (buffer->data == NULL) { free(buffer); return NULL; } return buffer; } /** * Re-allocate buffer size * * @param buffer: Buffer to modify * @param len: Size of new buffer * @returns: Modified buffer if realloc did work, check if buffer->len == len to verify */ static inline Buffer *buffer_reallocate(Buffer *buffer, size_t len) { char *new_buffer = (char *)realloc(buffer->data, len); if (new_buffer != NULL) { buffer->data = new_buffer; buffer->len = len; } return buffer; } /** * Create a new buffer from a memory area and a size * * @param data: Memory area * @param len: Length of memory area * @returns: New Buffer * * @attention: the data pointer will be owned by the buffer and freed with it! */ static inline Buffer *buffer_from_data_no_copy(char *data, size_t len) { Buffer *buffer = (Buffer *)malloc(sizeof(Buffer)); buffer->len = len; buffer->data = data; buffer->position = 0; return buffer; } /** * Create a new buffer and copy the data * * @param data: Data to copy into the buffer * @param len: Number of bytes to copy * @returns: New Buffer */ static inline Buffer *buffer_from_data_copy(char *data, size_t len) { Buffer *buffer = buffer_allocate(len); (void)buffer_copy_in(data, buffer, len); buffer->position = 0; return buffer; } /** * Release a buffer * * @param buffer: Buffer to release */ static inline void buffer_release(Buffer *buffer) { free(buffer->data); buffer->data = NULL; free(buffer); } /** * Append data to a buffer * * @param buffer: Buffer to append data to * @param data: Memory area to copy to the end of the buffer * @param len: Number of bytes to copy * @returns: Numbr of bytes copied * * @attention: May come up short if the destination buffer has to be reallocated and * that reallocation fails */ static inline size_t buffer_append_data(Buffer *buffer, char *data, size_t len) { size_t num_bytes = buffer_copy_in(data, buffer, len); if (num_bytes != len) { // reallocate (void)buffer_reallocate(buffer, buffer->len + (len - num_bytes)); if (buffer_eof(buffer)) { // reallocation failed return num_bytes; } (void)buffer_copy_in(data + num_bytes, buffer, (len - num_bytes)); } return len; } /** * Append a buffer to another buffer * * @param dest: Destination buffer * @param src: Source buffer to append * @returns: Number of bytes copied * * @attention: May come up short if the destination buffer has to be reallocated and * that reallocation fails */ static inline size_t buffer_append_buffer(Buffer *dest, Buffer *src) { return buffer_append_data(dest, src->data, src->len); } #if DEBUG #include "debug.h" static inline void buffer_hexdump(Buffer *buffer, int indent) { hexdump(buffer->data, buffer->len, indent); } #else #define buffer_hexdump(_buffer, _indent) /* */ #endif #endif /* buffer_h__included */