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