1 
2 /*
3  * geo.c
4  *   Type handler for the geometric data types.
5  *
6  * Copyright (c) 2011 eSilo, LLC. All rights reserved.
7  * This is free software; see the source for copying conditions.  There is
8  * NO warranty; not even for MERCHANTABILITY or  FITNESS FOR A  PARTICULAR
9  * PURPOSE.
10  */
11 
12 #include "libpqtypes-int.h"
13 
14 static int text2point(PGpoint *pt, char *text, char **endptr);
15 static int text2points(PGtypeArgs *args, PGpoint **pts, int *npts);
16 static int bin2points(PGtypeArgs *args, char *valp, int ptcnt,
17 	PGpoint **pts, int *npts);
18 static int putpoints(PGtypeArgs *args, int npts, PGpoint *pts,
19 	int is_path, int closed);
20 
21 int
pqt_put_point(PGtypeArgs * args)22 pqt_put_point(PGtypeArgs *args)
23 {
24 	unsigned int *buf;
25 	PGpoint *pt = va_arg(args->ap, PGpoint *);
26 
27 	PUTNULLCHK(args, pt);
28 
29 	buf = (unsigned int *) args->put.out;
30 	pqt_swap8(buf,	   &pt->x, 1);
31 	pqt_swap8(buf + 2, &pt->y, 1);
32 	return 16;
33 }
34 
35 int
pqt_get_point(PGtypeArgs * args)36 pqt_get_point(PGtypeArgs *args)
37 {
38 	DECLVALUE(args);
39 	PGpoint *pt = va_arg(args->ap, PGpoint *);
40 
41 	CHKGETVALS(args, pt);
42 
43 	if (args->format == TEXTFMT)
44 	{
45 		if (!text2point(pt, value, NULL))
46 			RERR_STR2INT(args);
47 
48 		return 0;
49 	}
50 
51 	pqt_swap8(&pt->x, (unsigned int *) value, 0);
52 	pqt_swap8(&pt->y, ((unsigned int *) (value)) + 2, 0);
53 	return 0;
54 }
55 
56 int
pqt_put_lseg(PGtypeArgs * args)57 pqt_put_lseg(PGtypeArgs *args)
58 {
59 	unsigned int *buf;
60 	PGlseg *lseg = va_arg(args->ap, PGlseg *);
61 
62 	PUTNULLCHK(args, lseg);
63 
64 	buf = (unsigned int *) args->put.out;
65 	pqt_swap8(buf,     &lseg->pts[0].x, 1);
66 	pqt_swap8(buf + 2, &lseg->pts[0].y, 1);
67 	pqt_swap8(buf + 4, &lseg->pts[1].x, 1);
68 	pqt_swap8(buf + 6, &lseg->pts[1].y, 1);
69 	return 32;
70 }
71 
72 int
pqt_get_lseg(PGtypeArgs * args)73 pqt_get_lseg(PGtypeArgs *args)
74 {
75 	DECLVALUE(args);
76 	unsigned int *v;
77 	PGlseg *lseg = va_arg(args->ap, PGlseg *);
78 
79 	CHKGETVALS(args, lseg);
80 
81 	if (args->format == TEXTFMT)
82 	{
83 		PGpoint *pts = (PGpoint *)lseg;
84 
85 		if (*value++ != '[' ||
86 			 !text2point(pts, value, &value) ||
87 			 *value++ != ',' ||
88 			 !text2point(pts + 1, value, &value) ||
89 			 *value != ']')
90 			RERR_STR2INT(args);
91 
92 		return 0;
93 	}
94 
95 	v = (unsigned int *) value;
96 	pqt_swap8(&lseg->pts[0].x, v, 0);
97 	pqt_swap8(&lseg->pts[0].y, v + 2, 0);
98 	pqt_swap8(&lseg->pts[1].x, v + 4, 0);
99 	pqt_swap8(&lseg->pts[1].y, v + 6, 0);
100 	return 0;
101 }
102 
103 int
pqt_put_box(PGtypeArgs * args)104 pqt_put_box(PGtypeArgs *args)
105 {
106 	unsigned int *buf;
107 	PGbox *box = va_arg(args->ap, PGbox *);
108 
109 	PUTNULLCHK(args, box);
110 
111 	buf = (unsigned int *) args->put.out;
112 	pqt_swap8(buf,     &box->high.x, 1);
113 	pqt_swap8(buf + 2, &box->high.y, 1);
114 	pqt_swap8(buf + 4, &box->low.x,  1);
115 	pqt_swap8(buf + 6, &box->low.y,  1);
116 	return 32;
117 }
118 
119 int
pqt_get_box(PGtypeArgs * args)120 pqt_get_box(PGtypeArgs *args)
121 {
122 	DECLVALUE(args);
123 	unsigned int *v;
124 	PGbox *box = va_arg(args->ap, PGbox *);
125 
126 	CHKGETVALS(args, box);
127 
128 	if (args->format == TEXTFMT)
129 	{
130 		PGpoint *pts = (PGpoint *)box;
131 
132 		if (!text2point(pts, value, &value) ||
133 			 *value++ != ',' ||
134 			 !text2point(pts + 1, value, NULL))
135 			RERR_STR2INT(args);
136 
137 		return 0;
138 	}
139 
140 	v = (unsigned int *) value;
141 	pqt_swap8(&box->high.x, v, 0);
142 	pqt_swap8(&box->high.y, v + 2, 0);
143 	pqt_swap8(&box->low.x,  v + 4, 0);
144 	pqt_swap8(&box->low.y,  v + 6, 0);
145 	return 0;
146 }
147 
148 int
pqt_put_circle(PGtypeArgs * args)149 pqt_put_circle(PGtypeArgs *args)
150 {
151 	unsigned int *buf;
152 	PGcircle *circle = va_arg(args->ap, PGcircle *);
153 
154 	PUTNULLCHK(args, circle);
155 
156 	buf = (unsigned int *) args->put.out;
157 	pqt_swap8(buf,     &circle->center.x, 1);
158 	pqt_swap8(buf + 2, &circle->center.y, 1);
159 	pqt_swap8(buf + 4, &circle->radius,   1);
160 	return 24;
161 }
162 
163 int
pqt_get_circle(PGtypeArgs * args)164 pqt_get_circle(PGtypeArgs *args)
165 {
166 	DECLVALUE(args);
167 	unsigned int *v;
168 	PGcircle *circle = va_arg(args->ap, PGcircle *);
169 
170 	CHKGETVALS(args, circle);
171 
172 	if (args->format == TEXTFMT)
173 	{
174 		if (*value++ != '<' ||
175 			 !text2point((PGpoint *)circle, value, &value) ||
176 			 *value++ != ',' ||
177 			 !pqt_text_to_float8(&circle->radius, value, &value) ||
178 			 *value != '>')
179 			RERR_STR2INT(args);
180 
181 		return 0;
182 	}
183 
184 	v = (unsigned int *) value;
185 	pqt_swap8(&circle->center.x, v, 0);
186 	pqt_swap8(&circle->center.y, v + 2, 0);
187 	pqt_swap8(&circle->radius,   v + 4, 0);
188 	return 0;
189 }
190 
191 int
pqt_put_path(PGtypeArgs * args)192 pqt_put_path(PGtypeArgs *args)
193 {
194 	PGpath *path = va_arg(args->ap, PGpath *);
195 	PUTNULLCHK(args, path);
196 	return putpoints(args, path->npts, path->pts, 1, path->closed ? 1 : 0);
197 }
198 
199 int
pqt_get_path(PGtypeArgs * args)200 pqt_get_path(PGtypeArgs *args)
201 {
202 	DECLVALUE(args);
203 	PGpath *path = va_arg(args->ap, PGpath *);
204 
205 	CHKGETVALS(args, path);
206 
207 	if (args->format == TEXTFMT)
208 	{
209 		path->closed = *value == '(' ? 1 : 0;
210 		return text2points(args, &path->pts, &path->npts);
211 	}
212 
213 	path->closed = *value ? 1 : 0;
214 	value++;
215 
216 	return bin2points(args,
217 		value + sizeof(int), /* beginning of point array */
218 		pqt_buf_getint4(value),  /* number of points */
219 		&path->pts, &path->npts);
220 }
221 
222 int
pqt_put_polygon(PGtypeArgs * args)223 pqt_put_polygon(PGtypeArgs *args)
224 {
225 	PGpolygon *polygon = va_arg(args->ap, PGpolygon *);
226 	PUTNULLCHK(args, polygon);
227 	return putpoints(args, polygon->npts, polygon->pts, 0, 0);
228 }
229 
230 int
pqt_get_polygon(PGtypeArgs * args)231 pqt_get_polygon(PGtypeArgs *args)
232 {
233 	DECLVALUE(args);
234 	PGpolygon *polygon = va_arg(args->ap, PGpolygon *);
235 
236 	CHKGETVALS(args, polygon);
237 
238 	if (args->format == TEXTFMT)
239 		return text2points(args, &polygon->pts, &polygon->npts);
240 
241 	return bin2points(args,
242 		value + sizeof(int), /* beginning of point array */
243 		pqt_buf_getint4(value),  /* number of points */
244 		&polygon->pts,
245 		&polygon->npts);
246 }
247 
248 
249 static int
putpoints(PGtypeArgs * args,int npts,PGpoint * pts,int is_path,int closed)250 putpoints(PGtypeArgs *args, int npts, PGpoint *pts,
251 	int is_path, int closed)
252 {
253 	int i;
254 	int datal;
255 	int hdr = (int) sizeof(int);
256 	char *out;
257 
258 	/* pts is for a path, include 1 byte open/closed flag */
259 	if (is_path)
260 		hdr++;
261 
262 	/* length of binary formated path */
263 	datal = (npts * sizeof(PGpoint)) + hdr;
264 
265 	/* make sure out is large enough */
266 	if (args->put.expandBuffer(args, datal) == -1)
267 		return -1;
268 
269 	out = args->put.out;
270 	if (is_path)
271 		*out++ = closed ? 1 : 0; /* path open/closed flag */
272 
273 	/* write the number of points as an int32 */
274 	pqt_buf_putint4(out, npts);
275 	out += 4;
276 
277 	/* assign points to the data 'out' buffer */
278 	for (i=0; i < npts; i++)
279 	{
280 		pqt_swap8(out, &pts[i].x, 1);
281 		out += sizeof(double);
282 
283 		pqt_swap8(out, &pts[i].y, 1);
284 		out += sizeof(double);
285 	}
286 
287 	return datal;
288 }
289 
290 static int
text2points(PGtypeArgs * args,PGpoint ** pts,int * npts)291 text2points(PGtypeArgs *args, PGpoint **pts, int *npts)
292 {
293 	DECLVALUE(args);
294 	char *s;
295 	int cnt = 0;
296 	PGpoint *p = NULL;
297 
298 	*pts = NULL;
299 	*npts = 0;
300 
301 	if (*value != '(' && *value != '[')
302 		RERR(args, "malformed point array");
303 
304 	/* get the number of points by counting the '(' */
305 	for (s=value+1; *s; s++)
306 	{
307 		if (*s == '(')
308 		{
309 			if (!(s = strchr(s, ')'))) /* skip point contents */
310 				break;
311 			cnt++;
312 		}
313 	}
314 
315 	if (cnt == 0)
316 		return 0; /* empty point list */
317 
318 	p = (PGpoint *) PQresultAlloc((PGresult *) args->get.result,
319 		cnt * sizeof(PGpoint));
320 	if (!p)
321 		RERR_MEM(args);
322 
323 	for (cnt=0; *++value; )
324 	{
325 		if (!text2point(&p[cnt++], value, &value))
326 			RERR_STR2INT(args);
327 
328 		/* done */
329 		if (*value != ',')
330 			break;
331 	}
332 
333 	*pts = p;
334 	*npts = cnt;
335 	return 0;
336 }
337 
338 static int
bin2points(PGtypeArgs * args,char * valp,int ptcnt,PGpoint ** pts,int * npts)339 bin2points(PGtypeArgs *args, char *valp, int ptcnt,
340 	PGpoint **pts, int *npts)
341 {
342 	int i;
343 	PGpoint *p;
344 
345 	*pts = NULL;
346 	*npts = 0;
347 
348 	if (ptcnt == 0)
349 		return 0;
350 
351 	p = (PGpoint *) PQresultAlloc((PGresult *) args->get.result,
352 		ptcnt * sizeof(PGpoint));
353 
354 	if (!p)
355 		RERR_MEM(args);
356 
357 	for (i=0; i < ptcnt; i++)
358 	{
359 		pqt_swap8(&p[i].x, valp, 0);
360 		valp += sizeof(double);
361 
362 		pqt_swap8(&p[i].y, valp, 0);
363 		valp += sizeof(double);
364 	}
365 
366 	*pts = p;
367 	*npts = ptcnt;
368 	return 0;
369 }
370 
371 static int
text2point(PGpoint * pt,char * text,char ** endptr)372 text2point(PGpoint *pt, char *text, char **endptr)
373 {
374 	if (*text++ != '(')
375 		return 0;
376 
377 	if (!pqt_text_to_float8(&pt->x, text, &text) || *text++ != ',')
378 		return 0;
379 
380 	if (!pqt_text_to_float8(&pt->y, text, &text) || *text++ != ')')
381 		return 0;
382 
383 	if (endptr)
384 		*endptr = text;
385 	return 1;
386 }
387 
388 
389 
390 
391 
392