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 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