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