xref: /openbsd/usr.sbin/nsd/buffer.h (revision bf87c3c0)
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
buffer_invariant(buffer_type * ATTR_UNUSED (buffer))55 buffer_invariant(buffer_type *ATTR_UNUSED(buffer))
56 {
57 }
58 #else
59 static inline void
buffer_invariant(buffer_type * buffer)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
buffer_position(buffer_type * buffer)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
buffer_set_position(buffer_type * buffer,size_t mark)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
buffer_skip(buffer_type * buffer,ssize_t count)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
buffer_limit(buffer_type * buffer)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
buffer_set_limit(buffer_type * buffer,size_t limit)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
buffer_capacity(buffer_type * buffer)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 *
buffer_at(buffer_type * buffer,size_t at)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 *
buffer_begin(buffer_type * buffer)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 *
buffer_end(buffer_type * buffer)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 *
buffer_current(buffer_type * buffer)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
buffer_remaining_at(buffer_type * buffer,size_t at)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
buffer_remaining(buffer_type * buffer)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
buffer_available_at(buffer_type * buffer,size_t at,size_t count)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
buffer_available(buffer_type * buffer,size_t count)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
buffer_write_at(buffer_type * buffer,size_t at,const void * data,size_t count)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
buffer_write(buffer_type * buffer,const void * data,size_t count)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
try_buffer_write_at(buffer_type * buffer,size_t at,const void * data,size_t count)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
try_buffer_write(buffer_type * buffer,const void * data,size_t count)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
buffer_write_string_at(buffer_type * buffer,size_t at,const char * str)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
buffer_write_string(buffer_type * buffer,const char * str)288 buffer_write_string(buffer_type *buffer, const char *str)
289 {
290 	buffer_write(buffer, str, strlen(str));
291 }
292 
293 static inline int
try_buffer_write_string_at(buffer_type * buffer,size_t at,const char * str)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
try_buffer_write_string(buffer_type * buffer,const char * str)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
buffer_write_u8_at(buffer_type * buffer,size_t at,uint8_t data)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
buffer_write_u8(buffer_type * buffer,uint8_t data)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
buffer_write_u16_at(buffer_type * buffer,size_t at,uint16_t data)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
buffer_write_u16(buffer_type * buffer,uint16_t data)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
buffer_write_u32_at(buffer_type * buffer,size_t at,uint32_t data)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
buffer_write_u32(buffer_type * buffer,uint32_t data)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
buffer_write_u64_at(buffer_type * buffer,size_t at,uint64_t data)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
buffer_write_u64(buffer_type * buffer,uint64_t data)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
try_buffer_write_u8_at(buffer_type * buffer,size_t at,uint8_t data)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
try_buffer_write_u8(buffer_type * buffer,uint8_t data)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
try_buffer_write_u16_at(buffer_type * buffer,size_t at,uint16_t data)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
try_buffer_write_u16(buffer_type * buffer,uint16_t data)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
try_buffer_write_u32_at(buffer_type * buffer,size_t at,uint32_t data)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
try_buffer_write_u32(buffer_type * buffer,uint32_t data)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
try_buffer_write_u64_at(buffer_type * buffer,size_t at,uint64_t data)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
try_buffer_write_u64(buffer_type * buffer,uint64_t data)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
buffer_read_at(buffer_type * buffer,size_t at,void * data,size_t count)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
buffer_read(buffer_type * buffer,void * data,size_t count)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
buffer_read_u8_at(buffer_type * buffer,size_t at)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
buffer_read_u8(buffer_type * buffer)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
buffer_read_u16_at(buffer_type * buffer,size_t at)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
buffer_read_u16(buffer_type * buffer)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
buffer_read_u32_at(buffer_type * buffer,size_t at)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
buffer_read_u32(buffer_type * buffer)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
buffer_read_u64_at(buffer_type * buffer,size_t at)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
buffer_read_u64(buffer_type * buffer)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