xref: /freebsd/contrib/unbound/sldns/sbuffer.c (revision a0ee8cc6)
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->_status_err = 0;
37 
38 	sldns_buffer_invariant(buffer);
39 
40 	return buffer;
41 }
42 
43 void
44 sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size)
45 {
46 	assert(data != NULL);
47 
48 	buffer->_position = 0;
49 	buffer->_limit = buffer->_capacity = size;
50 	buffer->_fixed = 0;
51 	buffer->_data = malloc(size);
52 	if(!buffer->_data) {
53 		buffer->_status_err = 1;
54 		return;
55 	}
56 	memcpy(buffer->_data, data, size);
57 	buffer->_status_err = 0;
58 
59 	sldns_buffer_invariant(buffer);
60 }
61 
62 void
63 sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size)
64 {
65 	memset(buffer, 0, sizeof(*buffer));
66 	buffer->_data = data;
67 	buffer->_capacity = buffer->_limit = size;
68 	buffer->_fixed = 1;
69 }
70 
71 int
72 sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity)
73 {
74 	void *data;
75 
76 	sldns_buffer_invariant(buffer);
77 	assert(buffer->_position <= capacity);
78 
79 	data = (uint8_t *) realloc(buffer->_data, capacity);
80 	if (!data) {
81 		buffer->_status_err = 1;
82 		return 0;
83 	} else {
84 		buffer->_data = data;
85 		buffer->_limit = buffer->_capacity = capacity;
86 		return 1;
87 	}
88 }
89 
90 int
91 sldns_buffer_reserve(sldns_buffer *buffer, size_t amount)
92 {
93 	sldns_buffer_invariant(buffer);
94 	assert(!buffer->_fixed);
95 	if (buffer->_capacity < buffer->_position + amount) {
96 		size_t new_capacity = buffer->_capacity * 3 / 2;
97 
98 		if (new_capacity < buffer->_position + amount) {
99 			new_capacity = buffer->_position + amount;
100 		}
101 		if (!sldns_buffer_set_capacity(buffer, new_capacity)) {
102 			buffer->_status_err = 1;
103 			return 0;
104 		}
105 	}
106 	buffer->_limit = buffer->_capacity;
107 	return 1;
108 }
109 
110 int
111 sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
112 {
113 	va_list args;
114 	int written = 0;
115 	size_t remaining;
116 
117 	if (sldns_buffer_status_ok(buffer)) {
118 		sldns_buffer_invariant(buffer);
119 		assert(buffer->_limit == buffer->_capacity);
120 
121 		remaining = sldns_buffer_remaining(buffer);
122 		va_start(args, format);
123 		written = vsnprintf((char *) sldns_buffer_current(buffer), remaining,
124 				    format, args);
125 		va_end(args);
126 		if (written == -1) {
127 			buffer->_status_err = 1;
128 			return -1;
129 		} else if ((size_t) written >= remaining) {
130 			if (!sldns_buffer_reserve(buffer, (size_t) written + 1)) {
131 				buffer->_status_err = 1;
132 				return -1;
133 			}
134 			va_start(args, format);
135 			written = vsnprintf((char *) sldns_buffer_current(buffer),
136 			    sldns_buffer_remaining(buffer), format, args);
137 			va_end(args);
138 			if (written == -1) {
139 				buffer->_status_err = 1;
140 				return -1;
141 			}
142 		}
143 		buffer->_position += written;
144 	}
145 	return written;
146 }
147 
148 void
149 sldns_buffer_free(sldns_buffer *buffer)
150 {
151 	if (!buffer) {
152 		return;
153 	}
154 
155 	if (!buffer->_fixed)
156 		free(buffer->_data);
157 
158 	free(buffer);
159 }
160 
161 void *
162 sldns_buffer_export(sldns_buffer *buffer)
163 {
164 	buffer->_fixed = 1;
165 	return buffer->_data;
166 }
167 
168 void
169 sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from)
170 {
171 	size_t tocopy = sldns_buffer_limit(from);
172 
173 	if(tocopy > sldns_buffer_capacity(result))
174 		tocopy = sldns_buffer_capacity(result);
175 	sldns_buffer_clear(result);
176 	sldns_buffer_write(result, sldns_buffer_begin(from), tocopy);
177 	sldns_buffer_flip(result);
178 }
179