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