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
23typedef struct buffer buffer_type;
24
25struct 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
54static inline void
55buffer_invariant(buffer_type *ATTR_UNUSED(buffer))
56{
57}
58#else
59static inline void
60buffer_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 */
72buffer_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 */
79void 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 */
85void 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 */
92void 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 */
98void buffer_rewind(buffer_type *buffer);
99
100static inline size_t
101buffer_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 */
110static inline void
111buffer_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 */
122static inline void
123buffer_skip(buffer_type *buffer, ssize_t count)
124{
125	assert(buffer->_position + count <= buffer->_limit);
126	buffer->_position += count;
127}
128
129static inline size_t
130buffer_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 */
139static inline void
140buffer_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
149static inline size_t
150buffer_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 */
160void 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 */
169void buffer_reserve(buffer_type *buffer, size_t amount);
170
171/*
172 * Return a pointer to the data at the indicated position.
173 */
174static inline uint8_t *
175buffer_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 */
185static inline uint8_t *
186buffer_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 */
195static inline uint8_t *
196buffer_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 */
204static inline uint8_t *
205buffer_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 */
214static inline size_t
215buffer_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 */
226static inline size_t
227buffer_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 */
237static inline int
238buffer_available_at(buffer_type *buffer, size_t at, size_t count)
239{
240	return count <= buffer_remaining_at(buffer, at);
241}
242
243static inline int
244buffer_available(buffer_type *buffer, size_t count)
245{
246	return buffer_available_at(buffer, buffer->_position, count);
247}
248
249static inline void
250buffer_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
256static inline void
257buffer_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
263static inline void
264buffer_write_string_at(buffer_type *buffer, size_t at, const char *str)
265{
266	buffer_write_at(buffer, at, str, strlen(str));
267}
268
269static inline void
270buffer_write_string(buffer_type *buffer, const char *str)
271{
272	buffer_write(buffer, str, strlen(str));
273}
274
275static inline void
276buffer_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
282static inline void
283buffer_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
289static inline void
290buffer_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
296static inline void
297buffer_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
303static inline void
304buffer_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
310static inline void
311buffer_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
317static inline void
318buffer_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
324static inline void
325buffer_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
331static inline void
332buffer_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
338static inline void
339buffer_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
345static inline uint8_t
346buffer_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
352static inline uint8_t
353buffer_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
360static inline uint16_t
361buffer_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
367static inline uint16_t
368buffer_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
375static inline uint32_t
376buffer_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
382static inline uint32_t
383buffer_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
390static inline uint64_t
391buffer_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
397static inline uint64_t
398buffer_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 */
411int buffer_printf(buffer_type *buffer, const char *format, ...)
412	ATTR_FORMAT(printf, 2, 3);
413
414#endif /* BUFFER_H */
415