packages feed

hpqtypes-1.2.2: libpqtypes/src/geo.c

/*
 * geo.c
 *   Type handler for the geometric data types.
 *
 * Copyright (c) 2011 eSilo, LLC. All rights reserved.
 * This is free software; see the source for copying conditions.  There is
 * NO warranty; not even for MERCHANTABILITY or  FITNESS FOR A  PARTICULAR
 * PURPOSE.
 */

#include "libpqtypes-int.h"

static int text2point(PGpoint *pt, char *text, char **endptr);
static int text2points(PGtypeArgs *args, PGpoint **pts, int *npts);
static int bin2points(PGtypeArgs *args, char *valp, int ptcnt,
	PGpoint **pts, int *npts);
static int putpoints(PGtypeArgs *args, int npts, PGpoint *pts,
	int is_path, int closed);

int
pqt_put_point(PGtypeArgs *args)
{
	unsigned int *buf;
	PGpoint *pt = va_arg(args->ap, PGpoint *);

	PUTNULLCHK(args, pt);

	buf = (unsigned int *) args->put.out;
	pqt_swap8(buf,	   &pt->x, 1);
	pqt_swap8(buf + 2, &pt->y, 1);
	return 16;
}

int
pqt_get_point(PGtypeArgs *args)
{
	DECLVALUE(args);
	PGpoint *pt = va_arg(args->ap, PGpoint *);

	CHKGETVALS(args, pt);

	if (args->format == TEXTFMT)
	{
		if (!text2point(pt, value, NULL))
			RERR_STR2INT(args);

		return 0;
	}

	pqt_swap8(&pt->x, (unsigned int *) value, 0);
	pqt_swap8(&pt->y, ((unsigned int *) (value)) + 2, 0);
	return 0;
}

int
pqt_put_lseg(PGtypeArgs *args)
{
	unsigned int *buf;
	PGlseg *lseg = va_arg(args->ap, PGlseg *);

	PUTNULLCHK(args, lseg);

	buf = (unsigned int *) args->put.out;
	pqt_swap8(buf,     &lseg->pts[0].x, 1);
	pqt_swap8(buf + 2, &lseg->pts[0].y, 1);
	pqt_swap8(buf + 4, &lseg->pts[1].x, 1);
	pqt_swap8(buf + 6, &lseg->pts[1].y, 1);
	return 32;
}

int
pqt_get_lseg(PGtypeArgs *args)
{
	DECLVALUE(args);
	unsigned int *v;
	PGlseg *lseg = va_arg(args->ap, PGlseg *);

	CHKGETVALS(args, lseg);

	if (args->format == TEXTFMT)
	{
		PGpoint *pts = (PGpoint *)lseg;

		if (*value++ != '[' ||
			 !text2point(pts, value, &value) ||
			 *value++ != ',' ||
			 !text2point(pts + 1, value, &value) ||
			 *value != ']')
			RERR_STR2INT(args);

		return 0;
	}

	v = (unsigned int *) value;
	pqt_swap8(&lseg->pts[0].x, v, 0);
	pqt_swap8(&lseg->pts[0].y, v + 2, 0);
	pqt_swap8(&lseg->pts[1].x, v + 4, 0);
	pqt_swap8(&lseg->pts[1].y, v + 6, 0);
	return 0;
}

int
pqt_put_box(PGtypeArgs *args)
{
	unsigned int *buf;
	PGbox *box = va_arg(args->ap, PGbox *);

	PUTNULLCHK(args, box);

	buf = (unsigned int *) args->put.out;
	pqt_swap8(buf,     &box->high.x, 1);
	pqt_swap8(buf + 2, &box->high.y, 1);
	pqt_swap8(buf + 4, &box->low.x,  1);
	pqt_swap8(buf + 6, &box->low.y,  1);
	return 32;
}

int
pqt_get_box(PGtypeArgs *args)
{
	DECLVALUE(args);
	unsigned int *v;
	PGbox *box = va_arg(args->ap, PGbox *);

	CHKGETVALS(args, box);

	if (args->format == TEXTFMT)
	{
		PGpoint *pts = (PGpoint *)box;

		if (!text2point(pts, value, &value) ||
			 *value++ != ',' ||
			 !text2point(pts + 1, value, NULL))
			RERR_STR2INT(args);

		return 0;
	}

	v = (unsigned int *) value;
	pqt_swap8(&box->high.x, v, 0);
	pqt_swap8(&box->high.y, v + 2, 0);
	pqt_swap8(&box->low.x,  v + 4, 0);
	pqt_swap8(&box->low.y,  v + 6, 0);
	return 0;
}

int
pqt_put_circle(PGtypeArgs *args)
{
	unsigned int *buf;
	PGcircle *circle = va_arg(args->ap, PGcircle *);

	PUTNULLCHK(args, circle);

	buf = (unsigned int *) args->put.out;
	pqt_swap8(buf,     &circle->center.x, 1);
	pqt_swap8(buf + 2, &circle->center.y, 1);
	pqt_swap8(buf + 4, &circle->radius,   1);
	return 24;
}

