1 /*
2 
3  gg_gml.c -- GML parser/lexer
4 
5  version 5.0, 2020 August 1
6 
7  Author: Sandro Furieri a.furieri@lqt.it
8 
9  ------------------------------------------------------------------------------
10 
11  Version: MPL 1.1/GPL 2.0/LGPL 2.1
12 
13  The contents of this file are subject to the Mozilla Public License Version
14  1.1 (the "License"); you may not use this file except in compliance with
15  the License. You may obtain a copy of the License at
16  http://www.mozilla.org/MPL/
17 
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22 
23 The Original Code is the SpatiaLite library
24 
25 The Initial Developer of the Original Code is Alessandro Furieri
26 
27 Portions created by the Initial Developer are Copyright (C) 2011-2021
28 the Initial Developer. All Rights Reserved.
29 
30 Alternatively, the contents of this file may be used under the terms of
31 either the GNU General Public License Version 2 or later (the "GPL"), or
32 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 in which case the provisions of the GPL or the LGPL are applicable instead
34 of those above. If you wish to allow use of your version of this file only
35 under the terms of either the GPL or the LGPL, and not to allow others to
36 use your version of this file under the terms of the MPL, indicate your
37 decision by deleting the provisions above and replace them with the notice
38 and other provisions required by the GPL or the LGPL. If you do not delete
39 the provisions above, a recipient may use your version of this file under
40 the terms of any one of the MPL, the GPL or the LGPL.
41 
42 */
43 
44 #include <sys/types.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 
49 #include <assert.h>
50 
51 #if defined(_WIN32) && !defined(__MINGW32__)
52 #include "config-msvc.h"
53 #else
54 #include "config.h"
55 #endif
56 
57 #include <spatialite/sqlite.h>
58 #include <spatialite/debug.h>
59 
60 #include <spatialite/gaiageo.h>
61 #include <spatialite_private.h>
62 
63 #if defined(_WIN32) || defined(WIN32)
64 #include <io.h>
65 #ifndef isatty
66 #define isatty	_isatty
67 #endif
68 #ifndef fileno
69 #define fileno	_fileno
70 #endif
71 #endif
72 
73 #define GML_PARSER_OPEN_NODE		1
74 #define GML_PARSER_SELF_CLOSED_NODE	2
75 #define GML_PARSER_CLOSED_NODE		3
76 
77 #define GAIA_GML_UNKNOWN		0
78 #define GAIA_GML_POINT			1
79 #define GAIA_GML_LINESTRING		2
80 #define GAIA_GML_CURVE			3
81 #define GAIA_GML_POLYGON		4
82 #define GAIA_GML_MULTIPOINT		5
83 #define GAIA_GML_MULTILINESTRING	6
84 #define GAIA_GML_MULTICURVE		7
85 #define GAIA_GML_MULTIPOLYGON		8
86 #define GAIA_GML_MULTISURFACE		9
87 #define GAIA_GML_MULTIGEOMETRY		10
88 #define GAIA_GML_BOX			11
89 
90 #define GML_DYN_NONE	0
91 #define GML_DYN_DYNLINE	1
92 #define GML_DYN_GEOM	2
93 #define GML_DYN_DYNPG	3
94 #define GML_DYN_NODE	4
95 #define GML_DYN_COORD	5
96 #define GML_DYN_ATTRIB	6
97 
98 #define GML_DYN_BLOCK 1024
99 
100 
101 
102 /*
103 ** CAVEAT: we must redefine any Lemon/Flex own macro
104 */
105 #define YYMINORTYPE		GML_MINORTYPE
106 #define YY_CHAR			GML_YY_CHAR
107 #define	input			gml_input
108 #define ParseAlloc		gmlParseAlloc
109 #define ParseFree		gmlParseFree
110 #define ParseStackPeak		gmlParseStackPeak
111 #define Parse			gmlParse
112 #define yyStackEntry		gml_yyStackEntry
113 #define yyzerominor		gml_yyzerominor
114 #define yy_accept		gml_yy_accept
115 #define yy_action		gml_yy_action
116 #define yy_base			gml_yy_base
117 #define yy_buffer_stack		gml_yy_buffer_stack
118 #define yy_buffer_stack_max	gml_yy_buffer_stack_max
119 #define yy_buffer_stack_top	gml_yy_buffer_stack_top
120 #define yy_c_buf_p		gml_yy_c_buf_p
121 #define yy_chk			gml_yy_chk
122 #define yy_def			gml_yy_def
123 #define yy_default		gml_yy_default
124 #define yy_destructor		gml_yy_destructor
125 #define yy_ec			gml_yy_ec
126 #define yy_fatal_error		gml_yy_fatal_error
127 #define yy_find_reduce_action	gml_yy_find_reduce_action
128 #define yy_find_shift_action	gml_yy_find_shift_action
129 #define yy_get_next_buffer	gml_yy_get_next_buffer
130 #define yy_get_previous_state	gml_yy_get_previous_state
131 #define yy_init			gml_yy_init
132 #define yy_init_globals		gml_yy_init_globals
133 #define yy_lookahead		gml_yy_lookahead
134 #define yy_meta			gml_yy_meta
135 #define yy_nxt			gml_yy_nxt
136 #define yy_parse_failed		gml_yy_parse_failed
137 #define yy_pop_parser_stack	gml_yy_pop_parser_stack
138 #define yy_reduce		gml_yy_reduce
139 #define yy_reduce_ofst		gml_yy_reduce_ofst
140 #define yy_shift		gml_yy_shift
141 #define yy_shift_ofst		gml_yy_shift_ofst
142 #define yy_start		gml_yy_start
143 #define yy_state_type		gml_yy_state_type
144 #define yy_syntax_error		gml_yy_syntax_error
145 #define yy_trans_info		gml_yy_trans_info
146 #define yy_try_NUL_trans	gml_yy_try_NUL_trans
147 #define yyParser		gml_yyParser
148 #define yyStackEntry		gml_yyStackEntry
149 #define yyStackOverflow		gml_yyStackOverflow
150 #define yyRuleInfo		gml_yyRuleInfo
151 #define yyunput			gml_yyunput
152 #define yyzerominor		gml_yyzerominor
153 #define yyTraceFILE		gml_yyTraceFILE
154 #define yyTracePrompt		gml_yyTracePrompt
155 #define yyTokenName		gml_yyTokenName
156 #define yyRuleName		gml_yyRuleName
157 #define ParseTrace		gml_ParseTrace
158 
159 #define yylex			gml_yylex
160 #define YY_DECL int yylex (yyscan_t yyscanner)
161 
162 
163 /* include LEMON generated header */
164 #include "Gml.h"
165 
166 
167 typedef union
168 {
169     char *pval;
170     struct symtab *symp;
171 } gml_yystype;
172 #define YYSTYPE gml_yystype
173 
174 
175 /*
176 ** This is a linked-list struct to store all the values for each token.
177 */
178 typedef struct gmlFlexTokenStruct
179 {
180     char *value;
181     struct gmlFlexTokenStruct *Next;
182 } gmlFlexToken;
183 
184 typedef struct gml_coord
185 {
186     char *Value;
187     struct gml_coord *Next;
188 } gmlCoord;
189 typedef gmlCoord *gmlCoordPtr;
190 
191 typedef struct gml_attr
192 {
193     char *Key;
194     char *Value;
195     struct gml_attr *Next;
196 } gmlAttr;
197 typedef gmlAttr *gmlAttrPtr;
198 
199 typedef struct gml_node
200 {
201     char *Tag;
202     int Type;
203     int Error;
204     struct gml_attr *Attributes;
205     struct gml_coord *Coordinates;
206     struct gml_node *Next;
207 } gmlNode;
208 typedef gmlNode *gmlNodePtr;
209 
210 typedef struct gml_dynamic_ring
211 {
212     gaiaDynamicLinePtr ring;
213     int interior;
214     int has_z;
215     struct gml_dynamic_ring *next;
216 } gmlDynamicRing;
217 typedef gmlDynamicRing *gmlDynamicRingPtr;
218 
219 typedef struct gml_dynamic_polygon
220 {
221     struct gml_dynamic_ring *first;
222     struct gml_dynamic_ring *last;
223 } gmlDynamicPolygon;
224 typedef gmlDynamicPolygon *gmlDynamicPolygonPtr;
225 
226 struct gml_dyn_block
227 {
228 /* a struct taking trace of dynamic allocations */
229     int type[GML_DYN_BLOCK];
230     void *ptr[GML_DYN_BLOCK];
231     int index;
232     struct gml_dyn_block *next;
233 };
234 
235 struct gml_data
236 {
237 /* a struct used to make the lexer-parser reentrant and thread-safe */
238     int gml_parse_error;
239     int gml_line;
240     int gml_col;
241     struct gml_dyn_block *gml_first_dyn_block;
242     struct gml_dyn_block *gml_last_dyn_block;
243     gmlNodePtr result;
244     YYSTYPE GmlLval;
245 };
246 
247 static struct gml_dyn_block *
gmlCreateDynBlock(void)248 gmlCreateDynBlock (void)
249 {
250 /* allocating a new block to trace dynamic allocations */
251     int i;
252     struct gml_dyn_block *p = malloc (sizeof (struct gml_dyn_block));
253     for (i = 0; i < GML_DYN_BLOCK; i++)
254       {
255 	  /* initializing map entries */
256 	  p->type[i] = GML_DYN_NONE;
257 	  p->ptr[i] = NULL;
258       }
259     p->index = 0;
260     p->next = NULL;
261     return p;
262 }
263 
264 static void
gmlMapDynAlloc(struct gml_data * p_data,int type,void * ptr)265 gmlMapDynAlloc (struct gml_data *p_data, int type, void *ptr)
266 {
267 /* appending a dynamic allocation into the map */
268     struct gml_dyn_block *p;
269     if (p_data->gml_first_dyn_block == NULL)
270       {
271 	  /* inserting the first block of the map */
272 	  p = gmlCreateDynBlock ();
273 	  p_data->gml_first_dyn_block = p;
274 	  p_data->gml_last_dyn_block = p;
275       }
276     if (p_data->gml_last_dyn_block->index >= GML_DYN_BLOCK)
277       {
278 	  /* adding a further block to the map */
279 	  p = gmlCreateDynBlock ();
280 	  p_data->gml_last_dyn_block->next = p;
281 	  p_data->gml_last_dyn_block = p;
282       }
283     p_data->gml_last_dyn_block->type[p_data->gml_last_dyn_block->index] = type;
284     p_data->gml_last_dyn_block->ptr[p_data->gml_last_dyn_block->index] = ptr;
285     p_data->gml_last_dyn_block->index++;
286 }
287 
288 static void
gmlMapDynClean(struct gml_data * p_data,void * ptr)289 gmlMapDynClean (struct gml_data *p_data, void *ptr)
290 {
291 /* deleting a dynamic allocation from the map */
292     int i;
293     struct gml_dyn_block *p = p_data->gml_first_dyn_block;
294     while (p)
295       {
296 	  for (i = 0; i < GML_DYN_BLOCK; i++)
297 	    {
298 		switch (p->type[i])
299 		  {
300 		  case GML_DYN_DYNLINE:
301 		  case GML_DYN_GEOM:
302 		  case GML_DYN_DYNPG:
303 		  case GML_DYN_NODE:
304 		  case GML_DYN_COORD:
305 		  case GML_DYN_ATTRIB:
306 		      if (p->ptr[i] == ptr)
307 			{
308 			    p->type[i] = GML_DYN_NONE;
309 			    return;
310 			}
311 		      break;
312 		  };
313 	    }
314 	  p = p->next;
315       }
316 }
317 
318 static void
gml_free_dyn_polygon(gmlDynamicPolygonPtr dyn)319 gml_free_dyn_polygon (gmlDynamicPolygonPtr dyn)
320 {
321 /* deleting a dynamic polygon (ring collection) */
322     gmlDynamicRingPtr r;
323     gmlDynamicRingPtr rn;
324     if (!dyn)
325 	return;
326     r = dyn->first;
327     while (r)
328       {
329 	  rn = r->next;
330 	  if (r->ring)
331 	      gaiaFreeDynamicLine (r->ring);
332 	  free (r);
333 	  r = rn;
334       }
335     free (dyn);
336 }
337 
338 static void
gml_free_coord(gmlCoordPtr c)339 gml_free_coord (gmlCoordPtr c)
340 {
341 /* deleting a GML coordinate */
342     if (c == NULL)
343 	return;
344     if (c->Value)
345 	free (c->Value);
346     free (c);
347 }
348 
349 static void
gml_free_attrib(gmlAttrPtr a)350 gml_free_attrib (gmlAttrPtr a)
351 {
352 /* deleting a GML attribute */
353     if (a == NULL)
354 	return;
355     if (a->Key)
356 	free (a->Key);
357     if (a->Value)
358 	free (a->Value);
359     free (a);
360 }
361 
362 static void
gml_free_node(gmlNodePtr n)363 gml_free_node (gmlNodePtr n)
364 {
365 /* deleting a GML node */
366     gmlAttrPtr a;
367     gmlAttrPtr an;
368     gmlCoordPtr c;
369     gmlCoordPtr cn;
370     if (n == NULL)
371 	return;
372     a = n->Attributes;
373     while (a)
374       {
375 	  an = a->Next;
376 	  gml_free_attrib (a);
377 	  a = an;
378       }
379     c = n->Coordinates;
380     while (c)
381       {
382 	  cn = c->Next;
383 	  gml_free_coord (c);
384 	  c = cn;
385       }
386     if (n->Tag)
387 	free (n->Tag);
388     free (n);
389 }
390 
391 static void
gmlCleanMapDynAlloc(struct gml_data * p_data,int clean_all)392 gmlCleanMapDynAlloc (struct gml_data *p_data, int clean_all)
393 {
394 /* cleaning the dynamic allocations map */
395     int i;
396     struct gml_dyn_block *pn;
397     struct gml_dyn_block *p = p_data->gml_first_dyn_block;
398     while (p)
399       {
400 	  if (clean_all)
401 	    {
402 		for (i = 0; i < GML_DYN_BLOCK; i++)
403 		  {
404 		      /* deleting Geometry objects */
405 		      switch (p->type[i])
406 			{
407 			case GML_DYN_DYNLINE:
408 			    gaiaFreeDynamicLine ((gaiaDynamicLinePtr)
409 						 (p->ptr[i]));
410 			    break;
411 			case GML_DYN_GEOM:
412 			    gaiaFreeGeomColl ((gaiaGeomCollPtr) (p->ptr[i]));
413 			    break;
414 			case GML_DYN_DYNPG:
415 			    gml_free_dyn_polygon ((gmlDynamicPolygonPtr)
416 						  (p->ptr[i]));
417 			    break;
418 			case GML_DYN_NODE:
419 			    gml_free_node ((gmlNodePtr) (p->ptr[i]));
420 			    break;
421 			case GML_DYN_COORD:
422 			    gml_free_coord ((gmlCoordPtr) (p->ptr[i]));
423 			    break;
424 			case GML_DYN_ATTRIB:
425 			    gml_free_attrib ((gmlAttrPtr) (p->ptr[i]));
426 			    break;
427 			};
428 		  }
429 	    }
430 	  /* deleting the map block */
431 	  pn = p->next;
432 	  free (p);
433 	  p = pn;
434       }
435 }
436 
437 static gmlDynamicPolygonPtr
gml_alloc_dyn_polygon(struct gml_data * p_data)438 gml_alloc_dyn_polygon (struct gml_data *p_data)
439 {
440 /* creating a dynamic polygon (ring collection) */
441     gmlDynamicPolygonPtr p = malloc (sizeof (gmlDynamicPolygon));
442     gmlMapDynAlloc (p_data, GML_DYN_DYNPG, p);
443     p->first = NULL;
444     p->last = NULL;
445     return p;
446 }
447 
448 static void
gml_add_polygon_ring(struct gml_data * p_data,gmlDynamicPolygonPtr dyn_pg,gaiaDynamicLinePtr dyn,int interior,int has_z)449 gml_add_polygon_ring (struct gml_data *p_data, gmlDynamicPolygonPtr dyn_pg,
450 		      gaiaDynamicLinePtr dyn, int interior, int has_z)
451 {
452 /* inserting a further ring into the collection (dynamic polygon) */
453     gmlDynamicRingPtr p = malloc (sizeof (gmlDynamicRing));
454     p->ring = dyn;
455     p->interior = interior;
456     p->has_z = has_z;
457     p->next = NULL;
458     if (dyn_pg->first == NULL)
459 	dyn_pg->first = p;
460     if (dyn_pg->last != NULL)
461 	dyn_pg->last->next = p;
462     dyn_pg->last = p;
463     gmlMapDynClean (p_data, p);
464 }
465 
466 static void
gml_freeString(char ** ptr)467 gml_freeString (char **ptr)
468 {
469 /* releasing a string from the lexer */
470     if (*ptr != NULL)
471 	free (*ptr);
472     *ptr = NULL;
473 }
474 
475 static void
gml_saveString(char ** ptr,const char * str)476 gml_saveString (char **ptr, const char *str)
477 {
478 /* saving a string from the lexer */
479     int len = strlen (str);
480     gml_freeString (ptr);
481     *ptr = malloc (len + 1);
482     strcpy (*ptr, str);
483 }
484 
485 static gmlCoordPtr
gml_coord(struct gml_data * p_data,void * value)486 gml_coord (struct gml_data *p_data, void *value)
487 {
488 /* creating a coord Item */
489     int len;
490     gmlFlexToken *tok = (gmlFlexToken *) value;
491     gmlCoordPtr c = malloc (sizeof (gmlCoord));
492     gmlMapDynAlloc (p_data, GML_DYN_COORD, c);
493     len = strlen (tok->value);
494     c->Value = malloc (len + 1);
495     strcpy (c->Value, tok->value);
496     c->Next = NULL;
497     return c;
498 }
499 
500 static gmlAttrPtr
gml_attribute(struct gml_data * p_data,void * key,void * value)501 gml_attribute (struct gml_data *p_data, void *key, void *value)
502 {
503 /* creating an attribute */
504     int len;
505     gmlFlexToken *k_tok = (gmlFlexToken *) key;
506     gmlFlexToken *v_tok = (gmlFlexToken *) value;
507     gmlAttrPtr a = malloc (sizeof (gmlAttr));
508     gmlMapDynAlloc (p_data, GML_DYN_ATTRIB, a);
509     len = strlen (k_tok->value);
510     a->Key = malloc (len + 1);
511     strcpy (a->Key, k_tok->value);
512     len = strlen (v_tok->value);
513 /* we need to de-quote the string, removing first and last ".." */
514     if (*(v_tok->value + 0) == '"' && *(v_tok->value + len - 1) == '"')
515       {
516 	  int bytesToCopy = len - 2;
517 	  char *startingPointForCopy = v_tok->value + 1;
518 	  a->Value = malloc (bytesToCopy + 1);
519 	  memcpy (a->Value, startingPointForCopy, bytesToCopy);
520 	  *(a->Value + bytesToCopy) = '\0';
521       }
522     else
523       {
524 	  a->Value = malloc (len + 1);
525 	  strcpy (a->Value, v_tok->value);
526       }
527     a->Next = NULL;
528     return a;
529 }
530 
531 static void
gml_freeTree(struct gml_data * p_data,gmlNodePtr t)532 gml_freeTree (struct gml_data *p_data, gmlNodePtr t)
533 {
534 /* deleting a GML tree */
535     gmlNodePtr n;
536     gmlNodePtr nn;
537     n = t;
538     while (n)
539       {
540 	  nn = n->Next;
541 	  gmlMapDynClean (p_data, n);
542 	  gml_free_node (n);
543 	  n = nn;
544       }
545 }
546 
547 static gmlNodePtr
gml_createNode(struct gml_data * p_data,void * tag,void * attributes,void * coords)548 gml_createNode (struct gml_data *p_data, void *tag, void *attributes,
549 		void *coords)
550 {
551 /* creating a node */
552     gmlAttrPtr a;
553     gmlCoordPtr c;
554     int len;
555     gmlFlexToken *tok = (gmlFlexToken *) tag;
556     gmlNodePtr n = malloc (sizeof (gmlNode));
557     gmlMapDynAlloc (p_data, GML_DYN_NODE, n);
558     len = strlen (tok->value);
559     n->Tag = malloc (len + 1);
560     strcpy (n->Tag, tok->value);
561     n->Type = GML_PARSER_OPEN_NODE;
562     n->Error = 0;
563     a = (gmlAttrPtr) attributes;
564     while (a)
565       {
566 	  /* transferring ownership of attributes */
567 	  gmlMapDynClean (p_data, a);
568 	  a = a->Next;
569       }
570     n->Attributes = attributes;
571     c = (gmlCoordPtr) coords;
572     while (c)
573       {
574 	  /* transferring ownership of attributes */
575 	  gmlMapDynClean (p_data, c);
576 	  c = c->Next;
577       }
578     n->Coordinates = coords;
579     n->Next = NULL;
580     return n;
581 }
582 
583 static gmlNodePtr
gml_createSelfClosedNode(struct gml_data * p_data,void * tag,void * attributes)584 gml_createSelfClosedNode (struct gml_data *p_data, void *tag, void *attributes)
585 {
586 /* creating a self-closed node */
587     gmlAttrPtr a;
588     int len;
589     gmlFlexToken *tok = (gmlFlexToken *) tag;
590     gmlNodePtr n = malloc (sizeof (gmlNode));
591     gmlMapDynAlloc (p_data, GML_DYN_NODE, n);
592     len = strlen (tok->value);
593     n->Tag = malloc (len + 1);
594     strcpy (n->Tag, tok->value);
595     n->Type = GML_PARSER_SELF_CLOSED_NODE;
596     n->Error = 0;
597     a = (gmlAttrPtr) attributes;
598     while (a)
599       {
600 	  /* transferring ownership of attributes */
601 	  gmlMapDynClean (p_data, a);
602 	  a = a->Next;
603       }
604     n->Attributes = attributes;
605     n->Coordinates = NULL;
606     n->Next = NULL;
607     return n;
608 }
609 
610 static gmlNodePtr
gml_closingNode(struct gml_data * p_data,void * tag)611 gml_closingNode (struct gml_data *p_data, void *tag)
612 {
613 /* creating a closing node */
614     int len;
615     gmlFlexToken *tok = (gmlFlexToken *) tag;
616     gmlNodePtr n = malloc (sizeof (gmlNode));
617     gmlMapDynAlloc (p_data, GML_DYN_NODE, n);
618     len = strlen (tok->value);
619     n->Tag = malloc (len + 1);
620     strcpy (n->Tag, tok->value);
621     n->Type = GML_PARSER_CLOSED_NODE;
622     n->Error = 0;
623     n->Attributes = NULL;
624     n->Coordinates = NULL;
625     n->Next = NULL;
626     return n;
627 }
628 
629 static int
gml_cleanup(gmlFlexToken * token)630 gml_cleanup (gmlFlexToken * token)
631 {
632     gmlFlexToken *ptok;
633     gmlFlexToken *ptok_n;
634     if (token == NULL)
635 	return 0;
636     ptok = token;
637     while (ptok)
638       {
639 	  ptok_n = ptok->Next;
640 	  if (ptok->value != NULL)
641 	      free (ptok->value);
642 	  free (ptok);
643 	  ptok = ptok_n;
644       }
645     return 0;
646 }
647 
648 static void
gml_xferString(char ** p,const char * str)649 gml_xferString (char **p, const char *str)
650 {
651 /* saving some token */
652     int len;
653     if (str == NULL)
654       {
655 	  *p = NULL;
656 	  return;
657       }
658     len = strlen (str);
659     *p = malloc (len + 1);
660     strcpy (*p, str);
661 }
662 
663 static int
gml_get_srid(gmlNodePtr node)664 gml_get_srid (gmlNodePtr node)
665 {
666 /* attempting to guess the SRID */
667     int len;
668     gmlAttrPtr attr = node->Attributes;
669     while (attr)
670       {
671 	  if (strcmp (attr->Key, "srsName") == 0)
672 	    {
673 		len = strlen (attr->Value);
674 		if (len > 5)
675 		  {
676 		      if (strncmp (attr->Value, "EPSG:", 5) == 0)
677 			  return atoi (attr->Value + 5);
678 		  }
679 		if (len > 21)
680 		  {
681 		      if (strncmp (attr->Value, "urn:ogc:def:crs:EPSG:", 21) ==
682 			  0)
683 			{
684 			    int i = strlen (attr->Value) - 1;
685 			    for (; i >= 0; i--)
686 			      {
687 				  if (*(attr->Value + i) == ':')
688 				      return atoi (attr->Value + i + 1);
689 			      }
690 			}
691 		  }
692 		if (len > 40)
693 		  {
694 		      if (strncmp
695 			  (attr->Value,
696 			   "http://www.opengis.net/gml/srs/epsg.xml#", 40) == 0)
697 			{
698 			    int i = strlen (attr->Value) - 1;
699 			    for (; i >= 0; i--)
700 			      {
701 				  if (*(attr->Value + i) == '#')
702 				      return atoi (attr->Value + i + 1);
703 			      }
704 			}
705 		  }
706 	    }
707 	  attr = attr->Next;
708       }
709     return -1;
710 }
711 
712 static int
guessGmlSrid(gmlNodePtr node)713 guessGmlSrid (gmlNodePtr node)
714 {
715 /* attempting to guess the SRID */
716     int srid = -1;
717     gmlNodePtr n = node;
718     while (n)
719       {
720 	  /* looping on GML Members */
721 	  srid = gml_get_srid (n);
722 	  if (srid >= 0)
723 	      return srid;
724 	  n = n->Next;
725       }
726     return srid;
727 }
728 
729 static int
gml_get_dimension(gmlNodePtr node)730 gml_get_dimension (gmlNodePtr node)
731 {
732 /* attempting to establish if there is a Z coordinate */
733     gmlAttrPtr attr = node->Attributes;
734     while (attr)
735       {
736 	  if (strcmp (attr->Key, "srsDimension") == 0)
737 	    {
738 		if (atoi (attr->Value) == 3)
739 		    return 3;
740 		else
741 		    return 2;
742 	    }
743 	  if (strcmp (attr->Key, "dimension") == 0)
744 	    {
745 		if (atoi (attr->Value) == 3)
746 		    return 3;
747 		else
748 		    return 2;
749 	    }
750 	  attr = attr->Next;
751       }
752     return -1;
753 }
754 
755 static int
gml_check_coord(const char * value)756 gml_check_coord (const char *value)
757 {
758 /* checking a GML coordinate */
759     int decimal = 0;
760     int exp = 0;
761     int expsign = 0;
762     const char *p = value;
763     if (*p == '+' || *p == '-')
764 	p++;
765     while (*p != '\0')
766       {
767 	  if (*p == '.')
768 	    {
769 		if (!decimal)
770 		    decimal = 1;
771 		else
772 		    return 0;
773 	    }
774 	  else if (*p >= '0' && *p <= '9')
775 	      ;
776 	  else if (*p == 'e' || *p == 'E')
777 	      exp++;
778 	  else if (*p == '+' || *p == '-')
779 	    {
780 		if (!exp)
781 		    return 0;
782 		expsign++;
783 	    }
784 	  else
785 	      return 0;
786 	  p++;
787       }
788     if (exp > 1 || expsign > 1)
789 	return 0;
790     return 1;
791 }
792 
793 static int
gml_check_coords(const char * value)794 gml_check_coords (const char *value)
795 {
796 /* extracting GML v2.x coords from a comma-separated string */
797     const char *in = value;
798     int count = 0;
799     char buf[1024];
800     char *out = buf;
801     *out = '\0';
802 
803     while (*in != '\0')
804       {
805 	  if (*in == ',')
806 	    {
807 		*out = '\0';
808 		if (*buf != '\0')
809 		  {
810 		      if (!gml_check_coord (buf))
811 			  return 0;
812 		      switch (count)
813 			{
814 			case 0:
815 			    count += 1;
816 			    break;
817 			case 1:
818 			    count += 1;
819 			    break;
820 			case 2:
821 			    count += 1;
822 			    break;
823 			default:
824 			    count += 1;
825 			    break;
826 			};
827 		  }
828 		in++;
829 		out = buf;
830 		*out = '\0';
831 		continue;
832 	    }
833 	  *out++ = *in++;
834       }
835     *out = '\0';
836 /* parsing the last item */
837     if (*buf != '\0')
838       {
839 	  if (!gml_check_coord (buf))
840 	      return 0;
841 	  switch (count)
842 	    {
843 	    case 0:
844 		count += 1;
845 		break;
846 	    case 1:
847 		count += 1;
848 		break;
849 	    case 2:
850 		count += 1;
851 		break;
852 	    default:
853 		count += 1;
854 		break;
855 	    };
856       }
857     if (count == 2 || count == 3)
858 	return count;
859     return -1;
860 }
861 
862 static int
gml_check_point_v2(gmlCoordPtr coord)863 gml_check_point_v2 (gmlCoordPtr coord)
864 {
865 /* Dimensions for GML v2.x <gml:coordinates> [Point] */
866     int count = 0;
867     gmlCoordPtr c = coord;
868     while (c)
869       {
870 	  count = gml_check_coords (c->Value);
871 	  if (count == 2 || count == 3)
872 	      return count;
873 	  c = c->Next;
874       }
875     return -1;
876 }
877 
878 static int
gml_check_point_v3(gmlCoordPtr coord)879 gml_check_point_v3 (gmlCoordPtr coord)
880 {
881 /* Dimensions for GML v2.x <gml:pos> [Point] */
882     int count = 0;
883     gmlCoordPtr c = coord;
884     while (c)
885       {
886 	  if (!gml_check_coord (c->Value))
887 	      return 0;
888 	  switch (count)
889 	    {
890 	    case 0:
891 		count++;
892 		break;
893 	    case 1:
894 		count++;
895 		break;
896 	    case 2:
897 		count++;
898 		break;
899 	    default:
900 		count++;
901 		break;
902 	    };
903 	  c = c->Next;
904       }
905     if (count == 2 || count == 3)
906 	return count;
907     return -1;
908 }
909 
910 static int
guessGmlDimensions(gmlNodePtr node)911 guessGmlDimensions (gmlNodePtr node)
912 {
913     int dims = -1;
914     gmlNodePtr n = node;
915     while (n)
916       {
917 	  /* looping on GML Members */
918 	  dims = gml_get_dimension (n);
919 	  if (dims == 2 || dims == 3)
920 	      return dims;
921 
922 	  if (strcmp (n->Tag, "gml:coordinates") == 0
923 	      || strcmp (n->Tag, "coordinates") == 0)
924 	    {
925 		dims = gml_check_point_v2 (n->Coordinates);
926 		if (dims == 2 || dims == 3)
927 		    return dims;
928 	    }
929 	  if (strcmp (n->Tag, "gml:pos") == 0 || strcmp (n->Tag, "pos") == 0)
930 	    {
931 		dims = gml_check_point_v3 (n->Coordinates);
932 		if (dims == 2 || dims == 3)
933 		    return dims;
934 	    }
935 	  n = n->Next;
936       }
937     return 2;
938 }
939 
940 static int
guessGmlGeometryType(gmlNodePtr node)941 guessGmlGeometryType (gmlNodePtr node)
942 {
943 /* attempting to guess the Geometry Type for a GML node */
944     int type = GAIA_GML_UNKNOWN;
945     if (strcmp (node->Tag, "gml:Point") == 0
946 	|| strcmp (node->Tag, "Point") == 0)
947 	type = GAIA_GML_POINT;
948     if (strcmp (node->Tag, "gml:LineString") == 0
949 	|| strcmp (node->Tag, "LineString") == 0)
950 	type = GAIA_GML_LINESTRING;
951     if (strcmp (node->Tag, "gml:Curve") == 0
952 	|| strcmp (node->Tag, "Curve") == 0)
953 	type = GAIA_GML_CURVE;
954     if (strcmp (node->Tag, "gml:Polygon") == 0
955 	|| strcmp (node->Tag, "Polygon") == 0)
956 	type = GAIA_GML_POLYGON;
957     if (strcmp (node->Tag, "gml:MultiPoint") == 0
958 	|| strcmp (node->Tag, "MultiPoint") == 0)
959 	type = GAIA_GML_MULTIPOINT;
960     if (strcmp (node->Tag, "gml:MultiLineString") == 0
961 	|| strcmp (node->Tag, "MultiLineString") == 0)
962 	type = GAIA_GML_MULTILINESTRING;
963     if (strcmp (node->Tag, "gml:MultiCurve") == 0
964 	|| strcmp (node->Tag, "MultiCurve") == 0)
965 	type = GAIA_GML_MULTICURVE;
966     if (strcmp (node->Tag, "gml:MultiPolygon") == 0
967 	|| strcmp (node->Tag, "MultiPolygon") == 0)
968 	type = GAIA_GML_MULTIPOLYGON;
969     if (strcmp (node->Tag, "gml:MultiSurface") == 0
970 	|| strcmp (node->Tag, "MultiSurface") == 0)
971 	type = GAIA_GML_MULTISURFACE;
972     if (strcmp (node->Tag, "gml:MultiGeometry") == 0
973 	|| strcmp (node->Tag, "MultiGeometry") == 0)
974 	type = GAIA_GML_MULTIGEOMETRY;
975     if (strcmp (node->Tag, "gml:Box") == 0 || strcmp (node->Tag, "Box") == 0)
976 	type = GAIA_GML_BOX;
977     return type;
978 }
979 
980 static int
gml_extract_coords(const char * value,double * x,double * y,double * z,int * count)981 gml_extract_coords (const char *value, double *x, double *y, double *z,
982 		    int *count)
983 {
984 /* extracting GML v2.x coords from a comma-separated string */
985     const char *in = value;
986     char buf[1024];
987     char *out = buf;
988     *out = '\0';
989 
990     while (*in != '\0')
991       {
992 	  if (*in == ',')
993 	    {
994 		*out = '\0';
995 		if (*buf != '\0')
996 		  {
997 		      if (!gml_check_coord (buf))
998 			  return 0;
999 		      switch (*count)
1000 			{
1001 			case 0:
1002 			    *x = atof (buf);
1003 			    *count += 1;
1004 			    break;
1005 			case 1:
1006 			    *y = atof (buf);
1007 			    *count += 1;
1008 			    break;
1009 			case 2:
1010 			    *z = atof (buf);
1011 			    *count += 1;
1012 			    break;
1013 			default:
1014 			    *count += 1;
1015 			    break;
1016 			};
1017 		  }
1018 		in++;
1019 		out = buf;
1020 		*out = '\0';
1021 		continue;
1022 	    }
1023 	  *out++ = *in++;
1024       }
1025     *out = '\0';
1026 /* parsing the last item */
1027     if (*buf != '\0')
1028       {
1029 	  if (!gml_check_coord (buf))
1030 	      return 0;
1031 	  switch (*count)
1032 	    {
1033 	    case 0:
1034 		*x = atof (buf);
1035 		*count += 1;
1036 		break;
1037 	    case 1:
1038 		*y = atof (buf);
1039 		*count += 1;
1040 		break;
1041 	    case 2:
1042 		*z = atof (buf);
1043 		*count += 1;
1044 		break;
1045 	    default:
1046 		*count += 1;
1047 		break;
1048 	    };
1049       }
1050     return 1;
1051 }
1052 
1053 static int
gml_parse_point_v2(gmlCoordPtr coord,double * x,double * y,double * z)1054 gml_parse_point_v2 (gmlCoordPtr coord, double *x, double *y, double *z)
1055 {
1056 /* parsing GML v2.x <gml:coordinates> [Point] */
1057     int count = 0;
1058     gmlCoordPtr c = coord;
1059     while (c)
1060       {
1061 	  if (!gml_extract_coords (c->Value, x, y, z, &count))
1062 	      return 0;
1063 	  c = c->Next;
1064       }
1065     if (count == 2)
1066       {
1067 	  *z = 0.0;
1068 	  return 1;
1069       }
1070     if (count == 3)
1071 	return 1;
1072     return 0;
1073 }
1074 
1075 static int
gml_parse_point_v3(gmlCoordPtr coord,double * x,double * y,double * z)1076 gml_parse_point_v3 (gmlCoordPtr coord, double *x, double *y, double *z)
1077 {
1078 /* parsing GML v2.x <gml:pos> [Point] */
1079     int count = 0;
1080     gmlCoordPtr c = coord;
1081     while (c)
1082       {
1083 	  if (!gml_check_coord (c->Value))
1084 	      return 0;
1085 	  switch (count)
1086 	    {
1087 	    case 0:
1088 		*x = atof (c->Value);
1089 		count++;
1090 		break;
1091 	    case 1:
1092 		*y = atof (c->Value);
1093 		count++;
1094 		break;
1095 	    case 2:
1096 		*z = atof (c->Value);
1097 		count++;
1098 		break;
1099 	    default:
1100 		count++;
1101 		break;
1102 	    };
1103 	  c = c->Next;
1104       }
1105     if (count == 2)
1106       {
1107 	  *z = 0.0;
1108 	  return 1;
1109       }
1110     if (count == 3)
1111 	return 1;
1112     return 0;
1113 }
1114 
1115 static int
gml_parse_point(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node,gmlNodePtr * next)1116 gml_parse_point (struct gml_data *p_data, gaiaGeomCollPtr geom, gmlNodePtr node,
1117 		 gmlNodePtr * next)
1118 {
1119 /* parsing a <gml:Point> */
1120     int srid = geom->Srid;
1121     int has_z = 0;
1122     double x;
1123     double y;
1124     double z;
1125     gaiaGeomCollPtr pt;
1126     gaiaGeomCollPtr last;
1127     if (geom->DimensionModel == GAIA_XY_Z
1128 	|| geom->DimensionModel == GAIA_XY_Z_M)
1129 	has_z = 1;
1130 
1131     if (strcmp (node->Tag, "gml:coordinates") == 0
1132 	|| strcmp (node->Tag, "coordinates") == 0)
1133       {
1134 	  /* parsing a GML v.2.x <gml:Point> */
1135 	  if (!gml_parse_point_v2 (node->Coordinates, &x, &y, &z))
1136 	      return 0;
1137 	  node = node->Next;
1138 	  if (node == NULL)
1139 	      return 0;
1140 	  if (strcmp (node->Tag, "gml:coordinates") == 0
1141 	      || strcmp (node->Tag, "coordinates") == 0)
1142 	      ;
1143 	  else
1144 	      return 0;
1145 	  node = node->Next;
1146 	  if (node == NULL)
1147 	      return 0;
1148 	  if (strcmp (node->Tag, "gml:Point") == 0
1149 	      || strcmp (node->Tag, "Point") == 0)
1150 	      ;
1151 	  else
1152 	      return 0;
1153 	  *next = node->Next;
1154 	  goto ok;
1155       }
1156     if (strcmp (node->Tag, "gml:pos") == 0 || strcmp (node->Tag, "pos") == 0)
1157       {
1158 	  /* parsing a GML v.3.x <gml:Point> */
1159 	  if (!gml_parse_point_v3 (node->Coordinates, &x, &y, &z))
1160 	      return 0;
1161 	  node = node->Next;
1162 	  if (node == NULL)
1163 	      return 0;
1164 	  if (strcmp (node->Tag, "gml:pos") == 0
1165 	      || strcmp (node->Tag, "pos") == 0)
1166 	      ;
1167 	  else
1168 	      return 0;
1169 	  node = node->Next;
1170 	  if (node == NULL)
1171 	      return 0;
1172 	  if (strcmp (node->Tag, "gml:Point") == 0
1173 	      || strcmp (node->Tag, "Point") == 0)
1174 	      ;
1175 	  else
1176 	      return 0;
1177 	  *next = node->Next;
1178 	  goto ok;
1179       }
1180     return 0;
1181 
1182   ok:
1183 /* ok, GML nodes match as expected */
1184     if (has_z)
1185       {
1186 	  pt = gaiaAllocGeomCollXYZ ();
1187 	  gmlMapDynAlloc (p_data, GML_DYN_GEOM, pt);
1188 	  pt->Srid = srid;
1189 	  gaiaAddPointToGeomCollXYZ (pt, x, y, z);
1190       }
1191     else
1192       {
1193 	  pt = gaiaAllocGeomColl ();
1194 	  gmlMapDynAlloc (p_data, GML_DYN_GEOM, pt);
1195 	  pt->Srid = srid;
1196 	  gaiaAddPointToGeomColl (pt, x, y);
1197       }
1198     last = geom;
1199     while (1)
1200       {
1201 	  /* searching the last Geometry within chain */
1202 	  if (last->Next == NULL)
1203 	      break;
1204 	  last = last->Next;
1205       }
1206     last->Next = pt;
1207     return 1;
1208 }
1209 
1210 static int
gml_extract_multi_coord(const char * value,double * x,double * y,double * z,int * count,int * follow)1211 gml_extract_multi_coord (const char *value, double *x, double *y, double *z,
1212 			 int *count, int *follow)
1213 {
1214 /* extracting GML v2.x coords from a comma-separated string */
1215     const char *in = value;
1216     char buf[1024];
1217     char *out = buf;
1218     int last = ' ';
1219     *out = '\0';
1220     while (*in != '\0')
1221       {
1222 	  last = *in;
1223 	  if (*in == ',')
1224 	    {
1225 		*out = '\0';
1226 		if (*buf != '\0')
1227 		  {
1228 		      if (!gml_check_coord (buf))
1229 			  return 0;
1230 		      switch (*count)
1231 			{
1232 			case 0:
1233 			    *x = atof (buf);
1234 			    *count += 1;
1235 			    break;
1236 			case 1:
1237 			    *y = atof (buf);
1238 			    *count += 1;
1239 			    break;
1240 			case 2:
1241 			    *z = atof (buf);
1242 			    *count += 1;
1243 			    break;
1244 			default:
1245 			    *count += 1;
1246 			    break;
1247 			};
1248 		  }
1249 		in++;
1250 		out = buf;
1251 		*out = '\0';
1252 		continue;
1253 	    }
1254 	  *out++ = *in++;
1255       }
1256     *out = '\0';
1257 /* parsing the last item */
1258     if (*buf != '\0')
1259       {
1260 	  if (!gml_check_coord (buf))
1261 	      return 0;
1262 	  switch (*count)
1263 	    {
1264 	    case 0:
1265 		*x = atof (buf);
1266 		*count += 1;
1267 		break;
1268 	    case 1:
1269 		*y = atof (buf);
1270 		*count += 1;
1271 		break;
1272 	    case 2:
1273 		*z = atof (buf);
1274 		*count += 1;
1275 		break;
1276 	    default:
1277 		*count += 1;
1278 		break;
1279 	    };
1280       }
1281     if (last == ',')
1282 	*follow = 1;
1283     else
1284 	*follow = 0;
1285     return 1;
1286 }
1287 
1288 static int
gml_extract_multi_coords(gmlCoordPtr coord,double * x,double * y,double * z,int * count,gmlCoordPtr * next)1289 gml_extract_multi_coords (gmlCoordPtr coord, double *x, double *y, double *z,
1290 			  int *count, gmlCoordPtr * next)
1291 {
1292 /* extracting GML v2.x coords from a comma-separated string */
1293     int follow;
1294     gmlCoordPtr c = coord;
1295     while (c)
1296       {
1297 	  if (!gml_extract_multi_coord (c->Value, x, y, z, count, &follow))
1298 	      return 0;
1299 	  if (!follow && c->Next != NULL)
1300 	    {
1301 		if (*(c->Next->Value) == ',')
1302 		    follow = 1;
1303 	    }
1304 	  if (follow)
1305 	      c = c->Next;
1306 	  else
1307 	    {
1308 		*next = c->Next;
1309 		break;
1310 	    }
1311       }
1312     return 1;
1313 }
1314 
1315 static void
gml_add_point_to_line(gaiaDynamicLinePtr dyn,double x,double y)1316 gml_add_point_to_line (gaiaDynamicLinePtr dyn, double x, double y)
1317 {
1318 /* appending a point */
1319     gaiaAppendPointToDynamicLine (dyn, x, y);
1320 }
1321 
1322 static void
gml_add_point_to_lineZ(gaiaDynamicLinePtr dyn,double x,double y,double z)1323 gml_add_point_to_lineZ (gaiaDynamicLinePtr dyn, double x, double y, double z)
1324 {
1325 /* appending a point */
1326     gaiaAppendPointZToDynamicLine (dyn, x, y, z);
1327 }
1328 
1329 static int
gml_parse_coordinates(gmlCoordPtr coord,gaiaDynamicLinePtr dyn,int * has_z)1330 gml_parse_coordinates (gmlCoordPtr coord, gaiaDynamicLinePtr dyn, int *has_z)
1331 {
1332 /* parsing GML v2.x <gml:coordinates> [Linestring or Ring] */
1333     int count = 0;
1334     double x;
1335     double y;
1336     double z;
1337     gmlCoordPtr next = NULL;
1338     gmlCoordPtr c = coord;
1339     while (c)
1340       {
1341 	  if (!gml_extract_multi_coords (c, &x, &y, &z, &count, &next))
1342 	      return 0;
1343 	  if (count == 2)
1344 	    {
1345 		*has_z = 0;
1346 		gml_add_point_to_line (dyn, x, y);
1347 		count = 0;
1348 	    }
1349 	  else if (count == 3)
1350 	    {
1351 		*has_z = 1;
1352 		gml_add_point_to_lineZ (dyn, x, y, z);
1353 		count = 0;
1354 	    }
1355 	  else
1356 	      return 0;
1357 	  c = next;
1358       }
1359     return 1;
1360 }
1361 
1362 static int
gml_parse_posList(gmlCoordPtr coord,gaiaDynamicLinePtr dyn,int has_z)1363 gml_parse_posList (gmlCoordPtr coord, gaiaDynamicLinePtr dyn, int has_z)
1364 {
1365 /* parsing GML v3.x <gml:posList> [Linestring or Ring] */
1366     int count = 0;
1367     double x = 0.0;
1368     double y = 0.0;
1369     double z = 0.0;
1370     gmlCoordPtr c = coord;
1371     if (has_z < 0)
1372 	has_z = 0;
1373     while (c)
1374       {
1375 	  if (!gml_check_coord (c->Value))
1376 	      return 0;
1377 	  if (!has_z)
1378 	    {
1379 		switch (count)
1380 		  {
1381 		  case 0:
1382 		      x = atof (c->Value);
1383 		      count++;
1384 		      break;
1385 		  case 1:
1386 		      y = atof (c->Value);
1387 		      gml_add_point_to_line (dyn, x, y);
1388 		      count = 0;
1389 		      break;
1390 		  };
1391 	    }
1392 	  else
1393 	    {
1394 		switch (count)
1395 		  {
1396 		  case 0:
1397 		      x = atof (c->Value);
1398 		      count++;
1399 		      break;
1400 		  case 1:
1401 		      y = atof (c->Value);
1402 		      count++;
1403 		      break;
1404 		  case 2:
1405 		      z = atof (c->Value);
1406 		      gml_add_point_to_lineZ (dyn, x, y, z);
1407 		      count = 0;
1408 		      break;
1409 		  };
1410 	    }
1411 	  c = c->Next;
1412       }
1413     if (count != 0)
1414 	return 0;
1415     return 1;
1416 }
1417 
1418 static int
gml_parse_pos_chain(gmlNodePtr * xnode,gaiaDynamicLinePtr dyn,int has_z)1419 gml_parse_pos_chain (gmlNodePtr * xnode, gaiaDynamicLinePtr dyn, int has_z)
1420 {
1421 /* parsing a chain of gml:pos elements */
1422     int error = 0;
1423     double x;
1424     double y;
1425     double z;
1426     int count = 0;
1427     gmlNodePtr last_node = *xnode;
1428     gmlNodePtr node = *xnode;
1429     while (node != NULL)
1430       {
1431 	  if (strcmp (node->Tag, "gml:pos") == 0
1432 	      || strcmp (node->Tag, "pos") == 0)
1433 	      ;
1434 	  else
1435 	      break;
1436 	  if (!gml_parse_point_v3 (node->Coordinates, &x, &y, &z))
1437 	      return 0;
1438 	  if (has_z)
1439 	      gml_add_point_to_lineZ (dyn, x, y, z);
1440 	  else
1441 	      gml_add_point_to_line (dyn, x, y);
1442 	  node = node->Next;
1443 	  if (strcmp (node->Tag, "gml:pos") == 0
1444 	      || strcmp (node->Tag, "pos") == 0)
1445 	      last_node = node;
1446 	  else
1447 	    {
1448 		error = 1;
1449 		break;
1450 	    }
1451 	  count++;
1452 	  node = node->Next;
1453       }
1454     if (count >= 2 && error == 0)
1455       {
1456 	  /* valid <gml:pos> sequence found */
1457 	  *xnode = last_node;
1458 	  return 1;
1459       }
1460     return 0;
1461 }
1462 
1463 static int
gml_count_dyn_points(gaiaDynamicLinePtr dyn)1464 gml_count_dyn_points (gaiaDynamicLinePtr dyn)
1465 {
1466 /* count how many vertices are into sone linestring/ring */
1467     int iv = 0;
1468     gaiaPointPtr pt = dyn->First;
1469     while (pt)
1470       {
1471 	  iv++;
1472 	  pt = pt->Next;
1473       }
1474     return iv;
1475 }
1476 
1477 static int
gml_parse_box(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node,int srid,gmlNodePtr * next)1478 gml_parse_box (struct gml_data *p_data, gaiaGeomCollPtr geom,
1479 	       gmlNodePtr node, int srid, gmlNodePtr * next)
1480 {
1481 /* parsing a <gml:Box> */
1482     gaiaGeomCollPtr last;
1483     gaiaGeomCollPtr pg;
1484     gaiaPolygonPtr new_pg;
1485     gaiaRingPtr ring;
1486     gaiaPointPtr pt;
1487     double minx;
1488     double miny;
1489     double maxx;
1490     double maxy;
1491     int has_z;
1492     int points = 0;
1493     gaiaDynamicLinePtr dyn = gaiaAllocDynamicLine ();
1494     gmlMapDynAlloc (p_data, GML_DYN_DYNLINE, dyn);
1495 
1496     if (strcmp (node->Tag, "gml:coordinates") == 0
1497 	|| strcmp (node->Tag, "coordinates") == 0)
1498       {
1499 	  /* parsing a GML v.2.x <gml:LineString> */
1500 	  if (!gml_parse_coordinates (node->Coordinates, dyn, &has_z))
1501 	      goto error;
1502 	  node = node->Next;
1503 	  if (node == NULL)
1504 	      goto error;
1505 	  if (strcmp (node->Tag, "gml:coordinates") == 0
1506 	      || strcmp (node->Tag, "coordinates") == 0)
1507 	      ;
1508 	  else
1509 	      goto error;
1510 	  node = node->Next;
1511 	  if (node == NULL)
1512 	      goto error;
1513 	  if (strcmp (node->Tag, "gml:Box") == 0
1514 	      || strcmp (node->Tag, "Box") == 0)
1515 	      ;
1516 	  else
1517 	      goto error;
1518 	  *next = node->Next;
1519 	  goto ok;
1520       }
1521 
1522   ok:
1523 /* ok, GML nodes match as expected */
1524     points = gml_count_dyn_points (dyn);
1525     if (points != 2)
1526 	goto error;
1527     pt = dyn->First;
1528     minx = pt->X;
1529     miny = pt->Y;
1530     maxx = pt->X;
1531     maxy = pt->Y;
1532     while (pt)
1533       {
1534 	  if (pt->X < minx)
1535 	      minx = pt->X;
1536 	  if (pt->Y < miny)
1537 	      miny = pt->Y;
1538 	  if (pt->X > maxx)
1539 	      maxx = pt->X;
1540 	  if (pt->Y > maxy)
1541 	      maxy = pt->Y;
1542 	  pt = pt->Next;
1543       }
1544     pg = gaiaAllocGeomColl ();
1545     gmlMapDynAlloc (p_data, GML_DYN_GEOM, pg);
1546     pg->Srid = srid;
1547     new_pg = gaiaAddPolygonToGeomColl (pg, 5, 0);
1548     /* initializing the EXTERIOR RING */
1549     ring = new_pg->Exterior;
1550     gaiaSetPoint (ring->Coords, 0, minx, miny);
1551     gaiaSetPoint (ring->Coords, 1, maxx, miny);
1552     gaiaSetPoint (ring->Coords, 2, maxx, maxy);
1553     gaiaSetPoint (ring->Coords, 3, minx, maxy);
1554     gaiaSetPoint (ring->Coords, 4, minx, miny);
1555     last = geom;
1556     while (1)
1557       {
1558 	  /* searching the last Geometry within chain */
1559 	  if (last->Next == NULL)
1560 	      break;
1561 	  last = last->Next;
1562       }
1563     last->Next = pg;
1564     gmlMapDynClean (p_data, dyn);
1565     gaiaFreeDynamicLine (dyn);
1566     return 1;
1567 
1568   error:
1569     gmlMapDynClean (p_data, dyn);
1570     gaiaFreeDynamicLine (dyn);
1571     return 0;
1572 }
1573 
1574 static int
gml_parse_linestring(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node,gmlNodePtr * next)1575 gml_parse_linestring (struct gml_data *p_data, gaiaGeomCollPtr geom,
1576 		      gmlNodePtr node, gmlNodePtr * next)
1577 {
1578 /* parsing a <gml:LineString> */
1579     int srid = geom->Srid;
1580     int has_z = 0;
1581     gaiaGeomCollPtr ln;
1582     gaiaGeomCollPtr last;
1583     gaiaLinestringPtr new_ln;
1584     gaiaPointPtr pt;
1585     int iv;
1586     int points = 0;
1587     gaiaDynamicLinePtr dyn = gaiaAllocDynamicLine ();
1588     gmlMapDynAlloc (p_data, GML_DYN_DYNLINE, dyn);
1589     if (geom->DimensionModel == GAIA_XY_Z
1590 	|| geom->DimensionModel == GAIA_XY_Z_M)
1591 	has_z = 1;
1592 
1593     if (strcmp (node->Tag, "gml:coordinates") == 0
1594 	|| strcmp (node->Tag, "coordinates") == 0)
1595       {
1596 	  /* parsing a GML v.2.x <gml:LineString> */
1597 	  if (!gml_parse_coordinates (node->Coordinates, dyn, &has_z))
1598 	      goto error;
1599 	  node = node->Next;
1600 	  if (node == NULL)
1601 	      goto error;
1602 	  if (strcmp (node->Tag, "gml:coordinates") == 0
1603 	      || strcmp (node->Tag, "coordinates") == 0)
1604 	      ;
1605 	  else
1606 	      goto error;
1607 	  node = node->Next;
1608 	  if (node == NULL)
1609 	      goto error;
1610 	  if (strcmp (node->Tag, "gml:LineString") == 0
1611 	      || strcmp (node->Tag, "LineString") == 0)
1612 	      ;
1613 	  else
1614 	      goto error;
1615 	  *next = node->Next;
1616 	  goto ok;
1617       }
1618     if (strcmp (node->Tag, "gml:posList") == 0
1619 	|| strcmp (node->Tag, "posList") == 0)
1620       {
1621 	  /* parsing a GML v.3.x <gml:LineString> */
1622 	  if (!gml_parse_posList (node->Coordinates, dyn, has_z))
1623 	      goto error;
1624 	  node = node->Next;
1625 	  if (node == NULL)
1626 	      goto error;
1627 	  if (strcmp (node->Tag, "gml:posList") == 0
1628 	      || strcmp (node->Tag, "posList") == 0)
1629 	      ;
1630 	  else
1631 	      goto error;
1632 	  node = node->Next;
1633 	  if (node == NULL)
1634 	      goto error;
1635 	  if (strcmp (node->Tag, "gml:LineString") == 0
1636 	      || strcmp (node->Tag, "LineString") == 0)
1637 	      ;
1638 	  else
1639 	      goto error;
1640 	  *next = node->Next;
1641 	  goto ok;
1642       }
1643     if (strcmp (node->Tag, "gml:pos") == 0 || strcmp (node->Tag, "pos") == 0)
1644       {
1645 	  /* parsing a GML v.3.x <gml:LineString><gml:pos ...> */
1646 	  gmlNodePtr node2 = node;
1647 	  if (!gml_parse_pos_chain (&node2, dyn, has_z))
1648 	      goto error;
1649 	  node = node2->Next;
1650 	  if (node == NULL)
1651 	      goto error;
1652 	  if (strcmp (node->Tag, "gml:LineString") == 0
1653 	      || strcmp (node->Tag, "LineString") == 0)
1654 	      ;
1655 	  else
1656 	      goto error;
1657 	  *next = node->Next;
1658 	  goto ok;
1659       }
1660 
1661   ok:
1662 /* ok, GML nodes match as expected */
1663     points = gml_count_dyn_points (dyn);
1664     if (points < 2)
1665 	goto error;
1666     if (has_z)
1667       {
1668 	  ln = gaiaAllocGeomCollXYZ ();
1669 	  gmlMapDynAlloc (p_data, GML_DYN_GEOM, ln);
1670 	  ln->Srid = srid;
1671 	  new_ln = gaiaAddLinestringToGeomColl (ln, points);
1672 	  pt = dyn->First;
1673 	  iv = 0;
1674 	  while (pt)
1675 	    {
1676 		gaiaSetPointXYZ (new_ln->Coords, iv, pt->X, pt->Y, pt->Z);
1677 		iv++;
1678 		pt = pt->Next;
1679 	    }
1680       }
1681     else
1682       {
1683 	  ln = gaiaAllocGeomColl ();
1684 	  gmlMapDynAlloc (p_data, GML_DYN_GEOM, ln);
1685 	  ln->Srid = srid;
1686 	  new_ln = gaiaAddLinestringToGeomColl (ln, points);
1687 	  pt = dyn->First;
1688 	  iv = 0;
1689 	  while (pt)
1690 	    {
1691 		gaiaSetPoint (new_ln->Coords, iv, pt->X, pt->Y);
1692 		iv++;
1693 		pt = pt->Next;
1694 	    }
1695       }
1696     last = geom;
1697     while (1)
1698       {
1699 	  /* searching the last Geometry within chain */
1700 	  if (last->Next == NULL)
1701 	      break;
1702 	  last = last->Next;
1703       }
1704     last->Next = ln;
1705     gmlMapDynClean (p_data, dyn);
1706     gaiaFreeDynamicLine (dyn);
1707     return 1;
1708 
1709   error:
1710     gmlMapDynClean (p_data, dyn);
1711     gaiaFreeDynamicLine (dyn);
1712     return 0;
1713 }
1714 
1715 static int
gml_parse_curve(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node,gmlNodePtr * next)1716 gml_parse_curve (struct gml_data *p_data, gaiaGeomCollPtr geom, gmlNodePtr node,
1717 		 gmlNodePtr * next)
1718 {
1719 /* parsing a <gml:Curve> */
1720     int srid = geom->Srid;
1721     int has_z = 0;
1722     gaiaGeomCollPtr ln;
1723     gaiaGeomCollPtr last;
1724     gaiaLinestringPtr new_ln;
1725     gaiaPointPtr pt;
1726     int iv;
1727     int points = 0;
1728     gaiaDynamicLinePtr dyn = gaiaAllocDynamicLine ();
1729     gmlMapDynAlloc (p_data, GML_DYN_DYNLINE, dyn);
1730     if (geom->DimensionModel == GAIA_XY_Z
1731 	|| geom->DimensionModel == GAIA_XY_Z_M)
1732 	has_z = 1;
1733 
1734     if (strcmp (node->Tag, "gml:segments") == 0
1735 	|| strcmp (node->Tag, "segments") == 0)
1736       {
1737 	  /* parsing a GML v.3.x <gml:Curve> */
1738 	  node = node->Next;
1739 	  if (node == NULL)
1740 	      goto error;
1741 	  if (strcmp (node->Tag, "gml:LineStringSegment") == 0
1742 	      || strcmp (node->Tag, "LineStringSegment") == 0)
1743 	      ;
1744 	  else
1745 	      goto error;
1746 	  node = node->Next;
1747 	  if (node == NULL)
1748 	      goto error;
1749 	  if (strcmp (node->Tag, "gml:posList") == 0
1750 	      || strcmp (node->Tag, "posList") == 0)
1751 	    {
1752 		/* parsing a GML v.3.x <gml:LineStringSegment><gml:posList ...> */
1753 		if (!gml_parse_posList (node->Coordinates, dyn, has_z))
1754 		    goto error;
1755 		node = node->Next;
1756 		if (node == NULL)
1757 		    goto error;
1758 		if (strcmp (node->Tag, "gml:posList") == 0
1759 		    || strcmp (node->Tag, "posList") == 0)
1760 		    ;
1761 		else
1762 		    goto error;
1763 
1764 	    }
1765 	  else if (strcmp (node->Tag, "gml:pos") == 0
1766 		   || strcmp (node->Tag, "pos") == 0)
1767 	    {
1768 		/* parsing a GML v.3.x <gml:LineStringSegment><gml:pos ...> */
1769 		gmlNodePtr node2 = node;
1770 		if (!gml_parse_pos_chain (&node2, dyn, has_z))
1771 		    goto error;
1772 		node = node2;
1773 		if (node == NULL)
1774 		    goto error;
1775 	    }
1776 	  else
1777 	      goto error;
1778 	  node = node->Next;
1779 	  if (node == NULL)
1780 	      goto error;
1781 	  if (strcmp (node->Tag, "gml:LineStringSegment") == 0
1782 	      || strcmp (node->Tag, "LineStringSegment") == 0)
1783 	      ;
1784 	  else
1785 	      goto error;
1786 	  node = node->Next;
1787 	  if (node == NULL)
1788 	      goto error;
1789 	  if (strcmp (node->Tag, "gml:segments") == 0
1790 	      || strcmp (node->Tag, "segments") == 0)
1791 	      ;
1792 	  else
1793 	      goto error;
1794 	  node = node->Next;
1795 	  if (node == NULL)
1796 	      goto error;
1797 	  if (strcmp (node->Tag, "gml:Curve") == 0
1798 	      || strcmp (node->Tag, "Curve") == 0)
1799 	      ;
1800 	  else
1801 	      goto error;
1802 	  *next = node->Next;
1803 	  goto ok;
1804       }
1805     goto error;
1806 
1807   ok:
1808 /* ok, GML nodes match as expected */
1809     points = gml_count_dyn_points (dyn);
1810     if (points < 2)
1811 	goto error;
1812     if (has_z)
1813       {
1814 	  ln = gaiaAllocGeomCollXYZ ();
1815 	  gmlMapDynAlloc (p_data, GML_DYN_GEOM, ln);
1816 	  ln->Srid = srid;
1817 	  new_ln = gaiaAddLinestringToGeomColl (ln, points);
1818 	  pt = dyn->First;
1819 	  iv = 0;
1820 	  while (pt)
1821 	    {
1822 		gaiaSetPointXYZ (new_ln->Coords, iv, pt->X, pt->Y, pt->Z);
1823 		iv++;
1824 		pt = pt->Next;
1825 	    }
1826       }
1827     else
1828       {
1829 	  ln = gaiaAllocGeomColl ();
1830 	  gmlMapDynAlloc (p_data, GML_DYN_GEOM, ln);
1831 	  ln->Srid = srid;
1832 	  new_ln = gaiaAddLinestringToGeomColl (ln, points);
1833 	  pt = dyn->First;
1834 	  iv = 0;
1835 	  while (pt)
1836 	    {
1837 		gaiaSetPoint (new_ln->Coords, iv, pt->X, pt->Y);
1838 		iv++;
1839 		pt = pt->Next;
1840 	    }
1841       }
1842     last = geom;
1843     while (1)
1844       {
1845 	  /* searching the last Geometry within chain */
1846 	  if (last->Next == NULL)
1847 	      break;
1848 	  last = last->Next;
1849       }
1850     last->Next = ln;
1851     gmlMapDynClean (p_data, dyn);
1852     gaiaFreeDynamicLine (dyn);
1853     return 1;
1854 
1855   error:
1856     gmlMapDynClean (p_data, dyn);
1857     gaiaFreeDynamicLine (dyn);
1858     return 0;
1859 }
1860 
1861 static int
gml_parse_alt_ring(gmlNodePtr node,int has_z,gmlNodePtr * next,gaiaDynamicLinePtr dyn)1862 gml_parse_alt_ring (gmlNodePtr node,
1863 		    int has_z, gmlNodePtr * next, gaiaDynamicLinePtr dyn)
1864 {
1865 /* alternative Ring syntax */
1866     if (strcmp (node->Tag, "gml:Ring") == 0 || strcmp (node->Tag, "Ring") == 0)
1867       {
1868 	  node = node->Next;
1869 	  if (node == NULL)
1870 	      return 0;
1871 	  if (strcmp (node->Tag, "gml:curveMember") == 0
1872 	      || strcmp (node->Tag, "curveMember") == 0)
1873 	      ;
1874 	  else
1875 	      return 0;
1876 	  node = node->Next;
1877 	  if (node == NULL)
1878 	      return 0;
1879 	  if (strcmp (node->Tag, "gml:Curve") == 0
1880 	      || strcmp (node->Tag, "Curve") == 0)
1881 	      ;
1882 	  else
1883 	      return 0;
1884 	  node = node->Next;
1885 	  if (node == NULL)
1886 	      return 0;
1887 	  if (strcmp (node->Tag, "gml:segments") == 0
1888 	      || strcmp (node->Tag, "segments") == 0)
1889 	    {
1890 		node = node->Next;
1891 		if (node == NULL)
1892 		    return 0;
1893 		if (strcmp (node->Tag, "gml:LineStringSegment") == 0
1894 		    || strcmp (node->Tag, "LineStringSegment") == 0)
1895 		    ;
1896 		else
1897 		    return 0;
1898 		node = node->Next;
1899 		if (node == NULL)
1900 		    return 0;
1901 		if (strcmp (node->Tag, "gml:posList") == 0
1902 		    || strcmp (node->Tag, "posList") == 0)
1903 		  {
1904 		      if (!gml_parse_posList (node->Coordinates, dyn, has_z))
1905 			  return 0;
1906 		      node = node->Next;
1907 		      if (node == NULL)
1908 			  return 0;
1909 		      if (strcmp (node->Tag, "gml:posList") == 0
1910 			  || strcmp (node->Tag, "posList") == 0)
1911 			  ;
1912 		      else
1913 			  return 0;
1914 		      node = node->Next;
1915 		      if (node == NULL)
1916 			  return 0;
1917 		      if (strcmp (node->Tag, "gml:LineStringSegment") == 0
1918 			  || strcmp (node->Tag, "LineStringSegment") == 0)
1919 			  ;
1920 		      else
1921 			  return 0;
1922 		      node = node->Next;
1923 		      if (node == NULL)
1924 			  return 0;
1925 		      if (strcmp (node->Tag, "gml:segments") == 0
1926 			  || strcmp (node->Tag, "segments") == 0)
1927 			  ;
1928 		      else
1929 			  return 0;
1930 		      node = node->Next;
1931 		      if (node == NULL)
1932 			  return 0;
1933 		      if (strcmp (node->Tag, "gml:Curve") == 0
1934 			  || strcmp (node->Tag, "Curve") == 0)
1935 			  ;
1936 		      else
1937 			  return 0;
1938 		      node = node->Next;
1939 		      if (node == NULL)
1940 			  return 0;
1941 		      if (strcmp (node->Tag, "gml:curveMember") == 0
1942 			  || strcmp (node->Tag, "curveMember") == 0)
1943 			  ;
1944 		      else
1945 			  return 0;
1946 		      node = node->Next;
1947 		      if (node == NULL)
1948 			  return 0;
1949 		      if (strcmp (node->Tag, "gml:Ring") == 0
1950 			  || strcmp (node->Tag, "Ring") == 0)
1951 			  *next = node;
1952 		      return 1;
1953 		  }
1954 
1955 	    }
1956       }
1957     return 0;
1958 }
1959 
1960 static gaiaDynamicLinePtr
gml_parse_ring(struct gml_data * p_data,gmlNodePtr node,int * interior,int has_z,gmlNodePtr * next)1961 gml_parse_ring (struct gml_data *p_data, gmlNodePtr node, int *interior,
1962 		int has_z, gmlNodePtr * next)
1963 {
1964 /* parsing a generic GML ring */
1965     gaiaDynamicLinePtr dyn = gaiaAllocDynamicLine ();
1966     gmlMapDynAlloc (p_data, GML_DYN_DYNLINE, dyn);
1967 
1968     if (strcmp (node->Tag, "gml:outerBoundaryIs") == 0
1969 	|| strcmp (node->Tag, "outerBoundaryIs") == 0)
1970       {
1971 	  /* parsing a GML v.2.x <gml:outerBoundaryIs> */
1972 	  node = node->Next;
1973 	  if (node == NULL)
1974 	      goto error;
1975 	  if (strcmp (node->Tag, "gml:LinearRing") == 0
1976 	      || strcmp (node->Tag, "LinearRing") == 0)
1977 	      ;
1978 	  else
1979 	      goto error;
1980 	  node = node->Next;
1981 	  if (node == NULL)
1982 	      goto error;
1983 	  if (strcmp (node->Tag, "gml:coordinates") == 0
1984 	      || strcmp (node->Tag, "coordinates") == 0)
1985 	    {
1986 		/* parsing a GML v.2.x <gml:coordinates> */
1987 		if (!gml_parse_coordinates (node->Coordinates, dyn, &has_z))
1988 		    goto error;
1989 		node = node->Next;
1990 		if (node == NULL)
1991 		    goto error;
1992 		if (strcmp (node->Tag, "gml:coordinates") == 0
1993 		    || strcmp (node->Tag, "coordinates") == 0)
1994 		    ;
1995 		else
1996 		    goto error;
1997 	    }
1998 	  else if (strcmp (node->Tag, "gml:posList") == 0
1999 		   || strcmp (node->Tag, "posList") == 0)
2000 	    {
2001 		/* parsing a GML v.3.x <gml:posList> */
2002 		if (!gml_parse_posList (node->Coordinates, dyn, has_z))
2003 		    goto error;
2004 		node = node->Next;
2005 		if (node == NULL)
2006 		    goto error;
2007 		if (strcmp (node->Tag, "gml:posList") == 0
2008 		    || strcmp (node->Tag, "posList") == 0)
2009 		    ;
2010 		else
2011 		    goto error;
2012 	    }
2013 	  else if (strcmp (node->Tag, "gml:pos") == 0
2014 		   || strcmp (node->Tag, "pos") == 0)
2015 	    {
2016 		/* parsing a GML v.3.x <gml:LinearRing><gml:pos ...> */
2017 		gmlNodePtr node2 = node;
2018 		if (!gml_parse_pos_chain (&node2, dyn, has_z))
2019 		    goto error;
2020 		node = node2;
2021 		if (node == NULL)
2022 		    goto error;
2023 	    }
2024 	  else
2025 	      goto error;
2026 	  node = node->Next;
2027 	  if (node == NULL)
2028 	      goto error;
2029 	  if (strcmp (node->Tag, "gml:LinearRing") == 0
2030 	      || strcmp (node->Tag, "LinearRing") == 0)
2031 	      ;
2032 	  else
2033 	      goto error;
2034 	  node = node->Next;
2035 	  if (node == NULL)
2036 	      goto error;
2037 	  if (strcmp (node->Tag, "gml:outerBoundaryIs") == 0
2038 	      || strcmp (node->Tag, "outerBoundaryIs") == 0)
2039 	      ;
2040 	  else
2041 	      goto error;
2042 	  *interior = 0;
2043 	  *next = node->Next;
2044 	  return dyn;
2045       }
2046     if (strcmp (node->Tag, "gml:innerBoundaryIs") == 0
2047 	|| strcmp (node->Tag, "innerBoundaryIs") == 0)
2048       {
2049 	  /* parsing a GML v.2.x <gml:innerBoundaryIs> */
2050 	  node = node->Next;
2051 	  if (node == NULL)
2052 	      goto error;
2053 	  if (strcmp (node->Tag, "gml:LinearRing") == 0
2054 	      || strcmp (node->Tag, "LinearRing") == 0)
2055 	      ;
2056 	  else
2057 	      goto error;
2058 	  node = node->Next;
2059 	  if (node == NULL)
2060 	      goto error;
2061 	  if (strcmp (node->Tag, "gml:coordinates") == 0
2062 	      || strcmp (node->Tag, "coordinates") == 0)
2063 	    {
2064 		/* parsing a GML v.2.x <gml:coordinates> */
2065 		if (!gml_parse_coordinates (node->Coordinates, dyn, &has_z))
2066 		    goto error;
2067 		node = node->Next;
2068 		if (node == NULL)
2069 		    goto error;
2070 		if (strcmp (node->Tag, "gml:coordinates") == 0
2071 		    || strcmp (node->Tag, "coordinates") == 0)
2072 		    ;
2073 		else
2074 		    goto error;
2075 	    }
2076 	  else if (strcmp (node->Tag, "gml:posList") == 0
2077 		   || strcmp (node->Tag, "posList") == 0)
2078 	    {
2079 		/* parsing a GML v.3.x <gml:posList> */
2080 		if (!gml_parse_posList (node->Coordinates, dyn, has_z))
2081 		    goto error;
2082 		node = node->Next;
2083 		if (node == NULL)
2084 		    goto error;
2085 		if (strcmp (node->Tag, "gml:posList") == 0
2086 		    || strcmp (node->Tag, "posList") == 0)
2087 		    ;
2088 		else
2089 		    goto error;
2090 	    }
2091 	  else if (strcmp (node->Tag, "gml:pos") == 0
2092 		   || strcmp (node->Tag, "pos") == 0)
2093 	    {
2094 		/* parsing a GML v.3.x <gml:LinearRing><gml:pos ...> */
2095 		gmlNodePtr node2 = node;
2096 		if (!gml_parse_pos_chain (&node2, dyn, has_z))
2097 		    goto error;
2098 		node = node2;
2099 		if (node == NULL)
2100 		    goto error;
2101 	    }
2102 	  else
2103 	      goto error;
2104 	  node = node->Next;
2105 	  if (node == NULL)
2106 	      goto error;
2107 	  if (strcmp (node->Tag, "gml:LinearRing") == 0
2108 	      || strcmp (node->Tag, "LinearRing") == 0)
2109 	      ;
2110 	  else
2111 	      goto error;
2112 	  node = node->Next;
2113 	  if (node == NULL)
2114 	      goto error;
2115 	  if (strcmp (node->Tag, "gml:innerBoundaryIs") == 0
2116 	      || strcmp (node->Tag, "innerBoundaryIs") == 0)
2117 	      ;
2118 	  else
2119 	      goto error;
2120 	  *interior = 1;
2121 	  *next = node->Next;
2122 	  return dyn;
2123       }
2124     if (strcmp (node->Tag, "gml:exterior") == 0
2125 	|| strcmp (node->Tag, "exterior") == 0)
2126       {
2127 	  /* parsing a GML v.3.x <gml:exterior> */
2128 	  node = node->Next;
2129 	  if (node == NULL)
2130 	      goto error;
2131 	  if (strcmp (node->Tag, "gml:LinearRing") == 0
2132 	      || strcmp (node->Tag, "LinearRing") == 0)
2133 	      ;
2134 	  else if (strcmp (node->Tag, "gml:Ring") == 0
2135 		   || strcmp (node->Tag, "Ring") == 0)
2136 	    {
2137 		if (gml_parse_alt_ring (node, has_z, next, dyn))
2138 		  {
2139 		      *interior = 0;
2140 		      node = *next;
2141 		      goto ex_exterior;
2142 		  }
2143 		else
2144 		    goto error;
2145 	    }
2146 	  else
2147 	      goto error;
2148 	  node = node->Next;
2149 	  if (node == NULL)
2150 	      goto error;
2151 	  if (strcmp (node->Tag, "gml:posList") == 0
2152 	      || strcmp (node->Tag, "posList") == 0)
2153 	    {
2154 		/* parsing a GML v.3.x <gml:LinearRing><gml:posList ...> */
2155 		if (!gml_parse_posList (node->Coordinates, dyn, has_z))
2156 		    goto error;
2157 		node = node->Next;
2158 		if (node == NULL)
2159 		    goto error;
2160 		if (strcmp (node->Tag, "gml:posList") == 0
2161 		    || strcmp (node->Tag, "posList") == 0)
2162 		    ;
2163 		else
2164 		    goto error;
2165 	    }
2166 	  else if (strcmp (node->Tag, "gml:pos") == 0
2167 		   || strcmp (node->Tag, "pos") == 0)
2168 	    {
2169 		/* parsing a GML v.3.x <gml:LinearRing><gml:pos ...> */
2170 		gmlNodePtr node2 = node;
2171 		if (!gml_parse_pos_chain (&node2, dyn, has_z))
2172 		    goto error;
2173 		node = node2;
2174 		if (node == NULL)
2175 		    goto error;
2176 	    }
2177 	  else
2178 	      goto error;
2179 	  node = node->Next;
2180 	  if (node == NULL)
2181 	      goto error;
2182 	  if (strcmp (node->Tag, "gml:LinearRing") == 0
2183 	      || strcmp (node->Tag, "LinearRing") == 0)
2184 	      ;
2185 	  else
2186 	      goto error;
2187 	ex_exterior:
2188 	  node = node->Next;
2189 	  if (node == NULL)
2190 	      goto error;
2191 	  if (strcmp (node->Tag, "gml:exterior") == 0
2192 	      || strcmp (node->Tag, "exterior") == 0)
2193 	      ;
2194 	  else
2195 	      goto error;
2196 	  *interior = 0;
2197 	  *next = node->Next;
2198 	  return dyn;
2199       }
2200     if (strcmp (node->Tag, "gml:interior") == 0
2201 	|| strcmp (node->Tag, "interior") == 0)
2202       {
2203 	  /* parsing a GML v.3.x <gml:interior> */
2204 	  node = node->Next;
2205 	  if (node == NULL)
2206 	      goto error;
2207 	  if (strcmp (node->Tag, "gml:LinearRing") == 0
2208 	      || strcmp (node->Tag, "LinearRing") == 0)
2209 	      ;
2210 	  else if (strcmp (node->Tag, "gml:Ring") == 0
2211 		   || strcmp (node->Tag, "Ring") == 0)
2212 	    {
2213 		if (gml_parse_alt_ring (node, has_z, next, dyn))
2214 		  {
2215 		      *interior = 1;
2216 		      node = *next;
2217 		      goto ex_interior;
2218 		  }
2219 		else
2220 		    goto error;
2221 	    }
2222 	  else
2223 	      goto error;
2224 	  node = node->Next;
2225 	  if (node == NULL)
2226 	      goto error;
2227 	  if (strcmp (node->Tag, "gml:posList") == 0
2228 	      || strcmp (node->Tag, "posList") == 0)
2229 	    {
2230 		/* parsing a GML v.3.x <gml:LinearRing><gml:posList ...> */
2231 		if (!gml_parse_posList (node->Coordinates, dyn, has_z))
2232 		    goto error;
2233 		node = node->Next;
2234 		if (node == NULL)
2235 		    goto error;
2236 		if (strcmp (node->Tag, "gml:posList") == 0
2237 		    || strcmp (node->Tag, "posList") == 0)
2238 		    ;
2239 		else
2240 		    goto error;
2241 	    }
2242 	  else if (strcmp (node->Tag, "gml:pos") == 0
2243 		   || strcmp (node->Tag, "pos") == 0)
2244 	    {
2245 		/* parsing a GML v.3.x <gml:LinearRing><gml:pos ...> */
2246 		gmlNodePtr node2 = node;
2247 		if (!gml_parse_pos_chain (&node2, dyn, has_z))
2248 		    goto error;
2249 		node = node2;
2250 		if (node == NULL)
2251 		    goto error;
2252 	    }
2253 	  else
2254 	      goto error;
2255 	  node = node->Next;
2256 	  if (node == NULL)
2257 	      goto error;
2258 	  if (strcmp (node->Tag, "gml:LinearRing") == 0
2259 	      || strcmp (node->Tag, "LinearRing") == 0)
2260 	      ;
2261 	  else
2262 	      goto error;
2263 	ex_interior:
2264 	  node = node->Next;
2265 	  if (node == NULL)
2266 	      goto error;
2267 	  if (strcmp (node->Tag, "gml:interior") == 0
2268 	      || strcmp (node->Tag, "interior") == 0)
2269 	      ;
2270 	  else
2271 	      goto error;
2272 	  *interior = 1;
2273 	  *next = node->Next;
2274 	  return dyn;
2275       }
2276 
2277   error:
2278     gmlMapDynClean (p_data, dyn);
2279     gaiaFreeDynamicLine (dyn);
2280     return 0;
2281 }
2282 
2283 static int
gml_parse_polygon(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node,gmlNodePtr * next_n)2284 gml_parse_polygon (struct gml_data *p_data, gaiaGeomCollPtr geom,
2285 		   gmlNodePtr node, gmlNodePtr * next_n)
2286 {
2287 /* parsing a <gml:Polygon> */
2288     int srid = geom->Srid;
2289     int has_z = 0;
2290     int interior;
2291     int inners;
2292     int outers;
2293     int points = 0;
2294     int iv;
2295     int ib = 0;
2296     gaiaGeomCollPtr pg;
2297     gaiaGeomCollPtr last_g;
2298     gaiaPolygonPtr new_pg;
2299     gaiaRingPtr ring;
2300     gaiaDynamicLinePtr dyn;
2301     gaiaPointPtr pt;
2302     gaiaDynamicLinePtr exterior_ring = NULL;
2303     gmlNodePtr next;
2304     gmlDynamicRingPtr dyn_rng;
2305     gmlDynamicPolygonPtr dyn_pg = gml_alloc_dyn_polygon (p_data);
2306     gmlNodePtr n = node;
2307     if (geom->DimensionModel == GAIA_XY_Z
2308 	|| geom->DimensionModel == GAIA_XY_Z_M)
2309 	has_z = 1;
2310 
2311     while (n)
2312       {
2313 	  /* looping on rings */
2314 	  if (strcmp (n->Tag, "gml:Polygon") == 0
2315 	      || strcmp (n->Tag, "Polygon") == 0)
2316 	    {
2317 		*next_n = n->Next;
2318 		break;
2319 	    }
2320 	  dyn = gml_parse_ring (p_data, n, &interior, has_z, &next);
2321 	  if (dyn == NULL)
2322 	      goto error;
2323 	  if (gml_count_dyn_points (dyn) < 4)
2324 	    {
2325 		/* cannot be a valid ring */
2326 		goto error;
2327 	    }
2328 	  /* checking if the ring is closed */
2329 	  if (has_z)
2330 	    {
2331 		if (dyn->First->X == dyn->Last->X
2332 		    && dyn->First->Y == dyn->Last->Y
2333 		    && dyn->First->Z == dyn->Last->Z)
2334 		    ;
2335 		else
2336 		    goto error;
2337 	    }
2338 	  else
2339 	    {
2340 		if (dyn->First->X == dyn->Last->X
2341 		    && dyn->First->Y == dyn->Last->Y)
2342 		    ;
2343 		else
2344 		    goto error;
2345 	    }
2346 	  gml_add_polygon_ring (p_data, dyn_pg, dyn, interior, has_z);
2347 	  n = next;
2348       }
2349 /* ok, GML nodes match as expected */
2350     inners = 0;
2351     outers = 0;
2352     dyn_rng = dyn_pg->first;
2353     while (dyn_rng)
2354       {
2355 	  /* verifying the rings collection */
2356 	  if (dyn_rng->interior)
2357 	      inners++;
2358 	  else
2359 	    {
2360 		outers++;
2361 		points = gml_count_dyn_points (dyn_rng->ring);
2362 		exterior_ring = dyn_rng->ring;
2363 	    }
2364 	  dyn_rng = dyn_rng->next;
2365       }
2366     if (outers != 1)		/* no exterior ring declared */
2367 	goto error;
2368 
2369     if (has_z)
2370       {
2371 	  pg = gaiaAllocGeomCollXYZ ();
2372 	  gmlMapDynAlloc (p_data, GML_DYN_GEOM, pg);
2373 	  pg->Srid = srid;
2374 	  new_pg = gaiaAddPolygonToGeomColl (pg, points, inners);
2375 	  /* initializing the EXTERIOR RING */
2376 	  ring = new_pg->Exterior;
2377 	  pt = exterior_ring->First;
2378 	  iv = 0;
2379 	  while (pt)
2380 	    {
2381 		gaiaSetPointXYZ (ring->Coords, iv, pt->X, pt->Y, pt->Z);
2382 		iv++;
2383 		pt = pt->Next;
2384 	    }
2385 	  dyn_rng = dyn_pg->first;
2386 	  while (dyn_rng)
2387 	    {
2388 		/* initializing any INTERIOR RING */
2389 		if (dyn_rng->interior == 0)
2390 		  {
2391 		      dyn_rng = dyn_rng->next;
2392 		      continue;
2393 		  }
2394 		points = gml_count_dyn_points (dyn_rng->ring);
2395 		ring = gaiaAddInteriorRing (new_pg, ib, points);
2396 		ib++;
2397 		pt = dyn_rng->ring->First;
2398 		iv = 0;
2399 		while (pt)
2400 		  {
2401 		      gaiaSetPointXYZ (ring->Coords, iv, pt->X, pt->Y, pt->Z);
2402 		      iv++;
2403 		      pt = pt->Next;
2404 		  }
2405 		dyn_rng = dyn_rng->next;
2406 	    }
2407       }
2408     else
2409       {
2410 	  pg = gaiaAllocGeomColl ();
2411 	  gmlMapDynAlloc (p_data, GML_DYN_GEOM, pg);
2412 	  pg->Srid = srid;
2413 	  new_pg = gaiaAddPolygonToGeomColl (pg, points, inners);
2414 	  /* initializing the EXTERIOR RING */
2415 	  ring = new_pg->Exterior;
2416 	  pt = exterior_ring->First;
2417 	  iv = 0;
2418 	  while (pt)
2419 	    {
2420 		gaiaSetPoint (ring->Coords, iv, pt->X, pt->Y);
2421 		iv++;
2422 		pt = pt->Next;
2423 	    }
2424 	  dyn_rng = dyn_pg->first;
2425 	  while (dyn_rng)
2426 	    {
2427 		/* initializing any INTERIOR RING */
2428 		if (dyn_rng->interior == 0)
2429 		  {
2430 		      dyn_rng = dyn_rng->next;
2431 		      continue;
2432 		  }
2433 		points = gml_count_dyn_points (dyn_rng->ring);
2434 		ring = gaiaAddInteriorRing (new_pg, ib, points);
2435 		ib++;
2436 		pt = dyn_rng->ring->First;
2437 		iv = 0;
2438 		while (pt)
2439 		  {
2440 		      gaiaSetPoint (ring->Coords, iv, pt->X, pt->Y);
2441 		      iv++;
2442 		      pt = pt->Next;
2443 		  }
2444 		dyn_rng = dyn_rng->next;
2445 	    }
2446       }
2447 
2448     last_g = geom;
2449     while (1)
2450       {
2451 	  /* searching the last Geometry within chain */
2452 	  if (last_g->Next == NULL)
2453 	      break;
2454 	  last_g = last_g->Next;
2455       }
2456     last_g->Next = pg;
2457     gml_free_dyn_polygon (dyn_pg);
2458     return 1;
2459 
2460   error:
2461     gml_free_dyn_polygon (dyn_pg);
2462     return 0;
2463 }
2464 
2465 static int
gml_parse_multi_point(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node)2466 gml_parse_multi_point (struct gml_data *p_data, gaiaGeomCollPtr geom,
2467 		       gmlNodePtr node)
2468 {
2469 /* parsing a <gml:MultiPoint> */
2470     int pts;
2471     gmlNodePtr n2;
2472     gmlNodePtr next;
2473     gmlNodePtr n = node;
2474 
2475     while (n)
2476       {
2477 	  /* looping on Point Members */
2478 	  if (n->Next == NULL)
2479 	    {
2480 		/* verifying the last GML node */
2481 		if (strcmp (n->Tag, "gml:MultiPoint") == 0
2482 		    || strcmp (n->Tag, "MultiPoint") == 0)
2483 		    break;
2484 		else
2485 		    return 0;
2486 	    }
2487 	  if (strcmp (n->Tag, "gml:pointMember") == 0
2488 	      || strcmp (n->Tag, "pointMember") == 0
2489 	      || strcmp (n->Tag, "gml:pointMembers") == 0
2490 	      || strcmp (n->Tag, "pointMembers") == 0)
2491 	      ;
2492 	  else
2493 	      return 0;
2494 	  n2 = n->Next;
2495 	  pts = 0;
2496 	  while (n2)
2497 	    {
2498 		/* looping on Point(s) */
2499 		if (strcmp (n2->Tag, "gml:Point") == 0
2500 		    || strcmp (n2->Tag, "Point") == 0)
2501 		    ;
2502 		else
2503 		  {
2504 		      n = n2;
2505 		      break;
2506 		  }
2507 		n2 = n2->Next;
2508 		if (n2 == NULL)
2509 		    return 0;
2510 		if (!gml_parse_point (p_data, geom, n2, &next))
2511 		    return 0;
2512 		n2 = next;
2513 		if (n2 == NULL)
2514 		    return 0;
2515 		pts++;
2516 	    }
2517 	  if (!pts)
2518 	      return 0;
2519 	  if (strcmp (n->Tag, "gml:pointMember") == 0
2520 	      || strcmp (n->Tag, "pointMember") == 0
2521 	      || strcmp (n->Tag, "gml:pointMembers") == 0
2522 	      || strcmp (n->Tag, "pointMembers") == 0)
2523 	      ;
2524 	  else
2525 	      return 0;
2526 	  n = n->Next;
2527       }
2528     return 1;
2529 }
2530 
2531 static int
gml_parse_multi_linestring(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node)2532 gml_parse_multi_linestring (struct gml_data *p_data, gaiaGeomCollPtr geom,
2533 			    gmlNodePtr node)
2534 {
2535 /* parsing a <gml:MultiLineString> */
2536     int lns;
2537     gmlNodePtr n2;
2538     gmlNodePtr next;
2539     gmlNodePtr n = node;
2540 
2541     while (n)
2542       {
2543 	  /* looping on LineString Members */
2544 	  if (n->Next == NULL)
2545 	    {
2546 		/* verifying the last GML node */
2547 		if (strcmp (n->Tag, "gml:MultiLineString") == 0
2548 		    || strcmp (n->Tag, "MultiLineString") == 0)
2549 		    break;
2550 		else
2551 		    return 0;
2552 	    }
2553 	  if (strcmp (n->Tag, "gml:lineStringMember") == 0
2554 	      || strcmp (n->Tag, "lineStringMember") == 0
2555 	      || strcmp (n->Tag, "gml:lineStringMembers") == 0
2556 	      || strcmp (n->Tag, "lineStringMembers") == 0)
2557 	      ;
2558 	  else
2559 	      return 0;
2560 	  n2 = n->Next;
2561 	  lns = 0;
2562 	  while (n2)
2563 	    {
2564 		/* looping on Linestring(s) */
2565 		if (strcmp (n2->Tag, "gml:LineString") == 0
2566 		    || strcmp (n2->Tag, "LineString") == 0)
2567 		    ;
2568 		else
2569 		  {
2570 		      n = n2;
2571 		      break;
2572 		  }
2573 		n2 = n2->Next;
2574 		if (n2 == NULL)
2575 		    return 0;
2576 		if (!gml_parse_linestring (p_data, geom, n2, &next))
2577 		    return 0;
2578 		n2 = next;
2579 		if (n2 == NULL)
2580 		    return 0;
2581 		lns++;
2582 	    }
2583 	  if (!lns)
2584 	      return 0;
2585 	  if (strcmp (n->Tag, "gml:lineStringMember") == 0
2586 	      || strcmp (n->Tag, "lineStringMember") == 0
2587 	      || strcmp (n->Tag, "gml:lineStringMembers") == 0
2588 	      || strcmp (n->Tag, "lineStringMembers") == 0)
2589 	      ;
2590 	  else
2591 	      return 0;
2592 	  n = n->Next;
2593       }
2594     return 1;
2595 }
2596 
2597 static int
gml_parse_multi_curve(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node)2598 gml_parse_multi_curve (struct gml_data *p_data, gaiaGeomCollPtr geom,
2599 		       gmlNodePtr node)
2600 {
2601 /* parsing a <gml:MultiCurve> */
2602     int lns;
2603     gmlNodePtr n2;
2604     gmlNodePtr next;
2605     gmlNodePtr n = node;
2606 
2607     while (n)
2608       {
2609 	  /* looping on Curve Members */
2610 	  if (n->Next == NULL)
2611 	    {
2612 		/* verifying the last GML node */
2613 		if (strcmp (n->Tag, "gml:MultiCurve") == 0
2614 		    || strcmp (n->Tag, "MultiCurve") == 0)
2615 		    break;
2616 		else
2617 		    return 0;
2618 	    }
2619 	  if (strcmp (n->Tag, "gml:curveMember") == 0
2620 	      || strcmp (n->Tag, "curveMember") == 0
2621 	      || strcmp (n->Tag, "gml:curveMembers") == 0
2622 	      || strcmp (n->Tag, "curveMembers") == 0)
2623 	      ;
2624 	  else
2625 	      return 0;
2626 	  n2 = n->Next;
2627 	  lns = 0;
2628 	  while (n2)
2629 	    {
2630 		/* looping on Curve(s) */
2631 		if (strcmp (n2->Tag, "gml:LineString") == 0
2632 		    || strcmp (n2->Tag, "LineString") == 0)
2633 		  {
2634 		      n2 = n2->Next;
2635 		      if (n2 == NULL)
2636 			  return 0;
2637 		      if (!gml_parse_linestring (p_data, geom, n2, &next))
2638 			  return 0;
2639 		      n2 = next;
2640 		      if (n2 == NULL)
2641 			  return 0;
2642 		      lns++;
2643 		  }
2644 		if (strcmp (n2->Tag, "gml:Curve") == 0
2645 		    || strcmp (n2->Tag, "Curve") == 0)
2646 		    ;
2647 		else
2648 		  {
2649 		      n = n2;
2650 		      break;
2651 		  }
2652 		n2 = n2->Next;
2653 		if (n2 == NULL)
2654 		    return 0;
2655 		if (!gml_parse_curve (p_data, geom, n2, &next))
2656 		    return 0;
2657 		n2 = next;
2658 		if (n2 == NULL)
2659 		    return 0;
2660 		lns++;
2661 	    }
2662 	  if (!lns)
2663 	      return 0;
2664 	  if (strcmp (n->Tag, "gml:curveMember") == 0
2665 	      || strcmp (n->Tag, "curveMember") == 0
2666 	      || strcmp (n->Tag, "gml:curveMembers") == 0
2667 	      || strcmp (n->Tag, "curveMembers") == 0)
2668 	      ;
2669 	  else
2670 	      return 0;
2671 	  n = n->Next;
2672       }
2673     return 1;
2674 }
2675 
2676 static int
gml_parse_multi_polygon(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node)2677 gml_parse_multi_polygon (struct gml_data *p_data, gaiaGeomCollPtr geom,
2678 			 gmlNodePtr node)
2679 {
2680 /* parsing a <gml:MultiPolygon> */
2681     int pgs;
2682     gmlNodePtr n2;
2683     gmlNodePtr next;
2684     gmlNodePtr n = node;
2685 
2686     while (n)
2687       {
2688 	  /* looping on Polygon Members */
2689 	  if (n->Next == NULL)
2690 	    {
2691 		/* verifying the last GML node */
2692 		if (strcmp (n->Tag, "gml:MultiPolygon") == 0
2693 		    || strcmp (n->Tag, "MultiPolygon") == 0)
2694 		    break;
2695 		else
2696 		    return 0;
2697 	    }
2698 	  if (strcmp (n->Tag, "gml:polygonMember") == 0
2699 	      || strcmp (n->Tag, "polygonMember") == 0
2700 	      || strcmp (n->Tag, "gml:polygonMembers") == 0
2701 	      || strcmp (n->Tag, "polygonMembers") == 0)
2702 	      ;
2703 	  else
2704 	      return 0;
2705 	  n2 = n->Next;
2706 	  pgs = 0;
2707 	  while (n2)
2708 	    {
2709 		/* looping on Polygon(s) */
2710 		if (strcmp (n2->Tag, "gml:Polygon") == 0
2711 		    || strcmp (n2->Tag, "Polygon") == 0)
2712 		    ;
2713 		else
2714 		  {
2715 		      n = n2;
2716 		      break;
2717 		  }
2718 		n2 = n2->Next;
2719 		if (n2 == NULL)
2720 		    return 0;
2721 		if (!gml_parse_polygon (p_data, geom, n2, &next))
2722 		    return 0;
2723 		n2 = next;
2724 		if (n2 == NULL)
2725 		    return 0;
2726 		pgs++;
2727 	    }
2728 	  if (!pgs)
2729 	      return 0;
2730 	  if (strcmp (n->Tag, "gml:polygonMember") == 0
2731 	      || strcmp (n->Tag, "polygonMember") == 0
2732 	      || strcmp (n->Tag, "gml:polygonMembers") == 0
2733 	      || strcmp (n->Tag, "polygonMembers") == 0)
2734 	      ;
2735 	  else
2736 	      return 0;
2737 	  n = n->Next;
2738       }
2739     return 1;
2740 }
2741 
2742 static int
gml_parse_multi_surface(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node)2743 gml_parse_multi_surface (struct gml_data *p_data, gaiaGeomCollPtr geom,
2744 			 gmlNodePtr node)
2745 {
2746 /* parsing a <gml:MultiSurface> */
2747     int pgs;
2748     gmlNodePtr n2;
2749     gmlNodePtr next;
2750     gmlNodePtr n = node;
2751 
2752     while (n)
2753       {
2754 	  /* looping on Surface Members */
2755 	  if (n->Next == NULL)
2756 	    {
2757 		/* verifying the last GML node */
2758 		if (strcmp (n->Tag, "gml:MultiSurface") == 0
2759 		    || strcmp (n->Tag, "MultiSurface") == 0)
2760 		    break;
2761 		else
2762 		    return 0;
2763 	    }
2764 	  if (strcmp (n->Tag, "gml:surfaceMember") == 0
2765 	      || strcmp (n->Tag, "surfaceMember") == 0
2766 	      || strcmp (n->Tag, "gml:surfaceMembers") == 0
2767 	      || strcmp (n->Tag, "surfaceMembers") == 0)
2768 	      ;
2769 	  else
2770 	      return 0;
2771 	  n2 = n->Next;
2772 	  pgs = 0;
2773 	  while (n2)
2774 	    {
2775 		/* looping on Polygon(s) */
2776 		if (strcmp (n2->Tag, "gml:Polygon") == 0
2777 		    || strcmp (n2->Tag, "Polygon") == 0)
2778 		    ;
2779 		else
2780 		  {
2781 		      n = n2;
2782 		      break;
2783 		  }
2784 		n2 = n2->Next;
2785 		if (n2 == NULL)
2786 		    return 0;
2787 		if (!gml_parse_polygon (p_data, geom, n2, &next))
2788 		    return 0;
2789 		n2 = next;
2790 		if (n2 == NULL)
2791 		    return 0;
2792 		pgs++;
2793 	    }
2794 	  if (!pgs)
2795 	      return 0;
2796 	  if (strcmp (n->Tag, "gml:surfaceMember") == 0
2797 	      || strcmp (n->Tag, "surfaceMember") == 0
2798 	      || strcmp (n->Tag, "gml:surfaceMembers") == 0
2799 	      || strcmp (n->Tag, "surfaceMembers") == 0)
2800 	      ;
2801 	  else
2802 	      return 0;
2803 	  n = n->Next;
2804       }
2805     return 1;
2806 }
2807 
2808 static int
gml_parse_multi_geometry(struct gml_data * p_data,gaiaGeomCollPtr geom,gmlNodePtr node)2809 gml_parse_multi_geometry (struct gml_data *p_data, gaiaGeomCollPtr geom,
2810 			  gmlNodePtr node)
2811 {
2812 /* parsing a <gml:MultiGeometry> */
2813     int elems;
2814     gmlNodePtr n2;
2815     gmlNodePtr next;
2816     gmlNodePtr n = node;
2817 
2818     while (n)
2819       {
2820 	  /* looping on Geometry Members */
2821 	  if (n->Next == NULL)
2822 	    {
2823 		/* verifying the last GML node */
2824 		if (strcmp (n->Tag, "gml:MultiGeometry") == 0
2825 		    || strcmp (n->Tag, "MultiGeometry") == 0)
2826 		    break;
2827 		else
2828 		    return 0;
2829 	    }
2830 	  if (strcmp (n->Tag, "gml:geometryMember") == 0
2831 	      || strcmp (n->Tag, "geometryMember") == 0
2832 	      || strcmp (n->Tag, "gml:geometryMembers") == 0
2833 	      || strcmp (n->Tag, "geometryMembers") == 0)
2834 	      ;
2835 	  else
2836 	      return 0;
2837 	  n2 = n->Next;
2838 	  elems = 0;
2839 	  while (n2)
2840 	    {
2841 		/* looping on elements */
2842 		if (strcmp (n2->Tag, "gml:Point") == 0
2843 		    || strcmp (n2->Tag, "Point") == 0)
2844 		  {
2845 		      n2 = n2->Next;
2846 		      if (n2 == NULL)
2847 			  return 0;
2848 		      if (!gml_parse_point (p_data, geom, n2, &next))
2849 			  return 0;
2850 		      n2 = next;
2851 		  }
2852 		else if (strcmp (n2->Tag, "gml:LineString") == 0
2853 			 || strcmp (n2->Tag, "LineString") == 0)
2854 		  {
2855 		      n2 = n2->Next;
2856 		      if (n2 == NULL)
2857 			  return 0;
2858 		      if (!gml_parse_linestring (p_data, geom, n2, &next))
2859 			  return 0;
2860 		      n2 = next;
2861 		  }
2862 		else if (strcmp (n2->Tag, "gml:Curve") == 0
2863 			 || strcmp (n2->Tag, "Curve") == 0)
2864 		  {
2865 		      n2 = n2->Next;
2866 		      if (n2 == NULL)
2867 			  return 0;
2868 		      if (!gml_parse_curve (p_data, geom, n2, &next))
2869 			  return 0;
2870 		      n2 = next;
2871 		  }
2872 		else if (strcmp (n2->Tag, "gml:Polygon") == 0
2873 			 || strcmp (n2->Tag, "Polygon") == 0)
2874 		  {
2875 		      n2 = n2->Next;
2876 		      if (n2 == NULL)
2877 			  return 0;
2878 		      if (!gml_parse_polygon (p_data, geom, n2, &next))
2879 			  return 0;
2880 		      n2 = next;
2881 		  }
2882 		else
2883 		  {
2884 		      n = n2;
2885 		      break;
2886 		  }
2887 		elems++;
2888 	    }
2889 	  if (!elems)
2890 	      return 0;
2891 	  if (strcmp (n->Tag, "gml:geometryMember") == 0
2892 	      || strcmp (n->Tag, "geometryMember") == 0
2893 	      || strcmp (n->Tag, "gml:geometryMembers") == 0
2894 	      || strcmp (n->Tag, "geometryMembers") == 0)
2895 	      ;
2896 	  else
2897 	      return 0;
2898 	  n = n->Next;
2899       }
2900     return 1;
2901 }
2902 
2903 static gaiaGeomCollPtr
gml_validate_geometry(const void * cache,struct gml_data * p_data,gaiaGeomCollPtr chain,sqlite3 * sqlite_handle)2904 gml_validate_geometry (const void *cache, struct gml_data *p_data,
2905 		       gaiaGeomCollPtr chain, sqlite3 * sqlite_handle)
2906 {
2907     int xy = 0;
2908     int xyz = 0;
2909     int pts = 0;
2910     int lns = 0;
2911     int pgs = 0;
2912     gaiaPointPtr pt;
2913     gaiaLinestringPtr ln;
2914     gaiaPolygonPtr pg;
2915     gaiaPointPtr save_pt = NULL;
2916     gaiaLinestringPtr save_ln = NULL;
2917     gaiaPolygonPtr save_pg = NULL;
2918     gaiaRingPtr i_ring;
2919     gaiaRingPtr o_ring;
2920     int ib;
2921     int delete_g2;
2922     gaiaGeomCollPtr g;
2923     gaiaGeomCollPtr g2;
2924     gaiaGeomCollPtr geom;
2925     char *proj_from;
2926     char *proj_to;
2927 
2928     g = chain;
2929     while (g)
2930       {
2931 	  if (g != chain)
2932 	    {
2933 		if (g->DimensionModel == GAIA_XY)
2934 		    xy++;
2935 		if (g->DimensionModel == GAIA_XY_Z)
2936 		    xyz++;
2937 	    }
2938 	  pt = g->FirstPoint;
2939 	  while (pt)
2940 	    {
2941 		pts++;
2942 		save_pt = pt;
2943 		pt = pt->Next;
2944 	    }
2945 	  ln = g->FirstLinestring;
2946 	  while (ln)
2947 	    {
2948 		lns++;
2949 		save_ln = ln;
2950 		ln = ln->Next;
2951 	    }
2952 	  pg = g->FirstPolygon;
2953 	  while (pg)
2954 	    {
2955 		pgs++;
2956 		save_pg = pg;
2957 		pg = pg->Next;
2958 	    }
2959 	  g = g->Next;
2960       }
2961     if (pts == 1 && lns == 0 && pgs == 0)
2962       {
2963 	  /* POINT */
2964 	  if (xy > 0)
2965 	    {
2966 		/* 2D [XY] */
2967 		geom = gaiaAllocGeomColl ();
2968 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
2969 		geom->Srid = chain->Srid;
2970 		if (chain->DeclaredType == GAIA_MULTIPOINT)
2971 		    geom->DeclaredType = GAIA_MULTIPOINT;
2972 		else if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2973 		    geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2974 		else
2975 		    geom->DeclaredType = GAIA_POINT;
2976 		gaiaAddPointToGeomColl (geom, save_pt->X, save_pt->Y);
2977 		return geom;
2978 	    }
2979 	  else
2980 	    {
2981 		/* 3D [XYZ] */
2982 		geom = gaiaAllocGeomCollXYZ ();
2983 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
2984 		geom->Srid = chain->Srid;
2985 		if (chain->DeclaredType == GAIA_MULTIPOINT)
2986 		    geom->DeclaredType = GAIA_MULTIPOINT;
2987 		else if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2988 		    geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2989 		else
2990 		    geom->DeclaredType = GAIA_POINT;
2991 		gaiaAddPointToGeomCollXYZ (geom, save_pt->X, save_pt->Y,
2992 					   save_pt->Z);
2993 		return geom;
2994 	    }
2995       }
2996     if (pts == 0 && lns == 1 && pgs == 0)
2997       {
2998 	  /* LINESTRING */
2999 	  if (xy > 0)
3000 	    {
3001 		/* 2D [XY] */
3002 		geom = gaiaAllocGeomColl ();
3003 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3004 	    }
3005 	  else
3006 	    {
3007 		/* 3D [XYZ] */
3008 		geom = gaiaAllocGeomCollXYZ ();
3009 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3010 	    }
3011 	  geom->Srid = chain->Srid;
3012 	  if (chain->DeclaredType == GAIA_MULTILINESTRING)
3013 	      geom->DeclaredType = GAIA_MULTILINESTRING;
3014 	  else if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3015 	      geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3016 	  else
3017 	      geom->DeclaredType = GAIA_LINESTRING;
3018 	  ln = gaiaAddLinestringToGeomColl (geom, save_ln->Points);
3019 	  gaiaCopyLinestringCoords (ln, save_ln);
3020 	  return geom;
3021       }
3022     if (pts == 0 && lns == 0 && pgs == 1)
3023       {
3024 	  /* POLYGON */
3025 	  if (xy > 0)
3026 	    {
3027 		/* 2D [XY] */
3028 		geom = gaiaAllocGeomColl ();
3029 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3030 	    }
3031 	  else
3032 	    {
3033 		/* 3D [XYZ] */
3034 		geom = gaiaAllocGeomCollXYZ ();
3035 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3036 	    }
3037 	  geom->Srid = chain->Srid;
3038 	  if (chain->DeclaredType == GAIA_MULTIPOLYGON)
3039 	      geom->DeclaredType = GAIA_MULTIPOLYGON;
3040 	  else if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3041 	      geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3042 	  else
3043 	      geom->DeclaredType = GAIA_POLYGON;
3044 	  i_ring = save_pg->Exterior;
3045 	  pg = gaiaAddPolygonToGeomColl (geom, i_ring->Points,
3046 					 save_pg->NumInteriors);
3047 	  o_ring = pg->Exterior;
3048 	  gaiaCopyRingCoords (o_ring, i_ring);
3049 	  for (ib = 0; ib < save_pg->NumInteriors; ib++)
3050 	    {
3051 		i_ring = save_pg->Interiors + ib;
3052 		o_ring = gaiaAddInteriorRing (pg, ib, i_ring->Points);
3053 		gaiaCopyRingCoords (o_ring, i_ring);
3054 	    }
3055 	  return geom;
3056       }
3057     if (pts >= 1 && lns == 0 && pgs == 0)
3058       {
3059 	  /* MULTIPOINT */
3060 	  if (xy > 0)
3061 	    {
3062 		/* 2D [XY] */
3063 		geom = gaiaAllocGeomColl ();
3064 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3065 		geom->Srid = chain->Srid;
3066 		if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3067 		    geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3068 		else
3069 		    geom->DeclaredType = GAIA_MULTIPOINT;
3070 		g = chain;
3071 		while (g)
3072 		  {
3073 		      if (geom->Srid <= 0)
3074 			{
3075 			    /* we haven't yet set any SRID */
3076 			    geom->Srid = g->Srid;
3077 			}
3078 		      g2 = g;
3079 		      delete_g2 = 0;
3080 		      if (g->Srid != geom->Srid && g->Srid > 0
3081 			  && sqlite_handle != NULL)
3082 			{
3083 			    /* we'll try to apply a reprojection */
3084 #ifndef OMIT_PROJ		/* but only if PROJ.4 is actually available */
3085 			    getProjParams (sqlite_handle, g->Srid, &proj_from);
3086 			    getProjParams (sqlite_handle, geom->Srid, &proj_to);
3087 			    if (proj_to == NULL || proj_from == NULL)
3088 				;
3089 			    else
3090 			      {
3091 				  if (cache != NULL)
3092 				      g2 = gaiaTransform_r (cache, g, proj_from,
3093 							    proj_to);
3094 				  else
3095 				      g2 = gaiaTransform (g, proj_from,
3096 							  proj_to);
3097 				  if (!g2)
3098 				      g2 = g;
3099 				  else
3100 				      delete_g2 = 1;
3101 			      }
3102 			    if (proj_from)
3103 				free (proj_from);
3104 			    if (proj_to)
3105 				free (proj_to);
3106 #endif
3107 			}
3108 		      pt = g2->FirstPoint;
3109 		      while (pt)
3110 			{
3111 			    gaiaAddPointToGeomColl (geom, pt->X, pt->Y);
3112 			    pt = pt->Next;
3113 			}
3114 		      if (delete_g2)
3115 			{
3116 			    gmlMapDynClean (p_data, g2);
3117 			    gaiaFreeGeomColl (g2);
3118 			}
3119 		      g = g->Next;
3120 		  }
3121 		return geom;
3122 	    }
3123 	  else
3124 	    {
3125 		/* 3D [XYZ] */
3126 		geom = gaiaAllocGeomCollXYZ ();
3127 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3128 		geom->Srid = chain->Srid;
3129 		if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3130 		    geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3131 		else
3132 		    geom->DeclaredType = GAIA_MULTIPOINT;
3133 		g = chain;
3134 		while (g)
3135 		  {
3136 		      if (geom->Srid <= 0)
3137 			{
3138 			    /* we haven't yet a SRID set */
3139 			    geom->Srid = g->Srid;
3140 			}
3141 		      g2 = g;
3142 		      delete_g2 = 0;
3143 		      if (g->Srid != geom->Srid && g->Srid > 0
3144 			  && sqlite_handle != NULL)
3145 			{
3146 			    /* we'll try to apply a reprojection */
3147 #ifndef OMIT_PROJ		/* but only if PROJ.4 is actually available */
3148 			    getProjParams (sqlite_handle, g->Srid, &proj_from);
3149 			    getProjParams (sqlite_handle, geom->Srid, &proj_to);
3150 			    if (proj_to == NULL || proj_from == NULL)
3151 				;
3152 			    else
3153 			      {
3154 				  if (cache != NULL)
3155 				      g2 = gaiaTransform_r (cache, g, proj_from,
3156 							    proj_to);
3157 				  else
3158 				      g2 = gaiaTransform (g, proj_from,
3159 							  proj_to);
3160 				  if (!g2)
3161 				      g2 = g;
3162 				  else
3163 				      delete_g2 = 1;
3164 			      }
3165 			    if (proj_from)
3166 				free (proj_from);
3167 			    if (proj_to)
3168 				free (proj_to);
3169 #endif
3170 			}
3171 		      pt = g2->FirstPoint;
3172 		      while (pt)
3173 			{
3174 			    gaiaAddPointToGeomCollXYZ (geom, pt->X, pt->Y,
3175 						       pt->Z);
3176 			    pt = pt->Next;
3177 			}
3178 		      if (delete_g2)
3179 			{
3180 			    gmlMapDynClean (p_data, g2);
3181 			    gaiaFreeGeomColl (g2);
3182 			}
3183 		      g = g->Next;
3184 		  }
3185 		return geom;
3186 	    }
3187       }
3188     if (pts == 0 && lns >= 1 && pgs == 0)
3189       {
3190 	  /* MULTILINESTRING */
3191 	  if (xy > 0)
3192 	    {
3193 		/* 2D [XY] */
3194 		geom = gaiaAllocGeomColl ();
3195 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3196 		geom->Srid = chain->Srid;
3197 		if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3198 		    geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3199 		else
3200 		    geom->DeclaredType = GAIA_MULTILINESTRING;
3201 		g = chain;
3202 		while (g)
3203 		  {
3204 		      if (geom->Srid <= 0)
3205 			{
3206 			    /* we haven't yet set any SRID */
3207 			    geom->Srid = g->Srid;
3208 			}
3209 		      g2 = g;
3210 		      delete_g2 = 0;
3211 		      if (g->Srid != geom->Srid && g->Srid > 0
3212 			  && sqlite_handle != NULL)
3213 			{
3214 			    /* we'll try to apply a reprojection */
3215 #ifndef OMIT_PROJ		/* but only if PROJ.4 is actually available */
3216 			    getProjParams (sqlite_handle, g->Srid, &proj_from);
3217 			    getProjParams (sqlite_handle, geom->Srid, &proj_to);
3218 			    if (proj_to == NULL || proj_from == NULL)
3219 				;
3220 			    else
3221 			      {
3222 				  if (cache != NULL)
3223 				      g2 = gaiaTransform_r (cache, g, proj_from,
3224 							    proj_to);
3225 				  else
3226 				      g2 = gaiaTransform (g, proj_from,
3227 							  proj_to);
3228 				  if (!g2)
3229 				      g2 = g;
3230 				  else
3231 				      delete_g2 = 1;
3232 			      }
3233 			    if (proj_from)
3234 				free (proj_from);
3235 			    if (proj_to)
3236 				free (proj_to);
3237 #endif
3238 			}
3239 		      ln = g2->FirstLinestring;
3240 		      while (ln)
3241 			{
3242 			    save_ln =
3243 				gaiaAddLinestringToGeomColl (geom, ln->Points);
3244 			    gaiaCopyLinestringCoords (save_ln, ln);
3245 			    ln = ln->Next;
3246 			}
3247 		      if (delete_g2)
3248 			{
3249 			    gmlMapDynClean (p_data, g2);
3250 			    gaiaFreeGeomColl (g2);
3251 			}
3252 		      g = g->Next;
3253 		  }
3254 		return geom;
3255 	    }
3256 	  else
3257 	    {
3258 		/* 3D [XYZ] */
3259 		geom = gaiaAllocGeomCollXYZ ();
3260 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3261 		geom->Srid = chain->Srid;
3262 		if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3263 		    geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3264 		else
3265 		    geom->DeclaredType = GAIA_MULTILINESTRING;
3266 		g = chain;
3267 		while (g)
3268 		  {
3269 		      if (geom->Srid <= 0)
3270 			{
3271 			    /* we haven't yet a SRID set */
3272 			    geom->Srid = g->Srid;
3273 			}
3274 		      g2 = g;
3275 		      delete_g2 = 0;
3276 		      if (g->Srid != geom->Srid && g->Srid > 0
3277 			  && sqlite_handle != NULL)
3278 			{
3279 			    /* we'll try to apply a reprojection */
3280 #ifndef OMIT_PROJ		/* but only if PROJ.4 is actually available */
3281 			    getProjParams (sqlite_handle, g->Srid, &proj_from);
3282 			    getProjParams (sqlite_handle, geom->Srid, &proj_to);
3283 			    if (proj_to == NULL || proj_from == NULL)
3284 				;
3285 			    else
3286 			      {
3287 				  if (cache != NULL)
3288 				      g2 = gaiaTransform_r (cache, g, proj_from,
3289 							    proj_to);
3290 				  else
3291 				      g2 = gaiaTransform (g, proj_from,
3292 							  proj_to);
3293 				  if (!g2)
3294 				      g2 = g;
3295 				  else
3296 				      delete_g2 = 1;
3297 			      }
3298 			    if (proj_from)
3299 				free (proj_from);
3300 			    if (proj_to)
3301 				free (proj_to);
3302 #endif
3303 			}
3304 		      ln = g2->FirstLinestring;
3305 		      while (ln)
3306 			{
3307 			    save_ln =
3308 				gaiaAddLinestringToGeomColl (geom, ln->Points);
3309 			    gaiaCopyLinestringCoords (save_ln, ln);
3310 			    ln = ln->Next;
3311 			}
3312 		      if (delete_g2)
3313 			{
3314 			    gmlMapDynClean (p_data, g2);
3315 			    gaiaFreeGeomColl (g2);
3316 			}
3317 		      g = g->Next;
3318 		  }
3319 		return geom;
3320 	    }
3321       }
3322     if (pts == 0 && lns == 0 && pgs >= 1)
3323       {
3324 	  /* MULTIPOLYGON */
3325 	  if (xy > 0)
3326 	    {
3327 		/* 2D [XY] */
3328 		geom = gaiaAllocGeomColl ();
3329 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3330 		geom->Srid = chain->Srid;
3331 		if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3332 		    geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3333 		else
3334 		    geom->DeclaredType = GAIA_MULTIPOLYGON;
3335 		g = chain;
3336 		while (g)
3337 		  {
3338 		      if (geom->Srid <= 0)
3339 			{
3340 			    /* we haven't yet set any SRID */
3341 			    geom->Srid = g->Srid;
3342 			}
3343 		      g2 = g;
3344 		      delete_g2 = 0;
3345 		      if (g->Srid != geom->Srid && g->Srid > 0
3346 			  && sqlite_handle != NULL)
3347 			{
3348 			    /* we'll try to apply a reprojection */
3349 #ifndef OMIT_PROJ		/* but only if PROJ.4 is actually available */
3350 			    getProjParams (sqlite_handle, g->Srid, &proj_from);
3351 			    getProjParams (sqlite_handle, geom->Srid, &proj_to);
3352 			    if (proj_to == NULL || proj_from == NULL)
3353 				;
3354 			    else
3355 			      {
3356 				  if (cache != NULL)
3357 				      g2 = gaiaTransform_r (cache, g, proj_from,
3358 							    proj_to);
3359 				  else
3360 				      g2 = gaiaTransform (g, proj_from,
3361 							  proj_to);
3362 				  if (!g2)
3363 				      g2 = g;
3364 				  else
3365 				      delete_g2 = 1;
3366 			      }
3367 			    if (proj_from)
3368 				free (proj_from);
3369 			    if (proj_to)
3370 				free (proj_to);
3371 #endif
3372 			}
3373 		      pg = g2->FirstPolygon;
3374 		      while (pg)
3375 			{
3376 			    i_ring = pg->Exterior;
3377 			    save_pg =
3378 				gaiaAddPolygonToGeomColl (geom, i_ring->Points,
3379 							  pg->NumInteriors);
3380 			    o_ring = save_pg->Exterior;
3381 			    gaiaCopyRingCoords (o_ring, i_ring);
3382 			    for (ib = 0; ib < pg->NumInteriors; ib++)
3383 			      {
3384 				  i_ring = pg->Interiors + ib;
3385 				  o_ring =
3386 				      gaiaAddInteriorRing (save_pg, ib,
3387 							   i_ring->Points);
3388 				  gaiaCopyRingCoords (o_ring, i_ring);
3389 			      }
3390 			    pg = pg->Next;
3391 			}
3392 		      if (delete_g2)
3393 			{
3394 			    gmlMapDynClean (p_data, g2);
3395 			    gaiaFreeGeomColl (g2);
3396 			}
3397 		      g = g->Next;
3398 		  }
3399 		return geom;
3400 	    }
3401 	  else
3402 	    {
3403 		/* 3D [XYZ] */
3404 		geom = gaiaAllocGeomCollXYZ ();
3405 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3406 		geom->Srid = chain->Srid;
3407 		if (chain->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3408 		    geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3409 		else
3410 		    geom->DeclaredType = GAIA_MULTIPOLYGON;
3411 		g = chain;
3412 		while (g)
3413 		  {
3414 		      if (geom->Srid <= 0)
3415 			{
3416 			    /* we haven't yet a SRID set */
3417 			    geom->Srid = g->Srid;
3418 			}
3419 		      g2 = g;
3420 		      delete_g2 = 0;
3421 		      if (g->Srid != geom->Srid && g->Srid > 0
3422 			  && sqlite_handle != NULL)
3423 			{
3424 			    /* we'll try to apply a reprojection */
3425 #ifndef OMIT_PROJ		/* but only if PROJ.4 is actually available */
3426 			    getProjParams (sqlite_handle, g->Srid, &proj_from);
3427 			    getProjParams (sqlite_handle, geom->Srid, &proj_to);
3428 			    if (proj_to == NULL || proj_from == NULL)
3429 				;
3430 			    else
3431 			      {
3432 				  if (cache != NULL)
3433 				      g2 = gaiaTransform_r (cache, g, proj_from,
3434 							    proj_to);
3435 				  else
3436 				      g2 = gaiaTransform (g, proj_from,
3437 							  proj_to);
3438 				  if (!g2)
3439 				      g2 = g;
3440 				  else
3441 				      delete_g2 = 1;
3442 			      }
3443 			    if (proj_from)
3444 				free (proj_from);
3445 			    if (proj_to)
3446 				free (proj_to);
3447 #endif
3448 			}
3449 		      pg = g2->FirstPolygon;
3450 		      while (pg)
3451 			{
3452 			    i_ring = pg->Exterior;
3453 			    save_pg =
3454 				gaiaAddPolygonToGeomColl (geom, i_ring->Points,
3455 							  pg->NumInteriors);
3456 			    o_ring = save_pg->Exterior;
3457 			    gaiaCopyRingCoords (o_ring, i_ring);
3458 			    for (ib = 0; ib < pg->NumInteriors; ib++)
3459 			      {
3460 				  i_ring = pg->Interiors + ib;
3461 				  o_ring =
3462 				      gaiaAddInteriorRing (save_pg, ib,
3463 							   i_ring->Points);
3464 				  gaiaCopyRingCoords (o_ring, i_ring);
3465 			      }
3466 			    pg = pg->Next;
3467 			}
3468 		      if (delete_g2)
3469 			{
3470 			    gmlMapDynClean (p_data, g2);
3471 			    gaiaFreeGeomColl (g2);
3472 			}
3473 		      g = g->Next;
3474 		  }
3475 		return geom;
3476 	    }
3477       }
3478     if ((pts + lns + pgs) > 0)
3479       {
3480 	  /* GEOMETRYCOLLECTION */
3481 	  if (xy > 0)
3482 	    {
3483 		/* 2D [XY] */
3484 		geom = gaiaAllocGeomColl ();
3485 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3486 		geom->Srid = chain->Srid;
3487 		geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3488 		g = chain;
3489 		while (g)
3490 		  {
3491 		      if (geom->Srid <= 0)
3492 			{
3493 			    /* we haven't yet set any SRID */
3494 			    geom->Srid = g->Srid;
3495 			}
3496 		      g2 = g;
3497 		      delete_g2 = 0;
3498 		      if (g->Srid != geom->Srid && g->Srid > 0
3499 			  && sqlite_handle != NULL)
3500 			{
3501 			    /* we'll try to apply a reprojection */
3502 #ifndef OMIT_PROJ		/* but only if PROJ.4 is actually available */
3503 			    getProjParams (sqlite_handle, g->Srid, &proj_from);
3504 			    getProjParams (sqlite_handle, geom->Srid, &proj_to);
3505 			    if (proj_to == NULL || proj_from == NULL)
3506 				;
3507 			    else
3508 			      {
3509 				  if (cache != NULL)
3510 				      g2 = gaiaTransform_r (cache, g, proj_from,
3511 							    proj_to);
3512 				  else
3513 				      g2 = gaiaTransform (g, proj_from,
3514 							  proj_to);
3515 				  if (!g2)
3516 				      g2 = g;
3517 				  else
3518 				      delete_g2 = 1;
3519 			      }
3520 			    if (proj_from)
3521 				free (proj_from);
3522 			    if (proj_to)
3523 				free (proj_to);
3524 #endif
3525 			}
3526 		      pt = g2->FirstPoint;
3527 		      while (pt)
3528 			{
3529 			    gaiaAddPointToGeomColl (geom, pt->X, pt->Y);
3530 			    pt = pt->Next;
3531 			}
3532 		      ln = g2->FirstLinestring;
3533 		      while (ln)
3534 			{
3535 			    save_ln =
3536 				gaiaAddLinestringToGeomColl (geom, ln->Points);
3537 			    gaiaCopyLinestringCoords (save_ln, ln);
3538 			    ln = ln->Next;
3539 			}
3540 		      pg = g2->FirstPolygon;
3541 		      while (pg)
3542 			{
3543 			    i_ring = pg->Exterior;
3544 			    save_pg =
3545 				gaiaAddPolygonToGeomColl (geom, i_ring->Points,
3546 							  pg->NumInteriors);
3547 			    o_ring = save_pg->Exterior;
3548 			    gaiaCopyRingCoords (o_ring, i_ring);
3549 			    for (ib = 0; ib < pg->NumInteriors; ib++)
3550 			      {
3551 				  i_ring = pg->Interiors + ib;
3552 				  o_ring =
3553 				      gaiaAddInteriorRing (save_pg, ib,
3554 							   i_ring->Points);
3555 				  gaiaCopyRingCoords (o_ring, i_ring);
3556 			      }
3557 			    pg = pg->Next;
3558 			}
3559 		      if (delete_g2)
3560 			{
3561 			    gmlMapDynClean (p_data, g2);
3562 			    gaiaFreeGeomColl (g2);
3563 			}
3564 		      g = g->Next;
3565 		  }
3566 		return geom;
3567 	    }
3568 	  else
3569 	    {
3570 		/* 3D [XYZ] */
3571 		geom = gaiaAllocGeomCollXYZ ();
3572 		gmlMapDynAlloc (p_data, GML_DYN_GEOM, geom);
3573 		geom->Srid = chain->Srid;
3574 		geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3575 		g = chain;
3576 		while (g)
3577 		  {
3578 		      if (geom->Srid <= 0)
3579 			{
3580 			    /* we haven't yet a SRID set */
3581 			    geom->Srid = g->Srid;
3582 			}
3583 		      g2 = g;
3584 		      delete_g2 = 0;
3585 		      if (g->Srid != geom->Srid && g->Srid > 0
3586 			  && sqlite_handle != NULL)
3587 			{
3588 			    /* we'll try to apply a reprojection */
3589 #ifndef OMIT_PROJ		/* but only if PROJ.4 is actually available */
3590 			    getProjParams (sqlite_handle, g->Srid, &proj_from);
3591 			    getProjParams (sqlite_handle, geom->Srid, &proj_to);
3592 			    if (*proj_to == '\0' || *proj_from == '\0')
3593 				;
3594 			    else
3595 			      {
3596 				  if (cache != NULL)
3597 				      g2 = gaiaTransform_r (cache, g, proj_from,
3598 							    proj_to);
3599 				  else
3600 				      g2 = gaiaTransform (g, proj_from,
3601 							  proj_to);
3602 				  if (!g2)
3603 				      g2 = g;
3604 				  else
3605 				      delete_g2 = 1;
3606 			      }
3607 			    if (proj_from)
3608 				free (proj_from);
3609 			    if (proj_to)
3610 				free (proj_to);
3611 #endif
3612 			}
3613 		      pt = g2->FirstPoint;
3614 		      while (pt)
3615 			{
3616 			    gaiaAddPointToGeomCollXYZ (geom, pt->X, pt->Y,
3617 						       pt->Z);
3618 			    pt = pt->Next;
3619 			}
3620 		      ln = g2->FirstLinestring;
3621 		      while (ln)
3622 			{
3623 			    save_ln =
3624 				gaiaAddLinestringToGeomColl (geom, ln->Points);
3625 			    gaiaCopyLinestringCoords (save_ln, ln);
3626 			    ln = ln->Next;
3627 			}
3628 		      pg = g2->FirstPolygon;
3629 		      while (pg)
3630 			{
3631 			    i_ring = pg->Exterior;
3632 			    save_pg =
3633 				gaiaAddPolygonToGeomColl (geom, i_ring->Points,
3634 							  pg->NumInteriors);
3635 			    o_ring = save_pg->Exterior;
3636 			    gaiaCopyRingCoords (o_ring, i_ring);
3637 			    for (ib = 0; ib < pg->NumInteriors; ib++)
3638 			      {
3639 				  i_ring = pg->Interiors + ib;
3640 				  o_ring =
3641 				      gaiaAddInteriorRing (save_pg, ib,
3642 							   i_ring->Points);
3643 				  gaiaCopyRingCoords (o_ring, i_ring);
3644 			      }
3645 			    pg = pg->Next;
3646 			}
3647 		      if (delete_g2)
3648 			{
3649 			    gmlMapDynClean (p_data, g2);
3650 			    gaiaFreeGeomColl (g2);
3651 			}
3652 		      g = g->Next;
3653 		  }
3654 		return geom;
3655 	    }
3656       }
3657     return NULL;
3658 }
3659 
3660 static void
gml_free_geom_chain(struct gml_data * p_data,gaiaGeomCollPtr geom)3661 gml_free_geom_chain (struct gml_data *p_data, gaiaGeomCollPtr geom)
3662 {
3663 /* deleting a chain of preliminary geometries */
3664     gaiaGeomCollPtr gn;
3665     while (geom)
3666       {
3667 	  gn = geom->Next;
3668 	  gmlMapDynClean (p_data, geom);
3669 	  gaiaFreeGeomColl (geom);
3670 	  geom = gn;
3671       }
3672 }
3673 
3674 static gaiaGeomCollPtr
gml_build_geometry(const void * cache,struct gml_data * p_data,gmlNodePtr tree,sqlite3 * sqlite_handle)3675 gml_build_geometry (const void *cache, struct gml_data *p_data, gmlNodePtr tree,
3676 		    sqlite3 * sqlite_handle)
3677 {
3678 /* attempting to build a geometry from GML nodes */
3679     gaiaGeomCollPtr geom;
3680     gaiaGeomCollPtr result;
3681     int geom_type;
3682     int dims = 2;
3683     gmlNodePtr next;
3684 
3685     if (tree == NULL)
3686 	return NULL;
3687     geom_type = guessGmlGeometryType (tree);
3688     if (geom_type == GAIA_GML_UNKNOWN)
3689       {
3690 	  /* unsupported main geometry type */
3691 	  return NULL;
3692       }
3693 
3694 /* creating the main geometry */
3695     dims = guessGmlDimensions (tree);
3696     if (dims == 2)
3697 	geom = gaiaAllocGeomColl ();
3698     else
3699 	geom = gaiaAllocGeomCollXYZ ();
3700     geom->Srid = guessGmlSrid (tree);
3701 
3702     switch (geom_type)
3703       {
3704 	  /* parsing GML nodes accordingly with declared GML type */
3705       case GAIA_GML_POINT:
3706 	  geom->DeclaredType = GAIA_POINT;
3707 	  if (!gml_parse_point (p_data, geom, tree->Next, &next))
3708 	      goto error;
3709 	  break;
3710       case GAIA_GML_LINESTRING:
3711 	  geom->DeclaredType = GAIA_LINESTRING;
3712 	  if (!gml_parse_linestring (p_data, geom, tree->Next, &next))
3713 	      goto error;
3714 	  break;
3715       case GAIA_GML_CURVE:
3716 	  geom->DeclaredType = GAIA_LINESTRING;
3717 	  if (!gml_parse_curve (p_data, geom, tree->Next, &next))
3718 	      goto error;
3719 	  break;
3720       case GAIA_GML_POLYGON:
3721 	  geom->DeclaredType = GAIA_POLYGON;
3722 	  if (!gml_parse_polygon (p_data, geom, tree->Next, &next))
3723 	      goto error;
3724 	  if (next != NULL)
3725 	      goto error;
3726 	  break;
3727       case GAIA_GML_MULTIPOINT:
3728 	  geom->DeclaredType = GAIA_MULTIPOINT;
3729 	  if (!gml_parse_multi_point (p_data, geom, tree->Next))
3730 	      goto error;
3731 	  break;
3732       case GAIA_GML_MULTILINESTRING:
3733 	  geom->DeclaredType = GAIA_MULTILINESTRING;
3734 	  if (!gml_parse_multi_linestring (p_data, geom, tree->Next))
3735 	      goto error;
3736 	  break;
3737       case GAIA_GML_MULTICURVE:
3738 	  geom->DeclaredType = GAIA_MULTILINESTRING;
3739 	  if (!gml_parse_multi_curve (p_data, geom, tree->Next))
3740 	      goto error;
3741 	  break;
3742       case GAIA_GML_MULTIPOLYGON:
3743 	  geom->DeclaredType = GAIA_MULTIPOLYGON;
3744 	  if (!gml_parse_multi_polygon (p_data, geom, tree->Next))
3745 	      goto error;
3746 	  break;
3747       case GAIA_GML_MULTISURFACE:
3748 	  geom->DeclaredType = GAIA_MULTIPOLYGON;
3749 	  if (!gml_parse_multi_surface (p_data, geom, tree->Next))
3750 	      goto error;
3751 	  break;
3752       case GAIA_GML_MULTIGEOMETRY:
3753 	  geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3754 	  if (!gml_parse_multi_geometry (p_data, geom, tree->Next))
3755 	      goto error;
3756 	  break;
3757       case GAIA_GML_BOX:
3758 	  geom->DeclaredType = GAIA_POLYGON;
3759 	  if (!gml_parse_box (p_data, geom, tree->Next, geom->Srid, &next))
3760 	      goto error;
3761 	  break;
3762       };
3763 
3764 /* attempting to build the final geometry */
3765     result = gml_validate_geometry (cache, p_data, geom, sqlite_handle);
3766     if (result == NULL)
3767 	goto error;
3768     gml_free_geom_chain (p_data, geom);
3769     return result;
3770 
3771   error:
3772     gml_free_geom_chain (p_data, geom);
3773     return NULL;
3774 }
3775 
3776 
3777 /* including LEMON generated code */
3778 #include "Gml.c"
3779 
3780 
3781 
3782 /*
3783 ** CAVEAT: there is an incompatibility between LEMON and FLEX
3784 ** this macro resolves the issue
3785 */
3786 #undef yy_accept
3787 #define yy_accept	yy_gml_flex_accept
3788 
3789 
3790 
3791 /* including FLEX generated code */
3792 #include "lex.Gml.c"
3793 
3794 
3795 
3796 static gaiaGeomCollPtr
gaiaParseGmlCommon(const void * cache,const unsigned char * dirty_buffer,sqlite3 * sqlite_handle)3797 gaiaParseGmlCommon (const void *cache, const unsigned char *dirty_buffer,
3798 		    sqlite3 * sqlite_handle)
3799 {
3800     void *pParser = ParseAlloc (malloc);
3801     /* Linked-list of token values */
3802     gmlFlexToken *tokens = malloc (sizeof (gmlFlexToken));
3803     /* Pointer to the head of the list */
3804     gmlFlexToken *head = tokens;
3805     int yv;
3806     gaiaGeomCollPtr geom = NULL;
3807     yyscan_t scanner;
3808     struct gml_data str_data;
3809 
3810 /* initializing the helper structs */
3811     str_data.gml_line = 1;
3812     str_data.gml_col = 1;
3813     str_data.gml_parse_error = 0;
3814     str_data.gml_first_dyn_block = NULL;
3815     str_data.gml_last_dyn_block = NULL;
3816     str_data.result = NULL;
3817 
3818 /* initializing the scanner state */
3819     Gmllex_init_extra (&str_data, &scanner);
3820 
3821     str_data.GmlLval.pval = NULL;
3822     tokens->value = NULL;
3823     tokens->Next = NULL;
3824     Gml_scan_string ((char *) dirty_buffer, scanner);
3825 
3826     /*
3827        / Keep tokenizing until we reach the end
3828        / yylex() will return the next matching Token for us.
3829      */
3830     while ((yv = yylex (scanner)) != 0)
3831       {
3832 	  if (yv == -1)
3833 	    {
3834 		str_data.gml_parse_error = 1;
3835 		break;
3836 	    }
3837 	  tokens->Next = malloc (sizeof (gmlFlexToken));
3838 	  tokens->Next->Next = NULL;
3839 	  gml_xferString (&(tokens->Next->value), str_data.GmlLval.pval);
3840 	  /* Pass the token to the GML parser created from lemon */
3841 	  Parse (pParser, yv, &(tokens->Next->value), &str_data);
3842 	  tokens = tokens->Next;
3843       }
3844     /* This denotes the end of a line as well as the end of the parser */
3845     Parse (pParser, GML_NEWLINE, 0, &str_data);
3846     ParseFree (pParser, free);
3847     Gmllex_destroy (scanner);
3848 
3849     /* Assigning the token as the end to avoid seg faults while cleaning */
3850     tokens->Next = NULL;
3851     gml_cleanup (head);
3852     gml_freeString (&(str_data.GmlLval.pval));
3853 
3854     if (str_data.gml_parse_error)
3855       {
3856 	  if (str_data.result)
3857 	    {
3858 		/* if a Geometry-result has been produced, the stack is already cleaned */
3859 		gml_freeTree (&str_data, str_data.result);
3860 		gmlCleanMapDynAlloc (&str_data, 0);
3861 	    }
3862 	  else
3863 	    {
3864 		/* otherwise we are required to clean the stack */
3865 		gmlCleanMapDynAlloc (&str_data, 1);
3866 	    }
3867 	  return NULL;
3868       }
3869 
3870     if (str_data.result == NULL)
3871       {
3872 	  gmlCleanMapDynAlloc (&str_data, 0);
3873 	  return NULL;
3874       }
3875 
3876     /* attempting to build a geometry from GML */
3877     geom =
3878 	gml_build_geometry (cache, &str_data, str_data.result, sqlite_handle);
3879     gml_freeTree (&str_data, str_data.result);
3880     gmlCleanMapDynAlloc (&str_data, 0);
3881     return geom;
3882 }
3883 
3884 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaParseGml(const unsigned char * dirty_buffer,sqlite3 * sqlite_handle)3885 gaiaParseGml (const unsigned char *dirty_buffer, sqlite3 * sqlite_handle)
3886 {
3887     return gaiaParseGmlCommon (NULL, dirty_buffer, sqlite_handle);
3888 }
3889 
3890 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaParseGml_r(const void * p_cache,const unsigned char * dirty_buffer,sqlite3 * sqlite_handle)3891 gaiaParseGml_r (const void *p_cache, const unsigned char *dirty_buffer,
3892 		sqlite3 * sqlite_handle)
3893 {
3894     return gaiaParseGmlCommon (p_cache, dirty_buffer, sqlite_handle);
3895 }
3896 
3897 
3898 /*
3899 ** CAVEAT: we must now undefine any Lemon/Flex own macro
3900 */
3901 #undef YYNOCODE
3902 #undef YYNSTATE
3903 #undef YYNRULE
3904 #undef YY_SHIFT_MAX
3905 #undef YY_SHIFT_USE_DFLT
3906 #undef YY_REDUCE_USE_DFLT
3907 #undef YY_REDUCE_MAX
3908 #undef YY_FLUSH_BUFFER
3909 #undef YY_DO_BEFORE_ACTION
3910 #undef YY_NUM_RULES
3911 #undef YY_END_OF_BUFFER
3912 #undef YY_END_FILE
3913 #undef YYACTIONTYPE
3914 #undef YY_SZ_ACTTAB
3915 #undef YY_NEW_FILE
3916 #undef BEGIN
3917 #undef YY_START
3918 #undef YY_CURRENT_BUFFER
3919 #undef YY_CURRENT_BUFFER_LVALUE
3920 #undef YY_STATE_BUF_SIZE
3921 #undef YY_DECL
3922 #undef YY_FATAL_ERROR
3923 #undef YYMINORTYPE
3924 #undef YY_CHAR
3925 #undef YYSTYPE
3926 #undef input
3927 #undef ParseAlloc
3928 #undef ParseFree
3929 #undef ParseStackPeak
3930 #undef Parse
3931 #undef yyalloc
3932 #undef yyfree
3933 #undef yyin
3934 #undef yyleng
3935 #undef yyless
3936 #undef yylex
3937 #undef yylineno
3938 #undef yyout
3939 #undef yyrealloc
3940 #undef yyrestart
3941 #undef yyStackEntry
3942 #undef yytext
3943 #undef yywrap
3944 #undef yyzerominor
3945 #undef yy_accept
3946 #undef yy_action
3947 #undef yy_base
3948 #undef yy_buffer_stack
3949 #undef yy_buffer_stack_max
3950 #undef yy_buffer_stack_top
3951 #undef yy_c_buf_p
3952 #undef yy_chk
3953 #undef yy_create_buffer
3954 #undef yy_def
3955 #undef yy_default
3956 #undef yy_delete_buffer
3957 #undef yy_destructor
3958 #undef yy_ec
3959 #undef yy_fatal_error
3960 #undef yy_find_reduce_action
3961 #undef yy_find_shift_action
3962 #undef yy_flex_debug
3963 #undef yy_flush_buffer
3964 #undef yy_get_next_buffer
3965 #undef yy_get_previous_state
3966 #undef yy_init
3967 #undef yy_init_buffer
3968 #undef yy_init_globals
3969 #undef yy_load_buffer
3970 #undef yy_load_buffer_state
3971 #undef yy_lookahead
3972 #undef yy_meta
3973 #undef yy_new_buffer
3974 #undef yy_nxt
3975 #undef yy_parse_failed
3976 #undef yy_pop_parser_stack
3977 #undef yy_reduce
3978 #undef yy_reduce_ofst
3979 #undef yy_set_bol
3980 #undef yy_set_interactive
3981 #undef yy_shift
3982 #undef yy_shift_ofst
3983 #undef yy_start
3984 #undef yy_state_type
3985 #undef yy_switch_to_buffer
3986 #undef yy_syntax_error
3987 #undef yy_trans_info
3988 #undef yy_try_NUL_trans
3989 #undef yyParser
3990 #undef yyStackEntry
3991 #undef yyStackOverflow
3992 #undef yyRuleInfo
3993 #undef yytext_ptr
3994 #undef yyunput
3995 #undef yyzerominor
3996 #undef ParseARG_SDECL
3997 #undef ParseARG_PDECL
3998 #undef ParseARG_FETCH
3999 #undef ParseARG_STORE
4000 #undef REJECT
4001 #undef yymore
4002 #undef YY_MORE_ADJ
4003 #undef YY_RESTORE_YY_MORE_OFFSET
4004 #undef YY_LESS_LINENO
4005 #undef yyTracePrompt
4006 #undef yyTraceFILE
4007 #undef yyTokenName
4008 #undef yyRuleName
4009 #undef ParseTrace
4010 
4011 #undef yylex
4012 #undef YY_DECL
4013