Home | History | Annotate | Line # | Download | only in dist
      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