int
pqt_get_circle(PGtypeArgs *args)
{
	DECLVALUE(args);
	unsigned int *v;
	PGcircle *circle = va_arg(args->ap, PGcircle *);

	CHKGETVALS(args, circle);

	if (args->format == TEXTFMT)
	{
		if (*value++ != '<' ||
			 !text2point((PGpoint *)circle, value, &value) ||
			 *value++ != ',' ||
			 !pqt_text_to_float8(&circle->radius, value, &value) ||
			 *value != '>')
			RERR_STR2INT(args);

		return 0;
	}

	v = (unsigned int *) value;
	pqt_swap8(&circle->center.x, v, 0);
	pqt_swap8(&circle->center.y, v + 2, 0);
	pqt_swap8(&circle->radius,   v + 4, 0);
	return 0;
}

int
pqt_put_path(PGtypeArgs *args)
{
	PGpath *path = va_arg(args->ap, PGpath *);
	PUTNULLCHK(args, path);
	return putpoints(args, path->npts, path->pts, 1, path->closed ? 1 : 0);
}

int
pqt_get_path(PGtypeArgs *args)
{
	DECLVALUE(args);
	PGpath *path = va_arg(args->ap, PGpath *);

	CHKGETVALS(args, path);

	if (args->format == TEXTFMT)
	{
		path->closed = *value == '(' ? 1 : 0;
		return text2points(args, &path->pts, &path->npts);
	}

	path->closed = *value ? 1 : 0;
	value++;

	return bin2points(args,
		value + sizeof(int), /* beginning of point array */
		pqt_buf_getint4(value),  /* number of points */
		&path->pts, &path->npts);
}

int
pqt_put_polygon(PGtypeArgs *args)
{
	PGpolygon *polygon = va_arg(args->ap, PGpolygon *);
	PUTNULLCHK(args, polygon);
	return putpoints(args, polygon->npts, polygon->pts, 0, 0);
}

int
pqt_get_polygon(PGtypeArgs *args)
{
	DECLVALUE(args);
	PGpolygon *polygon = va_arg(args->ap, PGpolygon *);

	CHKGETVALS(args, polygon);

	if (args->format == TEXTFMT)
		return text2points(args, &polygon->pts, &polygon->npts);

	return bin2points(args,
		value + sizeof(int), /* beginning of point array */
		pqt_buf_getint4(value),  /* number of points */
		&polygon->pts,
		&polygon->npts);
}


static int
putpoints(PGtypeArgs *args, int npts, PGpoint *pts,
	int is_path, int closed)
{
	int i;
	int datal;
	int hdr = (int) sizeof(int);
	char *out;

	/* pts is for a path, include 1 byte open/closed flag */
	if (is_path)
		hdr++;

	/* length of binary formated path */
	datal = (npts * sizeof(PGpoint)) + hdr;

	/* make sure out is large enough */
	if (args->put.expandBuffer(args, datal) == -1)
		return -1;

	out = args->put.out;
	if (is_path)
		*out++ = closed ? 1 : 0; /* path open/closed flag */

	/* write the number of points as an int32 */
	pqt_buf_putint4(out, npts);
	out += 4;

	/* assign points to the data 'out' buffer */
	for (i=0; i < npts; i++)
	{
		pqt_swap8(out, &pts[i].x, 1);
		out += sizeof(double);

		pqt_swap8(out, &pts[i].y, 1);
		out += sizeof(double);
	}

	return datal;
}

static int
text2points(PGtypeArgs *args, PGpoint **pts, int *npts)
{
	DECLVALUE(args);
	char *s;
	int cnt = 0;
	PGpoint *p = NULL;

	*pts = NULL;
	*npts = 0;

	if (*value != '(' && *value != '[')
		RERR(args, "malformed point array");

	/* get the number of points by counting the '(' */
	for (s=value+1; *s; s++)
	{
		if (*s == '(')
		{
			if (!(s = strchr(s, ')'))) /* skip point contents */
				break;
			cnt++;
		}
	}

	if (cnt == 0)
		return 0; /* empty point list */

	p = (PGpoint *) PQresultAlloc((PGresult *) args->get.result,
		cnt * sizeof(PGpoint));
	if (!p)
		RERR_MEM(args);

	for (cnt=0; *++value; )
	{
		if (!text2point(&p[cnt++], value, &value))
			RERR_STR2INT(args);

		/* done */
		if (*value != ',')
			break;
	}

	*pts = p;
	*npts = cnt;
	return 0;
}

static int
bin2points(PGtypeArgs *args, char *valp, int ptcnt,
	PGpoint **pts, int *npts)
{
	int i;
	PGpoint *p;

	*pts = NULL;
	*npts = 0;

	if (ptcnt == 0)
		return 0;

	p = (PGpoint *) PQresultAlloc((PGresult *) args->get.result,
		ptcnt * sizeof(PGpoint));

	if (!p)
		RERR_MEM(args);

	for (i=0; i < ptcnt; i++)
	{
		pqt_swap8(&p[i].x, valp, 0);
		valp += sizeof(double);

		pqt_swap8(&p[i].y, valp, 0);
		valp += sizeof(double);
	}

	*pts = p;
	*npts = ptcnt;
	return 0;
}

static int
text2point(PGpoint *pt, char *text, char **endptr)
{
	if (*text++ != '(')
		return 0;

	if (!pqt_text_to_float8(&pt->x, text, &text) || *text++ != ',')
		return 0;

	if (!pqt_text_to_float8(&pt->y, text, &text) || *text++ != ')')
		return 0;

	if (endptr)
		*endptr = text;
	return 1;
}