1238104Sdes/* 2238104Sdes * buffer.c -- generic memory buffer . 3238104Sdes * 4238104Sdes * Copyright (c) 2001-2008, NLnet Labs. All rights reserved. 5238104Sdes * 6238104Sdes * See LICENSE for the license. 7238104Sdes * 8238104Sdes */ 9238104Sdes 10238104Sdes#include <ldns/config.h> 11238104Sdes 12238104Sdes#include <ldns/ldns.h> 13238104Sdes#include <ldns/buffer.h> 14238104Sdes 15238104Sdesldns_buffer * 16238104Sdesldns_buffer_new(size_t capacity) 17238104Sdes{ 18238104Sdes ldns_buffer *buffer = LDNS_MALLOC(ldns_buffer); 19238104Sdes 20238104Sdes if (!buffer) { 21238104Sdes return NULL; 22238104Sdes } 23238104Sdes 24238104Sdes buffer->_data = (uint8_t *) LDNS_XMALLOC(uint8_t, capacity); 25238104Sdes if (!buffer->_data) { 26238104Sdes LDNS_FREE(buffer); 27238104Sdes return NULL; 28238104Sdes } 29238104Sdes 30238104Sdes buffer->_position = 0; 31238104Sdes buffer->_limit = buffer->_capacity = capacity; 32238104Sdes buffer->_fixed = 0; 33238104Sdes buffer->_status = LDNS_STATUS_OK; 34238104Sdes 35238104Sdes ldns_buffer_invariant(buffer); 36238104Sdes 37238104Sdes return buffer; 38238104Sdes} 39238104Sdes 40238104Sdesvoid 41238104Sdesldns_buffer_new_frm_data(ldns_buffer *buffer, void *data, size_t size) 42238104Sdes{ 43238104Sdes assert(data != NULL); 44238104Sdes 45238104Sdes buffer->_position = 0; 46238104Sdes buffer->_limit = buffer->_capacity = size; 47238104Sdes buffer->_fixed = 0; 48238104Sdes buffer->_data = LDNS_XMALLOC(uint8_t, size); 49238104Sdes if(!buffer->_data) { 50238104Sdes buffer->_status = LDNS_STATUS_MEM_ERR; 51238104Sdes return; 52238104Sdes } 53238104Sdes memcpy(buffer->_data, data, size); 54238104Sdes buffer->_status = LDNS_STATUS_OK; 55238104Sdes 56238104Sdes ldns_buffer_invariant(buffer); 57238104Sdes} 58238104Sdes 59238104Sdesbool 60238104Sdesldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity) 61238104Sdes{ 62238104Sdes void *data; 63238104Sdes 64238104Sdes ldns_buffer_invariant(buffer); 65238104Sdes assert(buffer->_position <= capacity); 66238104Sdes 67238104Sdes data = (uint8_t *) LDNS_XREALLOC(buffer->_data, uint8_t, capacity); 68238104Sdes if (!data) { 69238104Sdes buffer->_status = LDNS_STATUS_MEM_ERR; 70238104Sdes return false; 71238104Sdes } else { 72238104Sdes buffer->_data = data; 73238104Sdes buffer->_limit = buffer->_capacity = capacity; 74238104Sdes return true; 75238104Sdes } 76238104Sdes} 77238104Sdes 78238104Sdesbool 79238104Sdesldns_buffer_reserve(ldns_buffer *buffer, size_t amount) 80238104Sdes{ 81238104Sdes ldns_buffer_invariant(buffer); 82238104Sdes assert(!buffer->_fixed); 83238104Sdes if (buffer->_capacity < buffer->_position + amount) { 84238104Sdes size_t new_capacity = buffer->_capacity * 3 / 2; 85238104Sdes 86238104Sdes if (new_capacity < buffer->_position + amount) { 87238104Sdes new_capacity = buffer->_position + amount; 88238104Sdes } 89238104Sdes if (!ldns_buffer_set_capacity(buffer, new_capacity)) { 90238104Sdes buffer->_status = LDNS_STATUS_MEM_ERR; 91238104Sdes return false; 92238104Sdes } 93238104Sdes } 94238104Sdes buffer->_limit = buffer->_capacity; 95238104Sdes return true; 96238104Sdes} 97238104Sdes 98238104Sdesint 99238104Sdesldns_buffer_printf(ldns_buffer *buffer, const char *format, ...) 100238104Sdes{ 101238104Sdes va_list args; 102238104Sdes int written = 0; 103238104Sdes size_t remaining; 104238104Sdes 105238104Sdes if (ldns_buffer_status_ok(buffer)) { 106238104Sdes ldns_buffer_invariant(buffer); 107238104Sdes assert(buffer->_limit == buffer->_capacity); 108238104Sdes 109238104Sdes remaining = ldns_buffer_remaining(buffer); 110238104Sdes va_start(args, format); 111238104Sdes written = vsnprintf((char *) ldns_buffer_current(buffer), remaining, 112238104Sdes format, args); 113238104Sdes va_end(args); 114238104Sdes if (written == -1) { 115238104Sdes buffer->_status = LDNS_STATUS_INTERNAL_ERR; 116238104Sdes return -1; 117238104Sdes } else if ((size_t) written >= remaining) { 118238104Sdes if (!ldns_buffer_reserve(buffer, (size_t) written + 1)) { 119238104Sdes buffer->_status = LDNS_STATUS_MEM_ERR; 120238104Sdes return -1; 121238104Sdes } 122238104Sdes va_start(args, format); 123238104Sdes written = vsnprintf((char *) ldns_buffer_current(buffer), 124238104Sdes ldns_buffer_remaining(buffer), format, args); 125238104Sdes va_end(args); 126238104Sdes if (written == -1) { 127238104Sdes buffer->_status = LDNS_STATUS_INTERNAL_ERR; 128238104Sdes return -1; 129238104Sdes } 130238104Sdes } 131238104Sdes buffer->_position += written; 132238104Sdes } 133238104Sdes return written; 134238104Sdes} 135238104Sdes 136238104Sdesvoid 137238104Sdesldns_buffer_free(ldns_buffer *buffer) 138238104Sdes{ 139238104Sdes if (!buffer) { 140238104Sdes return; 141238104Sdes } 142238104Sdes 143246854Sdes if (!buffer->_fixed) 144246854Sdes LDNS_FREE(buffer->_data); 145238104Sdes 146238104Sdes LDNS_FREE(buffer); 147238104Sdes} 148238104Sdes 149238104Sdesvoid * 150238104Sdesldns_buffer_export(ldns_buffer *buffer) 151238104Sdes{ 152238104Sdes buffer->_fixed = 1; 153238104Sdes return buffer->_data; 154238104Sdes} 155238104Sdes 156238104Sdesint 157238104Sdesldns_bgetc(ldns_buffer *buffer) 158238104Sdes{ 159238104Sdes if (!ldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) { 160238104Sdes ldns_buffer_set_position(buffer, ldns_buffer_limit(buffer)); 161238104Sdes /* ldns_buffer_rewind(buffer);*/ 162238104Sdes return EOF; 163238104Sdes } 164238104Sdes return (int)ldns_buffer_read_u8(buffer); 165238104Sdes} 166238104Sdes 167238104Sdesvoid 168238104Sdesldns_buffer_copy(ldns_buffer* result, ldns_buffer* from) 169238104Sdes{ 170238104Sdes size_t tocopy = ldns_buffer_limit(from); 171238104Sdes 172238104Sdes if(tocopy > ldns_buffer_capacity(result)) 173238104Sdes tocopy = ldns_buffer_capacity(result); 174238104Sdes ldns_buffer_clear(result); 175238104Sdes ldns_buffer_write(result, ldns_buffer_begin(from), tocopy); 176238104Sdes ldns_buffer_flip(result); 177238104Sdes} 178