xref: /freebsd/contrib/unbound/sldns/sbuffer.c (revision 0957b409)
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  * \file
11  *
12  * This file contains the definition of sldns_buffer, and functions to manipulate those.
13  */
14 #include "config.h"
15 #include "sldns/sbuffer.h"
16 #include <stdarg.h>
17 
18 sldns_buffer *
19 sldns_buffer_new(size_t capacity)
20 {
21 	sldns_buffer *buffer = (sldns_buffer*)malloc(sizeof(sldns_buffer));
22 
23 	if (!buffer) {
24 		return NULL;
25 	}
26 
27 	buffer->_data = (uint8_t *) malloc(capacity);
28 	if (!buffer->_data) {
29 		free(buffer);
30 		return NULL;
31 	}
32 
33 	buffer->_position = 0;
34 	buffer->_limit = buffer->_capacity = capacity;
35 	buffer->_fixed = 0;
36 	buffer->_vfixed = 0;
37 	buffer->_status_err = 0;
38 
39 	sldns_buffer_invariant(buffer);
40 
41 	return buffer;
42 }
43 
44 void
45 sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size)
46 {
47 	assert(data != NULL);
48 
49 	buffer->_position = 0;
50 	buffer->_limit = buffer->_capacity = size;
51 	buffer->_fixed = 0;
52 	buffer->_vfixed = 0;
53 	if (!buffer->_fixed && buffer->_data)
54 		free(buffer->_data);
55 	buffer->_data = malloc(size);
56 	if(!buffer->_data) {
57 		buffer->_status_err = 1;
58 		return;
59 	}
60 	memcpy(buffer->_data, data, size);
61 	buffer->_status_err = 0;
62 
63 	sldns_buffer_invariant(buffer);
64 }
65 
66 void
67 sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size)
68 {
69 	memset(buffer, 0, sizeof(*buffer));
70 	buffer->_data = data;
71 	buffer->_capacity = buffer->_limit = size;
72 	buffer->_fixed = 1;
73 	buffer->_vfixed = 0;
74 }
75 
76 void
77 sldns_buffer_init_vfixed_frm_data(sldns_buffer *buffer, void *data, size_t size)
78 {
79 	memset(buffer, 0, sizeof(*buffer));
80 	buffer->_data = data;
81 	buffer->_capacity = buffer->_limit = size;
82 	buffer->_fixed = 1;
83 	buffer->_vfixed = 1;
84 }
85 
86 int
87 sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity)
88 {
89 	void *data;
90 
91 	sldns_buffer_invariant(buffer);
92 	assert(buffer->_position <= capacity && !buffer->_fixed);
93 
94 	data = (uint8_t *) realloc(buffer->_data, capacity);
95 	if (!data) {
96 		buffer->_status_err = 1;
97 		return 0;
98 	} else {
99 		buffer->_data = data;
100 		buffer->_limit = buffer->_capacity = capacity;
101 		return 1;
102 	}
103 }
104 
105 int
106 sldns_buffer_reserve(sldns_buffer *buffer, size_t amount)
107 {
108 	sldns_buffer_invariant(buffer);
109 	assert(!buffer->_fixed);
110 	if (buffer->_capacity < buffer->_position + amount) {
111 		size_t new_capacity = buffer->_capacity * 3 / 2;
112 
113 		if (new_capacity < buffer->_position + amount) {
114 			new_capacity = buffer->_position + amount;
115 		}
116 		if (!sldns_buffer_set_capacity(buffer, new_capacity)) {
117 			buffer->_status_err = 1;
118 			return 0;
119 		}
120 	}
121 	buffer->_limit = buffer->_capacity;
122 	return 1;
123 }
124 
125 int
126 sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
127 {
128 	va_list args;
129 	int written = 0;
130 	size_t remaining;
131 
132 	if (sldns_buffer_status_ok(buffer)) {
133 		sldns_buffer_invariant(buffer);
134 		assert(buffer->_limit == buffer->_capacity);
135 
136 		remaining = sldns_buffer_remaining(buffer);
137 		va_start(args, format);
138 		written = vsnprintf((char *) sldns_buffer_current(buffer), remaining,
139 				    format, args);
140 		va_end(args);
141 		if (written == -1) {
142 			buffer->_status_err = 1;
143 			return -1;
144 		} else if (!buffer->_vfixed && (size_t) written >= remaining) {
145 			if (!sldns_buffer_reserve(buffer, (size_t) written + 1)) {
146 				buffer->_status_err = 1;
147 				return -1;
148 			}
149 			va_start(args, format);
150 			written = vsnprintf((char *) sldns_buffer_current(buffer),
151 			    sldns_buffer_remaining(buffer), format, args);
152 			va_end(args);
153 			if (written == -1) {
154 				buffer->_status_err = 1;
155 				return -1;
156 			}
157 		}
158 		buffer->_position += written;
159 	}
160 	return written;
161 }
162 
163 void
164 sldns_buffer_free(sldns_buffer *buffer)
165 {
166 	if (!buffer) {
167 		return;
168 	}
169 
170 	if (!buffer->_fixed)
171 		free(buffer->_data);
172 
173 	free(buffer);
174 }
175 
176 void *
177 sldns_buffer_export(sldns_buffer *buffer)
178 {
179 	buffer->_fixed = 1;
180 	return buffer->_data;
181 }
182 
183 void
184 sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from)
185 {
186 	size_t tocopy = sldns_buffer_limit(from);
187 
188 	if(tocopy > sldns_buffer_capacity(result))
189 		tocopy = sldns_buffer_capacity(result);
190 	sldns_buffer_clear(result);
191 	sldns_buffer_write(result, sldns_buffer_begin(from), tocopy);
192 	sldns_buffer_flip(result);
193 }
194