1 /*
2  * buffer.h -- generic memory buffer.
3  *
4  * Copyright (c) 2005-2008, 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 GLDNS_SBUFFER_H
14 #define GLDNS_SBUFFER_H
15 
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
19 
20 #ifdef S_SPLINT_S
21 #  define INLINE
22 #else
23 #  ifdef SWIG
24 #    define INLINE static
25 #  else
26 #    define INLINE static inline
27 #  endif
28 #endif
29 
30 /*
31  * Copy data allowing for unaligned accesses in network byte order
32  * (big endian).
33  */
34 INLINE uint16_t
gldns_read_uint16(const void * src)35 gldns_read_uint16(const void *src)
36 {
37 #ifdef ALLOW_UNALIGNED_ACCESSES
38         return ntohs(*(const uint16_t *) src);
39 #else
40         const uint8_t *p = (const uint8_t *) src;
41         return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
42 #endif
43 }
44 
45 INLINE uint32_t
gldns_read_uint32(const void * src)46 gldns_read_uint32(const void *src)
47 {
48 #ifdef ALLOW_UNALIGNED_ACCESSES
49         return ntohl(*(const uint32_t *) src);
50 #else
51         const uint8_t *p = (const uint8_t *) src;
52         return (  ((uint32_t) p[0] << 24)
53                 | ((uint32_t) p[1] << 16)
54                 | ((uint32_t) p[2] << 8)
55                 |  (uint32_t) p[3]);
56 #endif
57 }
58 
59 /*
60  * Copy data allowing for unaligned accesses in network byte order
61  * (big endian).
62  */
63 INLINE void
gldns_write_uint16(void * dst,uint16_t data)64 gldns_write_uint16(void *dst, uint16_t data)
65 {
66 #ifdef ALLOW_UNALIGNED_ACCESSES
67         * (uint16_t *) dst = htons(data);
68 #else
69         uint8_t *p = (uint8_t *) dst;
70         p[0] = (uint8_t) ((data >> 8) & 0xff);
71         p[1] = (uint8_t) (data & 0xff);
72 #endif
73 }
74 
75 INLINE void
gldns_write_uint32(void * dst,uint32_t data)76 gldns_write_uint32(void *dst, uint32_t data)
77 {
78 #ifdef ALLOW_UNALIGNED_ACCESSES
79         * (uint32_t *) dst = htonl(data);
80 #else
81         uint8_t *p = (uint8_t *) dst;
82         p[0] = (uint8_t) ((data >> 24) & 0xff);
83         p[1] = (uint8_t) ((data >> 16) & 0xff);
84         p[2] = (uint8_t) ((data >> 8) & 0xff);
85         p[3] = (uint8_t) (data & 0xff);
86 #endif
87 }
88 
89 
90 INLINE void
gldns_write_uint48(void * dst,uint64_t data)91 gldns_write_uint48(void *dst, uint64_t data)
92 {
93         uint8_t *p = (uint8_t *) dst;
94         p[0] = (uint8_t) ((data >> 40) & 0xff);
95         p[1] = (uint8_t) ((data >> 32) & 0xff);
96         p[2] = (uint8_t) ((data >> 24) & 0xff);
97         p[3] = (uint8_t) ((data >> 16) & 0xff);
98         p[4] = (uint8_t) ((data >> 8) & 0xff);
99         p[5] = (uint8_t) (data & 0xff);
100 }
101 
102 
103 /**
104  * \file gbuffer.h
105  *
106  * This file contains the definition of gldns_buffer, and functions to manipulate those.
107  */
108 
109 /**
110  * implementation of buffers to ease operations
111  *
112  * gldns_buffers can contain arbitrary information, per octet. You can write
113  * to the current end of a buffer, read from the current position, and
114  * access any data within it.
115  */
116 struct gldns_buffer
117 {
118 	/** The current position used for reading/writing */
119 	size_t   _position;
120 
121 	/** The read/write limit */
122 	size_t   _limit;
123 
124 	/** The amount of data the buffer can contain */
125 	size_t   _capacity;
126 
127 	/** The data contained in the buffer */
128 	uint8_t *_data;
129 
130 	/** If the buffer is fixed it cannot be resized */
131 	unsigned _fixed : 1;
132 
133 	/** If the buffer is vfixed, no more than capacity bytes will be
134 	 * written to _data, however the _position counter will be updated
135 	 * with the amount that would have been written in consecutive
136 	 * writes.  This allows for a modus operandi in which a sequence is
137 	 * written on a fixed capacity buffer (perhaps with _data on stack).
138 	 * When everything could be written, then the _data is immediately
139 	 * usable, if not, then a buffer could be allocated sized precisely
140 	 * to fit the data for a second attempt.
141 	 */
142 	unsigned _vfixed : 1;
143 
144 	/** The current state of the buffer. If writing to the buffer fails
145 	 * for any reason, this value is changed. This way, you can perform
146 	 * multiple writes in sequence and check for success afterwards. */
147 	unsigned _status_err : 1;
148 };
149 typedef struct gldns_buffer gldns_buffer;
150 
151 #ifdef NDEBUG
152 INLINE void
gldns_buffer_invariant(gldns_buffer * ATTR_UNUSED (buffer))153 gldns_buffer_invariant(gldns_buffer *ATTR_UNUSED(buffer))
154 {
155 }
156 #else
157 INLINE void
gldns_buffer_invariant(gldns_buffer * buffer)158 gldns_buffer_invariant(gldns_buffer *buffer)
159 {
160 	assert(buffer != NULL);
161 	assert(buffer->_position <= buffer->_limit || buffer->_vfixed);
162 	assert(buffer->_limit <= buffer->_capacity);
163 	assert(buffer->_data != NULL || (buffer->_vfixed && buffer->_capacity == 0 && buffer->_limit == 0));
164 }
165 #endif
166 
167 /**
168  * creates a new buffer with the specified capacity.
169  *
170  * \param[in] capacity the size (in bytes) to allocate for the buffer
171  * \return the created buffer
172  */
173 gldns_buffer *gldns_buffer_new(size_t capacity);
174 
175 /**
176  * creates a buffer with the specified data.  The data IS copied
177  * and MEMORY allocations are done.  The buffer is not fixed and can
178  * be resized using buffer_reserve().
179  *
180  * \param[in] buffer pointer to the buffer to put the data in
181  * \param[in] data the data to encapsulate in the buffer
182  * \param[in] size the size of the data
183  */
184 void gldns_buffer_new_frm_data(gldns_buffer *buffer, void *data, size_t size);
185 
186 /**
187  * Setup a buffer with the data pointed to. No data copied, no memory allocs.
188  * The buffer is fixed.
189  * \param[in] buffer pointer to the buffer to put the data in
190  * \param[in] data the data to encapsulate in the buffer
191  * \param[in] size the size of the data
192  */
193 void gldns_buffer_init_frm_data(gldns_buffer *buffer, void *data, size_t size);
194 
195 /**
196  * Setup a buffer with the data pointed to. No data copied, no memory allocs.
197  * The buffer is "virtually" fixed.  Writes beyond size (the capacity) will
198  * only update position, but no data will be written beyond capacity.  This
199  * allows to determine how big the buffer should have been to contain all the
200  * written data, by looking at the position with gldns_buffer_position(),
201  * similarly to the return value of POSIX's snprintf.
202  * \param[in] buffer pointer to the buffer to put the data in
203  * \param[in] data the data to encapsulate in the buffer
204  * \param[in] size the size of the data
205  */
206 void gldns_buffer_init_vfixed_frm_data(gldns_buffer *buffer, void *data, size_t size);
207 
208 /**
209  * clears the buffer and make it ready for writing.  The buffer's limit
210  * is set to the capacity and the position is set to 0.
211  * \param[in] buffer the buffer to clear
212  */
gldns_buffer_clear(gldns_buffer * buffer)213 INLINE void gldns_buffer_clear(gldns_buffer *buffer)
214 {
215 	gldns_buffer_invariant(buffer);
216 
217 	/* reset status here? */
218 
219 	buffer->_position = 0;
220 	buffer->_limit = buffer->_capacity;
221 }
222 
223 /**
224  * makes the buffer ready for reading the data that has been written to
225  * the buffer.  The buffer's limit is set to the current position and
226  * the position is set to 0.
227  *
228  * \param[in] buffer the buffer to flip
229  * \return void
230  */
gldns_buffer_flip(gldns_buffer * buffer)231 INLINE void gldns_buffer_flip(gldns_buffer *buffer)
232 {
233 	gldns_buffer_invariant(buffer);
234 
235 	buffer->_limit = buffer->_position;
236 	buffer->_position = 0;
237 }
238 
239 /**
240  * make the buffer ready for re-reading the data.  The buffer's
241  * position is reset to 0.
242  * \param[in] buffer the buffer to rewind
243  */
gldns_buffer_rewind(gldns_buffer * buffer)244 INLINE void gldns_buffer_rewind(gldns_buffer *buffer)
245 {
246 	gldns_buffer_invariant(buffer);
247 
248 	buffer->_position = 0;
249 }
250 
251 /**
252  * returns the current position in the buffer (as a number of bytes)
253  * \param[in] buffer the buffer
254  * \return the current position
255  */
256 INLINE size_t
gldns_buffer_position(gldns_buffer * buffer)257 gldns_buffer_position(gldns_buffer *buffer)
258 {
259 	return buffer->_position;
260 }
261 
262 /**
263  * sets the buffer's position to MARK.  The position must be less than
264  * or equal to the buffer's limit.
265  * \param[in] buffer the buffer
266  * \param[in] mark the mark to use
267  */
268 INLINE void
gldns_buffer_set_position(gldns_buffer * buffer,size_t mark)269 gldns_buffer_set_position(gldns_buffer *buffer, size_t mark)
270 {
271 	assert(mark <= buffer->_limit || buffer->_vfixed);
272 	buffer->_position = mark;
273 }
274 
275 /**
276  * changes the buffer's position by COUNT bytes.  The position must not
277  * be moved behind the buffer's limit or before the beginning of the
278  * buffer.
279  * \param[in] buffer the buffer
280  * \param[in] count the count to use
281  */
282 INLINE void
gldns_buffer_skip(gldns_buffer * buffer,ssize_t count)283 gldns_buffer_skip(gldns_buffer *buffer, ssize_t count)
284 {
285 	assert(buffer->_position + count <= buffer->_limit || buffer->_vfixed);
286 	buffer->_position += count;
287 }
288 
289 /**
290  * returns the maximum size of the buffer
291  * \param[in] buffer
292  * \return the size
293  */
294 INLINE size_t
gldns_buffer_limit(gldns_buffer * buffer)295 gldns_buffer_limit(gldns_buffer *buffer)
296 {
297 	return buffer->_limit;
298 }
299 
300 /**
301  * changes the buffer's limit.  If the buffer's position is greater
302  * than the new limit the position is set to the limit.
303  * \param[in] buffer the buffer
304  * \param[in] limit the new limit
305  */
306 INLINE void
gldns_buffer_set_limit(gldns_buffer * buffer,size_t limit)307 gldns_buffer_set_limit(gldns_buffer *buffer, size_t limit)
308 {
309 	assert(limit <= buffer->_capacity);
310 	buffer->_limit = limit;
311 	if (buffer->_position > buffer->_limit)
312 		buffer->_position = buffer->_limit;
313 }
314 
315 /**
316  * returns the number of bytes the buffer can hold.
317  * \param[in] buffer the buffer
318  * \return the number of bytes
319  */
320 INLINE size_t
gldns_buffer_capacity(gldns_buffer * buffer)321 gldns_buffer_capacity(gldns_buffer *buffer)
322 {
323 	return buffer->_capacity;
324 }
325 
326 /**
327  * changes the buffer's capacity.  The data is reallocated so any
328  * pointers to the data may become invalid.  The buffer's limit is set
329  * to the buffer's new capacity.
330  * \param[in] buffer the buffer
331  * \param[in] capacity the capacity to use
332  * \return whether this failed or succeeded
333  */
334 int gldns_buffer_set_capacity(gldns_buffer *buffer, size_t capacity);
335 
336 /**
337  * ensures BUFFER can contain at least AMOUNT more bytes.  The buffer's
338  * capacity is increased if necessary using buffer_set_capacity().
339  *
340  * The buffer's limit is always set to the (possibly increased)
341  * capacity.
342  * \param[in] buffer the buffer
343  * \param[in] amount amount to use
344  * \return whether this failed or succeeded
345  */
346 int gldns_buffer_reserve(gldns_buffer *buffer, size_t amount);
347 
348 /**
349  * returns a pointer to the data at the indicated position.
350  * \param[in] buffer the buffer
351  * \param[in] at position
352  * \return the pointer to the data
353  */
354 INLINE uint8_t *
gldns_buffer_at(const gldns_buffer * buffer,size_t at)355 gldns_buffer_at(const gldns_buffer *buffer, size_t at)
356 {
357 	assert(at <= buffer->_limit || buffer->_vfixed);
358 	return buffer->_data + at;
359 }
360 
361 /**
362  * returns a pointer to the beginning of the buffer (the data at
363  * position 0).
364  * \param[in] buffer the buffer
365  * \return the pointer
366  */
367 INLINE uint8_t *
gldns_buffer_begin(const gldns_buffer * buffer)368 gldns_buffer_begin(const gldns_buffer *buffer)
369 {
370 	return gldns_buffer_at(buffer, 0);
371 }
372 
373 /**
374  * returns a pointer to the end of the buffer (the data at the buffer's
375  * limit).
376  * \param[in] buffer the buffer
377  * \return the pointer
378  */
379 INLINE uint8_t *
gldns_buffer_end(gldns_buffer * buffer)380 gldns_buffer_end(gldns_buffer *buffer)
381 {
382 	return gldns_buffer_at(buffer, buffer->_limit);
383 }
384 
385 /**
386  * returns a pointer to the data at the buffer's current position.
387  * \param[in] buffer the buffer
388  * \return the pointer
389  */
390 INLINE uint8_t *
gldns_buffer_current(gldns_buffer * buffer)391 gldns_buffer_current(gldns_buffer *buffer)
392 {
393 	return gldns_buffer_at(buffer, buffer->_position);
394 }
395 
396 /**
397  * returns the number of bytes remaining between the indicated position and
398  * the limit.
399  * \param[in] buffer the buffer
400  * \param[in] at indicated position
401  * \return number of bytes
402  */
403 INLINE size_t
gldns_buffer_remaining_at(gldns_buffer * buffer,size_t at)404 gldns_buffer_remaining_at(gldns_buffer *buffer, size_t at)
405 {
406 	gldns_buffer_invariant(buffer);
407 	assert(at <= buffer->_limit || buffer->_vfixed);
408 	return at < buffer->_limit ? buffer->_limit - at : 0;
409 }
410 
411 /**
412  * returns the number of bytes remaining between the buffer's position and
413  * limit.
414  * \param[in] buffer the buffer
415  * \return the number of bytes
416  */
417 INLINE size_t
gldns_buffer_remaining(gldns_buffer * buffer)418 gldns_buffer_remaining(gldns_buffer *buffer)
419 {
420 	return gldns_buffer_remaining_at(buffer, buffer->_position);
421 }
422 
423 /**
424  * checks if the buffer has at least COUNT more bytes available.
425  * Before reading or writing the caller needs to ensure enough space
426  * is available!
427  * \param[in] buffer the buffer
428  * \param[in] at indicated position
429  * \param[in] count how much is available
430  * \return true or false (as int?)
431  */
432 INLINE int
gldns_buffer_available_at(gldns_buffer * buffer,size_t at,size_t count)433 gldns_buffer_available_at(gldns_buffer *buffer, size_t at, size_t count)
434 {
435 	return count <= gldns_buffer_remaining_at(buffer, at);
436 }
437 
438 /**
439  * checks if the buffer has count bytes available at the current position
440  * \param[in] buffer the buffer
441  * \param[in] count how much is available
442  * \return true or false (as int?)
443  */
444 INLINE int
gldns_buffer_available(gldns_buffer * buffer,size_t count)445 gldns_buffer_available(gldns_buffer *buffer, size_t count)
446 {
447 	return gldns_buffer_available_at(buffer, buffer->_position, count);
448 }
449 
450 /**
451  * writes the given data to the buffer at the specified position
452  * \param[in] buffer the buffer
453  * \param[in] at the position (in number of bytes) to write the data at
454  * \param[in] data pointer to the data to write to the buffer
455  * \param[in] count the number of bytes of data to write
456  */
457 INLINE void
gldns_buffer_write_at(gldns_buffer * buffer,size_t at,const void * data,size_t count)458 gldns_buffer_write_at(gldns_buffer *buffer, size_t at, const void *data, size_t count)
459 {
460 	if (!buffer->_vfixed)
461 		assert(gldns_buffer_available_at(buffer, at, count));
462 	else if (gldns_buffer_remaining_at(buffer, at) == 0)
463 		return;
464 	else if (count > gldns_buffer_remaining_at(buffer, at)) {
465 		memcpy(buffer->_data + at, data,
466 		    gldns_buffer_remaining_at(buffer, at));
467 		return;
468 	}
469 	memcpy(buffer->_data + at, data, count);
470 }
471 
472 /**
473  * set the given byte to the buffer at the specified position
474  * \param[in] buffer the buffer
475  * \param[in] at the position (in number of bytes) to write the data at
476  * \param[in] c the byte to set to the buffer
477  * \param[in] count the number of bytes of bytes to write
478  */
479 
480 INLINE void
gldns_buffer_set_at(gldns_buffer * buffer,size_t at,int c,size_t count)481 gldns_buffer_set_at(gldns_buffer *buffer, size_t at, int c, size_t count)
482 {
483     if (!buffer->_vfixed)
484         assert(gldns_buffer_available_at(buffer, at, count));
485     else if (gldns_buffer_remaining_at(buffer, at) == 0)
486         return;
487     else if (count > gldns_buffer_remaining_at(buffer, at)) {
488         memset(buffer->_data + at, c,
489             gldns_buffer_remaining_at(buffer, at));
490         return;
491     }
492 	memset(buffer->_data + at, c, count);
493 }
494 
495 
496 /**
497  * writes count bytes of data to the current position of the buffer
498  * \param[in] buffer the buffer
499  * \param[in] data the data to write
500  * \param[in] count the length of the data to write
501  */
502 INLINE void
gldns_buffer_write(gldns_buffer * buffer,const void * data,size_t count)503 gldns_buffer_write(gldns_buffer *buffer, const void *data, size_t count)
504 {
505 	gldns_buffer_write_at(buffer, buffer->_position, data, count);
506 	buffer->_position += count;
507 }
508 
509 /**
510  * copies the given (null-delimited) string to the specified position at the buffer
511  * \param[in] buffer the buffer
512  * \param[in] at the position in the buffer
513  * \param[in] str the string to write
514  */
515 INLINE void
gldns_buffer_write_string_at(gldns_buffer * buffer,size_t at,const char * str)516 gldns_buffer_write_string_at(gldns_buffer *buffer, size_t at, const char *str)
517 {
518 	gldns_buffer_write_at(buffer, at, str, strlen(str));
519 }
520 
521 /**
522  * copies the given (null-delimited) string to the current position at the buffer
523  * \param[in] buffer the buffer
524  * \param[in] str the string to write
525  */
526 INLINE void
gldns_buffer_write_string(gldns_buffer * buffer,const char * str)527 gldns_buffer_write_string(gldns_buffer *buffer, const char *str)
528 {
529 	gldns_buffer_write(buffer, str, strlen(str));
530 }
531 
532 /**
533  * writes the given byte of data at the given position in the buffer
534  * \param[in] buffer the buffer
535  * \param[in] at the position in the buffer
536  * \param[in] data the 8 bits to write
537  */
538 INLINE void
gldns_buffer_write_u8_at(gldns_buffer * buffer,size_t at,uint8_t data)539 gldns_buffer_write_u8_at(gldns_buffer *buffer, size_t at, uint8_t data)
540 {
541 	if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return;
542 	assert(gldns_buffer_available_at(buffer, at, sizeof(data)));
543 	buffer->_data[at] = data;
544 }
545 
546 /**
547  * writes the given byte of data at the current position in the buffer
548  * \param[in] buffer the buffer
549  * \param[in] data the 8 bits to write
550  */
551 INLINE void
gldns_buffer_write_u8(gldns_buffer * buffer,uint8_t data)552 gldns_buffer_write_u8(gldns_buffer *buffer, uint8_t data)
553 {
554 	gldns_buffer_write_u8_at(buffer, buffer->_position, data);
555 	buffer->_position += sizeof(data);
556 }
557 
558 /**
559  * writes the given 2 byte integer at the given position in the buffer
560  * \param[in] buffer the buffer
561  * \param[in] at the position in the buffer
562  * \param[in] data the 16 bits to write
563  */
564 INLINE void
gldns_buffer_write_u16_at(gldns_buffer * buffer,size_t at,uint16_t data)565 gldns_buffer_write_u16_at(gldns_buffer *buffer, size_t at, uint16_t data)
566 {
567 	if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return;
568 	assert(gldns_buffer_available_at(buffer, at, sizeof(data)));
569 	gldns_write_uint16(buffer->_data + at, data);
570 }
571 
572 /**
573  * writes the given 2 byte integer at the current position in the buffer
574  * \param[in] buffer the buffer
575  * \param[in] data the 16 bits to write
576  */
577 INLINE void
gldns_buffer_write_u16(gldns_buffer * buffer,uint16_t data)578 gldns_buffer_write_u16(gldns_buffer *buffer, uint16_t data)
579 {
580 	gldns_buffer_write_u16_at(buffer, buffer->_position, data);
581 	buffer->_position += sizeof(data);
582 }
583 
584 /**
585  * writes the given 4 byte integer at the given position in the buffer
586  * \param[in] buffer the buffer
587  * \param[in] at the position in the buffer
588  * \param[in] data the 32 bits to write
589  */
590 INLINE void
gldns_buffer_write_u32_at(gldns_buffer * buffer,size_t at,uint32_t data)591 gldns_buffer_write_u32_at(gldns_buffer *buffer, size_t at, uint32_t data)
592 {
593 	if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return;
594 	assert(gldns_buffer_available_at(buffer, at, sizeof(data)));
595 	gldns_write_uint32(buffer->_data + at, data);
596 }
597 
598 /**
599  * writes the given 6 byte integer at the given position in the buffer
600  * \param[in] buffer the buffer
601  * \param[in] at the position in the buffer
602  * \param[in] data the (lower) 48 bits to write
603  */
604 INLINE void
gldns_buffer_write_u48_at(gldns_buffer * buffer,size_t at,uint64_t data)605 gldns_buffer_write_u48_at(gldns_buffer *buffer, size_t at, uint64_t data)
606 {
607 	if (buffer->_vfixed && at + 6 > buffer->_limit) return;
608 	assert(gldns_buffer_available_at(buffer, at, 6));
609 	gldns_write_uint48(buffer->_data + at, data);
610 }
611 
612 /**
613  * writes the given 4 byte integer at the current position in the buffer
614  * \param[in] buffer the buffer
615  * \param[in] data the 32 bits to write
616  */
617 INLINE void
gldns_buffer_write_u32(gldns_buffer * buffer,uint32_t data)618 gldns_buffer_write_u32(gldns_buffer *buffer, uint32_t data)
619 {
620 	gldns_buffer_write_u32_at(buffer, buffer->_position, data);
621 	buffer->_position += sizeof(data);
622 }
623 
624 /**
625  * writes the given 6 byte integer at the current position in the buffer
626  * \param[in] buffer the buffer
627  * \param[in] data the 48 bits to write
628  */
629 INLINE void
gldns_buffer_write_u48(gldns_buffer * buffer,uint64_t data)630 gldns_buffer_write_u48(gldns_buffer *buffer, uint64_t data)
631 {
632 	gldns_buffer_write_u48_at(buffer, buffer->_position, data);
633 	buffer->_position += 6;
634 }
635 
636 /**
637  * copies count bytes of data at the given position to the given data-array
638  * \param[in] buffer the buffer
639  * \param[in] at the position in the buffer to start
640  * \param[out] data buffer to copy to
641  * \param[in] count the length of the data to copy
642  */
643 INLINE void
gldns_buffer_read_at(gldns_buffer * buffer,size_t at,void * data,size_t count)644 gldns_buffer_read_at(gldns_buffer *buffer, size_t at, void *data, size_t count)
645 {
646 	assert(gldns_buffer_available_at(buffer, at, count));
647 	memcpy(data, buffer->_data + at, count);
648 }
649 
650 /**
651  * copies count bytes of data at the current position to the given data-array
652  * \param[in] buffer the buffer
653  * \param[out] data buffer to copy to
654  * \param[in] count the length of the data to copy
655  */
656 INLINE void
gldns_buffer_read(gldns_buffer * buffer,void * data,size_t count)657 gldns_buffer_read(gldns_buffer *buffer, void *data, size_t count)
658 {
659 	gldns_buffer_read_at(buffer, buffer->_position, data, count);
660 	buffer->_position += count;
661 }
662 
663 /**
664  * returns the byte value at the given position in the buffer
665  * \param[in] buffer the buffer
666  * \param[in] at the position in the buffer
667  * \return 1 byte integer
668  */
669 INLINE uint8_t
gldns_buffer_read_u8_at(gldns_buffer * buffer,size_t at)670 gldns_buffer_read_u8_at(gldns_buffer *buffer, size_t at)
671 {
672 	assert(gldns_buffer_available_at(buffer, at, sizeof(uint8_t)));
673 	return buffer->_data[at];
674 }
675 
676 /**
677  * returns the byte value at the current position in the buffer
678  * \param[in] buffer the buffer
679  * \return 1 byte integer
680  */
681 INLINE uint8_t
gldns_buffer_read_u8(gldns_buffer * buffer)682 gldns_buffer_read_u8(gldns_buffer *buffer)
683 {
684 	uint8_t result = gldns_buffer_read_u8_at(buffer, buffer->_position);
685 	buffer->_position += sizeof(uint8_t);
686 	return result;
687 }
688 
689 /**
690  * returns the 2-byte integer value at the given position in the buffer
691  * \param[in] buffer the buffer
692  * \param[in] at position in the buffer
693  * \return 2 byte integer
694  */
695 INLINE uint16_t
gldns_buffer_read_u16_at(gldns_buffer * buffer,size_t at)696 gldns_buffer_read_u16_at(gldns_buffer *buffer, size_t at)
697 {
698 	assert(gldns_buffer_available_at(buffer, at, sizeof(uint16_t)));
699 	return gldns_read_uint16(buffer->_data + at);
700 }
701 
702 /**
703  * returns the 2-byte integer value at the current position in the buffer
704  * \param[in] buffer the buffer
705  * \return 2 byte integer
706  */
707 INLINE uint16_t
gldns_buffer_read_u16(gldns_buffer * buffer)708 gldns_buffer_read_u16(gldns_buffer *buffer)
709 {
710 	uint16_t result = gldns_buffer_read_u16_at(buffer, buffer->_position);
711 	buffer->_position += sizeof(uint16_t);
712 	return result;
713 }
714 
715 /**
716  * returns the 4-byte integer value at the given position in the buffer
717  * \param[in] buffer the buffer
718  * \param[in] at position in the buffer
719  * \return 4 byte integer
720  */
721 INLINE uint32_t
gldns_buffer_read_u32_at(gldns_buffer * buffer,size_t at)722 gldns_buffer_read_u32_at(gldns_buffer *buffer, size_t at)
723 {
724 	assert(gldns_buffer_available_at(buffer, at, sizeof(uint32_t)));
725 	return gldns_read_uint32(buffer->_data + at);
726 }
727 
728 /**
729  * returns the 4-byte integer value at the current position in the buffer
730  * \param[in] buffer the buffer
731  * \return 4 byte integer
732  */
733 INLINE uint32_t
gldns_buffer_read_u32(gldns_buffer * buffer)734 gldns_buffer_read_u32(gldns_buffer *buffer)
735 {
736 	uint32_t result = gldns_buffer_read_u32_at(buffer, buffer->_position);
737 	buffer->_position += sizeof(uint32_t);
738 	return result;
739 }
740 
741 /**
742  * returns the status of the buffer
743  * \param[in] buffer
744  * \return the status
745  */
746 INLINE int
gldns_buffer_status(gldns_buffer * buffer)747 gldns_buffer_status(gldns_buffer *buffer)
748 {
749 	return (int)buffer->_status_err;
750 }
751 
752 /**
753  * returns true if the status of the buffer is GLDNS_STATUS_OK, false otherwise
754  * \param[in] buffer the buffer
755  * \return true or false
756  */
757 INLINE int
gldns_buffer_status_ok(gldns_buffer * buffer)758 gldns_buffer_status_ok(gldns_buffer *buffer)
759 {
760 	if (buffer) {
761 		return gldns_buffer_status(buffer) == 0;
762 	} else {
763 		return 0;
764 	}
765 }
766 
767 /**
768  * prints to the buffer, increasing the capacity if required using
769  * buffer_reserve(). The buffer's position is set to the terminating '\\0'
770  * Returns the number of characters written (not including the
771  * terminating '\\0') or -1 on failure.
772  */
773 int gldns_buffer_printf(gldns_buffer *buffer, const char *format, ...)
774 	ATTR_FORMAT(printf, 2, 3);
775 
776 /**
777  * frees the buffer.
778  * \param[in] *buffer the buffer to be freed
779  * \return void
780  */
781 void gldns_buffer_free(gldns_buffer *buffer);
782 
783 /**
784  * Makes the buffer fixed and returns a pointer to the data.  The
785  * caller is responsible for free'ing the result.
786  * \param[in] *buffer the buffer to be exported
787  * \return void
788  */
789 void *gldns_buffer_export(gldns_buffer *buffer);
790 
791 /**
792  * Copy contents of the from buffer to the result buffer and then flips
793  * the result buffer. Data will be silently truncated if the result buffer is
794  * too small.
795  * \param[out] *result resulting buffer which is copied to.
796  * \param[in] *from what to copy to result.
797  */
798 void gldns_buffer_copy(gldns_buffer* result, gldns_buffer* from);
799 
800 #ifdef __cplusplus
801 }
802 #endif
803 
804 #endif /* GLDNS_SBUFFER_H */
805