xref: /freebsd/contrib/ldns/buffer.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
1 /*
2  * buffer.c -- generic memory buffer .
3  *
4  * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include <ldns/config.h>
11 
12 #include <ldns/ldns.h>
13 #include <ldns/buffer.h>
14 
15 ldns_buffer *
ldns_buffer_new(size_t capacity)16 ldns_buffer_new(size_t capacity)
17 {
18 	ldns_buffer *buffer = LDNS_MALLOC(ldns_buffer);
19 
20 	if (!buffer) {
21 		return NULL;
22 	}
23 
24 	buffer->_data = (uint8_t *) LDNS_XMALLOC(uint8_t, capacity);
25 	if (!buffer->_data) {
26 		LDNS_FREE(buffer);
27 		return NULL;
28 	}
29 
30 	buffer->_position = 0;
31 	buffer->_limit = buffer->_capacity = capacity;
32 	buffer->_fixed = 0;
33 	buffer->_status = LDNS_STATUS_OK;
34 
35 	ldns_buffer_invariant(buffer);
36 
37 	return buffer;
38 }
39 
40 void
ldns_buffer_new_frm_data(ldns_buffer * buffer,const void * data,size_t size)41 ldns_buffer_new_frm_data(ldns_buffer *buffer, const void *data, size_t size)
42 {
43 	assert(data != NULL);
44 
45 	buffer->_position = 0;
46 	buffer->_limit = buffer->_capacity = size;
47 	buffer->_fixed = 0;
48 	buffer->_data = LDNS_XMALLOC(uint8_t, size);
49 	if(!buffer->_data) {
50 		buffer->_status = LDNS_STATUS_MEM_ERR;
51 		return;
52 	}
53 	memcpy(buffer->_data, data, size);
54 	buffer->_status = LDNS_STATUS_OK;
55 
56 	ldns_buffer_invariant(buffer);
57 }
58 
59 bool
ldns_buffer_set_capacity(ldns_buffer * buffer,size_t capacity)60 ldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity)
61 {
62 	void *data;
63 
64 	ldns_buffer_invariant(buffer);
65 	assert(buffer->_position <= capacity);
66 	assert(!buffer->_fixed);
67 
68 	data = (uint8_t *) LDNS_XREALLOC(buffer->_data, uint8_t, capacity);
69 	if (!data) {
70 		buffer->_status = LDNS_STATUS_MEM_ERR;
71 		return false;
72 	} else {
73 		buffer->_data = data;
74 		buffer->_limit = buffer->_capacity = capacity;
75 		return true;
76 	}
77 }
78 
79 bool
ldns_buffer_reserve(ldns_buffer * buffer,size_t amount)80 ldns_buffer_reserve(ldns_buffer *buffer, size_t amount)
81 {
82 	ldns_buffer_invariant(buffer);
83 	if (buffer->_capacity < buffer->_position + amount) {
84 		size_t new_capacity = buffer->_capacity * 3 / 2;
85 
86 		if (new_capacity < buffer->_position + amount) {
87 			new_capacity = buffer->_position + amount;
88 		}
89 		if (!ldns_buffer_set_capacity(buffer, new_capacity)) {
90 			buffer->_status = LDNS_STATUS_MEM_ERR;
91 			return false;
92 		}
93 	}
94 	buffer->_limit = buffer->_capacity;
95 	return true;
96 }
97 
98 int
ldns_buffer_printf(ldns_buffer * buffer,const char * format,...)99 ldns_buffer_printf(ldns_buffer *buffer, const char *format, ...)
100 {
101 	va_list args;
102 	int written = 0;
103 	size_t remaining;
104 
105 	if (ldns_buffer_status_ok(buffer)) {
106 		ldns_buffer_invariant(buffer);
107 		assert(buffer->_limit == buffer->_capacity);
108 
109 		remaining = ldns_buffer_remaining(buffer);
110 		va_start(args, format);
111 		written = vsnprintf((char *) ldns_buffer_current(buffer), remaining,
112 				    format, args);
113 		va_end(args);
114 		if (written == -1) {
115 			buffer->_status = LDNS_STATUS_INTERNAL_ERR;
116 			return -1;
117 		} else if ((size_t) written >= remaining) {
118 			if (!ldns_buffer_reserve(buffer, (size_t) written + 1)) {
119 				buffer->_status = LDNS_STATUS_MEM_ERR;
120 				return -1;
121 			}
122 			va_start(args, format);
123 			written = vsnprintf((char *) ldns_buffer_current(buffer),
124 			    ldns_buffer_remaining(buffer), format, args);
125 			va_end(args);
126 			if (written == -1) {
127 				buffer->_status = LDNS_STATUS_INTERNAL_ERR;
128 				return -1;
129 			}
130 		}
131 		buffer->_position += written;
132 	}
133 	return written;
134 }
135 
136 void
ldns_buffer_free(ldns_buffer * buffer)137 ldns_buffer_free(ldns_buffer *buffer)
138 {
139 	if (!buffer) {
140 		return;
141 	}
142 
143 	if (!buffer->_fixed)
144 		LDNS_FREE(buffer->_data);
145 
146 	LDNS_FREE(buffer);
147 }
148 
149 void *
ldns_buffer_export(ldns_buffer * buffer)150 ldns_buffer_export(ldns_buffer *buffer)
151 {
152 	buffer->_fixed = 1;
153 	return buffer->_data;
154 }
155 
156 int
ldns_bgetc(ldns_buffer * buffer)157 ldns_bgetc(ldns_buffer *buffer)
158 {
159 	if (!ldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) {
160 		ldns_buffer_set_position(buffer, ldns_buffer_limit(buffer));
161 		/* ldns_buffer_rewind(buffer);*/
162 		return EOF;
163 	}
164 	return (int)ldns_buffer_read_u8(buffer);
165 }
166 
167 void
ldns_buffer_copy(ldns_buffer * result,const ldns_buffer * from)168 ldns_buffer_copy(ldns_buffer* result, const ldns_buffer* from)
169 {
170 	size_t tocopy = ldns_buffer_limit(from);
171 
172 	if(tocopy > ldns_buffer_capacity(result))
173 		tocopy = ldns_buffer_capacity(result);
174 	ldns_buffer_clear(result);
175 	ldns_buffer_write(result, ldns_buffer_begin(from), tocopy);
176 	ldns_buffer_flip(result);
177 }
178