15185a700Sflorian /*
25185a700Sflorian * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian *
45185a700Sflorian * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian * copyright notice and this permission notice appear in all copies.
75185a700Sflorian *
85185a700Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian */
165185a700Sflorian
17*873f12b9Sflorian /* $Id: buffer.c,v 1.8 2020/02/26 18:47:59 florian Exp $ */
185185a700Sflorian
195185a700Sflorian /*! \file */
205185a700Sflorian
215185a700Sflorian #include <stdlib.h>
225185a700Sflorian #include <isc/buffer.h>
235185a700Sflorian
245185a700Sflorian #include <isc/region.h>
255185a700Sflorian #include <string.h>
265185a700Sflorian #include <isc/util.h>
275185a700Sflorian
285185a700Sflorian void
isc__buffer_init(isc_buffer_t * b,void * base,unsigned int length)295185a700Sflorian isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
305185a700Sflorian /*
315185a700Sflorian * Make 'b' refer to the 'length'-byte region starting at 'base'.
325185a700Sflorian * XXXDCL see the comment in buffer.h about base being const.
335185a700Sflorian */
345185a700Sflorian
355185a700Sflorian REQUIRE(b != NULL);
365185a700Sflorian
375185a700Sflorian ISC__BUFFER_INIT(b, base, length);
385185a700Sflorian }
395185a700Sflorian
405185a700Sflorian void
isc__buffer_invalidate(isc_buffer_t * b)415185a700Sflorian isc__buffer_invalidate(isc_buffer_t *b) {
425185a700Sflorian /*
435185a700Sflorian * Make 'b' an invalid buffer.
445185a700Sflorian */
455185a700Sflorian
465185a700Sflorian REQUIRE(!ISC_LINK_LINKED(b, link));
475185a700Sflorian
485185a700Sflorian ISC__BUFFER_INVALIDATE(b);
495185a700Sflorian }
505185a700Sflorian
515185a700Sflorian void
isc__buffer_usedregion(isc_buffer_t * b,isc_region_t * r)525185a700Sflorian isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) {
535185a700Sflorian /*
545185a700Sflorian * Make 'r' refer to the used region of 'b'.
555185a700Sflorian */
565185a700Sflorian
575185a700Sflorian REQUIRE(r != NULL);
585185a700Sflorian
595185a700Sflorian ISC__BUFFER_USEDREGION(b, r);
605185a700Sflorian }
615185a700Sflorian
625185a700Sflorian void
isc__buffer_availableregion(isc_buffer_t * b,isc_region_t * r)635185a700Sflorian isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
645185a700Sflorian /*
655185a700Sflorian * Make 'r' refer to the available region of 'b'.
665185a700Sflorian */
675185a700Sflorian
685185a700Sflorian REQUIRE(r != NULL);
695185a700Sflorian
705185a700Sflorian ISC__BUFFER_AVAILABLEREGION(b, r);
715185a700Sflorian }
725185a700Sflorian
735185a700Sflorian void
isc__buffer_add(isc_buffer_t * b,unsigned int n)745185a700Sflorian isc__buffer_add(isc_buffer_t *b, unsigned int n) {
755185a700Sflorian /*
765185a700Sflorian * Increase the 'used' region of 'b' by 'n' bytes.
775185a700Sflorian */
785185a700Sflorian
795185a700Sflorian REQUIRE(b->used + n <= b->length);
805185a700Sflorian
815185a700Sflorian ISC__BUFFER_ADD(b, n);
825185a700Sflorian }
835185a700Sflorian
845185a700Sflorian void
isc__buffer_subtract(isc_buffer_t * b,unsigned int n)855185a700Sflorian isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
865185a700Sflorian /*
875185a700Sflorian * Decrease the 'used' region of 'b' by 'n' bytes.
885185a700Sflorian */
895185a700Sflorian
905185a700Sflorian REQUIRE(b->used >= n);
915185a700Sflorian
925185a700Sflorian ISC__BUFFER_SUBTRACT(b, n);
935185a700Sflorian }
945185a700Sflorian
955185a700Sflorian void
isc__buffer_clear(isc_buffer_t * b)965185a700Sflorian isc__buffer_clear(isc_buffer_t *b) {
975185a700Sflorian /*
985185a700Sflorian * Make the used region empty.
995185a700Sflorian */
1005185a700Sflorian
1015185a700Sflorian ISC__BUFFER_CLEAR(b);
1025185a700Sflorian }
1035185a700Sflorian
1045185a700Sflorian void
isc__buffer_remainingregion(isc_buffer_t * b,isc_region_t * r)1055185a700Sflorian isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
1065185a700Sflorian /*
1075185a700Sflorian * Make 'r' refer to the remaining region of 'b'.
1085185a700Sflorian */
1095185a700Sflorian
1105185a700Sflorian REQUIRE(r != NULL);
1115185a700Sflorian
1125185a700Sflorian ISC__BUFFER_REMAININGREGION(b, r);
1135185a700Sflorian }
1145185a700Sflorian
1155185a700Sflorian void
isc__buffer_activeregion(isc_buffer_t * b,isc_region_t * r)1165185a700Sflorian isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
1175185a700Sflorian /*
1185185a700Sflorian * Make 'r' refer to the active region of 'b'.
1195185a700Sflorian */
1205185a700Sflorian
1215185a700Sflorian REQUIRE(r != NULL);
1225185a700Sflorian
1235185a700Sflorian ISC__BUFFER_ACTIVEREGION(b, r);
1245185a700Sflorian }
1255185a700Sflorian
1265185a700Sflorian void
isc__buffer_setactive(isc_buffer_t * b,unsigned int n)1275185a700Sflorian isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
1285185a700Sflorian /*
1295185a700Sflorian * Sets the end of the active region 'n' bytes after current.
1305185a700Sflorian */
1315185a700Sflorian
1325185a700Sflorian REQUIRE(b->current + n <= b->used);
1335185a700Sflorian
1345185a700Sflorian ISC__BUFFER_SETACTIVE(b, n);
1355185a700Sflorian }
1365185a700Sflorian
1375185a700Sflorian void
isc__buffer_first(isc_buffer_t * b)1385185a700Sflorian isc__buffer_first(isc_buffer_t *b) {
1395185a700Sflorian /*
1405185a700Sflorian * Make the consumed region empty.
1415185a700Sflorian */
1425185a700Sflorian
1435185a700Sflorian ISC__BUFFER_FIRST(b);
1445185a700Sflorian }
1455185a700Sflorian
1465185a700Sflorian void
isc__buffer_forward(isc_buffer_t * b,unsigned int n)1475185a700Sflorian isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
1485185a700Sflorian /*
1495185a700Sflorian * Increase the 'consumed' region of 'b' by 'n' bytes.
1505185a700Sflorian */
1515185a700Sflorian
1525185a700Sflorian REQUIRE(b->current + n <= b->used);
1535185a700Sflorian
1545185a700Sflorian ISC__BUFFER_FORWARD(b, n);
1555185a700Sflorian }
1565185a700Sflorian
1575185a700Sflorian void
isc_buffer_compact(isc_buffer_t * b)1585185a700Sflorian isc_buffer_compact(isc_buffer_t *b) {
1595185a700Sflorian unsigned int length;
1605185a700Sflorian void *src;
1615185a700Sflorian
1625185a700Sflorian /*
1635185a700Sflorian * Compact the used region by moving the remaining region so it occurs
1645185a700Sflorian * at the start of the buffer. The used region is shrunk by the size
1655185a700Sflorian * of the consumed region, and the consumed region is then made empty.
1665185a700Sflorian */
1675185a700Sflorian
1685185a700Sflorian src = isc_buffer_current(b);
1695185a700Sflorian length = isc_buffer_remaininglength(b);
1705185a700Sflorian (void)memmove(b->base, src, (size_t)length);
1715185a700Sflorian
1725185a700Sflorian if (b->active > b->current)
1735185a700Sflorian b->active -= b->current;
1745185a700Sflorian else
1755185a700Sflorian b->active = 0;
1765185a700Sflorian b->current = 0;
1775185a700Sflorian b->used = length;
1785185a700Sflorian }
1795185a700Sflorian
1805185a700Sflorian uint8_t
isc_buffer_getuint8(isc_buffer_t * b)1815185a700Sflorian isc_buffer_getuint8(isc_buffer_t *b) {
1825185a700Sflorian unsigned char *cp;
1835185a700Sflorian uint8_t result;
1845185a700Sflorian
1855185a700Sflorian /*
1865185a700Sflorian * Read an unsigned 8-bit integer from 'b' and return it.
1875185a700Sflorian */
1885185a700Sflorian
1895185a700Sflorian REQUIRE(b->used - b->current >= 1);
1905185a700Sflorian
1915185a700Sflorian cp = isc_buffer_current(b);
1925185a700Sflorian b->current += 1;
1935185a700Sflorian result = ((uint8_t)(cp[0]));
1945185a700Sflorian
1955185a700Sflorian return (result);
1965185a700Sflorian }
1975185a700Sflorian
1985185a700Sflorian void
isc__buffer_putuint8(isc_buffer_t * b,uint8_t val)1995185a700Sflorian isc__buffer_putuint8(isc_buffer_t *b, uint8_t val) {
2005185a700Sflorian REQUIRE(b->used + 1 <= b->length);
2015185a700Sflorian
2025185a700Sflorian ISC__BUFFER_PUTUINT8(b, val);
2035185a700Sflorian }
2045185a700Sflorian
2055185a700Sflorian uint16_t
isc_buffer_getuint16(isc_buffer_t * b)2065185a700Sflorian isc_buffer_getuint16(isc_buffer_t *b) {
2075185a700Sflorian unsigned char *cp;
2085185a700Sflorian uint16_t result;
2095185a700Sflorian
2105185a700Sflorian /*
2115185a700Sflorian * Read an unsigned 16-bit integer in network byte order from 'b',
2125185a700Sflorian * convert it to host byte order, and return it.
2135185a700Sflorian */
2145185a700Sflorian
2155185a700Sflorian REQUIRE(b->used - b->current >= 2);
2165185a700Sflorian
2175185a700Sflorian cp = isc_buffer_current(b);
2185185a700Sflorian b->current += 2;
2195185a700Sflorian result = ((unsigned int)(cp[0])) << 8;
2205185a700Sflorian result |= ((unsigned int)(cp[1]));
2215185a700Sflorian
2225185a700Sflorian return (result);
2235185a700Sflorian }
2245185a700Sflorian
2255185a700Sflorian void
isc__buffer_putuint16(isc_buffer_t * b,uint16_t val)2265185a700Sflorian isc__buffer_putuint16(isc_buffer_t *b, uint16_t val) {
2275185a700Sflorian REQUIRE(b->used + 2 <= b->length);
2285185a700Sflorian
2295185a700Sflorian ISC__BUFFER_PUTUINT16(b, val);
2305185a700Sflorian }
2315185a700Sflorian
2325185a700Sflorian uint32_t
isc_buffer_getuint32(isc_buffer_t * b)2335185a700Sflorian isc_buffer_getuint32(isc_buffer_t *b) {
2345185a700Sflorian unsigned char *cp;
2355185a700Sflorian uint32_t result;
2365185a700Sflorian
2375185a700Sflorian /*
2385185a700Sflorian * Read an unsigned 32-bit integer in network byte order from 'b',
2395185a700Sflorian * convert it to host byte order, and return it.
2405185a700Sflorian */
2415185a700Sflorian
2425185a700Sflorian REQUIRE(b->used - b->current >= 4);
2435185a700Sflorian
2445185a700Sflorian cp = isc_buffer_current(b);
2455185a700Sflorian b->current += 4;
2465185a700Sflorian result = ((unsigned int)(cp[0])) << 24;
2475185a700Sflorian result |= ((unsigned int)(cp[1])) << 16;
2485185a700Sflorian result |= ((unsigned int)(cp[2])) << 8;
2495185a700Sflorian result |= ((unsigned int)(cp[3]));
2505185a700Sflorian
2515185a700Sflorian return (result);
2525185a700Sflorian }
2535185a700Sflorian
2545185a700Sflorian void
isc__buffer_putuint32(isc_buffer_t * b,uint32_t val)2555185a700Sflorian isc__buffer_putuint32(isc_buffer_t *b, uint32_t val) {
2565185a700Sflorian REQUIRE(b->used + 4 <= b->length);
2575185a700Sflorian
2585185a700Sflorian ISC__BUFFER_PUTUINT32(b, val);
2595185a700Sflorian }
2605185a700Sflorian
2615185a700Sflorian void
isc__buffer_putuint48(isc_buffer_t * b,uint64_t val)2625185a700Sflorian isc__buffer_putuint48(isc_buffer_t *b, uint64_t val) {
2635185a700Sflorian uint16_t valhi;
2645185a700Sflorian uint32_t vallo;
2655185a700Sflorian
2665185a700Sflorian REQUIRE(b->used + 6 <= b->length);
2675185a700Sflorian
2685185a700Sflorian valhi = (uint16_t)(val >> 32);
2695185a700Sflorian vallo = (uint32_t)(val & 0xFFFFFFFF);
2705185a700Sflorian ISC__BUFFER_PUTUINT16(b, valhi);
2715185a700Sflorian ISC__BUFFER_PUTUINT32(b, vallo);
2725185a700Sflorian }
2735185a700Sflorian
2745185a700Sflorian void
isc__buffer_putmem(isc_buffer_t * b,const unsigned char * base,unsigned int length)2755185a700Sflorian isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
2765185a700Sflorian unsigned int length)
2775185a700Sflorian {
2785185a700Sflorian REQUIRE(b->used + length <= b->length);
2795185a700Sflorian
2805185a700Sflorian ISC__BUFFER_PUTMEM(b, base, length);
2815185a700Sflorian }
2825185a700Sflorian
2835185a700Sflorian void
isc__buffer_putstr(isc_buffer_t * b,const char * source)2845185a700Sflorian isc__buffer_putstr(isc_buffer_t *b, const char *source) {
2855185a700Sflorian unsigned int l;
2865185a700Sflorian unsigned char *cp;
2875185a700Sflorian
2885185a700Sflorian REQUIRE(source != NULL);
2895185a700Sflorian
2905185a700Sflorian /*
2915185a700Sflorian * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
2925185a700Sflorian */
2935185a700Sflorian l = strlen(source);
2945185a700Sflorian
2955185a700Sflorian REQUIRE(l <= isc_buffer_availablelength(b));
2965185a700Sflorian
2975185a700Sflorian cp = isc_buffer_used(b);
2985185a700Sflorian memmove(cp, source, l);
2995185a700Sflorian b->used += l;
3005185a700Sflorian }
3015185a700Sflorian
3025185a700Sflorian isc_result_t
isc_buffer_copyregion(isc_buffer_t * b,const isc_region_t * r)3035185a700Sflorian isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
3045185a700Sflorian unsigned char *base;
3055185a700Sflorian unsigned int available;
3065185a700Sflorian
3075185a700Sflorian REQUIRE(r != NULL);
3085185a700Sflorian
3095185a700Sflorian /*
3105185a700Sflorian * XXXDCL
3115185a700Sflorian */
3125185a700Sflorian base = isc_buffer_used(b);
3135185a700Sflorian available = isc_buffer_availablelength(b);
3145185a700Sflorian if (r->length > available)
3155185a700Sflorian return (ISC_R_NOSPACE);
3165185a700Sflorian memmove(base, r->base, r->length);
3175185a700Sflorian b->used += r->length;
3185185a700Sflorian
3195185a700Sflorian return (ISC_R_SUCCESS);
3205185a700Sflorian }
3215185a700Sflorian
3225185a700Sflorian isc_result_t
isc_buffer_allocate(isc_buffer_t ** dynbuffer,unsigned int length)3235185a700Sflorian isc_buffer_allocate(isc_buffer_t **dynbuffer,
3245185a700Sflorian unsigned int length)
3255185a700Sflorian {
3265185a700Sflorian isc_buffer_t *dbuf;
3275185a700Sflorian
3285185a700Sflorian REQUIRE(dynbuffer != NULL);
3295185a700Sflorian REQUIRE(*dynbuffer == NULL);
3305185a700Sflorian
3315185a700Sflorian dbuf = malloc(length + sizeof(isc_buffer_t));
3325185a700Sflorian if (dbuf == NULL)
3335185a700Sflorian return (ISC_R_NOMEMORY);
3345185a700Sflorian
3355185a700Sflorian isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
3365185a700Sflorian length);
3375185a700Sflorian
3385185a700Sflorian *dynbuffer = dbuf;
3395185a700Sflorian
3405185a700Sflorian return (ISC_R_SUCCESS);
3415185a700Sflorian }
3425185a700Sflorian
3435185a700Sflorian void
isc_buffer_free(isc_buffer_t ** dynbuffer)3445185a700Sflorian isc_buffer_free(isc_buffer_t **dynbuffer) {
3455185a700Sflorian isc_buffer_t *dbuf;
3465185a700Sflorian
3475185a700Sflorian REQUIRE(dynbuffer != NULL);
3485185a700Sflorian dbuf = *dynbuffer;
3495185a700Sflorian *dynbuffer = NULL; /* destroy external reference */
3505185a700Sflorian
3515185a700Sflorian isc_buffer_invalidate(dbuf);
3525185a700Sflorian
3535185a700Sflorian free(dbuf);
3545185a700Sflorian }
355637d8eb6Sflorian
356637d8eb6Sflorian isc_result_t
isc_mem_tobuffer(isc_buffer_t * target,void * base,unsigned int length)357637d8eb6Sflorian isc_mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
358637d8eb6Sflorian isc_region_t tr;
359637d8eb6Sflorian
360637d8eb6Sflorian isc_buffer_availableregion(target, &tr);
361637d8eb6Sflorian if (length > tr.length)
362637d8eb6Sflorian return (ISC_R_NOSPACE);
363637d8eb6Sflorian memmove(tr.base, base, length);
364637d8eb6Sflorian isc_buffer_add(target, length);
365637d8eb6Sflorian return (ISC_R_SUCCESS);
366637d8eb6Sflorian }
367*873f12b9Sflorian
368*873f12b9Sflorian /* this used to be str_totext() in rdata.c etc. */
369*873f12b9Sflorian isc_result_t
isc_str_tobuffer(const char * source,isc_buffer_t * target)370*873f12b9Sflorian isc_str_tobuffer(const char *source, isc_buffer_t *target) {
371*873f12b9Sflorian unsigned int l;
372*873f12b9Sflorian isc_region_t region;
373*873f12b9Sflorian
374*873f12b9Sflorian isc_buffer_availableregion(target, ®ion);
375*873f12b9Sflorian l = strlen(source);
376*873f12b9Sflorian
377*873f12b9Sflorian if (l > region.length)
378*873f12b9Sflorian return (ISC_R_NOSPACE);
379*873f12b9Sflorian
380*873f12b9Sflorian memmove(region.base, source, l);
381*873f12b9Sflorian isc_buffer_add(target, l);
382*873f12b9Sflorian return (ISC_R_SUCCESS);
383*873f12b9Sflorian }
384