buffer.c revision 238104
1255376Sdes/*
2255376Sdes * buffer.c -- generic memory buffer .
3271947Sdes *
494209Sdes * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
594209Sdes *
694209Sdes * See LICENSE for the license.
794209Sdes *
894209Sdes */
994209Sdes
1094209Sdes#include <ldns/config.h>
1194209Sdes
12108794Sdes#include <ldns/ldns.h>
1394209Sdes#include <ldns/buffer.h>
1495908Sdes
15117610Sdesldns_buffer *
1694209Sdesldns_buffer_new(size_t capacity)
1794209Sdes{
1894209Sdes	ldns_buffer *buffer = LDNS_MALLOC(ldns_buffer);
19236109Sdes
2094209Sdes	if (!buffer) {
2194209Sdes		return NULL;
2294209Sdes	}
2394209Sdes
2494209Sdes	buffer->_data = (uint8_t *) LDNS_XMALLOC(uint8_t, capacity);
25236109Sdes	if (!buffer->_data) {
2694209Sdes		LDNS_FREE(buffer);
2794209Sdes		return NULL;
2894209Sdes	}
2994209Sdes
3094209Sdes	buffer->_position = 0;
3194209Sdes	buffer->_limit = buffer->_capacity = capacity;
3294209Sdes	buffer->_fixed = 0;
3394209Sdes	buffer->_status = LDNS_STATUS_OK;
34141098Sdes
35141098Sdes	ldns_buffer_invariant(buffer);
36141098Sdes
3794209Sdes	return buffer;
3894209Sdes}
39141098Sdes
4094209Sdesvoid
4194209Sdesldns_buffer_new_frm_data(ldns_buffer *buffer, void *data, size_t size)
42236109Sdes{
4394209Sdes	assert(data != NULL);
4494209Sdes
4594209Sdes	buffer->_position = 0;
46236109Sdes	buffer->_limit = buffer->_capacity = size;
47236109Sdes	buffer->_fixed = 0;
48236109Sdes	buffer->_data = LDNS_XMALLOC(uint8_t, size);
49117610Sdes	if(!buffer->_data) {
50236109Sdes		buffer->_status = LDNS_STATUS_MEM_ERR;
51147466Sdes		return;
52117610Sdes	}
5394209Sdes	memcpy(buffer->_data, data, size);
5494209Sdes	buffer->_status = LDNS_STATUS_OK;
55255376Sdes
56255376Sdes	ldns_buffer_invariant(buffer);
57255376Sdes}
58
59bool
60ldns_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
67	data = (uint8_t *) LDNS_XREALLOC(buffer->_data, uint8_t, capacity);
68	if (!data) {
69		buffer->_status = LDNS_STATUS_MEM_ERR;
70		return false;
71	} else {
72		buffer->_data = data;
73		buffer->_limit = buffer->_capacity = capacity;
74		return true;
75	}
76}
77
78bool
79ldns_buffer_reserve(ldns_buffer *buffer, size_t amount)
80{
81	ldns_buffer_invariant(buffer);
82	assert(!buffer->_fixed);
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
98int
99ldns_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
136void
137ldns_buffer_free(ldns_buffer *buffer)
138{
139	if (!buffer) {
140		return;
141	}
142
143	LDNS_FREE(buffer->_data);
144
145	LDNS_FREE(buffer);
146}
147
148void *
149ldns_buffer_export(ldns_buffer *buffer)
150{
151	buffer->_fixed = 1;
152	return buffer->_data;
153}
154
155int
156ldns_bgetc(ldns_buffer *buffer)
157{
158	if (!ldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) {
159		ldns_buffer_set_position(buffer, ldns_buffer_limit(buffer));
160		/* ldns_buffer_rewind(buffer);*/
161		return EOF;
162	}
163	return (int)ldns_buffer_read_u8(buffer);
164}
165
166void
167ldns_buffer_copy(ldns_buffer* result, ldns_buffer* from)
168{
169	size_t tocopy = ldns_buffer_limit(from);
170
171	if(tocopy > ldns_buffer_capacity(result))
172		tocopy = ldns_buffer_capacity(result);
173	ldns_buffer_clear(result);
174	ldns_buffer_write(result, ldns_buffer_begin(from), tocopy);
175	ldns_buffer_flip(result);
176}
177