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, const 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 int 264 try_buffer_write_at(buffer_type *buffer, size_t at, const void *data, size_t count) 265{ 266 if(!buffer_available_at(buffer, at, count)) 267 return 0; 268 memcpy(buffer->_data + at, data, count); 269 return 1; 270} 271 272 static inline int 273 try_buffer_write(buffer_type *buffer, const void *data, size_t count) 274{ 275 if(!try_buffer_write_at(buffer, buffer->_position, data, count)) 276 return 0; 277 buffer->_position += count; 278 return 1; 279} 280 281 static inline void 282 buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) 283{ 284 buffer_write_at(buffer, at, str, strlen(str)); 285} 286 287 static inline void 288 buffer_write_string(buffer_type *buffer, const char *str) 289{ 290 buffer_write(buffer, str, strlen(str)); 291} 292 293 static inline int 294 try_buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) 295{ 296 return try_buffer_write_at(buffer, at, str, strlen(str)); 297} 298 299 static inline int 300 try_buffer_write_string(buffer_type *buffer, const char *str) 301{ 302 return try_buffer_write(buffer, str, strlen(str)); 303} 304 305 static inline void 306 buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data) 307{ 308 assert(buffer_available_at(buffer, at, sizeof(data))); 309 buffer->_data[at] = data; 310} 311 312 static inline void 313 buffer_write_u8(buffer_type *buffer, uint8_t data) 314{ 315 buffer_write_u8_at(buffer, buffer->_position, data); 316 buffer->_position += sizeof(data); 317} 318 319 static inline void 320 buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data) 321{ 322 assert(buffer_available_at(buffer, at, sizeof(data))); 323 write_uint16(buffer->_data + at, data); 324} 325 326 static inline void 327 buffer_write_u16(buffer_type *buffer, uint16_t data) 328{ 329 buffer_write_u16_at(buffer, buffer->_position, data); 330 buffer->_position += sizeof(data); 331} 332 333 static inline void 334 buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data) 335{ 336 assert(buffer_available_at(buffer, at, sizeof(data))); 337 write_uint32(buffer->_data + at, data); 338} 339 340 static inline void 341 buffer_write_u32(buffer_type *buffer, uint32_t data) 342{ 343 buffer_write_u32_at(buffer, buffer->_position, data); 344 buffer->_position += sizeof(data); 345} 346 347 static inline void 348 buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data) 349{ 350 assert(buffer_available_at(buffer, at, sizeof(data))); 351 write_uint64(buffer->_data + at, data); 352} 353 354 static inline void 355 buffer_write_u64(buffer_type *buffer, uint64_t data) 356{ 357 buffer_write_u64_at(buffer, buffer->_position, data); 358 buffer->_position += sizeof(data); 359} 360 361 static inline int 362 try_buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data) 363{ 364 if(!buffer_available_at(buffer, at, sizeof(data))) 365 return 0; 366 buffer->_data[at] = data; 367 return 1; 368} 369 370 static inline int 371 try_buffer_write_u8(buffer_type *buffer, uint8_t data) 372{ 373 if(!try_buffer_write_u8_at(buffer, buffer->_position, data)) 374 return 0; 375 buffer->_position += sizeof(data); 376 return 1; 377} 378 379 static inline int 380 try_buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data) 381{ 382 if(!buffer_available_at(buffer, at, sizeof(data))) 383 return 0; 384 write_uint16(buffer->_data + at, data); 385 return 1; 386} 387 388 static inline int 389 try_buffer_write_u16(buffer_type *buffer, uint16_t data) 390{ 391 if(!try_buffer_write_u16_at(buffer, buffer->_position, data)) 392 return 0; 393 buffer->_position += sizeof(data); 394 return 1; 395} 396 397 static inline int 398 try_buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data) 399{ 400 if(!buffer_available_at(buffer, at, sizeof(data))) 401 return 0; 402 write_uint32(buffer->_data + at, data); 403 return 1; 404} 405 406 static inline int 407 try_buffer_write_u32(buffer_type *buffer, uint32_t data) 408{ 409 if(!try_buffer_write_u32_at(buffer, buffer->_position, data)) 410 return 0; 411 buffer->_position += sizeof(data); 412 return 1; 413} 414 415 static inline int 416 try_buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data) 417{ 418 if(!buffer_available_at(buffer, at, sizeof(data))) 419 return 0; 420 write_uint64(buffer->_data + at, data); 421 return 1; 422} 423 424 static inline int 425 try_buffer_write_u64(buffer_type *buffer, uint64_t data) 426{ 427 if(!try_buffer_write_u64_at(buffer, buffer->_position, data)) 428 return 0; 429 buffer->_position += sizeof(data); 430 return 1; 431} 432 433 static inline void 434 buffer_read_at(buffer_type *buffer, size_t at, void *data, size_t count) 435{ 436 assert(buffer_available_at(buffer, at, count)); 437 memcpy(data, buffer->_data + at, count); 438} 439 440 static inline void 441 buffer_read(buffer_type *buffer, void *data, size_t count) 442{ 443 buffer_read_at(buffer, buffer->_position, data, count); 444 buffer->_position += count; 445} 446 447 static inline uint8_t 448 buffer_read_u8_at(buffer_type *buffer, size_t at) 449{ 450 assert(buffer_available_at(buffer, at, sizeof(uint8_t))); 451 return buffer->_data[at]; 452} 453 454 static inline uint8_t 455 buffer_read_u8(buffer_type *buffer) 456{ 457 uint8_t result = buffer_read_u8_at(buffer, buffer->_position); 458 buffer->_position += sizeof(uint8_t); 459 return result; 460} 461 462 static inline uint16_t 463 buffer_read_u16_at(buffer_type *buffer, size_t at) 464{ 465 assert(buffer_available_at(buffer, at, sizeof(uint16_t))); 466 return read_uint16(buffer->_data + at); 467} 468 469 static inline uint16_t 470 buffer_read_u16(buffer_type *buffer) 471{ 472 uint16_t result = buffer_read_u16_at(buffer, buffer->_position); 473 buffer->_position += sizeof(uint16_t); 474 return result; 475} 476 477 static inline uint32_t 478 buffer_read_u32_at(buffer_type *buffer, size_t at) 479{ 480 assert(buffer_available_at(buffer, at, sizeof(uint32_t))); 481 return read_uint32(buffer->_data + at); 482} 483 484 static inline uint32_t 485 buffer_read_u32(buffer_type *buffer) 486{ 487 uint32_t result = buffer_read_u32_at(buffer, buffer->_position); 488 buffer->_position += sizeof(uint32_t); 489 return result; 490} 491 492 static inline uint64_t 493 buffer_read_u64_at(buffer_type *buffer, size_t at) 494{ 495 assert(buffer_available_at(buffer, at, sizeof(uint64_t))); 496 return read_uint64(buffer->_data + at); 497} 498 499 static inline uint64_t 500 buffer_read_u64(buffer_type *buffer) 501{ 502 uint64_t result = buffer_read_u64_at(buffer, buffer->_position); 503 buffer->_position += sizeof(uint64_t); 504 return result; 505} 506 507 /* 508 * Print to the buffer, increasing the capacity if required using 509 * buffer_reserve(). The buffer's position is set to the terminating 510 * '0円'. Returns the number of characters written (not including the 511 * terminating '0円'). 512 */ 513 int buffer_printf(buffer_type *buffer, const char *format, ...) 514 ATTR_FORMAT(printf, 2, 3); 515 516#endif /* BUFFER_H */ 517