libmqtt/src/buffer.h

211 lines
5.3 KiB
C

#ifndef buffer_h__included
#define buffer_h__included
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#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 */