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