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 void
buffer_write_string_at(buffer_type * buffer,size_t at,const char * str)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
buffer_write_string(buffer_type * buffer,const char * str)270 buffer_write_string(buffer_type *buffer, const char *str)
271 {
272 	buffer_write(buffer, str, strlen(str));
273 }
274 
275 static inline void
buffer_write_u8_at(buffer_type * buffer,size_t at,uint8_t data)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
buffer_write_u8(buffer_type * buffer,uint8_t data)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
buffer_write_u16_at(buffer_type * buffer,size_t at,uint16_t data)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
buffer_write_u16(buffer_type * buffer,uint16_t data)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
buffer_write_u32_at(buffer_type * buffer,size_t at,uint32_t data)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
buffer_write_u32(buffer_type * buffer,uint32_t data)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
buffer_write_u64_at(buffer_type * buffer,size_t at,uint64_t data)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
buffer_write_u64(buffer_type * buffer,uint64_t data)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
buffer_read_at(buffer_type * buffer,size_t at,void * data,size_t count)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
buffer_read(buffer_type * buffer,void * data,size_t count)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
buffer_read_u8_at(buffer_type * buffer,size_t at)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
buffer_read_u8(buffer_type * buffer)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
buffer_read_u16_at(buffer_type * buffer,size_t at)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
buffer_read_u16(buffer_type * buffer)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
buffer_read_u32_at(buffer_type * buffer,size_t at)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
buffer_read_u32(buffer_type * buffer)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
buffer_read_u64_at(buffer_type * buffer,size_t at)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
buffer_read_u64(buffer_type * buffer)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