1 2 /* 3 * geo.c 4 * Type handler for the geometric data types. 5 * 6 * Copyright (c) 2009 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 } |