xref: /freebsd/contrib/ldns/buffer.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * buffer.c -- generic memory buffer .
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
57b5038d7SDag-Erling Smørgrav  *
67b5038d7SDag-Erling Smørgrav  * See LICENSE for the license.
77b5038d7SDag-Erling Smørgrav  *
87b5038d7SDag-Erling Smørgrav  */
97b5038d7SDag-Erling Smørgrav 
107b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
117b5038d7SDag-Erling Smørgrav 
127b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
137b5038d7SDag-Erling Smørgrav #include <ldns/buffer.h>
147b5038d7SDag-Erling Smørgrav 
157b5038d7SDag-Erling Smørgrav ldns_buffer *
ldns_buffer_new(size_t capacity)167b5038d7SDag-Erling Smørgrav ldns_buffer_new(size_t capacity)
177b5038d7SDag-Erling Smørgrav {
187b5038d7SDag-Erling Smørgrav 	ldns_buffer *buffer = LDNS_MALLOC(ldns_buffer);
197b5038d7SDag-Erling Smørgrav 
207b5038d7SDag-Erling Smørgrav 	if (!buffer) {
217b5038d7SDag-Erling Smørgrav 		return NULL;
227b5038d7SDag-Erling Smørgrav 	}
237b5038d7SDag-Erling Smørgrav 
247b5038d7SDag-Erling Smørgrav 	buffer->_data = (uint8_t *) LDNS_XMALLOC(uint8_t, capacity);
257b5038d7SDag-Erling Smørgrav 	if (!buffer->_data) {
267b5038d7SDag-Erling Smørgrav 		LDNS_FREE(buffer);
277b5038d7SDag-Erling Smørgrav 		return NULL;
287b5038d7SDag-Erling Smørgrav 	}
297b5038d7SDag-Erling Smørgrav 
307b5038d7SDag-Erling Smørgrav 	buffer->_position = 0;
317b5038d7SDag-Erling Smørgrav 	buffer->_limit = buffer->_capacity = capacity;
327b5038d7SDag-Erling Smørgrav 	buffer->_fixed = 0;
337b5038d7SDag-Erling Smørgrav 	buffer->_status = LDNS_STATUS_OK;
347b5038d7SDag-Erling Smørgrav 
357b5038d7SDag-Erling Smørgrav 	ldns_buffer_invariant(buffer);
367b5038d7SDag-Erling Smørgrav 
377b5038d7SDag-Erling Smørgrav 	return buffer;
387b5038d7SDag-Erling Smørgrav }
397b5038d7SDag-Erling Smørgrav 
407b5038d7SDag-Erling Smørgrav void
ldns_buffer_new_frm_data(ldns_buffer * buffer,const void * data,size_t size)41986ba33cSDag-Erling Smørgrav ldns_buffer_new_frm_data(ldns_buffer *buffer, const void *data, size_t size)
427b5038d7SDag-Erling Smørgrav {
437b5038d7SDag-Erling Smørgrav 	assert(data != NULL);
447b5038d7SDag-Erling Smørgrav 
457b5038d7SDag-Erling Smørgrav 	buffer->_position = 0;
467b5038d7SDag-Erling Smørgrav 	buffer->_limit = buffer->_capacity = size;
477b5038d7SDag-Erling Smørgrav 	buffer->_fixed = 0;
487b5038d7SDag-Erling Smørgrav 	buffer->_data = LDNS_XMALLOC(uint8_t, size);
497b5038d7SDag-Erling Smørgrav 	if(!buffer->_data) {
507b5038d7SDag-Erling Smørgrav 		buffer->_status = LDNS_STATUS_MEM_ERR;
517b5038d7SDag-Erling Smørgrav 		return;
527b5038d7SDag-Erling Smørgrav 	}
537b5038d7SDag-Erling Smørgrav 	memcpy(buffer->_data, data, size);
547b5038d7SDag-Erling Smørgrav 	buffer->_status = LDNS_STATUS_OK;
557b5038d7SDag-Erling Smørgrav 
567b5038d7SDag-Erling Smørgrav 	ldns_buffer_invariant(buffer);
577b5038d7SDag-Erling Smørgrav }
587b5038d7SDag-Erling Smørgrav 
597b5038d7SDag-Erling Smørgrav bool
ldns_buffer_set_capacity(ldns_buffer * buffer,size_t capacity)607b5038d7SDag-Erling Smørgrav ldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity)
617b5038d7SDag-Erling Smørgrav {
627b5038d7SDag-Erling Smørgrav 	void *data;
637b5038d7SDag-Erling Smørgrav 
647b5038d7SDag-Erling Smørgrav 	ldns_buffer_invariant(buffer);
657b5038d7SDag-Erling Smørgrav 	assert(buffer->_position <= capacity);
66*5afab0e5SDag-Erling Smørgrav 	assert(!buffer->_fixed);
677b5038d7SDag-Erling Smørgrav 
687b5038d7SDag-Erling Smørgrav 	data = (uint8_t *) LDNS_XREALLOC(buffer->_data, uint8_t, capacity);
697b5038d7SDag-Erling Smørgrav 	if (!data) {
707b5038d7SDag-Erling Smørgrav 		buffer->_status = LDNS_STATUS_MEM_ERR;
717b5038d7SDag-Erling Smørgrav 		return false;
727b5038d7SDag-Erling Smørgrav 	} else {
737b5038d7SDag-Erling Smørgrav 		buffer->_data = data;
747b5038d7SDag-Erling Smørgrav 		buffer->_limit = buffer->_capacity = capacity;
757b5038d7SDag-Erling Smørgrav 		return true;
767b5038d7SDag-Erling Smørgrav 	}
777b5038d7SDag-Erling Smørgrav }
787b5038d7SDag-Erling Smørgrav 
797b5038d7SDag-Erling Smørgrav bool
ldns_buffer_reserve(ldns_buffer * buffer,size_t amount)807b5038d7SDag-Erling Smørgrav ldns_buffer_reserve(ldns_buffer *buffer, size_t amount)
817b5038d7SDag-Erling Smørgrav {
827b5038d7SDag-Erling Smørgrav 	ldns_buffer_invariant(buffer);
837b5038d7SDag-Erling Smørgrav 	if (buffer->_capacity < buffer->_position + amount) {
847b5038d7SDag-Erling Smørgrav 		size_t new_capacity = buffer->_capacity * 3 / 2;
857b5038d7SDag-Erling Smørgrav 
867b5038d7SDag-Erling Smørgrav 		if (new_capacity < buffer->_position + amount) {
877b5038d7SDag-Erling Smørgrav 			new_capacity = buffer->_position + amount;
887b5038d7SDag-Erling Smørgrav 		}
897b5038d7SDag-Erling Smørgrav 		if (!ldns_buffer_set_capacity(buffer, new_capacity)) {
907b5038d7SDag-Erling Smørgrav 			buffer->_status = LDNS_STATUS_MEM_ERR;
917b5038d7SDag-Erling Smørgrav 			return false;
927b5038d7SDag-Erling Smørgrav 		}
937b5038d7SDag-Erling Smørgrav 	}
947b5038d7SDag-Erling Smørgrav 	buffer->_limit = buffer->_capacity;
957b5038d7SDag-Erling Smørgrav 	return true;
967b5038d7SDag-Erling Smørgrav }
977b5038d7SDag-Erling Smørgrav 
987b5038d7SDag-Erling Smørgrav int
ldns_buffer_printf(ldns_buffer * buffer,const char * format,...)997b5038d7SDag-Erling Smørgrav ldns_buffer_printf(ldns_buffer *buffer, const char *format, ...)
1007b5038d7SDag-Erling Smørgrav {
1017b5038d7SDag-Erling Smørgrav 	va_list args;
1027b5038d7SDag-Erling Smørgrav 	int written = 0;
1037b5038d7SDag-Erling Smørgrav 	size_t remaining;
1047b5038d7SDag-Erling Smørgrav 
1057b5038d7SDag-Erling Smørgrav 	if (ldns_buffer_status_ok(buffer)) {
1067b5038d7SDag-Erling Smørgrav 		ldns_buffer_invariant(buffer);
1077b5038d7SDag-Erling Smørgrav 		assert(buffer->_limit == buffer->_capacity);
1087b5038d7SDag-Erling Smørgrav 
1097b5038d7SDag-Erling Smørgrav 		remaining = ldns_buffer_remaining(buffer);
1107b5038d7SDag-Erling Smørgrav 		va_start(args, format);
1117b5038d7SDag-Erling Smørgrav 		written = vsnprintf((char *) ldns_buffer_current(buffer), remaining,
1127b5038d7SDag-Erling Smørgrav 				    format, args);
1137b5038d7SDag-Erling Smørgrav 		va_end(args);
1147b5038d7SDag-Erling Smørgrav 		if (written == -1) {
1157b5038d7SDag-Erling Smørgrav 			buffer->_status = LDNS_STATUS_INTERNAL_ERR;
1167b5038d7SDag-Erling Smørgrav 			return -1;
1177b5038d7SDag-Erling Smørgrav 		} else if ((size_t) written >= remaining) {
1187b5038d7SDag-Erling Smørgrav 			if (!ldns_buffer_reserve(buffer, (size_t) written + 1)) {
1197b5038d7SDag-Erling Smørgrav 				buffer->_status = LDNS_STATUS_MEM_ERR;
1207b5038d7SDag-Erling Smørgrav 				return -1;
1217b5038d7SDag-Erling Smørgrav 			}
1227b5038d7SDag-Erling Smørgrav 			va_start(args, format);
1237b5038d7SDag-Erling Smørgrav 			written = vsnprintf((char *) ldns_buffer_current(buffer),
1247b5038d7SDag-Erling Smørgrav 			    ldns_buffer_remaining(buffer), format, args);
1257b5038d7SDag-Erling Smørgrav 			va_end(args);
1267b5038d7SDag-Erling Smørgrav 			if (written == -1) {
1277b5038d7SDag-Erling Smørgrav 				buffer->_status = LDNS_STATUS_INTERNAL_ERR;
1287b5038d7SDag-Erling Smørgrav 				return -1;
1297b5038d7SDag-Erling Smørgrav 			}
1307b5038d7SDag-Erling Smørgrav 		}
1317b5038d7SDag-Erling Smørgrav 		buffer->_position += written;
1327b5038d7SDag-Erling Smørgrav 	}
1337b5038d7SDag-Erling Smørgrav 	return written;
1347b5038d7SDag-Erling Smørgrav }
1357b5038d7SDag-Erling Smørgrav 
1367b5038d7SDag-Erling Smørgrav void
ldns_buffer_free(ldns_buffer * buffer)1377b5038d7SDag-Erling Smørgrav ldns_buffer_free(ldns_buffer *buffer)
1387b5038d7SDag-Erling Smørgrav {
1397b5038d7SDag-Erling Smørgrav 	if (!buffer) {
1407b5038d7SDag-Erling Smørgrav 		return;
1417b5038d7SDag-Erling Smørgrav 	}
1427b5038d7SDag-Erling Smørgrav 
1432787e39aSDag-Erling Smørgrav 	if (!buffer->_fixed)
1447b5038d7SDag-Erling Smørgrav 		LDNS_FREE(buffer->_data);
1457b5038d7SDag-Erling Smørgrav 
1467b5038d7SDag-Erling Smørgrav 	LDNS_FREE(buffer);
1477b5038d7SDag-Erling Smørgrav }
1487b5038d7SDag-Erling Smørgrav 
1497b5038d7SDag-Erling Smørgrav void *
ldns_buffer_export(ldns_buffer * buffer)1507b5038d7SDag-Erling Smørgrav ldns_buffer_export(ldns_buffer *buffer)
1517b5038d7SDag-Erling Smørgrav {
1527b5038d7SDag-Erling Smørgrav 	buffer->_fixed = 1;
1537b5038d7SDag-Erling Smørgrav 	return buffer->_data;
1547b5038d7SDag-Erling Smørgrav }
1557b5038d7SDag-Erling Smørgrav 
1567b5038d7SDag-Erling Smørgrav int
ldns_bgetc(ldns_buffer * buffer)1577b5038d7SDag-Erling Smørgrav ldns_bgetc(ldns_buffer *buffer)
1587b5038d7SDag-Erling Smørgrav {
1597b5038d7SDag-Erling Smørgrav 	if (!ldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) {
1607b5038d7SDag-Erling Smørgrav 		ldns_buffer_set_position(buffer, ldns_buffer_limit(buffer));
1617b5038d7SDag-Erling Smørgrav 		/* ldns_buffer_rewind(buffer);*/
1627b5038d7SDag-Erling Smørgrav 		return EOF;
1637b5038d7SDag-Erling Smørgrav 	}
1647b5038d7SDag-Erling Smørgrav 	return (int)ldns_buffer_read_u8(buffer);
1657b5038d7SDag-Erling Smørgrav }
1667b5038d7SDag-Erling Smørgrav 
1677b5038d7SDag-Erling Smørgrav void
ldns_buffer_copy(ldns_buffer * result,const ldns_buffer * from)168986ba33cSDag-Erling Smørgrav ldns_buffer_copy(ldns_buffer* result, const ldns_buffer* from)
1697b5038d7SDag-Erling Smørgrav {
1707b5038d7SDag-Erling Smørgrav 	size_t tocopy = ldns_buffer_limit(from);
1717b5038d7SDag-Erling Smørgrav 
1727b5038d7SDag-Erling Smørgrav 	if(tocopy > ldns_buffer_capacity(result))
1737b5038d7SDag-Erling Smørgrav 		tocopy = ldns_buffer_capacity(result);
1747b5038d7SDag-Erling Smørgrav 	ldns_buffer_clear(result);
1757b5038d7SDag-Erling Smørgrav 	ldns_buffer_write(result, ldns_buffer_begin(from), tocopy);
1767b5038d7SDag-Erling Smørgrav 	ldns_buffer_flip(result);
1777b5038d7SDag-Erling Smørgrav }
178