PostGIS  2.5.0dev-r@@SVN_REVISION@@
lwout_wkb.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2009 Paul Ramsey <pramsey@cleverelephant.ca>
22  *
23  **********************************************************************/
24 
25 
26 #include <math.h>
27 
28 #include "liblwgeom_internal.h"
29 #include "lwgeom_log.h"
30 
31 static uint8_t* lwgeom_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant);
32 static size_t lwgeom_to_wkb_size(const LWGEOM *geom, uint8_t variant);
33 
34 /*
35 * Look-up table for hex writer
36 */
37 static char *hexchr = "0123456789ABCDEF";
38 
39 char* hexbytes_from_bytes(const uint8_t *bytes, size_t size)
40 {
41  char *hex;
42  uint32_t i;
43  if ( ! bytes || ! size )
44  {
45  lwerror("hexbutes_from_bytes: invalid input");
46  return NULL;
47  }
48  hex = lwalloc(size * 2 + 1);
49  hex[2*size] = '\0';
50  for( i = 0; i < size; i++ )
51  {
52  /* Top four bits to 0-F */
53  hex[2*i] = hexchr[bytes[i] >> 4];
54  /* Bottom four bits to 0-F */
55  hex[2*i+1] = hexchr[bytes[i] & 0x0F];
56  }
57  return hex;
58 }
59 
60 /*
61 * Optional SRID
62 */
63 static int lwgeom_wkb_needs_srid(const LWGEOM *geom, uint8_t variant)
64 {
65  /* Sub-components of collections inherit their SRID from the parent.
66  We force that behavior with the WKB_NO_SRID flag */
67  if ( variant & WKB_NO_SRID )
68  return LW_FALSE;
69 
70  /* We can only add an SRID if the geometry has one, and the
71  WKB form is extended */
72  if ( (variant & WKB_EXTENDED) && lwgeom_has_srid(geom) )
73  return LW_TRUE;
74 
75  /* Everything else doesn't get an SRID */
76  return LW_FALSE;
77 }
78 
79 /*
80 * GeometryType
81 */
83 {
84  uint32_t wkb_type = 0;
85 
86  switch ( geom->type )
87  {
88  case POINTTYPE:
89  wkb_type = WKB_POINT_TYPE;
90  break;
91  case LINETYPE:
92  wkb_type = WKB_LINESTRING_TYPE;
93  break;
94  case POLYGONTYPE:
95  wkb_type = WKB_POLYGON_TYPE;
96  break;
97  case MULTIPOINTTYPE:
98  wkb_type = WKB_MULTIPOINT_TYPE;
99  break;
100  case MULTILINETYPE:
101  wkb_type = WKB_MULTILINESTRING_TYPE;
102  break;
103  case MULTIPOLYGONTYPE:
104  wkb_type = WKB_MULTIPOLYGON_TYPE;
105  break;
106  case COLLECTIONTYPE:
107  wkb_type = WKB_GEOMETRYCOLLECTION_TYPE;
108  break;
109  case CIRCSTRINGTYPE:
110  wkb_type = WKB_CIRCULARSTRING_TYPE;
111  break;
112  case COMPOUNDTYPE:
113  wkb_type = WKB_COMPOUNDCURVE_TYPE;
114  break;
115  case CURVEPOLYTYPE:
116  wkb_type = WKB_CURVEPOLYGON_TYPE;
117  break;
118  case MULTICURVETYPE:
119  wkb_type = WKB_MULTICURVE_TYPE;
120  break;
121  case MULTISURFACETYPE:
122  wkb_type = WKB_MULTISURFACE_TYPE;
123  break;
125  wkb_type = WKB_POLYHEDRALSURFACE_TYPE;
126  break;
127  case TINTYPE:
128  wkb_type = WKB_TIN_TYPE;
129  break;
130  case TRIANGLETYPE:
131  wkb_type = WKB_TRIANGLE_TYPE;
132  break;
133  default:
134  lwerror("Unsupported geometry type: %s [%d]",
135  lwtype_name(geom->type), geom->type);
136  }
137 
138  if ( variant & WKB_EXTENDED )
139  {
140  if ( FLAGS_GET_Z(geom->flags) )
141  wkb_type |= WKBZOFFSET;
142  if ( FLAGS_GET_M(geom->flags) )
143  wkb_type |= WKBMOFFSET;
144 /* if ( geom->srid != SRID_UNKNOWN && ! (variant & WKB_NO_SRID) ) */
145  if ( lwgeom_wkb_needs_srid(geom, variant) )
146  wkb_type |= WKBSRIDFLAG;
147  }
148  else if ( variant & WKB_ISO )
149  {
150  /* Z types are in the 1000 range */
151  if ( FLAGS_GET_Z(geom->flags) )
152  wkb_type += 1000;
153  /* M types are in the 2000 range */
154  if ( FLAGS_GET_M(geom->flags) )
155  wkb_type += 2000;
156  /* ZM types are in the 1000 + 2000 = 3000 range, see above */
157  }
158  return wkb_type;
159 }
160 
161 /*
162 * Endian
163 */
165 {
166  if ( variant & WKB_HEX )
167  {
168  buf[0] = '0';
169  buf[1] = ((variant & WKB_NDR) ? '1' : '0');
170  return buf + 2;
171  }
172  else
173  {
174  buf[0] = ((variant & WKB_NDR) ? 1 : 0);
175  return buf + 1;
176  }
177 }
178 
179 /*
180 * SwapBytes?
181 */
182 static inline int wkb_swap_bytes(uint8_t variant)
183 {
184  /* If requested variant matches machine arch, we don't have to swap! */
185  if ( ((variant & WKB_NDR) && (getMachineEndian() == NDR)) ||
186  ((! (variant & WKB_NDR)) && (getMachineEndian() == XDR)) )
187  {
188  return LW_FALSE;
189  }
190  return LW_TRUE;
191 }
192 
193 /*
194 * Integer32
195 */
196 static uint8_t* integer_to_wkb_buf(const int ival, uint8_t *buf, uint8_t variant)
197 {
198  char *iptr = (char*)(&ival);
199  int i = 0;
200 
201  if ( sizeof(int) != WKB_INT_SIZE )
202  {
203  lwerror("Machine int size is not %d bytes!", WKB_INT_SIZE);
204  }
205  LWDEBUGF(4, "Writing value '%u'", ival);
206  if ( variant & WKB_HEX )
207  {
208  int swap = wkb_swap_bytes(variant);
209  /* Machine/request arch mismatch, so flip byte order */
210  for ( i = 0; i < WKB_INT_SIZE; i++ )
211  {
212  int j = (swap ? WKB_INT_SIZE - 1 - i : i);
213  uint8_t b = iptr[j];
214  /* Top four bits to 0-F */
215  buf[2*i] = hexchr[b >> 4];
216  /* Bottom four bits to 0-F */
217  buf[2*i+1] = hexchr[b & 0x0F];
218  }
219  return buf + (2 * WKB_INT_SIZE);
220  }
221  else
222  {
223  /* Machine/request arch mismatch, so flip byte order */
224  if ( wkb_swap_bytes(variant) )
225  {
226  for ( i = 0; i < WKB_INT_SIZE; i++ )
227  {
228  buf[i] = iptr[WKB_INT_SIZE - 1 - i];
229  }
230  }
231  /* If machine arch and requested arch match, don't flip byte order */
232  else
233  {
234  memcpy(buf, iptr, WKB_INT_SIZE);
235  }
236  return buf + WKB_INT_SIZE;
237  }
238 }
239 
240 /*
241 * Float64
242 */
243 static uint8_t* double_to_wkb_buf(const double d, uint8_t *buf, uint8_t variant)
244 {
245  char *dptr = (char*)(&d);
246  int i = 0;
247 
248  if ( sizeof(double) != WKB_DOUBLE_SIZE )
249  {
250  lwerror("Machine double size is not %d bytes!", WKB_DOUBLE_SIZE);
251  }
252 
253  if ( variant & WKB_HEX )
254  {
255  int swap = wkb_swap_bytes(variant);
256  /* Machine/request arch mismatch, so flip byte order */
257  for ( i = 0; i < WKB_DOUBLE_SIZE; i++ )
258  {
259  int j = (swap ? WKB_DOUBLE_SIZE - 1 - i : i);
260  uint8_t b = dptr[j];
261  /* Top four bits to 0-F */
262  buf[2*i] = hexchr[b >> 4];
263  /* Bottom four bits to 0-F */
264  buf[2*i+1] = hexchr[b & 0x0F];
265  }
266  return buf + (2 * WKB_DOUBLE_SIZE);
267  }
268  else
269  {
270  /* Machine/request arch mismatch, so flip byte order */
271  if ( wkb_swap_bytes(variant) )
272  {
273  for ( i = 0; i < WKB_DOUBLE_SIZE; i++ )
274  {
275  buf[i] = dptr[WKB_DOUBLE_SIZE - 1 - i];
276  }
277  }
278  /* If machine arch and requested arch match, don't flip byte order */
279  else
280  {
281  memcpy(buf, dptr, WKB_DOUBLE_SIZE);
282  }
283  return buf + WKB_DOUBLE_SIZE;
284  }
285 }
286 
287 
288 /*
289 * Empty
290 */
291 static size_t empty_to_wkb_size(const LWGEOM *geom, uint8_t variant)
292 {
293  /* endian byte + type integer */
294  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE;
295 
296  /* optional srid integer */
297  if ( lwgeom_wkb_needs_srid(geom, variant) )
298  size += WKB_INT_SIZE;
299 
300  /* Represent POINT EMPTY as POINT(NaN NaN) */
301  if ( geom->type == POINTTYPE )
302  {
303  const LWPOINT *pt = (LWPOINT*)geom;
304  size += WKB_DOUBLE_SIZE * FLAGS_NDIMS(pt->point->flags);
305  }
306  /* num-elements */
307  else
308  {
309  size += WKB_INT_SIZE;
310  }
311 
312  return size;
313 }
314 
316 {
317  uint32_t wkb_type = lwgeom_wkb_type(geom, variant);
318 
319  /* Set the endian flag */
320  buf = endian_to_wkb_buf(buf, variant);
321 
322  /* Set the geometry type */
323  buf = integer_to_wkb_buf(wkb_type, buf, variant);
324 
325  /* Set the SRID if necessary */
326  if ( lwgeom_wkb_needs_srid(geom, variant) )
327  buf = integer_to_wkb_buf(geom->srid, buf, variant);
328 
329  /* Represent POINT EMPTY as POINT(NaN NaN) */
330  if ( geom->type == POINTTYPE )
331  {
332  const LWPOINT *pt = (LWPOINT*)geom;
333  static double nn = NAN;
334  int i;
335  for ( i = 0; i < FLAGS_NDIMS(pt->point->flags); i++ )
336  {
337  buf = double_to_wkb_buf(nn, buf, variant);
338  }
339  }
340  /* Everything else is flagged as empty using num-elements == 0 */
341  else
342  {
343  /* Set nrings/npoints/ngeoms to zero */
344  buf = integer_to_wkb_buf(0, buf, variant);
345  }
346 
347  return buf;
348 }
349 
350 /*
351 * POINTARRAY
352 */
354 {
355  int dims = 2;
356  size_t size = 0;
357 
358  if ( variant & (WKB_ISO | WKB_EXTENDED) )
359  dims = FLAGS_NDIMS(pa->flags);
360 
361  /* Include the npoints if it's not a POINT type) */
362  if ( ! ( variant & WKB_NO_NPOINTS ) )
363  size += WKB_INT_SIZE;
364 
365  /* size of the double list */
366  size += pa->npoints * dims * WKB_DOUBLE_SIZE;
367 
368  return size;
369 }
370 
372 {
373  uint32_t dims = 2;
374  uint32_t pa_dims = FLAGS_NDIMS(pa->flags);
375  uint32_t i, j;
376  double *dbl_ptr;
377 
378  /* SFSQL is always 2-d. Extended and ISO use all available dimensions */
379  if ( (variant & WKB_ISO) || (variant & WKB_EXTENDED) )
380  dims = pa_dims;
381 
382  /* Set the number of points (if it's not a POINT type) */
383  if ( ! ( variant & WKB_NO_NPOINTS ) )
384  buf = integer_to_wkb_buf(pa->npoints, buf, variant);
385 
386  /* Bulk copy the coordinates when: dimensionality matches, output format */
387  /* is not hex, and output endian matches internal endian. */
388  if ( pa->npoints && (dims == pa_dims) && ! wkb_swap_bytes(variant) && ! (variant & WKB_HEX) )
389  {
390  size_t size = pa->npoints * dims * WKB_DOUBLE_SIZE;
391  memcpy(buf, getPoint_internal(pa, 0), size);
392  buf += size;
393  }
394  /* Copy coordinates one-by-one otherwise */
395  else
396  {
397  for ( i = 0; i < pa->npoints; i++ )
398  {
399  LWDEBUGF(4, "Writing point #%d", i);
400  dbl_ptr = (double*)getPoint_internal(pa, i);
401  for ( j = 0; j < dims; j++ )
402  {
403  LWDEBUGF(4, "Writing dimension #%d (buf = %p)", j, buf);
404  buf = double_to_wkb_buf(dbl_ptr[j], buf, variant);
405  }
406  }
407  }
408  LWDEBUGF(4, "Done (buf = %p)", buf);
409  return buf;
410 }
411 
412 /*
413 * POINT
414 */
415 static size_t lwpoint_to_wkb_size(const LWPOINT *pt, uint8_t variant)
416 {
417  /* Endian flag + type number */
418  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE;
419 
420  /* Only process empty at this level in the EXTENDED case */
421  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)pt) )
422  return empty_to_wkb_size((LWGEOM*)pt, variant);
423 
424  /* Extended WKB needs space for optional SRID integer */
425  if ( lwgeom_wkb_needs_srid((LWGEOM*)pt, variant) )
426  size += WKB_INT_SIZE;
427 
428  /* Points */
429  size += ptarray_to_wkb_size(pt->point, variant | WKB_NO_NPOINTS);
430  return size;
431 }
432 
434 {
435  /* Only process empty at this level in the EXTENDED case */
436  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)pt) )
437  return empty_to_wkb_buf((LWGEOM*)pt, buf, variant);
438 
439  /* Set the endian flag */
440  LWDEBUGF(4, "Entering function, buf = %p", buf);
441  buf = endian_to_wkb_buf(buf, variant);
442  LWDEBUGF(4, "Endian set, buf = %p", buf);
443  /* Set the geometry type */
444  buf = integer_to_wkb_buf(lwgeom_wkb_type((LWGEOM*)pt, variant), buf, variant);
445  LWDEBUGF(4, "Type set, buf = %p", buf);
446  /* Set the optional SRID for extended variant */
447  if ( lwgeom_wkb_needs_srid((LWGEOM*)pt, variant) )
448  {
449  buf = integer_to_wkb_buf(pt->srid, buf, variant);
450  LWDEBUGF(4, "SRID set, buf = %p", buf);
451  }
452  /* Set the coordinates */
453  buf = ptarray_to_wkb_buf(pt->point, buf, variant | WKB_NO_NPOINTS);
454  LWDEBUGF(4, "Pointarray set, buf = %p", buf);
455  return buf;
456 }
457 
458 /*
459 * LINESTRING, CIRCULARSTRING
460 */
461 static size_t lwline_to_wkb_size(const LWLINE *line, uint8_t variant)
462 {
463  /* Endian flag + type number */
464  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE;
465 
466  /* Only process empty at this level in the EXTENDED case */
467  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)line) )
468  return empty_to_wkb_size((LWGEOM*)line, variant);
469 
470  /* Extended WKB needs space for optional SRID integer */
471  if ( lwgeom_wkb_needs_srid((LWGEOM*)line, variant) )
472  size += WKB_INT_SIZE;
473 
474  /* Size of point array */
475  size += ptarray_to_wkb_size(line->points, variant);
476  return size;
477 }
478 
480 {
481  /* Only process empty at this level in the EXTENDED case */
482  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)line) )
483  return empty_to_wkb_buf((LWGEOM*)line, buf, variant);
484 
485  /* Set the endian flag */
486  buf = endian_to_wkb_buf(buf, variant);
487  /* Set the geometry type */
488  buf = integer_to_wkb_buf(lwgeom_wkb_type((LWGEOM*)line, variant), buf, variant);
489  /* Set the optional SRID for extended variant */
490  if ( lwgeom_wkb_needs_srid((LWGEOM*)line, variant) )
491  buf = integer_to_wkb_buf(line->srid, buf, variant);
492  /* Set the coordinates */
493  buf = ptarray_to_wkb_buf(line->points, buf, variant);
494  return buf;
495 }
496 
497 /*
498 * TRIANGLE
499 */
501 {
502  /* endian flag + type number + number of rings */
503  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE + WKB_INT_SIZE;
504 
505  /* Only process empty at this level in the EXTENDED case */
506  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)tri) )
507  return empty_to_wkb_size((LWGEOM*)tri, variant);
508 
509  /* Extended WKB needs space for optional SRID integer */
510  if ( lwgeom_wkb_needs_srid((LWGEOM*)tri, variant) )
511  size += WKB_INT_SIZE;
512 
513  /* How big is this point array? */
514  size += ptarray_to_wkb_size(tri->points, variant);
515 
516  return size;
517 }
518 
520 {
521  /* Only process empty at this level in the EXTENDED case */
522  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)tri) )
523  return empty_to_wkb_buf((LWGEOM*)tri, buf, variant);
524 
525  /* Set the endian flag */
526  buf = endian_to_wkb_buf(buf, variant);
527 
528  /* Set the geometry type */
529  buf = integer_to_wkb_buf(lwgeom_wkb_type((LWGEOM*)tri, variant), buf, variant);
530 
531  /* Set the optional SRID for extended variant */
532  if ( lwgeom_wkb_needs_srid((LWGEOM*)tri, variant) )
533  buf = integer_to_wkb_buf(tri->srid, buf, variant);
534 
535  /* Set the number of rings (only one, it's a triangle, buddy) */
536  buf = integer_to_wkb_buf(1, buf, variant);
537 
538  /* Write that ring */
539  buf = ptarray_to_wkb_buf(tri->points, buf, variant);
540 
541  return buf;
542 }
543 
544 /*
545 * POLYGON
546 */
547 static size_t lwpoly_to_wkb_size(const LWPOLY *poly, uint8_t variant)
548 {
549  /* endian flag + type number + number of rings */
550  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE + WKB_INT_SIZE;
551  uint32_t i = 0;
552 
553  /* Only process empty at this level in the EXTENDED case */
554  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)poly) )
555  return empty_to_wkb_size((LWGEOM*)poly, variant);
556 
557  /* Extended WKB needs space for optional SRID integer */
558  if ( lwgeom_wkb_needs_srid((LWGEOM*)poly, variant) )
559  size += WKB_INT_SIZE;
560 
561  for ( i = 0; i < poly->nrings; i++ )
562  {
563  /* Size of ring point array */
564  size += ptarray_to_wkb_size(poly->rings[i], variant);
565  }
566 
567  return size;
568 }
569 
571 {
572  uint32_t i;
573 
574  /* Only process empty at this level in the EXTENDED case */
575  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)poly) )
576  return empty_to_wkb_buf((LWGEOM*)poly, buf, variant);
577 
578  /* Set the endian flag */
579  buf = endian_to_wkb_buf(buf, variant);
580  /* Set the geometry type */
581  buf = integer_to_wkb_buf(lwgeom_wkb_type((LWGEOM*)poly, variant), buf, variant);
582  /* Set the optional SRID for extended variant */
583  if ( lwgeom_wkb_needs_srid((LWGEOM*)poly, variant) )
584  buf = integer_to_wkb_buf(poly->srid, buf, variant);
585  /* Set the number of rings */
586  buf = integer_to_wkb_buf(poly->nrings, buf, variant);
587 
588  for ( i = 0; i < poly->nrings; i++ )
589  {
590  buf = ptarray_to_wkb_buf(poly->rings[i], buf, variant);
591  }
592 
593  return buf;
594 }
595 
596 
597 /*
598 * MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION
599 * MULTICURVE, COMPOUNDCURVE, MULTISURFACE, CURVEPOLYGON, TIN,
600 * POLYHEDRALSURFACE
601 */
603 {
604  /* Endian flag + type number + number of subgeoms */
605  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE + WKB_INT_SIZE;
606  uint32_t i = 0;
607 
608  /* Extended WKB needs space for optional SRID integer */
609  if ( lwgeom_wkb_needs_srid((LWGEOM*)col, variant) )
610  size += WKB_INT_SIZE;
611 
612  for ( i = 0; i < col->ngeoms; i++ )
613  {
614  /* size of subgeom */
615  size += lwgeom_to_wkb_size((LWGEOM*)col->geoms[i], variant | WKB_NO_SRID);
616  }
617 
618  return size;
619 }
620 
622 {
623  uint32_t i;
624 
625  /* Set the endian flag */
626  buf = endian_to_wkb_buf(buf, variant);
627  /* Set the geometry type */
628  buf = integer_to_wkb_buf(lwgeom_wkb_type((LWGEOM*)col, variant), buf, variant);
629  /* Set the optional SRID for extended variant */
630  if ( lwgeom_wkb_needs_srid((LWGEOM*)col, variant) )
631  buf = integer_to_wkb_buf(col->srid, buf, variant);
632  /* Set the number of sub-geometries */
633  buf = integer_to_wkb_buf(col->ngeoms, buf, variant);
634 
635  /* Write the sub-geometries. Sub-geometries do not get SRIDs, they
636  inherit from their parents. */
637  for ( i = 0; i < col->ngeoms; i++ )
638  {
639  buf = lwgeom_to_wkb_buf(col->geoms[i], buf, variant | WKB_NO_SRID);
640  }
641 
642  return buf;
643 }
644 
645 /*
646 * GEOMETRY
647 */
648 static size_t lwgeom_to_wkb_size(const LWGEOM *geom, uint8_t variant)
649 {
650  size_t size = 0;
651 
652  if ( geom == NULL )
653  return 0;
654 
655  /* Short circuit out empty geometries */
656  if ( (!(variant & WKB_EXTENDED)) && lwgeom_is_empty(geom) )
657  {
658  return empty_to_wkb_size(geom, variant);
659  }
660 
661  switch ( geom->type )
662  {
663  case POINTTYPE:
664  size += lwpoint_to_wkb_size((LWPOINT*)geom, variant);
665  break;
666 
667  /* LineString and CircularString both have points elements */
668  case CIRCSTRINGTYPE:
669  case LINETYPE:
670  size += lwline_to_wkb_size((LWLINE*)geom, variant);
671  break;
672 
673  /* Polygon has nrings and rings elements */
674  case POLYGONTYPE:
675  size += lwpoly_to_wkb_size((LWPOLY*)geom, variant);
676  break;
677 
678  /* Triangle has one ring of three points */
679  case TRIANGLETYPE:
680  size += lwtriangle_to_wkb_size((LWTRIANGLE*)geom, variant);
681  break;
682 
683  /* All these Collection types have ngeoms and geoms elements */
684  case MULTIPOINTTYPE:
685  case MULTILINETYPE:
686  case MULTIPOLYGONTYPE:
687  case COMPOUNDTYPE:
688  case CURVEPOLYTYPE:
689  case MULTICURVETYPE:
690  case MULTISURFACETYPE:
691  case COLLECTIONTYPE:
693  case TINTYPE:
694  size += lwcollection_to_wkb_size((LWCOLLECTION*)geom, variant);
695  break;
696 
697  /* Unknown type! */
698  default:
699  lwerror("Unsupported geometry type: %s [%d]", lwtype_name(geom->type), geom->type);
700  }
701 
702  return size;
703 }
704 
705 /* TODO handle the TRIANGLE type properly */
706 
708 {
709 
710  /* Do not simplify empties when outputting to canonical form */
711  if (lwgeom_is_empty(geom) && !(variant & WKB_EXTENDED))
712  return empty_to_wkb_buf(geom, buf, variant);
713 
714  switch ( geom->type )
715  {
716  case POINTTYPE:
717  return lwpoint_to_wkb_buf((LWPOINT*)geom, buf, variant);
718 
719  /* LineString and CircularString both have 'points' elements */
720  case CIRCSTRINGTYPE:
721  case LINETYPE:
722  return lwline_to_wkb_buf((LWLINE*)geom, buf, variant);
723 
724  /* Polygon has 'nrings' and 'rings' elements */
725  case POLYGONTYPE:
726  return lwpoly_to_wkb_buf((LWPOLY*)geom, buf, variant);
727 
728  /* Triangle has one ring of three points */
729  case TRIANGLETYPE:
730  return lwtriangle_to_wkb_buf((LWTRIANGLE*)geom, buf, variant);
731 
732  /* All these Collection types have 'ngeoms' and 'geoms' elements */
733  case MULTIPOINTTYPE:
734  case MULTILINETYPE:
735  case MULTIPOLYGONTYPE:
736  case COMPOUNDTYPE:
737  case CURVEPOLYTYPE:
738  case MULTICURVETYPE:
739  case MULTISURFACETYPE:
740  case COLLECTIONTYPE:
742  case TINTYPE:
743  return lwcollection_to_wkb_buf((LWCOLLECTION*)geom, buf, variant);
744 
745  /* Unknown type! */
746  default:
747  lwerror("Unsupported geometry type: %s [%d]", lwtype_name(geom->type), geom->type);
748  }
749  /* Return value to keep compiler happy. */
750  return 0;
751 }
752 
764 uint8_t* lwgeom_to_wkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
765 {
766  size_t buf_size;
767  uint8_t *buf = NULL;
768  uint8_t *wkb_out = NULL;
769 
770  /* Initialize output size */
771  if ( size_out ) *size_out = 0;
772 
773  if ( geom == NULL )
774  {
775  LWDEBUG(4,"Cannot convert NULL into WKB.");
776  lwerror("Cannot convert NULL into WKB.");
777  return NULL;
778  }
779 
780  /* Calculate the required size of the output buffer */
781  buf_size = lwgeom_to_wkb_size(geom, variant);
782  LWDEBUGF(4, "WKB output size: %d", buf_size);
783 
784  if ( buf_size == 0 )
785  {
786  LWDEBUG(4,"Error calculating output WKB buffer size.");
787  lwerror("Error calculating output WKB buffer size.");
788  return NULL;
789  }
790 
791  /* Hex string takes twice as much space as binary + a null character */
792  if ( variant & WKB_HEX )
793  {
794  buf_size = 2 * buf_size + 1;
795  LWDEBUGF(4, "Hex WKB output size: %d", buf_size);
796  }
797 
798  /* If neither or both variants are specified, choose the native order */
799  if ( ! (variant & WKB_NDR || variant & WKB_XDR) ||
800  (variant & WKB_NDR && variant & WKB_XDR) )
801  {
802  if ( getMachineEndian() == NDR )
803  variant = variant | WKB_NDR;
804  else
805  variant = variant | WKB_XDR;
806  }
807 
808  /* Allocate the buffer */
809  buf = lwalloc(buf_size);
810 
811  if ( buf == NULL )
812  {
813  LWDEBUGF(4,"Unable to allocate %d bytes for WKB output buffer.", buf_size);
814  lwerror("Unable to allocate %d bytes for WKB output buffer.", buf_size);
815  return NULL;
816  }
817 
818  /* Retain a pointer to the front of the buffer for later */
819  wkb_out = buf;
820 
821  /* Write the WKB into the output buffer */
822  buf = lwgeom_to_wkb_buf(geom, buf, variant);
823 
824  /* Null the last byte if this is a hex output */
825  if ( variant & WKB_HEX )
826  {
827  *buf = '\0';
828  buf++;
829  }
830 
831  LWDEBUGF(4,"buf (%p) - wkb_out (%p) = %d", buf, wkb_out, buf - wkb_out);
832 
833  /* The buffer pointer should now land at the end of the allocated buffer space. Let's check. */
834  if ( buf_size != (size_t) (buf - wkb_out) )
835  {
836  LWDEBUG(4,"Output WKB is not the same size as the allocated buffer.");
837  lwerror("Output WKB is not the same size as the allocated buffer.");
838  lwfree(wkb_out);
839  return NULL;
840  }
841 
842  /* Report output size */
843  if ( size_out ) *size_out = buf_size;
844 
845  return wkb_out;
846 }
847 
848 char* lwgeom_to_hexwkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
849 {
850  return (char*)lwgeom_to_wkb(geom, variant | WKB_HEX, size_out);
851 }
852 
#define LINETYPE
Definition: liblwgeom.h:85
static uint8_t * empty_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:315
static int lwgeom_wkb_needs_srid(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:63
#define WKB_INT_SIZE
#define WKB_BYTE_SIZE
#define WKBMOFFSET
Definition: liblwgeom.h:107
POINTARRAY * points
Definition: liblwgeom.h:432
static size_t ptarray_to_wkb_size(const POINTARRAY *pa, uint8_t variant)
Definition: lwout_wkb.c:353
#define MULTICURVETYPE
Definition: liblwgeom.h:94
int lwgeom_has_srid(const LWGEOM *geom)
Return true or false depending on whether a geometry has a valid SRID set.
Definition: lwgeom.c:1429
uint8_t variant
Definition: cu_in_twkb.c:26
#define WKB_NDR
Definition: liblwgeom.h:2062
static uint8_t * lwline_to_wkb_buf(const LWLINE *line, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:479
void lwfree(void *mem)
Definition: lwutil.c:244
static uint32_t lwgeom_wkb_type(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:82
static uint8_t * lwpoly_to_wkb_buf(const LWPOLY *poly, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:570
static char * hexchr
Definition: lwout_wkb.c:37
#define WKB_COMPOUNDCURVE_TYPE
#define WKB_POLYHEDRALSURFACE_TYPE
#define POLYGONTYPE
Definition: liblwgeom.h:86
uint8_t flags
Definition: liblwgeom.h:396
#define NAN
Definition: lwgeodetic.h:37
#define CURVEPOLYTYPE
Definition: liblwgeom.h:93
#define WKB_TRIANGLE_TYPE
#define COMPOUNDTYPE
Definition: liblwgeom.h:92
#define MULTIPOINTTYPE
Definition: liblwgeom.h:87
#define WKB_MULTISURFACE_TYPE
#define NDR
#define WKB_DOUBLE_SIZE
Well-Known Binary (WKB) Output Variant Types.
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
static uint8_t * lwpoint_to_wkb_buf(const LWPOINT *pt, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:433
#define TRIANGLETYPE
Definition: liblwgeom.h:97
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:96
int32_t srid
Definition: liblwgeom.h:420
uint32_t ngeoms
Definition: liblwgeom.h:506
POINTARRAY * point
Definition: liblwgeom.h:410
#define WKB_MULTICURVE_TYPE
int32_t srid
Definition: liblwgeom.h:398
static uint8_t * integer_to_wkb_buf(const int ival, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:196
uint32_t nrings
Definition: liblwgeom.h:454
static size_t lwgeom_to_wkb_size(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:648
char * hexbytes_from_bytes(const uint8_t *bytes, size_t size)
Definition: lwout_wkb.c:39
unsigned int uint32_t
Definition: uthash.h:78
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
static uint8_t * lwgeom_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:707
#define WKBZOFFSET
Flags applied in EWKB to indicate Z/M dimensions and presence/absence of SRID and bounding boxes...
Definition: liblwgeom.h:106
#define WKB_POLYGON_TYPE
#define LW_FALSE
Definition: liblwgeom.h:76
uint8_t flags
Definition: liblwgeom.h:368
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:75
LWGEOM ** geoms
Definition: liblwgeom.h:508
#define TINTYPE
Definition: liblwgeom.h:98
#define WKBSRIDFLAG
Definition: liblwgeom.h:108
uint8_t * lwgeom_to_wkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
Convert LWGEOM to a char* in WKB format.
Definition: lwout_wkb.c:764
POINTARRAY ** rings
Definition: liblwgeom.h:456
#define WKB_POINT_TYPE
Well-Known Binary (WKB) Geometry Types.
int32_t srid
Definition: liblwgeom.h:505
static size_t lwpoly_to_wkb_size(const LWPOLY *poly, uint8_t variant)
Definition: lwout_wkb.c:547
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:139
#define WKB_LINESTRING_TYPE
char getMachineEndian(void)
Definition: lwutil.c:327
#define WKB_ISO
Definition: liblwgeom.h:2059
#define WKB_CIRCULARSTRING_TYPE
#define WKB_EXTENDED
Definition: liblwgeom.h:2061
#define WKB_MULTIPOLYGON_TYPE
int32_t srid
Definition: liblwgeom.h:409
#define WKB_CURVEPOLYGON_TYPE
#define WKB_MULTILINESTRING_TYPE
#define WKB_TIN_TYPE
static size_t empty_to_wkb_size(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:291
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:89
static int wkb_swap_bytes(uint8_t variant)
Definition: lwout_wkb.c:182
static size_t lwpoint_to_wkb_size(const LWPOINT *pt, uint8_t variant)
Definition: lwout_wkb.c:415
#define MULTISURFACETYPE
Definition: liblwgeom.h:95
static uint8_t * lwcollection_to_wkb_buf(const LWCOLLECTION *col, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:621
static uint8_t * double_to_wkb_buf(const double d, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:243
int32_t srid
Definition: liblwgeom.h:453
static uint8_t * ptarray_to_wkb_buf(const POINTARRAY *pa, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:371
#define WKB_NO_SRID
Definition: liblwgeom.h:2066
#define XDR
#define WKB_MULTIPOINT_TYPE
uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: ptarray.c:1743
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:84
#define WKB_NO_NPOINTS
Definition: liblwgeom.h:2065
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:140
#define WKB_XDR
Definition: liblwgeom.h:2063
uint8_t type
Definition: liblwgeom.h:395
static uint8_t * endian_to_wkb_buf(uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:164
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:91
void * lwalloc(size_t size)
Definition: lwutil.c:229
static size_t lwcollection_to_wkb_size(const LWCOLLECTION *col, uint8_t variant)
Definition: lwout_wkb.c:602
static size_t lwtriangle_to_wkb_size(const LWTRIANGLE *tri, uint8_t variant)
Definition: lwout_wkb.c:500
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
Definition: lwgeom.c:1386
#define MULTILINETYPE
Definition: liblwgeom.h:88
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:151
unsigned char uint8_t
Definition: uthash.h:79
static size_t lwline_to_wkb_size(const LWLINE *line, uint8_t variant)
Definition: lwout_wkb.c:461
#define WKB_HEX
Definition: liblwgeom.h:2064
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
char * lwgeom_to_hexwkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
Definition: lwout_wkb.c:848
int32_t srid
Definition: liblwgeom.h:431
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
#define WKB_GEOMETRYCOLLECTION_TYPE
static uint8_t * lwtriangle_to_wkb_buf(const LWTRIANGLE *tri, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:519
POINTARRAY * points
Definition: liblwgeom.h:421
uint32_t npoints
Definition: liblwgeom.h:370