/*
 * Copyright (c) 2003, 2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: rcbgetaint.c,v 1.2 2007/01/31 05:25:16 ca Exp $")

#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/error.h"
#include "sm/memops.h"
#include "sm/rpool.h"
#include "sm/limits.h"
#include "sm/rcb.h"
#include "sm/reccom.h"

#if MTA_USE_RCBV_INTN
/*
**  SM_RCB_GETAUINT32 -- Read n ints from the current position in a sm_rcb_P.
**		In contrast to other sm_rcb_getXuint32 functions, this one
**		"knows" about the structure of entries:
**		length, rt, value, value, ...
**
**	Parameters:
**		rcb -- sm_rcb_P object to read int from.
**		nmax -- maximum number of entries to read (#entries in pv)
**		pn -- (pointer to) number of values (output)
**			if NULL then nmax is the number of entries to read
**		prt -- (pointer to) record type (output)
**		pv -- (pointer to) array of values (output)
**
**	Returns:
**		usual sm_error code; SM_E_OVFLW_NS
**
**	Last code review:
**	Last code change:
*/

sm_ret_T
sm_rcb_getauint32(sm_rcb_P rcb, uint nmax, uint *pn, uint32_t *prt, uint32_t *pv)
{
	uint u, n;
	uint32_t v;

	SM_IS_RCB(rcb);
# if SM_RCB_CHECK
	SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_DEC);
# endif

	SM_REQUIRE(nmax > 0);
	SM_REQUIRE(pv != NULL);

	if (pn != NULL) {
		SM_REQUIRE(prt != NULL);

		/* at least 2 entries: number of bytes and rt */
		if (rcb->sm_rcb_len < rcb->sm_rcb_rw + sizeof(uint32_t) * 2)
			return sm_error_perm(SM_EM_RECCOM, SM_E_OVFLW_NS);

		/* number of bytes */
		sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
		rcb->sm_rcb_rw += sizeof(uint32_t);

		if (v >= UINT_MAX)
			return sm_error_perm(SM_EM_RECCOM, SM_E_OVFLW_NS);
		if (v % sizeof(uint32_t) != 0)
			return sm_error_perm(SM_EM_RECCOM, EINVAL);
		*pn = n = (uint) v / sizeof(uint32_t);
		if (n >= nmax)
			return sm_error_perm(SM_EM_RECCOM, SM_E_OVFLW_NS);

		if (rcb->sm_rcb_len < rcb->sm_rcb_rw + v)
			return sm_error_perm(SM_EM_RECCOM, SM_E_OVFLW_NS);

		/* record type */
		sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
		rcb->sm_rcb_rw += sizeof(uint32_t);
		*prt = v;
	}
	else {
		n = nmax;
	}

	/* are there n entries? */
	if (rcb->sm_rcb_len < rcb->sm_rcb_rw + sizeof(uint32_t) * n)
		return sm_error_perm(SM_EM_RECCOM, SM_E_OVFLW_NS);

	for (u = 0; u < n; u++) {
		sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
		rcb->sm_rcb_rw += sizeof(uint32_t);
		*pv++ = v;
	}

	return SM_SUCCESS;
}
#endif /* MTA_USE_RCBV_INTN */


syntax highlighted by Code2HTML, v. 0.9.1