PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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
31static uint8_t* lwgeom_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant);
32static size_t lwgeom_to_wkb_size(const LWGEOM *geom, uint8_t variant);
33
34/*
35* Look-up table for hex writer
36*/
37static char *hexchr = "0123456789ABCDEF";
38
39char* 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*/
63static 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*/
82static 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:
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;
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*/
163static 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*/
181static 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*/
195static uint8_t *
196integer_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
240static 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*/
271static 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*/
319static 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
343static 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*/
379static 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
397static 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*/
441static 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 */
452 size += WKB_INT_SIZE;
453
454 /* Points */
456 return size;
457}
458
459static 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 */
474 {
475 buf = integer_to_wkb_buf(pt->srid, buf, variant);
476 LWDEBUGF(4, "SRID set, buf = %p", buf);
477 }
478 /* Set the coordinates */
480 LWDEBUGF(4, "Pointarray set, buf = %p", buf);
481 return buf;
482}
483
484/*
485* LINESTRING, CIRCULARSTRING
486*/
487static 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
505static 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*/
526static 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 */
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
545static 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 */
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*/
573static 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
596static 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*/
628static 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 */
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
647static 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 */
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*/
674static 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:
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
733static 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
790uint8_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)
830 else
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
874char* 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
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
#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
void * lwalloc(size_t size)
Definition lwutil.c:227
#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
#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
#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
char * lwgeom_to_hexwkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
Definition lwout_wkb.c:874
static uint8_t * lwline_to_wkb_buf(const LWLINE *line, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:505
static uint8_t * lwtriangle_to_wkb_buf(const LWTRIANGLE *tri, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:545
static uint8_t * integer_to_wkb_buf(const uint32_t ival, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:196
static int lwgeom_wkb_needs_srid(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:63
static uint8_t * lwcollection_to_wkb_buf(const LWCOLLECTION *col, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:647
char * hexbytes_from_bytes(const uint8_t *bytes, size_t size)
Definition lwout_wkb.c:39
static uint8_t * ptarray_to_wkb_buf(const POINTARRAY *pa, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:397
static uint32_t lwgeom_wkb_type(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:82
static uint8_t * double_to_wkb_buf(const double d, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:271
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 * lwgeom_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:733
static size_t lwpoint_to_wkb_size(const LWPOINT *pt, uint8_t variant)
Definition lwout_wkb.c:441
static uint8_t * lwpoly_to_wkb_buf(const LWPOLY *poly, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:596
static size_t empty_to_wkb_size(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:319
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 size_t lwpoly_to_wkb_size(const LWPOLY *poly, uint8_t variant)
Definition lwout_wkb.c:573
static uint8_t * endian_to_wkb_buf(uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:163
static uint8_t * empty_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:343
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 * double_nan_to_wkb_buf(uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:240
static uint8_t * lwpoint_to_wkb_buf(const LWPOINT *pt, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:459
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