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