xref: /openbsd-src/usr.bin/dig/lib/isc/buffer.c (revision 873f12b9e6aaf39ba104db6af3d0dc687cd95f7e)
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, &region);
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