1 /*
2  alloc_cache.c -- Gaia spatial support for SQLite
3 
4  version 5.0, 2020 August 1
5 
6  Author: Sandro Furieri a.furieri@lqt.it
7 
8  ------------------------------------------------------------------------------
9 
10  Version: MPL 1.1/GPL 2.0/LGPL 2.1
11 
12  The contents of this file are subject to the Mozilla Public License Version
13  1.1 (the "License"); you may not use this file except in compliance with
14  the License. You may obtain a copy of the License at
15  http://www.mozilla.org/MPL/
16 
17 Software distributed under the License is distributed on an "AS IS" basis,
18 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
19 for the specific language governing rights and limitations under the
20 License.
21 
22 The Original Code is the SpatiaLite library
23 
24 The Initial Developer of the Original Code is Alessandro Furieri
25 
26 Portions created by the Initial Developer are Copyright (C) 2013-2021
27 the Initial Developer. All Rights Reserved.
28 
29 Contributor(s):
30 
31 Alternatively, the contents of this file may be used under the terms of
32 either the GNU General Public License Version 2 or later (the "GPL"), or
33 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 in which case the provisions of the GPL or the LGPL are applicable instead
35 of those above. If you wish to allow use of your version of this file only
36 under the terms of either the GPL or the LGPL, and not to allow others to
37 use your version of this file under the terms of the MPL, indicate your
38 decision by deleting the provisions above and replace them with the notice
39 and other provisions required by the GPL or the LGPL. If you do not delete
40 the provisions above, a recipient may use your version of this file under
41 the terms of any one of the MPL, the GPL or the LGPL.
42 
43 */
44 
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 
49 #if defined(_WIN32)
50 #include <windows.h>
51 #include <libloaderapi.h>
52 #endif
53 
54 #if defined(_WIN32) && !defined(__MINGW32__)
55 #include <windows.h>
56 #else
57 #include <pthread.h>
58 #endif
59 
60 #if defined(_WIN32) && !defined(__MINGW32__)
61 #include "config-msvc.h"
62 #else
63 #include "config.h"
64 #endif
65 
66 #ifdef ENABLE_LIBXML2		/* only if LIBXML2 is supported */
67 #include <libxml/parser.h>
68 #endif /* end LIBXML2 conditional */
69 
70 #include <spatialite/sqlite.h>
71 #include <spatialite/debug.h>
72 
73 #include <spatialite.h>
74 #include <spatialite_private.h>
75 #include <spatialite/gg_advanced.h>
76 #include <spatialite/gaiamatrix.h>
77 
78 #ifndef OMIT_GEOS		/* including GEOS */
79 #ifdef GEOS_REENTRANT
80 #ifdef GEOS_ONLY_REENTRANT
81 #define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
82 #endif
83 #endif
84 #include <geos_c.h>
85 #endif
86 
87 #ifndef OMIT_PROJ		/* including PROJ.4 */
88 #ifdef PROJ_NEW			/* supporting new PROJ.6 */
89 #include <proj.h>
90 #else /* supporting old PROJ.4 */
91 #include <proj_api.h>
92 #endif
93 #endif
94 
95 #ifdef ENABLE_RTTOPO		/* including RTTOPO */
96 #include <librttopo.h>
97 #endif
98 
99 #ifndef GEOS_REENTRANT		/* only when using the obsolete partially thread-safe mode */
100 #include "cache_aux_1.h"
101 #endif /* end GEOS_REENTRANT */
102 
103 #ifdef _WIN32
104 #define strcasecmp	_stricmp
105 #endif /* not WIN32 */
106 
107 /* GLOBAL variables */
108 extern char *gaia_geos_error_msg;
109 extern char *gaia_geos_warning_msg;
110 
111 /* GLOBAL semaphores */
112 int gaia_already_initialized = 0;
113 #if defined(_WIN32) && !defined(__MINGW32__)
114 static CRITICAL_SECTION gaia_cache_semaphore;
115 #else
116 static pthread_mutex_t gaia_cache_semaphore = PTHREAD_MUTEX_INITIALIZER;
117 #endif
118 
119 #define GAIA_CONN_RESERVED	(char *)1
120 
121 #ifdef PROJ_NEW			/* supporting new PROJ.6 */
122 static void
gaia_proj_log_funct(void * data,int level,const char * err_msg)123 gaia_proj_log_funct (void *data, int level, const char *err_msg)
124 {
125 /* intercepting PROJ.6 error messages */
126     gaiaSetProjErrorMsg_r (data, err_msg);
127     if (level == 0)
128 	return;			/* just silencing stupid compiler warnings aboit unused args */
129 }
130 #endif
131 
132 static void
conn_geos_error(const char * msg,void * userdata)133 conn_geos_error (const char *msg, void *userdata)
134 {
135 /* reporting some GEOS error - thread safe */
136     int len;
137     struct splite_internal_cache *cache =
138 	(struct splite_internal_cache *) userdata;
139     if (cache == NULL)
140 	goto invalid_cache;
141     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
142 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
143 	goto invalid_cache;
144 
145     if (cache->gaia_geos_error_msg != NULL)
146 	free (cache->gaia_geos_error_msg);
147     cache->gaia_geos_error_msg = NULL;
148     if (msg)
149       {
150 	  if (cache->silent_mode == 0)
151 	      spatialite_e ("GEOS error: %s\n", msg);
152 	  len = strlen (msg);
153 	  cache->gaia_geos_error_msg = malloc (len + 1);
154 	  strcpy (cache->gaia_geos_error_msg, msg);
155       }
156     return;
157 
158   invalid_cache:
159     if (msg)
160 	spatialite_e ("GEOS error: %s\n", msg);
161 }
162 
163 static void
conn_geos_warning(const char * msg,void * userdata)164 conn_geos_warning (const char *msg, void *userdata)
165 {
166 /* reporting some GEOS warning - thread safe */
167     int len;
168     struct splite_internal_cache *cache =
169 	(struct splite_internal_cache *) userdata;
170     if (cache == NULL)
171 	goto invalid_cache;
172     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
173 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
174 	goto invalid_cache;
175 
176     if (cache->gaia_geos_warning_msg != NULL)
177 	free (cache->gaia_geos_warning_msg);
178     cache->gaia_geos_warning_msg = NULL;
179     if (msg)
180       {
181 	  if (cache->silent_mode == 0)
182 	      spatialite_e ("GEOS warning: %s\n", msg);
183 	  len = strlen (msg);
184 	  cache->gaia_geos_warning_msg = malloc (len + 1);
185 	  strcpy (cache->gaia_geos_warning_msg, msg);
186       }
187     return;
188 
189   invalid_cache:
190     if (msg)
191 	spatialite_e ("GEOS warning: %s\n", msg);
192 }
193 
194 static void
conn_rttopo_error(const char * fmt,va_list ap,void * userdata)195 conn_rttopo_error (const char *fmt, va_list ap, void *userdata)
196 {
197 /* reporting some RTTOPO error - thread safe */
198     char *msg = NULL;
199     int len;
200     struct splite_internal_cache *cache =
201 	(struct splite_internal_cache *) userdata;
202     if (cache == NULL)
203 	goto invalid_cache;
204     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
205 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
206 	goto invalid_cache;
207 
208     if (cache->gaia_rttopo_error_msg != NULL)
209 	free (cache->gaia_rttopo_error_msg);
210     cache->gaia_rttopo_error_msg = NULL;
211 
212     msg = sqlite3_vmprintf (fmt, ap);
213     if (msg)
214       {
215 	  if (strlen (msg) > 0)
216 	    {
217 		if (cache->silent_mode == 0)
218 		    spatialite_e ("RTTOPO error: %s\n\n", msg);
219 		len = strlen (msg);
220 		cache->gaia_rttopo_error_msg = malloc (len + 1);
221 		strcpy (cache->gaia_rttopo_error_msg, msg);
222 	    }
223 	  sqlite3_free (msg);
224       }
225     return;
226 
227   invalid_cache:
228     if (msg)
229       {
230 	  spatialite_e ("RTTOPO error: %s\n", msg);
231 	  sqlite3_free (msg);
232       }
233 }
234 
235 static void
conn_rttopo_warning(const char * fmt,va_list ap,void * userdata)236 conn_rttopo_warning (const char *fmt, va_list ap, void *userdata)
237 {
238 /* reporting some RTTOPO warning - thread safe */
239     char *msg = NULL;
240     int len;
241     struct splite_internal_cache *cache =
242 	(struct splite_internal_cache *) userdata;
243     if (cache == NULL)
244 	goto invalid_cache;
245     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
246 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
247 	goto invalid_cache;
248 
249     if (cache->gaia_rttopo_warning_msg != NULL)
250 	free (cache->gaia_rttopo_warning_msg);
251     cache->gaia_rttopo_warning_msg = NULL;
252 
253     msg = sqlite3_vmprintf (fmt, ap);
254     if (msg)
255       {
256 	  if (strlen (msg) > 0)
257 	    {
258 		/* disabled so to stop endless warnings caused by topo-tolerance */
259 		if (cache->silent_mode == 0)
260 		    spatialite_e ("RTTOPO warning: %s\n", msg);
261 		len = strlen (msg);
262 		cache->gaia_rttopo_warning_msg = malloc (len + 1);
263 		strcpy (cache->gaia_rttopo_warning_msg, msg);
264 	    }
265 	  sqlite3_free (msg);
266       }
267     return;
268 
269   invalid_cache:
270     if (msg)
271       {
272 	  spatialite_e ("RTTOPO warning: %s\n\n", msg);
273 	  sqlite3_free (msg);
274       }
275 }
276 
277 #ifndef GEOS_REENTRANT		/* only when using the obsolete partially thread-safe mode */
278 static void
setGeosErrorMsg(int pool_index,const char * msg)279 setGeosErrorMsg (int pool_index, const char *msg)
280 {
281 /* setting the latest GEOS error message */
282     struct splite_connection *p = &(splite_connection_pool[pool_index]);
283     struct splite_internal_cache *cache =
284 	(struct splite_internal_cache *) (p->conn_ptr);
285     conn_geos_error (msg, cache);
286 }
287 
288 static void
setGeosWarningMsg(int pool_index,const char * msg)289 setGeosWarningMsg (int pool_index, const char *msg)
290 {
291 /* setting the latest GEOS error message */
292     struct splite_connection *p = &(splite_connection_pool[pool_index]);
293     struct splite_internal_cache *cache =
294 	(struct splite_internal_cache *) (p->conn_ptr);
295     conn_geos_warning (msg, cache);
296 }
297 
298 static void
geos_error_r(int pool_index,const char * fmt,va_list ap)299 geos_error_r (int pool_index, const char *fmt, va_list ap)
300 {
301 /* reporting some GEOS error - thread safe */
302     char *msg;
303     msg = sqlite3_vmprintf (fmt, ap);
304     if (msg)
305       {
306 	  spatialite_e ("GEOS error: %s\n", msg);
307 	  setGeosErrorMsg (pool_index, msg);
308 	  sqlite3_free (msg);
309       }
310     else
311 	setGeosErrorMsg (pool_index, NULL);
312 }
313 
314 static void
geos_warning_r(int pool_index,const char * fmt,va_list ap)315 geos_warning_r (int pool_index, const char *fmt, va_list ap)
316 {
317 /* reporting some GEOS warning - thread safe */
318     char *msg;
319     msg = sqlite3_vmprintf (fmt, ap);
320     if (msg)
321       {
322 	  spatialite_e ("GEOS warning: %s\n", msg);
323 	  setGeosWarningMsg (pool_index, msg);
324 	  sqlite3_free (msg);
325       }
326     else
327 	setGeosWarningMsg (pool_index, NULL);
328 }
329 
330 #include "cache_aux_2.h"
331 
332 static int
find_free_connection()333 find_free_connection ()
334 {
335     int i;
336     for (i = 0; i < SPATIALITE_MAX_CONNECTIONS; i++)
337       {
338 	  struct splite_connection *p = &(splite_connection_pool[i]);
339 	  if (p->conn_ptr == NULL)
340 	    {
341 		p->conn_ptr = GAIA_CONN_RESERVED;
342 		return i;
343 	    }
344       }
345     spatialite_e ("ERROR: Too many connections: max %d\n",
346 		  SPATIALITE_MAX_CONNECTIONS);
347     return -1;
348 }
349 
350 static void
confirm(int i,void * cache)351 confirm (int i, void *cache)
352 {
353 /* marking the slot as definitely reserved */
354     struct splite_connection *p = &(splite_connection_pool[i]);
355     p->conn_ptr = cache;
356 }
357 
358 static void
invalidate(int i)359 invalidate (int i)
360 {
361 /* definitely releasing the slot */
362     struct splite_connection *p = &(splite_connection_pool[i]);
363     p->conn_ptr = NULL;
364 }
365 #endif /* END obsolete partially thread-safe mode */
366 
367 static void
init_splite_internal_cache(struct splite_internal_cache * cache)368 init_splite_internal_cache (struct splite_internal_cache *cache)
369 {
370 /* common initialization of the internal cache */
371     gaiaOutBufferPtr out;
372     int i;
373     const char *tinyPoint;
374     struct splite_geos_cache_item *p;
375     struct splite_xmlSchema_cache_item *p_xmlSchema;
376     if (cache == NULL)
377 	return;
378 
379     cache->magic1 = SPATIALITE_CACHE_MAGIC1;
380     cache->magic2 = SPATIALITE_CACHE_MAGIC2;
381     cache->gpkg_mode = 0;
382     cache->gpkg_amphibious_mode = 0;
383     cache->decimal_precision = -1;
384     cache->GEOS_handle = NULL;
385     cache->PROJ_handle = NULL;
386     cache->proj6_cached = 0;
387     cache->proj6_cached_pj = NULL;
388     cache->proj6_cached_string_1 = NULL;
389     cache->proj6_cached_string_2 = NULL;
390     cache->proj6_cached_area = NULL;
391     cache->is_pause_enabled = 0;
392     cache->RTTOPO_handle = NULL;
393     cache->cutterMessage = NULL;
394     cache->storedProcError = NULL;
395     cache->createRoutingError = NULL;
396     cache->SqlProcLogfile = NULL;
397     cache->SqlProcLogfileAppend = 0;
398     cache->SqlProcLog = NULL;
399     cache->SqlProcContinue = 1;
400     cache->SqlProcRetValue = gaia_alloc_variant ();
401     cache->pool_index = -1;
402     cache->gaia_proj_error_msg = NULL;
403     cache->gaia_geos_error_msg = NULL;
404     cache->gaia_geos_warning_msg = NULL;
405     cache->gaia_geosaux_error_msg = NULL;
406     cache->gaia_rttopo_error_msg = NULL;
407     cache->gaia_rttopo_warning_msg = NULL;
408     cache->silent_mode = 0;
409     cache->tinyPointEnabled = 0;
410     tinyPoint = getenv ("SPATIALITE_TINYPOINT");
411     if (tinyPoint == NULL)
412 	;
413     else if (atoi (tinyPoint) != 0)
414 	cache->tinyPointEnabled = 1;
415     cache->lastPostgreSqlError = NULL;
416 #ifndef OMIT_GEOS		/* including GEOS */
417     cache->buffer_end_cap_style = GEOSBUF_CAP_ROUND;
418     cache->buffer_join_style = GEOSBUF_JOIN_ROUND;
419     cache->buffer_mitre_limit = 5.0;
420     cache->buffer_quadrant_segments = 30;
421 #endif /* end including GEOS */
422 /* initializing an empty linked list of Topologies */
423     cache->firstTopology = NULL;
424     cache->lastTopology = NULL;
425     cache->next_topo_savepoint = 0;
426     cache->first_topo_svpt = NULL;
427     cache->last_topo_svpt = NULL;
428     cache->firstNetwork = NULL;
429     cache->lastNetwork = NULL;
430     cache->next_network_savepoint = 0;
431     cache->first_net_svpt = NULL;
432     cache->last_net_svpt = NULL;
433 /* initializing Sequences */
434     cache->first_seq = NULL;
435     cache->last_seq = NULL;
436     cache->ok_last_used_sequence = 0;
437     cache->last_used_sequence_val = 0;
438 /* initializing Virtual BBOXes */
439     cache->first_vtable_extent = NULL;
440     cache->last_vtable_extent = NULL;
441 /* initializing the XML error buffers */
442     out = malloc (sizeof (gaiaOutBuffer));
443     gaiaOutBufferInitialize (out);
444     cache->xmlParsingErrors = out;
445     out = malloc (sizeof (gaiaOutBuffer));
446     gaiaOutBufferInitialize (out);
447     cache->xmlSchemaValidationErrors = out;
448     out = malloc (sizeof (gaiaOutBuffer));
449     gaiaOutBufferInitialize (out);
450     cache->xmlXPathErrors = out;
451 /* initializing the GEOS cache */
452     p = &(cache->cacheItem1);
453     memset (p->gaiaBlob, '\0', 64);
454     p->gaiaBlobSize = 0;
455     p->crc32 = 0;
456     p->geosGeom = NULL;
457     p->preparedGeosGeom = NULL;
458     p = &(cache->cacheItem2);
459     memset (p->gaiaBlob, '\0', 64);
460     p->gaiaBlobSize = 0;
461     p->crc32 = 0;
462     p->geosGeom = NULL;
463     p->preparedGeosGeom = NULL;
464     for (i = 0; i < MAX_XMLSCHEMA_CACHE; i++)
465       {
466 	  /* initializing the XmlSchema cache */
467 	  p_xmlSchema = &(cache->xmlSchemaCache[i]);
468 	  p_xmlSchema->timestamp = 0;
469 	  p_xmlSchema->schemaURI = NULL;
470 	  p_xmlSchema->schemaDoc = NULL;
471 	  p_xmlSchema->parserCtxt = NULL;
472 	  p_xmlSchema->schema = NULL;
473       }
474 }
475 
476 #ifdef GEOS_REENTRANT		/* reentrant (thread-safe) initialization */
477 static void *
spatialite_alloc_reentrant()478 spatialite_alloc_reentrant ()
479 {
480 /*
481  * allocating and initializing an empty internal cache
482  * fully reentrant (thread-safe) version requiring GEOS >= 3.5.0
483 */
484     struct splite_internal_cache *cache = NULL;
485 #ifdef PROJ_NEW			/* supporting new PROJ.6 */
486     int proj_set_ext_var = 0;
487     char *proj_db = NULL;
488     const char *proj_db_path = NULL;
489 #ifdef _WIN32
490     char *win_prefix = NULL;
491 #endif
492 #endif
493 
494 /* attempting to implicitly initialize the library */
495     spatialite_initialize ();
496 
497     cache = malloc (sizeof (struct splite_internal_cache));
498     if (cache == NULL)
499 	goto done;
500     init_splite_internal_cache (cache);
501 
502 /* initializing GEOS and PROJ.4 handles */
503 
504 #ifndef OMIT_GEOS		/* initializing GEOS */
505     cache->GEOS_handle = GEOS_init_r ();
506     GEOSContext_setNoticeMessageHandler_r (cache->GEOS_handle,
507 					   conn_geos_warning, cache);
508     GEOSContext_setErrorMessageHandler_r (cache->GEOS_handle, conn_geos_error,
509 					  cache);
510 #endif /* end GEOS  */
511 
512 #ifndef OMIT_PROJ		/* initializing the PROJ.4 context */
513 #ifdef PROJ_NEW			/* supporting new PROJ.6 */
514     cache->PROJ_handle = proj_context_create ();
515     proj_log_func (cache->PROJ_handle, cache, gaia_proj_log_funct);	/* installing an error handler routine */
516     if (getenv ("PROJ_LIB") != NULL)
517 	proj_db = sqlite3_mprintf ("%s/proj.db", getenv ("PROJ_LIB"));
518     if (proj_db != NULL)
519       {
520 	  proj_context_set_database_path (cache->PROJ_handle, proj_db,
521 					  NULL, NULL);
522 	  sqlite3_free (proj_db);
523 	  goto skip_win;
524       }
525 #ifdef _WIN32			/* only for Windows - checking the default locations for PROJ.6 DB */
526     proj_set_ext_var = 1;
527     proj_db_path = proj_context_get_database_path (cache->PROJ_handle);
528     if (proj_db_path == NULL)
529       {
530 	  char *win_path;
531 	  char *exe_path;
532 	  int max_len = 8192;
533 	  int i;
534 	  exe_path = malloc (max_len);
535 	  GetModuleFileNameA (NULL, exe_path, max_len);
536 	  if (exe_path != NULL)
537 	    {
538 		/* searching within the EXE's launch dir */
539 		for (i = strlen (exe_path) - 1; i >= 0; i--)
540 		  {
541 		      /* truncating the EXE name */
542 		      if (exe_path[i] == '\\')
543 			{
544 			    exe_path[i] = '\0';
545 			    break;
546 			}
547 		  }
548 		win_prefix = sqlite3_mprintf ("%s", exe_path);
549 		win_path = sqlite3_mprintf ("%s\\proj.db", exe_path);
550 		free (exe_path);
551 		proj_context_set_database_path (cache->PROJ_handle, win_path,
552 						NULL, NULL);
553 		proj_db_path =
554 		    proj_context_get_database_path (cache->PROJ_handle);
555 		sqlite3_free (win_path);
556 	    }
557 	  if (proj_db_path == NULL)
558 	    {
559 		/* searching on PUBLIC dir */
560 		if (win_prefix != NULL)
561 		    sqlite3_free (win_prefix);
562 		win_prefix =
563 		    sqlite3_mprintf ("%s\\spatialite\\proj", getenv ("PUBLIC"));
564 		win_path =
565 		    sqlite3_mprintf ("%s\\spatialite\\proj\\proj.db",
566 				     getenv ("PUBLIC"));
567 		proj_context_set_database_path (cache->PROJ_handle, win_path,
568 						NULL, NULL);
569 		proj_db_path =
570 		    proj_context_get_database_path (cache->PROJ_handle);
571 		sqlite3_free (win_path);
572 	    }
573 	  if (proj_db_path == NULL)
574 	    {
575 		/* searching on USER dir */
576 		if (win_prefix != NULL)
577 		    sqlite3_free (win_prefix);
578 		win_prefix =
579 		    sqlite3_mprintf ("%s\\spatialite\\proj",
580 				     getenv ("USERPROFILE"));
581 		win_path =
582 		    sqlite3_mprintf ("%s\\spatialite\\proj\\proj.db",
583 				     getenv ("USERPROFILE"));
584 		proj_context_set_database_path (cache->PROJ_handle, win_path,
585 						NULL, NULL);
586 		sqlite3_free (win_path);
587 	    }
588       }
589 #endif
590   skip_win:
591     proj_db_path = proj_context_get_database_path (cache->PROJ_handle);
592 #ifdef _WIN32			/* only for Windows - setting PROJ_LIB */
593     if (proj_set_ext_var && win_prefix && proj_db_path)
594       {
595 	  char *proj_lib = sqlite3_mprintf ("PROJ_LIB=%s", win_prefix);
596 	  _putenv (proj_lib);
597 	  sqlite3_free (proj_lib);
598       }
599     if (win_prefix != NULL)
600 	sqlite3_free (win_prefix);
601 #else
602 /* suppressing stupid compiler warnings about unused args */
603     if (proj_db_path == NULL && proj_set_ext_var < 0)
604 	proj_set_ext_var = 1;
605 #endif
606 
607 #else /* supporting old PROJ.4 */
608     cache->PROJ_handle = pj_ctx_alloc ();
609 #endif
610 #endif /* end PROJ.4  */
611 
612 #ifdef ENABLE_RTTOPO		/* initializing the RTTOPO context */
613     cache->RTTOPO_handle = rtgeom_init (NULL, NULL, NULL);
614     rtgeom_set_error_logger (cache->RTTOPO_handle, conn_rttopo_error, cache);
615     rtgeom_set_notice_logger (cache->RTTOPO_handle, conn_rttopo_warning, cache);
616 #endif /* end RTTOPO */
617 
618   done:
619     return cache;
620 }
621 #endif /* end GEOS_REENTRANT */
622 
623 SPATIALITE_DECLARE void *
spatialite_alloc_connection()624 spatialite_alloc_connection ()
625 {
626 /* allocating and initializing an empty internal cache */
627 
628 #ifdef GEOS_REENTRANT		/* reentrant (thread-safe) initialization */
629     return spatialite_alloc_reentrant ();
630 #else /* end GEOS_REENTRANT */
631     struct splite_internal_cache *cache = NULL;
632     int pool_index;
633 
634 /* attempting to implicitly initialize the library */
635     spatialite_initialize ();
636 
637 /* locking the semaphore */
638     splite_cache_semaphore_lock ();
639 
640     pool_index = find_free_connection ();
641 
642     if (pool_index < 0)
643 	goto done;
644 
645     cache = malloc (sizeof (struct splite_internal_cache));
646     if (cache == NULL)
647       {
648 	  invalidate (pool_index);
649 	  goto done;
650       }
651     init_splite_internal_cache (cache);
652     cache->pool_index = pool_index;
653     confirm (pool_index, cache);
654 
655 #include "cache_aux_3.h"
656 
657 /* initializing GEOS and PROJ.4 handles */
658 
659 #ifndef OMIT_GEOS		/* initializing GEOS */
660     cache->GEOS_handle = initGEOS_r (cache->geos_warning, cache->geos_error);
661 #endif /* end GEOS  */
662 
663 #ifndef OMIT_PROJ		/* initializing the PROJ.4 context */
664     cache->PROJ_handle = pj_ctx_alloc ();
665 #endif /* end PROJ.4  */
666 
667   done:
668 /* unlocking the semaphore */
669     splite_cache_semaphore_unlock ();
670     return cache;
671 #endif
672 }
673 
674 SPATIALITE_DECLARE void
spatialite_finalize_topologies(const void * ptr)675 spatialite_finalize_topologies (const void *ptr)
676 {
677 #ifdef ENABLE_RTTOPO		/* only if RTTOPO is enabled */
678 /* freeing all Topology Accessor Objects */
679     struct splite_savepoint *p_svpt;
680     struct splite_savepoint *p_svpt_n;
681     struct splite_internal_cache *cache = (struct splite_internal_cache *) ptr;
682     if (cache == NULL)
683 	return;
684     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
685 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
686 	return;
687     free_internal_cache_topologies (cache->firstTopology);
688     cache->firstTopology = NULL;
689     cache->lastTopology = NULL;
690     p_svpt = cache->first_topo_svpt;
691     while (p_svpt != NULL)
692       {
693 	  p_svpt_n = p_svpt->next;
694 	  if (p_svpt->savepoint_name != NULL)
695 	      sqlite3_free (p_svpt->savepoint_name);
696 	  free (p_svpt);
697 	  p_svpt = p_svpt_n;
698       }
699     cache->first_topo_svpt = NULL;
700     cache->last_topo_svpt = NULL;
701     free_internal_cache_networks (cache->firstNetwork);
702     cache->firstNetwork = NULL;
703     cache->lastTopology = NULL;
704     p_svpt = cache->first_net_svpt;
705     while (p_svpt != NULL)
706       {
707 	  p_svpt_n = p_svpt->next;
708 	  if (p_svpt->savepoint_name != NULL)
709 	      sqlite3_free (p_svpt->savepoint_name);
710 	  free (p_svpt);
711 	  p_svpt = p_svpt_n;
712       }
713     cache->first_net_svpt = NULL;
714     cache->last_net_svpt = NULL;
715 #else
716     if (ptr == NULL)
717 	return;			/* silencing stupid compiler warnings */
718 #endif /* end RTTOPO conditionals */
719 }
720 
721 static void
free_sequences(struct splite_internal_cache * cache)722 free_sequences (struct splite_internal_cache *cache)
723 {
724 /* freeing all Sequences */
725     gaiaSequencePtr pS;
726     gaiaSequencePtr pSn;
727 
728     pS = cache->first_seq;
729     while (pS != NULL)
730       {
731 	  pSn = pS->next;
732 	  if (pS->seq_name != NULL)
733 	      free (pS->seq_name);
734 	  free (pS);
735 	  pS = pSn;
736       }
737 }
738 
739 static void
free_vtable_extents(struct splite_internal_cache * cache)740 free_vtable_extents (struct splite_internal_cache *cache)
741 {
742 /* freeing all Virtual BBOXes */
743     struct splite_vtable_extent *pS;
744     struct splite_vtable_extent *pSn;
745 
746     pS = cache->first_vtable_extent;
747     while (pS != NULL)
748       {
749 	  pSn = pS->next;
750 	  if (pS->table != NULL)
751 	      free (pS->table);
752 	  free (pS);
753 	  pS = pSn;
754       }
755 }
756 
757 SPATIALITE_PRIVATE void
add_vtable_extent(const char * table,double minx,double miny,double maxx,double maxy,int srid,const void * p_cache)758 add_vtable_extent (const char *table, double minx,
759 		   double miny, double maxx,
760 		   double maxy, int srid, const void *p_cache)
761 {
762 /* adding a Virtual Full Extent */
763     struct splite_internal_cache *cache =
764 	(struct splite_internal_cache *) p_cache;
765     struct splite_vtable_extent *vtable =
766 	malloc (sizeof (struct splite_vtable_extent));
767     int len = strlen (table);
768     vtable->table = malloc (len + 1);
769     strcpy (vtable->table, table);
770     vtable->minx = minx;
771     vtable->miny = miny;
772     vtable->maxx = maxx;
773     vtable->maxy = maxy;
774     vtable->srid = srid;
775     vtable->prev = cache->last_vtable_extent;
776     vtable->next = NULL;
777     if (cache->first_vtable_extent == NULL)
778 	cache->first_vtable_extent = vtable;
779     if (cache->last_vtable_extent != NULL)
780 	cache->last_vtable_extent->next = vtable;
781     cache->last_vtable_extent = vtable;
782 }
783 
784 SPATIALITE_PRIVATE void
remove_vtable_extent(const char * table,const void * p_cache)785 remove_vtable_extent (const char *table, const void *p_cache)
786 {
787 /* adding a Virtual Full Extent */
788     struct splite_internal_cache *cache =
789 	(struct splite_internal_cache *) p_cache;
790     struct splite_vtable_extent *vtable_n;
791     struct splite_vtable_extent *vtable = cache->first_vtable_extent;
792     while (vtable != NULL)
793       {
794 	  vtable_n = vtable->next;
795 	  if (strcasecmp (vtable->table, table) == 0)
796 	    {
797 		if (vtable->table != NULL)
798 		    free (vtable->table);
799 		if (vtable->next != NULL)
800 		    vtable->next->prev = vtable->prev;
801 		if (vtable->prev != NULL)
802 		    vtable->prev->next = vtable->next;
803 		if (cache->first_vtable_extent == vtable)
804 		    cache->first_vtable_extent = vtable->next;
805 		if (cache->last_vtable_extent == vtable)
806 		    cache->last_vtable_extent = vtable->prev;
807 		free (vtable);
808 	    }
809 	  vtable = vtable_n;
810       }
811 }
812 
813 SPATIALITE_PRIVATE int
get_vtable_extent(const char * table,double * minx,double * miny,double * maxx,double * maxy,int * srid,const void * p_cache)814 get_vtable_extent (const char *table, double *minx, double *miny, double *maxx,
815 		   double *maxy, int *srid, const void *p_cache)
816 {
817 /* retrieving a Virtual Full Extent */
818     struct splite_internal_cache *cache =
819 	(struct splite_internal_cache *) p_cache;
820     struct splite_vtable_extent *vtable = cache->first_vtable_extent;
821     while (vtable != NULL)
822       {
823 	  if (strcasecmp (vtable->table, table) == 0)
824 	    {
825 		*minx = vtable->minx;
826 		*miny = vtable->miny;
827 		*maxx = vtable->maxx;
828 		*maxy = vtable->maxy;
829 		*srid = vtable->srid;
830 		return 1;
831 	    }
832 	  vtable = vtable->next;
833       }
834     return 0;
835 }
836 
837 SPATIALITE_PRIVATE void
free_internal_cache(struct splite_internal_cache * cache)838 free_internal_cache (struct splite_internal_cache *cache)
839 {
840 /* freeing an internal cache */
841     struct splite_geos_cache_item *p;
842 #ifndef OMIT_GEOS
843     GEOSContextHandle_t handle = NULL;
844 #endif
845 
846 #ifdef ENABLE_LIBXML2
847     int i;
848     struct splite_xmlSchema_cache_item *p_xmlSchema;
849 #endif
850 
851     if (cache == NULL)
852 	return;
853     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
854 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
855 	return;
856 
857     if (cache->SqlProcRetValue != NULL)
858 	gaia_free_variant (cache->SqlProcRetValue);
859     cache->SqlProcRetValue = NULL;
860 
861 #ifndef OMIT_GEOS
862     handle = cache->GEOS_handle;
863     if (handle != NULL)
864 #ifdef GEOS_REENTRANT		/* reentrant (thread-safe) initialization */
865 	GEOS_finish_r (handle);
866 #else /* end GEOS_REENTRANT */
867 	finishGEOS_r (handle);
868 #endif
869     cache->GEOS_handle = NULL;
870     gaiaResetGeosMsg_r (cache);
871 #endif
872 
873 #ifndef OMIT_PROJ
874 #ifdef PROJ_NEW			/* supporting new PROJ.6 */
875     if (cache->proj6_cached_string_1 != NULL)
876 	free (cache->proj6_cached_string_1);
877     if (cache->proj6_cached_string_2 != NULL)
878 	free (cache->proj6_cached_string_2);
879     if (cache->proj6_cached_area != NULL)
880 	free (cache->proj6_cached_area);
881     if (cache->proj6_cached_pj != NULL)
882 	proj_destroy (cache->proj6_cached_pj);
883     if (cache->PROJ_handle != NULL)
884 	proj_context_destroy (cache->PROJ_handle);
885     cache->PROJ_handle = NULL;
886     cache->proj6_cached = 0;
887     cache->proj6_cached_pj = NULL;
888     cache->proj6_cached_string_1 = NULL;
889     cache->proj6_cached_string_2 = NULL;
890     cache->proj6_cached_area = NULL;
891 #else /* supporting old PROJ.4 */
892     if (cache->PROJ_handle != NULL)
893 	pj_ctx_free (cache->PROJ_handle);
894     cache->PROJ_handle = NULL;
895 #endif
896 #endif
897 
898 /* freeing PROJ error buffer */
899     if (cache->gaia_proj_error_msg)
900 	sqlite3_free (cache->gaia_proj_error_msg);
901 
902 /* freeing GEOS error buffers */
903     if (cache->gaia_geos_error_msg)
904 	free (cache->gaia_geos_error_msg);
905     if (cache->gaia_geos_warning_msg)
906 	free (cache->gaia_geos_warning_msg);
907     if (cache->gaia_geosaux_error_msg)
908 	free (cache->gaia_geosaux_error_msg);
909 
910 /* freeing RTTOPO error buffers */
911     if (cache->gaia_rttopo_error_msg)
912 	free (cache->gaia_rttopo_error_msg);
913     if (cache->gaia_rttopo_warning_msg)
914 	free (cache->gaia_rttopo_warning_msg);
915 
916 /* freeing the XML error buffers */
917     gaiaOutBufferReset (cache->xmlParsingErrors);
918     gaiaOutBufferReset (cache->xmlSchemaValidationErrors);
919     gaiaOutBufferReset (cache->xmlXPathErrors);
920     free (cache->xmlParsingErrors);
921     free (cache->xmlSchemaValidationErrors);
922     free (cache->xmlXPathErrors);
923 
924 /* freeing the GEOS cache */
925     p = &(cache->cacheItem1);
926     splite_free_geos_cache_item_r (cache, p);
927     p = &(cache->cacheItem2);
928     splite_free_geos_cache_item_r (cache, p);
929 #ifdef ENABLE_LIBXML2
930     for (i = 0; i < MAX_XMLSCHEMA_CACHE; i++)
931       {
932 	  /* freeing the XmlSchema cache */
933 	  p_xmlSchema = &(cache->xmlSchemaCache[i]);
934 	  splite_free_xml_schema_cache_item (p_xmlSchema);
935       }
936 #endif
937 
938     if (cache->lastPostgreSqlError != NULL)
939 	sqlite3_free (cache->lastPostgreSqlError);
940 
941     if (cache->cutterMessage != NULL)
942 	sqlite3_free (cache->cutterMessage);
943     cache->cutterMessage = NULL;
944     if (cache->createRoutingError != NULL)
945 	free (cache->createRoutingError);
946     cache->createRoutingError = NULL;
947     if (cache->storedProcError != NULL)
948 	free (cache->storedProcError);
949     cache->storedProcError = NULL;
950     if (cache->SqlProcLogfile != NULL)
951 	free (cache->SqlProcLogfile);
952     cache->SqlProcLogfile = NULL;
953     if (cache->SqlProcLog != NULL)
954 	fclose (cache->SqlProcLog);
955     cache->SqlProcLog = NULL;
956     free_sequences (cache);
957     free_vtable_extents (cache);
958 
959     spatialite_finalize_topologies (cache);
960 
961 #ifdef ENABLE_RTTOPO
962     if (cache->RTTOPO_handle != NULL)
963 	rtgeom_finish (cache->RTTOPO_handle);
964     cache->RTTOPO_handle = NULL;
965 #endif
966 
967 #ifndef GEOS_REENTRANT		/* only partially thread-safe mode */
968 /* releasing the connection pool object */
969     invalidate (cache->pool_index);
970 #endif /* end GEOS_REENTRANT */
971 
972 /* freeing the cache itself */
973     free (cache);
974 }
975 
976 GAIAGEO_DECLARE void
gaiaResetGeosMsg_r(const void * p_cache)977 gaiaResetGeosMsg_r (const void *p_cache)
978 {
979 /* resets the GEOS error and warning messages */
980     struct splite_internal_cache *cache =
981 	(struct splite_internal_cache *) p_cache;
982     if (cache == NULL)
983 	return;
984     if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
985 	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
986 	;
987     else
988 	return;
989     if (cache->gaia_geos_error_msg != NULL)
990 	free (cache->gaia_geos_error_msg);
991     if (cache->gaia_geos_warning_msg != NULL)
992 	free (cache->gaia_geos_warning_msg);
993     if (cache->gaia_geosaux_error_msg != NULL)
994 	free (cache->gaia_geosaux_error_msg);
995     cache->gaia_geos_error_msg = NULL;
996     cache->gaia_geos_warning_msg = NULL;
997     cache->gaia_geosaux_error_msg = NULL;
998 }
999 
1000 GAIAGEO_DECLARE const char *
gaiaGetGeosErrorMsg_r(const void * p_cache)1001 gaiaGetGeosErrorMsg_r (const void *p_cache)
1002 {
1003 /* return the latest GEOS error message */
1004     struct splite_internal_cache *cache =
1005 	(struct splite_internal_cache *) p_cache;
1006     if (cache == NULL)
1007 	return NULL;
1008     if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1009 	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1010 	;
1011     else
1012 	return NULL;
1013     return cache->gaia_geos_error_msg;
1014 }
1015 
1016 GAIAGEO_DECLARE const char *
gaiaGetGeosWarningMsg_r(const void * p_cache)1017 gaiaGetGeosWarningMsg_r (const void *p_cache)
1018 {
1019 /* return the latest GEOS error message */
1020     struct splite_internal_cache *cache =
1021 	(struct splite_internal_cache *) p_cache;
1022     if (cache == NULL)
1023 	return NULL;
1024     if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1025 	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1026 	;
1027     else
1028 	return NULL;
1029     return cache->gaia_geos_warning_msg;
1030 }
1031 
1032 GAIAGEO_DECLARE const char *
gaiaGetGeosAuxErrorMsg_r(const void * p_cache)1033 gaiaGetGeosAuxErrorMsg_r (const void *p_cache)
1034 {
1035 /* return the latest GEOS (auxialiary) error message */
1036     struct splite_internal_cache *cache =
1037 	(struct splite_internal_cache *) p_cache;
1038     if (cache == NULL)
1039 	return NULL;
1040     if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1041 	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1042 	;
1043     else
1044 	return NULL;
1045     return cache->gaia_geosaux_error_msg;
1046 }
1047 
1048 GAIAGEO_DECLARE void
gaiaSetGeosErrorMsg_r(const void * p_cache,const char * msg)1049 gaiaSetGeosErrorMsg_r (const void *p_cache, const char *msg)
1050 {
1051 /* setting the latest GEOS error message */
1052     int len;
1053     struct splite_internal_cache *cache =
1054 	(struct splite_internal_cache *) p_cache;
1055     if (cache == NULL)
1056 	return;
1057     if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1058 	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1059 	;
1060     else
1061 	return;
1062     if (cache->gaia_geos_error_msg != NULL)
1063 	free (cache->gaia_geos_error_msg);
1064     cache->gaia_geos_error_msg = NULL;
1065     if (msg == NULL)
1066 	return;
1067     len = strlen (msg);
1068     cache->gaia_geos_error_msg = malloc (len + 1);
1069     strcpy (cache->gaia_geos_error_msg, msg);
1070 }
1071 
1072 GAIAGEO_DECLARE void
gaiaSetGeosWarningMsg_r(const void * p_cache,const char * msg)1073 gaiaSetGeosWarningMsg_r (const void *p_cache, const char *msg)
1074 {
1075 /* setting the latest GEOS error message */
1076     int len;
1077     struct splite_internal_cache *cache =
1078 	(struct splite_internal_cache *) p_cache;
1079     if (cache == NULL)
1080 	return;
1081     if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1082 	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1083 	;
1084     else
1085 	return;
1086     if (cache->gaia_geos_warning_msg != NULL)
1087 	free (cache->gaia_geos_warning_msg);
1088     cache->gaia_geos_warning_msg = NULL;
1089     if (msg == NULL)
1090 	return;
1091     len = strlen (msg);
1092     cache->gaia_geos_warning_msg = malloc (len + 1);
1093     strcpy (cache->gaia_geos_warning_msg, msg);
1094 }
1095 
1096 GAIAGEO_DECLARE void
gaiaSetGeosAuxErrorMsg_r(const void * p_cache,const char * msg)1097 gaiaSetGeosAuxErrorMsg_r (const void *p_cache, const char *msg)
1098 {
1099 /* setting the latest GEOS (auxiliary) error message */
1100     int len;
1101     struct splite_internal_cache *cache =
1102 	(struct splite_internal_cache *) p_cache;
1103     if (cache == NULL)
1104 	return;
1105     if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1106 	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1107 	;
1108     else
1109 	return;
1110     if (cache->gaia_geosaux_error_msg != NULL)
1111 	free (cache->gaia_geosaux_error_msg);
1112     cache->gaia_geosaux_error_msg = NULL;
1113     if (msg == NULL)
1114 	return;
1115     len = strlen (msg);
1116     cache->gaia_geosaux_error_msg = malloc (len + 1);
1117     strcpy (cache->gaia_geosaux_error_msg, msg);
1118 }
1119 
1120 static char *
parse_number_from_msg(const char * str)1121 parse_number_from_msg (const char *str)
1122 {
1123 /* attempting to parse a number from a string */
1124     int sign = 0;
1125     int point = 0;
1126     int digit = 0;
1127     int err = 0;
1128     int len;
1129     char *res;
1130     const char *p = str;
1131     while (1)
1132       {
1133 	  if (*p == '+' || *p == '-')
1134 	    {
1135 		sign++;
1136 		p++;
1137 		continue;
1138 	    }
1139 	  if (*p == '.')
1140 	    {
1141 		point++;
1142 		p++;
1143 		continue;
1144 	    }
1145 	  if (*p >= '0' && *p <= '9')
1146 	    {
1147 		p++;
1148 		digit++;
1149 		continue;
1150 	    }
1151 	  break;
1152       }
1153     if (sign > 1)
1154 	err = 1;
1155     if (sign == 1 && *str != '+' && *str != '-')
1156 	err = 1;
1157     if (point > 1)
1158 	err = 1;
1159     if (!digit)
1160 	err = 1;
1161     if (err)
1162 	return NULL;
1163     len = p - str;
1164     res = malloc (len + 1);
1165     memcpy (res, str, len);
1166     *(res + len) = '\0';
1167     return res;
1168 }
1169 
1170 static int
check_geos_critical_point(const char * msg,double * x,double * y)1171 check_geos_critical_point (const char *msg, double *x, double *y)
1172 {
1173 /* attempts to extract an [X,Y] Point coords from within a string */
1174     char *px;
1175     char *py;
1176     const char *ref = " at or near point ";
1177     const char *ref2 = " conflict at ";
1178     const char *p = strstr (msg, ref);
1179     if (p != NULL)
1180 	goto ok_ref;
1181     p = strstr (msg, ref2);
1182     if (p == NULL)
1183 	return 0;
1184     p += strlen (ref2);
1185     goto ok_ref2;
1186   ok_ref:
1187     p += strlen (ref);
1188   ok_ref2:
1189     px = parse_number_from_msg (p);
1190     if (px == NULL)
1191 	return 0;
1192     p += strlen (px) + 1;
1193     py = parse_number_from_msg (p);
1194     if (py == NULL)
1195       {
1196 	  free (px);
1197 	  return 0;
1198       }
1199     *x = atof (px);
1200     *y = atof (py);
1201     free (px);
1202     free (py);
1203     return 1;
1204 }
1205 
1206 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCriticalPointFromGEOSmsg(void)1207 gaiaCriticalPointFromGEOSmsg (void)
1208 {
1209 /*
1210 / Attempts to return a Point Geometry extracted from the latest GEOS
1211 / error / warning message
1212 */
1213     double x;
1214     double y;
1215     gaiaGeomCollPtr geom;
1216     const char *msg = gaia_geos_error_msg;
1217     if (msg == NULL)
1218 	msg = gaia_geos_warning_msg;
1219     if (msg == NULL)
1220 	return NULL;
1221     if (!check_geos_critical_point (msg, &x, &y))
1222 	return NULL;
1223     geom = gaiaAllocGeomColl ();
1224     gaiaAddPointToGeomColl (geom, x, y);
1225     return geom;
1226 }
1227 
1228 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCriticalPointFromGEOSmsg_r(const void * p_cache)1229 gaiaCriticalPointFromGEOSmsg_r (const void *p_cache)
1230 {
1231 /*
1232 / Attempts to return a Point Geometry extracted from the latest GEOS
1233 / error / warning message
1234 */
1235     double x;
1236     double y;
1237     gaiaGeomCollPtr geom;
1238     const char *msg;
1239     struct splite_internal_cache *cache =
1240 	(struct splite_internal_cache *) p_cache;
1241 
1242     if (cache == NULL)
1243 	return NULL;
1244     if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1245 	|| cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1246 	;
1247     else
1248 	return NULL;
1249 
1250     msg = cache->gaia_geos_error_msg;
1251     if (msg == NULL)
1252 	msg = cache->gaia_geos_warning_msg;
1253     if (msg == NULL)
1254 	return NULL;
1255     if (!check_geos_critical_point (msg, &x, &y))
1256 	return NULL;
1257     geom = gaiaAllocGeomColl ();
1258     gaiaAddPointToGeomColl (geom, x, y);
1259     return geom;
1260 }
1261 
1262 SPATIALITE_PRIVATE void
splite_cache_semaphore_lock(void)1263 splite_cache_semaphore_lock (void)
1264 {
1265 #if defined(_WIN32) && !defined(__MINGW32__)
1266     EnterCriticalSection (&gaia_cache_semaphore);
1267 #else
1268     pthread_mutex_lock (&gaia_cache_semaphore);
1269 #endif
1270 }
1271 
1272 SPATIALITE_PRIVATE void
splite_cache_semaphore_unlock(void)1273 splite_cache_semaphore_unlock (void)
1274 {
1275 #if defined(_WIN32) && !defined(__MINGW32__)
1276     LeaveCriticalSection (&gaia_cache_semaphore);
1277 #else
1278     pthread_mutex_trylock (&gaia_cache_semaphore);
1279     pthread_mutex_unlock (&gaia_cache_semaphore);
1280 #endif
1281 }
1282 
1283 SPATIALITE_DECLARE void
spatialite_initialize(void)1284 spatialite_initialize (void)
1285 {
1286 /* initializes the library */
1287     if (gaia_already_initialized)
1288 	return;
1289 
1290 #if defined(_WIN32) && !defined(__MINGW32__)
1291     InitializeCriticalSection (&gaia_cache_semaphore);
1292 #endif
1293 
1294 #ifdef ENABLE_LIBXML2		/* only if LIBXML2 is supported */
1295     xmlInitParser ();
1296 #endif /* end LIBXML2 conditional */
1297 
1298     gaia_already_initialized = 1;
1299 }
1300 
1301 SPATIALITE_DECLARE void
spatialite_shutdown(void)1302 spatialite_shutdown (void)
1303 {
1304 /* finalizes the library */
1305 #ifndef GEOS_REENTRANT
1306     int i;
1307 #endif
1308     if (!gaia_already_initialized)
1309 	return;
1310 
1311 #if defined(_WIN32) && !defined(__MINGW32__)
1312     DeleteCriticalSection (&gaia_cache_semaphore);
1313 #endif
1314 
1315 #ifdef ENABLE_LIBXML2		/* only if LIBXML2 is supported */
1316     xmlCleanupParser ();
1317 #endif /* end LIBXML2 conditional */
1318 
1319 #ifndef GEOS_REENTRANT		/* only when using the obsolete partially thread-safe mode */
1320     for (i = 0; i < SPATIALITE_MAX_CONNECTIONS; i++)
1321       {
1322 	  struct splite_connection *p = &(splite_connection_pool[i]);
1323 	  if (p->conn_ptr != NULL && p->conn_ptr != GAIA_CONN_RESERVED)
1324 	      free_internal_cache (p->conn_ptr);
1325       }
1326 #endif /* end GEOS_REENTRANT */
1327 
1328     gaia_already_initialized = 0;
1329 }
1330 
1331 SPATIALITE_DECLARE void
spatialite_set_silent_mode(const void * p_cache)1332 spatialite_set_silent_mode (const void *p_cache)
1333 {
1334 /* setting up the SILENT mode */
1335     struct splite_internal_cache *cache =
1336 	(struct splite_internal_cache *) p_cache;
1337     if (cache == NULL)
1338 	return;
1339     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1340 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1341 	return;
1342     cache->silent_mode = 1;
1343 }
1344 
1345 SPATIALITE_DECLARE void
spatialite_set_verbose_mode(const void * p_cache)1346 spatialite_set_verbose_mode (const void *p_cache)
1347 {
1348 /* setting up the VERBOSE mode */
1349     struct splite_internal_cache *cache =
1350 	(struct splite_internal_cache *) p_cache;
1351     if (cache == NULL)
1352 	return;
1353     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1354 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1355 	return;
1356     cache->silent_mode = 0;
1357 }
1358 
1359 SPATIALITE_DECLARE void
enable_tiny_point(const void * p_cache)1360 enable_tiny_point (const void *p_cache)
1361 {
1362 /* Enabling the BLOB-TinyPoint encoding */
1363     struct splite_internal_cache *cache =
1364 	(struct splite_internal_cache *) p_cache;
1365     if (cache == NULL)
1366 	return;
1367     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1368 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1369 	return;
1370     cache->tinyPointEnabled = 1;
1371 }
1372 
1373 SPATIALITE_DECLARE void
disable_tiny_point(const void * p_cache)1374 disable_tiny_point (const void *p_cache)
1375 {
1376 /* Disabling the BLOB-TinyPoint encoding */
1377     struct splite_internal_cache *cache =
1378 	(struct splite_internal_cache *) p_cache;
1379     if (cache == NULL)
1380 	return;
1381     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1382 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1383 	return;
1384     cache->tinyPointEnabled = 0;
1385 }
1386 
1387 SPATIALITE_DECLARE int
is_tiny_point_enabled(const void * p_cache)1388 is_tiny_point_enabled (const void *p_cache)
1389 {
1390 /* Checking if the BLOB-TinyPoint encoding is enabled or not */
1391     struct splite_internal_cache *cache =
1392 	(struct splite_internal_cache *) p_cache;
1393     if (cache == NULL)
1394 	return 0;
1395     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1396 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1397 	return 0;
1398     return cache->tinyPointEnabled;
1399 }
1400 
1401 SPATIALITE_PRIVATE struct gaia_variant_value *
gaia_alloc_variant()1402 gaia_alloc_variant ()
1403 {
1404 /* allocating and initializing a NULL Variant Value */
1405     struct gaia_variant_value *var =
1406 	malloc (sizeof (struct gaia_variant_value));
1407     if (var == NULL)
1408 	return NULL;
1409     var->dataType = SQLITE_NULL;
1410     var->textValue = NULL;
1411     var->blobValue = NULL;
1412     var->size = 0;
1413     return var;
1414 }
1415 
1416 SPATIALITE_PRIVATE void
gaia_free_variant(struct gaia_variant_value * variant)1417 gaia_free_variant (struct gaia_variant_value *variant)
1418 {
1419 /* destroying a Variant Value */
1420     if (variant == NULL)
1421 	return;
1422     if (variant->textValue != NULL)
1423 	free (variant->textValue);
1424     if (variant->blobValue != NULL)
1425 	free (variant->blobValue);
1426     free (variant);
1427 }
1428 
1429 SPATIALITE_PRIVATE void
gaia_set_variant_null(struct gaia_variant_value * variant)1430 gaia_set_variant_null (struct gaia_variant_value *variant)
1431 {
1432 /* setting a Variant Value - NULL */
1433     if (variant->textValue != NULL)
1434 	free (variant->textValue);
1435     if (variant->blobValue != NULL)
1436 	free (variant->blobValue);
1437     variant->dataType = SQLITE_NULL;
1438     variant->textValue = NULL;
1439     variant->blobValue = NULL;
1440     variant->size = 0;
1441 }
1442 
1443 SPATIALITE_PRIVATE void
gaia_set_variant_int64(struct gaia_variant_value * variant,sqlite3_int64 value)1444 gaia_set_variant_int64 (struct gaia_variant_value *variant, sqlite3_int64 value)
1445 {
1446 /* setting a Variant Value - INT64 */
1447     if (variant->textValue != NULL)
1448 	free (variant->textValue);
1449     if (variant->blobValue != NULL)
1450 	free (variant->blobValue);
1451     variant->dataType = SQLITE_INTEGER;
1452     variant->intValue = value;
1453     variant->textValue = NULL;
1454     variant->blobValue = NULL;
1455     variant->size = 0;
1456 }
1457 
1458 SPATIALITE_PRIVATE void
gaia_set_variant_double(struct gaia_variant_value * variant,double value)1459 gaia_set_variant_double (struct gaia_variant_value *variant, double value)
1460 {
1461 /* setting a Variant Value - DOUBLE */
1462     if (variant->textValue != NULL)
1463 	free (variant->textValue);
1464     if (variant->blobValue != NULL)
1465 	free (variant->blobValue);
1466     variant->dataType = SQLITE_FLOAT;
1467     variant->dblValue = value;
1468     variant->textValue = NULL;
1469     variant->blobValue = NULL;
1470     variant->size = 0;
1471 }
1472 
1473 SPATIALITE_PRIVATE int
gaia_set_variant_text(struct gaia_variant_value * variant,const char * value,int size)1474 gaia_set_variant_text (struct gaia_variant_value *variant, const char *value,
1475 		       int size)
1476 {
1477 /* setting a Variant Value - TEXT */
1478     char *text;
1479     if (variant->textValue != NULL)
1480 	free (variant->textValue);
1481     if (variant->blobValue != NULL)
1482 	free (variant->blobValue);
1483     text = malloc (size + 1);
1484     if (text == NULL)
1485       {
1486 	  variant->dataType = SQLITE_NULL;
1487 	  variant->textValue = NULL;
1488 	  variant->blobValue = NULL;
1489 	  variant->size = 0;
1490 	  return 0;
1491       }
1492     variant->dataType = SQLITE_TEXT;
1493     strcpy (text, value);
1494     variant->textValue = text;
1495     variant->blobValue = NULL;
1496     variant->size = size;
1497     return 1;
1498 }
1499 
1500 SPATIALITE_PRIVATE int
gaia_set_variant_blob(struct gaia_variant_value * variant,const unsigned char * value,int size)1501 gaia_set_variant_blob (struct gaia_variant_value *variant,
1502 		       const unsigned char *value, int size)
1503 {
1504 /* setting a Variant Value - BLOB */
1505     unsigned char *blob;
1506     if (variant->textValue != NULL)
1507 	free (variant->textValue);
1508     if (variant->blobValue != NULL)
1509 	free (variant->blobValue);
1510     blob = malloc (size + 1);
1511     if (blob == NULL)
1512       {
1513 	  variant->dataType = SQLITE_NULL;
1514 	  variant->textValue = NULL;
1515 	  variant->blobValue = NULL;
1516 	  variant->size = 0;
1517 	  return 0;
1518       }
1519     variant->dataType = SQLITE_BLOB;
1520     memcpy (blob, value, size);
1521     variant->textValue = NULL;
1522     variant->blobValue = blob;
1523     variant->size = size;
1524     return 1;
1525 }
1526 
1527 #ifdef PROJ_NEW			/* only when using new PROJ.6 */
1528 SPATIALITE_DECLARE const void *
gaiaGetCurrentProjContext(const void * p_cache)1529 gaiaGetCurrentProjContext (const void *p_cache)
1530 {
1531 /* return the current PROJ.6 context (if any) */
1532     struct splite_internal_cache *cache =
1533 	(struct splite_internal_cache *) p_cache;
1534     if (cache != NULL)
1535       {
1536 	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1537 	      && cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1538 	      return cache->PROJ_handle;
1539       }
1540     return NULL;
1541 }
1542 
1543 SPATIALITE_DECLARE int
gaiaSetCurrentCachedProj(const void * p_cache,void * pj,const char * proj_string_1,const char * proj_string_2,void * area)1544 gaiaSetCurrentCachedProj (const void
1545 			  *p_cache, void *pj,
1546 			  const char *proj_string_1,
1547 			  const char *proj_string_2, void *area)
1548 {
1549 /* updates the PROJ6 internal cache */
1550     int ok = 0;
1551     int len;
1552     gaiaProjAreaPtr bbox_in = (gaiaProjAreaPtr) area;
1553     struct splite_internal_cache *cache =
1554 	(struct splite_internal_cache *) p_cache;
1555     if (cache != NULL)
1556       {
1557 	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1558 	      && cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1559 	      ok = 1;
1560       }
1561     if (!ok)
1562 	return 0;		/* invalid cache */
1563     if (proj_string_1 == NULL || pj == NULL)
1564 	return 0;
1565 
1566 /* resetting the PROJ6 internal cache */
1567     if (cache->proj6_cached_string_1 != NULL)
1568 	free (cache->proj6_cached_string_1);
1569     if (cache->proj6_cached_string_2 != NULL)
1570 	free (cache->proj6_cached_string_2);
1571     if (cache->proj6_cached_area != NULL)
1572 	free (cache->proj6_cached_area);
1573     if (cache->proj6_cached_pj != NULL)
1574 	proj_destroy (cache->proj6_cached_pj);
1575 
1576 /* updating the PROJ6 internal cache */
1577     cache->proj6_cached = 1;
1578     cache->proj6_cached_pj = pj;
1579     len = strlen (proj_string_1);
1580     cache->proj6_cached_string_1 = malloc (len + 1);
1581     strcpy (cache->proj6_cached_string_1, proj_string_1);
1582     if (proj_string_2 == NULL)
1583 	cache->proj6_cached_string_2 = NULL;
1584     else
1585       {
1586 	  len = strlen (proj_string_2);
1587 	  cache->proj6_cached_string_2 = malloc (len + 1);
1588 	  strcpy (cache->proj6_cached_string_2, proj_string_2);
1589       }
1590     if (bbox_in == NULL)
1591 	cache->proj6_cached_area = NULL;
1592     else
1593       {
1594 	  gaiaProjAreaPtr bbox_out =
1595 	      (gaiaProjAreaPtr) (cache->proj6_cached_area);
1596 	  if (bbox_out != NULL)
1597 	      free (bbox_out);
1598 	  bbox_out = malloc (sizeof (gaiaProjArea));
1599 	  bbox_out->WestLongitude = bbox_in->WestLongitude;
1600 	  bbox_out->SouthLatitude = bbox_in->SouthLatitude;
1601 	  bbox_out->EastLongitude = bbox_in->EastLongitude;
1602 	  bbox_out->NorthLatitude = bbox_in->NorthLatitude;
1603 	  cache->proj6_cached_area = bbox_out;
1604       }
1605     return 1;
1606 }
1607 
1608 SPATIALITE_DECLARE void *
gaiaGetCurrentCachedProj(const void * p_cache)1609 gaiaGetCurrentCachedProj (const void *p_cache)
1610 {
1611 /* returning the currently cached PROJ6 object */
1612     struct splite_internal_cache *cache =
1613 	(struct splite_internal_cache *) p_cache;
1614     if (cache != NULL)
1615       {
1616 	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1617 	      && cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1618 	    {
1619 		if (cache->proj6_cached)
1620 		    return cache->proj6_cached_pj;
1621 		else
1622 		    return NULL;
1623 	    }
1624       }
1625     return NULL;		/* invalid cache */
1626 }
1627 
1628 SPATIALITE_DECLARE int
gaiaCurrentCachedProjMatches(const void * p_cache,const char * proj_string_1,const char * proj_string_2,void * area)1629 gaiaCurrentCachedProjMatches (const void *p_cache,
1630 			      const char
1631 			      *proj_string_1,
1632 			      const char *proj_string_2, void *area)
1633 {
1634 /* checking if the currently cached PROJ6 object matches */
1635     int ok = 0;
1636     gaiaProjAreaPtr bbox_1 = (gaiaProjAreaPtr) area;
1637     struct splite_internal_cache *cache =
1638 	(struct splite_internal_cache *) p_cache;
1639     if (cache != NULL)
1640       {
1641 	  if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1642 	      && cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1643 	      ok = 1;
1644       }
1645     if (!ok)
1646 	return 0;		/* invalid cache */
1647     if (proj_string_1 == NULL)
1648 	return 0;		/* invalid request */
1649     if (cache->proj6_cached == 0)
1650 	return 0;		/* there is no PROJ6 object currently cached */
1651 
1652 /* checking all definitions */
1653     if (strcmp (proj_string_1, cache->proj6_cached_string_1) != 0)
1654 	return 0;		/* mismatching string #1 */
1655     if (proj_string_2 == NULL && cache->proj6_cached_string_2 == NULL)
1656 	;
1657     else if (proj_string_2 != NULL && cache->proj6_cached_string_2 != NULL)
1658       {
1659 	  if (strcmp (proj_string_2, cache->proj6_cached_string_2) != 0)
1660 	      return 0;		/* mismatching string #2 */
1661       }
1662     else
1663 	return 0;		/* mismatching string #2 */
1664     if (bbox_1 == NULL && cache->proj6_cached_area == NULL)
1665 	;
1666     else if (bbox_1 != NULL && cache->proj6_cached_area != NULL)
1667       {
1668 	  gaiaProjAreaPtr bbox_2 = (gaiaProjAreaPtr) (cache->proj6_cached_area);
1669 	  if (bbox_1->WestLongitude != bbox_2->WestLongitude)
1670 	      return 0;
1671 	  if (bbox_1->SouthLatitude != bbox_2->SouthLatitude)
1672 	      return 0;
1673 	  if (bbox_1->EastLongitude != bbox_2->EastLongitude)
1674 	      return 0;
1675 	  if (bbox_1->NorthLatitude != bbox_2->NorthLatitude)
1676 	      return 0;
1677       }
1678     else
1679 	return 0;		/* mismatching area */
1680 
1681     return 1;			/* anything nicely matches */
1682 }
1683 #endif
1684