17b5038d7SDag-Erling Smørgrav /* 27b5038d7SDag-Erling Smørgrav * buffer.c -- generic memory buffer . 37b5038d7SDag-Erling Smørgrav * 47b5038d7SDag-Erling Smørgrav * Copyright (c) 2001-2008, NLnet Labs. All rights reserved. 57b5038d7SDag-Erling Smørgrav * 67b5038d7SDag-Erling Smørgrav * See LICENSE for the license. 77b5038d7SDag-Erling Smørgrav * 87b5038d7SDag-Erling Smørgrav */ 97b5038d7SDag-Erling Smørgrav 107b5038d7SDag-Erling Smørgrav #include <ldns/config.h> 117b5038d7SDag-Erling Smørgrav 127b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h> 137b5038d7SDag-Erling Smørgrav #include <ldns/buffer.h> 147b5038d7SDag-Erling Smørgrav 157b5038d7SDag-Erling Smørgrav ldns_buffer * 167b5038d7SDag-Erling Smørgrav ldns_buffer_new(size_t capacity) 177b5038d7SDag-Erling Smørgrav { 187b5038d7SDag-Erling Smørgrav ldns_buffer *buffer = LDNS_MALLOC(ldns_buffer); 197b5038d7SDag-Erling Smørgrav 207b5038d7SDag-Erling Smørgrav if (!buffer) { 217b5038d7SDag-Erling Smørgrav return NULL; 227b5038d7SDag-Erling Smørgrav } 237b5038d7SDag-Erling Smørgrav 247b5038d7SDag-Erling Smørgrav buffer->_data = (uint8_t *) LDNS_XMALLOC(uint8_t, capacity); 257b5038d7SDag-Erling Smørgrav if (!buffer->_data) { 267b5038d7SDag-Erling Smørgrav LDNS_FREE(buffer); 277b5038d7SDag-Erling Smørgrav return NULL; 287b5038d7SDag-Erling Smørgrav } 297b5038d7SDag-Erling Smørgrav 307b5038d7SDag-Erling Smørgrav buffer->_position = 0; 317b5038d7SDag-Erling Smørgrav buffer->_limit = buffer->_capacity = capacity; 327b5038d7SDag-Erling Smørgrav buffer->_fixed = 0; 337b5038d7SDag-Erling Smørgrav buffer->_status = LDNS_STATUS_OK; 347b5038d7SDag-Erling Smørgrav 357b5038d7SDag-Erling Smørgrav ldns_buffer_invariant(buffer); 367b5038d7SDag-Erling Smørgrav 377b5038d7SDag-Erling Smørgrav return buffer; 387b5038d7SDag-Erling Smørgrav } 397b5038d7SDag-Erling Smørgrav 407b5038d7SDag-Erling Smørgrav void 41*986ba33cSDag-Erling Smørgrav ldns_buffer_new_frm_data(ldns_buffer *buffer, const void *data, size_t size) 427b5038d7SDag-Erling Smørgrav { 437b5038d7SDag-Erling Smørgrav assert(data != NULL); 447b5038d7SDag-Erling Smørgrav 457b5038d7SDag-Erling Smørgrav buffer->_position = 0; 467b5038d7SDag-Erling Smørgrav buffer->_limit = buffer->_capacity = size; 477b5038d7SDag-Erling Smørgrav buffer->_fixed = 0; 487b5038d7SDag-Erling Smørgrav buffer->_data = LDNS_XMALLOC(uint8_t, size); 497b5038d7SDag-Erling Smørgrav if(!buffer->_data) { 507b5038d7SDag-Erling Smørgrav buffer->_status = LDNS_STATUS_MEM_ERR; 517b5038d7SDag-Erling Smørgrav return; 527b5038d7SDag-Erling Smørgrav } 537b5038d7SDag-Erling Smørgrav memcpy(buffer->_data, data, size); 547b5038d7SDag-Erling Smørgrav buffer->_status = LDNS_STATUS_OK; 557b5038d7SDag-Erling Smørgrav 567b5038d7SDag-Erling Smørgrav ldns_buffer_invariant(buffer); 577b5038d7SDag-Erling Smørgrav } 587b5038d7SDag-Erling Smørgrav 597b5038d7SDag-Erling Smørgrav bool 607b5038d7SDag-Erling Smørgrav ldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity) 617b5038d7SDag-Erling Smørgrav { 627b5038d7SDag-Erling Smørgrav void *data; 637b5038d7SDag-Erling Smørgrav 647b5038d7SDag-Erling Smørgrav ldns_buffer_invariant(buffer); 657b5038d7SDag-Erling Smørgrav assert(buffer->_position <= capacity); 667b5038d7SDag-Erling Smørgrav 677b5038d7SDag-Erling Smørgrav data = (uint8_t *) LDNS_XREALLOC(buffer->_data, uint8_t, capacity); 687b5038d7SDag-Erling Smørgrav if (!data) { 697b5038d7SDag-Erling Smørgrav buffer->_status = LDNS_STATUS_MEM_ERR; 707b5038d7SDag-Erling Smørgrav return false; 717b5038d7SDag-Erling Smørgrav } else { 727b5038d7SDag-Erling Smørgrav buffer->_data = data; 737b5038d7SDag-Erling Smørgrav buffer->_limit = buffer->_capacity = capacity; 747b5038d7SDag-Erling Smørgrav return true; 757b5038d7SDag-Erling Smørgrav } 767b5038d7SDag-Erling Smørgrav } 777b5038d7SDag-Erling Smørgrav 787b5038d7SDag-Erling Smørgrav bool 797b5038d7SDag-Erling Smørgrav ldns_buffer_reserve(ldns_buffer *buffer, size_t amount) 807b5038d7SDag-Erling Smørgrav { 817b5038d7SDag-Erling Smørgrav ldns_buffer_invariant(buffer); 827b5038d7SDag-Erling Smørgrav assert(!buffer->_fixed); 837b5038d7SDag-Erling Smørgrav if (buffer->_capacity < buffer->_position + amount) { 847b5038d7SDag-Erling Smørgrav size_t new_capacity = buffer->_capacity * 3 / 2; 857b5038d7SDag-Erling Smørgrav 867b5038d7SDag-Erling Smørgrav if (new_capacity < buffer->_position + amount) { 877b5038d7SDag-Erling Smørgrav new_capacity = buffer->_position + amount; 887b5038d7SDag-Erling Smørgrav } 897b5038d7SDag-Erling Smørgrav if (!ldns_buffer_set_capacity(buffer, new_capacity)) { 907b5038d7SDag-Erling Smørgrav buffer->_status = LDNS_STATUS_MEM_ERR; 917b5038d7SDag-Erling Smørgrav return false; 927b5038d7SDag-Erling Smørgrav } 937b5038d7SDag-Erling Smørgrav } 947b5038d7SDag-Erling Smørgrav buffer->_limit = buffer->_capacity; 957b5038d7SDag-Erling Smørgrav return true; 967b5038d7SDag-Erling Smørgrav } 977b5038d7SDag-Erling Smørgrav 987b5038d7SDag-Erling Smørgrav int 997b5038d7SDag-Erling Smørgrav ldns_buffer_printf(ldns_buffer *buffer, const char *format, ...) 1007b5038d7SDag-Erling Smørgrav { 1017b5038d7SDag-Erling Smørgrav va_list args; 1027b5038d7SDag-Erling Smørgrav int written = 0; 1037b5038d7SDag-Erling Smørgrav size_t remaining; 1047b5038d7SDag-Erling Smørgrav 1057b5038d7SDag-Erling Smørgrav if (ldns_buffer_status_ok(buffer)) { 1067b5038d7SDag-Erling Smørgrav ldns_buffer_invariant(buffer); 1077b5038d7SDag-Erling Smørgrav assert(buffer->_limit == buffer->_capacity); 1087b5038d7SDag-Erling Smørgrav 1097b5038d7SDag-Erling Smørgrav remaining = ldns_buffer_remaining(buffer); 1107b5038d7SDag-Erling Smørgrav va_start(args, format); 1117b5038d7SDag-Erling Smørgrav written = vsnprintf((char *) ldns_buffer_current(buffer), remaining, 1127b5038d7SDag-Erling Smørgrav format, args); 1137b5038d7SDag-Erling Smørgrav va_end(args); 1147b5038d7SDag-Erling Smørgrav if (written == -1) { 1157b5038d7SDag-Erling Smørgrav buffer->_status = LDNS_STATUS_INTERNAL_ERR; 1167b5038d7SDag-Erling Smørgrav return -1; 1177b5038d7SDag-Erling Smørgrav } else if ((size_t) written >= remaining) { 1187b5038d7SDag-Erling Smørgrav if (!ldns_buffer_reserve(buffer, (size_t) written + 1)) { 1197b5038d7SDag-Erling Smørgrav buffer->_status = LDNS_STATUS_MEM_ERR; 1207b5038d7SDag-Erling Smørgrav return -1; 1217b5038d7SDag-Erling Smørgrav } 1227b5038d7SDag-Erling Smørgrav va_start(args, format); 1237b5038d7SDag-Erling Smørgrav written = vsnprintf((char *) ldns_buffer_current(buffer), 1247b5038d7SDag-Erling Smørgrav ldns_buffer_remaining(buffer), format, args); 1257b5038d7SDag-Erling Smørgrav va_end(args); 1267b5038d7SDag-Erling Smørgrav if (written == -1) { 1277b5038d7SDag-Erling Smørgrav buffer->_status = LDNS_STATUS_INTERNAL_ERR; 1287b5038d7SDag-Erling Smørgrav return -1; 1297b5038d7SDag-Erling Smørgrav } 1307b5038d7SDag-Erling Smørgrav } 1317b5038d7SDag-Erling Smørgrav buffer->_position += written; 1327b5038d7SDag-Erling Smørgrav } 1337b5038d7SDag-Erling Smørgrav return written; 1347b5038d7SDag-Erling Smørgrav } 1357b5038d7SDag-Erling Smørgrav 1367b5038d7SDag-Erling Smørgrav void 1377b5038d7SDag-Erling Smørgrav ldns_buffer_free(ldns_buffer *buffer) 1387b5038d7SDag-Erling Smørgrav { 1397b5038d7SDag-Erling Smørgrav if (!buffer) { 1407b5038d7SDag-Erling Smørgrav return; 1417b5038d7SDag-Erling Smørgrav } 1427b5038d7SDag-Erling Smørgrav 1432787e39aSDag-Erling Smørgrav if (!buffer->_fixed) 1447b5038d7SDag-Erling Smørgrav LDNS_FREE(buffer->_data); 1457b5038d7SDag-Erling Smørgrav 1467b5038d7SDag-Erling Smørgrav LDNS_FREE(buffer); 1477b5038d7SDag-Erling Smørgrav } 1487b5038d7SDag-Erling Smørgrav 1497b5038d7SDag-Erling Smørgrav void * 1507b5038d7SDag-Erling Smørgrav ldns_buffer_export(ldns_buffer *buffer) 1517b5038d7SDag-Erling Smørgrav { 1527b5038d7SDag-Erling Smørgrav buffer->_fixed = 1; 1537b5038d7SDag-Erling Smørgrav return buffer->_data; 1547b5038d7SDag-Erling Smørgrav } 1557b5038d7SDag-Erling Smørgrav 1567b5038d7SDag-Erling Smørgrav int 1577b5038d7SDag-Erling Smørgrav ldns_bgetc(ldns_buffer *buffer) 1587b5038d7SDag-Erling Smørgrav { 1597b5038d7SDag-Erling Smørgrav if (!ldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) { 1607b5038d7SDag-Erling Smørgrav ldns_buffer_set_position(buffer, ldns_buffer_limit(buffer)); 1617b5038d7SDag-Erling Smørgrav /* ldns_buffer_rewind(buffer);*/ 1627b5038d7SDag-Erling Smørgrav return EOF; 1637b5038d7SDag-Erling Smørgrav } 1647b5038d7SDag-Erling Smørgrav return (int)ldns_buffer_read_u8(buffer); 1657b5038d7SDag-Erling Smørgrav } 1667b5038d7SDag-Erling Smørgrav 1677b5038d7SDag-Erling Smørgrav void 168*986ba33cSDag-Erling Smørgrav ldns_buffer_copy(ldns_buffer* result, const ldns_buffer* from) 1697b5038d7SDag-Erling Smørgrav { 1707b5038d7SDag-Erling Smørgrav size_t tocopy = ldns_buffer_limit(from); 1717b5038d7SDag-Erling Smørgrav 1727b5038d7SDag-Erling Smørgrav if(tocopy > ldns_buffer_capacity(result)) 1737b5038d7SDag-Erling Smørgrav tocopy = ldns_buffer_capacity(result); 1747b5038d7SDag-Erling Smørgrav ldns_buffer_clear(result); 1757b5038d7SDag-Erling Smørgrav ldns_buffer_write(result, ldns_buffer_begin(from), tocopy); 1767b5038d7SDag-Erling Smørgrav ldns_buffer_flip(result); 1777b5038d7SDag-Erling Smørgrav } 178