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