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