1 /*
2 
3  virtualgeojson.c -- SQLite3 extension [VIRTUAL TABLE GeoJson]
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) 2016-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 <sys/types.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <float.h>
51 
52 #if defined(_WIN32) && !defined(__MINGW32__)
53 #include "config-msvc.h"
54 #else
55 #include "config.h"
56 #endif
57 
58 #include <spatialite/sqlite.h>
59 #include <spatialite/debug.h>
60 
61 #include <spatialite/gaiaaux.h>
62 #include <spatialite.h>
63 #include <spatialite/spatialite_ext.h>
64 #include <spatialite/geojson.h>
65 
66 #ifdef _WIN32
67 #define strcasecmp	_stricmp
68 #endif /* not WIN32 */
69 
70 static struct sqlite3_module my_geojson_module;
71 
72 typedef struct VirtualGeoJsonStruct
73 {
74 /* extends the sqlite3_vtab struct */
75     const sqlite3_module *pModule;	/* ptr to sqlite module: USED INTERNALLY BY SQLITE */
76     int nRef;			/* # references: USED INTERNALLY BY SQLITE */
77     char *zErrMsg;		/* error message: USE INTERNALLY BY SQLITE */
78     sqlite3 *db;		/* the sqlite db holding the virtual table */
79     int Srid;			/* the GeoJSON SRID */
80     char *TableName;		/* the VirtualTable name */
81     int Valid;			/* validity flag */
82     geojson_parser_ptr Parser;	/* the GeoJSON Parser */
83     int DeclaredType;		/* Geometry DeclaredType */
84     int DimensionModel;		/* Geometry Dimension Model */
85     double MinX;		/* the GeoJSON Full Extent */
86     double MinY;
87     double MaxX;
88     double MaxY;
89 } VirtualGeoJson;
90 typedef VirtualGeoJson *VirtualGeoJsonPtr;
91 
92 typedef struct VirtualGeoJsonConstraintStruct
93 {
94 /* a constraint to be verified for xFilter */
95     int iColumn;		/* Column on left-hand side of constraint */
96     int op;			/* Constraint operator */
97     char valueType;		/* value Type (GEOJSON_TEXT, GEOJSON_INTEGER, GEOJSON_DOUBLE etc) */
98     sqlite3_int64 intValue;	/* Int64 comparison value */
99     double dblValue;		/* Double comparison value */
100     char *txtValue;		/* Text comparison value */
101     struct VirtualGeoJsonConstraintStruct *next;
102 } VirtualGeoJsonConstraint;
103 typedef VirtualGeoJsonConstraint *VirtualGeoJsonConstraintPtr;
104 
105 typedef struct VirtualGeoJsonCursorStruct
106 {
107 /* extends the sqlite3_vtab_cursor struct */
108     VirtualGeoJsonPtr pVtab;	/* Virtual table of this cursor */
109     int current_fid;		/* the current row FID */
110     geojson_feature_ptr Feature;	/* pointer to the current Feature */
111     int eof;			/* the EOF marker */
112     VirtualGeoJsonConstraintPtr firstConstraint;
113     VirtualGeoJsonConstraintPtr lastConstraint;
114 } VirtualGeoJsonCursor;
115 typedef VirtualGeoJsonCursor *VirtualGeoJsonCursorPtr;
116 
117 
118 static int
geojson_is_float(const char * buf)119 geojson_is_float (const char *buf)
120 {
121 /* checking for a possible floating point number */
122     int ok = 0;
123     int err = 0;
124     unsigned int i;
125     for (i = 0; i < strlen (buf); i++)
126       {
127 	  if (i == 0 && (*(buf + i) == '-' || *(buf + i) == '+'))
128 	      continue;
129 	  if (*(buf + i) == '.')
130 	    {
131 		ok++;
132 		continue;
133 	    }
134 	  if (*(buf + i) == 'e' || *(buf + i) == 'E')
135 	    {
136 		ok++;
137 		continue;
138 	    }
139 	  if (*(buf + i) >= '0' && *(buf + i) <= '9')
140 	      ;
141 	  else
142 	      err++;
143       }
144     if (!err && ok == 1)
145 	return 1;
146     return 0;
147 }
148 
149 static geojson_property_ptr
geojson_create_property()150 geojson_create_property ()
151 {
152 /* creating an empty GeoJSON property */
153     geojson_property_ptr prop = malloc (sizeof (geojson_property));
154     prop->name = NULL;
155     prop->type = GEOJSON_UNKNOWN;
156     prop->txt_value = NULL;
157     prop->next = NULL;
158     return prop;
159 }
160 
161 static void
geojson_destroy_property(geojson_property_ptr prop)162 geojson_destroy_property (geojson_property_ptr prop)
163 {
164 /* destroying a GeoJSON property */
165     if (prop->name != NULL)
166 	free (prop->name);
167     if (prop->txt_value != NULL)
168 	free (prop->txt_value);
169     free (prop);
170 }
171 
172 static void
geojson_init_property(geojson_property_ptr prop)173 geojson_init_property (geojson_property_ptr prop)
174 {
175 /* initializing an empty GeoJSON property */
176     prop->name = NULL;
177     prop->type = GEOJSON_UNKNOWN;
178     prop->txt_value = NULL;
179     prop->next = NULL;
180 }
181 
182 static void
geojson_reset_property(geojson_property_ptr prop)183 geojson_reset_property (geojson_property_ptr prop)
184 {
185 /* resetting a GeoJSON property */
186     if (prop->name != NULL)
187 	free (prop->name);
188     if (prop->txt_value != NULL)
189 	free (prop->txt_value);
190     geojson_init_property (prop);
191 }
192 
193 static geojson_column_ptr
geojson_create_column(const char * name,int type)194 geojson_create_column (const char *name, int type)
195 {
196 /* creating a GeoJSON column object */
197     int len;
198     geojson_column_ptr col = malloc (sizeof (geojson_column));
199     len = strlen (name);
200     col->name = malloc (len + 1);
201     strcpy (col->name, name);
202     col->n_text = 0;
203     col->n_int = 0;
204     col->n_double = 0;
205     col->n_bool = 0;
206     col->n_null = 0;
207     col->next = NULL;
208     switch (type)
209       {
210       case GEOJSON_TEXT:
211 	  col->n_text = 1;
212 	  break;
213       case GEOJSON_INTEGER:
214 	  col->n_int = 1;
215 	  break;
216       case GEOJSON_DOUBLE:
217 	  col->n_double = 1;
218 	  break;
219       case GEOJSON_TRUE:
220       case GEOJSON_FALSE:
221 	  col->n_bool = 1;
222 	  break;
223       case GEOJSON_NULL:
224 	  col->n_null = 1;
225 	  break;
226       };
227     return col;
228 }
229 
230 static geojson_stack_ptr
geojson_create_stack()231 geojson_create_stack ()
232 {
233 /* creating an empty GeoJSON stack object */
234     int i;
235     geojson_stack_ptr ptr = malloc (sizeof (geojson_stack));
236     ptr->level = -1;
237     memset (ptr->key, '\0', GEOJSON_MAX);
238     ptr->key_idx = 0;
239     memset (ptr->value, '\0', GEOJSON_MAX);
240     ptr->value_idx = 0;
241     memset (ptr->numvalue, '\0', GEOJSON_MAX);
242     ptr->numvalue_idx = 0;
243     for (i = 0; i < GEOJSON_STACK; i++)
244       {
245 	  geojson_stack_entry_ptr p = ptr->entries + i;
246 	  p->obj = NULL;
247 	  p->first = NULL;
248 	  p->last = NULL;
249       }
250     return ptr;
251 }
252 
253 static void
geojson_destroy_stack(geojson_stack_ptr ptr)254 geojson_destroy_stack (geojson_stack_ptr ptr)
255 {
256 /* memory cleanup - destroying a GeoJSON stack object */
257     int i;
258     if (ptr == NULL)
259 	return;
260     for (i = 0; i < GEOJSON_STACK; i++)
261       {
262 	  geojson_stack_entry_ptr p = ptr->entries + i;
263 	  geojson_keyval_ptr pkv = p->first;
264 	  while (pkv != NULL)
265 	    {
266 		geojson_keyval_ptr pn = pkv->next;
267 		if (pkv->key != NULL)
268 		    free (pkv->key);
269 		if (pkv->value != NULL)
270 		    free (pkv->value);
271 		free (pkv);
272 		pkv = pn;
273 	    }
274       }
275     free (ptr);
276 }
277 
278 static int
geojson_parse_key(geojson_stack_ptr stack,char c,char ** error_message)279 geojson_parse_key (geojson_stack_ptr stack, char c, char **error_message)
280 {
281 /* parsing a GeoJSON Object's Key string */
282     if (stack->key_idx >= GEOJSON_MAX - 1)
283       {
284 	  *error_message =
285 	      sqlite3_mprintf ("GeoJSON Object's Key string: len > %d chars\n",
286 			       GEOJSON_MAX);
287 	  return 0;
288       }
289     *(stack->key + stack->key_idx) = c;
290     stack->key_idx += 1;
291     return 1;
292 }
293 
294 static int
geojson_parse_value(geojson_stack_ptr stack,char c,char ** error_message)295 geojson_parse_value (geojson_stack_ptr stack, char c, char **error_message)
296 {
297 /* parsing a GeoJSON Object's Value string */
298     if (stack->key_idx >= GEOJSON_MAX - 1)
299       {
300 	  *error_message =
301 	      sqlite3_mprintf
302 	      ("GeoJSON Object's Value string: len > %d chars\n", GEOJSON_MAX);
303 	  return 0;
304       }
305     *(stack->value + stack->value_idx) = c;
306     stack->value_idx += 1;
307     return 1;
308 }
309 
310 static int
geojson_parse_numvalue(geojson_stack_ptr stack,char c,char ** error_message)311 geojson_parse_numvalue (geojson_stack_ptr stack, char c, char **error_message)
312 {
313 /* parsing a GeoJSON Object's numeric or special Value */
314     if (stack->numvalue_idx >= GEOJSON_MAX - 1)
315       {
316 	  *error_message =
317 	      sqlite3_mprintf
318 	      ("GeoJSON Object's Numeric Value: len > %d chars\n", GEOJSON_MAX);
319 	  return 0;
320       }
321     *(stack->numvalue + stack->numvalue_idx) = c;
322     stack->numvalue_idx += 1;
323     return 1;
324 }
325 
326 static void
geojson_add_keyval(geojson_stack_ptr stack,int level)327 geojson_add_keyval (geojson_stack_ptr stack, int level)
328 {
329 /* adding a Key-Value item to a GeoJSON Object */
330     geojson_stack_entry_ptr entry;
331     geojson_keyval_ptr pkv;
332     int len;
333 
334     if (*(stack->key) == '\0')
335 	goto reset;
336     entry = stack->entries + level;
337 /* setting the Key name */
338     pkv = malloc (sizeof (geojson_keyval));
339     len = strlen (stack->key);
340     if (len > 0)
341       {
342 	  pkv->key = malloc (len + 1);
343 	  strcpy (pkv->key, stack->key);
344       }
345     else
346 	pkv->key = NULL;
347     len = strlen (stack->value);
348     if (len > 0)
349       {
350 	  /* setting a string value */
351 	  pkv->value = malloc (len + 1);
352 	  strcpy (pkv->value, stack->value);
353 	  pkv->numvalue = 0;
354       }
355     else
356 	pkv->value = NULL;
357     if (pkv->value == NULL)
358       {
359 	  len = strlen (stack->numvalue);
360 	  if (len > 0)
361 	    {
362 		/* setting a numeric or special value */
363 		pkv->value = malloc (len + 1);
364 		strcpy (pkv->value, stack->numvalue);
365 		pkv->numvalue = 1;
366 	    }
367       }
368     pkv->next = NULL;
369 /* updating the Key-Value linked list */
370     if (entry->first == NULL)
371 	entry->first = pkv;
372     if (entry->last != NULL)
373 	entry->last->next = pkv;
374     entry->last = pkv;
375 
376 /* resetting the Key-Value input buffers */
377   reset:
378     memset (stack->key, '\0', GEOJSON_MAX);
379     stack->key_idx = 0;
380     memset (stack->value, '\0', GEOJSON_MAX);
381     stack->value_idx = 0;
382     memset (stack->numvalue, '\0', GEOJSON_MAX);
383     stack->numvalue_idx = 0;
384 }
385 
386 static geojson_block_ptr
geojson_add_block(geojson_parser_ptr parser)387 geojson_add_block (geojson_parser_ptr parser)
388 {
389 /* adding a new block of objects to the GeoJSON parser */
390     int i;
391     geojson_block_ptr block;
392     if (parser == NULL)
393 	return NULL;
394     block = malloc (sizeof (geojson_block));
395 /* initializing an empty block */
396     for (i = 0; i < GEOJSON_BLOCK; i++)
397       {
398 	  geojson_entry_ptr entry = block->entries + i;
399 	  entry->parent_key = NULL;
400 	  entry->type = GEOJSON_UNKNOWN;
401 	  entry->properties = 0;
402 	  entry->geometry = 0;
403 	  entry->offset_start = -1;
404 	  entry->offset_end = -1;
405       }
406     block->next_free_entry = 0;
407     block->next = NULL;
408 /* appending to the linked list */
409     if (parser->first == NULL)
410 	parser->first = block;
411     if (parser->last != NULL)
412 	parser->last->next = block;
413     parser->last = block;
414     return block;
415 }
416 
417 static void
geojson_add_column(geojson_parser_ptr parser,const char * name,int type)418 geojson_add_column (geojson_parser_ptr parser, const char *name, int type)
419 {
420 /* updating the Columns list */
421     geojson_column_ptr col;
422 
423     col = parser->first_col;
424     while (col != NULL)
425       {
426 	  if (strcasecmp (col->name, name) == 0)
427 	    {
428 		/* already defined: updating stats */
429 		switch (type)
430 		  {
431 		  case GEOJSON_TEXT:
432 		      col->n_text += 1;
433 		      break;
434 		  case GEOJSON_INTEGER:
435 		      col->n_int += 1;
436 		      break;
437 		  case GEOJSON_DOUBLE:
438 		      col->n_double += 1;
439 		      break;
440 		  case GEOJSON_TRUE:
441 		  case GEOJSON_FALSE:
442 		      col->n_bool += 1;
443 		      break;
444 		  case GEOJSON_NULL:
445 		      col->n_null += 1;
446 		      break;
447 		  };
448 		return;
449 	    }
450 	  col = col->next;
451       }
452 
453 /* inserting a new column into the list */
454     col = geojson_create_column (name, type);
455     if (parser->first_col == NULL)
456 	parser->first_col = col;
457     if (parser->last_col != NULL)
458 	parser->last_col->next = col;
459     parser->last_col = col;
460 }
461 
462 static int
geojson_push(geojson_stack_ptr stack,geojson_entry_ptr entry,int level,char ** error_message)463 geojson_push (geojson_stack_ptr stack, geojson_entry_ptr entry, int level,
464 	      char **error_message)
465 {
466 /* GeoJSON stack pseudo-push */
467     geojson_stack_entry_ptr p_entry;
468     if (stack == NULL || entry == NULL)
469       {
470 	  *error_message = sqlite3_mprintf ("GeoJSON push: NULL pointer\n");
471 	  return 0;
472       }
473     if (level < 0 || level >= GEOJSON_STACK)
474       {
475 	  *error_message =
476 	      sqlite3_mprintf ("GeoJSON push: forbidden nesting level %d\n",
477 			       level);
478 	  return 0;
479       }
480     if (level != (stack->level + 1))
481       {
482 	  *error_message =
483 	      sqlite3_mprintf
484 	      ("GeoJSON push: unexpected nesting level %d (%d)\n", level,
485 	       stack->level);
486 	  return 0;
487       }
488     stack->level += 1;
489     p_entry = stack->entries + level;
490     if (p_entry->obj != NULL)
491       {
492 	  *error_message =
493 	      sqlite3_mprintf ("GeoJSON push: unexpected unfreed level %d\n",
494 			       level);
495 	  return 0;
496       }
497 /* initializing the stack entry */
498     p_entry->obj = entry;
499     memset (stack->key, '\0', GEOJSON_MAX);
500     stack->key_idx = 0;
501     memset (stack->value, '\0', GEOJSON_MAX);
502     stack->value_idx = 0;
503     memset (stack->numvalue, '\0', GEOJSON_MAX);
504     stack->numvalue_idx = 0;
505     return 1;
506 }
507 
508 static int
geojson_pop(geojson_stack_ptr stack,int level,long offset,char ** error_message)509 geojson_pop (geojson_stack_ptr stack, int level, long offset,
510 	     char **error_message)
511 {
512 /* GeoJSON stack pseudo-pop */
513     geojson_stack_entry_ptr p_entry;
514     geojson_keyval_ptr pkv;
515     if (level < 0 || level >= GEOJSON_STACK)
516       {
517 	  *error_message =
518 	      sqlite3_mprintf ("GeoJSON pop: forbidden nesting level %d\n",
519 			       level);
520 	  return 0;
521       }
522     if (level != stack->level)
523       {
524 	  *error_message =
525 	      sqlite3_mprintf
526 	      ("GeoJSON pop: unexpected nesting level %d (%d)\n", level,
527 	       stack->level);
528 	  return 0;
529       }
530     p_entry = stack->entries + level;
531     if (p_entry->obj == NULL)
532       {
533 	  *error_message =
534 	      sqlite3_mprintf
535 	      ("GeoJSON pop: unexpected uninitialized level %d\n", level);
536 	  return 0;
537       }
538     p_entry->obj->offset_end = offset;
539     if (strcasecmp (p_entry->obj->parent_key, "properties") == 0)
540 	p_entry->obj->type = GEOJSON_PROPERTIES;
541     pkv = p_entry->first;
542     if (pkv != NULL)
543       {
544 	  if (pkv->key != NULL)
545 	    {
546 		if (strcasecmp (pkv->key, "type") == 0)
547 		  {
548 		      if (pkv->value != NULL)
549 			{
550 			    if (strcasecmp (pkv->value, "FeatureCollection") ==
551 				0)
552 				p_entry->obj->type = GEOJSON_FCOLLECTION;
553 			    if (strcasecmp (pkv->value, "Feature") == 0)
554 				p_entry->obj->type = GEOJSON_FEATURE;
555 			    if (strcasecmp
556 				(p_entry->obj->parent_key, "geometry") == 0)
557 			      {
558 				  if (strcasecmp (pkv->value, "Point") == 0)
559 				      p_entry->obj->type = GEOJSON_POINT;
560 				  if (strcasecmp (pkv->value, "LineString") ==
561 				      0)
562 				      p_entry->obj->type = GEOJSON_LINESTRING;
563 				  if (strcasecmp (pkv->value, "Polygon") == 0)
564 				      p_entry->obj->type = GEOJSON_POLYGON;
565 				  if (strcasecmp (pkv->value, "MultiPoint") ==
566 				      0)
567 				      p_entry->obj->type = GEOJSON_MULTIPOINT;
568 				  if (strcasecmp (pkv->value, "MultiLineString")
569 				      == 0)
570 				      p_entry->obj->type =
571 					  GEOJSON_MULTILINESTRING;
572 				  if (strcasecmp (pkv->value, "MultiPolygon") ==
573 				      0)
574 				      p_entry->obj->type = GEOJSON_MULTIPOLYGON;
575 				  if (strcasecmp
576 				      (pkv->value, "GeometryCollection") == 0)
577 				      p_entry->obj->type =
578 					  GEOJSON_GEOMCOLLECTION;
579 			      }
580 			}
581 		  }
582 	    }
583       }
584     if (p_entry->obj->type == GEOJSON_FEATURE)
585       {
586 	  pkv = p_entry->first;
587 	  while (pkv != NULL)
588 	    {
589 		if (strcasecmp (pkv->key, "geometry") == 0
590 		    && pkv->value == NULL)
591 		    p_entry->obj->geometry += 1;
592 		if (strcasecmp (pkv->key, "properties") == 0
593 		    && pkv->value == NULL)
594 		    p_entry->obj->properties += 1;
595 		pkv = pkv->next;
596 	    }
597       }
598 
599 /* resetting the Key-Value list */
600     pkv = p_entry->first;
601     while (pkv != NULL)
602       {
603 	  geojson_keyval_ptr pn = pkv->next;
604 	  if (pkv->key != NULL)
605 	      free (pkv->key);
606 	  if (pkv->value != NULL)
607 	      free (pkv->value);
608 	  free (pkv);
609 	  pkv = pn;
610       }
611     p_entry->first = NULL;
612     p_entry->last = NULL;
613 
614 /* resetting the stack entry */
615     p_entry->obj = NULL;
616     memset (stack->key, '\0', GEOJSON_MAX);
617     stack->key_idx = 0;
618     memset (stack->value, '\0', GEOJSON_MAX);
619     stack->value_idx = 0;
620     memset (stack->numvalue, '\0', GEOJSON_MAX);
621     stack->numvalue_idx = 0;
622     stack->level -= 1;
623     return 1;
624 }
625 
626 static geojson_entry_ptr
geojson_add_object(geojson_block_ptr block,long offset,const char * parent_key)627 geojson_add_object (geojson_block_ptr block, long offset,
628 		    const char *parent_key)
629 {
630 /* adding a new GeoJSON object */
631     geojson_entry_ptr entry;
632     if (block->next_free_entry < 0 || block->next_free_entry >= GEOJSON_BLOCK)
633 	return NULL;
634     entry = block->entries + block->next_free_entry;
635     block->next_free_entry += 1;
636     entry->type = GEOJSON_UNKNOWN;
637     if (entry->parent_key != NULL)
638 	free (entry->parent_key);
639     entry->parent_key = NULL;
640     if (parent_key != NULL)
641       {
642 	  int len = strlen (parent_key);
643 	  entry->parent_key = malloc (len + 1);
644 	  strcpy (entry->parent_key, parent_key);
645       }
646     entry->offset_start = offset;
647     entry->offset_end = -1;
648     return entry;
649 }
650 
651 
652 static int
geojson_start_object(geojson_parser_ptr parser,geojson_stack_ptr stack,int level,long offset,const char * parent_key,char ** error_message)653 geojson_start_object (geojson_parser_ptr parser, geojson_stack_ptr stack,
654 		      int level, long offset, const char *parent_key,
655 		      char **error_message)
656 {
657 /* registering a GeoJSON object */
658     int expand = 0;
659     geojson_block_ptr block;
660     geojson_entry_ptr entry;
661 
662     if (parser->last == NULL)
663 	expand = 1;
664     else if (parser->last->next_free_entry >= GEOJSON_BLOCK)
665 	expand = 1;
666     if (expand)
667       {
668 	  /* adding a new GeoJSON Block to the parser's list */
669 	  block = geojson_add_block (parser);
670       }
671     else
672       {
673 	  /* continuing to insert into the last Block */
674 	  block = parser->last;
675       }
676     if (block == NULL)
677       {
678 	  *error_message =
679 	      sqlite3_mprintf ("GeoJSON start_object: NULL pointer\n");
680 	  return 0;
681       }
682     entry = geojson_add_object (block, offset, parent_key);
683     if (!geojson_push (stack, entry, level, error_message))
684 	return 0;
685     return 1;
686 }
687 
688 static int
geojson_end_object(geojson_stack_ptr stack,int level,long offset,char ** error_message)689 geojson_end_object (geojson_stack_ptr stack, int level, long offset,
690 		    char **error_message)
691 {
692 /* completing the definition of a GeoJSON object */
693     if (!geojson_pop (stack, level, offset, error_message))
694 	return 0;
695     return 1;
696 }
697 
698 SPATIALITE_DECLARE geojson_parser_ptr
geojson_create_parser(FILE * in)699 geojson_create_parser (FILE * in)
700 {
701 /* creating an empty GeoJSON parser object */
702     geojson_parser_ptr ptr = malloc (sizeof (geojson_parser));
703     ptr->in = in;
704     ptr->first = NULL;
705     ptr->last = NULL;
706     ptr->count = 0;
707     ptr->features = NULL;
708     ptr->first_col = NULL;
709     ptr->last_col = NULL;
710     ptr->n_points = 0;
711     ptr->n_linestrings = 0;
712     ptr->n_polygons = 0;
713     ptr->n_mpoints = 0;
714     ptr->n_mlinestrings = 0;
715     ptr->n_mpolygons = 0;
716     ptr->n_geomcolls = 0;
717     ptr->n_geom_2d = 0;
718     ptr->n_geom_3d = 0;
719     ptr->n_geom_4d = 0;
720     *(ptr->cast_type) = '\0';
721     *(ptr->cast_dims) = '\0';
722     return ptr;
723 }
724 
725 SPATIALITE_DECLARE void
geojson_destroy_parser(geojson_parser_ptr ptr)726 geojson_destroy_parser (geojson_parser_ptr ptr)
727 {
728 /* memory cleanup - destroying a GeoJSON parser object */
729     geojson_block_ptr pb;
730     geojson_block_ptr pbn;
731     geojson_column_ptr pc;
732     geojson_column_ptr pcn;
733     int i;
734     if (ptr == NULL)
735 	return;
736     pb = ptr->first;
737     while (pb != NULL)
738       {
739 	  pbn = pb->next;
740 	  free (pb);
741 	  pb = pbn;
742       }
743     pc = ptr->first_col;
744     while (pc != NULL)
745       {
746 	  pcn = pc->next;
747 	  if (pc->name != NULL)
748 	      free (pc->name);
749 	  free (pc);
750 	  pc = pcn;
751       }
752     if (ptr->features != NULL)
753       {
754 	  for (i = 0; i < ptr->count; i++)
755 	    {
756 		geojson_property_ptr pp;
757 		geojson_feature_ptr pf = ptr->features + i;
758 		if (pf->geometry != NULL)
759 		    free (pf->geometry);
760 		pp = pf->first;
761 		while (pp != NULL)
762 		  {
763 		      geojson_property_ptr ppn = pp->next;
764 		      if (pp->name != NULL)
765 			  free (pp->name);
766 		      if (pp->txt_value != NULL)
767 			  free (pp->txt_value);
768 		      free (pp);
769 		      pp = ppn;
770 		  }
771 	    }
772 	  free (ptr->features);
773       }
774 /* close the GeoJSON file handle */
775     if (ptr->in != NULL)
776 	fclose (ptr->in);
777     free (ptr);
778 }
779 
780 SPATIALITE_DECLARE int
geojson_parser_init(geojson_parser_ptr parser,char ** error_message)781 geojson_parser_init (geojson_parser_ptr parser, char **error_message)
782 {
783 /* initializing the GeoJSON parser object */
784     int c;
785     long offset;
786     int level = -1;
787     int is_string = 0;
788     int prev_char = '\0';
789     int is_first = 0;
790     int is_second = 0;
791     int is_first_ready = 0;
792     int is_second_ready = 0;
793     int is_numeric = 0;
794     geojson_stack_ptr stack = geojson_create_stack ();
795     *error_message = NULL;
796 
797     while ((c = getc (parser->in)) != EOF)
798       {
799 	  /* consuming the GeoJSON input file */
800 	  if (is_string)
801 	    {
802 		/* consuming a quoted text string */
803 		if (c == '"' && prev_char != '/')
804 		  {
805 		      is_string = 0;	/* end string marker */
806 		      if (is_first)
807 			{
808 			    /* found the GeoJSON object Key terminator */
809 			    is_first = 0;
810 			}
811 		      if (is_second)
812 			{
813 			    /* found the GeoJSON object Value terminator */
814 			    is_second = 0;
815 			}
816 		  }
817 		else
818 		  {
819 		      if (is_first)
820 			{
821 			    /* found the GeoJSON object Key */
822 			    if (!geojson_parse_key (stack, c, error_message))
823 				goto err;
824 			}
825 		      if (is_second)
826 			{
827 			    /* found the GeoJSON object Value */
828 			    if (!geojson_parse_value (stack, c, error_message))
829 				goto err;
830 			}
831 		  }
832 		prev_char = c;
833 		continue;
834 	    }
835 	  if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
836 	    {
837 		/* ignoring white spaces */
838 		prev_char = c;
839 		continue;
840 	    }
841 	  if (c == '[' || c == ']')
842 	    {
843 		prev_char = c;
844 		is_second_ready = 0;
845 		is_second = 0;
846 		is_numeric = 0;
847 		continue;
848 	    }
849 	  if (c == '{')
850 	    {
851 		/* found a JSON Start Object marker */
852 		char parent_key[GEOJSON_MAX];
853 		strcpy (parent_key, stack->key);
854 		if (level >= 0)
855 		    geojson_add_keyval (stack, level);
856 		level++;
857 		offset = ftell (parser->in);
858 		if (!geojson_start_object
859 		    (parser, stack, level, offset, parent_key, error_message))
860 		    goto err;
861 		prev_char = c;
862 		is_first_ready = 1;
863 		is_first = 0;
864 		is_second_ready = 0;
865 		is_second = 0;
866 		is_numeric = 0;
867 		continue;
868 	    }
869 	  if (c == '}')
870 	    {
871 		/* found a JSON End Object marker */
872 		geojson_add_keyval (stack, level);
873 		offset = ftell (parser->in);
874 		if (!geojson_end_object (stack, level, offset, error_message))
875 		    goto err;
876 		level--;
877 		prev_char = c;
878 		is_first_ready = 0;
879 		is_first = 0;
880 		is_second_ready = 0;
881 		is_second = 0;
882 		is_numeric = 0;
883 		continue;
884 	    }
885 	  if (c == ':')
886 	    {
887 		prev_char = c;
888 		is_first_ready = 0;
889 		is_second_ready = 1;
890 		continue;
891 	    }
892 	  if (c == ',')
893 	    {
894 		geojson_add_keyval (stack, level);
895 		prev_char = c;
896 		is_first_ready = 1;
897 		is_first = 0;
898 		is_second_ready = 0;
899 		is_second = 0;
900 		is_numeric = 0;
901 		continue;
902 	    }
903 	  if (c == '"')
904 	    {
905 		/* a quoted text string starts here */
906 		is_string = 1;
907 		prev_char = c;
908 		if (is_first_ready)
909 		  {
910 		      is_first_ready = 0;
911 		      is_first = 1;
912 		  }
913 		if (is_second_ready)
914 		  {
915 		      is_second_ready = 0;
916 		      is_second = 1;
917 		  }
918 		continue;
919 	    }
920 	  if (is_second_ready)
921 	    {
922 		/* should be the beginning of some numeric value */
923 		is_second_ready = 0;
924 		is_numeric = 1;
925 	    }
926 	  if (is_numeric)
927 	    {
928 		/* consuming a numeric or special value */
929 		if (!geojson_parse_numvalue (stack, c, error_message))
930 		    goto err;
931 		prev_char = c;
932 		continue;
933 	    }
934 	  prev_char = c;
935       }
936     geojson_destroy_stack (stack);
937     return 1;
938 
939   err:
940     geojson_destroy_stack (stack);
941     return 0;
942 }
943 
944 static int
geojson_get_property(const char * buf,geojson_stack_ptr stack,geojson_property_ptr prop,int * off,char ** error_message)945 geojson_get_property (const char *buf, geojson_stack_ptr stack,
946 		      geojson_property_ptr prop, int *off, char **error_message)
947 {
948 /* parsing the Feature's Properties string */
949     char c;
950     int len;
951     int is_string = 0;
952     int prev_char = '\0';
953     int is_first = 0;
954     int is_second = 0;
955     int is_first_ready = 1;
956     int is_second_ready = 0;
957     int is_numeric = 0;
958     const char *end_p = buf + strlen (buf);
959     const char *p = buf + *off;
960     if (p < buf || p >= end_p)
961 	return -1;		/* the string has been completely parsed */
962 
963 /* resetting all stack buffers */
964     memset (stack->key, '\0', GEOJSON_MAX);
965     stack->key_idx = 0;
966     memset (stack->value, '\0', GEOJSON_MAX);
967     stack->value_idx = 0;
968     memset (stack->numvalue, '\0', GEOJSON_MAX);
969     stack->numvalue_idx = 0;
970 
971     while (1)
972       {
973 	  /* consuming the GeoJSON Properties string */
974 	  if (p >= end_p)
975 	      break;
976 	  c = *p++;
977 	  if (is_string)
978 	    {
979 		/* consuming a quoted text string */
980 		if (c == '"' && prev_char != '/')
981 		  {
982 		      is_string = 0;	/* end string marker */
983 		      if (is_first)
984 			{
985 			    /* found the GeoJSON object Key terminator */
986 			    is_first = 0;
987 			}
988 		      if (is_second)
989 			{
990 			    /* found the GeoJSON object Value terminator */
991 			    is_second = 0;
992 			}
993 		  }
994 		else
995 		  {
996 		      if (is_first)
997 			{
998 			    /* found the GeoJSON object Key */
999 			    if (!geojson_parse_key (stack, c, error_message))
1000 				goto err;
1001 			    if (prop->name != NULL)
1002 				free (prop->name);
1003 			    len = strlen (stack->key);
1004 			    if (len == 0)
1005 				prop->name = NULL;
1006 			    else
1007 			      {
1008 				  prop->name = malloc (len + 1);
1009 				  strcpy (prop->name, stack->key);
1010 			      }
1011 			}
1012 		      if (is_second)
1013 			{
1014 			    /* found the GeoJSON object Value */
1015 			    if (!geojson_parse_value (stack, c, error_message))
1016 				goto err;
1017 			    if (prop->txt_value != NULL)
1018 				free (prop->txt_value);
1019 			    prop->txt_value = NULL;
1020 			    len = strlen (stack->value);
1021 			    if (len > 0)
1022 			      {
1023 				  prop->txt_value = malloc (len + 1);
1024 				  strcpy (prop->txt_value, stack->value);
1025 			      }
1026 			    prop->type = GEOJSON_TEXT;
1027 			}
1028 		  }
1029 		prev_char = c;
1030 		continue;
1031 	    }
1032 	  if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1033 	    {
1034 		/* ignoring white spaces */
1035 		prev_char = c;
1036 		continue;
1037 	    }
1038 	  if (c == ':')
1039 	    {
1040 		prev_char = c;
1041 		is_first = 0;
1042 		is_first_ready = 0;
1043 		is_second_ready = 1;
1044 		continue;
1045 	    }
1046 	  if (c == ',')
1047 	      break;
1048 	  if (c == '"')
1049 	    {
1050 		/* a quoted text string starts here */
1051 		is_string = 1;
1052 		prev_char = c;
1053 		if (is_first_ready)
1054 		  {
1055 		      is_first_ready = 0;
1056 		      is_first = 1;
1057 		  }
1058 		if (is_second_ready)
1059 		  {
1060 		      is_second_ready = 0;
1061 		      is_second = 1;
1062 		  }
1063 		continue;
1064 	    }
1065 	  if (is_second_ready)
1066 	    {
1067 		/* should be the beginning of some numeric value */
1068 		is_second_ready = 0;
1069 		is_numeric = 1;
1070 	    }
1071 	  if (is_numeric)
1072 	    {
1073 		/* consuming a numeric or special value */
1074 		if (!geojson_parse_numvalue (stack, c, error_message))
1075 		    goto err;
1076 		prev_char = c;
1077 		continue;
1078 	    }
1079 	  prev_char = c;
1080       }
1081     if (is_numeric)
1082       {
1083 	  if (strcmp (stack->numvalue, "null") == 0)
1084 	      prop->type = GEOJSON_NULL;
1085 	  else if (strcmp (stack->numvalue, "true") == 0)
1086 	      prop->type = GEOJSON_TRUE;
1087 	  else if (strcmp (stack->numvalue, "false") == 0)
1088 	      prop->type = GEOJSON_FALSE;
1089 	  else
1090 	    {
1091 		len = strlen (stack->numvalue);
1092 		if (len > 0)
1093 		  {
1094 		      if (geojson_is_float (stack->numvalue))
1095 			{
1096 			    prop->dbl_value = atof (stack->numvalue);
1097 			    prop->type = GEOJSON_DOUBLE;
1098 			}
1099 		      else
1100 			{
1101 			    prop->int_value = atoll (stack->numvalue);
1102 			    prop->type = GEOJSON_INTEGER;
1103 			}
1104 		  }
1105 	    }
1106       }
1107 
1108     *off = p - buf;
1109     return 1;
1110 
1111   err:
1112     return 0;
1113 }
1114 
1115 static int
geojson_parse_columns(geojson_parser_ptr parser,const char * buf,char ** error_message)1116 geojson_parse_columns (geojson_parser_ptr parser, const char *buf,
1117 		       char **error_message)
1118 {
1119 /* attempting to parse Feature's Properties for detecting Column types */
1120     int off = 0;
1121     geojson_stack_ptr stack = geojson_create_stack ();
1122     geojson_property prop;
1123     geojson_init_property (&prop);
1124 
1125     while (1)
1126       {
1127 	  int ret;
1128 	  geojson_reset_property (&prop);
1129 	  ret = geojson_get_property (buf, stack, &prop, &off, error_message);
1130 	  if (ret <= 0)
1131 	      geojson_reset_property (&prop);
1132 	  if (ret < 0)
1133 	      break;
1134 	  if (ret == 0)
1135 	      goto err;
1136 	  if (prop.name != NULL)
1137 	    {
1138 		switch (prop.type)
1139 		  {
1140 		  case GEOJSON_TEXT:
1141 		  case GEOJSON_INTEGER:
1142 		  case GEOJSON_DOUBLE:
1143 		  case GEOJSON_TRUE:
1144 		  case GEOJSON_FALSE:
1145 		  case GEOJSON_NULL:
1146 		      geojson_add_column (parser, prop.name, prop.type);
1147 		      break;
1148 		  default:
1149 		      goto err;
1150 		  };
1151 	    }
1152 	  else
1153 	      goto err;
1154 	  geojson_reset_property (&prop);
1155       }
1156     geojson_destroy_stack (stack);
1157     return 1;
1158 
1159   err:
1160     geojson_destroy_stack (stack);
1161     return 0;
1162 }
1163 
1164 static int
geojson_parse_properties(geojson_feature_ptr ft,const char * buf,char ** error_message)1165 geojson_parse_properties (geojson_feature_ptr ft, const char *buf,
1166 			  char **error_message)
1167 {
1168 /* attempting to parse Feature's Properties for loading Values */
1169     int off = 0;
1170     geojson_stack_ptr stack = geojson_create_stack ();
1171     geojson_property_ptr prop;
1172 
1173     while (1)
1174       {
1175 	  int ret;
1176 	  prop = geojson_create_property ();
1177 	  ret = geojson_get_property (buf, stack, prop, &off, error_message);
1178 	  if (ret <= 0)
1179 	      geojson_destroy_property (prop);
1180 	  if (ret < 0)
1181 	      break;
1182 	  if (ret == 0)
1183 	      goto err;
1184 	  if (prop->name != NULL)
1185 	    {
1186 		switch (prop->type)
1187 		  {
1188 		  case GEOJSON_TEXT:
1189 		  case GEOJSON_INTEGER:
1190 		  case GEOJSON_DOUBLE:
1191 		  case GEOJSON_TRUE:
1192 		  case GEOJSON_FALSE:
1193 		  case GEOJSON_NULL:
1194 		      /* adding a Property into the linked list */
1195 		      if (ft->first == NULL)
1196 			  ft->first = prop;
1197 		      if (ft->last != NULL)
1198 			  ft->last->next = prop;
1199 		      ft->last = prop;
1200 		      break;
1201 		  default:
1202 		      geojson_destroy_property (prop);
1203 		      goto err;
1204 		  };
1205 	    }
1206 	  else
1207 	    {
1208 		geojson_destroy_property (prop);
1209 		goto err;
1210 	    }
1211       }
1212     geojson_destroy_stack (stack);
1213     return 1;
1214 
1215   err:
1216     geojson_destroy_stack (stack);
1217     return 0;
1218 }
1219 
1220 SPATIALITE_DECLARE int
geojson_check_features(geojson_parser_ptr parser,char ** error_message)1221 geojson_check_features (geojson_parser_ptr parser, char **error_message)
1222 {
1223 /* checking Features for validity */
1224     int i;
1225     int len;
1226     char *buf;
1227     gaiaGeomCollPtr geo = NULL;
1228     *error_message = NULL;
1229 
1230     if (parser == NULL)
1231       {
1232 	  *error_message = sqlite3_mprintf ("GeoJSON parser: NULL object\n");
1233 	  return 0;
1234       }
1235     parser->n_points = 0;
1236     parser->n_linestrings = 0;
1237     parser->n_polygons = 0;
1238     parser->n_mpoints = 0;
1239     parser->n_mlinestrings = 0;
1240     parser->n_mpolygons = 0;
1241     parser->n_geomcolls = 0;
1242     parser->n_geom_2d = 0;
1243     parser->n_geom_3d = 0;
1244     parser->n_geom_4d = 0;
1245     *(parser->cast_type) = '\0';
1246     *(parser->cast_dims) = '\0';
1247     for (i = 0; i < parser->count; i++)
1248       {
1249 	  /* reading and parsing Properties for each Feature */
1250 	  int ret;
1251 	  geojson_feature_ptr ft = parser->features + i;
1252 	  if (ft->prop_offset_start < 0 || ft->prop_offset_end < 0)
1253 	    {
1254 		*error_message =
1255 		    sqlite3_mprintf
1256 		    ("GeoJSON parser: invalid Properties (fid=%d)\n", ft->fid);
1257 		return 0;
1258 	    }
1259 	  if (ft->prop_offset_end <= ft->prop_offset_start)
1260 	    {
1261 		*error_message =
1262 		    sqlite3_mprintf
1263 		    ("GeoJSON parser: invalid Properties (fid=%d)\n", ft->fid);
1264 		return 0;
1265 	    }
1266 	  ret = fseek (parser->in, ft->prop_offset_start, SEEK_SET);
1267 	  if (ret != 0)
1268 	    {
1269 		*error_message =
1270 		    sqlite3_mprintf
1271 		    ("GeoJSON parser: Properties invalid seek (fid=%d)\n",
1272 		     ft->fid);
1273 		return 0;
1274 	    }
1275 	  len = ft->prop_offset_end - ft->prop_offset_start - 1;
1276 	  buf = malloc (len + 1);
1277 	  if (buf == NULL)
1278 	    {
1279 		*error_message =
1280 		    sqlite3_mprintf
1281 		    ("GeoJSON parser: Properties insufficient memory (fid=%d)\n",
1282 		     ft->fid);
1283 		return 0;
1284 	    }
1285 	  ret = fread (buf, 1, len, parser->in);
1286 	  if (ret != len)
1287 	    {
1288 		*error_message =
1289 		    sqlite3_mprintf
1290 		    ("GeoJSON parser: Properties read error (fid=%d)\n",
1291 		     ft->fid);
1292 		free (buf);
1293 		return 0;
1294 	    }
1295 	  *(buf + len) = '\0';
1296 	  geojson_parse_columns (parser, buf, error_message);
1297 	  free (buf);
1298       }
1299     for (i = 0; i < parser->count; i++)
1300       {
1301 	  /* reading and parsing Geometry for each Feature */
1302 	  int ret;
1303 	  geojson_feature_ptr ft = parser->features + i;
1304 	  if (ft->geom_offset_start < 0 || ft->geom_offset_end < 0)
1305 	    {
1306 		*error_message =
1307 		    sqlite3_mprintf
1308 		    ("GeoJSON parser: invalid Geometry (fid=%d)\n", ft->fid);
1309 		return 0;
1310 	    }
1311 	  if (ft->geom_offset_end <= ft->geom_offset_start)
1312 	    {
1313 		*error_message =
1314 		    sqlite3_mprintf
1315 		    ("GeoJSON parser: invalid Geometry (fid=%d)\n", ft->fid);
1316 		return 0;
1317 	    }
1318 	  ret = fseek (parser->in, ft->geom_offset_start, SEEK_SET);
1319 	  if (ret != 0)
1320 	    {
1321 		*error_message =
1322 		    sqlite3_mprintf
1323 		    ("GeoJSON parser: Geometry invalid seek (fid=%d)\n",
1324 		     ft->fid);
1325 		return 0;
1326 	    }
1327 	  len = ft->geom_offset_end - ft->geom_offset_start;
1328 	  if (len == 0)
1329 	    {
1330 		/* NULL Geometry */
1331 		parser->n_geom_null += 1;
1332 		continue;
1333 	    }
1334 	  buf = malloc (len + 2);
1335 	  if (buf == NULL)
1336 	    {
1337 		*error_message =
1338 		    sqlite3_mprintf
1339 		    ("GeoJSON parser: Geometry insufficient memory (fid=%d)\n",
1340 		     ft->fid);
1341 		return 0;
1342 	    }
1343 	  *buf = '{';
1344 	  ret = fread (buf + 1, 1, len, parser->in);
1345 	  if (ret != len)
1346 	    {
1347 		*error_message =
1348 		    sqlite3_mprintf
1349 		    ("GeoJSON parser: Geometry read error (fid=%d)\n", ft->fid);
1350 		free (buf);
1351 		return 0;
1352 	    }
1353 	  *(buf + len + 1) = '\0';
1354 	  geo = gaiaParseGeoJSON ((const unsigned char *) buf);
1355 	  if (geo != NULL)
1356 	    {
1357 		/* sniffing GeometryType and Dimensions */
1358 		switch (geo->DimensionModel)
1359 		  {
1360 		  case GAIA_XY:
1361 		      parser->n_geom_2d += 1;
1362 		      break;
1363 		  case GAIA_XY_Z:
1364 		      parser->n_geom_3d += 1;
1365 		      break;
1366 		  case GAIA_XY_Z_M:
1367 		      parser->n_geom_4d += 1;
1368 		      break;
1369 		  default:
1370 		      *error_message =
1371 			  sqlite3_mprintf
1372 			  ("GeoJSON parser: Geometry has invalid dimensions (fid=%d)\n",
1373 			   ft->fid);
1374 		      free (buf);
1375 		      gaiaFreeGeomColl (geo);
1376 		      return 0;
1377 		  };
1378 		switch (geo->DeclaredType)
1379 		  {
1380 		  case GAIA_POINT:
1381 		      parser->n_points += 1;
1382 		      break;
1383 		  case GAIA_LINESTRING:
1384 		      parser->n_linestrings += 1;
1385 		      break;
1386 		  case GAIA_POLYGON:
1387 		      parser->n_polygons += 1;
1388 		      break;
1389 		  case GAIA_MULTIPOINT:
1390 		      parser->n_mpoints += 1;
1391 		      break;
1392 		  case GAIA_MULTILINESTRING:
1393 		      parser->n_mlinestrings += 1;
1394 		      break;
1395 		  case GAIA_MULTIPOLYGON:
1396 		      parser->n_mpolygons += 1;
1397 		      break;
1398 		  case GAIA_GEOMETRYCOLLECTION:
1399 		      parser->n_geomcolls += 1;
1400 		      break;
1401 		  default:
1402 		      *error_message =
1403 			  sqlite3_mprintf
1404 			  ("GeoJSON parser: Geometry has an invalid Type (fid=%d)\n",
1405 			   ft->fid);
1406 		      free (buf);
1407 		      gaiaFreeGeomColl (geo);
1408 		      return 0;
1409 		  };
1410 		gaiaFreeGeomColl (geo);
1411 	    }
1412 	  else
1413 	      parser->n_geom_null += 1;
1414 	  free (buf);
1415       }
1416     return 1;
1417 }
1418 
1419 SPATIALITE_DECLARE int
geojson_create_features_index(geojson_parser_ptr parser,char ** error_message)1420 geojson_create_features_index (geojson_parser_ptr parser, char **error_message)
1421 {
1422 /* creating the index of all GeoJSON Features */
1423     geojson_block_ptr pb;
1424     geojson_block_ptr pbn;
1425     geojson_feature_ptr pf = NULL;
1426     geojson_entry_ptr entry;
1427     int count;
1428     int i;
1429     *error_message = NULL;
1430 
1431     if (parser == NULL)
1432       {
1433 	  *error_message = sqlite3_mprintf ("GeoJSON parser: NULL object\n");
1434 	  return 0;
1435       }
1436 
1437     parser->count = 0;
1438     pb = parser->first;
1439     while (pb != NULL)
1440       {
1441 	  /* counting how many Features are there */
1442 	  for (i = 0; i < pb->next_free_entry; i++)
1443 	    {
1444 		entry = pb->entries + i;
1445 		if (entry->type != GEOJSON_FEATURE)
1446 		    continue;
1447 		parser->count += 1;
1448 	    }
1449 	  pb = pb->next;
1450       }
1451     if (parser->features != NULL)
1452 	free (parser->features);
1453 /* allocating the index of all Features */
1454     if (parser->count <= 0)
1455       {
1456 	  *error_message =
1457 	      sqlite3_mprintf
1458 	      ("GeoJSON parser: not a single Feature was found ... invalid format ?\n");
1459 	  return 0;
1460       }
1461     parser->features = malloc (sizeof (geojson_feature) * parser->count);
1462     if (parser->features == NULL)
1463       {
1464 	  *error_message =
1465 	      sqlite3_mprintf ("GeoJSON parser: insufficient memory\n");
1466 	  return 0;
1467       }
1468     for (i = 0; i < parser->count; i++)
1469       {
1470 	  /* initializing empty Features */
1471 	  pf = parser->features + i;
1472 	  pf->fid = i + 1;
1473 	  pf->geom_offset_start = -1;
1474 	  pf->geom_offset_end = -1;
1475 	  pf->prop_offset_start = -1;
1476 	  pf->prop_offset_end = -1;
1477 	  pf->geometry = NULL;
1478 	  pf->first = NULL;
1479 	  pf->last = NULL;
1480       }
1481 
1482     count = 0;
1483     pb = parser->first;
1484     while (pb != NULL)
1485       {
1486 	  /* properly initializing Features */
1487 	  for (i = 0; i < pb->next_free_entry; i++)
1488 	    {
1489 		entry = pb->entries + i;
1490 		if (entry->type != GEOJSON_FEATURE)
1491 		  {
1492 		      if (pf != NULL)
1493 			{
1494 			    if (entry->type == GEOJSON_POINT ||
1495 				entry->type == GEOJSON_LINESTRING ||
1496 				entry->type == GEOJSON_POLYGON ||
1497 				entry->type == GEOJSON_MULTIPOINT ||
1498 				entry->type == GEOJSON_MULTILINESTRING ||
1499 				entry->type == GEOJSON_MULTIPOLYGON ||
1500 				entry->type == GEOJSON_GEOMCOLLECTION)
1501 			      {
1502 				  pf->geom_offset_start = entry->offset_start;
1503 				  pf->geom_offset_end = entry->offset_end;
1504 			      }
1505 			    if (entry->type == GEOJSON_PROPERTIES)
1506 			      {
1507 				  pf->prop_offset_start = entry->offset_start;
1508 				  pf->prop_offset_end = entry->offset_end;
1509 			      }
1510 			}
1511 		      continue;
1512 		  }
1513 		pf = parser->features + count;
1514 		count += 1;
1515 	    }
1516 	  pb = pb->next;
1517       }
1518 
1519 /* destroying the Pass I dictionary */
1520     pb = parser->first;
1521     while (pb != NULL)
1522       {
1523 	  for (i = 0; i < pb->next_free_entry; i++)
1524 	    {
1525 		geojson_entry_ptr e = pb->entries + i;
1526 		if (e->parent_key != NULL)
1527 		    free (e->parent_key);
1528 	    }
1529 	  pbn = pb->next;
1530 	  free (pb);
1531 	  pb = pbn;
1532       }
1533     parser->first = NULL;
1534     parser->last = NULL;
1535     return 1;
1536 }
1537 
1538 static char *
geojson_normalize_case(const char * name,int colname_case)1539 geojson_normalize_case (const char *name, int colname_case)
1540 {
1541 /* transforming a name in full lower- or upper-case */
1542     int len = strlen (name);
1543     char *clean = malloc (len + 1);
1544     char *p = clean;
1545     strcpy (clean, name);
1546     while (*p != '\0')
1547       {
1548 	  if (colname_case == GAIA_DBF_COLNAME_LOWERCASE)
1549 	    {
1550 		if (*p >= 'A' && *p <= 'Z')
1551 		    *p = *p - 'A' + 'a';
1552 	    }
1553 	  if (colname_case == GAIA_DBF_COLNAME_UPPERCASE)
1554 	    {
1555 		if (*p >= 'a' && *p <= 'z')
1556 		    *p = *p - 'a' + 'A';
1557 	    }
1558 	  p++;
1559       }
1560     return clean;
1561 }
1562 
1563 static char *
geojson_unique_pk(geojson_parser_ptr parser,const char * pk_base_name)1564 geojson_unique_pk (geojson_parser_ptr parser, const char *pk_base_name)
1565 {
1566 /* will return a surely unique PK name */
1567     int ok = 0;
1568     int idx = 0;
1569     char *pk = sqlite3_mprintf ("%s", pk_base_name);
1570     while (ok == 0)
1571       {
1572 	  geojson_column_ptr col = parser->first_col;
1573 	  ok = 1;
1574 	  while (col != NULL)
1575 	    {
1576 		if (strcasecmp (pk, col->name) == 0)
1577 		  {
1578 		      sqlite3_free (pk);
1579 		      pk = sqlite3_mprintf ("%s_%d", pk_base_name, idx++);
1580 		      ok = 0;
1581 		      break;
1582 		  }
1583 		col = col->next;
1584 	    }
1585       }
1586     return pk;
1587 }
1588 
1589 static char *
geojson_unique_geom(geojson_parser_ptr parser,const char * geom_base_name)1590 geojson_unique_geom (geojson_parser_ptr parser, const char *geom_base_name)
1591 {
1592 /* will return a surely unique PK name */
1593     int ok = 0;
1594     int idx = 0;
1595     char *geom = sqlite3_mprintf ("%s", geom_base_name);
1596     while (ok == 0)
1597       {
1598 	  geojson_column_ptr col = parser->first_col;
1599 	  ok = 1;
1600 	  while (col != NULL)
1601 	    {
1602 		if (strcasecmp (geom, col->name) == 0)
1603 		  {
1604 		      sqlite3_free (geom);
1605 		      geom = sqlite3_mprintf ("%s_%d", geom_base_name, idx++);
1606 		      ok = 0;
1607 		      break;
1608 		  }
1609 		col = col->next;
1610 	    }
1611       }
1612     return geom;
1613 }
1614 
1615 static char *
geojson_sql_create_virtual_table(geojson_parser_ptr parser,const char * table,int colname_case)1616 geojson_sql_create_virtual_table (geojson_parser_ptr parser, const char *table,
1617 				  int colname_case)
1618 {
1619 /* will return the SQL CREATE TABLE statement */
1620     char *sql;
1621     char *prev;
1622     char *xname;
1623     char *pk_name;
1624     char *geom_name;
1625     char *xpk_name;
1626     char *xgeom_name;
1627     const char *type;
1628     geojson_column_ptr col;
1629     if (table == NULL)
1630 	return NULL;
1631 
1632     xname = gaiaDoubleQuotedSql (table);
1633     pk_name = geojson_unique_pk (parser, "fid");
1634     xpk_name = geojson_normalize_case (pk_name, colname_case);
1635     sqlite3_free (pk_name);
1636     geom_name = geojson_unique_geom (parser, "geometry");
1637     xgeom_name = geojson_normalize_case (geom_name, colname_case);
1638     sqlite3_free (geom_name);
1639     sql =
1640 	sqlite3_mprintf
1641 	("CREATE TABLE \"%s\" (\n\t%s INTEGER PRIMARY KEY AUTOINCREMENT,\n\t%s BLOB",
1642 	 xname, xpk_name, xgeom_name);
1643     free (xname);
1644     free (xpk_name);
1645     free (xgeom_name);
1646     col = parser->first_col;
1647     while (col != NULL)
1648       {
1649 	  /* adding columns */
1650 	  char *xcol = geojson_normalize_case (col->name, colname_case);
1651 	  xname = gaiaDoubleQuotedSql (xcol);
1652 	  free (xcol);
1653 	  type = "TEXT";
1654 	  if (col->n_null > 0)
1655 	    {
1656 		/* NULL values */
1657 		if (col->n_text > 0 && col->n_int == 0 && col->n_double == 0
1658 		    && col->n_bool == 0)
1659 		    type = "TEXT";
1660 		if (col->n_text == 0 && col->n_int > 0 && col->n_double == 0
1661 		    && col->n_bool == 0)
1662 		    type = "INTEGER";
1663 		if (col->n_text == 0 && (col->n_int > 0 && col->n_bool > 0)
1664 		    && col->n_double == 0)
1665 		    type = "INTEGER";
1666 		if (col->n_text == 0 && col->n_int == 0 && col->n_double > 0
1667 		    && col->n_bool == 0)
1668 		    type = "DOUBLE";
1669 		if (col->n_text == 0 && col->n_int == 0 && col->n_double == 0
1670 		    && col->n_bool > 0)
1671 		    type = "BOOLEAN";
1672 	    }
1673 	  else
1674 	    {
1675 		/* NOT NULL */
1676 		if (col->n_text > 0 && col->n_int == 0 && col->n_double == 0
1677 		    && col->n_bool == 0)
1678 		    type = "TEXT NOT NULL";
1679 		if (col->n_text == 0 && col->n_int > 0 && col->n_double == 0
1680 		    && col->n_bool == 0)
1681 		    type = "INTEGER NOT NULL";
1682 		if (col->n_text == 0 && (col->n_int > 0 && col->n_bool > 0)
1683 		    && col->n_double == 0)
1684 		    type = "INTEGER NOT NULL";
1685 		if (col->n_text == 0 && col->n_int == 0 && col->n_double > 0
1686 		    && col->n_bool == 0)
1687 		    type = "DOUBLE NOT NULL";
1688 		if (col->n_text == 0 && col->n_int == 0 && col->n_double == 0
1689 		    && col->n_bool > 0)
1690 		    type = "BOOLEAN NOT NULL";
1691 	    }
1692 	  prev = sql;
1693 	  sql = sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev, xname, type);
1694 	  free (xname);
1695 	  sqlite3_free (prev);
1696 	  col = col->next;
1697       }
1698     prev = sql;
1699     sql = sqlite3_mprintf ("%s)\n", prev);
1700     sqlite3_free (prev);
1701     return sql;
1702 }
1703 
1704 SPATIALITE_DECLARE char *
geojson_sql_create_table(geojson_parser_ptr parser,const char * table,int colname_case)1705 geojson_sql_create_table (geojson_parser_ptr parser, const char *table,
1706 			  int colname_case)
1707 {
1708 /* will return the SQL CREATE TABLE statement */
1709     char *sql;
1710     char *prev;
1711     char *xname;
1712     char *pk_name;
1713     char *xpk_name;
1714     const char *type;
1715     geojson_column_ptr col;
1716     if (table == NULL)
1717 	return NULL;
1718 
1719     xname = gaiaDoubleQuotedSql (table);
1720     pk_name = geojson_unique_pk (parser, "pk_uid");
1721     xpk_name = geojson_normalize_case (pk_name, colname_case);
1722     sqlite3_free (pk_name);
1723     sql =
1724 	sqlite3_mprintf
1725 	("CREATE TABLE \"%s\" (\n\t%s INTEGER PRIMARY KEY AUTOINCREMENT", xname,
1726 	 xpk_name);
1727     free (xname);
1728     free (xpk_name);
1729     col = parser->first_col;
1730     while (col != NULL)
1731       {
1732 	  /* adding columns */
1733 	  char *xcol = geojson_normalize_case (col->name, colname_case);
1734 	  xname = gaiaDoubleQuotedSql (xcol);
1735 	  free (xcol);
1736 	  type = "TEXT";
1737 	  if (col->n_null > 0)
1738 	    {
1739 		/* NULL values */
1740 		if (col->n_text > 0 && col->n_int == 0 && col->n_double == 0
1741 		    && col->n_bool == 0)
1742 		    type = "TEXT";
1743 		if (col->n_text == 0 && col->n_int > 0 && col->n_double == 0
1744 		    && col->n_bool == 0)
1745 		    type = "INTEGER";
1746 		if (col->n_text == 0 && (col->n_int > 0 && col->n_bool > 0)
1747 		    && col->n_double == 0)
1748 		    type = "INTEGER";
1749 		if (col->n_text == 0 && col->n_int == 0 && col->n_double > 0
1750 		    && col->n_bool == 0)
1751 		    type = "DOUBLE";
1752 		if (col->n_text == 0 && col->n_int == 0 && col->n_double == 0
1753 		    && col->n_bool > 0)
1754 		    type = "BOOLEAN";
1755 	    }
1756 	  else
1757 	    {
1758 		/* NOT NULL */
1759 		if (col->n_text > 0 && col->n_int == 0 && col->n_double == 0
1760 		    && col->n_bool == 0)
1761 		    type = "TEXT NOT NULL";
1762 		if (col->n_text == 0 && col->n_int > 0 && col->n_double == 0
1763 		    && col->n_bool == 0)
1764 		    type = "INTEGER NOT NULL";
1765 		if (col->n_text == 0 && (col->n_int > 0 && col->n_bool > 0)
1766 		    && col->n_double == 0)
1767 		    type = "INTEGER NOT NULL";
1768 		if (col->n_text == 0 && col->n_int == 0 && col->n_double > 0
1769 		    && col->n_bool == 0)
1770 		    type = "DOUBLE NOT NULL";
1771 		if (col->n_text == 0 && col->n_int == 0 && col->n_double == 0
1772 		    && col->n_bool > 0)
1773 		    type = "BOOLEAN NOT NULL";
1774 	    }
1775 	  prev = sql;
1776 	  sql = sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev, xname, type);
1777 	  free (xname);
1778 	  sqlite3_free (prev);
1779 	  col = col->next;
1780       }
1781     prev = sql;
1782     sql = sqlite3_mprintf ("%s)\n", prev);
1783     sqlite3_free (prev);
1784     return sql;
1785 }
1786 
1787 SPATIALITE_DECLARE char *
geojson_sql_add_geometry(geojson_parser_ptr parser,const char * table,const char * geom_col,int colname_case,int srid)1788 geojson_sql_add_geometry (geojson_parser_ptr parser, const char *table,
1789 			  const char *geom_col, int colname_case, int srid)
1790 {
1791 /* will return the SQL AddGeometryColumn() statement */
1792     char *sql;
1793     char *geom_name;
1794     char *xgeom_col;
1795     char *type = "GEOMETRY";
1796     char *dims = "XY";
1797     if (table == NULL || geom_col == NULL)
1798 	return NULL;
1799     if (parser->n_points == 0 && parser->n_linestrings == 0
1800 	&& parser->n_polygons == 0 && parser->n_mpoints == 0
1801 	&& parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
1802 	&& parser->n_geomcolls == 0)
1803 	return NULL;
1804     if (parser->n_geom_2d == 0 && parser->n_geom_3d == 0
1805 	&& parser->n_geom_4d == 0)
1806 	return NULL;
1807 
1808     if (parser->n_points > 0 && parser->n_linestrings == 0
1809 	&& parser->n_polygons == 0 && parser->n_mpoints == 0
1810 	&& parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
1811 	&& parser->n_geomcolls == 0)
1812       {
1813 	  type = "POINT";
1814 	  strcpy (parser->cast_type, "CastToPoint");
1815       }
1816     if (parser->n_mpoints > 0 && parser->n_linestrings == 0
1817 	&& parser->n_polygons == 0 && parser->n_mlinestrings == 0
1818 	&& parser->n_mpolygons == 0 && parser->n_geomcolls == 0)
1819       {
1820 	  type = "MULTIPOINT";
1821 	  strcpy (parser->cast_type, "CastToMultiPoint");
1822       }
1823     if (parser->n_points == 0 && parser->n_linestrings > 0
1824 	&& parser->n_polygons == 0 && parser->n_mpoints == 0
1825 	&& parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
1826 	&& parser->n_geomcolls == 0)
1827       {
1828 	  type = "LINESTRING";
1829 	  strcpy (parser->cast_type, "CastToLinestring");
1830       }
1831     if (parser->n_mlinestrings > 0 && parser->n_points == 0
1832 	&& parser->n_polygons == 0 && parser->n_mpoints == 0
1833 	&& parser->n_mpolygons == 0 && parser->n_geomcolls == 0)
1834       {
1835 	  type = "MULTILINESTRING";
1836 	  strcpy (parser->cast_type, "CastToMultiLinestring");
1837       }
1838     if (parser->n_points == 0 && parser->n_linestrings > 0
1839 	&& parser->n_polygons > 0 && parser->n_mpoints == 0
1840 	&& parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
1841 	&& parser->n_geomcolls == 0)
1842       {
1843 	  type = "POLYGON";
1844 	  strcpy (parser->cast_type, "CastToPolygon");
1845       }
1846     if (parser->n_mpolygons > 0 && parser->n_points == 0
1847 	&& parser->n_linestrings == 0 && parser->n_mpoints == 0
1848 	&& parser->n_mlinestrings == 0 && parser->n_geomcolls == 0)
1849       {
1850 	  type = "MULTIPOLYGON";
1851 	  strcpy (parser->cast_type, "CastToMultiPolygon");
1852       }
1853     if ((parser->n_points + parser->n_mpoints) > 0
1854 	&& (parser->n_linestrings + parser->n_mlinestrings) > 0)
1855       {
1856 	  type = "GEOMETRYCOLLECTION";
1857 	  strcpy (parser->cast_type, "CastToGeometryCollection");
1858       }
1859     if ((parser->n_points + parser->n_mpoints) > 0
1860 	&& (parser->n_polygons + parser->n_mpolygons) > 0)
1861       {
1862 	  type = "GEOMETRYCOLLECTION";
1863 	  strcpy (parser->cast_type, "CastToGeometryCollection");
1864       }
1865     if ((parser->n_linestrings + parser->n_mlinestrings) > 0
1866 	&& (parser->n_polygons + parser->n_mpolygons) > 0)
1867       {
1868 	  type = "GEOMETRYCOLLECTION";
1869 	  strcpy (parser->cast_type, "CastToGeometryCollection");
1870       }
1871 
1872     if (parser->n_geom_2d > 0 && parser->n_geom_3d == 0
1873 	&& parser->n_geom_4d == 0)
1874       {
1875 	  dims = "XY";
1876 	  strcpy (parser->cast_dims, "CastToXY");
1877       }
1878     if (parser->n_geom_3d > 0 && parser->n_geom_4d == 0)
1879       {
1880 	  dims = "XYZ";
1881 	  strcpy (parser->cast_dims, "CastToXYZ");
1882       }
1883     if (parser->n_geom_4d > 0)
1884       {
1885 	  dims = "XYZM";
1886 	  strcpy (parser->cast_dims, "CastToXYZM");
1887       }
1888     geom_name = geojson_unique_geom (parser, geom_col);
1889     xgeom_col = geojson_normalize_case (geom_name, colname_case);
1890     sqlite3_free (geom_name);
1891     sql =
1892 	sqlite3_mprintf ("SELECT AddGeometryColumn(%Q, %Q, %d, %Q, %Q)", table,
1893 			 xgeom_col, srid, type, dims);
1894     free (xgeom_col);
1895     return sql;
1896 }
1897 
1898 SPATIALITE_DECLARE char *
geojson_sql_create_rtree(const char * table,const char * geom_col,int colname_case)1899 geojson_sql_create_rtree (const char *table, const char *geom_col,
1900 			  int colname_case)
1901 {
1902 /* will return the SQL CreateSpatialIndex() statement */
1903     char *sql;
1904     char *xgeom_col;
1905     if (table == NULL || geom_col == NULL)
1906 	return NULL;
1907     xgeom_col = geojson_normalize_case (geom_col, colname_case);
1908     sql =
1909 	sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, %Q)", table, xgeom_col);
1910     free (xgeom_col);
1911     return sql;
1912 }
1913 
1914 SPATIALITE_DECLARE char *
geojson_sql_insert_into(geojson_parser_ptr parser,const char * table)1915 geojson_sql_insert_into (geojson_parser_ptr parser, const char *table)
1916 {
1917 /* will return the SQL INSERT INTO statement */
1918     char *sql;
1919     char *prev;
1920     char *xname;
1921     geojson_column_ptr col;
1922     if (table == NULL)
1923 	return NULL;
1924 
1925     xname = gaiaDoubleQuotedSql (table);
1926     sql = sqlite3_mprintf ("INSERT INTO \"%s\" VALUES (NULL", xname);
1927     free (xname);
1928 
1929     col = parser->first_col;
1930     while (col != NULL)
1931       {
1932 	  prev = sql;
1933 	  sql = sqlite3_mprintf ("%s, ?", prev);
1934 	  sqlite3_free (prev);
1935 	  col = col->next;
1936       }
1937     prev = sql;
1938 /* Geometry is always the last Column */
1939     sql =
1940 	sqlite3_mprintf ("%s, %s(%s(?)))", prev, parser->cast_dims,
1941 			 parser->cast_type);
1942     sqlite3_free (prev);
1943     return sql;
1944 }
1945 
1946 SPATIALITE_DECLARE int
geojson_init_feature(geojson_parser_ptr parser,geojson_feature_ptr ft,char ** error_message)1947 geojson_init_feature (geojson_parser_ptr parser, geojson_feature_ptr ft,
1948 		      char **error_message)
1949 {
1950 /* attempting to fully initialize a GeoJSON Feature object */
1951     int ret;
1952     int len;
1953     char *buf;
1954     geojson_property_ptr prop;
1955     *error_message = NULL;
1956 
1957     if (ft->prop_offset_start < 0 || ft->prop_offset_end < 0)
1958       {
1959 	  *error_message =
1960 	      sqlite3_mprintf ("GeoJSON parser: invalid Properties (fid=%d)\n",
1961 			       ft->fid);
1962 	  return 0;
1963       }
1964     if (ft->prop_offset_end <= ft->prop_offset_start)
1965       {
1966 	  *error_message =
1967 	      sqlite3_mprintf ("GeoJSON parser: invalid Properties (fid=%d)\n",
1968 			       ft->fid);
1969 	  return 0;
1970       }
1971     ret = fseek (parser->in, ft->prop_offset_start, SEEK_SET);
1972     if (ret != 0)
1973       {
1974 	  *error_message =
1975 	      sqlite3_mprintf
1976 	      ("GeoJSON parser: Properties invalid seek (fid=%d)\n", ft->fid);
1977 	  return 0;
1978       }
1979     len = ft->prop_offset_end - ft->prop_offset_start - 1;
1980     buf = malloc (len + 1);
1981     if (buf == NULL)
1982       {
1983 	  *error_message =
1984 	      sqlite3_mprintf
1985 	      ("GeoJSON parser: Properties insufficient memory (fid=%d)\n",
1986 	       ft->fid);
1987 	  return 0;
1988       }
1989     ret = fread (buf, 1, len, parser->in);
1990     if (ret != len)
1991       {
1992 	  *error_message =
1993 	      sqlite3_mprintf
1994 	      ("GeoJSON parser: Properties read error (fid=%d)\n", ft->fid);
1995 	  free (buf);
1996 	  return 0;
1997       }
1998     *(buf + len) = '\0';
1999     geojson_parse_properties (ft, buf, error_message);
2000     free (buf);
2001 
2002 /* checking for duplicate Droperty names */
2003     prop = ft->first;
2004     while (prop != NULL)
2005       {
2006 	  geojson_property_ptr prop2 = prop->next;
2007 	  while (prop2 != NULL)
2008 	    {
2009 		if (strcasecmp (prop->name, prop2->name) == 0)
2010 		  {
2011 		      *error_message =
2012 			  sqlite3_mprintf
2013 			  ("GeoJSON parser: duplicate property name \"%s\" (fid=%d)\n",
2014 			   prop->name, ft->fid);
2015 		      return 0;
2016 		  }
2017 		prop2 = prop2->next;
2018 	    }
2019 	  prop = prop->next;
2020       }
2021 
2022 /* reading the GeoJSON Geometry */
2023     if (ft->geom_offset_start < 0 || ft->geom_offset_end < 0)
2024       {
2025 	  *error_message =
2026 	      sqlite3_mprintf ("GeoJSON parser: invalid Geometry (fid=%d)\n",
2027 			       ft->fid);
2028 	  return 0;
2029       }
2030     if (ft->geom_offset_end <= ft->geom_offset_start)
2031       {
2032 	  *error_message =
2033 	      sqlite3_mprintf ("GeoJSON parser: invalid Geometry (fid=%d)\n",
2034 			       ft->fid);
2035 	  return 0;
2036       }
2037     ret = fseek (parser->in, ft->geom_offset_start, SEEK_SET);
2038     if (ret != 0)
2039       {
2040 	  *error_message =
2041 	      sqlite3_mprintf
2042 	      ("GeoJSON parser: Geometry invalid seek (fid=%d)\n", ft->fid);
2043 	  return 0;
2044       }
2045     len = ft->geom_offset_end - ft->geom_offset_start;
2046     if (len == 0)
2047       {
2048 	  /* NULL Geometry */
2049 	  if (ft->geometry != NULL)
2050 	      free (ft->geometry);
2051 	  ft->geometry = NULL;
2052 	  return 1;
2053       }
2054     buf = malloc (len + 2);
2055     if (buf == NULL)
2056       {
2057 	  *error_message =
2058 	      sqlite3_mprintf
2059 	      ("GeoJSON parser: Geometry insufficient memory (fid=%d)\n",
2060 	       ft->fid);
2061 	  return 0;
2062       }
2063     *buf = '{';
2064     ret = fread (buf + 1, 1, len, parser->in);
2065     if (ret != len)
2066       {
2067 	  *error_message =
2068 	      sqlite3_mprintf ("GeoJSON parser: Geometry read error (fid=%d)\n",
2069 			       ft->fid);
2070 	  free (buf);
2071 	  return 0;
2072       }
2073     *(buf + len + 1) = '\0';
2074     if (ft->geometry != NULL)
2075 	free (ft->geometry);
2076     ft->geometry = buf;
2077     return 1;
2078 }
2079 
2080 SPATIALITE_DECLARE void
geojson_reset_feature(geojson_feature_ptr ft)2081 geojson_reset_feature (geojson_feature_ptr ft)
2082 {
2083 /* memory cleanup - freeing a Feature */
2084     geojson_property_ptr pp;
2085     if (ft == NULL)
2086 	return;
2087 
2088     if (ft->geometry != NULL)
2089 	free (ft->geometry);
2090     pp = ft->first;
2091     while (pp != NULL)
2092       {
2093 	  geojson_property_ptr ppn = pp->next;
2094 	  if (pp->name != NULL)
2095 	      free (pp->name);
2096 	  if (pp->txt_value != NULL)
2097 	      free (pp->txt_value);
2098 	  free (pp);
2099 	  pp = ppn;
2100       }
2101     ft->geometry = NULL;
2102     ft->first = NULL;
2103     ft->last = NULL;
2104 }
2105 
2106 SPATIALITE_DECLARE geojson_property_ptr
geojson_get_property_by_name(geojson_feature_ptr ft,const char * name)2107 geojson_get_property_by_name (geojson_feature_ptr ft, const char *name)
2108 {
2109 /* will return the pointer to a Property indentified by its name */
2110     geojson_property_ptr pp;
2111     if (ft == NULL || name == NULL)
2112 	return NULL;
2113 
2114     pp = ft->first;
2115     while (pp != NULL)
2116       {
2117 	  if (strcasecmp (pp->name, name) == 0)
2118 	      return pp;
2119 	  pp = pp->next;
2120       }
2121     return NULL;
2122 }
2123 
2124 static int
vgeojson_has_metadata(sqlite3 * db,int * geotype)2125 vgeojson_has_metadata (sqlite3 * db, int *geotype)
2126 {
2127 /* testing the layout of virts_geometry_columns table */
2128     char **results;
2129     int ret;
2130     int rows;
2131     int columns;
2132     int i;
2133     int ok_virt_name = 0;
2134     int ok_virt_geometry = 0;
2135     int ok_srid = 0;
2136     int ok_geometry_type = 0;
2137     int ok_type = 0;
2138     int ok_coord_dimension = 0;
2139 
2140     ret =
2141 	sqlite3_get_table (db, "PRAGMA table_info(virts_geometry_columns)",
2142 			   &results, &rows, &columns, NULL);
2143     if (ret != SQLITE_OK)
2144 	return 0;
2145     for (i = 1; i <= rows; i++)
2146       {
2147 	  if (strcasecmp ("virt_name", results[(i * columns) + 1]) == 0)
2148 	      ok_virt_name = 1;
2149 	  if (strcasecmp ("virt_geometry", results[(i * columns) + 1]) == 0)
2150 	      ok_virt_geometry = 1;
2151 	  if (strcasecmp ("srid", results[(i * columns) + 1]) == 0)
2152 	      ok_srid = 1;
2153 	  if (strcasecmp ("geometry_type", results[(i * columns) + 1]) == 0)
2154 	      ok_geometry_type = 1;
2155 	  if (strcasecmp ("type", results[(i * columns) + 1]) == 0)
2156 	      ok_type = 1;
2157 	  if (strcasecmp ("coord_dimension", results[(i * columns) + 1]) == 0)
2158 	      ok_coord_dimension = 1;
2159       }
2160     sqlite3_free_table (results);
2161 
2162     if (ok_virt_name && ok_virt_geometry && ok_srid && ok_geometry_type
2163 	&& ok_coord_dimension)
2164       {
2165 	  *geotype = 1;
2166 	  return 1;
2167       }
2168     if (ok_virt_name && ok_virt_geometry && ok_srid && ok_type)
2169       {
2170 	  *geotype = 0;
2171 	  return 1;
2172       }
2173     return 0;
2174 }
2175 
2176 static geojson_property_ptr
vgeojson_get_property_by_name(VirtualGeoJsonCursorPtr cursor,const char * name)2177 vgeojson_get_property_by_name (VirtualGeoJsonCursorPtr cursor, const char *name)
2178 {
2179 /* attempting to retrieve a Property from the current Feature (by property name) */
2180     geojson_feature_ptr ft = cursor->Feature;
2181     geojson_property_ptr prop;
2182     if (ft == NULL)
2183 	return NULL;
2184     prop = ft->first;
2185     while (prop != NULL)
2186       {
2187 	  if (prop->name != NULL)
2188 	    {
2189 		if (strcasecmp (prop->name, name) == 0)
2190 		    return prop;
2191 	    }
2192 	  prop = prop->next;
2193       }
2194     return NULL;
2195 }
2196 
2197 static geojson_property_ptr
vgeojson_get_property_by_col(VirtualGeoJsonCursorPtr cursor,int column)2198 vgeojson_get_property_by_col (VirtualGeoJsonCursorPtr cursor, int column)
2199 {
2200 /* attempting to retrieve a Property from the current Feature (by column index) */
2201     int icol = 0;
2202     geojson_column_ptr col;
2203     geojson_parser_ptr parser = cursor->pVtab->Parser;
2204     if (parser == NULL)
2205 	return NULL;
2206     col = parser->first_col;
2207     while (col != NULL)
2208       {
2209 	  if (icol == column)
2210 	      return vgeojson_get_property_by_name (cursor, col->name);
2211 	  icol++;
2212 	  col = col->next;
2213       }
2214     return NULL;
2215 }
2216 
2217 static void
vgeojson_get_extent(VirtualGeoJsonPtr p_vt)2218 vgeojson_get_extent (VirtualGeoJsonPtr p_vt)
2219 {
2220 /* determining the Full Extent */
2221     int fid;
2222     geojson_feature_ptr ft;
2223     char *error_message;
2224     gaiaGeomCollPtr geom;
2225     if (!(p_vt->Valid))
2226 	return;
2227 
2228     for (fid = 0; fid < p_vt->Parser->count; fid++)
2229       {
2230 	  ft = p_vt->Parser->features + fid;
2231 	  if (!geojson_init_feature (p_vt->Parser, ft, &error_message))
2232 	    {
2233 		/* an error occurred */
2234 		spatialite_e ("%s\n", error_message);
2235 		sqlite3_free (error_message);
2236 		p_vt->Valid = 0;
2237 		return;
2238 	    }
2239 	  geom = gaiaParseGeoJSON ((const unsigned char *) (ft->geometry));
2240 	  if (geom != NULL)
2241 	    {
2242 		if (geom->MinX < p_vt->MinX)
2243 		    p_vt->MinX = geom->MinX;
2244 		if (geom->MaxX > p_vt->MaxX)
2245 		    p_vt->MaxX = geom->MaxX;
2246 		if (geom->MinY < p_vt->MinY)
2247 		    p_vt->MinY = geom->MinY;
2248 		if (geom->MaxY > p_vt->MaxY)
2249 		    p_vt->MaxY = geom->MaxY;
2250 		gaiaFreeGeomColl (geom);
2251 	    }
2252 	  geojson_reset_feature (ft);
2253       }
2254 }
2255 
2256 static int
vgeojson_create(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVTab,char ** pzErr)2257 vgeojson_create (sqlite3 * db, void *pAux, int argc, const char *const *argv,
2258 		 sqlite3_vtab ** ppVTab, char **pzErr)
2259 {
2260 /* creates the virtual table connected to some GeoJSON file */
2261     char *sql;
2262     VirtualGeoJsonPtr p_vt;
2263     char path[2048];
2264     char ColnameCase[128];
2265     const char *pColnameCase;
2266     int len;
2267     const char *pPath = NULL;
2268     int srid = 4326;
2269     int colname_case = GAIA_DBF_COLNAME_LOWERCASE;
2270     char *xname;
2271     int geotype;
2272     int ret;
2273     sqlite3_stmt *stmt = NULL;
2274     FILE *in;
2275     char *error_message = NULL;
2276     geojson_parser_ptr parser;
2277     if (pAux)
2278 	pAux = pAux;		/* unused arg warning suppression */
2279 /* checking for GeoJSON PATH */
2280     if (argc == 4 || argc == 5 || argc == 6)
2281       {
2282 	  pPath = argv[3];
2283 	  len = strlen (pPath);
2284 	  if ((*(pPath + 0) == '\'' || *(pPath + 0) == '"')
2285 	      && (*(pPath + len - 1) == '\'' || *(pPath + len - 1) == '"'))
2286 	    {
2287 		/* the path is enclosed between quotes - we need to dequote it */
2288 		strcpy (path, pPath + 1);
2289 		len = strlen (path);
2290 		*(path + len - 1) = '\0';
2291 	    }
2292 	  else
2293 	      strcpy (path, pPath);
2294 	  if (argc >= 5)
2295 	    {
2296 		srid = atoi (argv[4]);
2297 		if (srid < 0)
2298 		    srid = -1;
2299 	    }
2300 	  if (argc >= 6)
2301 	    {
2302 		pColnameCase = argv[5];
2303 		len = strlen (pColnameCase);
2304 		if ((*(pColnameCase + 0) == '\'' || *(pColnameCase + 0) == '"')
2305 		    && (*(pColnameCase + len - 1) == '\''
2306 			|| *(pColnameCase + len - 1) == '"'))
2307 		  {
2308 		      /* the colcase-name is enclosed between quotes - we need to dequote it */
2309 		      strcpy (ColnameCase, pColnameCase + 1);
2310 		      len = strlen (ColnameCase);
2311 		      *(ColnameCase + len - 1) = '\0';
2312 		  }
2313 		else
2314 		    strcpy (ColnameCase, pColnameCase);
2315 		if (strcasecmp (ColnameCase, "uppercase") == 0
2316 		    || strcasecmp (ColnameCase, "upper") == 0)
2317 		    colname_case = GAIA_DBF_COLNAME_UPPERCASE;
2318 		else if (strcasecmp (ColnameCase, "samecase") == 0
2319 			 || strcasecmp (ColnameCase, "same") == 0)
2320 		    colname_case = GAIA_DBF_COLNAME_CASE_IGNORE;
2321 		else
2322 		    colname_case = GAIA_DBF_COLNAME_LOWERCASE;
2323 	    }
2324       }
2325     else
2326       {
2327 	  *pzErr =
2328 	      sqlite3_mprintf
2329 	      ("[VirtualGeoJSON module] CREATE VIRTUAL: illegal arg list {geojson_path [ , srid [ , colname_case ]] }");
2330 	  return SQLITE_ERROR;
2331       }
2332     p_vt = (VirtualGeoJsonPtr) sqlite3_malloc (sizeof (VirtualGeoJson));
2333     if (!p_vt)
2334 	return SQLITE_NOMEM;
2335     p_vt->pModule = &my_geojson_module;
2336     p_vt->nRef = 0;
2337     p_vt->zErrMsg = NULL;
2338     p_vt->db = db;
2339     p_vt->Srid = srid;
2340     p_vt->Valid = 0;
2341     p_vt->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2342     p_vt->DimensionModel = GAIA_XY;
2343     len = strlen (argv[2]);
2344     p_vt->TableName = malloc (len + 1);
2345     strcpy (p_vt->TableName, argv[2]);
2346     p_vt->MinX = DBL_MAX;
2347     p_vt->MinY = DBL_MAX;
2348     p_vt->MaxX = -DBL_MAX;
2349     p_vt->MaxY = -DBL_MAX;
2350 
2351 /* attempting to open the GeoJSON file for reading */
2352 #ifdef _WIN32
2353     in = gaia_win_fopen (path, "rb");
2354 #else
2355     in = fopen (path, "rb");
2356 #endif
2357     if (in == NULL)
2358       {
2359 	  error_message =
2360 	      sqlite3_mprintf
2361 	      ("GeoJSON parser: unable to open %s for reading\n", path);
2362 	  goto err;
2363       }
2364 /* creating the GeoJSON parser */
2365     parser = geojson_create_parser (in);
2366     if (!geojson_parser_init (parser, &error_message))
2367 	goto err;
2368     if (!geojson_create_features_index (parser, &error_message))
2369 	goto err;
2370     if (!geojson_check_features (parser, &error_message))
2371 	goto err;
2372     p_vt->Valid = 1;
2373     p_vt->Parser = parser;
2374     goto ok;
2375   err:
2376     if (error_message != NULL)
2377       {
2378 	  spatialite_e ("%s\n", error_message);
2379 	  sqlite3_free (error_message);
2380       }
2381   ok:
2382     vgeojson_get_extent (p_vt);
2383     if (!(p_vt->Valid))
2384       {
2385 	  /* something is going the wrong way; creating a stupid default table */
2386 	  xname = gaiaDoubleQuotedSql ((const char *) argv[2]);
2387 	  sql =
2388 	      sqlite3_mprintf
2389 	      ("CREATE TABLE \"%s\" (FID INTEGER, Geometry BLOB)", xname);
2390 	  free (xname);
2391 	  if (sqlite3_declare_vtab (db, sql) != SQLITE_OK)
2392 	    {
2393 		sqlite3_free (sql);
2394 		*pzErr =
2395 		    sqlite3_mprintf
2396 		    ("[VirtualGeoJSON module] cannot build a table from the GeoJSON file\n");
2397 		return SQLITE_ERROR;
2398 	    }
2399 	  sqlite3_free (sql);
2400 	  *ppVTab = (sqlite3_vtab *) p_vt;
2401 	  return SQLITE_OK;
2402       }
2403     if (parser->n_points > 0 && parser->n_linestrings == 0
2404 	&& parser->n_polygons == 0 && parser->n_mpoints == 0
2405 	&& parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
2406 	&& parser->n_geomcolls == 0)
2407 	p_vt->DeclaredType = GAIA_POINT;
2408     if (parser->n_mpoints > 0 && parser->n_linestrings == 0
2409 	&& parser->n_polygons == 0 && parser->n_mlinestrings == 0
2410 	&& parser->n_mpolygons == 0 && parser->n_geomcolls == 0)
2411 	p_vt->DeclaredType = GAIA_MULTIPOINT;
2412     if (parser->n_points == 0 && parser->n_linestrings > 0
2413 	&& parser->n_polygons == 0 && parser->n_mpoints == 0
2414 	&& parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
2415 	&& parser->n_geomcolls == 0)
2416 	p_vt->DeclaredType = GAIA_LINESTRING;
2417     if (parser->n_mlinestrings > 0 && parser->n_points == 0
2418 	&& parser->n_polygons == 0 && parser->n_mpoints == 0
2419 	&& parser->n_mpolygons == 0 && parser->n_geomcolls == 0)
2420 	p_vt->DeclaredType = GAIA_MULTILINESTRING;
2421     if (parser->n_points == 0 && parser->n_linestrings > 0
2422 	&& parser->n_polygons > 0 && parser->n_mpoints == 0
2423 	&& parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
2424 	&& parser->n_geomcolls == 0)
2425 	p_vt->DeclaredType = GAIA_POLYGON;
2426     if (parser->n_mpolygons > 0 && parser->n_points == 0
2427 	&& parser->n_linestrings == 0 && parser->n_mpoints == 0
2428 	&& parser->n_mlinestrings == 0 && parser->n_geomcolls == 0)
2429 	p_vt->DeclaredType = GAIA_MULTIPOLYGON;
2430     if ((parser->n_points + parser->n_mpoints) > 0
2431 	&& (parser->n_linestrings + parser->n_mlinestrings) > 0)
2432 	p_vt->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2433     if ((parser->n_points + parser->n_mpoints) > 0
2434 	&& (parser->n_polygons + parser->n_mpolygons) > 0)
2435 	p_vt->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2436     if ((parser->n_linestrings + parser->n_mlinestrings) > 0
2437 	&& (parser->n_polygons + parser->n_mpolygons) > 0)
2438 	p_vt->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2439     if (parser->n_geom_2d > 0 && parser->n_geom_3d == 0
2440 	&& parser->n_geom_4d == 0)
2441 	p_vt->DimensionModel = GAIA_XY;
2442     if (parser->n_geom_3d > 0 && parser->n_geom_4d == 0)
2443 	p_vt->DimensionModel = GAIA_XY_Z;
2444     if (parser->n_geom_4d > 0)
2445 	p_vt->DimensionModel = GAIA_XY_Z_M;
2446 /* preparing the COLUMNs for this VIRTUAL TABLE */
2447     sql =
2448 	geojson_sql_create_virtual_table (parser, (const char *) argv[2],
2449 					  colname_case);
2450     ret = sqlite3_declare_vtab (db, sql);
2451     sqlite3_free (sql);
2452     if (ret != SQLITE_OK)
2453       {
2454 	  *pzErr =
2455 	      sqlite3_mprintf
2456 	      ("[VirtualGeoJSON module] CREATE VIRTUAL: invalid SQL statement \"%s\"",
2457 	       sql);
2458 	  return SQLITE_ERROR;
2459       }
2460     *ppVTab = (sqlite3_vtab *) p_vt;
2461 
2462     if (vgeojson_has_metadata (db, &geotype))
2463       {
2464 	  /* registering the Virtual Geometry */
2465 	  if (geotype)
2466 	    {
2467 		int xtype = 0;
2468 		int xdims = 0;
2469 		switch (p_vt->DeclaredType)
2470 		  {
2471 		  case GAIA_POINT:
2472 		      switch (p_vt->DimensionModel)
2473 			{
2474 			case GAIA_XY_Z_M:
2475 			    xtype = 3001;
2476 			    xdims = 4;
2477 			    break;
2478 			case GAIA_XY_M:
2479 			    xtype = 2001;
2480 			    xdims = 3;
2481 			    break;
2482 			case GAIA_XY_Z:
2483 			    xtype = 1001;
2484 			    xdims = 3;
2485 			    break;
2486 			default:
2487 			    xtype = 1;
2488 			    xdims = 2;
2489 			    break;
2490 			};
2491 		      break;
2492 		  case GAIA_LINESTRING:
2493 		      switch (p_vt->DimensionModel)
2494 			{
2495 			case GAIA_XY_Z_M:
2496 			    xtype = 3002;
2497 			    xdims = 4;
2498 			    break;
2499 			case GAIA_XY_M:
2500 			    xtype = 2002;
2501 			    xdims = 3;
2502 			    break;
2503 			case GAIA_XY_Z:
2504 			    xtype = 1002;
2505 			    xdims = 3;
2506 			    break;
2507 			default:
2508 			    xtype = 2;
2509 			    xdims = 2;
2510 			    break;
2511 			};
2512 		      break;
2513 		  case GAIA_POLYGON:
2514 		      switch (p_vt->DimensionModel)
2515 			{
2516 			case GAIA_XY_Z_M:
2517 			    xtype = 3003;
2518 			    xdims = 4;
2519 			    break;
2520 			case GAIA_XY_M:
2521 			    xtype = 2003;
2522 			    xdims = 3;
2523 			    break;
2524 			case GAIA_XY_Z:
2525 			    xtype = 1003;
2526 			    xdims = 3;
2527 			    break;
2528 			default:
2529 			    xtype = 3;
2530 			    xdims = 2;
2531 			    break;
2532 			};
2533 		      break;
2534 		  case GAIA_MULTIPOINT:
2535 		      switch (p_vt->DimensionModel)
2536 			{
2537 			case GAIA_XY_Z_M:
2538 			    xtype = 3004;
2539 			    xdims = 4;
2540 			    break;
2541 			case GAIA_XY_M:
2542 			    xtype = 2004;
2543 			    xdims = 3;
2544 			    break;
2545 			case GAIA_XY_Z:
2546 			    xtype = 1004;
2547 			    xdims = 3;
2548 			    break;
2549 			default:
2550 			    xtype = 4;
2551 			    xdims = 2;
2552 			    break;
2553 			};
2554 		      break;
2555 		  case GAIA_MULTILINESTRING:
2556 		      switch (p_vt->DimensionModel)
2557 			{
2558 			case GAIA_XY_Z_M:
2559 			    xtype = 3005;
2560 			    xdims = 4;
2561 			    break;
2562 			case GAIA_XY_M:
2563 			    xtype = 2005;
2564 			    xdims = 3;
2565 			    break;
2566 			case GAIA_XY_Z:
2567 			    xtype = 1005;
2568 			    xdims = 3;
2569 			    break;
2570 			default:
2571 			    xtype = 5;
2572 			    xdims = 2;
2573 			    break;
2574 			};
2575 		      break;
2576 		  case GAIA_MULTIPOLYGON:
2577 		      switch (p_vt->DimensionModel)
2578 			{
2579 			case GAIA_XY_Z_M:
2580 			    xtype = 3006;
2581 			    xdims = 4;
2582 			    break;
2583 			case GAIA_XY_M:
2584 			    xtype = 2006;
2585 			    xdims = 3;
2586 			    break;
2587 			case GAIA_XY_Z:
2588 			    xtype = 1006;
2589 			    xdims = 3;
2590 			    break;
2591 			default:
2592 			    xtype = 6;
2593 			    xdims = 2;
2594 			    break;
2595 			};
2596 		      break;
2597 		  case GAIA_GEOMETRYCOLLECTION:
2598 		      switch (p_vt->DimensionModel)
2599 			{
2600 			case GAIA_XY_Z_M:
2601 			    xtype = 3007;
2602 			    xdims = 4;
2603 			    break;
2604 			case GAIA_XY_M:
2605 			    xtype = 2007;
2606 			    xdims = 3;
2607 			    break;
2608 			case GAIA_XY_Z:
2609 			    xtype = 1007;
2610 			    xdims = 3;
2611 			    break;
2612 			default:
2613 			    xtype = 7;
2614 			    xdims = 2;
2615 			    break;
2616 			};
2617 		      break;
2618 		  };
2619 		sql =
2620 		    sqlite3_mprintf
2621 		    ("INSERT OR IGNORE INTO virts_geometry_columns "
2622 		     "(virt_name, virt_geometry, geometry_type, coord_dimension, srid) "
2623 		     "VALUES (Lower(%Q), 'geometry', %d, %d, %d)", argv[2],
2624 		     xtype, xdims, p_vt->Srid);
2625 	    }
2626 	  else
2627 	    {
2628 		const char *xgtype = "GEOMETRY";
2629 		switch (p_vt->DeclaredType)
2630 		  {
2631 		  case GAIA_POINT:
2632 		      xgtype = "POINT";
2633 		      break;
2634 		  case GAIA_LINESTRING:
2635 		      xgtype = "LINESTRING";
2636 		      break;
2637 		  case GAIA_POLYGON:
2638 		      xgtype = "POLYGON";
2639 		      break;
2640 		  case GAIA_MULTIPOINT:
2641 		      xgtype = "MULTIPOINT";
2642 		      break;
2643 		  case GAIA_MULTILINESTRING:
2644 		      xgtype = "MULTILINESTRING";
2645 		      break;
2646 		  case GAIA_MULTIPOLYGON:
2647 		      xgtype = "MULTIPOLYGON";
2648 		      break;
2649 		  case GAIA_GEOMETRYCOLLECTION:
2650 		      xgtype = "GEOMETRYCOLLECTION";
2651 		      break;
2652 		  };
2653 		sql =
2654 		    sqlite3_mprintf
2655 		    ("INSERT OR IGNORE INTO virts_geometry_columns "
2656 		     "(virt_name, virt_geometry, type, srid) "
2657 		     "VALUES (Lower(%Q), 'geometry', %Q, %d)", argv[2], xgtype,
2658 		     p_vt->Srid);
2659 	    }
2660 	  sqlite3_exec (db, sql, NULL, NULL, NULL);
2661 	  sqlite3_free (sql);
2662       }
2663     if (checkSpatialMetaData (db) == 3)
2664       {
2665 	  /* current metadata style >= v.4.0.0 */
2666 
2667 	  /* inserting a row into VIRTS_GEOMETRY_COLUMNS_AUTH */
2668 	  sql = sqlite3_mprintf ("INSERT OR IGNORE INTO "
2669 				 "virts_geometry_columns_auth (virt_name, virt_geometry, hidden) "
2670 				 "VALUES (Lower(%Q), 'geometry', 0)", argv[2]);
2671 	  sqlite3_exec (db, sql, NULL, NULL, NULL);
2672 	  sqlite3_free (sql);
2673 
2674 	  /* inserting a row into GEOMETRY_COLUMNS_STATISTICS */
2675 	  sql = sqlite3_mprintf ("INSERT OR IGNORE INTO "
2676 				 "virts_geometry_columns_statistics (virt_name, virt_geometry) "
2677 				 "VALUES (Lower(%Q), 'geometry')", argv[2]);
2678 	  sqlite3_exec (db, sql, NULL, NULL, NULL);
2679 	  sqlite3_free (sql);
2680       }
2681 
2682 /* inserting into the connection cache: Virtual Extent */
2683     sql = "SELECT \"*Add-VirtualTable+Extent\"(?, ?, ?, ?, ?, ?)";
2684     ret = sqlite3_prepare_v2 (db, sql, strlen (sql), &stmt, NULL);
2685     if (ret == SQLITE_OK)
2686       {
2687 	  sqlite3_reset (stmt);
2688 	  sqlite3_clear_bindings (stmt);
2689 	  sqlite3_bind_text (stmt, 1, argv[2], strlen (argv[2]), SQLITE_STATIC);
2690 	  sqlite3_bind_double (stmt, 2, p_vt->MinX);
2691 	  sqlite3_bind_double (stmt, 3, p_vt->MinY);
2692 	  sqlite3_bind_double (stmt, 4, p_vt->MaxX);
2693 	  sqlite3_bind_double (stmt, 5, p_vt->MaxY);
2694 	  sqlite3_bind_int (stmt, 6, p_vt->Srid);
2695 	  ret = sqlite3_step (stmt);
2696       }
2697     sqlite3_finalize (stmt);
2698     return SQLITE_OK;
2699 }
2700 
2701 static int
vgeojson_connect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVTab,char ** pzErr)2702 vgeojson_connect (sqlite3 * db, void *pAux, int argc, const char *const *argv,
2703 		  sqlite3_vtab ** ppVTab, char **pzErr)
2704 {
2705 /* connects the virtual table to some GeoJSON file - simply aliases vgeojson_create() */
2706     return vgeojson_create (db, pAux, argc, argv, ppVTab, pzErr);
2707 }
2708 
2709 static int
vgeojson_best_index(sqlite3_vtab * pVTab,sqlite3_index_info * pIndex)2710 vgeojson_best_index (sqlite3_vtab * pVTab, sqlite3_index_info * pIndex)
2711 {
2712 /* best index selection */
2713     int i;
2714     int iArg = 0;
2715     char str[2048];
2716     char buf[64];
2717 
2718     if (pVTab)
2719 	pVTab = pVTab;		/* unused arg warning suppression */
2720 
2721     *str = '\0';
2722     for (i = 0; i < pIndex->nConstraint; i++)
2723       {
2724 	  if (pIndex->aConstraint[i].usable)
2725 	    {
2726 		iArg++;
2727 		pIndex->aConstraintUsage[i].argvIndex = iArg;
2728 		pIndex->aConstraintUsage[i].omit = 1;
2729 		sprintf (buf, "%d:%d,", pIndex->aConstraint[i].iColumn,
2730 			 pIndex->aConstraint[i].op);
2731 		strcat (str, buf);
2732 	    }
2733       }
2734     if (*str != '\0')
2735       {
2736 	  pIndex->idxStr = sqlite3_mprintf ("%s", str);
2737 	  pIndex->needToFreeIdxStr = 1;
2738       }
2739 
2740     return SQLITE_OK;
2741 }
2742 
2743 static int
vgeojson_disconnect(sqlite3_vtab * pVTab)2744 vgeojson_disconnect (sqlite3_vtab * pVTab)
2745 {
2746 /* disconnects the virtual table */
2747     int ret;
2748     sqlite3_stmt *stmt;
2749     const char *sql;
2750     VirtualGeoJsonPtr p_vt = (VirtualGeoJsonPtr) pVTab;
2751 
2752 /* removing from the connection cache: Virtual Extent */
2753     sql = "SELECT \"*Remove-VirtualTable+Extent\"(?)";
2754     ret = sqlite3_prepare_v2 (p_vt->db, sql, strlen (sql), &stmt, NULL);
2755     if (ret == SQLITE_OK)
2756       {
2757 	  sqlite3_reset (stmt);
2758 	  sqlite3_clear_bindings (stmt);
2759 	  sqlite3_bind_text (stmt, 1, p_vt->TableName, strlen (p_vt->TableName),
2760 			     SQLITE_STATIC);
2761 	  ret = sqlite3_step (stmt);
2762       }
2763     sqlite3_finalize (stmt);
2764 
2765     if (p_vt->TableName != NULL)
2766 	free (p_vt->TableName);
2767     sqlite3_free (p_vt);
2768 
2769     return SQLITE_OK;
2770 }
2771 
2772 static int
vgeojson_destroy(sqlite3_vtab * pVTab)2773 vgeojson_destroy (sqlite3_vtab * pVTab)
2774 {
2775 /* destroys the virtual table - simply aliases vgeojson_disconnect() */
2776     return vgeojson_disconnect (pVTab);
2777 }
2778 
2779 static void
vgeojson_read_row(VirtualGeoJsonCursorPtr cursor)2780 vgeojson_read_row (VirtualGeoJsonCursorPtr cursor)
2781 {
2782 /* trying to read a "row" from the GeoJSON file */
2783     int fid;
2784     geojson_feature_ptr ft;
2785     char *error_message;
2786     if (!(cursor->pVtab->Valid))
2787       {
2788 	  cursor->eof = 1;
2789 	  return;
2790       }
2791     if (cursor->Feature != NULL)
2792 	geojson_reset_feature (cursor->Feature);
2793     fid = cursor->current_fid;
2794     if (fid < 0 || fid >= cursor->pVtab->Parser->count)
2795       {
2796 	  /* normal GeoJSON EOF */
2797 	  cursor->eof = 1;
2798 	  return;
2799       }
2800     ft = cursor->pVtab->Parser->features + fid;
2801     if (!geojson_init_feature (cursor->pVtab->Parser, ft, &error_message))
2802       {
2803 	  /* an error occurred */
2804 	  spatialite_e ("%s\n", error_message);
2805 	  sqlite3_free (error_message);
2806 	  cursor->eof = 1;
2807 	  return;
2808       }
2809     cursor->Feature = ft;
2810 }
2811 
2812 static int
vgeojson_open(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCursor)2813 vgeojson_open (sqlite3_vtab * pVTab, sqlite3_vtab_cursor ** ppCursor)
2814 {
2815 /* opening a new cursor */
2816     VirtualGeoJsonCursorPtr cursor =
2817 	(VirtualGeoJsonCursorPtr)
2818 	sqlite3_malloc (sizeof (VirtualGeoJsonCursor));
2819     if (cursor == NULL)
2820 	return SQLITE_ERROR;
2821     cursor->firstConstraint = NULL;
2822     cursor->lastConstraint = NULL;
2823     cursor->pVtab = (VirtualGeoJsonPtr) pVTab;
2824     cursor->current_fid = 0;
2825     cursor->Feature = NULL;
2826     cursor->eof = 0;
2827     *ppCursor = (sqlite3_vtab_cursor *) cursor;
2828     vgeojson_read_row (cursor);
2829     return SQLITE_OK;
2830 }
2831 
2832 static void
vgeojson_free_constraints(VirtualGeoJsonCursorPtr cursor)2833 vgeojson_free_constraints (VirtualGeoJsonCursorPtr cursor)
2834 {
2835 /* memory cleanup - cursor constraints */
2836     VirtualGeoJsonConstraintPtr pC;
2837     VirtualGeoJsonConstraintPtr pCn;
2838     pC = cursor->firstConstraint;
2839     while (pC)
2840       {
2841 	  pCn = pC->next;
2842 	  if (pC->txtValue)
2843 	      sqlite3_free (pC->txtValue);
2844 	  sqlite3_free (pC);
2845 	  pC = pCn;
2846       }
2847     cursor->firstConstraint = NULL;
2848     cursor->lastConstraint = NULL;
2849 }
2850 
2851 static int
vgeojson_close(sqlite3_vtab_cursor * pCursor)2852 vgeojson_close (sqlite3_vtab_cursor * pCursor)
2853 {
2854 /* closing the cursor */
2855     VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
2856     if (cursor->Feature != NULL)
2857 	geojson_reset_feature (cursor->Feature);
2858     vgeojson_free_constraints (cursor);
2859     sqlite3_free (pCursor);
2860     return SQLITE_OK;
2861 }
2862 
2863 static int
vgeojson_parse_constraint(const char * str,int index,int * iColumn,int * op)2864 vgeojson_parse_constraint (const char *str, int index, int *iColumn, int *op)
2865 {
2866 /* parsing a constraint string */
2867     char buf[64];
2868     const char *in = str;
2869     char *out = buf;
2870     int i = 0;
2871     int found = 0;
2872 
2873     *out = '\0';
2874     while (*in != '\0')
2875       {
2876 	  if (*in == ',')
2877 	    {
2878 		if (index == i)
2879 		  {
2880 		      *out = '\0';
2881 		      found = 1;
2882 		      break;
2883 		  }
2884 		i++;
2885 		in++;
2886 		continue;
2887 	    }
2888 	  if (index == i)
2889 	      *out++ = *in;
2890 	  in++;
2891       }
2892     if (!found)
2893 	return 0;
2894     in = buf;
2895     for (i = 0; i < (int) strlen (buf); i++)
2896       {
2897 	  if (buf[i] == ':')
2898 	    {
2899 		buf[i] = '\0';
2900 		*iColumn = atoi (buf);
2901 		*op = atoi (buf + i + 1);
2902 		return 1;
2903 	    }
2904 	  in++;
2905       }
2906     return 0;
2907 }
2908 
2909 static int
vgeojson_eval_constraints(VirtualGeoJsonCursorPtr cursor)2910 vgeojson_eval_constraints (VirtualGeoJsonCursorPtr cursor)
2911 {
2912 /* evaluating Filter constraints */
2913     int nCol;
2914     geojson_column_ptr col;
2915     geojson_property_ptr prop;
2916     VirtualGeoJsonConstraintPtr pC = cursor->firstConstraint;
2917     if (pC == NULL)
2918 	return 1;
2919     while (pC)
2920       {
2921 	  int ok = 0;
2922 	  if (pC->iColumn == 0)
2923 	    {
2924 		/* the PRIMARY KEY column */
2925 		if (pC->op == SQLITE_INDEX_CONSTRAINT_ISNULL)
2926 		  {
2927 		      ok = 0;
2928 		      goto done;
2929 		  }
2930 		if (pC->op == SQLITE_INDEX_CONSTRAINT_ISNOTNULL)
2931 		  {
2932 		      ok = 1;
2933 		      goto done;
2934 		  }
2935 		if (pC->valueType == 'I')
2936 		  {
2937 		      switch (pC->op)
2938 			{
2939 			case SQLITE_INDEX_CONSTRAINT_EQ:
2940 			    if (cursor->current_fid == pC->intValue)
2941 				ok = 1;
2942 			    break;
2943 			case SQLITE_INDEX_CONSTRAINT_GT:
2944 			    if (cursor->current_fid > pC->intValue)
2945 				ok = 1;
2946 			    break;
2947 			case SQLITE_INDEX_CONSTRAINT_LE:
2948 			    if (cursor->current_fid <= pC->intValue)
2949 				ok = 1;
2950 			    break;
2951 			case SQLITE_INDEX_CONSTRAINT_LT:
2952 			    if (cursor->current_fid < pC->intValue)
2953 				ok = 1;
2954 			    break;
2955 			case SQLITE_INDEX_CONSTRAINT_GE:
2956 			    if (cursor->current_fid >= pC->intValue)
2957 				ok = 1;
2958 			    break;
2959 			case SQLITE_INDEX_CONSTRAINT_NE:
2960 			    if (cursor->current_fid != pC->intValue)
2961 				ok = 1;
2962 			    break;
2963 			};
2964 		  }
2965 		goto done;
2966 	    }
2967 	  if (pC->iColumn == 1)
2968 	    {
2969 		/* the Geometry column */
2970 		if (cursor->Feature != NULL)
2971 		  {
2972 		      switch (pC->op)
2973 			{
2974 			case SQLITE_INDEX_CONSTRAINT_ISNULL:
2975 			    if (cursor->Feature->geometry == NULL)
2976 				ok = 1;
2977 			    break;
2978 			case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
2979 			    if (cursor->Feature->geometry != NULL)
2980 				ok = 1;
2981 			    break;
2982 			};
2983 
2984 		  }
2985 		else
2986 		  {
2987 		      if (pC->op == SQLITE_INDEX_CONSTRAINT_ISNULL)
2988 			  ok = 1;
2989 		  }
2990 		goto done;
2991 	    }
2992 	  /* any other ordinary column */
2993 	  nCol = 2;
2994 	  col = cursor->pVtab->Parser->first_col;
2995 	  while (col)
2996 	    {
2997 		if (nCol != pC->iColumn)
2998 		  {
2999 		      nCol++;
3000 		      col = col->next;
3001 		      continue;
3002 		  }
3003 		if (col->name == NULL)
3004 		  {
3005 		      ok = 1;
3006 		      goto done;
3007 		  }
3008 		prop = vgeojson_get_property_by_name (cursor, col->name);
3009 		if (prop == NULL)
3010 		  {
3011 		      nCol++;
3012 		      col = col->next;
3013 		      continue;
3014 		  }
3015 		switch (pC->op)
3016 		  {
3017 		  case SQLITE_INDEX_CONSTRAINT_ISNULL:
3018 		      if (prop->type == GEOJSON_NULL)
3019 			  ok = 1;
3020 		      break;
3021 		  case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
3022 		      if (prop->type != GEOJSON_NULL)
3023 			  ok = 1;
3024 		      break;
3025 		  };
3026 		if (ok)
3027 		    break;
3028 		switch (prop->type)
3029 		  {
3030 		  case GEOJSON_INTEGER:
3031 		      if (pC->valueType == 'I')
3032 			{
3033 			    switch (pC->op)
3034 			      {
3035 			      case SQLITE_INDEX_CONSTRAINT_EQ:
3036 				  if (prop->int_value == pC->intValue)
3037 				      ok = 1;
3038 				  break;
3039 			      case SQLITE_INDEX_CONSTRAINT_GT:
3040 				  if (prop->int_value > pC->intValue)
3041 				      ok = 1;
3042 				  break;
3043 			      case SQLITE_INDEX_CONSTRAINT_LE:
3044 				  if (prop->int_value <= pC->intValue)
3045 				      ok = 1;
3046 				  break;
3047 			      case SQLITE_INDEX_CONSTRAINT_LT:
3048 				  if (prop->int_value < pC->intValue)
3049 				      ok = 1;
3050 				  break;
3051 			      case SQLITE_INDEX_CONSTRAINT_GE:
3052 				  if (prop->int_value >= pC->intValue)
3053 				      ok = 1;
3054 				  break;
3055 			      case SQLITE_INDEX_CONSTRAINT_NE:
3056 				  if (prop->int_value != pC->intValue)
3057 				      ok = 1;
3058 				  break;
3059 			      };
3060 			}
3061 		      break;
3062 		  case GEOJSON_DOUBLE:
3063 		      if (pC->valueType == 'I')
3064 			{
3065 			    switch (pC->op)
3066 			      {
3067 			      case SQLITE_INDEX_CONSTRAINT_EQ:
3068 				  if (prop->dbl_value == pC->intValue)
3069 				      ok = 1;
3070 				  break;
3071 			      case SQLITE_INDEX_CONSTRAINT_GT:
3072 				  if (prop->dbl_value > pC->intValue)
3073 				      ok = 1;
3074 				  break;
3075 			      case SQLITE_INDEX_CONSTRAINT_LE:
3076 				  if (prop->dbl_value <= pC->intValue)
3077 				      ok = 1;
3078 				  break;
3079 			      case SQLITE_INDEX_CONSTRAINT_LT:
3080 				  if (prop->dbl_value < pC->intValue)
3081 				      ok = 1;
3082 				  break;
3083 			      case SQLITE_INDEX_CONSTRAINT_GE:
3084 				  if (prop->dbl_value >= pC->intValue)
3085 				      ok = 1;
3086 				  break;
3087 			      case SQLITE_INDEX_CONSTRAINT_NE:
3088 				  if (prop->dbl_value != pC->intValue)
3089 				      ok = 1;
3090 				  break;
3091 			      };
3092 			}
3093 		      if (pC->valueType == 'D')
3094 			{
3095 			    switch (pC->op)
3096 			      {
3097 			      case SQLITE_INDEX_CONSTRAINT_EQ:
3098 				  if (prop->dbl_value == pC->dblValue)
3099 				      ok = 1;
3100 				  break;
3101 			      case SQLITE_INDEX_CONSTRAINT_GT:
3102 				  if (prop->dbl_value > pC->dblValue)
3103 				      ok = 1;
3104 				  break;
3105 			      case SQLITE_INDEX_CONSTRAINT_LE:
3106 				  if (prop->dbl_value <= pC->dblValue)
3107 				      ok = 1;
3108 				  break;
3109 			      case SQLITE_INDEX_CONSTRAINT_LT:
3110 				  if (prop->dbl_value < pC->dblValue)
3111 				      ok = 1;
3112 				  break;
3113 			      case SQLITE_INDEX_CONSTRAINT_GE:
3114 				  if (prop->dbl_value >= pC->dblValue)
3115 				      ok = 1;
3116 				  break;
3117 			      case SQLITE_INDEX_CONSTRAINT_NE:
3118 				  if (prop->dbl_value != pC->dblValue)
3119 				      ok = 1;
3120 				  break;
3121 			      }
3122 			}
3123 		      break;
3124 		  case GEOJSON_TEXT:
3125 		      if (pC->valueType == 'T' && pC->txtValue)
3126 			{
3127 			    int ret;
3128 			    ret = strcmp (prop->txt_value, pC->txtValue);
3129 			    switch (pC->op)
3130 			      {
3131 			      case SQLITE_INDEX_CONSTRAINT_EQ:
3132 				  if (ret == 0)
3133 				      ok = 1;
3134 				  break;
3135 			      case SQLITE_INDEX_CONSTRAINT_GT:
3136 				  if (ret > 0)
3137 				      ok = 1;
3138 				  break;
3139 			      case SQLITE_INDEX_CONSTRAINT_LE:
3140 				  if (ret <= 0)
3141 				      ok = 1;
3142 				  break;
3143 			      case SQLITE_INDEX_CONSTRAINT_LT:
3144 				  if (ret < 0)
3145 				      ok = 1;
3146 				  break;
3147 			      case SQLITE_INDEX_CONSTRAINT_GE:
3148 				  if (ret >= 0)
3149 				      ok = 1;
3150 				  break;
3151 			      case SQLITE_INDEX_CONSTRAINT_NE:
3152 				  if (ret != 0)
3153 				      ok = 1;
3154 				  break;
3155 #ifdef HAVE_DECL_SQLITE_INDEX_CONSTRAINT_LIKE
3156 			      case SQLITE_INDEX_CONSTRAINT_LIKE:
3157 				  ret =
3158 				      sqlite3_strlike (pC->txtValue,
3159 						       prop->txt_value, 0);
3160 				  if (ret == 0)
3161 				      ok = 1;
3162 				  break;
3163 #endif
3164 			      };
3165 			}
3166 		      break;
3167 		  };
3168 		break;
3169 	    }
3170 	done:
3171 	  if (!ok)
3172 	      return 0;
3173 	  pC = pC->next;
3174       }
3175     return 1;
3176 }
3177 
3178 static int
vgeojson_filter(sqlite3_vtab_cursor * pCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)3179 vgeojson_filter (sqlite3_vtab_cursor * pCursor, int idxNum, const char *idxStr,
3180 		 int argc, sqlite3_value ** argv)
3181 {
3182 /* setting up a cursor filter */
3183     int i;
3184     int iColumn;
3185     int op;
3186     int len;
3187     VirtualGeoJsonConstraintPtr pC;
3188     VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3189     if (idxNum)
3190 	idxNum = idxNum;	/* unused arg warning suppression */
3191 
3192 /* resetting any previously set filter constraint */
3193     vgeojson_free_constraints (cursor);
3194 
3195     for (i = 0; i < argc; i++)
3196       {
3197 	  if (!vgeojson_parse_constraint (idxStr, i, &iColumn, &op))
3198 	      continue;
3199 	  pC = sqlite3_malloc (sizeof (VirtualGeoJsonConstraint));
3200 	  if (!pC)
3201 	      continue;
3202 	  pC->iColumn = iColumn;
3203 	  pC->op = op;
3204 	  pC->valueType = '\0';
3205 	  pC->txtValue = NULL;
3206 	  pC->next = NULL;
3207 
3208 	  if (sqlite3_value_type (argv[i]) == SQLITE_INTEGER)
3209 	    {
3210 		pC->valueType = 'I';
3211 		pC->intValue = sqlite3_value_int64 (argv[i]);
3212 	    }
3213 	  if (sqlite3_value_type (argv[i]) == SQLITE_FLOAT)
3214 	    {
3215 		pC->valueType = 'D';
3216 		pC->dblValue = sqlite3_value_double (argv[i]);
3217 	    }
3218 	  if (sqlite3_value_type (argv[i]) == SQLITE_TEXT)
3219 	    {
3220 		pC->valueType = 'T';
3221 		len = sqlite3_value_bytes (argv[i]) + 1;
3222 		pC->txtValue = (char *) sqlite3_malloc (len);
3223 		if (pC->txtValue)
3224 		    strcpy (pC->txtValue,
3225 			    (char *) sqlite3_value_text (argv[i]));
3226 	    }
3227 	  if (cursor->firstConstraint == NULL)
3228 	      cursor->firstConstraint = pC;
3229 	  if (cursor->lastConstraint != NULL)
3230 	      cursor->lastConstraint->next = pC;
3231 	  cursor->lastConstraint = pC;
3232       }
3233 
3234     cursor->current_fid = 0;
3235     cursor->eof = 0;
3236     while (1)
3237       {
3238 	  vgeojson_read_row (cursor);
3239 	  if (cursor->eof)
3240 	      break;
3241 	  if (vgeojson_eval_constraints (cursor))
3242 	      break;
3243 	  cursor->current_fid += 1;
3244       }
3245     return SQLITE_OK;
3246 }
3247 
3248 static int
vgeojson_next(sqlite3_vtab_cursor * pCursor)3249 vgeojson_next (sqlite3_vtab_cursor * pCursor)
3250 {
3251 /* fetching a next row from cursor */
3252     VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3253     cursor->current_fid += 1;
3254     while (1)
3255       {
3256 	  vgeojson_read_row (cursor);
3257 	  if (cursor->eof)
3258 	      break;
3259 	  if (vgeojson_eval_constraints (cursor))
3260 	      break;
3261 	  cursor->current_fid += 1;
3262       }
3263     return SQLITE_OK;
3264 }
3265 
3266 static int
vgeojson_eof(sqlite3_vtab_cursor * pCursor)3267 vgeojson_eof (sqlite3_vtab_cursor * pCursor)
3268 {
3269 /* cursor EOF */
3270     VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3271     return cursor->eof;
3272 }
3273 
3274 static gaiaGeomCollPtr
vgeojson_get_geometry(VirtualGeoJsonCursorPtr cursor)3275 vgeojson_get_geometry (VirtualGeoJsonCursorPtr cursor)
3276 {
3277 /* attempting to return a normalized GeoJSON geometry */
3278     gaiaGeomCollPtr geom;
3279     if (cursor == NULL)
3280 	return NULL;
3281     if (cursor->Feature == NULL)
3282 	return NULL;
3283     if (cursor->Feature->geometry == NULL)
3284 	return NULL;
3285 
3286     geom =
3287 	gaiaParseGeoJSON ((const unsigned char *) (cursor->Feature->geometry));
3288     if (geom == NULL)
3289 	return NULL;
3290     geom->Srid = cursor->pVtab->Srid;
3291     geom->DeclaredType = cursor->pVtab->DeclaredType;
3292     if (cursor->pVtab->DimensionModel != geom->DimensionModel)
3293       {
3294 	  /* normalizing Dimensions */
3295 	  gaiaGeomCollPtr g2;
3296 	  switch (cursor->pVtab->DimensionModel)
3297 	    {
3298 	    case GAIA_XY_Z_M:
3299 		g2 = gaiaCastGeomCollToXYZM (geom);
3300 		break;
3301 	    case GAIA_XY_Z:
3302 		g2 = gaiaCastGeomCollToXYZ (geom);
3303 		break;
3304 	    case GAIA_XY_M:
3305 		g2 = gaiaCastGeomCollToXYM (geom);
3306 		break;
3307 	    case GAIA_XY:
3308 	    default:
3309 		g2 = gaiaCastGeomCollToXY (geom);
3310 		break;
3311 	    };
3312 	  gaiaFreeGeomColl (geom);
3313 	  geom = g2;
3314       }
3315     return geom;
3316 }
3317 
3318 static int
vgeojson_column(sqlite3_vtab_cursor * pCursor,sqlite3_context * pContext,int column)3319 vgeojson_column (sqlite3_vtab_cursor * pCursor, sqlite3_context * pContext,
3320 		 int column)
3321 {
3322 /* fetching value for the Nth column */
3323     gaiaGeomCollPtr geom;
3324     geojson_property_ptr prop;
3325     VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3326     if (column == 0)
3327       {
3328 	  /* the PRIMARY KEY column */
3329 	  sqlite3_result_int (pContext, cursor->current_fid);
3330 	  return SQLITE_OK;
3331       }
3332     if (column == 1)
3333       {
3334 	  /* the GEOMETRY column */
3335 	  geom = vgeojson_get_geometry (cursor);
3336 	  if (geom)
3337 	    {
3338 		unsigned char *blob;
3339 		int blobSize;
3340 		gaiaToSpatiaLiteBlobWkb (geom, &blob, &blobSize);
3341 		sqlite3_result_blob (pContext, blob, blobSize, free);
3342 		gaiaFreeGeomColl (geom);
3343 	    }
3344 	  else
3345 	      sqlite3_result_null (pContext);
3346 	  return SQLITE_OK;
3347       }
3348     prop = vgeojson_get_property_by_col (cursor, column - 2);
3349     if (prop == NULL)
3350       {
3351 	  sqlite3_result_null (pContext);
3352 	  return SQLITE_OK;
3353       }
3354     switch (prop->type)
3355       {
3356       case GEOJSON_TRUE:
3357 	  sqlite3_result_int (pContext, 1);
3358 	  break;
3359       case GEOJSON_FALSE:
3360 	  sqlite3_result_int (pContext, 0);
3361 	  break;
3362       case GEOJSON_INTEGER:
3363 	  sqlite3_result_int64 (pContext, prop->int_value);
3364 	  break;
3365       case GEOJSON_DOUBLE:
3366 	  sqlite3_result_double (pContext, prop->dbl_value);
3367 	  break;
3368       case GEOJSON_TEXT:
3369 	  sqlite3_result_text (pContext, prop->txt_value,
3370 			       strlen (prop->txt_value), SQLITE_STATIC);
3371 	  break;
3372       case GEOJSON_NULL:
3373       default:
3374 	  sqlite3_result_null (pContext);
3375 	  break;
3376       };
3377     return SQLITE_OK;
3378 }
3379 
3380 static int
vgeojson_rowid(sqlite3_vtab_cursor * pCursor,sqlite_int64 * pRowid)3381 vgeojson_rowid (sqlite3_vtab_cursor * pCursor, sqlite_int64 * pRowid)
3382 {
3383 /* fetching the ROWID */
3384     VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3385     *pRowid = cursor->current_fid;
3386     return SQLITE_OK;
3387 }
3388 
3389 static int
vgeojson_update(sqlite3_vtab * pVTab,int argc,sqlite3_value ** argv,sqlite_int64 * pRowid)3390 vgeojson_update (sqlite3_vtab * pVTab, int argc, sqlite3_value ** argv,
3391 		 sqlite_int64 * pRowid)
3392 {
3393 /* generic update [INSERT / UPDATE / DELETE */
3394     if (pVTab || argc || argv || pRowid)
3395 	pVTab = pVTab;		/* unused arg warning suppression */
3396     return SQLITE_READONLY;
3397 }
3398 
3399 static int
vgeojson_begin(sqlite3_vtab * pVTab)3400 vgeojson_begin (sqlite3_vtab * pVTab)
3401 {
3402 /* BEGIN TRANSACTION */
3403     if (pVTab)
3404 	pVTab = pVTab;		/* unused arg warning suppression */
3405     return SQLITE_OK;
3406 }
3407 
3408 static int
vgeojson_sync(sqlite3_vtab * pVTab)3409 vgeojson_sync (sqlite3_vtab * pVTab)
3410 {
3411 /* BEGIN TRANSACTION */
3412     if (pVTab)
3413 	pVTab = pVTab;		/* unused arg warning suppression */
3414     return SQLITE_OK;
3415 }
3416 
3417 static int
vgeojson_commit(sqlite3_vtab * pVTab)3418 vgeojson_commit (sqlite3_vtab * pVTab)
3419 {
3420 /* BEGIN TRANSACTION */
3421     if (pVTab)
3422 	pVTab = pVTab;		/* unused arg warning suppression */
3423     return SQLITE_OK;
3424 }
3425 
3426 static int
vgeojson_rollback(sqlite3_vtab * pVTab)3427 vgeojson_rollback (sqlite3_vtab * pVTab)
3428 {
3429 /* BEGIN TRANSACTION */
3430     if (pVTab)
3431 	pVTab = pVTab;		/* unused arg warning suppression */
3432     return SQLITE_OK;
3433 }
3434 
3435 static int
vgeojson_rename(sqlite3_vtab * pVTab,const char * zNew)3436 vgeojson_rename (sqlite3_vtab * pVTab, const char *zNew)
3437 {
3438 /* BEGIN TRANSACTION */
3439     if (pVTab)
3440 	pVTab = pVTab;		/* unused arg warning suppression */
3441     if (zNew)
3442 	zNew = zNew;		/* unused arg warning suppression */
3443     return SQLITE_ERROR;
3444 }
3445 
3446 static int
spliteVirtualGeoJsonInit(sqlite3 * db)3447 spliteVirtualGeoJsonInit (sqlite3 * db)
3448 {
3449     int rc = SQLITE_OK;
3450     my_geojson_module.iVersion = 1;
3451     my_geojson_module.xCreate = &vgeojson_create;
3452     my_geojson_module.xConnect = &vgeojson_connect;
3453     my_geojson_module.xBestIndex = &vgeojson_best_index;
3454     my_geojson_module.xDisconnect = &vgeojson_disconnect;
3455     my_geojson_module.xDestroy = &vgeojson_destroy;
3456     my_geojson_module.xOpen = &vgeojson_open;
3457     my_geojson_module.xClose = &vgeojson_close;
3458     my_geojson_module.xFilter = &vgeojson_filter;
3459     my_geojson_module.xNext = &vgeojson_next;
3460     my_geojson_module.xEof = &vgeojson_eof;
3461     my_geojson_module.xColumn = &vgeojson_column;
3462     my_geojson_module.xRowid = &vgeojson_rowid;
3463     my_geojson_module.xUpdate = &vgeojson_update;
3464     my_geojson_module.xBegin = &vgeojson_begin;
3465     my_geojson_module.xSync = &vgeojson_sync;
3466     my_geojson_module.xCommit = &vgeojson_commit;
3467     my_geojson_module.xRollback = &vgeojson_rollback;
3468     my_geojson_module.xFindFunction = NULL;
3469     my_geojson_module.xRename = &vgeojson_rename;
3470     sqlite3_create_module_v2 (db, "VirtualGeoJSON", &my_geojson_module, NULL,
3471 			      0);
3472     return rc;
3473 }
3474 
3475 SPATIALITE_PRIVATE int
virtualgeojson_extension_init(void * xdb)3476 virtualgeojson_extension_init (void *xdb)
3477 {
3478     sqlite3 *db = (sqlite3 *) xdb;
3479     return spliteVirtualGeoJsonInit (db);
3480 }
3481