/* * buffer.c -- generic memory buffer . * * Copyright (c) 2001-2008, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ /** * \file * * This file contains the definition of sldns_buffer, and functions to manipulate those. */ #include "config.h" #include "sldns/sbuffer.h" #include sldns_buffer * sldns_buffer_new(size_t capacity) { sldns_buffer *buffer = (sldns_buffer*)malloc(sizeof(sldns_buffer)); if (!buffer) { return NULL; } buffer->_data = (uint8_t *) malloc(capacity); if (!buffer->_data) { free(buffer); return NULL; } buffer->_position = 0; buffer->_limit = buffer->_capacity = capacity; buffer->_fixed = 0; buffer->_status_err = 0; sldns_buffer_invariant(buffer); return buffer; } void sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size) { assert(data != NULL); buffer->_position = 0; buffer->_limit = buffer->_capacity = size; buffer->_fixed = 0; buffer->_data = malloc(size); if(!buffer->_data) { buffer->_status_err = 1; return; } memcpy(buffer->_data, data, size); buffer->_status_err = 0; sldns_buffer_invariant(buffer); } void sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size) { memset(buffer, 0, sizeof(*buffer)); buffer->_data = data; buffer->_capacity = buffer->_limit = size; buffer->_fixed = 1; } int sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity) { void *data; sldns_buffer_invariant(buffer); assert(buffer->_position <= capacity); data = (uint8_t *) realloc(buffer->_data, capacity); if (!data) { buffer->_status_err = 1; return 0; } else { buffer->_data = data; buffer->_limit = buffer->_capacity = capacity; return 1; } } int sldns_buffer_reserve(sldns_buffer *buffer, size_t amount) { sldns_buffer_invariant(buffer); assert(!buffer->_fixed); if (buffer->_capacity < buffer->_position + amount) { size_t new_capacity = buffer->_capacity * 3 / 2; if (new_capacity < buffer->_position + amount) { new_capacity = buffer->_position + amount; } if (!sldns_buffer_set_capacity(buffer, new_capacity)) { buffer->_status_err = 1; return 0; } } buffer->_limit = buffer->_capacity; return 1; } int sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...) { va_list args; int written = 0; size_t remaining; if (sldns_buffer_status_ok(buffer)) { sldns_buffer_invariant(buffer); assert(buffer->_limit == buffer->_capacity); remaining = sldns_buffer_remaining(buffer); va_start(args, format); written = vsnprintf((char *) sldns_buffer_current(buffer), remaining, format, args); va_end(args); if (written == -1) { buffer->_status_err = 1; return -1; } else if ((size_t) written >= remaining) { if (!sldns_buffer_reserve(buffer, (size_t) written + 1)) { buffer->_status_err = 1; return -1; } va_start(args, format); written = vsnprintf((char *) sldns_buffer_current(buffer), sldns_buffer_remaining(buffer), format, args); va_end(args); if (written == -1) { buffer->_status_err = 1; return -1; } } buffer->_position += written; } return written; } void sldns_buffer_free(sldns_buffer *buffer) { if (!buffer) { return; } if (!buffer->_fixed) free(buffer->_data); free(buffer); } void * sldns_buffer_export(sldns_buffer *buffer) { buffer->_fixed = 1; return buffer->_data; } void sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from) { size_t tocopy = sldns_buffer_limit(from); if(tocopy > sldns_buffer_capacity(result)) tocopy = sldns_buffer_capacity(result); sldns_buffer_clear(result); sldns_buffer_write(result, sldns_buffer_begin(from), tocopy); sldns_buffer_flip(result); }