1 /*
2 
3  gg_xml.c -- XML Document implementation
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) 2008-2021
28 the Initial Developer. All Rights Reserved.
29 
30 Contributor(s):
31 
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43 
44 */
45 
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <time.h>
50 
51 #if defined(_WIN32) && !defined(__MINGW32__)
52 #include "config-msvc.h"
53 #else
54 #include "config.h"
55 #endif
56 
57 #ifdef ENABLE_LIBXML2		/* LIBXML2 enabled: supporting XML documents */
58 
59 #include <zlib.h>
60 #include <libxml/parser.h>
61 #include <libxml/xmlschemas.h>
62 #include <libxml/xpath.h>
63 #include <libxml/xpathInternals.h>
64 
65 #include <spatialite_private.h>
66 #include <spatialite/sqlite.h>
67 #include <spatialite/debug.h>
68 #include <spatialite/gaiageo.h>
69 #include <spatialite/gaiaaux.h>
70 
71 
72 struct gaiaxml_namespace
73 {
74 /* a Namespace declaration */
75     int type;
76     xmlChar *prefix;
77     xmlChar *href;
78     struct gaiaxml_namespace *next;
79 };
80 
81 struct gaiaxml_ns_list
82 {
83 /* a Namespaces list */
84     struct gaiaxml_namespace *first;
85     struct gaiaxml_namespace *last;
86 };
87 
88 static int
is_valid_cache(struct splite_internal_cache * cache)89 is_valid_cache (struct splite_internal_cache *cache)
90 {
91 /* testing if the passed cache is a valid one */
92     if (cache == NULL)
93 	return 0;
94     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
95 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
96 	return 0;
97     return 1;
98 }
99 
100 static struct gaiaxml_namespace *
splite_create_namespace(int type,const xmlChar * prefix,const xmlChar * href)101 splite_create_namespace (int type, const xmlChar * prefix, const xmlChar * href)
102 {
103 /* allocating and initializing a Namespace declaration */
104     int len;
105     struct gaiaxml_namespace *ptr = malloc (sizeof (struct gaiaxml_namespace));
106     ptr->type = type;
107     if (prefix == NULL)
108 	ptr->prefix = NULL;
109     else
110       {
111 	  len = strlen ((const char *) prefix);
112 	  ptr->prefix = malloc (len + 1);
113 	  memcpy (ptr->prefix, prefix, len + 1);
114       }
115     if (href == NULL)
116 	ptr->href = NULL;
117     else
118       {
119 	  len = strlen ((const char *) href);
120 	  ptr->href = malloc (len + 1);
121 	  memcpy (ptr->href, href, len + 1);
122       }
123     ptr->next = NULL;
124     return ptr;
125 }
126 
127 static void
splite_free_namespace(struct gaiaxml_namespace * ptr)128 splite_free_namespace (struct gaiaxml_namespace *ptr)
129 {
130 /* memory cleanup - destroying a Namespace declaration */
131     if (ptr == NULL)
132 	return;
133     if (ptr->prefix != NULL)
134 	free (ptr->prefix);
135     if (ptr->href != NULL)
136 	free (ptr->href);
137     free (ptr);
138 }
139 
140 static struct gaiaxml_ns_list *
splite_create_ns_list(void)141 splite_create_ns_list (void)
142 {
143 /* allocating and initializing a Namespaces list */
144     struct gaiaxml_ns_list *ptr = malloc (sizeof (struct gaiaxml_ns_list));
145     ptr->first = NULL;
146     ptr->last = NULL;
147     return ptr;
148 }
149 
150 static void
splite_free_ns_list(struct gaiaxml_ns_list * ptr)151 splite_free_ns_list (struct gaiaxml_ns_list *ptr)
152 {
153 /* memory cleanup - destroying a Namespaces list */
154     struct gaiaxml_namespace *p;
155     struct gaiaxml_namespace *p_n;
156     if (ptr == NULL)
157 	return;
158     p = ptr->first;
159     while (p != NULL)
160       {
161 	  p_n = p->next;
162 	  splite_free_namespace (p);
163 	  p = p_n;
164       }
165     free (ptr);
166 }
167 
168 static void
splite_add_namespace(struct gaiaxml_ns_list * list,int type,const xmlChar * prefix,const xmlChar * href)169 splite_add_namespace (struct gaiaxml_ns_list *list, int type,
170 		      const xmlChar * prefix, const xmlChar * href)
171 {
172 /* inserting a new Namespace into the list */
173     struct gaiaxml_namespace *ns;
174     if (list == NULL)
175 	return;
176     ns = list->first;
177     while (ns != NULL)
178       {
179 	  /* checking if already defined */
180 	  int ok_type = 0;
181 	  int ok_prefix = 0;
182 	  int ok_href = 0;
183 	  if (ns->type == type)
184 	      ok_type = 1;
185 	  if (ns->prefix == NULL && prefix == NULL)
186 	      ok_prefix = 1;
187 	  if (ns->prefix != NULL && prefix != NULL)
188 	    {
189 		if (strcmp ((const char *) (ns->prefix), (const char *) prefix)
190 		    == 0)
191 		    ok_prefix = 1;
192 	    }
193 	  if (ns->href == NULL && href == NULL)
194 	      ok_href = 1;
195 	  if (ns->href != NULL && href != NULL)
196 	    {
197 		if (strcmp ((const char *) (ns->href), (const char *) href) ==
198 		    0)
199 		    ok_href = 1;
200 	    }
201 	  if (ok_type && ok_prefix && ok_href)
202 	      return;
203 	  ns = ns->next;
204       }
205 /* inserting a new Namespace */
206     ns = splite_create_namespace (type, prefix, href);
207     if (list->first == NULL)
208 	list->first = ns;
209     if (list->last != NULL)
210 	list->last->next = ns;
211     list->last = ns;
212 }
213 
214 static void
spliteSilentError(void * ctx,const char * msg,...)215 spliteSilentError (void *ctx, const char *msg, ...)
216 {
217 /* shutting up XML Errors */
218     if (ctx != NULL)
219 	ctx = NULL;		/* suppressing stupid compiler warnings (unused args) */
220     if (msg != NULL)
221 	ctx = NULL;		/* suppressing stupid compiler warnings (unused args) */
222 }
223 
224 static void
spliteParsingError(void * ctx,const char * msg,...)225 spliteParsingError (void *ctx, const char *msg, ...)
226 {
227 /* appending to the current Parsing Error buffer */
228     struct splite_internal_cache *cache = (struct splite_internal_cache *) ctx;
229     gaiaOutBufferPtr buf;
230     char out[65536];
231     va_list args;
232 
233     if (ctx != NULL)
234 	ctx = NULL;		/* suppressing stupid compiler warnings (unused args) */
235     if (!is_valid_cache (cache))
236 	return;
237     buf = (gaiaOutBufferPtr) (cache->xmlParsingErrors);
238 
239     va_start (args, msg);
240     vsnprintf (out, 65536, msg, args);
241     gaiaAppendToOutBuffer (buf, out);
242     va_end (args);
243 }
244 
245 static void
spliteSchemaValidationError(void * ctx,const char * msg,...)246 spliteSchemaValidationError (void *ctx, const char *msg, ...)
247 {
248 /* appending to the current SchemaValidation Error buffer */
249     struct splite_internal_cache *cache = (struct splite_internal_cache *) ctx;
250     gaiaOutBufferPtr buf;
251     char out[65536];
252     va_list args;
253 
254     if (ctx != NULL)
255 	ctx = NULL;		/* suppressing stupid compiler warnings (unused args) */
256     if (!is_valid_cache (cache))
257 	return;
258     buf = (gaiaOutBufferPtr) (cache->xmlSchemaValidationErrors);
259 
260     va_start (args, msg);
261     vsnprintf (out, 65536, msg, args);
262     gaiaAppendToOutBuffer (buf, out);
263     va_end (args);
264 }
265 
266 static void
spliteResetXmlErrors(struct splite_internal_cache * cache)267 spliteResetXmlErrors (struct splite_internal_cache *cache)
268 {
269 /* resetting the XML Error buffers */
270     gaiaOutBufferPtr buf;
271     if (!is_valid_cache (cache))
272 	return;
273     buf = (gaiaOutBufferPtr) (cache->xmlParsingErrors);
274     gaiaOutBufferReset (buf);
275     buf = (gaiaOutBufferPtr) (cache->xmlSchemaValidationErrors);
276     gaiaOutBufferReset (buf);
277 }
278 
279 GAIAGEO_DECLARE char *
gaiaXmlBlobGetLastParseError(const void * ptr)280 gaiaXmlBlobGetLastParseError (const void *ptr)
281 {
282 /* get the most recent XML Parse error/warning message */
283     struct splite_internal_cache *cache = (struct splite_internal_cache *) ptr;
284     gaiaOutBufferPtr buf;
285     if (!is_valid_cache (cache))
286 	return NULL;
287     buf = (gaiaOutBufferPtr) (cache->xmlParsingErrors);
288     return buf->Buffer;
289 }
290 
291 GAIAGEO_DECLARE char *
gaiaXmlBlobGetLastValidateError(const void * ptr)292 gaiaXmlBlobGetLastValidateError (const void *ptr)
293 {
294 /* get the most recent XML Validate error/warning message */
295     struct splite_internal_cache *cache = (struct splite_internal_cache *) ptr;
296     gaiaOutBufferPtr buf;
297     if (!is_valid_cache (cache))
298 	return NULL;
299     buf = (gaiaOutBufferPtr) (cache->xmlSchemaValidationErrors);
300     return buf->Buffer;
301 }
302 
303 GAIAGEO_DECLARE char *
gaiaXmlBlobGetLastXPathError(const void * ptr)304 gaiaXmlBlobGetLastXPathError (const void *ptr)
305 {
306 /* get the most recent XML Validate error/warning message */
307     struct splite_internal_cache *cache = (struct splite_internal_cache *) ptr;
308     gaiaOutBufferPtr buf;
309     if (!is_valid_cache (cache))
310 	return NULL;
311     buf = (gaiaOutBufferPtr) (cache->xmlXPathErrors);
312     return buf->Buffer;
313 }
314 
315 SPATIALITE_PRIVATE void
splite_free_xml_schema_cache_item(struct splite_xmlSchema_cache_item * p)316 splite_free_xml_schema_cache_item (struct splite_xmlSchema_cache_item *p)
317 {
318 /* freeing an XmlSchema Cache Item */
319     if (p->schemaURI)
320 	free (p->schemaURI);
321     if (p->parserCtxt)
322 	xmlSchemaFreeParserCtxt (p->parserCtxt);
323     if (p->schema)
324 	xmlSchemaFree (p->schema);
325     if (p->schemaDoc)
326 	xmlFreeDoc (p->schemaDoc);
327     p->schemaURI = NULL;
328     p->parserCtxt = NULL;
329     p->schemaDoc = NULL;
330     p->schema = NULL;
331 }
332 
333 static int
splite_xmlSchemaCacheFind(struct splite_internal_cache * cache,const char * schemaURI,xmlDocPtr * schema_doc,xmlSchemaParserCtxtPtr * parser_ctxt,xmlSchemaPtr * schema)334 splite_xmlSchemaCacheFind (struct splite_internal_cache *cache,
335 			   const char *schemaURI, xmlDocPtr * schema_doc,
336 			   xmlSchemaParserCtxtPtr * parser_ctxt,
337 			   xmlSchemaPtr * schema)
338 {
339 /* attempting to retrieve some XmlSchema from within the Cache */
340     int i;
341     time_t now;
342     struct splite_xmlSchema_cache_item *p;
343     if (!is_valid_cache (cache))
344 	return 0;
345     for (i = 0; i < MAX_XMLSCHEMA_CACHE; i++)
346       {
347 	  p = &(cache->xmlSchemaCache[i]);
348 	  if (p->schemaURI)
349 	    {
350 		if (strcmp (schemaURI, p->schemaURI) == 0)
351 		  {
352 		      /* found a matching cache-item */
353 		      *schema_doc = p->schemaDoc;
354 		      *parser_ctxt = p->parserCtxt;
355 		      *schema = p->schema;
356 		      /* updating the timestamp */ time (&now);
357 		      p->timestamp = now;
358 		      return 1;
359 		  }
360 	    }
361       }
362     return 0;
363 }
364 
365 static void
splite_xmlSchemaCacheInsert(struct splite_internal_cache * cache,const char * schemaURI,xmlDocPtr schema_doc,xmlSchemaParserCtxtPtr parser_ctxt,xmlSchemaPtr schema)366 splite_xmlSchemaCacheInsert (struct splite_internal_cache *cache,
367 			     const char *schemaURI, xmlDocPtr schema_doc,
368 			     xmlSchemaParserCtxtPtr parser_ctxt,
369 			     xmlSchemaPtr schema)
370 {
371 /* inserting a new XmlSchema item into the Cache */
372     int i;
373     int len = strlen (schemaURI);
374     time_t now;
375     time_t oldest;
376     struct splite_xmlSchema_cache_item *pSlot = NULL;
377     struct splite_xmlSchema_cache_item *p;
378     if (!is_valid_cache (cache))
379 	return;
380     time (&now);
381     oldest = now;
382     for (i = 0; i < MAX_XMLSCHEMA_CACHE; i++)
383       {
384 	  p = &(cache->xmlSchemaCache[i]);
385 	  if (p->schemaURI == NULL)
386 	    {
387 		/* found an empty slot */
388 		pSlot = p;
389 		break;
390 	    }
391 	  if (p->timestamp < oldest)
392 	    {
393 		/* saving the oldest slot */
394 		pSlot = p;
395 		oldest = p->timestamp;
396 	    }
397       }
398 /* inserting into the Cache Slot */
399     splite_free_xml_schema_cache_item (pSlot);
400     pSlot->timestamp = now;
401     pSlot->schemaURI = malloc (len + 1);
402     strcpy (pSlot->schemaURI, schemaURI);
403     pSlot->schemaDoc = schema_doc;
404     pSlot->parserCtxt = parser_ctxt;
405     pSlot->schema = schema;
406 }
407 
408 static void
sniff_sld_payload(xmlNodePtr node,int * layers,int * point,int * line,int * polygon,int * raster)409 sniff_sld_payload (xmlNodePtr node, int *layers, int *point, int *line,
410 		   int *polygon, int *raster)
411 {
412 /* recursively sniffing a generic SLD payload type */
413 
414     while (node)
415       {
416 	  if (node->type == XML_ELEMENT_NODE)
417 	    {
418 		const char *name = (const char *) (node->name);
419 		if (strcmp (name, "FeatureTypeStyle") == 0)
420 		    *layers += 1;
421 		if (strcmp (name, "CoverageStyle") == 0)
422 		    *layers += 1;
423 		if (strcmp (name, "PointSymbolizer") == 0)
424 		    *point += 1;
425 		if (strcmp (name, "LineSymbolizer") == 0)
426 		    *line += 1;
427 		if (strcmp (name, "PolygonSymbolizer") == 0)
428 		    *polygon += 1;
429 		if (strcmp (name, "RasterSymbolizer") == 0)
430 		    *raster += 1;
431 	    }
432 	  sniff_sld_payload (node->children, layers, point, line, polygon,
433 			     raster);
434 	  node = node->next;
435       }
436 }
437 
438 static void
sniff_payload(xmlDocPtr xml_doc,int * is_iso_metadata,int * is_sld_se_vector_style,int * is_sld_se_raster_style,int * is_sld_style,int * is_svg,int * is_gpx,int * is_map_config)439 sniff_payload (xmlDocPtr xml_doc, int *is_iso_metadata,
440 	       int *is_sld_se_vector_style, int *is_sld_se_raster_style,
441 	       int *is_sld_style, int *is_svg, int *is_gpx, int *is_map_config)
442 {
443 /* sniffing the payload type */
444     xmlNodePtr root = xmlDocGetRootElement (xml_doc);
445     *is_iso_metadata = 0;
446     *is_sld_se_vector_style = 0;
447     *is_sld_se_raster_style = 0;
448     *is_svg = 0;
449     *is_gpx = 0;
450     if (root->name != NULL)
451       {
452 	  const char *name = (const char *) (root->name);
453 	  if (strcmp (name, "MD_Metadata") == 0)
454 	      *is_iso_metadata = 1;
455 	  if (strcmp (name, "FeatureTypeStyle") == 0
456 	      || strcmp (name, "PointSymbolizer") == 0
457 	      || strcmp (name, "LineSymbolizer") == 0
458 	      || strcmp (name, "PolygonSymbolizer") == 0
459 	      || strcmp (name, "TextSymbolizer") == 0)
460 	      *is_sld_se_vector_style = 1;
461 	  if (strcmp (name, "RasterSymbolizer") == 0
462 	      || strcmp (name, "CoverageStyle") == 0)
463 	      *is_sld_se_raster_style = 1;
464 	  if (strcmp (name, "StyledLayerDescriptor") == 0)
465 	    {
466 		/* sniffing an SLD (1.0.0 ??) payload */
467 		int layers = 0;
468 		int point = 0;
469 		int line = 0;
470 		int polygon = 0;
471 		int raster = 0;
472 		xmlNodePtr node = xmlDocGetRootElement (xml_doc);
473 		sniff_sld_payload (node, &layers, &point, &line, &polygon,
474 				   &raster);
475 		if (layers == 1 && point == 0 && line == 0 && polygon == 0
476 		    && raster == 1)
477 		  {
478 		      /* raster style */
479 		      *is_sld_se_raster_style = 1;
480 		  }
481 		if (layers == 1 && (point > 0 || line > 0 || polygon > 0)
482 		    && raster == 0)
483 		  {
484 		      /* vector style */
485 		      *is_sld_se_vector_style = 1;
486 		  }
487 		*is_sld_style = 1;
488 	    }
489 	  if (strcmp (name, "svg") == 0)
490 	      *is_svg = 1;
491 	  if (strcmp (name, "gpx") == 0)
492 	      *is_gpx = 1;
493 	  if (strcmp (name, "RL2MapConfig") == 0)
494 	      *is_map_config = 1;
495       }
496 }
497 
498 static void
find_iso_ids(xmlNodePtr node,const char * name,char ** string,int * open_tag,int * char_string,int * count)499 find_iso_ids (xmlNodePtr node, const char *name, char **string, int *open_tag,
500 	      int *char_string, int *count)
501 {
502 /* recursively scanning the DOM tree [fileIdentifier or parentIdentifier] */
503     xmlNode *cur_node = NULL;
504     int open = 0;
505     int cs = 0;
506 
507     for (cur_node = node; cur_node; cur_node = cur_node->next)
508       {
509 	  if (cur_node->type == XML_ELEMENT_NODE)
510 	    {
511 		const char *xname = (const char *) (cur_node->name);
512 		if (*open_tag == 1)
513 		  {
514 		      if (strcmp (xname, "CharacterString") == 0)
515 			{
516 			    cs = 1;
517 			    *char_string = 1;
518 			}
519 		  }
520 		if (strcmp (xname, name) == 0)
521 		  {
522 		      if (cur_node->parent != NULL)
523 			{
524 			    if (cur_node->parent->type == XML_ELEMENT_NODE)
525 			      {
526 				  if (strcmp
527 				      ((const char *) (cur_node->parent->name),
528 				       "MD_Metadata") == 0)
529 				    {
530 					/*
531 					   / only if <MD_Metadata>
532 					   /           <fileIdentifier>
533 					   /             <CharacterString>
534 					 */
535 					open = 1;
536 					*open_tag = 1;
537 				    }
538 			      }
539 			}
540 		  }
541 	    }
542 	  if (cur_node->type == XML_TEXT_NODE && *open_tag == 1
543 	      && *char_string == 1)
544 	    {
545 		if (cur_node->content != NULL)
546 		  {
547 		      int len = strlen ((const char *) cur_node->content);
548 		      char *buf = malloc (len + 1);
549 		      strcpy (buf, (const char *) cur_node->content);
550 		      if (*string)
551 			  free (*string);
552 		      *string = buf;
553 		      *count += 1;
554 		  }
555 	    }
556 
557 	  find_iso_ids (cur_node->children, name, string, open_tag, char_string,
558 			count);
559 	  if (open)
560 	      *open_tag = 0;
561 	  if (cs)
562 	      *char_string = 0;
563       }
564 }
565 
566 static void
find_iso_title(xmlNodePtr node,char ** string,int * open_tag,int * char_string,int * count)567 find_iso_title (xmlNodePtr node, char **string, int *open_tag, int *char_string,
568 		int *count)
569 {
570 /* recursively scanning the DOM tree [title] */
571     xmlNode *cur_node = NULL;
572     xmlNode *parent;
573     int open = 0;
574     int cs = 0;
575     int ok_parent;
576 
577     for (cur_node = node; cur_node; cur_node = cur_node->next)
578       {
579 	  if (cur_node->type == XML_ELEMENT_NODE)
580 	    {
581 		if (*open_tag == 1)
582 		  {
583 		      if (strcmp
584 			  ((const char *) (cur_node->name),
585 			   "CharacterString") == 0)
586 			{
587 			    cs = 1;
588 			    *char_string = 1;
589 			}
590 		  }
591 		if (strcmp ((const char *) (cur_node->name), "title") == 0)
592 		  {
593 		      ok_parent = 0;
594 		      parent = cur_node->parent;
595 		      if (parent)
596 			{
597 			    if (strcmp
598 				((const char *) (parent->name),
599 				 "CI_Citation") == 0)
600 				ok_parent++;
601 			}
602 		      if (ok_parent == 1)
603 			{
604 			    parent = parent->parent;
605 			    if (strcmp
606 				((const char *) (parent->name),
607 				 "citation") == 0)
608 				ok_parent++;
609 			}
610 		      if (ok_parent == 2)
611 			{
612 			    parent = parent->parent;
613 			    if (strcmp
614 				((const char *) (parent->name),
615 				 "MD_DataIdentification") == 0)
616 				ok_parent++;
617 			}
618 		      if (ok_parent == 3)
619 			{
620 			    parent = parent->parent;
621 			    if (strcmp
622 				((const char *) (parent->name),
623 				 "identificationInfo") == 0)
624 				ok_parent++;
625 			}
626 		      if (ok_parent == 4)
627 			{
628 			    parent = parent->parent;
629 			    if (strcmp
630 				((const char *) (parent->name),
631 				 "MD_Metadata") == 0)
632 				ok_parent++;
633 			}
634 		      if (ok_parent == 5)
635 			{
636 			    /*
637 			       / only if <MD_Metadata>
638 			       /           <identificationInfo>
639 			       /             <MD_DataIdentification>
640 			       /               <citation>
641 			       /                 <CI_Citation>
642 			       /                   <title>
643 			     */
644 			    open = 1;
645 			    *open_tag = 1;
646 			}
647 		  }
648 	    }
649 	  if (cur_node->type == XML_TEXT_NODE && *open_tag == 1
650 	      && *char_string == 1)
651 	    {
652 		if (cur_node->content != NULL)
653 		  {
654 		      int len = strlen ((const char *) cur_node->content);
655 		      char *buf = malloc (len + 1);
656 		      strcpy (buf, (const char *) cur_node->content);
657 		      if (*string)
658 			  free (*string);
659 		      *string = buf;
660 		      *count += 1;
661 		  }
662 	    }
663 
664 	  find_iso_title (cur_node->children, string, open_tag, char_string,
665 			  count);
666 	  if (open)
667 	      *open_tag = 0;
668 	  if (cs)
669 	      *char_string = 0;
670       }
671 }
672 
673 static void
find_iso_abstract(xmlNodePtr node,char ** string,int * open_tag,int * char_string,int * count)674 find_iso_abstract (xmlNodePtr node, char **string, int *open_tag,
675 		   int *char_string, int *count)
676 {
677 /* recursively scanning the DOM abstract [title] */
678     xmlNode *cur_node = NULL;
679     xmlNode *parent;
680     int open = 0;
681     int cs = 0;
682     int ok_parent;
683 
684     for (cur_node = node; cur_node; cur_node = cur_node->next)
685       {
686 	  if (cur_node->type == XML_ELEMENT_NODE)
687 	    {
688 		if (*open_tag == 1)
689 		  {
690 		      if (strcmp
691 			  ((const char *) (cur_node->name),
692 			   "CharacterString") == 0)
693 			{
694 			    cs = 1;
695 			    *char_string = 1;
696 			}
697 		  }
698 		if (strcmp ((const char *) (cur_node->name), "abstract") == 0)
699 		  {
700 		      ok_parent = 0;
701 		      parent = cur_node->parent;
702 		      if (parent)
703 			{
704 			    if (strcmp
705 				((const char *) (parent->name),
706 				 "MD_DataIdentification") == 0)
707 				ok_parent++;
708 			}
709 		      if (ok_parent == 1)
710 			{
711 			    parent = parent->parent;
712 			    if (strcmp
713 				((const char *) (parent->name),
714 				 "identificationInfo") == 0)
715 				ok_parent++;
716 			}
717 		      if (ok_parent == 2)
718 			{
719 			    parent = parent->parent;
720 			    if (strcmp
721 				((const char *) (parent->name),
722 				 "MD_Metadata") == 0)
723 				ok_parent++;
724 			}
725 		      if (ok_parent == 3)
726 			{
727 			    /* only if <MD_Metadata>
728 			       /            <identificationInfo>
729 			       /              <MD_DataIdentification>
730 			       /                <abstract>
731 			     */
732 			    open = 1;
733 			    *open_tag = 1;
734 			}
735 		  }
736 	    }
737 	  if (cur_node->type == XML_TEXT_NODE && *open_tag == 1
738 	      && *char_string == 1)
739 	    {
740 		if (cur_node->content != NULL)
741 		  {
742 		      int len = strlen ((const char *) cur_node->content);
743 		      char *buf = malloc (len + 1);
744 		      strcpy (buf, (const char *) cur_node->content);
745 		      if (*string)
746 			  free (*string);
747 		      *string = buf;
748 		      *count += 1;
749 		  }
750 	    }
751 
752 	  find_iso_abstract (cur_node->children, string, open_tag, char_string,
753 			     count);
754 	  if (open)
755 	      *open_tag = 0;
756 	  if (cs)
757 	      *char_string = 0;
758       }
759 }
760 
761 static void
find_bbox_coord(xmlNodePtr node,const char * name,double * coord,int * open_tag,int * decimal,int * count)762 find_bbox_coord (xmlNodePtr node, const char *name, double *coord,
763 		 int *open_tag, int *decimal, int *count)
764 {
765 /* recursively scanning an EX_GeographicBoundingBox sub-tree */
766     xmlNode *cur_node = NULL;
767     int open = 0;
768     int dec = 0;
769 
770     for (cur_node = node; cur_node; cur_node = cur_node->next)
771       {
772 	  if (cur_node->type == XML_ELEMENT_NODE)
773 	    {
774 		if (*open_tag == 1)
775 		  {
776 		      if (strcmp ((const char *) (cur_node->name), "Decimal") ==
777 			  0)
778 			{
779 			    dec = 1;
780 			    *decimal = 1;
781 			}
782 		  }
783 		if (strcmp ((const char *) (cur_node->name), name) == 0)
784 		  {
785 		      open = 1;
786 		      *open_tag = 1;
787 		  }
788 	    }
789 	  if (cur_node->type == XML_TEXT_NODE && *open_tag == 1
790 	      && *decimal == 1)
791 	    {
792 		if (cur_node->content != NULL)
793 		  {
794 		      /* found a coord value */
795 		      double value = atof ((const char *) cur_node->content);
796 		      *coord = value;
797 		      *count += 1;
798 		  }
799 	    }
800 
801 	  find_bbox_coord (cur_node->children, name, coord, open_tag, decimal,
802 			   count);
803 	  if (open)
804 	      *open_tag = 0;
805 	  if (dec)
806 	      *decimal = 0;
807       }
808 }
809 
810 static int
parse_bounding_box(xmlNodePtr node,double * minx,double * miny,double * maxx,double * maxy)811 parse_bounding_box (xmlNodePtr node, double *minx, double *miny, double *maxx,
812 		    double *maxy)
813 {
814 /* attempting to parse an EX_GeographicBoundingBox sub-tree */
815     int ok_minx = 0;
816     int ok_miny = 0;
817     int ok_maxx = 0;
818     int ok_maxy = 0;
819     int open_tag;
820     int decimal;
821     int count;
822     double coord;
823 
824 /* retrieving minx - West */
825     open_tag = 0;
826     decimal = 0;
827     count = 0;
828     find_bbox_coord (node, "westBoundLongitude", &coord, &open_tag, &decimal,
829 		     &count);
830     if (count == 1)
831       {
832 	  *minx = coord;
833 	  ok_minx = 1;
834       }
835 
836 /* retrieving maxx - East */
837     open_tag = 0;
838     decimal = 0;
839     count = 0;
840     find_bbox_coord (node, "eastBoundLongitude", &coord, &open_tag, &decimal,
841 		     &count);
842     if (count == 1)
843       {
844 	  *maxx = coord;
845 	  ok_maxx = 1;
846       }
847 
848 /* retrieving miny - South */
849     open_tag = 0;
850     decimal = 0;
851     count = 0;
852     find_bbox_coord (node, "southBoundLatitude", &coord, &open_tag, &decimal,
853 		     &count);
854     if (count == 1)
855       {
856 	  *miny = coord;
857 	  ok_miny = 1;
858       }
859 
860 /* retrieving maxy - North */
861     open_tag = 0;
862     decimal = 0;
863     count = 0;
864     find_bbox_coord (node, "northBoundLatitude", &coord, &open_tag, &decimal,
865 		     &count);
866     if (count == 1)
867       {
868 	  *maxy = coord;
869 	  ok_maxy = 1;
870       }
871 
872     if (ok_minx && ok_miny && ok_maxx && ok_maxy)
873       {
874 	  /* ok, valid BBOX */
875 	  return 1;
876       }
877     return 0;
878 }
879 
880 static void
find_iso_geometry(xmlNodePtr node,gaiaGeomCollPtr * geom)881 find_iso_geometry (xmlNodePtr node, gaiaGeomCollPtr * geom)
882 {
883 /* recursively scanning the DOM tree [geometry] */
884     xmlNode *cur_node = NULL;
885     xmlNode *parent;
886     int ok_parent;
887 
888     for (cur_node = node; cur_node; cur_node = cur_node->next)
889       {
890 	  if (cur_node->type == XML_ELEMENT_NODE)
891 	    {
892 		if (strcmp
893 		    ((const char *) (cur_node->name),
894 		     "EX_GeographicBoundingBox") == 0)
895 		  {
896 		      ok_parent = 0;
897 		      parent = cur_node->parent;
898 		      if (parent)
899 			{
900 			    if (strcmp
901 				((const char *) (parent->name),
902 				 "geographicElement") == 0)
903 				ok_parent++;
904 			}
905 		      if (ok_parent == 1)
906 			{
907 			    parent = parent->parent;
908 			    if (strcmp
909 				((const char *) (parent->name),
910 				 "EX_Extent") == 0)
911 				ok_parent++;
912 			}
913 		      if (ok_parent == 2)
914 			{
915 			    parent = parent->parent;
916 			    if (strcmp ((const char *) (parent->name), "extent")
917 				== 0)
918 				ok_parent++;
919 			}
920 		      if (ok_parent == 3)
921 			{
922 			    parent = parent->parent;
923 			    if (strcmp
924 				((const char *) (parent->name),
925 				 "MD_DataIdentification") == 0)
926 				ok_parent++;
927 			}
928 		      if (ok_parent == 4)
929 			{
930 			    parent = parent->parent;
931 			    if (strcmp
932 				((const char *) (parent->name),
933 				 "identificationInfo") == 0)
934 				ok_parent++;
935 			}
936 		      if (ok_parent == 5)
937 			{
938 			    parent = parent->parent;
939 			    if (strcmp
940 				((const char *) (parent->name),
941 				 "MD_Metadata") == 0)
942 				ok_parent++;
943 			}
944 		      if (ok_parent == 6)
945 			{
946 			    /* only if <MD_Metadata>
947 			       /            <identificationInfo>
948 			       /              <MD_DataIdentification>
949 			       /                <extent>
950 			       /                  <EX_Extent>
951 			       /                    <geographicElement>
952 			       /                      <EX_GeographicBoundingBox>
953 			     */
954 			    double minx = 0.0;
955 			    double maxx = 0.0;
956 			    double miny = 0.0;
957 			    double maxy = 0.0;
958 			    if (parse_bounding_box
959 				(cur_node, &minx, &miny, &maxx, &maxy))
960 			      {
961 				  gaiaPolygonPtr pg;
962 				  gaiaRingPtr rng;
963 				  gaiaGeomCollPtr g = *geom;
964 				  if (g == NULL)
965 				    {
966 					g = gaiaAllocGeomColl ();
967 					g->Srid = 4326;
968 					g->DeclaredType = GAIA_MULTIPOLYGON;
969 				    }
970 				  pg = gaiaAddPolygonToGeomColl (g, 5, 0);
971 				  rng = pg->Exterior;
972 				  gaiaSetPoint (rng->Coords, 0, minx, miny);
973 				  gaiaSetPoint (rng->Coords, 1, maxx, miny);
974 				  gaiaSetPoint (rng->Coords, 2, maxx, maxy);
975 				  gaiaSetPoint (rng->Coords, 3, minx, maxy);
976 				  gaiaSetPoint (rng->Coords, 4, minx, miny);
977 				  *geom = g;
978 			      }
979 			}
980 		  }
981 	    }
982 	  find_iso_geometry (cur_node->children, geom);
983       }
984 }
985 
986 static void
retrieve_iso_identifiers(xmlDocPtr xml_doc,char ** fileIdentifier,char ** parentIdentifier,char ** title,char ** abstract,unsigned char ** geometry,short * geometry_len)987 retrieve_iso_identifiers (xmlDocPtr xml_doc, char **fileIdentifier,
988 			  char **parentIdentifier, char **title,
989 			  char **abstract, unsigned char **geometry,
990 			  short *geometry_len)
991 {
992 /*
993 / attempting to retrieve the FileIdentifier, ParentIdentifier,
994 / Title, Abstract and Geometry items from an ISO Metadata document
995 */
996     xmlNodePtr root = xmlDocGetRootElement (xml_doc);
997     int open_tag;
998     int char_string;
999     int count;
1000     char *string;
1001     gaiaGeomCollPtr geom = NULL;
1002 
1003     *fileIdentifier = NULL;
1004     *parentIdentifier = NULL;
1005     *title = NULL;
1006     *abstract = NULL;
1007     *geometry = NULL;
1008 
1009 /* attempting to retrieve the FileIdentifier item */
1010     open_tag = 0;
1011     char_string = 0;
1012     count = 0;
1013     string = NULL;
1014     find_iso_ids (root, "fileIdentifier", &string, &open_tag, &char_string,
1015 		  &count);
1016     if (string)
1017       {
1018 	  if (count == 1)
1019 	      *fileIdentifier = string;
1020 	  else
1021 	      free (string);
1022       }
1023 
1024 /* attempting to retrieve the ParentIdentifier item */
1025     open_tag = 0;
1026     char_string = 0;
1027     count = 0;
1028     string = NULL;
1029     find_iso_ids (root, "parentIdentifier", &string, &open_tag, &char_string,
1030 		  &count);
1031     if (string)
1032       {
1033 	  if (count == 1)
1034 	      *parentIdentifier = string;
1035 	  else
1036 	      free (string);
1037       }
1038 
1039 /* attempting to retrieve the Title item */
1040     open_tag = 0;
1041     char_string = 0;
1042     count = 0;
1043     string = NULL;
1044     find_iso_title (root, &string, &open_tag, &char_string, &count);
1045     if (string)
1046       {
1047 	  if (count == 1)
1048 	      *title = string;
1049 	  else
1050 	      free (string);
1051       }
1052 
1053 /* attempting to retrieve the Abstract item */
1054     open_tag = 0;
1055     char_string = 0;
1056     count = 0;
1057     string = NULL;
1058     find_iso_abstract (root, &string, &open_tag, &char_string, &count);
1059     if (string)
1060       {
1061 	  if (count == 1)
1062 	      *abstract = string;
1063 	  else
1064 	      free (string);
1065       }
1066 
1067 /* attempting to retrieve the Geometry item */
1068     open_tag = 0;
1069     char_string = 0;
1070     count = 0;
1071     string = NULL;
1072     find_iso_geometry (root, &geom);
1073     if (geom)
1074       {
1075 	  int blob_len;
1076 	  unsigned char *blob = NULL;
1077 	  gaiaMbrGeometry (geom);
1078 	  gaiaToSpatiaLiteBlobWkb (geom, &blob, &blob_len);
1079 	  gaiaFreeGeomColl (geom);
1080 	  *geometry = blob;
1081 	  *geometry_len = (short) blob_len;
1082       }
1083 }
1084 
1085 static void
find_sld_name(xmlNodePtr node,char ** string)1086 find_sld_name (xmlNodePtr node, char **string)
1087 {
1088 /* recursively scanning the DOM tree [name] */
1089     while (node)
1090       {
1091 	  if (node->type == XML_ELEMENT_NODE)
1092 	    {
1093 		const char *name = (const char *) (node->name);
1094 		if (strcmp (name, "Name") == 0)
1095 		  {
1096 		      xmlNodePtr child = node->children;
1097 		      if (child)
1098 			{
1099 			    if (child->type == XML_TEXT_NODE)
1100 			      {
1101 				  int len;
1102 				  const char *value =
1103 				      (const char *) (child->content);
1104 				  len = strlen (value);
1105 				  if (*string != NULL)
1106 				      free (*string);
1107 				  *string = malloc (len + 1);
1108 				  strcpy (*string, value);
1109 			      }
1110 			}
1111 		  }
1112 	    }
1113 	  node = node->next;
1114       }
1115 }
1116 
1117 static void
find_sld_title(xmlNodePtr node,char ** string)1118 find_sld_title (xmlNodePtr node, char **string)
1119 {
1120 /* recursively scanning the DOM tree [title] */
1121     while (node)
1122       {
1123 	  if (node->type == XML_ELEMENT_NODE)
1124 	    {
1125 		const char *name = (const char *) (node->name);
1126 		if (strcmp (name, "Title") == 0)
1127 		  {
1128 		      xmlNodePtr child = node->children;
1129 		      if (child)
1130 			{
1131 			    if (child->type == XML_TEXT_NODE)
1132 			      {
1133 				  int len;
1134 				  const char *value =
1135 				      (const char *) (child->content);
1136 				  len = strlen (value);
1137 				  if (*string != NULL)
1138 				      free (*string);
1139 				  *string = malloc (len + 1);
1140 				  strcpy (*string, value);
1141 			      }
1142 			}
1143 		  }
1144 		if (strcmp (name, "Description") == 0)
1145 		    find_sld_title (node->children, string);
1146 	    }
1147 	  node = node->next;
1148       }
1149 }
1150 
1151 static void
find_sld_abstract(xmlNodePtr node,char ** string)1152 find_sld_abstract (xmlNodePtr node, char **string)
1153 {
1154 /* recursively scanning the DOM tree [abstract] */
1155     while (node)
1156       {
1157 	  if (node->type == XML_ELEMENT_NODE)
1158 	    {
1159 		const char *name = (const char *) (node->name);
1160 		if (strcmp (name, "Abstract") == 0)
1161 		  {
1162 		      xmlNodePtr child = node->children;
1163 		      if (child)
1164 			{
1165 			    if (child->type == XML_TEXT_NODE)
1166 			      {
1167 				  int len;
1168 				  const char *value =
1169 				      (const char *) (child->content);
1170 				  len = strlen (value);
1171 				  if (*string != NULL)
1172 				      free (*string);
1173 				  *string = malloc (len + 1);
1174 				  strcpy (*string, value);
1175 			      }
1176 			}
1177 		  }
1178 		if (strcmp (name, "Description") == 0)
1179 		    find_sld_abstract (node->children, string);
1180 	    }
1181 	  node = node->next;
1182       }
1183 }
1184 
1185 static void
retrieve_sld_identifiers(xmlDocPtr xml_doc,char ** name,char ** title,char ** abstract)1186 retrieve_sld_identifiers (xmlDocPtr xml_doc, char **name, char **title,
1187 			  char **abstract)
1188 {
1189 /*
1190 / attempting to retrieve the Name, Title and Abstract items
1191 / from an SLD Style document
1192 */
1193     xmlNodePtr root = xmlDocGetRootElement (xml_doc);
1194     char *string;
1195     const char *xname = (const char *) (root->name);
1196 
1197     *name = NULL;
1198     *title = NULL;
1199     *abstract = NULL;
1200 
1201     if (xname != NULL)
1202       {
1203 	  if (strcmp (xname, "StyledLayerDescriptor") != 0)
1204 	      return;
1205       }
1206 
1207 /* attempting to retrieve the Name item */
1208     string = NULL;
1209     find_sld_name (root->children, &string);
1210     if (string)
1211 	*name = string;
1212 
1213 /* attempting to retrieve the Title item */
1214     string = NULL;
1215     find_sld_title (root->children, &string);
1216     if (string)
1217 	*title = string;
1218 
1219 /* attempting to retrieve the Abstract item */
1220     string = NULL;
1221     find_sld_abstract (root->children, &string);
1222     if (string)
1223 	*abstract = string;
1224 }
1225 
1226 static void
find_sld_se_name(xmlNodePtr node,char ** string,int * style,int * rule)1227 find_sld_se_name (xmlNodePtr node, char **string, int *style, int *rule)
1228 {
1229 /* recursively scanning the DOM tree [name] */
1230     int is_style = 0;
1231     int is_rule = 0;
1232     while (node)
1233       {
1234 	  if (node->type == XML_ELEMENT_NODE)
1235 	    {
1236 		const char *name = (const char *) (node->name);
1237 		if (strcmp (name, "FeatureTypeStyle") == 0
1238 		    || strcmp (name, "CoverageStyle") == 0)
1239 		  {
1240 		      is_style = 1;
1241 		      *style = 1;
1242 		  }
1243 		if (strcmp (name, "Rule") == 0)
1244 		  {
1245 		      is_rule = 1;
1246 		      *rule = 1;
1247 		  }
1248 		if (strcmp (name, "Name") == 0)
1249 		  {
1250 		      if (*style == 1 && *rule == 0)
1251 			{
1252 			    xmlNodePtr child = node->children;
1253 			    if (child)
1254 			      {
1255 				  if (child->type == XML_TEXT_NODE)
1256 				    {
1257 					int len;
1258 					const char *value =
1259 					    (const char *) (child->content);
1260 					len = strlen (value);
1261 					if (*string != NULL)
1262 					    free (*string);
1263 					*string = malloc (len + 1);
1264 					strcpy (*string, value);
1265 				    }
1266 			      }
1267 			}
1268 		  }
1269 	    }
1270 
1271 	  find_sld_se_name (node->children, string, style, rule);
1272 	  if (is_style)
1273 	      *style = 0;
1274 	  if (is_rule)
1275 	      *rule = 0;
1276 	  node = node->next;
1277       }
1278 }
1279 
1280 static void
find_sld_se_title(xmlNodePtr node,char ** string,int * style,int * rule)1281 find_sld_se_title (xmlNodePtr node, char **string, int *style, int *rule)
1282 {
1283 /* recursively scanning the DOM tree [title] */
1284     int is_style = 0;
1285     int is_rule = 0;
1286     while (node)
1287       {
1288 	  if (node->type == XML_ELEMENT_NODE)
1289 	    {
1290 		const char *name = (const char *) (node->name);
1291 		if (strcmp (name, "FeatureTypeStyle") == 0
1292 		    || strcmp (name, "CoverageStyle") == 0)
1293 		  {
1294 		      is_style = 1;
1295 		      *style = 1;
1296 		  }
1297 		if (strcmp (name, "Rule") == 0)
1298 		  {
1299 		      is_rule = 1;
1300 		      *rule = 1;
1301 		  }
1302 		if (strcmp (name, "Title") == 0)
1303 		  {
1304 		      if (*style == 1 && *rule == 0)
1305 			{
1306 			    xmlNodePtr child = node->children;
1307 			    if (child)
1308 			      {
1309 				  if (child->type == XML_TEXT_NODE)
1310 				    {
1311 					int len;
1312 					const char *value =
1313 					    (const char *) (child->content);
1314 					len = strlen (value);
1315 					if (*string != NULL)
1316 					    free (*string);
1317 					*string = malloc (len + 1);
1318 					strcpy (*string, value);
1319 				    }
1320 			      }
1321 			}
1322 		  }
1323 	    }
1324 
1325 	  find_sld_se_title (node->children, string, style, rule);
1326 	  if (is_style)
1327 	      *style = 0;
1328 	  if (is_rule)
1329 	      *rule = 0;
1330 	  node = node->next;
1331       }
1332 }
1333 
1334 static void
find_sld_se_abstract(xmlNodePtr node,char ** string,int * style,int * rule)1335 find_sld_se_abstract (xmlNodePtr node, char **string, int *style, int *rule)
1336 {
1337 /* recursively scanning the DOM tree [abstract] */
1338     int is_style = 0;
1339     int is_rule = 0;
1340     while (node)
1341       {
1342 	  if (node->type == XML_ELEMENT_NODE)
1343 	    {
1344 		const char *name = (const char *) (node->name);
1345 		if (strcmp (name, "FeatureTypeStyle") == 0
1346 		    || strcmp (name, "CoverageStyle") == 0)
1347 		  {
1348 		      is_style = 1;
1349 		      *style = 1;
1350 		  }
1351 		if (strcmp (name, "Rule") == 0)
1352 		  {
1353 		      is_rule = 1;
1354 		      *rule = 1;
1355 		  }
1356 		if (strcmp (name, "Abstract") == 0)
1357 		  {
1358 		      if (*style == 1 && *rule == 0)
1359 			{
1360 			    xmlNodePtr child = node->children;
1361 			    if (child)
1362 			      {
1363 				  if (child->type == XML_TEXT_NODE)
1364 				    {
1365 					int len;
1366 					const char *value =
1367 					    (const char *) (child->content);
1368 					len = strlen (value);
1369 					if (*string != NULL)
1370 					    free (*string);
1371 					*string = malloc (len + 1);
1372 					strcpy (*string, value);
1373 				    }
1374 			      }
1375 			}
1376 		  }
1377 	    }
1378 
1379 	  find_sld_se_abstract (node->children, string, style, rule);
1380 	  if (is_style)
1381 	      *style = 0;
1382 	  if (is_rule)
1383 	      *rule = 0;
1384 	  node = node->next;
1385       }
1386 }
1387 
1388 static void
retrieve_sld_se_identifiers(xmlDocPtr xml_doc,char ** name,char ** title,char ** abstract)1389 retrieve_sld_se_identifiers (xmlDocPtr xml_doc, char **name, char **title,
1390 			     char **abstract)
1391 {
1392 /*
1393 / attempting to retrieve the Name, Title and Abstract items
1394 / from an SLD/SE Style document
1395 */
1396     xmlNodePtr root = xmlDocGetRootElement (xml_doc);
1397     int style;
1398     int rule;
1399     char *string;
1400     const char *xname = (const char *) (root->name);
1401 
1402     *name = NULL;
1403     *title = NULL;
1404     *abstract = NULL;
1405 
1406 /* attempting to retrieve the Name item */
1407     style = 0;
1408     rule = 0;
1409     string = NULL;
1410     if (xname != NULL)
1411       {
1412 	  if (strcmp (xname, "PointSymbolizer") == 0
1413 	      || strcmp (xname, "LineSymbolizer") == 0
1414 	      || strcmp (xname, "PolygonSymbolizer") == 0
1415 	      || strcmp (xname, "TextSymbolizer") == 0
1416 	      || strcmp (xname, "RasterSymbolizer") == 0)
1417 	      style = 1;
1418       }
1419     find_sld_se_name (root, &string, &style, &rule);
1420     if (string)
1421 	*name = string;
1422 
1423 /* attempting to retrieve the Title item */
1424     style = 0;
1425     rule = 0;
1426     string = NULL;
1427     if (xname != NULL)
1428       {
1429 	  if (strcmp (xname, "PointSymbolizer") == 0
1430 	      || strcmp (xname, "LineSymbolizer") == 0
1431 	      || strcmp (xname, "PolygonSymbolizer") == 0
1432 	      || strcmp (xname, "TextSymbolizer") == 0
1433 	      || strcmp (xname, "RasterSymbolizer") == 0)
1434 	      style = 1;
1435       }
1436     find_sld_se_title (root, &string, &style, &rule);
1437     if (string)
1438 	*title = string;
1439 
1440 /* attempting to retrieve the Abstract item */
1441     style = 0;
1442     rule = 0;
1443     string = NULL;
1444     if (xname != NULL)
1445       {
1446 	  if (strcmp (xname, "PointSymbolizer") == 0
1447 	      || strcmp (xname, "LineSymbolizer") == 0
1448 	      || strcmp (xname, "PolygonSymbolizer") == 0
1449 	      || strcmp (xname, "TextSymbolizer") == 0
1450 	      || strcmp (xname, "RasterSymbolizer") == 0)
1451 	      style = 1;
1452       }
1453     find_sld_se_abstract (root, &string, &style, &rule);
1454     if (string)
1455 	*abstract = string;
1456 }
1457 
1458 static void
find_map_config_name(xmlNodePtr node,char ** string)1459 find_map_config_name (xmlNodePtr node, char **string)
1460 {
1461 /* recursively scanning the DOM tree [name] */
1462     while (node)
1463       {
1464 	  if (node->type == XML_ELEMENT_NODE)
1465 	    {
1466 		const char *name = (const char *) (node->name);
1467 		if (strcmp (name, "Name") == 0)
1468 		  {
1469 		      xmlNodePtr child = node->children;
1470 		      if (child)
1471 			{
1472 			    if (child->type == XML_TEXT_NODE)
1473 			      {
1474 				  int len;
1475 				  const char *value =
1476 				      (const char *) (child->content);
1477 				  len = strlen (value);
1478 				  if (*string != NULL)
1479 				      free (*string);
1480 				  *string = malloc (len + 1);
1481 				  strcpy (*string, value);
1482 			      }
1483 			}
1484 		  }
1485 	    }
1486 	  node = node->next;
1487       }
1488 }
1489 
1490 static void
find_map_config_title(xmlNodePtr node,char ** string)1491 find_map_config_title (xmlNodePtr node, char **string)
1492 {
1493 /* recursively scanning the DOM tree [title] */
1494     while (node)
1495       {
1496 	  if (node->type == XML_ELEMENT_NODE)
1497 	    {
1498 		const char *name = (const char *) (node->name);
1499 		if (strcmp (name, "Title") == 0)
1500 		  {
1501 		      xmlNodePtr child = node->children;
1502 		      if (child)
1503 			{
1504 			    if (child->type == XML_TEXT_NODE)
1505 			      {
1506 				  int len;
1507 				  const char *value =
1508 				      (const char *) (child->content);
1509 				  len = strlen (value);
1510 				  if (*string != NULL)
1511 				      free (*string);
1512 				  *string = malloc (len + 1);
1513 				  strcpy (*string, value);
1514 			      }
1515 			}
1516 		  }
1517 		if (strcmp (name, "Description") == 0)
1518 		    find_map_config_title (node->children, string);
1519 	    }
1520 	  node = node->next;
1521       }
1522 }
1523 
1524 static void
find_map_config_abstract(xmlNodePtr node,char ** string)1525 find_map_config_abstract (xmlNodePtr node, char **string)
1526 {
1527 /* recursively scanning the DOM tree [abstract] */
1528     while (node)
1529       {
1530 	  if (node->type == XML_ELEMENT_NODE)
1531 	    {
1532 		const char *name = (const char *) (node->name);
1533 		if (strcmp (name, "Abstract") == 0)
1534 		  {
1535 		      xmlNodePtr child = node->children;
1536 		      if (child)
1537 			{
1538 			    if (child->type == XML_TEXT_NODE)
1539 			      {
1540 				  int len;
1541 				  const char *value =
1542 				      (const char *) (child->content);
1543 				  len = strlen (value);
1544 				  if (*string != NULL)
1545 				      free (*string);
1546 				  *string = malloc (len + 1);
1547 				  strcpy (*string, value);
1548 			      }
1549 			}
1550 		  }
1551 		if (strcmp (name, "Description") == 0)
1552 		    find_map_config_abstract (node->children, string);
1553 	    }
1554 	  node = node->next;
1555       }
1556 }
1557 
1558 static void
retrieve_map_config_identifiers(xmlDocPtr xml_doc,char ** name,char ** title,char ** abstract)1559 retrieve_map_config_identifiers (xmlDocPtr xml_doc, char **name, char **title,
1560 				 char **abstract)
1561 {
1562 /*
1563 / attempting to retrieve the Name, Title and Abstract items
1564 / from a Map Config document
1565 */
1566     xmlNodePtr root = xmlDocGetRootElement (xml_doc);
1567     char *string;
1568     const char *xname = (const char *) (root->name);
1569 
1570     *name = NULL;
1571     *title = NULL;
1572     *abstract = NULL;
1573 
1574     if (xname != NULL)
1575       {
1576 	  if (strcmp (xname, "RL2MapConfig") != 0)
1577 	      return;
1578       }
1579 
1580 /* attempting to retrieve the Name item */
1581     string = NULL;
1582     find_map_config_name (root->children, &string);
1583     if (string)
1584 	*name = string;
1585 
1586 /* attempting to retrieve the Title item */
1587     string = NULL;
1588     find_map_config_title (root->children, &string);
1589     if (string)
1590 	*title = string;
1591 
1592 /* attempting to retrieve the Abstract item */
1593     string = NULL;
1594     find_map_config_abstract (root->children, &string);
1595     if (string)
1596 	*abstract = string;
1597 }
1598 
1599 GAIAGEO_DECLARE void
gaiaXmlToBlob(const void * p_cache,const unsigned char * xml,int xml_len,int compressed,const char * schemaURI,unsigned char ** result,int * size,char ** parsing_errors,char ** schema_validation_errors)1600 gaiaXmlToBlob (const void *p_cache, const unsigned char *xml, int xml_len,
1601 	       int compressed, const char *schemaURI, unsigned char **result,
1602 	       int *size, char **parsing_errors,
1603 	       char **schema_validation_errors)
1604 {
1605 /* attempting to build an XmlBLOB buffer */
1606     xmlDocPtr xml_doc;
1607     xmlDocPtr schema_doc;
1608     xmlSchemaPtr schema = NULL;
1609     xmlSchemaParserCtxtPtr parser_ctxt;
1610     xmlSchemaValidCtxtPtr valid_ctxt;
1611     int is_iso_metadata = 0;
1612     int is_sld_se_vector_style = 0;
1613     int is_sld_se_raster_style = 0;
1614     int is_sld_style = 0;
1615     int is_svg = 0;
1616     int is_gpx = 0;
1617     int is_map_config = 0;
1618     int len;
1619     int zip_len;
1620     short uri_len = 0;
1621     short fileid_len = 0;
1622     short parentid_len = 0;
1623     short name_len = 0;
1624     short title_len = 0;
1625     short abstract_len = 0;
1626     short geometry_len = 0;
1627     char *fileIdentifier = NULL;
1628     char *parentIdentifier = NULL;
1629     char *name = NULL;
1630     char *title = NULL;
1631     char *abstract = NULL;
1632     unsigned char *geometry = NULL;
1633     uLong crc;
1634     Bytef *zip_buf = NULL;
1635     unsigned char *buf;
1636     unsigned char *ptr;
1637     unsigned char flags = 0x00;
1638     int endian_arch = gaiaEndianArch ();
1639     struct splite_internal_cache *cache =
1640 	(struct splite_internal_cache *) p_cache;
1641     gaiaOutBufferPtr parsingBuf = NULL;
1642     gaiaOutBufferPtr schemaValidationBuf = NULL;
1643     xmlGenericErrorFunc silentError = NULL;
1644     xmlGenericErrorFunc parsingError = NULL;
1645     xmlGenericErrorFunc schemaError = NULL;
1646     if (is_valid_cache (cache))
1647       {
1648 	  parsingBuf = (gaiaOutBufferPtr) (cache->xmlParsingErrors);
1649 	  schemaValidationBuf =
1650 	      (gaiaOutBufferPtr) (cache->xmlSchemaValidationErrors);
1651 	  parsingError = (xmlGenericErrorFunc) spliteParsingError;
1652 	  schemaError = (xmlGenericErrorFunc) spliteSchemaValidationError;
1653 	  spliteResetXmlErrors (cache);
1654       }
1655 
1656     *result = NULL;
1657     *size = 0;
1658     if (parsing_errors)
1659 	*parsing_errors = NULL;
1660     if (schema_validation_errors)
1661 	*schema_validation_errors = NULL;
1662     if (xml == NULL)
1663 	return;
1664 
1665     xmlSetGenericErrorFunc (NULL, silentError);
1666 
1667     if (schemaURI != NULL)
1668       {
1669 	  if (splite_xmlSchemaCacheFind
1670 	      (cache, schemaURI, &schema_doc, &parser_ctxt, &schema))
1671 	      ;
1672 	  else
1673 	    {
1674 		/* preparing the Schema */
1675 		xmlSetGenericErrorFunc (cache, schemaError);
1676 		schema_doc = xmlReadFile ((const char *) schemaURI, NULL, 0);
1677 		if (schema_doc == NULL)
1678 		  {
1679 		      spatialite_e ("unable to load the Schema\n");
1680 		      if (schema_validation_errors)
1681 			  *schema_validation_errors =
1682 			      schemaValidationBuf->Buffer;
1683 		      xmlSetGenericErrorFunc ((void *) stderr, NULL);
1684 		      return;
1685 		  }
1686 		parser_ctxt = xmlSchemaNewDocParserCtxt (schema_doc);
1687 		if (parser_ctxt == NULL)
1688 		  {
1689 		      spatialite_e ("unable to prepare the Schema Context\n");
1690 		      xmlFreeDoc (schema_doc);
1691 		      if (schema_validation_errors)
1692 			  *schema_validation_errors =
1693 			      schemaValidationBuf->Buffer;
1694 		      xmlSetGenericErrorFunc ((void *) stderr, NULL);
1695 		      return;
1696 		  }
1697 		schema = xmlSchemaParse (parser_ctxt);
1698 		if (schema == NULL)
1699 		  {
1700 		      spatialite_e ("invalid Schema\n");
1701 		      xmlFreeDoc (schema_doc);
1702 		      if (schema_validation_errors)
1703 			  *schema_validation_errors =
1704 			      schemaValidationBuf->Buffer;
1705 		      xmlSetGenericErrorFunc ((void *) stderr, NULL);
1706 		      return;
1707 		  }
1708 		splite_xmlSchemaCacheInsert (cache, schemaURI, schema_doc,
1709 					     parser_ctxt, schema);
1710 	    }
1711       }
1712 
1713 /* testing if the XMLDocument is well-formed */
1714     xmlSetGenericErrorFunc (cache, parsingError);
1715     xml_doc =
1716 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
1717     if (xml_doc == NULL)
1718       {
1719 	  /* parsing error; not a well-formed XML */
1720 	  spatialite_e ("XML parsing error\n");
1721 	  if (parsing_errors && parsingBuf)
1722 	      *parsing_errors = parsingBuf->Buffer;
1723 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
1724 	  return;
1725       }
1726     if (parsing_errors && parsingBuf)
1727 	*parsing_errors = parsingBuf->Buffer;
1728 
1729     if (schemaURI != NULL)
1730       {
1731 	  /* Schema validation */
1732 	  xmlSetGenericErrorFunc (cache, schemaError);
1733 	  valid_ctxt = xmlSchemaNewValidCtxt (schema);
1734 	  if (valid_ctxt == NULL)
1735 	    {
1736 		spatialite_e ("unable to prepare a validation context\n");
1737 		xmlFreeDoc (xml_doc);
1738 		if (schema_validation_errors && schemaValidationBuf)
1739 		    *schema_validation_errors = schemaValidationBuf->Buffer;
1740 		xmlSetGenericErrorFunc ((void *) stderr, NULL);
1741 		return;
1742 	    }
1743 	  if (xmlSchemaValidateDoc (valid_ctxt, xml_doc) != 0)
1744 	    {
1745 		spatialite_e ("Schema validation failed\n");
1746 		xmlSchemaFreeValidCtxt (valid_ctxt);
1747 		xmlFreeDoc (xml_doc);
1748 		if (schema_validation_errors && schemaValidationBuf)
1749 		    *schema_validation_errors = schemaValidationBuf->Buffer;
1750 		xmlSetGenericErrorFunc ((void *) stderr, NULL);
1751 		return;
1752 	    }
1753 	  xmlSchemaFreeValidCtxt (valid_ctxt);
1754       }
1755 
1756 /* testing for special cases: ISO Metadata, SLD/SE Styles and SVG */
1757     sniff_payload (xml_doc, &is_iso_metadata, &is_sld_se_vector_style,
1758 		   &is_sld_se_raster_style, &is_sld_style, &is_svg, &is_gpx,
1759 		   &is_map_config);
1760     if (is_iso_metadata)
1761 	retrieve_iso_identifiers (xml_doc, &fileIdentifier,
1762 				  &parentIdentifier, &title, &abstract,
1763 				  &geometry, &geometry_len);
1764     if (is_sld_style)
1765 	retrieve_sld_identifiers (xml_doc, &name, &title, &abstract);
1766     else if (is_sld_se_vector_style || is_sld_se_raster_style)
1767 	retrieve_sld_se_identifiers (xml_doc, &name, &title, &abstract);
1768     else if (is_map_config)
1769 	retrieve_map_config_identifiers (xml_doc, &name, &title, &abstract);
1770     xmlFreeDoc (xml_doc);
1771 
1772     if (compressed)
1773       {
1774 	  /* compressing the XML payload */
1775 	  uLong zLen = compressBound (xml_len);
1776 	  zip_buf = malloc (zLen);
1777 	  if (compress (zip_buf, &zLen, (const Bytef *) xml, (uLong) xml_len) !=
1778 	      Z_OK)
1779 	    {
1780 		/* compression error */
1781 		spatialite_e ("XmlBLOB DEFLATE compress error\n");
1782 		free (zip_buf);
1783 		xmlSetGenericErrorFunc ((void *) stderr, NULL);
1784 		return;
1785 	    }
1786 	  zip_len = (int) zLen;
1787       }
1788     else
1789 	zip_len = xml_len;
1790 
1791 /* reporting errors */
1792     if (parsing_errors && parsingBuf)
1793 	*parsing_errors = parsingBuf->Buffer;
1794     if (schema_validation_errors && schemaValidationBuf)
1795 	*schema_validation_errors = schemaValidationBuf->Buffer;
1796 
1797 /* computing the XmlBLOB size */
1798     len = 39;			/* fixed header-footer size */
1799     if (schemaURI)
1800 	uri_len = (short) strlen ((const char *) schemaURI);
1801     if (fileIdentifier)
1802 	fileid_len = (short) strlen ((const char *) fileIdentifier);
1803     if (parentIdentifier)
1804 	parentid_len = strlen ((const char *) parentIdentifier);
1805     if (name)
1806 	name_len = (short) strlen ((const char *) name);
1807     if (title)
1808 	title_len = (short) strlen ((const char *) title);
1809     if (abstract)
1810 	abstract_len = (short) strlen ((const char *) abstract);
1811     len += zip_len;
1812     len += uri_len;
1813     len += fileid_len;
1814     len += parentid_len;
1815     len += name_len;
1816     len += title_len;
1817     len += abstract_len;
1818     len += geometry_len;
1819     buf = malloc (len);
1820     *buf = GAIA_XML_START;	/* START signature */
1821     flags |= GAIA_XML_LITTLE_ENDIAN;
1822     if (compressed)
1823 	flags |= GAIA_XML_COMPRESSED;
1824     if (schemaURI != NULL)
1825 	flags |= GAIA_XML_VALIDATED;
1826     if (is_iso_metadata)
1827 	flags |= GAIA_XML_ISO_METADATA;
1828     if (is_sld_se_vector_style)
1829 	flags |= GAIA_XML_SLD_SE_VECTOR_STYLE;
1830     if (is_sld_se_raster_style)
1831 	flags |= GAIA_XML_SLD_SE_RASTER_STYLE;
1832     if (is_sld_style)
1833 	flags |= GAIA_XML_SLD_STYLE;
1834     if (is_svg)
1835 	flags |= GAIA_XML_SVG;
1836     if (is_gpx)
1837 	flags |= GAIA_XML_GPX;
1838     if (is_map_config)
1839 	flags |= GAIA_XML_MAP_CONFIG;
1840     *(buf + 1) = flags;		/* XmlBLOB flags */
1841     *(buf + 2) = GAIA_XML_HEADER;	/* HEADER signature */
1842     gaiaExport32 (buf + 3, xml_len, 1, endian_arch);	/* the uncompressed XMLDocument size */
1843     gaiaExport32 (buf + 7, zip_len, 1, endian_arch);	/* the compressed XMLDocument size */
1844     gaiaExport16 (buf + 11, uri_len, 1, endian_arch);	/* the SchemaURI length in bytes */
1845     *(buf + 13) = GAIA_XML_SCHEMA;	/* SCHEMA signature */
1846     ptr = buf + 14;
1847     if (schemaURI)
1848       {
1849 	  /* the SchemaURI */
1850 	  memcpy (ptr, schemaURI, uri_len);
1851 	  ptr += uri_len;
1852       }
1853     gaiaExport16 (ptr, fileid_len, 1, endian_arch);	/* the FileIdentifier length in bytes */
1854     ptr += 2;
1855     *ptr = GAIA_XML_FILEID;	/* FileIdentifier signature */
1856     ptr++;
1857     if (fileIdentifier)
1858       {
1859 	  /* the FileIdentifier */
1860 	  memcpy (ptr, fileIdentifier, fileid_len);
1861 	  free (fileIdentifier);
1862 	  ptr += fileid_len;
1863       }
1864     gaiaExport16 (ptr, parentid_len, 1, endian_arch);	/* the ParentIdentifier length in bytes */
1865     ptr += 2;
1866     *ptr = GAIA_XML_PARENTID;	/* ParentIdentifier signature */
1867     ptr++;
1868     if (parentIdentifier)
1869       {
1870 	  /* the ParentIdentifier */
1871 	  memcpy (ptr, parentIdentifier, parentid_len);
1872 	  free (parentIdentifier);
1873 	  ptr += parentid_len;
1874       }
1875     gaiaExport16 (ptr, name_len, 1, endian_arch);	/* the Name length in bytes */
1876     ptr += 2;
1877     *ptr = GAIA_XML_NAME;	/* Title signature */
1878     ptr++;
1879     if (name)
1880       {
1881 	  /* the Name */
1882 	  memcpy (ptr, name, name_len);
1883 	  free (name);
1884 	  ptr += name_len;
1885       }
1886     gaiaExport16 (ptr, title_len, 1, endian_arch);	/* the Title length in bytes */
1887     ptr += 2;
1888     *ptr = GAIA_XML_TITLE;	/* Title signature */
1889     ptr++;
1890     if (title)
1891       {
1892 	  /* the Title */
1893 	  memcpy (ptr, title, title_len);
1894 	  free (title);
1895 	  ptr += title_len;
1896       }
1897     gaiaExport16 (ptr, abstract_len, 1, endian_arch);	/* the Abstract length in bytes */
1898     ptr += 2;
1899     *ptr = GAIA_XML_ABSTRACT;	/* Abstract signature */
1900     ptr++;
1901     if (abstract)
1902       {
1903 	  /* the Abstract */
1904 	  memcpy (ptr, abstract, abstract_len);
1905 	  free (abstract);
1906 	  ptr += abstract_len;
1907       }
1908     gaiaExport16 (ptr, geometry_len, 1, endian_arch);	/* the Geometry length in bytes */
1909     ptr += 2;
1910     *ptr = GAIA_XML_GEOMETRY;	/* Geometry signature */
1911     ptr++;
1912     if (geometry)
1913       {
1914 	  /* the Geometry */
1915 	  memcpy (ptr, geometry, geometry_len);
1916 	  free (geometry);
1917 	  ptr += geometry_len;
1918       }
1919     *ptr = GAIA_XML_PAYLOAD;	/* PAYLOAD signature */
1920     ptr++;
1921     if (compressed)
1922       {
1923 	  /* the compressed XML payload */
1924 	  memcpy (ptr, zip_buf, zip_len);
1925 	  free (zip_buf);
1926 	  ptr += zip_len;
1927       }
1928     else
1929       {
1930 	  /* the uncompressed XML payload */
1931 	  memcpy (ptr, xml, xml_len);
1932 	  ptr += xml_len;
1933       }
1934     *ptr = GAIA_XML_CRC32;	/* CRC32 signature */
1935     ptr++;
1936 /* computing the CRC32 */
1937     crc = crc32 (0L, buf, ptr - buf);
1938     gaiaExportU32 (ptr, crc, 1, endian_arch);	/* the CRC32 */
1939     ptr += 4;
1940     *ptr = GAIA_XML_END;	/* END signature */
1941 
1942     *result = buf;
1943     *size = len;
1944     xmlSetGenericErrorFunc ((void *) stderr, NULL);
1945 }
1946 
1947 GAIAGEO_DECLARE void
gaiaXmlBlobCompression(const unsigned char * blob,int in_size,int compressed,unsigned char ** result,int * out_size)1948 gaiaXmlBlobCompression (const unsigned char *blob,
1949 			int in_size, int compressed,
1950 			unsigned char **result, int *out_size)
1951 {
1952 /* Return another XmlBLOB buffer compressed / uncompressed */
1953     int in_compressed = 0;
1954     int little_endian = 0;
1955     unsigned char flag;
1956     int in_xml_len;
1957     int in_zip_len = 0;
1958     short uri_len;
1959     short fileid_len;
1960     short parentid_len;
1961     short name_len;
1962     short title_len;
1963     short abstract_len;
1964     short geometry_len;
1965     int out_xml_len;
1966     int out_zip_len;
1967     uLong crc;
1968     Bytef *zip_buf = NULL;
1969     int len;
1970     char *schemaURI;
1971     char *fileIdentifier;
1972     char *parentIdentifier;
1973     char *name;
1974     char *title;
1975     char *abstract;
1976     unsigned char *geometry;
1977     int is_iso_metadata = 0;
1978     int is_sld_se_vector_style = 0;
1979     int is_sld_se_raster_style = 0;
1980     int is_sld_style = 0;
1981     int is_svg = 0;
1982     int is_gpx = 0;
1983     unsigned char *xml = NULL;
1984     unsigned char *buf;
1985     unsigned char *ptr;
1986     unsigned char flags;
1987     int legacy_blob = 0;
1988     int endian_arch = gaiaEndianArch ();
1989 
1990     *result = NULL;
1991     *out_size = 0;
1992 /* validity check */
1993     if (!gaiaIsValidXmlBlob (blob, in_size))
1994 	return;			/* cannot be an XmlBLOB */
1995     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
1996 	legacy_blob = 1;
1997     flag = *(blob + 1);
1998     flag = *(blob + 1);
1999     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
2000 	little_endian = 1;
2001     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
2002 	in_compressed = 1;
2003     if ((flag & GAIA_XML_ISO_METADATA) == GAIA_XML_ISO_METADATA)
2004 	is_iso_metadata = 1;
2005     if ((flag & GAIA_XML_SLD_SE_VECTOR_STYLE) == GAIA_XML_SLD_SE_VECTOR_STYLE)
2006 	is_sld_se_vector_style = 1;
2007     if ((flag & GAIA_XML_SLD_SE_RASTER_STYLE) == GAIA_XML_SLD_SE_RASTER_STYLE)
2008 	is_sld_se_raster_style = 1;
2009     if ((flag & GAIA_XML_SLD_STYLE) == GAIA_XML_SLD_STYLE)
2010 	is_sld_style = 1;
2011     if ((flag & GAIA_XML_SVG) == GAIA_XML_SVG)
2012 	is_svg = 1;
2013     if ((flag & GAIA_XML_GPX) == GAIA_XML_GPX)
2014 	is_gpx = 1;
2015     in_xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
2016     in_zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
2017     uri_len = gaiaImport16 (blob + 11, little_endian, endian_arch);
2018     ptr = (unsigned char *) blob + 14;
2019     if (uri_len)
2020       {
2021 	  schemaURI = (char *) ptr;
2022 	  ptr += uri_len;
2023       }
2024     else
2025       {
2026 	  schemaURI = NULL;
2027       }
2028     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2029     ptr += 3;
2030     if (fileid_len)
2031       {
2032 	  fileIdentifier = (char *) ptr;
2033 	  ptr += fileid_len;
2034       }
2035     else
2036       {
2037 	  fileIdentifier = NULL;
2038       }
2039     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2040     ptr += 3;
2041     if (parentid_len)
2042       {
2043 	  parentIdentifier = (char *) ptr;
2044 	  ptr += parentid_len;
2045       }
2046     else
2047       {
2048 	  parentIdentifier = NULL;
2049       }
2050     if (!legacy_blob)
2051       {
2052 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
2053 	  ptr += 3;
2054 	  if (name_len)
2055 	    {
2056 		name = (char *) ptr;
2057 		ptr += name_len;
2058 	    }
2059 	  else
2060 	    {
2061 		name = NULL;
2062 	    }
2063       }
2064     else
2065       {
2066 	  name_len = 0;
2067 	  name = NULL;
2068       }
2069     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
2070     ptr += 3;
2071     if (title_len)
2072       {
2073 	  title = (char *) ptr;
2074 	  ptr += title_len;
2075       }
2076     else
2077       {
2078 	  title = NULL;
2079       }
2080     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
2081     ptr += 3;
2082     if (abstract_len)
2083       {
2084 	  abstract = (char *) ptr;
2085 	  ptr += abstract_len;
2086       }
2087     else
2088       {
2089 	  abstract = NULL;
2090       }
2091     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
2092     ptr += 3;
2093     if (geometry_len)
2094       {
2095 	  geometry = (unsigned char *) ptr;
2096 	  ptr += geometry_len;
2097       }
2098     else
2099       {
2100 	  geometry = NULL;
2101       }
2102     ptr++;
2103 
2104     if (in_compressed == compressed)
2105       {
2106 	  /* unchanged compression */
2107 	  out_xml_len = in_xml_len;
2108 	  out_zip_len = in_zip_len;
2109 	  zip_buf = (unsigned char *) ptr;
2110       }
2111     else if (compressed)
2112       {
2113 	  /* compressing the XML payload */
2114 	  uLong zLen;
2115 	  out_xml_len = in_xml_len;
2116 	  zLen = compressBound (out_xml_len);
2117 	  xml = (unsigned char *) ptr;
2118 	  zip_buf = malloc (zLen);
2119 	  if (compress
2120 	      (zip_buf, &zLen, (const Bytef *) xml,
2121 	       (uLong) out_xml_len) != Z_OK)
2122 	    {
2123 		/* compression error */
2124 		spatialite_e ("XmlBLOB DEFLATE compress error\n");
2125 		free (zip_buf);
2126 		return;
2127 	    }
2128 	  out_zip_len = (int) zLen;
2129       }
2130     else
2131       {
2132 	  /* unzipping the XML payload */
2133 	  uLong refLen = in_xml_len;
2134 	  const Bytef *in = ptr;
2135 	  xml = malloc (in_xml_len + 1);
2136 	  if (uncompress (xml, &refLen, in, in_zip_len) != Z_OK)
2137 	    {
2138 		/* uncompress error */
2139 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
2140 		free (xml);
2141 		return;
2142 	    }
2143 	  *(xml + in_xml_len) = '\0';
2144 	  out_xml_len = in_xml_len;
2145 	  out_zip_len = out_xml_len;
2146       }
2147 
2148 /* computing the XmlBLOB size */
2149     len = 39;			/* fixed header-footer size */
2150     len += out_zip_len;
2151     len += uri_len;
2152     len += fileid_len;
2153     len += parentid_len;
2154     len += name_len;
2155     len += title_len;
2156     len += abstract_len;
2157     len += geometry_len;
2158     buf = malloc (len);
2159     *buf = GAIA_XML_START;	/* START signature */
2160     flags = 0x00;
2161     flags |= GAIA_XML_LITTLE_ENDIAN;
2162     if (compressed)
2163 	flags |= GAIA_XML_COMPRESSED;
2164     if (schemaURI != NULL)
2165 	flags |= GAIA_XML_VALIDATED;
2166     if (is_iso_metadata)
2167 	flags |= GAIA_XML_ISO_METADATA;
2168     if (is_sld_se_vector_style)
2169 	flags |= GAIA_XML_SLD_SE_VECTOR_STYLE;
2170     if (is_sld_se_raster_style)
2171 	flags |= GAIA_XML_SLD_SE_RASTER_STYLE;
2172     if (is_sld_style)
2173 	flags |= GAIA_XML_SLD_STYLE;
2174     if (is_svg)
2175 	flags |= GAIA_XML_SVG;
2176     if (is_gpx)
2177 	flags |= GAIA_XML_GPX;
2178     *(buf + 1) = flags;		/* XmlBLOB flags */
2179     *(buf + 2) = GAIA_XML_HEADER;	/* HEADER signature */
2180     gaiaExport32 (buf + 3, out_xml_len, 1, endian_arch);	/* the uncompressed XMLDocument size */
2181     gaiaExport32 (buf + 7, out_zip_len, 1, endian_arch);	/* the compressed XMLDocument size */
2182     gaiaExport16 (buf + 11, uri_len, 1, endian_arch);	/* the SchemaURI length in bytes */
2183     *(buf + 13) = GAIA_XML_SCHEMA;	/* SCHEMA signature */
2184     ptr = buf + 14;
2185     if (schemaURI)
2186       {
2187 	  /* the SchemaURI */
2188 	  memcpy (ptr, schemaURI, uri_len);
2189 	  ptr += uri_len;
2190       }
2191     gaiaExport16 (ptr, fileid_len, 1, endian_arch);	/* the FileIdentifier length in bytes */
2192     ptr += 2;
2193     *ptr = GAIA_XML_FILEID;	/* FileIdentifier signature */
2194     ptr++;
2195     if (fileIdentifier)
2196       {
2197 	  /* the FileIdentifier */
2198 	  memcpy (ptr, fileIdentifier, fileid_len);
2199 	  ptr += fileid_len;
2200       }
2201     gaiaExport16 (ptr, parentid_len, 1, endian_arch);	/* the ParentIdentifier length in bytes */
2202     ptr += 2;
2203     *ptr = GAIA_XML_PARENTID;	/* ParentIdentifier signature */
2204     ptr++;
2205     if (parentIdentifier)
2206       {
2207 	  /* the ParentIdentifier */
2208 	  memcpy (ptr, parentIdentifier, parentid_len);
2209 	  ptr += parentid_len;
2210       }
2211     gaiaExport16 (ptr, name_len, 1, endian_arch);	/* the Name length in bytes */
2212     ptr += 2;
2213     *ptr = GAIA_XML_NAME;	/* Name signature */
2214     ptr++;
2215     if (name)
2216       {
2217 	  /* the Name */
2218 	  memcpy (ptr, name, name_len);
2219 	  ptr += name_len;
2220       }
2221     gaiaExport16 (ptr, title_len, 1, endian_arch);	/* the Title length in bytes */
2222     ptr += 2;
2223     *ptr = GAIA_XML_TITLE;	/* Title signature */
2224     ptr++;
2225     if (title)
2226       {
2227 	  /* the Title */
2228 	  memcpy (ptr, title, title_len);
2229 	  ptr += title_len;
2230       }
2231     gaiaExport16 (ptr, abstract_len, 1, endian_arch);	/* the Abstract length in bytes */
2232     ptr += 2;
2233     *ptr = GAIA_XML_ABSTRACT;	/* Abstract signature */
2234     ptr++;
2235     if (abstract)
2236       {
2237 	  /* the Abstract */
2238 	  memcpy (ptr, abstract, abstract_len);
2239 	  ptr += abstract_len;
2240       }
2241     gaiaExport16 (ptr, geometry_len, 1, endian_arch);	/* the Geometry length in bytes */
2242     ptr += 2;
2243     *ptr = GAIA_XML_GEOMETRY;	/* Geometry signature */
2244     ptr++;
2245     if (geometry)
2246       {
2247 	  /* the Geometry */
2248 	  memcpy (ptr, geometry, geometry_len);
2249 	  ptr += geometry_len;
2250       }
2251 
2252     *ptr = GAIA_XML_PAYLOAD;	/* PAYLOAD signature */
2253     ptr++;
2254     if (in_compressed == compressed)
2255       {
2256 	  /* the unchanged XML payload */
2257 	  memcpy (ptr, zip_buf, out_zip_len);
2258 	  ptr += out_zip_len;
2259       }
2260     else if (compressed)
2261       {
2262 	  /* the compressed XML payload */
2263 	  memcpy (ptr, zip_buf, out_zip_len);
2264 	  free (zip_buf);
2265 	  ptr += out_zip_len;
2266       }
2267     else
2268       {
2269 	  /* the uncompressed XML payload */
2270 	  memcpy (ptr, xml, out_xml_len);
2271 	  free (xml);
2272 	  ptr += out_xml_len;
2273       }
2274     *ptr = GAIA_XML_CRC32;	/* CRC32 signature */
2275     ptr++;
2276 /* computing the CRC32 */
2277     crc = crc32 (0L, buf, ptr - buf);
2278     gaiaExportU32 (ptr, crc, 1, endian_arch);	/* the CRC32 */
2279     ptr += 4;
2280     *ptr = GAIA_XML_END;	/* END signature */
2281 
2282     *result = buf;
2283     *out_size = len;
2284 }
2285 
2286 static int
is_valid_legacy_xml_blob(const unsigned char * blob,int blob_size)2287 is_valid_legacy_xml_blob (const unsigned char *blob, int blob_size)
2288 {
2289 /* Checks if a BLOB actually is a valid LEGACY XmlBLOB buffer */
2290     int little_endian = 0;
2291     unsigned char flag;
2292     const unsigned char *ptr;
2293     short uri_len;
2294     short fileid_len;
2295     short parentid_len;
2296     short title_len;
2297     short abstract_len;
2298     short geometry_len;
2299     uLong crc;
2300     uLong refCrc;
2301     int endian_arch = gaiaEndianArch ();
2302 
2303 /* validity check */
2304     if (blob_size < 36)
2305 	return 0;		/* cannot be an XmlBLOB */
2306     if (*blob != GAIA_XML_START)
2307 	return 0;		/* failed to recognize START signature */
2308     if (*(blob + (blob_size - 1)) != GAIA_XML_END)
2309 	return 0;		/* failed to recognize END signature */
2310     if (*(blob + (blob_size - 6)) != GAIA_XML_CRC32)
2311 	return 0;		/* failed to recognize CRC32 signature */
2312     if (*(blob + 2) != GAIA_XML_LEGACY_HEADER)
2313 	return 0;		/* failed to recognize HEADER signature */
2314     if (*(blob + 13) != GAIA_XML_SCHEMA)
2315 	return 0;		/* failed to recognize SCHEMA signature */
2316     flag = *(blob + 1);
2317     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
2318 	little_endian = 1;
2319     ptr = blob + 11;
2320     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
2321     ptr += 2;
2322     if (*ptr != GAIA_XML_SCHEMA)
2323 	return 0;
2324     ptr++;
2325     ptr += uri_len;
2326     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2327     ptr += 2;
2328     if (*ptr != GAIA_XML_FILEID)
2329 	return 0;
2330     ptr++;
2331     ptr += fileid_len;
2332     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2333     ptr += 2;
2334     if (*ptr != GAIA_XML_PARENTID)
2335 	return 0;
2336     ptr++;
2337     ptr += parentid_len;
2338     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
2339     ptr += 2;
2340     if (*ptr != GAIA_XML_TITLE)
2341 	return 0;
2342     ptr++;
2343     ptr += title_len;
2344     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
2345     ptr += 2;
2346     if (*ptr != GAIA_XML_ABSTRACT)
2347 	return 0;
2348     ptr++;
2349     ptr += abstract_len;
2350     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
2351     ptr += 2;
2352     if (*ptr != GAIA_XML_GEOMETRY)
2353 	return 0;
2354     ptr++;
2355     ptr += geometry_len;
2356     if (*ptr != GAIA_XML_PAYLOAD)
2357 	return 0;
2358 
2359 /* verifying the CRC32 */
2360     crc = crc32 (0L, blob, blob_size - 5);
2361     refCrc = gaiaImportU32 (blob + blob_size - 5, little_endian, endian_arch);
2362     if (crc != refCrc)
2363 	return 0;
2364 
2365     return 1;
2366 }
2367 
2368 GAIAGEO_DECLARE int
gaiaIsValidXmlBlob(const unsigned char * blob,int blob_size)2369 gaiaIsValidXmlBlob (const unsigned char *blob, int blob_size)
2370 {
2371 /* Checks if a BLOB actually is a valid XmlBLOB buffer */
2372     int little_endian = 0;
2373     unsigned char flag;
2374     const unsigned char *ptr;
2375     short uri_len;
2376     short fileid_len;
2377     short parentid_len;
2378     short name_len;
2379     short title_len;
2380     short abstract_len;
2381     short geometry_len;
2382     uLong crc;
2383     uLong refCrc;
2384     int endian_arch = gaiaEndianArch ();
2385 
2386     if (blob_size > 3)
2387       {
2388 	  /* legacy format */
2389 	  if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
2390 	      return is_valid_legacy_xml_blob (blob, blob_size);
2391       }
2392 
2393 /* validity check */
2394     if (blob_size < 39)
2395 	return 0;		/* cannot be an XmlBLOB */
2396     if (*blob != GAIA_XML_START)
2397 	return 0;		/* failed to recognize START signature */
2398     if (*(blob + (blob_size - 1)) != GAIA_XML_END)
2399 	return 0;		/* failed to recognize END signature */
2400     if (*(blob + (blob_size - 6)) != GAIA_XML_CRC32)
2401 	return 0;		/* failed to recognize CRC32 signature */
2402     if (*(blob + 2) != GAIA_XML_HEADER)
2403 	return 0;		/* failed to recognize HEADER signature */
2404     if (*(blob + 13) != GAIA_XML_SCHEMA)
2405 	return 0;		/* failed to recognize SCHEMA signature */
2406     flag = *(blob + 1);
2407     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
2408 	little_endian = 1;
2409     ptr = blob + 11;
2410     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
2411     ptr += 2;
2412     if (*ptr != GAIA_XML_SCHEMA)
2413 	return 0;
2414     ptr++;
2415     ptr += uri_len;
2416     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2417     ptr += 2;
2418     if (*ptr != GAIA_XML_FILEID)
2419 	return 0;
2420     ptr++;
2421     ptr += fileid_len;
2422     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2423     ptr += 2;
2424     if (*ptr != GAIA_XML_PARENTID)
2425 	return 0;
2426     ptr++;
2427     ptr += parentid_len;
2428     name_len = gaiaImport16 (ptr, little_endian, endian_arch);
2429     ptr += 2;
2430     if (*ptr != GAIA_XML_NAME)
2431 	return 0;
2432     ptr++;
2433     ptr += name_len;
2434     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
2435     ptr += 2;
2436     if (*ptr != GAIA_XML_TITLE)
2437 	return 0;
2438     ptr++;
2439     ptr += title_len;
2440     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
2441     ptr += 2;
2442     if (*ptr != GAIA_XML_ABSTRACT)
2443 	return 0;
2444     ptr++;
2445     ptr += abstract_len;
2446     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
2447     ptr += 2;
2448     if (*ptr != GAIA_XML_GEOMETRY)
2449 	return 0;
2450     ptr++;
2451     ptr += geometry_len;
2452     if (*ptr != GAIA_XML_PAYLOAD)
2453 	return 0;
2454 
2455 /* verifying the CRC32 */
2456     crc = crc32 (0L, blob, blob_size - 5);
2457     refCrc = gaiaImportU32 (blob + blob_size - 5, little_endian, endian_arch);
2458     if (crc != refCrc)
2459 	return 0;
2460 
2461     return 1;
2462 }
2463 
2464 static void
find_xml_namespaces(xmlNode * node,struct gaiaxml_ns_list * list)2465 find_xml_namespaces (xmlNode * node, struct gaiaxml_ns_list *list)
2466 {
2467 /* recursively identifying all XML Namespaces from DOM-nodes */
2468     struct _xmlAttr *attr;
2469     while (node)
2470       {
2471 	  xmlNs *ns = node->ns;
2472 	  if (ns != NULL)
2473 	      splite_add_namespace (list, ns->type, ns->prefix, ns->href);
2474 	  attr = node->properties;
2475 	  while (attr != NULL)
2476 	    {
2477 		ns = attr->ns;
2478 		if (ns != NULL)
2479 		    splite_add_namespace (list, ns->type, ns->prefix, ns->href);
2480 		attr = attr->next;
2481 	    }
2482 	  find_xml_namespaces (node->children, list);
2483 	  node = node->next;
2484       }
2485 }
2486 
2487 static void
xml_out(gaiaOutBufferPtr buf,const xmlChar * str)2488 xml_out (gaiaOutBufferPtr buf, const xmlChar * str)
2489 {
2490 /* clean XML output */
2491     const xmlChar *p = str;
2492     while (*p != '\0')
2493       {
2494 	  if (*p == '>')
2495 	      gaiaAppendToOutBuffer (buf, "&gt;");
2496 	  else if (*p == '<')
2497 	      gaiaAppendToOutBuffer (buf, "&lt;");
2498 	  else if (*p == '&')
2499 	      gaiaAppendToOutBuffer (buf, "&amp;");
2500 	  else if (*p == '"')
2501 	      gaiaAppendToOutBuffer (buf, "&quot;");
2502 	  else if (*p == '\'')
2503 	      gaiaAppendToOutBuffer (buf, "&apos;");
2504 	  else
2505 	    {
2506 		char xx[2];
2507 		xx[0] = *p;
2508 		xx[1] = '\0';
2509 		gaiaAppendToOutBuffer (buf, xx);
2510 	    }
2511 	  p++;
2512       }
2513 }
2514 
2515 static void
format_xml(xmlNode * root,xmlNode * node,struct gaiaxml_ns_list * list,gaiaOutBufferPtr buf,int indent,int * level)2516 format_xml (xmlNode * root, xmlNode * node, struct gaiaxml_ns_list *list,
2517 	    gaiaOutBufferPtr buf, int indent, int *level)
2518 {
2519 /* recursively printing the XML-DOM nodes */
2520     struct _xmlAttr *attr;
2521     xmlNode *child;
2522     xmlNs *ns;
2523     const xmlChar *namespace;
2524     char *indenting = NULL;
2525     const char no = '\0';
2526     const char *pre;
2527     int tab;
2528     int width;
2529     int has_children;
2530     int has_text;
2531     if (!indent)
2532 	pre = &no;
2533     else
2534       {
2535 	  if (indent <= 8)
2536 	      tab = indent;
2537 	  else
2538 	      tab = 8;
2539 	  width = tab * *level;
2540 	  indenting = malloc (width + 2);
2541 	  *indenting = '\n';
2542 	  memset (indenting + 1, ' ', width);
2543 	  *(indenting + width + 1) = '\0';
2544 	  pre = indenting;
2545       }
2546 
2547     while (node)
2548       {
2549 	  if (node->type == XML_COMMENT_NODE)
2550 	    {
2551 		/* comment node */
2552 		if (*pre != '\0')
2553 		    gaiaAppendToOutBuffer (buf, "<!--");
2554 		else
2555 		    gaiaAppendToOutBuffer (buf, "\n<!--");
2556 		xml_out (buf, node->content);
2557 		gaiaAppendToOutBuffer (buf, "-->");
2558 	    }
2559 	  if (node->type == XML_ELEMENT_NODE)
2560 	    {
2561 		if (*pre != '\0')
2562 		    gaiaAppendToOutBuffer (buf, pre);
2563 		gaiaAppendToOutBuffer (buf, "<");
2564 		ns = node->ns;
2565 		namespace = NULL;
2566 		if (ns != NULL)
2567 		    namespace = ns->prefix;
2568 		if (namespace)
2569 		  {
2570 		      xml_out (buf, namespace);
2571 		      gaiaAppendToOutBuffer (buf, ":");
2572 		  }
2573 		xml_out (buf, node->name);
2574 		if (node == root)
2575 		  {
2576 		      /* Namespaces */
2577 		      struct gaiaxml_namespace *p_ns = list->first;
2578 		      while (p_ns != NULL)
2579 			{
2580 			    if (p_ns->prefix == NULL)
2581 				gaiaAppendToOutBuffer (buf, " xmlns=\"");
2582 			    else
2583 			      {
2584 				  gaiaAppendToOutBuffer (buf, " xmlns:");
2585 				  xml_out (buf, p_ns->prefix);
2586 				  gaiaAppendToOutBuffer (buf, "=\"");
2587 			      }
2588 			    xml_out (buf, p_ns->href);
2589 			    gaiaAppendToOutBuffer (buf, "\"");
2590 			    p_ns = p_ns->next;
2591 			}
2592 		  }
2593 		attr = node->properties;
2594 		while (attr != NULL)
2595 		  {
2596 		      /* attributes */
2597 		      if (attr->type == XML_ATTRIBUTE_NODE)
2598 			{
2599 			    xmlNode *text = attr->children;
2600 			    gaiaAppendToOutBuffer (buf, " ");
2601 			    ns = attr->ns;
2602 			    namespace = NULL;
2603 			    if (ns != NULL)
2604 				namespace = ns->prefix;
2605 			    if (namespace)
2606 			      {
2607 				  xml_out (buf, namespace);
2608 				  gaiaAppendToOutBuffer (buf, ":");
2609 			      }
2610 			    xml_out (buf, attr->name);
2611 			    gaiaAppendToOutBuffer (buf, "=\"");
2612 			    if (text != NULL)
2613 			      {
2614 				  if (text->type == XML_TEXT_NODE)
2615 				      xml_out (buf, text->content);
2616 			      }
2617 			    gaiaAppendToOutBuffer (buf, "\"");
2618 			}
2619 		      attr = attr->next;
2620 		  }
2621 		has_children = 0;
2622 		has_text = 0;
2623 		child = node->children;
2624 		while (child)
2625 		  {
2626 		      if (child->type == XML_ELEMENT_NODE
2627 			  || child->type == XML_COMMENT_NODE)
2628 			  has_children = 1;
2629 		      if (child->type == XML_TEXT_NODE)
2630 			  has_text++;
2631 		      child = child->next;
2632 		  }
2633 		if (has_children)
2634 		    has_text = 0;
2635 
2636 		if (!has_text && !has_children)
2637 		    gaiaAppendToOutBuffer (buf, " />");
2638 
2639 		if (has_text)
2640 		  {
2641 		      child = node->children;
2642 		      if (child->type == XML_TEXT_NODE)
2643 			{
2644 			    /* text node */
2645 			    gaiaAppendToOutBuffer (buf, ">");
2646 			    xml_out (buf, child->content);
2647 			    gaiaAppendToOutBuffer (buf, "</");
2648 			    ns = node->ns;
2649 			    namespace = NULL;
2650 			    if (ns != NULL)
2651 				namespace = ns->prefix;
2652 			    if (namespace)
2653 			      {
2654 				  xml_out (buf, namespace);
2655 				  gaiaAppendToOutBuffer (buf, ":");
2656 			      }
2657 			    xml_out (buf, node->name);
2658 			    gaiaAppendToOutBuffer (buf, ">");
2659 			}
2660 		  }
2661 		if (has_children)
2662 		  {
2663 		      /* recursively expanding all children */
2664 		      gaiaAppendToOutBuffer (buf, ">");
2665 		      *level += 1;
2666 		      format_xml (root, node->children, list, buf, indent,
2667 				  level);
2668 		      *level -= 1;
2669 		      if (*pre != '\0')
2670 			  gaiaAppendToOutBuffer (buf, pre);
2671 		      gaiaAppendToOutBuffer (buf, "</");
2672 		      ns = node->ns;
2673 		      namespace = NULL;
2674 		      if (ns != NULL)
2675 			  namespace = ns->prefix;
2676 		      if (namespace)
2677 			{
2678 			    xml_out (buf, namespace);
2679 			    gaiaAppendToOutBuffer (buf, ":");
2680 			}
2681 		      xml_out (buf, node->name);
2682 		      gaiaAppendToOutBuffer (buf, ">");
2683 		  }
2684 	    }
2685 	  node = node->next;
2686       }
2687     if (indenting)
2688 	free (indenting);
2689 }
2690 
2691 static int
gaiaXmlFormat(xmlDocPtr xml_doc,xmlChar ** out,int * out_len,const xmlChar * encoding,int indent)2692 gaiaXmlFormat (xmlDocPtr xml_doc, xmlChar ** out, int *out_len,
2693 	       const xmlChar * encoding, int indent)
2694 {
2695 /* reformatting an XML Document - properly indenting */
2696     int level = 0;
2697     int ret;
2698     gaiaOutBuffer buf;
2699     const xmlChar *version = xml_doc->version;
2700     xmlNode *root = xmlDocGetRootElement (xml_doc);
2701     struct gaiaxml_ns_list *list = splite_create_ns_list ();
2702 
2703     gaiaOutBufferInitialize (&buf);
2704     if (encoding != NULL)
2705       {
2706 	  gaiaAppendToOutBuffer (&buf, "<?xml version=\"");
2707 	  gaiaAppendToOutBuffer (&buf, (const char *) version);
2708 	  gaiaAppendToOutBuffer (&buf, "\" encoding=\"");
2709 	  gaiaAppendToOutBuffer (&buf, (const char *) encoding);
2710 	  gaiaAppendToOutBuffer (&buf, "\"?>");
2711       }
2712     else
2713       {
2714 	  gaiaAppendToOutBuffer (&buf, "<?xml version=\"");
2715 	  gaiaAppendToOutBuffer (&buf, (const char *) version);
2716 	  gaiaAppendToOutBuffer (&buf, "\"?>");
2717       }
2718 
2719     find_xml_namespaces (root, list);
2720     format_xml (root, root, list, &buf, indent, &level);
2721     splite_free_ns_list (list);
2722 
2723     if (buf.Error == 0 && buf.Buffer != NULL)
2724       {
2725 	  xmlChar *output;
2726 	  /* terminating the last line */
2727 	  gaiaAppendToOutBuffer (&buf, "\n");
2728 	  output = malloc (buf.WriteOffset + 1);
2729 	  memcpy (output, buf.Buffer, buf.WriteOffset);
2730 	  /* NULL-terminated string */
2731 	  *(output + buf.WriteOffset) = '\0';
2732 	  *out = output;
2733 	  *out_len = buf.WriteOffset + 1;
2734 	  ret = 1;
2735       }
2736     else
2737       {
2738 	  *out = NULL;
2739 	  *out_len = 0;
2740 	  ret = 0;
2741       }
2742     gaiaOutBufferReset (&buf);
2743     return ret;
2744 }
2745 
2746 GAIAGEO_DECLARE char *
gaiaXmlTextFromBlob(const unsigned char * blob,int blob_size,int indent)2747 gaiaXmlTextFromBlob (const unsigned char *blob, int blob_size, int indent)
2748 {
2749 /* attempting to extract an XMLDocument from within an XmlBLOB buffer */
2750 
2751 #ifndef OMIT_ICONV		/* only if ICONV is supported */
2752     int compressed = 0;
2753     int little_endian = 0;
2754     unsigned char flag;
2755     const unsigned char *ptr;
2756     int xml_len;
2757     int zip_len;
2758     short uri_len;
2759     short fileid_len;
2760     short parentid_len;
2761     short name_len = 0;
2762     short title_len;
2763     short abstract_len;
2764     short geometry_len;
2765     unsigned char *xml;
2766     xmlDocPtr xml_doc;
2767     xmlChar *out;
2768     int out_len;
2769     xmlChar *encoding = NULL;
2770     void *cvt;
2771     char *utf8;
2772     int err;
2773     int legacy_blob = 0;
2774     int endian_arch = gaiaEndianArch ();
2775     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
2776 
2777 /* validity check */
2778     if (!gaiaIsValidXmlBlob (blob, blob_size))
2779 	return NULL;		/* cannot be an XmlBLOB */
2780     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
2781 	legacy_blob = 1;
2782     flag = *(blob + 1);
2783     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
2784 	little_endian = 1;
2785     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
2786 	compressed = 1;
2787     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
2788     zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
2789     ptr = blob + 11;
2790     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
2791     ptr += 3 + uri_len;
2792     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2793     ptr += 3 + fileid_len;
2794     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2795     ptr += 3 + parentid_len;
2796     if (!legacy_blob)
2797       {
2798 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
2799 	  ptr += 3 + name_len;
2800       }
2801     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
2802     ptr += 3 + title_len;
2803     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
2804     ptr += 3 + abstract_len;
2805     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
2806     ptr += 3 + geometry_len;
2807     ptr++;
2808 
2809     if (compressed)
2810       {
2811 	  /* unzipping the XML payload */
2812 	  uLong refLen = xml_len;
2813 	  const Bytef *in = ptr;
2814 	  xml = malloc (xml_len + 1);
2815 	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
2816 	    {
2817 		/* uncompress error */
2818 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
2819 		free (xml);
2820 		return NULL;
2821 	    }
2822 	  *(xml + xml_len) = '\0';
2823       }
2824     else
2825       {
2826 	  /* just copying the uncompressed XML payload */
2827 	  xml = malloc (xml_len + 1);
2828 	  memcpy (xml, ptr, xml_len);
2829 	  *(xml + xml_len) = '\0';
2830       }
2831 /* retrieving the XMLDocument encoding */
2832     xmlSetGenericErrorFunc (NULL, silentError);
2833     xml_doc =
2834 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
2835     if (xml_doc == NULL)
2836       {
2837 	  /* parsing error; not a well-formed XML */
2838 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
2839 	  return NULL;
2840       }
2841     if (xml_doc->encoding)
2842       {
2843 	  /* using the internal character enconding */
2844 	  int enclen = (int) strlen ((const char *) xml_doc->encoding);
2845 	  encoding = malloc (enclen + 1);
2846 	  strcpy ((char *) encoding, (const char *) (xml_doc->encoding));
2847       }
2848     else
2849       {
2850 	  /* no declared encoding: defaulting to UTF-8 */
2851 	  encoding = malloc (6);
2852 	  strcpy ((char *) encoding, "UTF-8");
2853       }
2854 
2855     if (indent < 0)
2856       {
2857 	  /* just returning the XMLDocument "as is" */
2858 	  xmlFreeDoc (xml_doc);
2859 	  cvt = gaiaCreateUTF8Converter ((const char *) encoding);
2860 	  free (encoding);
2861 	  if (cvt == NULL)
2862 	    {
2863 		xmlSetGenericErrorFunc ((void *) stderr, NULL);
2864 		return NULL;
2865 	    }
2866 	  utf8 = gaiaConvertToUTF8 (cvt, (const char *) xml, xml_len, &err);
2867 	  free (xml);
2868 	  gaiaFreeUTF8Converter (cvt);
2869 	  if (utf8 && !err)
2870 	    {
2871 		xmlSetGenericErrorFunc ((void *) stderr, NULL);
2872 		return utf8;
2873 	    }
2874 	  if (utf8)
2875 	      free (utf8);
2876 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
2877 	  return NULL;
2878       }
2879 
2880 /* properly indenting the XMLDocument */
2881     gaiaXmlFormat (xml_doc, &out, &out_len, encoding, indent);
2882     free (xml);
2883     xmlFreeDoc (xml_doc);
2884     free (encoding);
2885     if (out)
2886       {
2887 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
2888 	  return (char *) out;
2889       }
2890     xmlSetGenericErrorFunc ((void *) stderr, NULL);
2891     return NULL;
2892 
2893 #else
2894     if (blob != NULL && blob_size == 0 && indent == 0)
2895 	blob = NULL;		/* silencing stupid compiler warnings */
2896 #endif
2897     return NULL;
2898 }
2899 
2900 GAIAGEO_DECLARE void
gaiaXmlFromBlob(const unsigned char * blob,int blob_size,int indent,unsigned char ** result,int * res_size)2901 gaiaXmlFromBlob (const unsigned char *blob, int blob_size, int indent,
2902 		 unsigned char **result, int *res_size)
2903 {
2904 /* attempting to extract an XMLDocument from within an XmlBLOB buffer */
2905     int compressed = 0;
2906     int little_endian = 0;
2907     unsigned char flag;
2908     const unsigned char *ptr;
2909     int xml_len;
2910     int zip_len;
2911     short uri_len;
2912     short fileid_len;
2913     short parentid_len;
2914     short name_len;
2915     short title_len;
2916     short abstract_len;
2917     short geometry_len;
2918     unsigned char *xml;
2919     xmlDocPtr xml_doc;
2920     xmlChar *out;
2921     int out_len;
2922     int legacy_blob = 0;
2923     int endian_arch = gaiaEndianArch ();
2924     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
2925     *result = NULL;
2926     *res_size = 0;
2927 
2928 /* validity check */
2929     if (!gaiaIsValidXmlBlob (blob, blob_size))
2930 	return;			/* cannot be an XmlBLOB */
2931     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
2932 	legacy_blob = 1;
2933     flag = *(blob + 1);
2934     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
2935 	little_endian = 1;
2936     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
2937 	compressed = 1;
2938     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
2939     zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
2940     ptr = blob + 11;
2941     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
2942     ptr += 3 + uri_len;
2943     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2944     ptr += 3 + fileid_len;
2945     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
2946     ptr += 3 + parentid_len;
2947     if (!legacy_blob)
2948       {
2949 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
2950 	  ptr += 3 + name_len;
2951       }
2952     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
2953     ptr += 3 + title_len;
2954     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
2955     ptr += 3 + abstract_len;
2956     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
2957     ptr += 3 + geometry_len;
2958     ptr++;
2959 
2960     if (compressed)
2961       {
2962 	  /* unzipping the XML payload */
2963 	  uLong refLen = xml_len;
2964 	  const Bytef *in = ptr;
2965 	  xml = malloc (xml_len + 1);
2966 	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
2967 	    {
2968 		/* uncompress error */
2969 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
2970 		free (xml);
2971 		return;
2972 	    }
2973 	  *(xml + xml_len) = '\0';
2974       }
2975     else
2976       {
2977 	  /* just copying the uncompressed XML payload */
2978 	  xml = malloc (xml_len + 1);
2979 	  memcpy (xml, ptr, xml_len);
2980 	  *(xml + xml_len) = '\0';
2981       }
2982     if (indent < 0)
2983       {
2984 	  /* just returning the XMLDocument "as is" */
2985 	  *result = xml;
2986 	  *res_size = xml_len;
2987 	  return;
2988       }
2989 
2990 /* properly indenting the XMLDocument */
2991     xmlSetGenericErrorFunc (NULL, silentError);
2992     xml_doc =
2993 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
2994     if (xml_doc == NULL)
2995       {
2996 	  /* parsing error; not a well-formed XML */
2997 	  *result = xml;
2998 	  *res_size = xml_len;
2999 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3000 	  return;
3001       }
3002     gaiaXmlFormat (xml_doc, &out, &out_len, xml_doc->encoding, indent);
3003     free (xml);
3004     xmlFreeDoc (xml_doc);
3005     *result = out;
3006     if (*(out + out_len - 1) == '\0' && out_len > 0)
3007 	out_len -= 1;
3008     *res_size = out_len;
3009     xmlSetGenericErrorFunc ((void *) stderr, NULL);
3010 }
3011 
3012 GAIAGEO_DECLARE int
gaiaXmlLoad(const void * p_cache,const char * path_or_url,unsigned char ** result,int * size,char ** parsing_errors)3013 gaiaXmlLoad (const void *p_cache, const char *path_or_url,
3014 	     unsigned char **result, int *size, char **parsing_errors)
3015 {
3016 /* attempting to load an external XML Document into a BLOB buffer */
3017     unsigned char *out;
3018     int len;
3019     xmlDocPtr xml_doc;
3020     struct splite_internal_cache *cache =
3021 	(struct splite_internal_cache *) p_cache;
3022     gaiaOutBufferPtr parsingBuf = NULL;
3023     xmlGenericErrorFunc parsingError = NULL;
3024     if (is_valid_cache (cache))
3025       {
3026 	  parsingBuf = (gaiaOutBufferPtr) (cache->xmlParsingErrors);
3027 	  parsingError = (xmlGenericErrorFunc) spliteParsingError;
3028 	  spliteResetXmlErrors (cache);
3029       }
3030 
3031     *result = NULL;
3032     *size = 0;
3033     if (parsing_errors)
3034 	*parsing_errors = NULL;
3035     if (path_or_url == NULL)
3036 	return 0;
3037 
3038 /* testing if the XMLDocument is well-formed */
3039     xmlSetGenericErrorFunc (cache, parsingError);
3040     xml_doc = xmlReadFile (path_or_url, NULL, 0);
3041     if (xml_doc == NULL)
3042       {
3043 	  /* parsing error; not a well-formed XML */
3044 	  spatialite_e ("XML parsing error\n");
3045 	  if (parsing_errors && parsingBuf)
3046 	      *parsing_errors = parsingBuf->Buffer;
3047 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3048 	  return 0;
3049       }
3050     if (parsing_errors && parsingBuf)
3051 	*parsing_errors = parsingBuf->Buffer;
3052 
3053 /* exporting the XML Document into a BLOB */
3054     xmlDocDumpFormatMemory (xml_doc, &out, &len, 0);
3055     xmlFreeDoc (xml_doc);
3056     *result = out;
3057     *size = len;
3058     xmlSetGenericErrorFunc ((void *) stderr, NULL);
3059     if (out == NULL)
3060 	return 0;
3061     return 1;
3062 }
3063 
3064 GAIAGEO_DECLARE int
gaiaXmlStore(const unsigned char * blob,int size,const char * path,int indent)3065 gaiaXmlStore (const unsigned char *blob, int size, const char *path, int indent)
3066 {
3067 /* attempting to store an XmlBLOB Document into an external file */
3068     FILE *fl;
3069     int wr;
3070     unsigned char *result = NULL;
3071     int res_size;
3072     gaiaXmlFromBlob (blob, size, indent, &result, &res_size);
3073     if (result == NULL)
3074 	return 0;
3075 
3076 /* exporting the XML Document into an external file */
3077 #ifdef _WIN32
3078     fl = gaia_win_fopen (path, "wb");
3079 #else
3080     fl = fopen (path, "wb");
3081 #endif
3082     if (fl == NULL)
3083       {
3084 	  spatialite_e ("Unable to open \"%s\"\n", path);
3085 	  return 0;
3086       }
3087     wr = fwrite (result, 1, res_size, fl);
3088     if (wr != res_size)
3089       {
3090 	  spatialite_e
3091 	      ("I/O error: written %d bytes into \"%s\", expected %d\n", wr,
3092 	       path, res_size);
3093 	  fclose (fl);
3094 	  return 0;
3095       }
3096     fclose (fl);
3097     return 1;
3098 }
3099 
3100 GAIAGEO_DECLARE int
gaiaIsCompressedXmlBlob(const unsigned char * blob,int blob_size)3101 gaiaIsCompressedXmlBlob (const unsigned char *blob, int blob_size)
3102 {
3103 /* Checks if a valid XmlBLOB buffer is compressed or not */
3104     int compressed = 0;
3105     unsigned char flag;
3106 
3107 /* validity check */
3108     if (!gaiaIsValidXmlBlob (blob, blob_size))
3109 	return -1;		/* cannot be an XmlBLOB */
3110     flag = *(blob + 1);
3111     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
3112 	compressed = 1;
3113     return compressed;
3114 }
3115 
3116 GAIAGEO_DECLARE int
gaiaIsSchemaValidatedXmlBlob(const unsigned char * blob,int blob_size)3117 gaiaIsSchemaValidatedXmlBlob (const unsigned char *blob, int blob_size)
3118 {
3119 /* Checks if a valid XmlBLOB buffer has successfully passed a formal Schema validation or not */
3120     int validated = 0;
3121     unsigned char flag;
3122 
3123 /* validity check */
3124     if (!gaiaIsValidXmlBlob (blob, blob_size))
3125 	return -1;		/* cannot be an XmlBLOB */
3126     flag = *(blob + 1);
3127     if ((flag & GAIA_XML_VALIDATED) == GAIA_XML_VALIDATED)
3128 	validated = 1;
3129     return validated;
3130 }
3131 
3132 GAIAGEO_DECLARE int
gaiaIsIsoMetadataXmlBlob(const unsigned char * blob,int blob_size)3133 gaiaIsIsoMetadataXmlBlob (const unsigned char *blob, int blob_size)
3134 {
3135 /* Checks if a valid XmlBLOB buffer does actually contains an ISO Metadata or not */
3136     int iso_metadata = 0;
3137     unsigned char flag;
3138 
3139 /* validity check */
3140     if (!gaiaIsValidXmlBlob (blob, blob_size))
3141 	return -1;		/* cannot be an XmlBLOB */
3142     flag = *(blob + 1);
3143     if (((flag & GAIA_XML_ISO_METADATA) == GAIA_XML_ISO_METADATA)
3144 	&& ((flag & GAIA_XML_MAP_CONFIG) != GAIA_XML_MAP_CONFIG))
3145 	iso_metadata = 1;
3146     return iso_metadata;
3147 }
3148 
3149 GAIAGEO_DECLARE int
gaiaIsSldSeVectorStyleXmlBlob(const unsigned char * blob,int blob_size)3150 gaiaIsSldSeVectorStyleXmlBlob (const unsigned char *blob, int blob_size)
3151 {
3152 /* Checks if a valid XmlBLOB buffer does actually contains an SLD/SE Vector Style or not */
3153     int sld_se_style = 0;
3154     unsigned char flag;
3155 
3156 /* validity check */
3157     if (!gaiaIsValidXmlBlob (blob, blob_size))
3158 	return -1;		/* cannot be an XmlBLOB */
3159     flag = *(blob + 1);
3160     if (((flag & GAIA_XML_SLD_SE_VECTOR_STYLE) == GAIA_XML_SLD_SE_VECTOR_STYLE)
3161 	&& ((flag & GAIA_XML_SLD_STYLE) != GAIA_XML_SLD_STYLE))
3162 	sld_se_style = 1;
3163     return sld_se_style;
3164 }
3165 
3166 GAIAGEO_DECLARE int
gaiaIsSldSeRasterStyleXmlBlob(const unsigned char * blob,int blob_size)3167 gaiaIsSldSeRasterStyleXmlBlob (const unsigned char *blob, int blob_size)
3168 {
3169 /* Checks if a valid XmlBLOB buffer does actually contains an SLD/SE Raster Style or not */
3170     int sld_se_style = 0;
3171     unsigned char flag;
3172 
3173 /* validity check */
3174     if (!gaiaIsValidXmlBlob (blob, blob_size))
3175 	return -1;		/* cannot be an XmlBLOB */
3176     flag = *(blob + 1);
3177     if ((flag & GAIA_XML_SLD_SE_RASTER_STYLE) == GAIA_XML_SLD_SE_RASTER_STYLE)
3178 	sld_se_style = 1;
3179     return sld_se_style;
3180 }
3181 
3182 GAIAGEO_DECLARE int
gaiaIsSldStyleXmlBlob(const unsigned char * blob,int blob_size)3183 gaiaIsSldStyleXmlBlob (const unsigned char *blob, int blob_size)
3184 {
3185 /* Checks if a valid XmlBLOB buffer does actually contains an SLD Style or not */
3186     int sld_style = 0;
3187     unsigned char flag;
3188 
3189 /* validity check */
3190     if (!gaiaIsValidXmlBlob (blob, blob_size))
3191 	return -1;		/* cannot be an XmlBLOB */
3192     flag = *(blob + 1);
3193     if ((flag & GAIA_XML_SLD_STYLE) == GAIA_XML_SLD_STYLE)
3194 	sld_style = 1;
3195     return sld_style;
3196 }
3197 
3198 GAIAGEO_DECLARE int
gaiaIsMapConfigXmlBlob(const unsigned char * blob,int blob_size)3199 gaiaIsMapConfigXmlBlob (const unsigned char *blob, int blob_size)
3200 {
3201 /* Checks if a valid XmlBLOB buffer does actually contains a MapConfig or not */
3202     int sld_style = 0;
3203     unsigned char flag;
3204 
3205 /* validity check */
3206     if (!gaiaIsValidXmlBlob (blob, blob_size))
3207 	return -1;		/* cannot be an XmlBLOB */
3208     flag = *(blob + 1);
3209     if ((flag & GAIA_XML_MAP_CONFIG) == GAIA_XML_MAP_CONFIG)
3210 	sld_style = 1;
3211     return sld_style;
3212 }
3213 
3214 GAIAGEO_DECLARE int
gaiaIsSvgXmlBlob(const unsigned char * blob,int blob_size)3215 gaiaIsSvgXmlBlob (const unsigned char *blob, int blob_size)
3216 {
3217 /* Checks if a valid XmlBLOB buffer does actually contains an SVG image or not */
3218     int svg = 0;
3219     unsigned char flag;
3220 
3221 /* validity check */
3222     if (!gaiaIsValidXmlBlob (blob, blob_size))
3223 	return -1;		/* cannot be an XmlBLOB */
3224     flag = *(blob + 1);
3225     if ((flag & GAIA_XML_SVG) == GAIA_XML_SVG)
3226 	svg = 1;
3227     return svg;
3228 }
3229 
3230 GAIAGEO_DECLARE int
gaiaIsGpxXmlBlob(const unsigned char * blob,int blob_size)3231 gaiaIsGpxXmlBlob (const unsigned char *blob, int blob_size)
3232 {
3233 /* Checks if a valid XmlBLOB buffer does actually contains a GPX document or not */
3234     int gpx = 0;
3235     unsigned char flag;
3236 
3237 /* validity check */
3238     if (!gaiaIsValidXmlBlob (blob, blob_size))
3239 	return -1;		/* cannot be an XmlBLOB */
3240     flag = *(blob + 1);
3241     if (((flag & GAIA_XML_GPX) == GAIA_XML_GPX)
3242 	&& ((flag & GAIA_XML_MAP_CONFIG) != GAIA_XML_MAP_CONFIG))
3243 	gpx = 1;
3244     return gpx;
3245 }
3246 
3247 GAIAGEO_DECLARE int
gaiaXmlBlobGetDocumentSize(const unsigned char * blob,int blob_size)3248 gaiaXmlBlobGetDocumentSize (const unsigned char *blob, int blob_size)
3249 {
3250 /* Return the XMLDocument size (in bytes) from a valid XmlBLOB buffer */
3251     int little_endian = 0;
3252     unsigned char flag;
3253     int xml_len;
3254     int endian_arch = gaiaEndianArch ();
3255 
3256 /* validity check */
3257     if (!gaiaIsValidXmlBlob (blob, blob_size))
3258 	return -1;		/* cannot be an XmlBLOB */
3259     flag = *(blob + 1);
3260     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
3261 	little_endian = 1;
3262     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
3263     return xml_len;
3264 }
3265 
3266 GAIAGEO_DECLARE char *
gaiaXmlBlobGetSchemaURI(const unsigned char * blob,int blob_size)3267 gaiaXmlBlobGetSchemaURI (const unsigned char *blob, int blob_size)
3268 {
3269 /* Return the SchemaURI from a valid XmlBLOB buffer */
3270     int little_endian = 0;
3271     unsigned char flag;
3272     short uri_len;
3273     char *uri;
3274     int endian_arch = gaiaEndianArch ();
3275 
3276 /* validity check */
3277     if (!gaiaIsValidXmlBlob (blob, blob_size))
3278 	return NULL;		/* cannot be an XmlBLOB */
3279     flag = *(blob + 1);
3280     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
3281 	little_endian = 1;
3282     uri_len = gaiaImport16 (blob + 11, little_endian, endian_arch);
3283     if (!uri_len)
3284 	return NULL;
3285 
3286     uri = malloc (uri_len + 1);
3287     memcpy (uri, blob + 14, uri_len);
3288     *(uri + uri_len) = '\0';
3289     return uri;
3290 }
3291 
3292 GAIAGEO_DECLARE char *
gaiaXmlGetInternalSchemaURI(const void * p_cache,const unsigned char * xml,int xml_len)3293 gaiaXmlGetInternalSchemaURI (const void *p_cache, const unsigned char *xml,
3294 			     int xml_len)
3295 {
3296 /* Return the internally defined SchemaURI from a valid XmlDocument */
3297     xmlDocPtr xml_doc;
3298     char *uri = NULL;
3299     xmlXPathContextPtr xpathCtx;
3300     xmlXPathObjectPtr xpathObj;
3301     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
3302 
3303 /* retrieving the XMLDocument internal SchemaURI (if any) */
3304     xmlSetGenericErrorFunc (NULL, silentError);
3305     xml_doc =
3306 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
3307     if (xml_doc == NULL)
3308       {
3309 	  /* parsing error; not a well-formed XML */
3310 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3311 	  return NULL;
3312       }
3313 
3314     if (vxpath_eval_expr
3315 	(p_cache, xml_doc, "/*/@xsi:schemaLocation", &xpathCtx, &xpathObj))
3316       {
3317 	  /* attempting first to extract xsi:schemaLocation */
3318 	  xmlNodeSetPtr nodeset = xpathObj->nodesetval;
3319 	  xmlNodePtr node;
3320 	  int num_nodes = (nodeset) ? nodeset->nodeNr : 0;
3321 	  if (num_nodes == 1)
3322 	    {
3323 		node = nodeset->nodeTab[0];
3324 		if (node->type == XML_ATTRIBUTE_NODE)
3325 		  {
3326 		      if (node->children != NULL)
3327 			{
3328 			    if (node->children->content != NULL)
3329 			      {
3330 				  const char *str =
3331 				      (const char *) (node->children->content);
3332 				  const char *ptr = str;
3333 				  int i;
3334 				  int len = strlen (str);
3335 				  for (i = len - 1; i >= 0; i--)
3336 				    {
3337 					if (*(str + i) == ' ')
3338 					  {
3339 					      /* last occurrence of SPACE [namespace/schema separator] */
3340 					      ptr = str + i + 1;
3341 					      break;
3342 					  }
3343 				    }
3344 				  len = strlen (ptr);
3345 				  uri = malloc (len + 1);
3346 				  strcpy (uri, ptr);
3347 			      }
3348 			}
3349 		  }
3350 	    }
3351 	  if (uri != NULL)
3352 	      xmlXPathFreeContext (xpathCtx);
3353 	  xmlXPathFreeObject (xpathObj);
3354       }
3355     if (uri == NULL)
3356       {
3357 	  /* checking for xsi:noNamespaceSchemaLocation */
3358 	  if (vxpath_eval_expr
3359 	      (p_cache, xml_doc, "/*/@xsi:noNamespaceSchemaLocation", &xpathCtx,
3360 	       &xpathObj))
3361 	    {
3362 		xmlNodeSetPtr nodeset = xpathObj->nodesetval;
3363 		xmlNodePtr node;
3364 		int num_nodes = (nodeset) ? nodeset->nodeNr : 0;
3365 		if (num_nodes == 1)
3366 		  {
3367 		      node = nodeset->nodeTab[0];
3368 		      if (node->type == XML_ATTRIBUTE_NODE)
3369 			{
3370 			    if (node->children != NULL)
3371 			      {
3372 				  if (node->children->content != NULL)
3373 				    {
3374 					int len =
3375 					    strlen ((const char *)
3376 						    node->children->content);
3377 					uri = malloc (len + 1);
3378 					strcpy (uri,
3379 						(const char *) node->
3380 						children->content);
3381 				    }
3382 			      }
3383 			}
3384 		  }
3385 		xmlXPathFreeContext (xpathCtx);
3386 		xmlXPathFreeObject (xpathObj);
3387 	    }
3388       }
3389 
3390     xmlFreeDoc (xml_doc);
3391     xmlSetGenericErrorFunc ((void *) stderr, NULL);
3392     return uri;
3393 }
3394 
3395 GAIAGEO_DECLARE char *
gaiaXmlBlobGetFileId(const unsigned char * blob,int blob_size)3396 gaiaXmlBlobGetFileId (const unsigned char *blob, int blob_size)
3397 {
3398 /* Return the FileIdentifier from a valid XmlBLOB buffer */
3399     int little_endian = 0;
3400     unsigned char flag;
3401     const unsigned char *ptr;
3402     short uri_len;
3403     short fileid_len;
3404     char *file_identifier;
3405     int endian_arch = gaiaEndianArch ();
3406 
3407 /* validity check */
3408     if (!gaiaIsValidXmlBlob (blob, blob_size))
3409 	return NULL;		/* cannot be an XmlBLOB */
3410     flag = *(blob + 1);
3411     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
3412 	little_endian = 1;
3413     ptr = blob + 11;
3414     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
3415     ptr += 3 + uri_len;
3416     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3417     if (!fileid_len)
3418 	return NULL;
3419     ptr += 3;
3420 
3421     file_identifier = malloc (fileid_len + 1);
3422     memcpy (file_identifier, ptr, fileid_len);
3423     *(file_identifier + fileid_len) = '\0';
3424     return file_identifier;
3425 }
3426 
3427 GAIAGEO_DECLARE char *
gaiaXmlBlobGetParentId(const unsigned char * blob,int blob_size)3428 gaiaXmlBlobGetParentId (const unsigned char *blob, int blob_size)
3429 {
3430 /* Return the ParentIdentifier from a valid XmlBLOB buffer */
3431     int little_endian = 0;
3432     unsigned char flag;
3433     const unsigned char *ptr;
3434     short uri_len;
3435     short fileid_len;
3436     short parentid_len;
3437     char *parent_identifier;
3438     int endian_arch = gaiaEndianArch ();
3439 
3440 /* validity check */
3441     if (!gaiaIsValidXmlBlob (blob, blob_size))
3442 	return NULL;		/* cannot be an XmlBLOB */
3443     flag = *(blob + 1);
3444     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
3445 	little_endian = 1;
3446     ptr = blob + 11;
3447     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
3448     ptr += 3 + uri_len;
3449     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3450     ptr += 3 + fileid_len;
3451     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3452     if (!parentid_len)
3453 	return NULL;
3454     ptr += 3;
3455 
3456     parent_identifier = malloc (parentid_len + 1);
3457     memcpy (parent_identifier, ptr, parentid_len);
3458     *(parent_identifier + parentid_len) = '\0';
3459     return parent_identifier;
3460 }
3461 
3462 static xmlNodePtr
find_iso_node(xmlNodePtr root,const char * name)3463 find_iso_node (xmlNodePtr root, const char *name)
3464 {
3465 /* scanning the Root node [fileIdentifier or parentIdentifier] */
3466     xmlNodePtr nodeId = NULL;
3467     xmlNodePtr node;
3468 
3469     for (node = root->children; node; node = node->next)
3470       {
3471 	  if (node->type == XML_ELEMENT_NODE)
3472 	    {
3473 		const char *xname = (const char *) (node->name);
3474 		if (strcmp (xname, name) == 0)
3475 		  {
3476 		      nodeId = node;
3477 		      break;
3478 		  }
3479 	    }
3480       }
3481     if (nodeId == NULL)
3482 	return NULL;
3483     for (node = nodeId->children; node; node = node->next)
3484       {
3485 	  if (node->type == XML_ELEMENT_NODE)
3486 	    {
3487 		const char *xname = (const char *) (node->name);
3488 		if (strcmp (xname, "CharacterString") == 0)
3489 		    return node;
3490 	    }
3491       }
3492     return NULL;
3493 }
3494 
3495 static int
setIsoId(xmlDocPtr xml_doc,const char * node_name,const char * identifier,unsigned char ** out_blob,int * out_len)3496 setIsoId (xmlDocPtr xml_doc, const char *node_name, const char *identifier,
3497 	  unsigned char **out_blob, int *out_len)
3498 {
3499 /* attempting to change an ISO Id */
3500     xmlNodePtr node;
3501     xmlNodePtr new_node;
3502     xmlNodePtr text;
3503     xmlNodePtr old_node;
3504     xmlChar *buf;
3505     int len;
3506     *out_blob = NULL;
3507     *out_len = 0;
3508     node = find_iso_node (xmlDocGetRootElement (xml_doc), node_name);
3509     if (node == NULL)
3510 	return 0;
3511 /* replacing the existing XML Node */
3512     new_node = xmlNewNode (node->ns, node->name);
3513     text = xmlNewText ((xmlChar *) identifier);
3514     xmlAddChild (new_node, text);
3515     old_node = xmlReplaceNode (node, new_node);
3516     xmlFreeNode (old_node);
3517     xmlDocDumpFormatMemory (xml_doc, &buf, &len, 0);
3518     if (buf == NULL)
3519 	return 0;
3520     *out_blob = buf;
3521     *out_len = len;
3522     return 1;
3523 }
3524 
3525 GAIAGEO_DECLARE int
gaiaXmlBlobSetFileId(const void * p_cache,const unsigned char * blob,int blob_size,const char * identifier,unsigned char ** new_blob,int * new_size)3526 gaiaXmlBlobSetFileId (const void *p_cache, const unsigned char *blob,
3527 		      int blob_size, const char *identifier,
3528 		      unsigned char **new_blob, int *new_size)
3529 {
3530 /* Return a new XmlBLOB buffer by replacing the FileId value */
3531     struct splite_internal_cache *cache =
3532 	(struct splite_internal_cache *) p_cache;
3533     int compressed = 0;
3534     int little_endian = 0;
3535     unsigned char flag;
3536     const unsigned char *ptr;
3537     short uri_len;
3538     short fileid_len;
3539     short parentid_len;
3540     int xml_len;
3541     int zip_len;
3542     int name_len;
3543     short title_len;
3544     short abstract_len;
3545     short geometry_len;
3546     char *schemaURI = NULL;
3547     unsigned char *xml;
3548     xmlDocPtr xml_doc;
3549     unsigned char *out_blob;
3550     int out_len;
3551     int legacy_blob = 0;
3552     int endian_arch = gaiaEndianArch ();
3553     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
3554 
3555     *new_blob = NULL;
3556     *new_size = 0;
3557 /* validity check */
3558     if (!gaiaIsValidXmlBlob (blob, blob_size))
3559 	return 0;		/* cannot be an XmlBLOB */
3560     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
3561 	legacy_blob = 1;
3562     flag = *(blob + 1);
3563     if ((flag & GAIA_XML_ISO_METADATA) == GAIA_XML_ISO_METADATA)
3564 	;
3565     else
3566 	return 0;		/* not an ISO Metadata XmlBLOB */
3567     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
3568 	little_endian = 1;
3569     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
3570 	compressed = 1;
3571     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
3572     zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
3573     ptr = blob + 11;
3574     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
3575     if (uri_len > 0)
3576       {
3577 	  schemaURI = malloc (uri_len + 1);
3578 	  memcpy (schemaURI, blob + 14, uri_len);
3579 	  *(schemaURI + uri_len) = '\0';
3580       }
3581     ptr += 3 + uri_len;
3582     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3583     ptr += 3 + fileid_len;
3584     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3585     ptr += 3 + parentid_len;
3586     if (!legacy_blob)
3587       {
3588 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
3589 	  ptr += 3 + name_len;
3590       }
3591     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
3592     ptr += 3 + title_len;
3593     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
3594     ptr += 3 + abstract_len;
3595     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
3596     ptr += 3 + geometry_len;
3597     ptr++;
3598 
3599     if (compressed)
3600       {
3601 	  /* unzipping the XML payload */
3602 	  uLong refLen = xml_len;
3603 	  const Bytef *in = ptr;
3604 	  xml = malloc (xml_len + 1);
3605 	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
3606 	    {
3607 		/* uncompress error */
3608 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
3609 		free (xml);
3610 		return 0;
3611 	    }
3612 	  *(xml + xml_len) = '\0';
3613       }
3614     else
3615       {
3616 	  /* just copying the uncompressed XML payload */
3617 	  xml = malloc (xml_len + 1);
3618 	  memcpy (xml, ptr, xml_len);
3619 	  *(xml + xml_len) = '\0';
3620       }
3621 /* loading the XMLDocument */
3622     xmlSetGenericErrorFunc (NULL, silentError);
3623     xml_doc =
3624 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
3625     if (xml_doc == NULL)
3626       {
3627 	  /* parsing error; not a well-formed XML */
3628 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3629 	  return 0;
3630       }
3631 /* replacing the FileId value */
3632     setIsoId (xml_doc, "fileIdentifier", identifier, &out_blob, &out_len);
3633     free (xml);
3634     xmlFreeDoc (xml_doc);
3635     if (out_blob)
3636       {
3637 	  gaiaXmlToBlob (cache, out_blob, out_len, compressed, schemaURI,
3638 			 new_blob, new_size, NULL, NULL);
3639 #ifdef __MINGW32__
3640 /* MinGW is unable to statically link libxml2 if xmlFree() is declared */
3641 	  free (out_blob);
3642 #else
3643 	  xmlFree (out_blob);
3644 #endif
3645 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3646 	  return 1;
3647       }
3648     xmlSetGenericErrorFunc ((void *) stderr, NULL);
3649     return 0;
3650 }
3651 
3652 GAIAGEO_DECLARE int
gaiaXmlBlobSetParentId(const void * p_cache,const unsigned char * blob,int blob_size,const char * identifier,unsigned char ** new_blob,int * new_size)3653 gaiaXmlBlobSetParentId (const void *p_cache, const unsigned char *blob,
3654 			int blob_size, const char *identifier,
3655 			unsigned char **new_blob, int *new_size)
3656 {
3657 /* Return a new XmlBLOB buffer by replacing the ParentId value */
3658     struct splite_internal_cache *cache =
3659 	(struct splite_internal_cache *) p_cache;
3660     int compressed = 0;
3661     int little_endian = 0;
3662     unsigned char flag;
3663     const unsigned char *ptr;
3664     short uri_len;
3665     short fileid_len;
3666     short parentid_len;
3667     int xml_len;
3668     int zip_len;
3669     short name_len;
3670     short title_len;
3671     short abstract_len;
3672     short geometry_len;
3673     char *schemaURI = NULL;
3674     unsigned char *xml;
3675     xmlDocPtr xml_doc;
3676     unsigned char *out_blob;
3677     int out_len;
3678     int legacy_blob = 0;
3679     int endian_arch = gaiaEndianArch ();
3680     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
3681 
3682     *new_blob = NULL;
3683     *new_size = 0;
3684 /* validity check */
3685     if (!gaiaIsValidXmlBlob (blob, blob_size))
3686 	return 0;		/* cannot be an XmlBLOB */
3687     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
3688 	legacy_blob = 1;
3689     flag = *(blob + 1);
3690     if ((flag & GAIA_XML_ISO_METADATA) == GAIA_XML_ISO_METADATA)
3691 	;
3692     else
3693 	return 0;		/* not an ISO Metadata XmlBLOB */
3694     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
3695 	little_endian = 1;
3696     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
3697 	compressed = 1;
3698     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
3699     zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
3700     ptr = blob + 11;
3701     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
3702     if (uri_len > 0)
3703       {
3704 	  schemaURI = malloc (uri_len + 1);
3705 	  memcpy (schemaURI, blob + 14, uri_len);
3706 	  *(schemaURI + uri_len) = '\0';
3707       }
3708     ptr += 3 + uri_len;
3709     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3710     ptr += 3 + fileid_len;
3711     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3712     ptr += 3 + parentid_len;
3713     if (!legacy_blob)
3714       {
3715 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
3716 	  ptr += 3 + name_len;
3717       }
3718     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
3719     ptr += 3 + title_len;
3720     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
3721     ptr += 3 + abstract_len;
3722     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
3723     ptr += 3 + geometry_len;
3724     ptr++;
3725 
3726     if (compressed)
3727       {
3728 	  /* unzipping the XML payload */
3729 	  uLong refLen = xml_len;
3730 	  const Bytef *in = ptr;
3731 	  xml = malloc (xml_len + 1);
3732 	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
3733 	    {
3734 		/* uncompress error */
3735 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
3736 		free (xml);
3737 		return 0;
3738 	    }
3739 	  *(xml + xml_len) = '\0';
3740       }
3741     else
3742       {
3743 	  /* just copying the uncompressed XML payload */
3744 	  xml = malloc (xml_len + 1);
3745 	  memcpy (xml, ptr, xml_len);
3746 	  *(xml + xml_len) = '\0';
3747       }
3748 /* loading the XMLDocument */
3749     xmlSetGenericErrorFunc (NULL, silentError);
3750     xml_doc =
3751 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
3752     if (xml_doc == NULL)
3753       {
3754 	  /* parsing error; not a well-formed XML */
3755 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3756 	  return 0;
3757       }
3758 /* replacing the ParentId value */
3759     setIsoId (xml_doc, "parentIdentifier", identifier, &out_blob, &out_len);
3760     free (xml);
3761     xmlFreeDoc (xml_doc);
3762     if (out_blob)
3763       {
3764 	  gaiaXmlToBlob (cache, out_blob, out_len, compressed, schemaURI,
3765 			 new_blob, new_size, NULL, NULL);
3766 #ifdef __MINGW32__
3767 /* MinGW is unable to statically link libxml2 if xmlFree() is declared */
3768 	  free (out_blob);
3769 #else
3770 	  xmlFree (out_blob);
3771 #endif
3772 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3773 	  return 1;
3774       }
3775     xmlSetGenericErrorFunc ((void *) stderr, NULL);
3776     return 0;
3777 }
3778 
3779 static xmlNodePtr
find_iso_sibling(xmlNodePtr root,const char * name)3780 find_iso_sibling (xmlNodePtr root, const char *name)
3781 {
3782 /* scanning the Root node [previous sibling] */
3783     xmlNodePtr node;
3784 
3785     for (node = root->children; node; node = node->next)
3786       {
3787 	  if (node->type == XML_ELEMENT_NODE)
3788 	    {
3789 		const char *xname = (const char *) (node->name);
3790 		if (strcmp (xname, name) == 0)
3791 		    return node;
3792 	    }
3793       }
3794     return NULL;
3795 }
3796 
3797 static int
addIsoId(xmlDocPtr xml_doc,const char * node_name,const char * identifier,const char * ns_id,const char * uri_id,const char * ns_charstr,const char * uri_charstr,unsigned char ** out_blob,int * out_len)3798 addIsoId (xmlDocPtr xml_doc, const char *node_name, const char *identifier,
3799 	  const char *ns_id, const char *uri_id, const char *ns_charstr,
3800 	  const char *uri_charstr, unsigned char **out_blob, int *out_len)
3801 {
3802 /* attempting to insert a new ISO Id */
3803     xmlNsPtr ns_id_ptr = NULL;
3804     xmlNsPtr ns_charstr_ptr = NULL;
3805     xmlNodePtr id_node;
3806     xmlNodePtr charstr_node;
3807     xmlNodePtr text;
3808     xmlNodePtr root = xmlDocGetRootElement (xml_doc);
3809     xmlNodePtr before = NULL;
3810     xmlChar *buf;
3811     int len;
3812     *out_blob = NULL;
3813     *out_len = 0;
3814     if (find_iso_node (root, node_name))
3815 	return 0;
3816 /* retrieving the ID NameSpace */
3817     if (uri_id != NULL)
3818 	ns_id_ptr = xmlSearchNsByHref (xml_doc, root, (xmlChar *) uri_id);
3819     if (ns_id_ptr == NULL)
3820 	ns_id_ptr = xmlSearchNs (xml_doc, root, (xmlChar *) ns_id);
3821 /* inserting the "ID" XML Node */
3822     id_node = xmlNewNode (ns_id_ptr, (xmlChar *) node_name);
3823     if (strcmp (node_name, "parentIdentifier") == 0)
3824       {
3825 	  /* attempting to identify the previous sibling */
3826 	  before = find_iso_sibling (root, "characterSet");
3827 	  if (before == NULL)
3828 	      before = find_iso_sibling (root, "language");
3829 	  if (before == NULL)
3830 	      before = find_iso_sibling (root, "fileIdentifier");
3831       }
3832     if (before)
3833 	xmlAddNextSibling (before, id_node);
3834     else
3835       {
3836 	  before = root->children;
3837 	  if (before)
3838 	      xmlAddPrevSibling (before, id_node);
3839 	  else
3840 	      xmlAddChild (root, id_node);
3841       }
3842     if (ns_id_ptr == NULL && ns_id != NULL && uri_id != NULL)
3843       {
3844 	  ns_id_ptr = xmlNewNs (root, (xmlChar *) uri_id, (xmlChar *) ns_id);
3845 	  xmlSetNs (id_node, ns_id_ptr);
3846       }
3847 /* retrieving the CharacterString NameSpace */
3848     if (uri_charstr != NULL)
3849 	ns_charstr_ptr =
3850 	    xmlSearchNsByHref (xml_doc, root, (xmlChar *) uri_charstr);
3851     if (ns_charstr_ptr == NULL)
3852 	ns_charstr_ptr = xmlSearchNs (xml_doc, root, (xmlChar *) ns_charstr);
3853 /* inserting the "CharacterString" XML Node */
3854     charstr_node = xmlNewNode (ns_charstr_ptr, (xmlChar *) "CharacterString");
3855     xmlAddChild (id_node, charstr_node);
3856     if (ns_charstr_ptr == NULL && ns_charstr != NULL && uri_charstr != NULL)
3857       {
3858 	  ns_charstr_ptr =
3859 	      xmlNewNs (root, (xmlChar *) uri_charstr, (xmlChar *) ns_charstr);
3860 	  xmlSetNs (charstr_node, ns_charstr_ptr);
3861       }
3862     text = xmlNewText ((xmlChar *) identifier);
3863     xmlAddChild (charstr_node, text);
3864     xmlDocDumpFormatMemory (xml_doc, &buf, &len, 0);
3865     if (buf == NULL)
3866 	return 0;
3867     *out_blob = buf;
3868     *out_len = len;
3869     return 1;
3870 }
3871 
3872 GAIAGEO_DECLARE int
gaiaXmlBlobAddFileId(const void * p_cache,const unsigned char * blob,int blob_size,const char * identifier,const char * ns_id,const char * uri_id,const char * ns_charstr,const char * uri_charstr,unsigned char ** new_blob,int * new_size)3873 gaiaXmlBlobAddFileId (const void *p_cache, const unsigned char *blob,
3874 		      int blob_size, const char *identifier, const char *ns_id,
3875 		      const char *uri_id, const char *ns_charstr,
3876 		      const char *uri_charstr, unsigned char **new_blob,
3877 		      int *new_size)
3878 {
3879 /* Return a new XmlBLOB buffer by inserting a FileId value */
3880     struct splite_internal_cache *cache =
3881 	(struct splite_internal_cache *) p_cache;
3882     int compressed = 0;
3883     int little_endian = 0;
3884     unsigned char flag;
3885     const unsigned char *ptr;
3886     short uri_len;
3887     short fileid_len;
3888     short parentid_len;
3889     int xml_len;
3890     int zip_len;
3891     short name_len;
3892     short title_len;
3893     short abstract_len;
3894     short geometry_len;
3895     char *schemaURI = NULL;
3896     unsigned char *xml;
3897     xmlDocPtr xml_doc;
3898     unsigned char *out_blob;
3899     int out_len;
3900     int legacy_blob = 0;
3901     int endian_arch = gaiaEndianArch ();
3902     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
3903 
3904     *new_blob = NULL;
3905     *new_size = 0;
3906 /* validity check */
3907     if (!gaiaIsValidXmlBlob (blob, blob_size))
3908 	return 0;		/* cannot be an XmlBLOB */
3909     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
3910 	legacy_blob = 1;
3911     flag = *(blob + 1);
3912     if ((flag & GAIA_XML_ISO_METADATA) == GAIA_XML_ISO_METADATA)
3913 	;
3914     else
3915 	return 0;		/* not an ISO Metadata XmlBLOB */
3916     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
3917 	little_endian = 1;
3918     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
3919 	compressed = 1;
3920     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
3921     zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
3922     ptr = blob + 11;
3923     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
3924     if (uri_len > 0)
3925       {
3926 	  schemaURI = malloc (uri_len + 1);
3927 	  memcpy (schemaURI, blob + 14, uri_len);
3928 	  *(schemaURI + uri_len) = '\0';
3929       }
3930     ptr += 3 + uri_len;
3931     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3932     ptr += 3 + fileid_len;
3933     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
3934     ptr += 3 + parentid_len;
3935     if (!legacy_blob)
3936       {
3937 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
3938 	  ptr += 3 + name_len;
3939       }
3940     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
3941     ptr += 3 + title_len;
3942     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
3943     ptr += 3 + abstract_len;
3944     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
3945     ptr += 3 + geometry_len;
3946     ptr++;
3947 
3948     if (compressed)
3949       {
3950 	  /* unzipping the XML payload */
3951 	  uLong refLen = xml_len;
3952 	  const Bytef *in = ptr;
3953 	  xml = malloc (xml_len + 1);
3954 	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
3955 	    {
3956 		/* uncompress error */
3957 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
3958 		free (xml);
3959 		return 0;
3960 	    }
3961 	  *(xml + xml_len) = '\0';
3962       }
3963     else
3964       {
3965 	  /* just copying the uncompressed XML payload */
3966 	  xml = malloc (xml_len + 1);
3967 	  memcpy (xml, ptr, xml_len);
3968 	  *(xml + xml_len) = '\0';
3969       }
3970 /* loading the XMLDocument */
3971     xmlSetGenericErrorFunc (NULL, silentError);
3972     xml_doc =
3973 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
3974     if (xml_doc == NULL)
3975       {
3976 	  /* parsing error; not a well-formed XML */
3977 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3978 	  return 0;
3979       }
3980 /* inserting the FileId value */
3981     addIsoId (xml_doc, "fileIdentifier", identifier, ns_id, uri_id, ns_charstr,
3982 	      uri_charstr, &out_blob, &out_len);
3983     free (xml);
3984     xmlFreeDoc (xml_doc);
3985     if (out_blob)
3986       {
3987 	  gaiaXmlToBlob (cache, out_blob, out_len, compressed, schemaURI,
3988 			 new_blob, new_size, NULL, NULL);
3989 #ifdef __MINGW32__
3990 /* MinGW is unable to statically link libxml2 if xmlFree() is declared */
3991 	  free (out_blob);
3992 #else
3993 	  xmlFree (out_blob);
3994 #endif
3995 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3996 	  return 1;
3997       }
3998     xmlSetGenericErrorFunc ((void *) stderr, NULL);
3999     return 0;
4000 }
4001 
4002 GAIAGEO_DECLARE int
gaiaXmlBlobAddParentId(const void * p_cache,const unsigned char * blob,int blob_size,const char * identifier,const char * ns_id,const char * uri_id,const char * ns_charstr,const char * uri_charstr,unsigned char ** new_blob,int * new_size)4003 gaiaXmlBlobAddParentId (const void *p_cache, const unsigned char *blob,
4004 			int blob_size, const char *identifier,
4005 			const char *ns_id, const char *uri_id,
4006 			const char *ns_charstr, const char *uri_charstr,
4007 			unsigned char **new_blob, int *new_size)
4008 {
4009 /* Return a new XmlBLOB buffer by inserting a ParentId value */
4010     struct splite_internal_cache *cache =
4011 	(struct splite_internal_cache *) p_cache;
4012     int compressed = 0;
4013     int little_endian = 0;
4014     unsigned char flag;
4015     const unsigned char *ptr;
4016     short uri_len;
4017     short fileid_len;
4018     short parentid_len;
4019     int xml_len;
4020     int zip_len;
4021     short name_len;
4022     short title_len;
4023     short abstract_len;
4024     short geometry_len;
4025     char *schemaURI = NULL;
4026     unsigned char *xml;
4027     xmlDocPtr xml_doc;
4028     unsigned char *out_blob;
4029     int out_len;
4030     int legacy_blob = 0;
4031     int endian_arch = gaiaEndianArch ();
4032     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
4033 
4034     *new_blob = NULL;
4035     *new_size = 0;
4036 /* validity check */
4037     if (!gaiaIsValidXmlBlob (blob, blob_size))
4038 	return 0;		/* cannot be an XmlBLOB */
4039     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
4040 	legacy_blob = 1;
4041     flag = *(blob + 1);
4042     if ((flag & GAIA_XML_ISO_METADATA) == GAIA_XML_ISO_METADATA)
4043 	;
4044     else
4045 	return 0;		/* not an ISO Metadata XmlBLOB */
4046     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
4047 	little_endian = 1;
4048     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
4049 	compressed = 1;
4050     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
4051     zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
4052     ptr = blob + 11;
4053     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
4054     if (uri_len > 0)
4055       {
4056 	  schemaURI = malloc (uri_len + 1);
4057 	  memcpy (schemaURI, blob + 14, uri_len);
4058 	  *(schemaURI + uri_len) = '\0';
4059       }
4060     ptr += 3 + uri_len;
4061     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4062     ptr += 3 + fileid_len;
4063     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4064     ptr += 3 + parentid_len;
4065     if (!legacy_blob)
4066       {
4067 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
4068 	  ptr += 3 + name_len;
4069       }
4070     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
4071     ptr += 3 + title_len;
4072     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
4073     ptr += 3 + abstract_len;
4074     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
4075     ptr += 3 + geometry_len;
4076     ptr++;
4077 
4078     if (compressed)
4079       {
4080 	  /* unzipping the XML payload */
4081 	  uLong refLen = xml_len;
4082 	  const Bytef *in = ptr;
4083 	  xml = malloc (xml_len + 1);
4084 	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
4085 	    {
4086 		/* uncompress error */
4087 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
4088 		free (xml);
4089 		return 0;
4090 	    }
4091 	  *(xml + xml_len) = '\0';
4092       }
4093     else
4094       {
4095 	  /* just copying the uncompressed XML payload */
4096 	  xml = malloc (xml_len + 1);
4097 	  memcpy (xml, ptr, xml_len);
4098 	  *(xml + xml_len) = '\0';
4099       }
4100 /* loading the XMLDocument */
4101     xmlSetGenericErrorFunc (NULL, silentError);
4102     xml_doc =
4103 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
4104     if (xml_doc == NULL)
4105       {
4106 	  /* parsing error; not a well-formed XML */
4107 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
4108 	  return 0;
4109       }
4110 /* inserting the ParentId value */
4111     addIsoId (xml_doc, "parentIdentifier", identifier, ns_id, uri_id,
4112 	      ns_charstr, uri_charstr, &out_blob, &out_len);
4113     free (xml);
4114     xmlFreeDoc (xml_doc);
4115     if (out_blob)
4116       {
4117 	  gaiaXmlToBlob (cache, out_blob, out_len, compressed, schemaURI,
4118 			 new_blob, new_size, NULL, NULL);
4119 #ifdef __MINGW32__
4120 /* MinGW is unable to statically link libxml2 if xmlFree() is declared */
4121 	  free (out_blob);
4122 #else
4123 	  xmlFree (out_blob);
4124 #endif
4125 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
4126 	  return 1;
4127       }
4128     xmlSetGenericErrorFunc ((void *) stderr, NULL);
4129     return 0;
4130 }
4131 
4132 GAIAGEO_DECLARE char *
gaiaXmlBlobGetName(const unsigned char * blob,int blob_size)4133 gaiaXmlBlobGetName (const unsigned char *blob, int blob_size)
4134 {
4135 /* Return the Name from a valid XmlBLOB buffer */
4136     int little_endian = 0;
4137     unsigned char flag;
4138     const unsigned char *ptr;
4139     short uri_len;
4140     short fileid_len;
4141     short parentid_len;
4142     short name_len;
4143     char *name;
4144     int endian_arch = gaiaEndianArch ();
4145 
4146 /* validity check */
4147     if (!gaiaIsValidXmlBlob (blob, blob_size))
4148 	return NULL;		/* cannot be an XmlBLOB */
4149     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
4150 	return NULL;
4151     flag = *(blob + 1);
4152     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
4153 	little_endian = 1;
4154     ptr = blob + 11;
4155     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
4156     ptr += 3 + uri_len;
4157     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4158     ptr += 3 + fileid_len;
4159     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4160     ptr += 3 + parentid_len;
4161     name_len = gaiaImport16 (ptr, little_endian, endian_arch);
4162     if (!name_len)
4163 	return NULL;
4164     ptr += 3;
4165 
4166     name = malloc (name_len + 1);
4167     memcpy (name, ptr, name_len);
4168     *(name + name_len) = '\0';
4169     return name;
4170 }
4171 
4172 GAIAGEO_DECLARE char *
gaiaXmlBlobGetTitle(const unsigned char * blob,int blob_size)4173 gaiaXmlBlobGetTitle (const unsigned char *blob, int blob_size)
4174 {
4175 /* Return the Title from a valid XmlBLOB buffer */
4176     int little_endian = 0;
4177     unsigned char flag;
4178     const unsigned char *ptr;
4179     short uri_len;
4180     short fileid_len;
4181     short parentid_len;
4182     short name_len;
4183     short title_len;
4184     char *title;
4185     int legacy_blob = 0;
4186     int endian_arch = gaiaEndianArch ();
4187 
4188 /* validity check */
4189     if (!gaiaIsValidXmlBlob (blob, blob_size))
4190 	return NULL;		/* cannot be an XmlBLOB */
4191     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
4192 	legacy_blob = 1;
4193     flag = *(blob + 1);
4194     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
4195 	little_endian = 1;
4196     ptr = blob + 11;
4197     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
4198     ptr += 3 + uri_len;
4199     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4200     ptr += 3 + fileid_len;
4201     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4202     ptr += 3 + parentid_len;
4203     if (!legacy_blob)
4204       {
4205 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
4206 	  ptr += 3 + name_len;
4207       }
4208     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
4209     if (!title_len)
4210 	return NULL;
4211     ptr += 3;
4212 
4213     title = malloc (title_len + 1);
4214     memcpy (title, ptr, title_len);
4215     *(title + title_len) = '\0';
4216     return title;
4217 }
4218 
4219 GAIAGEO_DECLARE char *
gaiaXmlBlobGetAbstract(const unsigned char * blob,int blob_size)4220 gaiaXmlBlobGetAbstract (const unsigned char *blob, int blob_size)
4221 {
4222 /* Return the Abstract from a valid XmlBLOB buffer */
4223     int little_endian = 0;
4224     unsigned char flag;
4225     const unsigned char *ptr;
4226     short uri_len;
4227     short fileid_len;
4228     short parentid_len;
4229     short name_len;
4230     short title_len;
4231     short abstract_len;
4232     char *abstract;
4233     int legacy_blob = 0;
4234     int endian_arch = gaiaEndianArch ();
4235 
4236 /* validity check */
4237     if (!gaiaIsValidXmlBlob (blob, blob_size))
4238 	return NULL;		/* cannot be an XmlBLOB */
4239     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
4240 	legacy_blob = 1;
4241     flag = *(blob + 1);
4242     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
4243 	little_endian = 1;
4244     ptr = blob + 11;
4245     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
4246     ptr += 3 + uri_len;
4247     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4248     ptr += 3 + fileid_len;
4249     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4250     ptr += 3 + parentid_len;
4251     if (!legacy_blob)
4252       {
4253 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
4254 	  ptr += 3 + name_len;
4255       }
4256     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
4257     ptr += 3 + title_len;
4258     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
4259     if (!abstract_len)
4260 	return NULL;
4261     ptr += 3;
4262 
4263     abstract = malloc (abstract_len + 1);
4264     memcpy (abstract, ptr, abstract_len);
4265     *(abstract + abstract_len) = '\0';
4266     return abstract;
4267 }
4268 
4269 GAIAGEO_DECLARE void
gaiaXmlBlobGetGeometry(const unsigned char * blob,int blob_size,unsigned char ** blob_geom,int * geom_size)4270 gaiaXmlBlobGetGeometry (const unsigned char *blob, int blob_size,
4271 			unsigned char **blob_geom, int *geom_size)
4272 {
4273 /* Return the Geometry from a valid XmlBLOB buffer */
4274     int little_endian = 0;
4275     unsigned char flag;
4276     const unsigned char *ptr;
4277     short uri_len;
4278     short fileid_len;
4279     short parentid_len;
4280     short name_len;
4281     short title_len;
4282     short abstract_len;
4283     short geometry_len;
4284     unsigned char *geometry;
4285     int legacy_blob = 0;
4286     int endian_arch = gaiaEndianArch ();
4287 
4288     *blob_geom = NULL;
4289     *geom_size = 0;
4290 
4291 /* validity check */
4292     if (!gaiaIsValidXmlBlob (blob, blob_size))
4293 	return;			/* cannot be an XmlBLOB */
4294     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
4295 	legacy_blob = 1;
4296     flag = *(blob + 1);
4297     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
4298 	little_endian = 1;
4299     ptr = blob + 11;
4300     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
4301     ptr += 3 + uri_len;
4302     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4303     ptr += 3 + fileid_len;
4304     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4305     ptr += 3 + parentid_len;
4306     if (!legacy_blob)
4307       {
4308 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
4309 	  ptr += 3 + name_len;
4310       }
4311     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
4312     ptr += 3 + title_len;
4313     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
4314     ptr += 3 + abstract_len;
4315     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
4316     if (!geometry_len)
4317 	return;
4318     ptr += 3;
4319 
4320     geometry = malloc (geometry_len);
4321     memcpy (geometry, ptr, geometry_len);
4322     *blob_geom = geometry;
4323     *geom_size = geometry_len;
4324 }
4325 
4326 GAIAGEO_DECLARE char *
gaiaXmlBlobGetEncoding(const unsigned char * blob,int blob_size)4327 gaiaXmlBlobGetEncoding (const unsigned char *blob, int blob_size)
4328 {
4329 /* Return the Charset Encoding from a valid XmlBLOB buffer */
4330     int compressed = 0;
4331     int little_endian = 0;
4332     unsigned char flag;
4333     const unsigned char *ptr;
4334     int xml_len;
4335     int zip_len;
4336     short uri_len;
4337     short fileid_len;
4338     short parentid_len;
4339     short name_len;
4340     short title_len;
4341     short abstract_len;
4342     short geometry_len;
4343     unsigned char *xml;
4344     xmlDocPtr xml_doc;
4345     char *encoding = NULL;
4346     int legacy_blob = 0;
4347     int endian_arch = gaiaEndianArch ();
4348     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
4349 
4350 /* validity check */
4351     if (!gaiaIsValidXmlBlob (blob, blob_size))
4352 	return NULL;		/* cannot be an XmlBLOB */
4353     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
4354 	legacy_blob = 1;
4355     flag = *(blob + 1);
4356     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
4357 	little_endian = 1;
4358     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
4359 	compressed = 1;
4360     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
4361     zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
4362     ptr = blob + 11;
4363     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
4364     ptr += 3 + uri_len;
4365     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4366     ptr += 3 + fileid_len;
4367     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4368     ptr += 3 + parentid_len;
4369     if (!legacy_blob)
4370       {
4371 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
4372 	  ptr += 3 + name_len;
4373       }
4374     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
4375     ptr += 3 + title_len;
4376     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
4377     ptr += 3 + abstract_len;
4378     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
4379     ptr += 3 + geometry_len;
4380     ptr++;
4381     if (compressed)
4382       {
4383 	  /* unzipping the XML payload */
4384 	  uLong refLen = xml_len;
4385 	  const Bytef *in = ptr;
4386 	  xml = malloc (xml_len + 1);
4387 	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
4388 	    {
4389 		/* uncompress error */
4390 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
4391 		free (xml);
4392 		return NULL;
4393 	    }
4394 	  *(xml + xml_len) = '\0';
4395       }
4396     else
4397       {
4398 	  /* just copying the uncompressed XML payload */
4399 	  xml = malloc (xml_len + 1);
4400 	  memcpy (xml, ptr, xml_len);
4401 	  *(xml + xml_len) = '\0';
4402       }
4403 /* retrieving the XMLDocument encoding */
4404     xmlSetGenericErrorFunc (NULL, silentError);
4405     xml_doc =
4406 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
4407     if (xml_doc == NULL)
4408       {
4409 	  /* parsing error; not a well-formed XML */
4410 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
4411 	  return NULL;
4412       }
4413     free (xml);
4414     if (xml_doc->encoding)
4415       {
4416 	  /* using the internal character enconding */
4417 	  int enclen = strlen ((const char *) xml_doc->encoding);
4418 	  encoding = malloc (enclen + 1);
4419 	  strcpy (encoding, (const char *) xml_doc->encoding);
4420 	  xmlFreeDoc (xml_doc);
4421 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
4422 	  return encoding;
4423       }
4424     xmlFreeDoc (xml_doc);
4425     xmlSetGenericErrorFunc ((void *) stderr, NULL);
4426     return NULL;
4427 }
4428 
4429 static void
parse_gpx_trkpt_values(xmlNodePtr node,double * x,double * y)4430 parse_gpx_trkpt_values (xmlNodePtr node, double *x, double *y)
4431 {
4432 /* fetching values from a GPX <trkpt> tag */
4433     struct _xmlAttr *attr;
4434 
4435     *x = 0.0;
4436     *y = 0.0;
4437 
4438     attr = node->properties;
4439     while (attr != NULL)
4440       {
4441 	  /* attributes */
4442 	  if (attr->type == XML_ATTRIBUTE_NODE)
4443 	    {
4444 		const char *name = (const char *) (attr->name);
4445 		xmlNode *text = attr->children;
4446 		if (strcmp (name, "lat") == 0 && text != NULL)
4447 		    *y = atof ((const char *) (text->content));
4448 		if (strcmp (name, "lon") == 0 && text != NULL)
4449 		    *x = atof ((const char *) (text->content));
4450 	    }
4451 	  attr = attr->next;
4452       }
4453 }
4454 
4455 static double
gpx_time2m(sqlite3_stmt * stmt,const char * timestamp)4456 gpx_time2m (sqlite3_stmt * stmt, const char *timestamp)
4457 {
4458 /* transforming a timestamp into an M-value */
4459     double m = 0.0;
4460     int ret;
4461 
4462     sqlite3_reset (stmt);
4463     sqlite3_clear_bindings (stmt);
4464     sqlite3_bind_text (stmt, 1, timestamp, strlen (timestamp), SQLITE_STATIC);
4465     while (1)
4466       {
4467 	  /* scrolling the result set rows */
4468 	  ret = sqlite3_step (stmt);
4469 	  if (ret == SQLITE_DONE)
4470 	      break;		/* end of result set */
4471 	  if (ret == SQLITE_ROW)
4472 	    {
4473 		if (sqlite3_column_type (stmt, 0) == SQLITE_FLOAT)
4474 		    m = sqlite3_column_double (stmt, 0);
4475 	    }
4476       }
4477     return m;
4478 }
4479 
4480 static void
parse_gpx_trkpt_children(xmlNodePtr node,sqlite3_stmt * stmt,double * z,double * m)4481 parse_gpx_trkpt_children (xmlNodePtr node, sqlite3_stmt * stmt, double *z,
4482 			  double *m)
4483 {
4484 /* parsing the children of a GPX <trkpt> tag */
4485     xmlNode *text;
4486     *z = 0.0;
4487     *m = 1721059.500000;	/* 0000-01-01T00:00:00Z */
4488 
4489     while (node)
4490       {
4491 	  if (node->type == XML_ELEMENT_NODE)
4492 	    {
4493 		const char *name = (const char *) (node->name);
4494 		if (strcmp (name, "ele") == 0)
4495 		  {
4496 		      text = node->children;
4497 		      if (text != NULL)
4498 			  *z = atof ((const char *) (text->content));
4499 		  }
4500 		if (strcmp (name, "time") == 0)
4501 		  {
4502 		      text = node->children;
4503 		      if (text != NULL)
4504 			  *m = gpx_time2m (stmt,
4505 					   (const char *) (text->content));
4506 		  }
4507 	    }
4508 	  node = node->next;
4509       }
4510 }
4511 
4512 static void
parse_gpx_trkpt_tag(xmlNodePtr node,sqlite3_stmt * stmt,gaiaDynamicLinePtr dyn)4513 parse_gpx_trkpt_tag (xmlNodePtr node, sqlite3_stmt * stmt,
4514 		     gaiaDynamicLinePtr dyn)
4515 {
4516 /* parsing a GPX <trkpt> tag */
4517 
4518     while (node)
4519       {
4520 	  if (node->type == XML_ELEMENT_NODE)
4521 	    {
4522 		const char *name = (const char *) (node->name);
4523 		if (strcmp (name, "trkpt") == 0)
4524 		  {
4525 		      double x;
4526 		      double y;
4527 		      double z;
4528 		      double m;
4529 		      parse_gpx_trkpt_values (node, &x, &y);
4530 		      parse_gpx_trkpt_children (node->children, stmt, &z, &m);
4531 		      gaiaAppendPointZMToDynamicLine (dyn, x, y, z, m);
4532 		  }
4533 	    }
4534 	  node = node->next;
4535       }
4536 }
4537 
4538 static void
gpx_copy_line(gaiaDynamicLinePtr dyn,gaiaGeomCollPtr geom)4539 gpx_copy_line (gaiaDynamicLinePtr dyn, gaiaGeomCollPtr geom)
4540 {
4541 /* copying a Linestring from a DynamicLine */
4542     gaiaPointPtr pt;
4543     int pts = 0;
4544     gaiaLinestringPtr ln;
4545     int iv;
4546 
4547     pt = dyn->First;
4548     while (pt != NULL)
4549       {
4550 	  /* counting how many points */
4551 	  pts++;
4552 	  pt = pt->Next;
4553       }
4554     if (pts < 2)
4555 	return;
4556 
4557     ln = gaiaAddLinestringToGeomColl (geom, pts);
4558     iv = 0;
4559     pt = dyn->First;
4560     while (pt != NULL)
4561       {
4562 	  /* copying points */
4563 	  gaiaSetPointXYZM (ln->Coords, iv, pt->X, pt->Y, pt->Z, pt->M);
4564 	  iv++;
4565 	  pt = pt->Next;
4566       }
4567 }
4568 
4569 static void
parse_gpx_trkseg_tag(xmlNodePtr node,sqlite3_stmt * stmt,gaiaGeomCollPtr geom)4570 parse_gpx_trkseg_tag (xmlNodePtr node, sqlite3_stmt * stmt,
4571 		      gaiaGeomCollPtr geom)
4572 {
4573 /* parsing a GPX <trkseg> tag */
4574 
4575     while (node)
4576       {
4577 	  if (node->type == XML_ELEMENT_NODE)
4578 	    {
4579 		const char *name = (const char *) (node->name);
4580 		if (strcmp (name, "trkseg") == 0)
4581 		  {
4582 		      gaiaDynamicLinePtr dyn = gaiaAllocDynamicLine ();
4583 		      parse_gpx_trkpt_tag (node->children, stmt, dyn);
4584 		      gpx_copy_line (dyn, geom);
4585 		      gaiaFreeDynamicLine (dyn);
4586 		  }
4587 	    }
4588 	  node = node->next;
4589       }
4590 }
4591 
4592 static void
parse_gpx_trk_tag(xmlNodePtr node,sqlite3_stmt * stmt,gaiaGeomCollPtr geom)4593 parse_gpx_trk_tag (xmlNodePtr node, sqlite3_stmt * stmt, gaiaGeomCollPtr geom)
4594 {
4595 /* parsing a GPX <trk> tag */
4596 
4597     while (node)
4598       {
4599 	  if (node->type == XML_ELEMENT_NODE)
4600 	    {
4601 		const char *name = (const char *) (node->name);
4602 		if (strcmp (name, "trk") == 0)
4603 		    parse_gpx_trkseg_tag (node->children, stmt, geom);
4604 	    }
4605 	  node = node->next;
4606       }
4607 }
4608 
4609 static void
parse_gpx_tag(xmlNodePtr node,sqlite3_stmt * stmt,gaiaGeomCollPtr geom)4610 parse_gpx_tag (xmlNodePtr node, sqlite3_stmt * stmt, gaiaGeomCollPtr geom)
4611 {
4612 /* parsing a GPX document */
4613 
4614     while (node)
4615       {
4616 	  if (node->type == XML_ELEMENT_NODE)
4617 	    {
4618 		const char *name = (const char *) (node->name);
4619 		if (strcmp (name, "gpx") == 0)
4620 		    parse_gpx_trk_tag (node->children, stmt, geom);
4621 	    }
4622 	  node = node->next;
4623       }
4624 }
4625 
4626 static void
parse_gpx(xmlDocPtr xml_doc,sqlite3_stmt * stmt,gaiaGeomCollPtr geom)4627 parse_gpx (xmlDocPtr xml_doc, sqlite3_stmt * stmt, gaiaGeomCollPtr geom)
4628 {
4629 /* attempting to parse a GPX document */
4630     xmlNodePtr root = xmlDocGetRootElement (xml_doc);
4631     parse_gpx_tag (root, stmt, geom);
4632 }
4633 
4634 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaXmlBlobMLineFromGPX(const unsigned char * blob,int blob_size,sqlite3 * sqlite)4635 gaiaXmlBlobMLineFromGPX (const unsigned char *blob, int blob_size,
4636 			 sqlite3 * sqlite)
4637 {
4638 /* Return a MultiLinestring Geometry from a valid XmlBLOB buffer of the GPX type */
4639     int ret;
4640     const char *sql;
4641     sqlite3_stmt *stmt = NULL;
4642     int compressed = 0;
4643     int little_endian = 0;
4644     unsigned char flag;
4645     const unsigned char *ptr;
4646     int xml_len;
4647     int zip_len;
4648     short uri_len;
4649     short fileid_len;
4650     short parentid_len;
4651     short name_len;
4652     short title_len;
4653     short abstract_len;
4654     short geometry_len;
4655     unsigned char *xml;
4656     xmlDocPtr xml_doc;
4657     int legacy_blob = 0;
4658     int endian_arch = gaiaEndianArch ();
4659     xmlGenericErrorFunc silentError = (xmlGenericErrorFunc) spliteSilentError;
4660     gaiaGeomCollPtr geom = NULL;
4661 
4662 /* validity check */
4663     if (!gaiaIsValidXmlBlob (blob, blob_size))
4664 	return NULL;		/* cannot be an XmlBLOB */
4665     if (!gaiaIsGpxXmlBlob (blob, blob_size))
4666 	return NULL;		/* not a GPX document */
4667     if (*(blob + 2) == GAIA_XML_LEGACY_HEADER)
4668 	legacy_blob = 1;
4669     flag = *(blob + 1);
4670     if ((flag & GAIA_XML_LITTLE_ENDIAN) == GAIA_XML_LITTLE_ENDIAN)
4671 	little_endian = 1;
4672     if ((flag & GAIA_XML_COMPRESSED) == GAIA_XML_COMPRESSED)
4673 	compressed = 1;
4674     xml_len = gaiaImport32 (blob + 3, little_endian, endian_arch);
4675     zip_len = gaiaImport32 (blob + 7, little_endian, endian_arch);
4676     ptr = blob + 11;
4677     uri_len = gaiaImport16 (ptr, little_endian, endian_arch);
4678     ptr += 3 + uri_len;
4679     fileid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4680     ptr += 3 + fileid_len;
4681     parentid_len = gaiaImport16 (ptr, little_endian, endian_arch);
4682     ptr += 3 + parentid_len;
4683     if (!legacy_blob)
4684       {
4685 	  name_len = gaiaImport16 (ptr, little_endian, endian_arch);
4686 	  ptr += 3 + name_len;
4687       }
4688     title_len = gaiaImport16 (ptr, little_endian, endian_arch);
4689     ptr += 3 + title_len;
4690     abstract_len = gaiaImport16 (ptr, little_endian, endian_arch);
4691     ptr += 3 + abstract_len;
4692     geometry_len = gaiaImport16 (ptr, little_endian, endian_arch);
4693     ptr += 3 + geometry_len;
4694     ptr++;
4695     if (compressed)
4696       {
4697 	  /* unzipping the XML payload */
4698 	  uLong refLen = xml_len;
4699 	  const Bytef *in = ptr;
4700 	  xml = malloc (xml_len + 1);
4701 	  if (uncompress (xml, &refLen, in, zip_len) != Z_OK)
4702 	    {
4703 		/* uncompress error */
4704 		spatialite_e ("XmlBLOB DEFLATE uncompress error\n");
4705 		free (xml);
4706 		return NULL;
4707 	    }
4708 	  *(xml + xml_len) = '\0';
4709       }
4710     else
4711       {
4712 	  /* just copying the uncompressed XML payload */
4713 	  xml = malloc (xml_len + 1);
4714 	  memcpy (xml, ptr, xml_len);
4715 	  *(xml + xml_len) = '\0';
4716       }
4717 /* attempting to parse the GPX document */
4718     xmlSetGenericErrorFunc (NULL, silentError);
4719     xml_doc =
4720 	xmlReadMemory ((const char *) xml, xml_len, "noname.xml", NULL, 0);
4721     if (xml_doc == NULL)
4722       {
4723 	  /* parsing error; not a well-formed XML */
4724 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
4725 	  return NULL;
4726       }
4727     free (xml);
4728 
4729 /* creating a prepared SQL statement transforming timestamps into M-values */
4730     sql = "SELECT julianday(?)";
4731     ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
4732     if (ret != SQLITE_OK)
4733 	goto end;
4734 
4735     geom = gaiaAllocGeomCollXYZM ();
4736     geom->Srid = 4326;
4737     geom->DeclaredType = GAIA_MULTILINESTRING;
4738     parse_gpx (xml_doc, stmt, geom);
4739     sqlite3_finalize (stmt);
4740 
4741     if (geom->FirstLinestring == NULL)
4742       {
4743 	  /* empty geometry: returning NULL */
4744 	  gaiaFreeGeomColl (geom);
4745 	  geom = NULL;
4746       }
4747 
4748   end:
4749     xmlFreeDoc (xml_doc);
4750     xmlSetGenericErrorFunc ((void *) stderr, NULL);
4751     return geom;
4752 }
4753 
4754 GAIAGEO_DECLARE char *
gaia_libxml2_version(void)4755 gaia_libxml2_version (void)
4756 {
4757 /* return the current LIBXML2 version */
4758     int len;
4759     char *version;
4760     const char *ver = LIBXML_DOTTED_VERSION;
4761     len = strlen (ver);
4762     version = malloc (len + 1);
4763     strcpy (version, ver);
4764     return version;
4765 }
4766 
4767 #endif /* end LIBXML2: supporting XML documents */
4768