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 23 typedef struct buffer buffer_type; 24 25 struct 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 54 static inline void 55 buffer_invariant(buffer_type *ATTR_UNUSED(buffer)) 56 { 57 } 58 #else 59 static inline void 60 buffer_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 */ 72 buffer_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 */ 79 void 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 */ 85 void 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 */ 92 void 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 */ 98 void buffer_rewind(buffer_type *buffer); 99 100 static inline size_t 101 buffer_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 */ 110 static inline void 111 buffer_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 */ 122 static inline void 123 buffer_skip(buffer_type *buffer, ssize_t count) 124 { 125 assert(buffer->_position + count <= buffer->_limit); 126 buffer->_position += count; 127 } 128 129 static inline size_t 130 buffer_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 */ 139 static inline void 140 buffer_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 149 static inline size_t 150 buffer_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 */ 160 void 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 */ 169 void buffer_reserve(buffer_type *buffer, size_t amount); 170 171 /* 172 * Return a pointer to the data at the indicated position. 173 */ 174 static inline uint8_t * 175 buffer_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 */ 185 static inline uint8_t * 186 buffer_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 */ 195 static inline uint8_t * 196 buffer_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 */ 204 static inline uint8_t * 205 buffer_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 */ 214 static inline size_t 215 buffer_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 */ 226 static inline size_t 227 buffer_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 */ 237 static inline int 238 buffer_available_at(buffer_type *buffer, size_t at, size_t count) 239 { 240 return count <= buffer_remaining_at(buffer, at); 241 } 242 243 static inline int 244 buffer_available(buffer_type *buffer, size_t count) 245 { 246 return buffer_available_at(buffer, buffer->_position, count); 247 } 248 249 static inline void 250 buffer_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 256 static inline void 257 buffer_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 263 static inline void 264 buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) 265 { 266 buffer_write_at(buffer, at, str, strlen(str)); 267 } 268 269 static inline void 270 buffer_write_string(buffer_type *buffer, const char *str) 271 { 272 buffer_write(buffer, str, strlen(str)); 273 } 274 275 static inline void 276 buffer_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 282 static inline void 283 buffer_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 289 static inline void 290 buffer_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 296 static inline void 297 buffer_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 303 static inline void 304 buffer_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 310 static inline void 311 buffer_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 317 static inline void 318 buffer_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 324 static inline void 325 buffer_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 331 static inline void 332 buffer_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 338 static inline void 339 buffer_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 345 static inline uint8_t 346 buffer_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 352 static inline uint8_t 353 buffer_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 360 static inline uint16_t 361 buffer_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 367 static inline uint16_t 368 buffer_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 375 static inline uint32_t 376 buffer_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 382 static inline uint32_t 383 buffer_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 390 static inline uint64_t 391 buffer_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 397 static inline uint64_t 398 buffer_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 */ 411 int buffer_printf(buffer_type *buffer, const char *format, ...) 412 ATTR_FORMAT(printf, 2, 3); 413 414 #endif /* _BUFFER_H_ */ 415