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