PostGIS 3.7.0dev-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#include <stddef.h> // for ptrdiff_t
28
29#include "liblwgeom_internal.h"
30#include "lwgeom_log.h"
31
32static uint8_t* lwgeom_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant);
33static size_t lwgeom_to_wkb_size(const LWGEOM *geom, uint8_t variant);
34
35/*
36* Look-up table for hex writer
37*/
38static char *hexchr = "0123456789ABCDEF";
39
40char* 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*/
64static 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*/
83static 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:
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;
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*/
164static 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*/
182static 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*/
196static uint8_t *
197integer_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
241static 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*/
272static 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*/
320static 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
344static 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*/
380static 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 += (size_t)pa->npoints * dims * WKB_DOUBLE_SIZE;
394
395 return size;
396}
397
398static 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 = (size_t)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*/
442static 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 */
453 size += WKB_INT_SIZE;
454
455 /* Points */
457 return size;
458}
459
460static 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 */
475 {
476 buf = integer_to_wkb_buf(pt->srid, buf, variant);
477 LWDEBUGF(4, "SRID set, buf = %p", buf);
478 }
479 /* Set the coordinates */
481 LWDEBUGF(4, "Pointarray set, buf = %p", buf);
482 return buf;
483}
484
485/*
486* LINESTRING, CIRCULARSTRING
487*/
488static 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
506static 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*/
527static 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 */
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
546static 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 */
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*/
574static 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
597static 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*/
629static 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 */
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
648static 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 */
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*/
675static size_t
676lwgeom_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:
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
739static 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
796static ptrdiff_t
797lwgeom_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)
804 else
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
814uint8_t *
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
844char *
846{
847 return (char *)lwgeom_to_wkb_buffer(geom, variant | WKB_HEX);
848}
849
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
876{
877 return lwgeom_to_wkb_varlena(geom, variant | WKB_HEX);
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 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:2217
#define COMPOUNDTYPE
Definition liblwgeom.h:110
#define WKB_ISO
Definition liblwgeom.h:2210
#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:2216
#define MULTISURFACETYPE
Definition liblwgeom.h:113
#define LINETYPE
Definition liblwgeom.h:103
#define WKT_EXTENDED
Definition liblwgeom.h:2221
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 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:1495
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:102
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:165
void * lwalloc(size_t size)
Definition lwutil.c:227
#define WKB_HEX
Definition liblwgeom.h:2215
#define TINTYPE
Definition liblwgeom.h:116
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:107
void lwfree(void *mem)
Definition lwutil.c:248
#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:2212
#define WKB_NDR
Definition liblwgeom.h:2213
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:166
#define LWSIZE_SET(varsize, len)
Definition liblwgeom.h:325
#define MULTICURVETYPE
Definition liblwgeom.h:112
#define TRIANGLETYPE
Definition liblwgeom.h:115
#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:2214
#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:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition lwinline.h:75
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:199
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
char * lwgeom_to_hexwkb_buffer(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:845
static uint8_t * lwline_to_wkb_buf(const LWLINE *line, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:506
static uint8_t * lwtriangle_to_wkb_buf(const LWTRIANGLE *tri, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:546
lwvarlena_t * lwgeom_to_hexwkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:875
static uint8_t * integer_to_wkb_buf(const uint32_t ival, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:197
static int lwgeom_wkb_needs_srid(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:64
static uint8_t * lwcollection_to_wkb_buf(const LWCOLLECTION *col, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:648
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:851
char * hexbytes_from_bytes(const uint8_t *bytes, size_t size)
Definition lwout_wkb.c:40
static uint8_t * ptarray_to_wkb_buf(const POINTARRAY *pa, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:398
static uint32_t lwgeom_wkb_type(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:83
static uint8_t * double_to_wkb_buf(const double d, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:272
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 * lwgeom_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:739
static size_t lwpoint_to_wkb_size(const LWPOINT *pt, uint8_t variant)
Definition lwout_wkb.c:442
static uint8_t * lwpoly_to_wkb_buf(const LWPOLY *poly, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:597
static size_t empty_to_wkb_size(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:320
static size_t lwpoly_to_wkb_size(const LWPOLY *poly, uint8_t variant)
Definition lwout_wkb.c:574
static uint8_t * endian_to_wkb_buf(uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:164
static uint8_t * empty_to_wkb_buf(const LWGEOM *geom, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:344
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 * double_nan_to_wkb_buf(uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:241
static uint8_t * lwpoint_to_wkb_buf(const LWPOINT *pt, uint8_t *buf, uint8_t variant)
Definition lwout_wkb.c:460
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
uint8_t * lwgeom_to_wkb_buffer(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:815
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
void * data
Definition liblwgeom.h:459
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