PostGIS  3.0.6dev-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 */
82 static uint32_t lwgeom_wkb_type(const LWGEOM *geom, uint8_t variant)
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("%s: Unsupported geometry type: %s", __func__, lwtype_name(geom->type));
135  }
136 
137  if ( variant & WKB_EXTENDED )
138  {
139  if ( FLAGS_GET_Z(geom->flags) )
140  wkb_type |= WKBZOFFSET;
141  if ( FLAGS_GET_M(geom->flags) )
142  wkb_type |= WKBMOFFSET;
143 /* if ( geom->srid != SRID_UNKNOWN && ! (variant & WKB_NO_SRID) ) */
144  if ( lwgeom_wkb_needs_srid(geom, variant) )
145  wkb_type |= WKBSRIDFLAG;
146  }
147  else if ( variant & WKB_ISO )
148  {
149  /* Z types are in the 1000 range */
150  if ( FLAGS_GET_Z(geom->flags) )
151  wkb_type += 1000;
152  /* M types are in the 2000 range */
153  if ( FLAGS_GET_M(geom->flags) )
154  wkb_type += 2000;
155  /* ZM types are in the 1000 + 2000 = 3000 range, see above */
156  }
157  return wkb_type;
158 }
159 
160 /*
161 * Endian
162 */
163 static uint8_t* endian_to_wkb_buf(uint8_t *buf, uint8_t variant)
164 {
165  if ( variant & WKB_HEX )
166  {
167  buf[0] = '0';
168  buf[1] = ((variant & WKB_NDR) ? '1' : '0');
169  return buf + 2;
170  }
171  else
172  {
173  buf[0] = ((variant & WKB_NDR) ? 1 : 0);
174  return buf + 1;
175  }
176 }
177 
178 /*
179 * SwapBytes?
180 */
181 static inline int wkb_swap_bytes(uint8_t variant)
182 {
183  /* If requested variant matches machine arch, we don't have to swap! */
184  if (((variant & WKB_NDR) && !IS_BIG_ENDIAN) ||
185  ((!(variant & WKB_NDR)) && IS_BIG_ENDIAN))
186  {
187  return LW_FALSE;
188  }
189  return LW_TRUE;
190 }
191 
192 /*
193 * Integer32
194 */
195 static uint8_t *
196 integer_to_wkb_buf(const uint32_t ival, uint8_t *buf, uint8_t variant)
197 {
198  uint8_t *iptr = (uint8_t *)(&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 static uint8_t* double_nan_to_wkb_buf(uint8_t *buf, uint8_t variant)
241 {
242 #define NAN_SIZE 8
243  const uint8_t ndr_nan[NAN_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f};
244  const uint8_t xdr_nan[NAN_SIZE] = {0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
245 
246  if ( variant & WKB_HEX )
247  {
248  for (int i = 0; i < NAN_SIZE; i++)
249  {
250  uint8_t b = (variant & WKB_NDR) ? ndr_nan[i] : xdr_nan[i];
251  /* Top four bits to 0-F */
252  buf[2*i] = hexchr[b >> 4];
253  /* Bottom four bits to 0-F */
254  buf[2*i + 1] = hexchr[b & 0x0F];
255  }
256  return buf + (2 * NAN_SIZE);
257  }
258  else
259  {
260  for (int i = 0; i < NAN_SIZE; i++)
261  {
262  buf[i] = (variant & WKB_NDR) ? ndr_nan[i] : xdr_nan[i];;
263  }
264  return buf + NAN_SIZE;
265  }
266 }
267 
268 /*
269 * Float64
270 */
271 static uint8_t* double_to_wkb_buf(const double d, uint8_t *buf, uint8_t variant)
272 {
273  uint8_t *dptr = (uint8_t *)(&d);
274  int i = 0;
275 
276  if ( sizeof(double) != WKB_DOUBLE_SIZE )
277  {
278  lwerror("Machine double size is not %d bytes!", WKB_DOUBLE_SIZE);
279  }
280 
281  if ( variant & WKB_HEX )
282  {
283  int swap = wkb_swap_bytes(variant);
284  /* Machine/request arch mismatch, so flip byte order */
285  for ( i = 0; i < WKB_DOUBLE_SIZE; i++ )
286  {
287  int j = (swap ? WKB_DOUBLE_SIZE - 1 - i : i);
288  uint8_t b = dptr[j];
289  /* Top four bits to 0-F */
290  buf[2*i] = hexchr[b >> 4];
291  /* Bottom four bits to 0-F */
292  buf[2*i+1] = hexchr[b & 0x0F];
293  }
294  return buf + (2 * WKB_DOUBLE_SIZE);
295  }
296  else
297  {
298  /* Machine/request arch mismatch, so flip byte order */
299  if ( wkb_swap_bytes(variant) )
300  {
301  for ( i = 0; i < WKB_DOUBLE_SIZE; i++ )
302  {
303  buf[i] = dptr[WKB_DOUBLE_SIZE - 1 - i];
304  }
305  }
306  /* If machine arch and requested arch match, don't flip byte order */
307  else
308  {
309  memcpy(buf, dptr, WKB_DOUBLE_SIZE);
310  }
311  return buf + WKB_DOUBLE_SIZE;
312  }
313 }
314 
315 
316 /*
317 * Empty
318 */
319 static size_t empty_to_wkb_size(const LWGEOM *geom, uint8_t variant)
320 {
321  /* endian byte + type integer */
322  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE;
323 
324  /* optional srid integer */
325  if ( lwgeom_wkb_needs_srid(geom, variant) )
326  size += WKB_INT_SIZE;
327 
328  /* Represent POINT EMPTY as POINT(NaN NaN) */
329  if ( geom->type == POINTTYPE )
330  {
331  const LWPOINT *pt = (LWPOINT*)geom;
332  size += WKB_DOUBLE_SIZE * FLAGS_NDIMS(pt->point->flags);
333  }
334  /* num-elements */
335  else
336  {
337  size += WKB_INT_SIZE;
338  }
339 
340  return size;
341 }
342 
343 static uint8_t* empty_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
344 {
345  uint32_t wkb_type = lwgeom_wkb_type(geom, variant);
346 
347  /* Set the endian flag */
348  buf = endian_to_wkb_buf(buf, variant);
349 
350  /* Set the geometry type */
351  buf = integer_to_wkb_buf(wkb_type, buf, variant);
352 
353  /* Set the SRID if necessary */
354  if ( lwgeom_wkb_needs_srid(geom, variant) )
355  buf = integer_to_wkb_buf(geom->srid, buf, variant);
356 
357  /* Represent POINT EMPTY as POINT(NaN NaN) */
358  if ( geom->type == POINTTYPE )
359  {
360  const LWPOINT *pt = (LWPOINT*)geom;
361  for (int i = 0; i < FLAGS_NDIMS(pt->point->flags); i++)
362  {
363  buf = double_nan_to_wkb_buf(buf, variant);
364  }
365  }
366  /* Everything else is flagged as empty using num-elements == 0 */
367  else
368  {
369  /* Set nrings/npoints/ngeoms to zero */
370  buf = integer_to_wkb_buf(0, buf, variant);
371  }
372 
373  return buf;
374 }
375 
376 /*
377 * POINTARRAY
378 */
379 static size_t ptarray_to_wkb_size(const POINTARRAY *pa, uint8_t variant)
380 {
381  int dims = 2;
382  size_t size = 0;
383 
384  if ( variant & (WKB_ISO | WKB_EXTENDED) )
385  dims = FLAGS_NDIMS(pa->flags);
386 
387  /* Include the npoints if it's not a POINT type) */
388  if ( ! ( variant & WKB_NO_NPOINTS ) )
389  size += WKB_INT_SIZE;
390 
391  /* size of the double list */
392  size += pa->npoints * dims * WKB_DOUBLE_SIZE;
393 
394  return size;
395 }
396 
397 static uint8_t* ptarray_to_wkb_buf(const POINTARRAY *pa, uint8_t *buf, uint8_t variant)
398 {
399  uint32_t dims = 2;
400  uint32_t pa_dims = FLAGS_NDIMS(pa->flags);
401  uint32_t i, j;
402  double *dbl_ptr;
403 
404  /* SFSQL is always 2-d. Extended and ISO use all available dimensions */
405  if ( (variant & WKB_ISO) || (variant & WKB_EXTENDED) )
406  dims = pa_dims;
407 
408  /* Set the number of points (if it's not a POINT type) */
409  if ( ! ( variant & WKB_NO_NPOINTS ) )
410  buf = integer_to_wkb_buf(pa->npoints, buf, variant);
411 
412  /* Bulk copy the coordinates when: dimensionality matches, output format */
413  /* is not hex, and output endian matches internal endian. */
414  if ( pa->npoints && (dims == pa_dims) && ! wkb_swap_bytes(variant) && ! (variant & WKB_HEX) )
415  {
416  size_t size = pa->npoints * dims * WKB_DOUBLE_SIZE;
417  memcpy(buf, getPoint_internal(pa, 0), size);
418  buf += size;
419  }
420  /* Copy coordinates one-by-one otherwise */
421  else
422  {
423  for ( i = 0; i < pa->npoints; i++ )
424  {
425  LWDEBUGF(4, "Writing point #%d", i);
426  dbl_ptr = (double*)getPoint_internal(pa, i);
427  for ( j = 0; j < dims; j++ )
428  {
429  LWDEBUGF(4, "Writing dimension #%d (buf = %p)", j, buf);
430  buf = double_to_wkb_buf(dbl_ptr[j], buf, variant);
431  }
432  }
433  }
434  LWDEBUGF(4, "Done (buf = %p)", buf);
435  return buf;
436 }
437 
438 /*
439 * POINT
440 */
441 static size_t lwpoint_to_wkb_size(const LWPOINT *pt, uint8_t variant)
442 {
443  /* Endian flag + type number */
444  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE;
445 
446  /* Only process empty at this level in the EXTENDED case */
447  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)pt) )
448  return empty_to_wkb_size((LWGEOM*)pt, variant);
449 
450  /* Extended WKB needs space for optional SRID integer */
451  if ( lwgeom_wkb_needs_srid((LWGEOM*)pt, variant) )
452  size += WKB_INT_SIZE;
453 
454  /* Points */
456  return size;
457 }
458 
459 static uint8_t* lwpoint_to_wkb_buf(const LWPOINT *pt, uint8_t *buf, uint8_t variant)
460 {
461  /* Only process empty at this level in the EXTENDED case */
462  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)pt) )
463  return empty_to_wkb_buf((LWGEOM*)pt, buf, variant);
464 
465  /* Set the endian flag */
466  LWDEBUGF(4, "Entering function, buf = %p", buf);
467  buf = endian_to_wkb_buf(buf, variant);
468  LWDEBUGF(4, "Endian set, buf = %p", buf);
469  /* Set the geometry type */
471  LWDEBUGF(4, "Type set, buf = %p", buf);
472  /* Set the optional SRID for extended variant */
473  if ( lwgeom_wkb_needs_srid((LWGEOM*)pt, variant) )
474  {
475  buf = integer_to_wkb_buf(pt->srid, buf, variant);
476  LWDEBUGF(4, "SRID set, buf = %p", buf);
477  }
478  /* Set the coordinates */
479  buf = ptarray_to_wkb_buf(pt->point, buf, variant | WKB_NO_NPOINTS);
480  LWDEBUGF(4, "Pointarray set, buf = %p", buf);
481  return buf;
482 }
483 
484 /*
485 * LINESTRING, CIRCULARSTRING
486 */
487 static size_t lwline_to_wkb_size(const LWLINE *line, uint8_t variant)
488 {
489  /* Endian flag + type number */
490  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE;
491 
492  /* Only process empty at this level in the EXTENDED case */
493  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)line) )
494  return empty_to_wkb_size((LWGEOM*)line, variant);
495 
496  /* Extended WKB needs space for optional SRID integer */
497  if ( lwgeom_wkb_needs_srid((LWGEOM*)line, variant) )
498  size += WKB_INT_SIZE;
499 
500  /* Size of point array */
501  size += ptarray_to_wkb_size(line->points, variant);
502  return size;
503 }
504 
505 static uint8_t* lwline_to_wkb_buf(const LWLINE *line, 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*)line) )
509  return empty_to_wkb_buf((LWGEOM*)line, buf, variant);
510 
511  /* Set the endian flag */
512  buf = endian_to_wkb_buf(buf, variant);
513  /* Set the geometry type */
515  /* Set the optional SRID for extended variant */
516  if ( lwgeom_wkb_needs_srid((LWGEOM*)line, variant) )
517  buf = integer_to_wkb_buf(line->srid, buf, variant);
518  /* Set the coordinates */
519  buf = ptarray_to_wkb_buf(line->points, buf, variant);
520  return buf;
521 }
522 
523 /*
524 * TRIANGLE
525 */
526 static size_t lwtriangle_to_wkb_size(const LWTRIANGLE *tri, uint8_t variant)
527 {
528  /* endian flag + type number + number of rings */
529  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE + WKB_INT_SIZE;
530 
531  /* Only process empty at this level in the EXTENDED case */
532  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)tri) )
533  return empty_to_wkb_size((LWGEOM*)tri, variant);
534 
535  /* Extended WKB needs space for optional SRID integer */
536  if ( lwgeom_wkb_needs_srid((LWGEOM*)tri, variant) )
537  size += WKB_INT_SIZE;
538 
539  /* How big is this point array? */
540  size += ptarray_to_wkb_size(tri->points, variant);
541 
542  return size;
543 }
544 
545 static uint8_t* lwtriangle_to_wkb_buf(const LWTRIANGLE *tri, uint8_t *buf, uint8_t variant)
546 {
547  /* Only process empty at this level in the EXTENDED case */
548  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)tri) )
549  return empty_to_wkb_buf((LWGEOM*)tri, buf, variant);
550 
551  /* Set the endian flag */
552  buf = endian_to_wkb_buf(buf, variant);
553 
554  /* Set the geometry type */
556 
557  /* Set the optional SRID for extended variant */
558  if ( lwgeom_wkb_needs_srid((LWGEOM*)tri, variant) )
559  buf = integer_to_wkb_buf(tri->srid, buf, variant);
560 
561  /* Set the number of rings (only one, it's a triangle, buddy) */
562  buf = integer_to_wkb_buf(1, buf, variant);
563 
564  /* Write that ring */
565  buf = ptarray_to_wkb_buf(tri->points, buf, variant);
566 
567  return buf;
568 }
569 
570 /*
571 * POLYGON
572 */
573 static size_t lwpoly_to_wkb_size(const LWPOLY *poly, uint8_t variant)
574 {
575  /* endian flag + type number + number of rings */
576  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE + WKB_INT_SIZE;
577  uint32_t i = 0;
578 
579  /* Only process empty at this level in the EXTENDED case */
580  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)poly) )
581  return empty_to_wkb_size((LWGEOM*)poly, variant);
582 
583  /* Extended WKB needs space for optional SRID integer */
584  if ( lwgeom_wkb_needs_srid((LWGEOM*)poly, variant) )
585  size += WKB_INT_SIZE;
586 
587  for ( i = 0; i < poly->nrings; i++ )
588  {
589  /* Size of ring point array */
590  size += ptarray_to_wkb_size(poly->rings[i], variant);
591  }
592 
593  return size;
594 }
595 
596 static uint8_t* lwpoly_to_wkb_buf(const LWPOLY *poly, uint8_t *buf, uint8_t variant)
597 {
598  uint32_t i;
599 
600  /* Only process empty at this level in the EXTENDED case */
601  if ( (variant & WKB_EXTENDED) && lwgeom_is_empty((LWGEOM*)poly) )
602  return empty_to_wkb_buf((LWGEOM*)poly, buf, variant);
603 
604  /* Set the endian flag */
605  buf = endian_to_wkb_buf(buf, variant);
606  /* Set the geometry type */
608  /* Set the optional SRID for extended variant */
609  if ( lwgeom_wkb_needs_srid((LWGEOM*)poly, variant) )
610  buf = integer_to_wkb_buf(poly->srid, buf, variant);
611  /* Set the number of rings */
612  buf = integer_to_wkb_buf(poly->nrings, buf, variant);
613 
614  for ( i = 0; i < poly->nrings; i++ )
615  {
616  buf = ptarray_to_wkb_buf(poly->rings[i], buf, variant);
617  }
618 
619  return buf;
620 }
621 
622 
623 /*
624 * MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION
625 * MULTICURVE, COMPOUNDCURVE, MULTISURFACE, CURVEPOLYGON, TIN,
626 * POLYHEDRALSURFACE
627 */
628 static size_t lwcollection_to_wkb_size(const LWCOLLECTION *col, uint8_t variant)
629 {
630  /* Endian flag + type number + number of subgeoms */
631  size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE + WKB_INT_SIZE;
632  uint32_t i = 0;
633 
634  /* Extended WKB needs space for optional SRID integer */
635  if ( lwgeom_wkb_needs_srid((LWGEOM*)col, variant) )
636  size += WKB_INT_SIZE;
637 
638  for ( i = 0; i < col->ngeoms; i++ )
639  {
640  /* size of subgeom */
641  size += lwgeom_to_wkb_size((LWGEOM*)col->geoms[i], variant | WKB_NO_SRID);
642  }
643 
644  return size;
645 }
646 
647 static uint8_t* lwcollection_to_wkb_buf(const LWCOLLECTION *col, uint8_t *buf, uint8_t variant)
648 {
649  uint32_t i;
650 
651  /* Set the endian flag */
652  buf = endian_to_wkb_buf(buf, variant);
653  /* Set the geometry type */
655  /* Set the optional SRID for extended variant */
656  if ( lwgeom_wkb_needs_srid((LWGEOM*)col, variant) )
657  buf = integer_to_wkb_buf(col->srid, buf, variant);
658  /* Set the number of sub-geometries */
659  buf = integer_to_wkb_buf(col->ngeoms, buf, variant);
660 
661  /* Write the sub-geometries. Sub-geometries do not get SRIDs, they
662  inherit from their parents. */
663  for ( i = 0; i < col->ngeoms; i++ )
664  {
665  buf = lwgeom_to_wkb_buf(col->geoms[i], buf, variant | WKB_NO_SRID);
666  }
667 
668  return buf;
669 }
670 
671 /*
672 * GEOMETRY
673 */
674 static size_t lwgeom_to_wkb_size(const LWGEOM *geom, uint8_t variant)
675 {
676  size_t size = 0;
677 
678  if ( geom == NULL )
679  return 0;
680 
681  /* Short circuit out empty geometries */
682  if ( (!(variant & WKB_EXTENDED)) && lwgeom_is_empty(geom) )
683  {
684  return empty_to_wkb_size(geom, variant);
685  }
686 
687  switch ( geom->type )
688  {
689  case POINTTYPE:
690  size += lwpoint_to_wkb_size((LWPOINT*)geom, variant);
691  break;
692 
693  /* LineString and CircularString both have points elements */
694  case CIRCSTRINGTYPE:
695  case LINETYPE:
696  size += lwline_to_wkb_size((LWLINE*)geom, variant);
697  break;
698 
699  /* Polygon has nrings and rings elements */
700  case POLYGONTYPE:
701  size += lwpoly_to_wkb_size((LWPOLY*)geom, variant);
702  break;
703 
704  /* Triangle has one ring of three points */
705  case TRIANGLETYPE:
706  size += lwtriangle_to_wkb_size((LWTRIANGLE*)geom, variant);
707  break;
708 
709  /* All these Collection types have ngeoms and geoms elements */
710  case MULTIPOINTTYPE:
711  case MULTILINETYPE:
712  case MULTIPOLYGONTYPE:
713  case COMPOUNDTYPE:
714  case CURVEPOLYTYPE:
715  case MULTICURVETYPE:
716  case MULTISURFACETYPE:
717  case COLLECTIONTYPE:
719  case TINTYPE:
721  break;
722 
723  /* Unknown type! */
724  default:
725  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(geom->type));
726  }
727 
728  return size;
729 }
730 
731 /* TODO handle the TRIANGLE type properly */
732 
733 static uint8_t* lwgeom_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
734 {
735 
736  /* Do not simplify empties when outputting to canonical form */
737  if (lwgeom_is_empty(geom) && !(variant & WKB_EXTENDED))
738  return empty_to_wkb_buf(geom, buf, variant);
739 
740  switch ( geom->type )
741  {
742  case POINTTYPE:
743  return lwpoint_to_wkb_buf((LWPOINT*)geom, buf, variant);
744 
745  /* LineString and CircularString both have 'points' elements */
746  case CIRCSTRINGTYPE:
747  case LINETYPE:
748  return lwline_to_wkb_buf((LWLINE*)geom, buf, variant);
749 
750  /* Polygon has 'nrings' and 'rings' elements */
751  case POLYGONTYPE:
752  return lwpoly_to_wkb_buf((LWPOLY*)geom, buf, variant);
753 
754  /* Triangle has one ring of three points */
755  case TRIANGLETYPE:
756  return lwtriangle_to_wkb_buf((LWTRIANGLE*)geom, buf, variant);
757 
758  /* All these Collection types have 'ngeoms' and 'geoms' elements */
759  case MULTIPOINTTYPE:
760  case MULTILINETYPE:
761  case MULTIPOLYGONTYPE:
762  case COMPOUNDTYPE:
763  case CURVEPOLYTYPE:
764  case MULTICURVETYPE:
765  case MULTISURFACETYPE:
766  case COLLECTIONTYPE:
768  case TINTYPE:
769  return lwcollection_to_wkb_buf((LWCOLLECTION*)geom, buf, variant);
770 
771  /* Unknown type! */
772  default:
773  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(geom->type));
774  }
775  /* Return value to keep compiler happy. */
776  return 0;
777 }
778 
790 uint8_t* lwgeom_to_wkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
791 {
792  size_t buf_size;
793  uint8_t *buf = NULL;
794  uint8_t *wkb_out = NULL;
795 
796  /* Initialize output size */
797  if ( size_out ) *size_out = 0;
798 
799  if ( geom == NULL )
800  {
801  LWDEBUG(4,"Cannot convert NULL into WKB.");
802  lwerror("Cannot convert NULL into WKB.");
803  return NULL;
804  }
805 
806  /* Calculate the required size of the output buffer */
807  buf_size = lwgeom_to_wkb_size(geom, variant);
808  LWDEBUGF(4, "WKB output size: %d", buf_size);
809 
810  if ( buf_size == 0 )
811  {
812  LWDEBUG(4,"Error calculating output WKB buffer size.");
813  lwerror("Error calculating output WKB buffer size.");
814  return NULL;
815  }
816 
817  /* Hex string takes twice as much space as binary + a null character */
818  if ( variant & WKB_HEX )
819  {
820  buf_size = 2 * buf_size + 1;
821  LWDEBUGF(4, "Hex WKB output size: %d", buf_size);
822  }
823 
824  /* If neither or both variants are specified, choose the native order */
825  if ( ! (variant & WKB_NDR || variant & WKB_XDR) ||
826  (variant & WKB_NDR && variant & WKB_XDR) )
827  {
828  if (IS_BIG_ENDIAN)
829  variant = variant | WKB_XDR;
830  else
831  variant = variant | WKB_NDR;
832  }
833 
834  /* Allocate the buffer */
835  buf = lwalloc(buf_size);
836 
837  if ( buf == NULL )
838  {
839  LWDEBUGF(4,"Unable to allocate %d bytes for WKB output buffer.", buf_size);
840  lwerror("Unable to allocate %d bytes for WKB output buffer.", buf_size);
841  return NULL;
842  }
843 
844  /* Retain a pointer to the front of the buffer for later */
845  wkb_out = buf;
846 
847  /* Write the WKB into the output buffer */
848  buf = lwgeom_to_wkb_buf(geom, buf, variant);
849 
850  /* Null the last byte if this is a hex output */
851  if ( variant & WKB_HEX )
852  {
853  *buf = '\0';
854  buf++;
855  }
856 
857  LWDEBUGF(4,"buf (%p) - wkb_out (%p) = %d", buf, wkb_out, buf - wkb_out);
858 
859  /* The buffer pointer should now land at the end of the allocated buffer space. Let's check. */
860  if ( buf_size != (size_t) (buf - wkb_out) )
861  {
862  LWDEBUG(4,"Output WKB is not the same size as the allocated buffer.");
863  lwerror("Output WKB is not the same size as the allocated buffer.");
864  lwfree(wkb_out);
865  return NULL;
866  }
867 
868  /* Report output size */
869  if ( size_out ) *size_out = buf_size;
870 
871  return wkb_out;
872 }
873 
874 char* lwgeom_to_hexwkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
875 {
876  return (char*)lwgeom_to_wkb(geom, variant | WKB_HEX, size_out);
877 }
878 
static uint8_t variant
Definition: cu_in_twkb.c:26
#define WKBMOFFSET
Definition: liblwgeom.h:139
#define LW_FALSE
Definition: liblwgeom.h:108
#define COLLECTIONTYPE
Definition: liblwgeom.h:122
#define WKB_NO_SRID
Definition: liblwgeom.h:2128
#define COMPOUNDTYPE
Definition: liblwgeom.h:124
#define WKB_ISO
Definition: liblwgeom.h:2121
#define CURVEPOLYTYPE
Definition: liblwgeom.h:125
#define MULTILINETYPE
Definition: liblwgeom.h:120
#define WKB_NO_NPOINTS
Definition: liblwgeom.h:2127
#define MULTISURFACETYPE
Definition: liblwgeom.h:127
#define LINETYPE
Definition: liblwgeom.h:117
#define MULTIPOINTTYPE
Definition: liblwgeom.h:119
#define WKBSRIDFLAG
Definition: liblwgeom.h:140
int lwgeom_has_srid(const LWGEOM *geom)
Return true or false depending on whether a geometry has a valid SRID set.
Definition: lwgeom.c:1387
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:116
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:179
#define WKB_HEX
Definition: liblwgeom.h:2126
#define TINTYPE
Definition: liblwgeom.h:130
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:121
void lwfree(void *mem)
Definition: lwutil.c:242
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:193
#define POLYGONTYPE
Definition: liblwgeom.h:118
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:128
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:123
#define WKB_EXTENDED
Definition: liblwgeom.h:2123
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:2124
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:180
#define MULTICURVETYPE
Definition: liblwgeom.h:126
#define TRIANGLETYPE
Definition: liblwgeom.h:129
void * lwalloc(size_t size)
Definition: lwutil.c:227
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:107
#define WKBZOFFSET
Flags applied in EWKB to indicate Z/M dimensions and presence/absence of SRID and bounding boxes.
Definition: liblwgeom.h:138
#define WKB_XDR
Definition: liblwgeom.h:2125
#define WKB_COMPOUNDCURVE_TYPE
#define IS_BIG_ENDIAN
#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:67
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:193
static size_t lwcollection_to_wkb_size(const LWCOLLECTION *col, uint8_t variant)
Definition: lwout_wkb.c:628
static size_t lwgeom_to_wkb_size(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:674
static uint8_t * ptarray_to_wkb_buf(const POINTARRAY *pa, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:397
static uint8_t * lwpoint_to_wkb_buf(const LWPOINT *pt, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:459
char * hexbytes_from_bytes(const uint8_t *bytes, size_t size)
Definition: lwout_wkb.c:39
static uint8_t * double_nan_to_wkb_buf(uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:240
static int lwgeom_wkb_needs_srid(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:63
static uint8_t * endian_to_wkb_buf(uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:163
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:790
static uint8_t * lwtriangle_to_wkb_buf(const LWTRIANGLE *tri, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:545
static uint32_t lwgeom_wkb_type(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:82
static size_t ptarray_to_wkb_size(const POINTARRAY *pa, uint8_t variant)
Definition: lwout_wkb.c:379
#define NAN_SIZE
static size_t lwtriangle_to_wkb_size(const LWTRIANGLE *tri, uint8_t variant)
Definition: lwout_wkb.c:526
static uint8_t * empty_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:343
static uint8_t * lwgeom_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:733
static uint8_t * double_to_wkb_buf(const double d, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:271
static size_t lwpoint_to_wkb_size(const LWPOINT *pt, uint8_t variant)
Definition: lwout_wkb.c:441
char * lwgeom_to_hexwkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
Definition: lwout_wkb.c:874
static size_t empty_to_wkb_size(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:319
static uint8_t * integer_to_wkb_buf(const uint32_t ival, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:196
static size_t lwpoly_to_wkb_size(const LWPOLY *poly, uint8_t variant)
Definition: lwout_wkb.c:573
static size_t lwline_to_wkb_size(const LWLINE *line, uint8_t variant)
Definition: lwout_wkb.c:487
static char * hexchr
Definition: lwout_wkb.c:37
static int wkb_swap_bytes(uint8_t variant)
Definition: lwout_wkb.c:181
static uint8_t * lwpoly_to_wkb_buf(const LWPOLY *poly, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:596
static uint8_t * lwline_to_wkb_buf(const LWLINE *line, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:505
static uint8_t * lwcollection_to_wkb_buf(const LWCOLLECTION *col, uint8_t *buf, uint8_t variant)
Definition: lwout_wkb.c:647
uint32_t ngeoms
Definition: liblwgeom.h:566
LWGEOM ** geoms
Definition: liblwgeom.h:561
int32_t srid
Definition: liblwgeom.h:562
uint8_t type
Definition: liblwgeom.h:448
int32_t srid
Definition: liblwgeom.h:446
lwflags_t flags
Definition: liblwgeom.h:447
POINTARRAY * points
Definition: liblwgeom.h:469
int32_t srid
Definition: liblwgeom.h:470
POINTARRAY * point
Definition: liblwgeom.h:457
uint8_t type
Definition: liblwgeom.h:460
int32_t srid
Definition: liblwgeom.h:458
POINTARRAY ** rings
Definition: liblwgeom.h:505
uint32_t nrings
Definition: liblwgeom.h:510
int32_t srid
Definition: liblwgeom.h:506
int32_t srid
Definition: liblwgeom.h:482
POINTARRAY * points
Definition: liblwgeom.h:481
lwflags_t flags
Definition: liblwgeom.h:417
uint32_t npoints
Definition: liblwgeom.h:413