1/* 2 * buffer.h -- generic memory buffer. 3 * 4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 * 9 * The buffer module implements a generic buffer. The API is based on 10 * the java.nio.Buffer interface. 11 */ 12 13#ifndef BUFFER_H 14#define BUFFER_H 15 16#include <assert.h> 17#include <stdarg.h> 18#include <string.h> 19 20#include "region-allocator.h" 21#include "util.h" 22 23typedef struct buffer buffer_type; 24 25struct buffer 26{ 27 /* 28 * The current position used for reading/writing. 29 */ 30 size_t _position; 31 32 /* 33 * The read/write limit. 34 */ 35 size_t _limit; 36 37 /* 38 * The amount of data the buffer can contain. 39 */ 40 size_t _capacity; 41 42 /* 43 * The data contained in the buffer. 44 */ 45 uint8_t *_data; 46 47 /* 48 * If the buffer is fixed it cannot be resized. 49 */ 50 unsigned _fixed : 1; 51}; 52 53#ifdef NDEBUG 54static inline void 55buffer_invariant(buffer_type *ATTR_UNUSED(buffer)) 56{ 57} 58#else 59static inline void 60buffer_invariant(buffer_type *buffer) 61{ 62 assert(buffer); 63 assert(buffer->_position <= buffer->_limit); 64 assert(buffer->_limit <= buffer->_capacity); 65 assert(buffer->_data); 66} 67#endif 68 69/* 70 * Create a new buffer with the specified capacity. 71 */ 72buffer_type *buffer_create(region_type *region, size_t capacity); 73 74/* 75 * Create a buffer with the specified data. The data is not copied 76 * and no memory allocations are done. The buffer is fixed and cannot 77 * be resized using buffer_reserve(). 78 */ 79void buffer_create_from(buffer_type *buffer, void *data, size_t size); 80 81/* 82 * Clear the buffer and make it ready for writing. The buffer's limit 83 * is set to the capacity and the position is set to 0. 84 */ 85void buffer_clear(buffer_type *buffer); 86 87/* 88 * Make the buffer ready for reading the data that has been written to 89 * the buffer. The buffer's limit is set to the current position and 90 * the position is set to 0. 91 */ 92void buffer_flip(buffer_type *buffer); 93 94/* 95 * Make the buffer ready for re-reading the data. The buffer's 96 * position is reset to 0. 97 */ 98void buffer_rewind(buffer_type *buffer); 99 100static inline size_t 101buffer_position(buffer_type *buffer) 102{ 103 return buffer->_position; 104} 105 106/* 107 * Set the buffer's position to MARK. The position must be less than 108 * or equal to the buffer's limit. 109 */ 110static inline void 111buffer_set_position(buffer_type *buffer, size_t mark) 112{ 113 assert(mark <= buffer->_limit); 114 buffer->_position = mark; 115} 116 117/* 118 * Change the buffer's position by COUNT bytes. The position must not 119 * be moved behind the buffer's limit or before the beginning of the 120 * buffer. 121 */ 122static inline void 123buffer_skip(buffer_type *buffer, ssize_t count) 124{ 125 assert(buffer->_position + count <= buffer->_limit); 126 buffer->_position += count; 127} 128 129static inline size_t 130buffer_limit(buffer_type *buffer) 131{ 132 return buffer->_limit; 133} 134 135/* 136 * Change the buffer's limit. If the buffer's position is greater 137 * than the new limit the position is set to the limit. 138 */ 139static inline void 140buffer_set_limit(buffer_type *buffer, size_t limit) 141{ 142 assert(limit <= buffer->_capacity); 143 buffer->_limit = limit; 144 if (buffer->_position > buffer->_limit) 145 buffer->_position = buffer->_limit; 146} 147 148 149static inline size_t 150buffer_capacity(buffer_type *buffer) 151{ 152 return buffer->_capacity; 153} 154 155/* 156 * Change the buffer's capacity. The data is reallocated so any 157 * pointers to the data may become invalid. The buffer's limit is set 158 * to the buffer's new capacity. 159 */ 160void buffer_set_capacity(buffer_type *buffer, size_t capacity); 161 162/* 163 * Ensure BUFFER can contain at least AMOUNT more bytes. The buffer's 164 * capacity is increased if necessary using buffer_set_capacity(). 165 * 166 * The buffer's limit is always set to the (possibly increased) 167 * capacity. 168 */ 169void buffer_reserve(buffer_type *buffer, size_t amount); 170 171/* 172 * Return a pointer to the data at the indicated position. 173 */ 174static inline uint8_t * 175buffer_at(buffer_type *buffer, size_t at) 176{ 177 assert(at <= buffer->_limit); 178 return buffer->_data + at; 179} 180 181/* 182 * Return a pointer to the beginning of the buffer (the data at 183 * position 0). 184 */ 185static inline uint8_t * 186buffer_begin(buffer_type *buffer) 187{ 188 return buffer_at(buffer, 0); 189} 190 191/* 192 * Return a pointer to the end of the buffer (the data at the buffer's 193 * limit). 194 */ 195static inline uint8_t * 196buffer_end(buffer_type *buffer) 197{ 198 return buffer_at(buffer, buffer->_limit); 199} 200 201/* 202 * Return a pointer to the data at the buffer's current position. 203 */ 204static inline uint8_t * 205buffer_current(buffer_type *buffer) 206{ 207 return buffer_at(buffer, buffer->_position); 208} 209 210/* 211 * The number of bytes remaining between the indicated position and 212 * the limit. 213 */ 214static inline size_t 215buffer_remaining_at(buffer_type *buffer, size_t at) 216{ 217 buffer_invariant(buffer); 218 assert(at <= buffer->_limit); 219 return buffer->_limit - at; 220} 221 222/* 223 * The number of bytes remaining between the buffer's position and 224 * limit. 225 */ 226static inline size_t 227buffer_remaining(buffer_type *buffer) 228{ 229 return buffer_remaining_at(buffer, buffer->_position); 230} 231 232/* 233 * Check if the buffer has at least COUNT more bytes available. 234 * Before reading or writing the caller needs to ensure enough space 235 * is available! 236 */ 237static inline int 238buffer_available_at(buffer_type *buffer, size_t at, size_t count) 239{ 240 return count <= buffer_remaining_at(buffer, at); 241} 242 243static inline int 244buffer_available(buffer_type *buffer, size_t count) 245{ 246 return buffer_available_at(buffer, buffer->_position, count); 247} 248 249static inline void 250buffer_write_at(buffer_type *buffer, size_t at, const void *data, size_t count) 251{ 252 assert(buffer_available_at(buffer, at, count)); 253 memcpy(buffer->_data + at, data, count); 254} 255 256static inline void 257buffer_write(buffer_type *buffer, const void *data, size_t count) 258{ 259 buffer_write_at(buffer, buffer->_position, data, count); 260 buffer->_position += count; 261} 262 263static inline void 264buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) 265{ 266 buffer_write_at(buffer, at, str, strlen(str)); 267} 268 269static inline void 270buffer_write_string(buffer_type *buffer, const char *str) 271{ 272 buffer_write(buffer, str, strlen(str)); 273} 274 275static inline void 276buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data) 277{ 278 assert(buffer_available_at(buffer, at, sizeof(data))); 279 buffer->_data[at] = data; 280} 281 282static inline void 283buffer_write_u8(buffer_type *buffer, uint8_t data) 284{ 285 buffer_write_u8_at(buffer, buffer->_position, data); 286 buffer->_position += sizeof(data); 287} 288 289static inline void 290buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data) 291{ 292 assert(buffer_available_at(buffer, at, sizeof(data))); 293 write_uint16(buffer->_data + at, data); 294} 295 296static inline void 297buffer_write_u16(buffer_type *buffer, uint16_t data) 298{ 299 buffer_write_u16_at(buffer, buffer->_position, data); 300 buffer->_position += sizeof(data); 301} 302 303static inline void 304buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data) 305{ 306 assert(buffer_available_at(buffer, at, sizeof(data))); 307 write_uint32(buffer->_data + at, data); 308} 309 310static inline void 311buffer_write_u32(buffer_type *buffer, uint32_t data) 312{ 313 buffer_write_u32_at(buffer, buffer->_position, data); 314 buffer->_position += sizeof(data); 315} 316 317static inline void 318buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data) 319{ 320 assert(buffer_available_at(buffer, at, sizeof(data))); 321 write_uint64(buffer->_data + at, data); 322} 323 324static inline void 325buffer_write_u64(buffer_type *buffer, uint64_t data) 326{ 327 buffer_write_u64_at(buffer, buffer->_position, data); 328 buffer->_position += sizeof(data); 329} 330 331static inline void 332buffer_read_at(buffer_type *buffer, size_t at, void *data, size_t count) 333{ 334 assert(buffer_available_at(buffer, at, count)); 335 memcpy(data, buffer->_data + at, count); 336} 337 338static inline void 339buffer_read(buffer_type *buffer, void *data, size_t count) 340{ 341 buffer_read_at(buffer, buffer->_position, data, count); 342 buffer->_position += count; 343} 344 345static inline uint8_t 346buffer_read_u8_at(buffer_type *buffer, size_t at) 347{ 348 assert(buffer_available_at(buffer, at, sizeof(uint8_t))); 349 return buffer->_data[at]; 350} 351 352static inline uint8_t 353buffer_read_u8(buffer_type *buffer) 354{ 355 uint8_t result = buffer_read_u8_at(buffer, buffer->_position); 356 buffer->_position += sizeof(uint8_t); 357 return result; 358} 359 360static inline uint16_t 361buffer_read_u16_at(buffer_type *buffer, size_t at) 362{ 363 assert(buffer_available_at(buffer, at, sizeof(uint16_t))); 364 return read_uint16(buffer->_data + at); 365} 366 367static inline uint16_t 368buffer_read_u16(buffer_type *buffer) 369{ 370 uint16_t result = buffer_read_u16_at(buffer, buffer->_position); 371 buffer->_position += sizeof(uint16_t); 372 return result; 373} 374 375static inline uint32_t 376buffer_read_u32_at(buffer_type *buffer, size_t at) 377{ 378 assert(buffer_available_at(buffer, at, sizeof(uint32_t))); 379 return read_uint32(buffer->_data + at); 380} 381 382static inline uint32_t 383buffer_read_u32(buffer_type *buffer) 384{ 385 uint32_t result = buffer_read_u32_at(buffer, buffer->_position); 386 buffer->_position += sizeof(uint32_t); 387 return result; 388} 389 390static inline uint64_t 391buffer_read_u64_at(buffer_type *buffer, size_t at) 392{ 393 assert(buffer_available_at(buffer, at, sizeof(uint64_t))); 394 return read_uint64(buffer->_data + at); 395} 396 397static inline uint64_t 398buffer_read_u64(buffer_type *buffer) 399{ 400 uint64_t result = buffer_read_u64_at(buffer, buffer->_position); 401 buffer->_position += sizeof(uint64_t); 402 return result; 403} 404 405/* 406 * Print to the buffer, increasing the capacity if required using 407 * buffer_reserve(). The buffer's position is set to the terminating 408 * '\0'. Returns the number of characters written (not including the 409 * terminating '\0'). 410 */ 411int buffer_printf(buffer_type *buffer, const char *format, ...) 412 ATTR_FORMAT(printf, 2, 3); 413 414#endif /* BUFFER_H */ 415