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