PostGIS  3.4.0dev-r@@SVN_REVISION@@
lwgeom_in_gml.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 2009 - 2010 Oslandia
22  *
23  **********************************************************************/
24 
25 
49 #include "postgres.h"
50 #include "executor/spi.h"
51 #include "utils/builtins.h"
52 
53 #include <libxml/tree.h>
54 #include <libxml/parser.h>
55 #include <libxml/xpath.h>
56 #include <libxml/xpathInternals.h>
57 
58 #include "../postgis_config.h"
59 #include "lwgeom_pg.h"
60 #include "liblwgeom.h"
61 #include "lwgeom_transform.h"
62 
63 
64 Datum geom_from_gml(PG_FUNCTION_ARGS);
65 static LWGEOM *lwgeom_from_gml(const char *wkt, int xml_size);
66 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid);
67 
68 typedef struct struct_gmlSrs
69 {
70  int32_t srid;
72 }
74 
75 #define XLINK_NS ((char *) "http://www.w3.org/1999/xlink")
76 #define GML_NS ((char *) "http://www.opengis.net/gml")
77 #define GML32_NS ((char *) "http://www.opengis.net/gml/3.2")
78 
79 
80 
81 static void gml_lwpgerror(char *msg, __attribute__((__unused__)) int error_code)
82 {
83  POSTGIS_DEBUGF(3, "ST_GeomFromGML ERROR %i", error_code);
84  lwpgerror("%s", msg);
85 }
86 
97 Datum geom_from_gml(PG_FUNCTION_ARGS)
98 {
99  GSERIALIZED *geom;
100  text *xml_input;
101  LWGEOM *lwgeom;
102  char *xml;
103  int root_srid=SRID_UNKNOWN;
104  int xml_size;
105 
106  /* Get the GML stream */
107  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
108  xml_input = PG_GETARG_TEXT_P(0);
109  xml = text_to_cstring(xml_input);
110  xml_size = VARSIZE_ANY_EXHDR(xml_input);
111 
112  /* Zero for undefined */
113  root_srid = PG_GETARG_INT32(1);
114 
115  lwgeom = lwgeom_from_gml(xml, xml_size);
116  if ( root_srid != SRID_UNKNOWN )
117  lwgeom->srid = root_srid;
118 
119  geom = geometry_serialize(lwgeom);
120  lwgeom_free(lwgeom);
121 
122  PG_RETURN_POINTER(geom);
123 }
124 
125 
130 static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
131 {
132  xmlNsPtr *ns, *p;
133 
134  ns = xmlGetNsList(xnode->doc, xnode);
135  /*
136  * If no namespace is available we could return true anyway
137  * (because we work only on GML fragment, we don't want to
138  * 'oblige' to add namespace on the geometry root node)
139  */
140  if (ns == NULL) { return !is_strict; }
141 
142  /*
143  * Handle namespaces:
144  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
145  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
146  */
147  for (p=ns ; *p ; p++)
148  {
149  if ((*p)->href == NULL || (*p)->prefix == NULL ||
150  xnode->ns == NULL || xnode->ns->prefix == NULL) continue;
151 
152  if (!xmlStrcmp(xnode->ns->prefix, (*p)->prefix))
153  {
154  if ( !strcmp((char *) (*p)->href, GML_NS)
155  || !strcmp((char *) (*p)->href, GML32_NS))
156  {
157  xmlFree(ns);
158  return true;
159  } else {
160  xmlFree(ns);
161  return false;
162  }
163  }
164  }
165 
166  xmlFree(ns);
167  return !is_strict; /* Same reason here to not return false */
168 }
169 
170 
175 static xmlChar *gmlGetProp(xmlNodePtr xnode, xmlChar *prop)
176 {
177  xmlChar *value;
178 
179  if (!is_gml_namespace(xnode, true))
180  return xmlGetProp(xnode, prop);
181  /*
182  * Handle namespaces:
183  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
184  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
185  */
186  value = xmlGetNsProp(xnode, prop, (xmlChar *) GML_NS);
187  if (value == NULL) value = xmlGetNsProp(xnode, prop, (xmlChar *) GML32_NS);
188 
189  /* In last case try without explicit namespace */
190  if (value == NULL) value = xmlGetNoNsProp(xnode, prop);
191 
192  return value;
193 }
194 
195 
200 static bool is_xlink(xmlNodePtr node)
201 {
202  xmlChar *prop;
203 
204  prop = xmlGetNsProp(node, (xmlChar *)"type", (xmlChar *) XLINK_NS);
205  if (prop == NULL) return false;
206  if (strcmp((char *) prop, "simple"))
207  {
208  xmlFree(prop);
209  return false;
210  }
211 
212  prop = xmlGetNsProp(node, (xmlChar *)"href", (xmlChar *) XLINK_NS);
213  if (prop == NULL) return false;
214  if (prop[0] != '#')
215  {
216  xmlFree(prop);
217  return false;
218  }
219  xmlFree(prop);
220 
221  return true;
222 }
223 
224 
228 static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
229 {
230  char *id;
231  xmlNsPtr *ns, *n;
232  xmlXPathContext *ctx;
233  xmlXPathObject *xpath;
234  xmlNodePtr node, ret_node;
235  xmlChar *href, *p, *node_id;
236 
237  href = xmlGetNsProp(xnode, (xmlChar *)"href", (xmlChar *) XLINK_NS);
238  id = lwalloc((xmlStrlen(xnode->ns->prefix) * 2 + xmlStrlen(xnode->name)
239  + xmlStrlen(href) + sizeof("//:[@:id='']") + 1));
240  p = href;
241  p++; /* ignore '#' first char */
242 
243  /* XPath pattern look like: //gml:point[@gml:id='p1'] */
244  sprintf(id, "//%s:%s[@%s:id='%s']", (char *) xnode->ns->prefix,
245  (char *) xnode->name,
246  (char *) xnode->ns->prefix,
247  (char *) p);
248 
249  ctx = xmlXPathNewContext(xnode->doc);
250  if (ctx == NULL)
251  {
252  xmlFree(href);
253  lwfree(id);
254  return NULL;
255  }
256 
257  /* Handle namespaces */
258  ns = xmlGetNsList(xnode->doc, xnode);
259  for (n=ns ; *n; n++) xmlXPathRegisterNs(ctx, (*n)->prefix, (*n)->href);
260  xmlFree(ns);
261 
262  /* Execute XPath expression */
263  xpath = xmlXPathEvalExpression((xmlChar *) id, ctx);
264  lwfree(id);
265  if (xpath == NULL || xpath->nodesetval == NULL || xpath->nodesetval->nodeNr != 1)
266  {
267  xmlFree(href);
268  xmlXPathFreeObject(xpath);
269  xmlXPathFreeContext(ctx);
270  return NULL;
271  }
272  ret_node = xpath->nodesetval->nodeTab[0];
273  xmlXPathFreeObject(xpath);
274  xmlXPathFreeContext(ctx);
275 
276  /* Protection against circular calls */
277  for (node = xnode ; node != NULL ; node = node->parent)
278  {
279  if (node->type != XML_ELEMENT_NODE) continue;
280  node_id = gmlGetProp(node, (xmlChar *) "id");
281  if (node_id != NULL)
282  {
283  if (!xmlStrcmp(node_id, p))
284  gml_lwpgerror("invalid GML representation", 2);
285  xmlFree(node_id);
286  }
287  }
288 
289  xmlFree(href);
290  return ret_node;
291 }
292 
293 
294 
299 static POINTARRAY *
300 gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
301 {
302  LWPROJ *lwp;
303  char text_in[16];
304  char text_out[16];
305 
306  if (epsg_in == SRID_UNKNOWN)
307  return pa; /* nothing to do */
308 
309  if (epsg_out == SRID_UNKNOWN)
310  {
311  gml_lwpgerror("invalid GML representation", 3);
312  return NULL;
313  }
314 
315  snprintf(text_in, 16, "EPSG:%d", epsg_in);
316  snprintf(text_out, 16, "EPSG:%d", epsg_out);
317 
318 
319  lwp = lwproj_from_str(text_in, text_out);
320  if (!lwp)
321  {
322  gml_lwpgerror("Could not create LWPROJ*", 57);
323  return NULL;
324  }
325 
326  if (ptarray_transform(pa, lwp) == LW_FAILURE)
327  {
328  elog(ERROR, "gml_reproject_pa: reprojection failed");
329  return NULL;
330  }
331  proj_destroy(lwp->pj);
332  pfree(lwp);
333 
334  return pa;
335 }
336 
342 static int
344 {
345  char *srtext;
346  char query[256];
347  int is_axis_order_gis_friendly, err;
348 
349  if (SPI_OK_CONNECT != SPI_connect ())
350  lwpgerror("gml_is_srs_axis_order_gis_friendly: could not connect to SPI manager");
351 
352  sprintf(query, "SELECT srtext \
353  FROM spatial_ref_sys WHERE srid='%d'", srid);
354 
355  err = SPI_exec(query, 1);
356  if (err < 0) lwpgerror("gml_is_srs_axis_order_gis_friendly: error executing query %d", err);
357 
358  /* No entry in spatial_ref_sys */
359  if (SPI_processed <= 0)
360  {
361  SPI_finish();
362  return -1;
363  }
364 
365  srtext = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
366 
367  is_axis_order_gis_friendly = 1;
368  if (srtext && srtext[0] != '\0')
369  {
370  char* ptr;
371  char* srtext_horizontal = (char*) malloc(strlen(srtext) + 1);
372  strcpy(srtext_horizontal, srtext);
373 
374  /* Remove the VERT_CS part if we are in a COMPD_CS */
375  ptr = strstr(srtext_horizontal, ",VERT_CS[");
376  if (ptr)
377  *ptr = '\0';
378 
379  if( strstr(srtext_horizontal, "AXIS[") == NULL &&
380  strstr(srtext_horizontal, "GEOCCS[") == NULL )
381  {
382  /* If there is no axis definition, then due to how GDAL < 3
383  * generated the WKT, this means that the axis order is not
384  * GIS friendly */
385  is_axis_order_gis_friendly = 0;
386  }
387  else if( strstr(srtext_horizontal,
388  "AXIS[\"Latitude\",NORTH],AXIS[\"Longitude\",EAST]") != NULL )
389  {
390  is_axis_order_gis_friendly = 0;
391  }
392  else if( strstr(srtext_horizontal,
393  "AXIS[\"Northing\",NORTH],AXIS[\"Easting\",EAST]") != NULL )
394  {
395  is_axis_order_gis_friendly = 0;
396  }
397  else if( strstr(srtext_horizontal,
398  "AXIS[\"geodetic latitude (Lat)\",north,ORDER[1]") != NULL )
399  {
400  is_axis_order_gis_friendly = 0;
401  }
402 
403  free(srtext_horizontal);
404  }
405  SPI_finish();
406 
407  return is_axis_order_gis_friendly;
408 }
409 
410 
414 static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
415 {
416  char *p;
417  int is_axis_order_gis_friendly;
418  xmlNodePtr node;
419  xmlChar *srsname;
420  bool honours_authority_axis_order = false;
421  char sep = ':';
422 
423  node = xnode;
424  srsname = gmlGetProp(node, (xmlChar *) "srsName");
425  /*printf("srsname %s\n",srsname);*/
426  if (!srsname)
427  {
428  if (node->parent == NULL)
429  {
430  srs->srid = SRID_UNKNOWN;
431  srs->reverse_axis = false;
432  return;
433  }
434  parse_gml_srs(node->parent, srs);
435  }
436  else
437  {
438  /* Severals srsName formats are available...
439  * cf WFS 1.1.0 -> 9.2 (p36)
440  * cf ISO 19142:2009 -> 7.9.2.4.4 (p34)
441  * cf RFC 5165 <http://tools.ietf.org/html/rfc5165>
442  * cf CITE WFS-1.1 (GetFeature-tc17.2)
443  */
444 
445  /* SRS pattern like: EPSG:4326
446  urn:EPSG:geographicCRS:4326
447  urn:ogc:def:crs:EPSG:4326
448  urn:ogc:def:crs:EPSG::4326
449  urn:ogc:def:crs:EPSG:6.6:4326
450  urn:x-ogc:def:crs:EPSG:6.6:4326
451  http://www.opengis.net/gml/srs/epsg.xml#4326
452  http://www.epsg.org/6.11.2/4326
453  */
454 
455  if (!strncmp((char *) srsname, "EPSG:", 5))
456  {
457  sep = ':';
458  honours_authority_axis_order = false;
459  }
460  else if (!strncmp((char *) srsname, "urn:ogc:def:crs:EPSG:", 21)
461  || !strncmp((char *) srsname, "urn:x-ogc:def:crs:EPSG:", 23)
462  || !strncmp((char *) srsname, "urn:EPSG:geographicCRS:", 23))
463  {
464  sep = ':';
465  honours_authority_axis_order = true;
466  }
467  else if (!strncmp((char *) srsname,
468  "http://www.opengis.net/gml/srs/epsg.xml#", 40))
469  {
470  sep = '#';
471  honours_authority_axis_order = false;
472  }
473  else gml_lwpgerror("unknown spatial reference system", 4);
474 
475  /* retrieve the last ':' or '#' char */
476  for (p = (char *) srsname ; *p ; p++);
477  for (--p ; *p != sep ; p--)
478  if (!isdigit(*p)) gml_lwpgerror("unknown spatial reference system", 5);
479 
480  srs->srid = atoi(++p);
481 
482  /* Check into spatial_ref_sys that this SRID really exist */
483  is_axis_order_gis_friendly = gml_is_srs_axis_order_gis_friendly(srs->srid);
484  if (srs->srid == SRID_UNKNOWN || is_axis_order_gis_friendly == -1)
485  gml_lwpgerror("unknown spatial reference system", 6);
486 
487  /* Reverse axis order if the srsName is meant to honour the axis
488  order defined by the authority and if that axis order is not
489  the GIS friendly one. */
490  srs->reverse_axis = !is_axis_order_gis_friendly && honours_authority_axis_order;
491 
492  xmlFree(srsname);
493  return;
494  }
495 }
496 
497 
501 static double parse_gml_double(char *d, bool space_before, bool space_after)
502 {
503  char *p;
504  int st;
505  enum states
506  {
507  INIT = 0,
508  NEED_DIG = 1,
509  DIG = 2,
510  NEED_DIG_DEC = 3,
511  DIG_DEC = 4,
512  EXP = 5,
513  NEED_DIG_EXP = 6,
514  DIG_EXP = 7,
515  END = 8
516  };
517 
518  /*
519  * Double pattern
520  * [-|\+]?[0-9]+(\.)?([0-9]+)?([Ee](\+|-)?[0-9]+)?
521  * We could also meet spaces before and/or after
522  * this pattern upon parameters
523  */
524 
525  if (space_before) while (isspace(*d)) d++;
526  for (st = INIT, p = d ; *p ; p++)
527  {
528 
529  if (isdigit(*p))
530  {
531  if (st == INIT || st == NEED_DIG) st = DIG;
532  else if (st == NEED_DIG_DEC) st = DIG_DEC;
533  else if (st == NEED_DIG_EXP || st == EXP) st = DIG_EXP;
534  else if (st == DIG || st == DIG_DEC || st == DIG_EXP);
535  else gml_lwpgerror("invalid GML representation", 7);
536  }
537  else if (*p == '.')
538  {
539  if (st == DIG) st = NEED_DIG_DEC;
540  else gml_lwpgerror("invalid GML representation", 8);
541  }
542  else if (*p == '-' || *p == '+')
543  {
544  if (st == INIT) st = NEED_DIG;
545  else if (st == EXP) st = NEED_DIG_EXP;
546  else gml_lwpgerror("invalid GML representation", 9);
547  }
548  else if (*p == 'e' || *p == 'E')
549  {
550  if (st == DIG || st == DIG_DEC) st = EXP;
551  else gml_lwpgerror("invalid GML representation", 10);
552  }
553  else if (isspace(*p))
554  {
555  if (!space_after) gml_lwpgerror("invalid GML representation", 11);
556  if (st == DIG || st == DIG_DEC || st == DIG_EXP)st = END;
557  else if (st == NEED_DIG_DEC) st = END;
558  else if (st == END);
559  else gml_lwpgerror("invalid GML representation", 12);
560  }
561  else gml_lwpgerror("invalid GML representation", 13);
562  }
563 
564  if (st != DIG && st != NEED_DIG_DEC && st != DIG_DEC && st != DIG_EXP && st != END)
565  gml_lwpgerror("invalid GML representation", 14);
566 
567  return atof(d);
568 }
569 
570 
574 static POINTARRAY* parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
575 {
576  xmlChar *gml_coord, *gml_ts, *gml_cs, *gml_dec;
577  char cs, ts, dec;
578  POINTARRAY *dpa;
579  int gml_dims;
580  char *p, *q;
581  bool digit;
582  POINT4D pt = {0};
583 
584  /* We begin to retrieve coordinates string */
585  gml_coord = xmlNodeGetContent(xnode);
586  p = (char *) gml_coord;
587 
588  /* Default GML coordinates pattern: x1,y1 x2,y2
589  * x1,y1,z1 x2,y2,z2
590  *
591  * Cf GML 2.1.2 -> 4.3.1 (p18)
592  */
593 
594  /* Retrieve separator between coordinates tuples */
595  gml_ts = gmlGetProp(xnode, (xmlChar *) "ts");
596  if (gml_ts == NULL) ts = ' ';
597  else
598  {
599  if (xmlStrlen(gml_ts) > 1 || isdigit(gml_ts[0]))
600  gml_lwpgerror("invalid GML representation", 15);
601  ts = gml_ts[0];
602  xmlFree(gml_ts);
603  }
604 
605  /* Retrieve separator between each coordinate */
606  gml_cs = gmlGetProp(xnode, (xmlChar *) "cs");
607  if (gml_cs == NULL) cs = ',';
608  else
609  {
610  if (xmlStrlen(gml_cs) > 1 || isdigit(gml_cs[0]))
611  gml_lwpgerror("invalid GML representation", 16);
612  cs = gml_cs[0];
613  xmlFree(gml_cs);
614  }
615 
616  /* Retrieve decimal separator */
617  gml_dec = gmlGetProp(xnode, (xmlChar *) "decimal");
618  if (gml_dec == NULL) dec = '.';
619  else
620  {
621  if (xmlStrlen(gml_dec) > 1 || isdigit(gml_dec[0]))
622  gml_lwpgerror("invalid GML representation", 17);
623  dec = gml_dec[0];
624  xmlFree(gml_dec);
625  }
626 
627  if (cs == ts || cs == dec || ts == dec)
628  gml_lwpgerror("invalid GML representation", 18);
629 
630  /* HasZ, !HasM, 1 Point */
631  dpa = ptarray_construct_empty(1, 0, 1);
632 
633  while (isspace(*p)) p++; /* Eat extra whitespaces if any */
634  for (q = p, gml_dims=0, digit = false ; *p ; p++)
635  {
636 
637  if (isdigit(*p)) digit = true; /* One state parser */
638 
639  /* Coordinate Separator */
640  if (*p == cs)
641  {
642  *p = '\0';
643  gml_dims++;
644 
645  if (*(p+1) == '\0') gml_lwpgerror("invalid GML representation", 19);
646 
647  if (gml_dims == 1) pt.x = parse_gml_double(q, false, true);
648  else if (gml_dims == 2) pt.y = parse_gml_double(q, false, true);
649 
650  q = p+1;
651 
652  /* Tuple Separator (or end string) */
653  }
654  else if (digit && (*p == ts || *(p+1) == '\0'))
655  {
656  if (*p == ts) *p = '\0';
657  gml_dims++;
658 
659  if (gml_dims < 2 || gml_dims > 3)
660  gml_lwpgerror("invalid GML representation", 20);
661 
662  if (gml_dims == 3)
663  pt.z = parse_gml_double(q, false, true);
664  else
665  {
666  pt.y = parse_gml_double(q, false, true);
667  *hasz = false;
668  }
669 
670  ptarray_append_point(dpa, &pt, LW_TRUE);
671  digit = false;
672 
673  q = p+1;
674  gml_dims = 0;
675 
676  /* Need to put standard decimal separator to atof handle */
677  }
678  else if (*p == dec && dec != '.') *p = '.';
679  }
680 
681  xmlFree(gml_coord);
682 
683  return dpa; /* ptarray_clone_deep(dpa); */
684 }
685 
686 
690 static POINTARRAY* parse_gml_coord(xmlNodePtr xnode, bool *hasz)
691 {
692  xmlNodePtr xyz;
693  POINTARRAY *dpa;
694  bool x,y,z;
695  xmlChar *c;
696  POINT4D p = {0};
697 
698  /* HasZ?, !HasM, 1 Point */
699  dpa = ptarray_construct_empty(1, 0, 1);
700 
701  x = y = z = false;
702  for (xyz = xnode->children ; xyz != NULL ; xyz = xyz->next)
703  {
704  if (xyz->type != XML_ELEMENT_NODE) continue;
705  if (!is_gml_namespace(xyz, false)) continue;
706 
707  if (!strcmp((char *) xyz->name, "X"))
708  {
709  if (x) gml_lwpgerror("invalid GML representation", 21);
710  c = xmlNodeGetContent(xyz);
711  p.x = parse_gml_double((char *) c, true, true);
712  x = true;
713  xmlFree(c);
714  }
715  else if (!strcmp((char *) xyz->name, "Y"))
716  {
717  if (y) gml_lwpgerror("invalid GML representation", 22);
718  c = xmlNodeGetContent(xyz);
719  p.y = parse_gml_double((char *) c, true, true);
720  y = true;
721  xmlFree(c);
722  }
723  else if (!strcmp((char *) xyz->name, "Z"))
724  {
725  if (z) gml_lwpgerror("invalid GML representation", 23);
726  c = xmlNodeGetContent(xyz);
727  p.z = parse_gml_double((char *) c, true, true);
728  z = true;
729  xmlFree(c);
730  }
731  }
732  /* Check dimension consistancy */
733  if (!x || !y) gml_lwpgerror("invalid GML representation", 24);
734  if (!z) *hasz = false;
735 
736  ptarray_append_point(dpa, &p, LW_FALSE);
737 
738  return dpa; /* ptarray_clone_deep(dpa); */
739 }
740 
741 
745 static POINTARRAY* parse_gml_pos(xmlNodePtr xnode, bool *hasz)
746 {
747  xmlChar *dimension, *gmlpos;
748  int dim, gml_dim;
749  POINTARRAY *dpa;
750  char *pos, *p;
751  bool digit;
752  POINT4D pt = {0, 0, 0, 0};
753 
754  /* HasZ, !HasM, 1 Point */
755  dpa = ptarray_construct_empty(1, 0, 1);
756 
757  dimension = gmlGetProp(xnode, (xmlChar *) "srsDimension");
758  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
759  dimension = gmlGetProp(xnode, (xmlChar *) "dimension");
760  if (dimension == NULL) dim = 2; /* We assume that we are in 2D */
761  else
762  {
763  dim = atoi((char *) dimension);
764  xmlFree(dimension);
765  if (dim < 2 || dim > 3)
766  gml_lwpgerror("invalid GML representation", 25);
767  }
768  if (dim == 2) *hasz = false;
769 
770  /* We retrieve gml:pos string */
771  gmlpos = xmlNodeGetContent(xnode);
772  pos = (char *) gmlpos;
773  while (isspace(*pos)) pos++; /* Eat extra whitespaces if any */
774 
775  /* gml:pos pattern: x1 y1
776  * x1 y1 z1
777  */
778  for (p=pos, gml_dim=0, digit=false ; *pos ; pos++)
779  {
780  if (isdigit(*pos)) digit = true;
781  if (digit && (*pos == ' ' || *(pos+1) == '\0'))
782  {
783  if (*pos == ' ') *pos = '\0';
784  gml_dim++;
785  if (gml_dim == 1)
786  pt.x = parse_gml_double(p, true, true);
787  else if (gml_dim == 2)
788  pt.y = parse_gml_double(p, true, true);
789  else if (gml_dim == 3)
790  pt.z = parse_gml_double(p, true, true);
791 
792  p = pos+1;
793  digit = false;
794  }
795  }
796  xmlFree(gmlpos);
797 
798  /* Test again coherent dimensions on each coord */
799  if (gml_dim == 2) *hasz = false;
800  if (gml_dim < 2 || gml_dim > 3 || gml_dim != dim)
801  gml_lwpgerror("invalid GML representation", 26);
802 
803  ptarray_append_point(dpa, &pt, LW_FALSE);
804 
805  return dpa; /* ptarray_clone_deep(dpa); */
806 }
807 
808 
812 static POINTARRAY* parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
813 {
814  xmlChar *dimension, *gmlposlist;
815  char *poslist, *p;
816  int dim, gml_dim;
817  POINTARRAY *dpa;
818  POINT4D pt = {0, 0, 0, 0};
819  bool digit;
820 
821  /* Retrieve gml:srsDimension attribute if any */
822  dimension = gmlGetProp(xnode, (xmlChar *) "srsDimension");
823  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
824  dimension = gmlGetProp(xnode, (xmlChar *) "dimension");
825  if (dimension == NULL) dim = 2; /* We assume that we are in common 2D */
826  else
827  {
828  dim = atoi((char *) dimension);
829  xmlFree(dimension);
830  if (dim < 2 || dim > 3) gml_lwpgerror("invalid GML representation", 27);
831  }
832  if (dim == 2) *hasz = false;
833 
834  /* Retrieve gml:posList string */
835  gmlposlist = xmlNodeGetContent(xnode);
836  poslist = (char *) gmlposlist;
837 
838  /* HasZ?, !HasM, 1 point */
839  dpa = ptarray_construct_empty(1, 0, 1);
840 
841  /* gml:posList pattern: x1 y1 x2 y2
842  * x1 y1 z1 x2 y2 z2
843  */
844  while (isspace(*poslist)) poslist++; /* Eat extra whitespaces if any */
845  for (p=poslist, gml_dim=0, digit=false ; *poslist ; poslist++)
846  {
847  if (isdigit(*poslist)) digit = true;
848  if (digit && (*poslist == ' ' || *(poslist+1) == '\0'))
849  {
850  if (*poslist == ' ') *poslist = '\0';
851 
852  gml_dim++;
853  if (gml_dim == 1) pt.x = parse_gml_double(p, true, true);
854  else if (gml_dim == 2) pt.y = parse_gml_double(p, true, true);
855  else if (gml_dim == 3) pt.z = parse_gml_double(p, true, true);
856 
857  if (gml_dim == dim)
858  {
859  /* Add to ptarray, allowing dupes */
860  ptarray_append_point(dpa, &pt, LW_TRUE);
861  pt.x = pt.y = pt.z = pt.m = 0.0;
862  gml_dim = 0;
863  }
864  else if (*(poslist+1) == '\0')
865  gml_lwpgerror("invalid GML representation", 28);
866 
867  p = poslist+1;
868  digit = false;
869  }
870  }
871 
872  xmlFree(gmlposlist);
873 
874  return dpa; /* ptarray_clone_deep(dpa); */
875 }
876 
877 
890 static POINTARRAY* parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
891 {
892  POINTARRAY *pa = 0, *tmp_pa = 0;
893  xmlNodePtr xa, xb;
894  gmlSrs srs;
895  bool found;
896 
897  pa = NULL;
898 
899  for (xa = xnode ; xa != NULL ; xa = xa->next)
900  {
901  if (xa->type != XML_ELEMENT_NODE) continue;
902  if (!is_gml_namespace(xa, false)) continue;
903  if (xa->name == NULL) continue;
904 
905  if (!strcmp((char *) xa->name, "pos"))
906  {
907  tmp_pa = parse_gml_pos(xa, hasz);
908  if (pa == NULL) pa = tmp_pa;
909  else pa = ptarray_merge(pa, tmp_pa);
910 
911  }
912  else if (!strcmp((char *) xa->name, "posList"))
913  {
914  tmp_pa = parse_gml_poslist(xa, hasz);
915  if (pa == NULL) pa = tmp_pa;
916  else pa = ptarray_merge(pa, tmp_pa);
917 
918  }
919  else if (!strcmp((char *) xa->name, "coordinates"))
920  {
921  tmp_pa = parse_gml_coordinates(xa, hasz);
922  if (pa == NULL) pa = tmp_pa;
923  else pa = ptarray_merge(pa, tmp_pa);
924 
925  }
926  else if (!strcmp((char *) xa->name, "coord"))
927  {
928  tmp_pa = parse_gml_coord(xa, hasz);
929  if (pa == NULL) pa = tmp_pa;
930  else pa = ptarray_merge(pa, tmp_pa);
931 
932  }
933  else if (!strcmp((char *) xa->name, "pointRep") ||
934  !strcmp((char *) xa->name, "pointProperty"))
935  {
936 
937  found = false;
938  for (xb = xa->children ; xb != NULL ; xb = xb->next)
939  {
940  if (xb->type != XML_ELEMENT_NODE) continue;
941  if (!is_gml_namespace(xb, false)) continue;
942  if (!strcmp((char *) xb->name, "Point"))
943  {
944  found = true;
945  break;
946  }
947  }
948  if (!found || xb == NULL)
949  gml_lwpgerror("invalid GML representation", 29);
950 
951  if (is_xlink(xb)) xb = get_xlink_node(xb);
952  if (xb == NULL || xb->children == NULL)
953  gml_lwpgerror("invalid GML representation", 30);
954 
955  tmp_pa = parse_gml_data(xb->children, hasz, root_srid);
956  if (tmp_pa->npoints != 1)
957  gml_lwpgerror("invalid GML representation", 31);
958 
959  parse_gml_srs(xb, &srs);
960  if (srs.reverse_axis) tmp_pa = ptarray_flip_coordinates(tmp_pa);
961  if (*root_srid == SRID_UNKNOWN) *root_srid = srs.srid;
962  else if (srs.srid != *root_srid)
963  gml_reproject_pa(tmp_pa, srs.srid, *root_srid);
964  if (pa == NULL) pa = tmp_pa;
965  else pa = ptarray_merge(pa, tmp_pa);
966  }
967  }
968 
969  if (pa == NULL) gml_lwpgerror("invalid GML representation", 32);
970 
971  return pa;
972 }
973 
974 
978 static LWGEOM* parse_gml_point(xmlNodePtr xnode, bool *hasz, int *root_srid)
979 {
980  gmlSrs srs;
981  LWGEOM *geom;
982  POINTARRAY *pa;
983 
984  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
985 
986  if (xnode->children == NULL)
987  return lwpoint_as_lwgeom(lwpoint_construct_empty(*root_srid, 0, 0));
988 
989  pa = parse_gml_data(xnode->children, hasz, root_srid);
990  if (pa->npoints != 1) gml_lwpgerror("invalid GML representation", 34);
991 
992  parse_gml_srs(xnode, &srs);
993  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
994  if (!*root_srid)
995  {
996  *root_srid = srs.srid;
997  geom = (LWGEOM *) lwpoint_construct(*root_srid, NULL, pa);
998  }
999  else
1000  {
1001  if (srs.srid != *root_srid)
1002  gml_reproject_pa(pa, srs.srid, *root_srid);
1003  geom = (LWGEOM *) lwpoint_construct(SRID_UNKNOWN, NULL, pa);
1004  }
1005 
1006  return geom;
1007 }
1008 
1009 
1013 static LWGEOM* parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
1014 {
1015  gmlSrs srs;
1016  LWGEOM *geom;
1017  POINTARRAY *pa;
1018 
1019  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1020 
1021  if (xnode->children == NULL)
1022  return lwline_as_lwgeom(lwline_construct_empty(*root_srid, 0, 0));
1023 
1024  pa = parse_gml_data(xnode->children, hasz, root_srid);
1025  if (pa->npoints < 2) gml_lwpgerror("invalid GML representation", 36);
1026 
1027  parse_gml_srs(xnode, &srs);
1028  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1029  if (!*root_srid)
1030  {
1031  *root_srid = srs.srid;
1032  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
1033  }
1034  else
1035  {
1036  if (srs.srid != *root_srid)
1037  gml_reproject_pa(pa, srs.srid, *root_srid);
1038  geom = (LWGEOM *) lwline_construct(SRID_UNKNOWN, NULL, pa);
1039  }
1040 
1041  return geom;
1042 }
1043 
1044 
1048 static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
1049 {
1050  xmlNodePtr xa;
1051  size_t lss;
1052  bool found=false;
1053  gmlSrs srs;
1054  LWGEOM *geom=NULL;
1055  POINTARRAY *pa=NULL;
1056  POINTARRAY **ppa=NULL;
1057  uint32 npoints=0;
1058  xmlChar *interpolation=NULL;
1059 
1060  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1061 
1062  /* Looking for gml:segments */
1063  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1064  {
1065  if (xa->type != XML_ELEMENT_NODE) continue;
1066  if (!is_gml_namespace(xa, false)) continue;
1067  if (!strcmp((char *) xa->name, "segments"))
1068  {
1069  found = true;
1070  break;
1071  }
1072  }
1073  if (!found) gml_lwpgerror("invalid GML representation", 37);
1074 
1075  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1076 
1077  /* Processing each gml:LineStringSegment */
1078  for (xa = xa->children, lss=0; xa != NULL ; xa = xa->next)
1079  {
1080  if (xa->type != XML_ELEMENT_NODE) continue;
1081  if (!is_gml_namespace(xa, false)) continue;
1082  if (strcmp((char *) xa->name, "LineStringSegment")) continue;
1083 
1084  /* GML SF is restricted to linear interpolation */
1085  interpolation = gmlGetProp(xa, (xmlChar *) "interpolation");
1086  if (interpolation != NULL)
1087  {
1088  if (strcmp((char *) interpolation, "linear"))
1089  gml_lwpgerror("invalid GML representation", 38);
1090  xmlFree(interpolation);
1091  }
1092 
1093  if (lss > 0) ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1094  sizeof(POINTARRAY*) * (lss + 1));
1095 
1096  ppa[lss] = parse_gml_data(xa->children, hasz, root_srid);
1097  npoints += ppa[lss]->npoints;
1098  if (ppa[lss]->npoints < 2)
1099  gml_lwpgerror("invalid GML representation", 39);
1100  lss++;
1101  }
1102  if (lss == 0) gml_lwpgerror("invalid GML representation", 40);
1103 
1104  /* Most common case, a single segment */
1105  if (lss == 1) pa = ppa[0];
1106 
1107  if (lss > 1)
1108  {
1109  /*
1110  * "The curve segments are connected to one another, with the end point
1111  * of each segment except the last being the start point of the next
1112  * segment" from ISO 19107:2003 -> 6.3.16.1 (p43)
1113  *
1114  * So we must aggregate all the segments into a single one and avoid
1115  * to copy the redundant points
1116  */
1117  size_t cp_point_size = sizeof(POINT3D); /* All internals are done with 3D */
1118  size_t final_point_size = *hasz ? sizeof(POINT3D) : sizeof(POINT2D);
1119  pa = ptarray_construct(1, 0, npoints - lss + 1);
1120 
1121  /* Copy the first linestring fully */
1122  memcpy(getPoint_internal(pa, 0), getPoint_internal(ppa[0], 0), cp_point_size * (ppa[0]->npoints));
1123  npoints = ppa[0]->npoints;
1124  lwfree(ppa[0]);
1125 
1126  /* For the rest of linestrings, ensure the first point matches the
1127  * last point of the previous one, and copy all points except the
1128  * first one (since it'd be repeated)
1129  */
1130  for (size_t i = 1; i < lss; i++)
1131  {
1132  if (memcmp(getPoint_internal(pa, npoints - 1), getPoint_internal(ppa[i], 0), final_point_size))
1133  gml_lwpgerror("invalid GML representation", 41);
1134 
1135  memcpy(getPoint_internal(pa, npoints),
1136  getPoint_internal(ppa[i], 1),
1137  cp_point_size * (ppa[i]->npoints - 1));
1138 
1139  npoints += ppa[i]->npoints - 1;
1140  lwfree(ppa[i]);
1141  }
1142  }
1143 
1144  lwfree(ppa);
1145 
1146  parse_gml_srs(xnode, &srs);
1147  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1148  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1149  gml_reproject_pa(pa, srs.srid, *root_srid);
1150  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
1151 
1152  return geom;
1153 }
1154 
1155 
1159 static LWGEOM* parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
1160 {
1161  gmlSrs srs;
1162  LWGEOM *geom;
1163  POINTARRAY **ppa = NULL;
1164 
1165  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1166  parse_gml_srs(xnode, &srs);
1167 
1168  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1169  ppa[0] = parse_gml_data(xnode->children, hasz, root_srid);
1170 
1171  if (ppa[0]->npoints < 4
1172  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1173  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1174  gml_lwpgerror("invalid GML representation", 42);
1175 
1176  if (srs.reverse_axis)
1177  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1178 
1179  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1180  gml_reproject_pa(ppa[0], srs.srid, *root_srid);
1181 
1182  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, 1, ppa);
1183 
1184  return geom;
1185 }
1186 
1187 
1191 static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
1192 {
1193  gmlSrs srs;
1194  int i, ring;
1195  LWGEOM *geom;
1196  xmlNodePtr xa, xb;
1197  POINTARRAY **ppa = NULL;
1198 
1199  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1200 
1201  if (xnode->children == NULL)
1202  return lwpoly_as_lwgeom(lwpoly_construct_empty(*root_srid, 0, 0));
1203 
1204  parse_gml_srs(xnode, &srs);
1205 
1206  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1207  {
1208  /* Polygon/outerBoundaryIs -> GML 2.1.2 */
1209  /* Polygon/exterior -> GML 3.1.1 */
1210  if (xa->type != XML_ELEMENT_NODE) continue;
1211  if (!is_gml_namespace(xa, false)) continue;
1212  if (strcmp((char *) xa->name, "outerBoundaryIs") &&
1213  strcmp((char *) xa->name, "exterior")) continue;
1214 
1215  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1216  {
1217  if (xb->type != XML_ELEMENT_NODE) continue;
1218  if (!is_gml_namespace(xb, false)) continue;
1219  if (strcmp((char *) xb->name, "LinearRing")) continue;
1220 
1221  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1222  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1223 
1224  if (ppa[0]->npoints < 4
1225  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1226  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1227  gml_lwpgerror("invalid GML representation", 43);
1228 
1229  if (srs.reverse_axis) ppa[0] = ptarray_flip_coordinates(ppa[0]);
1230  }
1231  }
1232 
1233  /* Found an <exterior> or <outerBoundaryIs> but no rings?!? We're outa here! */
1234  if ( ! ppa )
1235  gml_lwpgerror("invalid GML representation", 43);
1236 
1237  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1238  {
1239  /* Polygon/innerBoundaryIs -> GML 2.1.2 */
1240  /* Polygon/interior -> GML 3.1.1 */
1241  if (xa->type != XML_ELEMENT_NODE) continue;
1242  if (!is_gml_namespace(xa, false)) continue;
1243  if (strcmp((char *) xa->name, "innerBoundaryIs") &&
1244  strcmp((char *) xa->name, "interior")) continue;
1245 
1246  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1247  {
1248  if (xb->type != XML_ELEMENT_NODE) continue;
1249  if (!is_gml_namespace(xb, false)) continue;
1250  if (strcmp((char *) xb->name, "LinearRing")) continue;
1251 
1252  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1253  sizeof(POINTARRAY*) * (ring + 1));
1254  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1255 
1256  if (ppa[ring]->npoints < 4
1257  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1258  || (*hasz && !ptarray_is_closed_3d(ppa[ring])))
1259  gml_lwpgerror("invalid GML representation", 43);
1260 
1261  if (srs.reverse_axis) ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1262  ring++;
1263  }
1264  }
1265 
1266  /* Exterior Ring is mandatory */
1267  if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 44);
1268 
1269  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1270  {
1271  for (i=0 ; i < ring ; i++)
1272  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1273  }
1274  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1275 
1276  return geom;
1277 }
1278 
1279 
1283 static LWGEOM* parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
1284 {
1285  gmlSrs srs;
1286  LWGEOM *geom;
1287  xmlNodePtr xa, xb;
1288  POINTARRAY *pa = NULL;
1289  xmlChar *interpolation=NULL;
1290 
1291  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1292 
1293  if (xnode->children == NULL)
1294  return lwtriangle_as_lwgeom(lwtriangle_construct_empty(*root_srid, 0, 0));
1295 
1296  /* GML SF is restricted to planar interpolation
1297  NOTA: I know Triangle is not part of SF, but
1298  we have to be consistent with other surfaces */
1299  interpolation = gmlGetProp(xnode, (xmlChar *) "interpolation");
1300  if (interpolation != NULL)
1301  {
1302  if (strcmp((char *) interpolation, "planar"))
1303  gml_lwpgerror("invalid GML representation", 45);
1304  xmlFree(interpolation);
1305  }
1306 
1307  parse_gml_srs(xnode, &srs);
1308 
1309  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1310  {
1311  /* Triangle/exterior */
1312  if (xa->type != XML_ELEMENT_NODE) continue;
1313  if (!is_gml_namespace(xa, false)) continue;
1314  if (strcmp((char *) xa->name, "exterior")) continue;
1315 
1316  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1317  {
1318  /* Triangle/exterior/LinearRing */
1319  if (xb->type != XML_ELEMENT_NODE) continue;
1320  if (!is_gml_namespace(xb, false)) continue;
1321  if (strcmp((char *) xb->name, "LinearRing")) continue;
1322 
1323  pa = (POINTARRAY*) lwalloc(sizeof(POINTARRAY));
1324  pa = parse_gml_data(xb->children, hasz, root_srid);
1325 
1326  if (pa->npoints != 4
1327  || (!*hasz && !ptarray_is_closed_2d(pa))
1328  || (*hasz && !ptarray_is_closed_3d(pa)))
1329  gml_lwpgerror("invalid GML representation", 46);
1330 
1331  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1332  }
1333  }
1334 
1335  /* Exterior Ring is mandatory */
1336  if (pa == NULL) gml_lwpgerror("invalid GML representation", 47);
1337 
1338  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1339  gml_reproject_pa(pa, srs.srid, *root_srid);
1340 
1341  geom = (LWGEOM *) lwtriangle_construct(*root_srid, NULL, pa);
1342 
1343  return geom;
1344 }
1345 
1346 
1350 static LWGEOM* parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
1351 {
1352  xmlChar *interpolation=NULL;
1353  POINTARRAY **ppa=NULL;
1354  LWGEOM *geom=NULL;
1355  xmlNodePtr xa, xb;
1356  int i, ring=0;
1357  gmlSrs srs;
1358 
1359  /* PolygonPatch */
1360  if (strcmp((char *) xnode->name, "PolygonPatch"))
1361  gml_lwpgerror("invalid GML representation", 48);
1362 
1363  /* GML SF is restricted to planar interpolation */
1364  interpolation = gmlGetProp(xnode, (xmlChar *) "interpolation");
1365  if (interpolation != NULL)
1366  {
1367  if (strcmp((char *) interpolation, "planar"))
1368  gml_lwpgerror("invalid GML representation", 48);
1369  xmlFree(interpolation);
1370  }
1371 
1372  parse_gml_srs(xnode, &srs);
1373 
1374  /* PolygonPatch/exterior */
1375  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1376  {
1377  if (!is_gml_namespace(xa, false)) continue;
1378  if (strcmp((char *) xa->name, "exterior")) continue;
1379 
1380  /* PolygonPatch/exterior/LinearRing */
1381  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1382  {
1383  if (xb->type != XML_ELEMENT_NODE) continue;
1384  if (!is_gml_namespace(xb, false)) continue;
1385  if (strcmp((char *) xb->name, "LinearRing")) continue;
1386 
1387  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1388  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1389 
1390  if (ppa[0]->npoints < 4
1391  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1392  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1393  gml_lwpgerror("invalid GML representation", 48);
1394 
1395  if (srs.reverse_axis)
1396  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1397  }
1398  }
1399 
1400  /* Interior but no Exterior ! */
1401  if ( ! ppa )
1402  gml_lwpgerror("invalid GML representation", 48);
1403 
1404  /* PolygonPatch/interior */
1405  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1406  {
1407  if (xa->type != XML_ELEMENT_NODE) continue;
1408  if (!is_gml_namespace(xa, false)) continue;
1409  if (strcmp((char *) xa->name, "interior")) continue;
1410 
1411  /* PolygonPatch/interior/LinearRing */
1412  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1413  {
1414  if (xb->type != XML_ELEMENT_NODE) continue;
1415  if (strcmp((char *) xb->name, "LinearRing")) continue;
1416 
1417  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1418  sizeof(POINTARRAY*) * (ring + 1));
1419  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1420 
1421  if (ppa[ring]->npoints < 4
1422  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1423  || ( *hasz && !ptarray_is_closed_3d(ppa[ring])))
1424  gml_lwpgerror("invalid GML representation", 49);
1425 
1426  if (srs.reverse_axis)
1427  ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1428 
1429  ring++;
1430  }
1431  }
1432 
1433  /* Exterior Ring is mandatory */
1434  if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 50);
1435 
1436  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1437  {
1438  for (i=0 ; i < ring ; i++)
1439  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1440  }
1441  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1442 
1443  return geom;
1444 }
1445 
1446 
1450 static LWGEOM* parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1451 {
1452  xmlNodePtr xa;
1453  int patch;
1454  LWGEOM *geom=NULL;
1455  bool found=false;
1456 
1457  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1458 
1459  /* Looking for gml:patches */
1460  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1461  {
1462  if (xa->type != XML_ELEMENT_NODE) continue;
1463  if (!is_gml_namespace(xa, false)) continue;
1464  if (!strcmp((char *) xa->name, "patches"))
1465  {
1466  found = true;
1467  break;
1468  }
1469  }
1470  if (!found) gml_lwpgerror("invalid GML representation", 51);
1471 
1472  /* Processing gml:PolygonPatch */
1473  for (patch=0, xa = xa->children ; xa != NULL ; xa = xa->next)
1474  {
1475  if (xa->type != XML_ELEMENT_NODE) continue;
1476  if (!is_gml_namespace(xa, false)) continue;
1477  if (strcmp((char *) xa->name, "PolygonPatch")) continue;
1478  patch++;
1479 
1480  /* SQL/MM define ST_CurvePolygon as a single patch only,
1481  cf ISO 13249-3:2009 -> 4.2.9 (p27) */
1482  if (patch > 1) gml_lwpgerror("invalid GML representation", 52);
1483 
1484  geom = parse_gml_patch(xa, hasz, root_srid);
1485  }
1486 
1487  if (!patch) gml_lwpgerror("invalid GML representation", 53);
1488 
1489  return geom;
1490 }
1491 
1492 
1502 static LWGEOM* parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
1503 {
1504  gmlSrs srs;
1505  xmlNodePtr xa;
1506  LWGEOM *geom=NULL;
1507  bool found=false;
1508 
1509  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1510 
1511  parse_gml_srs(xnode, &srs);
1512  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1513  *root_srid = srs.srid;
1514 
1515  geom = (LWGEOM *)lwcollection_construct_empty(TINTYPE, *root_srid, 1, 0);
1516 
1517  if (xnode->children == NULL)
1518  return geom;
1519 
1520  /* Looking for gml:patches or gml:trianglePatches */
1521  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1522  {
1523  if (xa->type != XML_ELEMENT_NODE) continue;
1524  if (!is_gml_namespace(xa, false)) continue;
1525  if (!strcmp((char *) xa->name, "patches") ||
1526  !strcmp((char *) xa->name, "trianglePatches"))
1527  {
1528  found = true;
1529  break;
1530  }
1531  }
1532  if (!found) return geom; /* empty one */
1533 
1534  /* Processing each gml:Triangle */
1535  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1536  {
1537  if (xa->type != XML_ELEMENT_NODE) continue;
1538  if (!is_gml_namespace(xa, false)) continue;
1539  if (strcmp((char *) xa->name, "Triangle")) continue;
1540 
1541  if (xa->children != NULL)
1542  geom = (LWGEOM*) lwtin_add_lwtriangle((LWTIN *) geom,
1543  (LWTRIANGLE *) parse_gml_triangle(xa, hasz, root_srid));
1544  }
1545 
1546  return geom;
1547 }
1548 
1549 
1553 static LWGEOM* parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
1554 {
1555  gmlSrs srs;
1556  xmlNodePtr xa, xb;
1557  LWGEOM *geom = NULL;
1558 
1559  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1560 
1561  parse_gml_srs(xnode, &srs);
1562  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1563  *root_srid = srs.srid;
1564 
1565  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, *root_srid, 1, 0);
1566 
1567  if (xnode->children == NULL)
1568  return geom;
1569 
1570  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1571  {
1572  /* MultiPoint/pointMember */
1573  if (xa->type != XML_ELEMENT_NODE) continue;
1574  if (!is_gml_namespace(xa, false)) continue;
1575  if (!strcmp((char *) xa->name, "pointMembers"))
1576  {
1577  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1578  {
1579  geom = (LWGEOM*)lwmpoint_add_lwpoint(
1580  (LWMPOINT*)geom,
1581  (LWPOINT*)parse_gml(xb, hasz, root_srid));
1582  }
1583  }
1584  else if (!strcmp((char *) xa->name, "pointMember"))
1585  {
1586  if (xa->children != NULL)
1587  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
1588  (LWPOINT*)parse_gml(xa->children, hasz, root_srid));
1589  }
1590  }
1591 
1592  return geom;
1593 }
1594 
1595 
1599 static LWGEOM* parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
1600 {
1601  gmlSrs srs;
1602  xmlNodePtr xa;
1603  LWGEOM *geom = NULL;
1604 
1605  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1606 
1607  parse_gml_srs(xnode, &srs);
1608  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1609  *root_srid = srs.srid;
1610 
1611  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1612 
1613  if (xnode->children == NULL)
1614  return geom;
1615 
1616  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1617  {
1618  /* MultiLineString/lineStringMember */
1619  if (xa->type != XML_ELEMENT_NODE) continue;
1620  if (!is_gml_namespace(xa, false)) continue;
1621  if (strcmp((char *) xa->name, "lineStringMember")) continue;
1622  if (xa->children != NULL)
1623  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1624  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1625  }
1626 
1627  return geom;
1628 }
1629 
1630 
1634 static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
1635 {
1636  gmlSrs srs;
1637  xmlNodePtr xa, xb;
1638  LWGEOM *geom = NULL;
1639 
1640  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1641 
1642  parse_gml_srs(xnode, &srs);
1643  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1644  *root_srid = srs.srid;
1645 
1646  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1647 
1648  if (xnode->children == NULL)
1649  return geom;
1650 
1651  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1652  {
1653 
1654  /* MultiCurve/curveMember */
1655  if (xa->type != XML_ELEMENT_NODE) continue;
1656  if (!is_gml_namespace(xa, false)) continue;
1657  if (!strcmp((char *) xa->name, "curveMembers"))
1658  {
1659  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1660  {
1661  if (xb != NULL)
1662  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1663  (LWLINE*)parse_gml(xb, hasz, root_srid));
1664  }
1665  }
1666  else if (!strcmp((char *) xa->name, "curveMember"))
1667  {
1668  if (xa->children != NULL)
1669  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1670  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1671  }
1672  }
1673 
1674  return geom;
1675 }
1676 
1677 
1681 static LWGEOM* parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
1682 {
1683  gmlSrs srs;
1684  xmlNodePtr xa;
1685  LWGEOM *geom = NULL;
1686 
1687  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1688 
1689  parse_gml_srs(xnode, &srs);
1690  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1691  *root_srid = srs.srid;
1692 
1693  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1694 
1695  if (xnode->children == NULL)
1696  return geom;
1697 
1698  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1699  {
1700  /* MultiPolygon/polygonMember */
1701  if (xa->type != XML_ELEMENT_NODE) continue;
1702  if (!is_gml_namespace(xa, false)) continue;
1703  if (strcmp((char *) xa->name, "polygonMember")) continue;
1704  if (xa->children != NULL)
1705  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1706  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1707  }
1708 
1709  return geom;
1710 }
1711 
1712 
1716 static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1717 {
1718  gmlSrs srs;
1719  xmlNodePtr xa, xb;
1720  LWGEOM *geom = NULL;
1721 
1722  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1723 
1724  parse_gml_srs(xnode, &srs);
1725  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1726  *root_srid = srs.srid;
1727 
1728  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1729 
1730  if (xnode->children == NULL)
1731  return geom;
1732 
1733  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1734  {
1735  /* MultiSurface/surfaceMember */
1736  if (xa->type != XML_ELEMENT_NODE) continue;
1737  if (!is_gml_namespace(xa, false)) continue;
1738  if (!strcmp((char *) xa->name, "surfaceMembers"))
1739  {
1740  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1741  {
1742  if (xb != NULL)
1743  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1744  (LWPOLY*)parse_gml(xb, hasz, root_srid));
1745  }
1746  }
1747  else if (!strcmp((char *) xa->name, "surfaceMember"))
1748  {
1749  if (xa->children != NULL)
1750  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1751  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1752  }
1753  }
1754 
1755  return geom;
1756 }
1757 
1758 
1763 static LWGEOM* parse_gml_psurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1764 {
1765  gmlSrs srs;
1766  xmlNodePtr xa;
1767  bool found = false;
1768  LWGEOM *geom = NULL;
1769 
1770  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1771 
1772  parse_gml_srs(xnode, &srs);
1773  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1774  *root_srid = srs.srid;
1775 
1776  geom = (LWGEOM *)lwcollection_construct_empty(POLYHEDRALSURFACETYPE, *root_srid, 1, 0);
1777 
1778  if (xnode->children == NULL)
1779  return geom;
1780 
1781  /* Looking for gml:polygonPatches */
1782  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1783  {
1784  if (xa->type != XML_ELEMENT_NODE) continue;
1785  if (!is_gml_namespace(xa, false)) continue;
1786  if (!strcmp((char *) xa->name, "polygonPatches"))
1787  {
1788  found = true;
1789  break;
1790  }
1791  }
1792  if (!found) return geom;
1793 
1794  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1795  {
1796  /* PolyhedralSurface/polygonPatches/PolygonPatch */
1797  if (xa->type != XML_ELEMENT_NODE) continue;
1798  if (!is_gml_namespace(xa, false)) continue;
1799  if (strcmp((char *) xa->name, "PolygonPatch")) continue;
1800 
1801  geom = (LWGEOM*)lwpsurface_add_lwpoly((LWPSURFACE*)geom,
1802  (LWPOLY*)parse_gml_patch(xa, hasz, root_srid));
1803  }
1804 
1805  return geom;
1806 }
1807 
1808 
1812 static LWGEOM* parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
1813 {
1814  gmlSrs srs;
1815  xmlNodePtr xa;
1816  LWGEOM *geom = NULL;
1817 
1818  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1819 
1820  parse_gml_srs(xnode, &srs);
1821  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1822  *root_srid = srs.srid;
1823 
1824  geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, *root_srid, 1, 0);
1825 
1826  if (xnode->children == NULL)
1827  return geom;
1828 
1829  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1830  {
1831  if (xa->type != XML_ELEMENT_NODE) continue;
1832  if (!is_gml_namespace(xa, false)) continue;
1833 
1834  /*
1835  * In GML 2.1.2 pointMember, lineStringMember and
1836  * polygonMember are parts of geometryMember
1837  * substitution group
1838  */
1839  if ( !strcmp((char *) xa->name, "pointMember")
1840  || !strcmp((char *) xa->name, "lineStringMember")
1841  || !strcmp((char *) xa->name, "polygonMember")
1842  || !strcmp((char *) xa->name, "geometryMember"))
1843  {
1844  if (xa->children == NULL) break;
1845  geom = (LWGEOM*)lwcollection_add_lwgeom((LWCOLLECTION *)geom,
1846  parse_gml(xa->children, hasz, root_srid));
1847  }
1848  }
1849 
1850  return geom;
1851 }
1852 
1856 static LWGEOM *
1857 lwgeom_from_gml(const char *xml, int xml_size)
1858 {
1859  xmlDocPtr xmldoc;
1860  xmlNodePtr xmlroot=NULL;
1861  LWGEOM *lwgeom = NULL;
1862  bool hasz=true;
1863  int root_srid=SRID_UNKNOWN;
1864 
1865  /* Begin to Parse XML doc */
1866  xmlInitParser();
1867 
1868  xmldoc = xmlReadMemory(xml, xml_size, NULL, NULL, XML_PARSE_SAX1);
1869  if (!xmldoc)
1870  {
1871  xmlCleanupParser();
1872  gml_lwpgerror("invalid GML representation", 1);
1873  return NULL;
1874  }
1875 
1876  xmlroot = xmlDocGetRootElement(xmldoc);
1877  if (!xmlroot)
1878  {
1879  xmlFreeDoc(xmldoc);
1880  xmlCleanupParser();
1881  gml_lwpgerror("invalid GML representation", 1);
1882  return NULL;
1883  }
1884 
1885  lwgeom = parse_gml(xmlroot, &hasz, &root_srid);
1886 
1887  xmlFreeDoc(xmldoc);
1888  xmlCleanupParser();
1889  /* shouldn't we be releasing xmldoc too here ? */
1890 
1891  if ( root_srid != SRID_UNKNOWN )
1892  lwgeom->srid = root_srid;
1893 
1894  /* GML geometries could be either 2 or 3D and can be nested mixed.
1895  * Missing Z dimension is even tolerated inside some GML coords
1896  *
1897  * So we deal with 3D in all structures allocation, and flag hasz
1898  * to false if we met once a missing Z dimension
1899  * In this case, we force recursive 2D.
1900  */
1901  if (!hasz)
1902  {
1903  LWGEOM *tmp = lwgeom_force_2d(lwgeom);
1904  lwgeom_free(lwgeom);
1905  lwgeom = tmp;
1906  }
1907 
1908  return lwgeom;
1909 }
1910 
1911 
1915 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
1916 {
1917  xmlNodePtr xa = xnode;
1918  gmlSrs srs;
1919 
1920  while (xa != NULL && (xa->type != XML_ELEMENT_NODE
1921  || !is_gml_namespace(xa, false))) xa = xa->next;
1922 
1923  if (xa == NULL) gml_lwpgerror("invalid GML representation", 55);
1924 
1925  parse_gml_srs(xa, &srs);
1926  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1927  {
1928  *root_srid = srs.srid;
1929  }
1930 
1931  if (!strcmp((char *) xa->name, "Point"))
1932  return parse_gml_point(xa, hasz, root_srid);
1933 
1934  if (!strcmp((char *) xa->name, "LineString"))
1935  return parse_gml_line(xa, hasz, root_srid);
1936 
1937  if (!strcmp((char *) xa->name, "Curve"))
1938  return parse_gml_curve(xa, hasz, root_srid);
1939 
1940  if (!strcmp((char *) xa->name, "LinearRing"))
1941  return parse_gml_linearring(xa, hasz, root_srid);
1942 
1943  if (!strcmp((char *) xa->name, "Polygon"))
1944  return parse_gml_polygon(xa, hasz, root_srid);
1945 
1946  if (!strcmp((char *) xa->name, "Triangle"))
1947  return parse_gml_triangle(xa, hasz, root_srid);
1948 
1949  if (!strcmp((char *) xa->name, "Surface"))
1950  return parse_gml_surface(xa, hasz, root_srid);
1951 
1952  if (!strcmp((char *) xa->name, "MultiPoint"))
1953  return parse_gml_mpoint(xa, hasz, root_srid);
1954 
1955  if (!strcmp((char *) xa->name, "MultiLineString"))
1956  return parse_gml_mline(xa, hasz, root_srid);
1957 
1958  if (!strcmp((char *) xa->name, "MultiCurve"))
1959  return parse_gml_mcurve(xa, hasz, root_srid);
1960 
1961  if (!strcmp((char *) xa->name, "MultiPolygon"))
1962  return parse_gml_mpoly(xa, hasz, root_srid);
1963 
1964  if (!strcmp((char *) xa->name, "MultiSurface"))
1965  return parse_gml_msurface(xa, hasz, root_srid);
1966 
1967  if (!strcmp((char *) xa->name, "PolyhedralSurface"))
1968  return parse_gml_psurface(xa, hasz, root_srid);
1969 
1970  if ((!strcmp((char *) xa->name, "Tin")) ||
1971  !strcmp((char *) xa->name, "TriangulatedSurface" ))
1972  return parse_gml_tin(xa, hasz, root_srid);
1973 
1974  if (!strcmp((char *) xa->name, "MultiGeometry"))
1975  return parse_gml_coll(xa, hasz, root_srid);
1976 
1977  gml_lwpgerror("invalid GML representation", 56);
1978  return NULL; /* Never reach */
1979 }
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoint.c:151
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
#define LW_FALSE
Definition: liblwgeom.h:94
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
int ptarray_transform(POINTARRAY *pa, LWPROJ *pj)
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
int ptarray_is_closed_3d(const POINTARRAY *pa)
Definition: ptarray.c:727
#define MULTILINETYPE
Definition: liblwgeom.h:106
LWTIN * lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj)
Definition: lwtin.c:34
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:329
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition: lwmline.c:46
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:51
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWTRIANGLE * lwtriangle_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwtriangle.c:58
LWMPOINT * lwmpoint_add_lwpoint(LWMPOINT *mobj, const LWPOINT *obj)
Definition: lwmpoint.c:45
#define TINTYPE
Definition: liblwgeom.h:116
LWMPOLY * lwmpoly_add_lwpoly(LWMPOLY *mobj, const LWPOLY *obj)
Definition: lwmpoly.c:47
LWPSURFACE * lwpsurface_add_lwpoly(LWPSURFACE *mobj, const LWPOLY *obj)
Definition: lwpsurface.c:33
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:107
LWPROJ * lwproj_from_str(const char *str_in, const char *str_out)
Allocate a new LWPROJ containing the reference to the PROJ's PJ If extra_geography_data is true,...
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:235
void lwfree(void *mem)
Definition: lwutil.c:242
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
LWPOINT * lwpoint_construct(int32_t srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:129
#define __attribute__(x)
Definition: liblwgeom.h:228
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:114
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition: ptarray.c:147
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:188
void * lwalloc(size_t size)
Definition: lwutil.c:227
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition: ptarray.c:714
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition: lwgeom.c:334
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoly.c:161
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition: lwpoly.c:43
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:616
POINTARRAY * ptarray_flip_coordinates(POINTARRAY *pa)
Reverse X and Y axis on a given POINTARRAY.
Definition: ptarray.c:360
LWLINE * lwline_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwline.c:55
LWTRIANGLE * lwtriangle_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwtriangle.c:40
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:793
This library is the generic geometry handling section of PostGIS.
static LWGEOM * parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Surface (3.1.1)
struct struct_gmlSrs gmlSrs
static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
Return a xmlNodePtr on a node referenced by a XLink or NULL otherwise.
static POINTARRAY * parse_gml_pos(xmlNodePtr xnode, bool *hasz)
Parse gml:pos.
#define GML_NS
Definition: lwgeom_in_gml.c:76
PG_FUNCTION_INFO_V1(geom_from_gml)
Ability to parse GML geometry fragment and to return an LWGEOM or an error message.
static bool is_xlink(xmlNodePtr node)
Return true if current node contains a simple XLink Return false otherwise.
#define GML32_NS
Definition: lwgeom_in_gml.c:77
#define XLINK_NS
Definition: lwgeom_in_gml.c:75
static LWGEOM * parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML PolygonPatch (3.1.1)
static LWGEOM * parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiSurface (3.1.1)
static LWGEOM * parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML.
static LWGEOM * parse_gml_psurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML PolyhedralSurface (3.1.1) Nota: It's not part of SF-2.
static LWGEOM * parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiGeometry (2.1.2, 3.1.1)
static POINTARRAY * gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
Use Proj to reproject a given POINTARRAY.
static double parse_gml_double(char *d, bool space_before, bool space_after)
Parse a string supposed to be a double.
static int gml_is_srs_axis_order_gis_friendly(int32_t srid)
Return 1 if the SRS definition from the authority has a GIS friendly order, that is easting,...
static LWGEOM * parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiCurve (3.1.1)
static xmlChar * gmlGetProp(xmlNodePtr xnode, xmlChar *prop)
Retrieve a GML property from a node or NULL otherwise Respect namespaces if presents in the node elem...
Datum geom_from_gml(PG_FUNCTION_ARGS)
Definition: lwgeom_in_gml.c:97
static LWGEOM * lwgeom_from_gml(const char *wkt, int xml_size)
Read GML.
static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
Return false if current element namespace is not a GML one Return true otherwise.
static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
Parse gml srsName attribute.
static LWGEOM * parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Polygon (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
Parse gml:coordinates.
static LWGEOM * parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML lineString (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse data coordinates.
static LWGEOM * parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiPolygon (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_coord(xmlNodePtr xnode, bool *hasz)
Parse gml:coord.
static LWGEOM * parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Curve (3.1.1)
static void gml_lwpgerror(char *msg, __attribute__((__unused__)) int error_code)
Definition: lwgeom_in_gml.c:81
static LWGEOM * parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse gml:MultiPoint (2.1.2, 3.1.1)
static LWGEOM * parse_gml_point(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML point (2.1.2, 3.1.1)
static LWGEOM * parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Tin (and TriangulatedSurface) (3.1.1)
static LWGEOM * parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Triangle (3.1.1)
static LWGEOM * parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse gml:MultiLineString (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
Parse gml:posList.
static LWGEOM * parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML LinearRing (3.1.1)
void * malloc(YYSIZE_T)
void free(void *)
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:77
int value
Definition: genraster.py:62
int32_t srid
Definition: liblwgeom.h:460
PJ * pj
Definition: liblwgeom.h:46
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
uint32_t npoints
Definition: liblwgeom.h:427