1 /*
2 
3  gg_shape.c -- Gaia shapefile handling
4 
5  version 5.0, 2020 August 1
6 
7  Author: Sandro Furieri a.furieri@lqt.it
8 
9  ------------------------------------------------------------------------------
10 
11  Version: MPL 1.1/GPL 2.0/LGPL 2.1
12 
13  The contents of this file are subject to the Mozilla Public License Version
14  1.1 (the "License"); you may not use this file except in compliance with
15  the License. You may obtain a copy of the License at
16  http://www.mozilla.org/MPL/
17 
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22 
23 The Original Code is the SpatiaLite library
24 
25 The Initial Developer of the Original Code is Alessandro Furieri
26 
27 Portions created by the Initial Developer are Copyright (C) 2008-2021
28 the Initial Developer. All Rights Reserved.
29 
30 Contributor(s):
31 
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43 
44 */
45 
46 #include <sys/types.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <math.h>
51 #include <float.h>
52 #include <errno.h>
53 
54 #if defined(_WIN32) && !defined(__MINGW32__)
55 #include "config-msvc.h"
56 #else
57 #include "config.h"
58 #endif
59 
60 #ifdef _WIN32
61 #include <Windows.h>
62 #endif
63 
64 #if OMIT_ICONV == 0		/* if ICONV is disabled no SHP support is available */
65 
66 #if defined(__MINGW32__) || defined(_WIN32)
67 #define LIBICONV_STATIC
68 #include <iconv.h>
69 #define LIBCHARSET_STATIC
70 #ifdef _MSC_VER
71 /* <localcharset.h> isn't supported on OSGeo4W */
72 /* applying a tricky workaround to fix this issue */
73 extern const char *locale_charset (void);
74 #else /* sane Windows - not OSGeo4W */
75 #include <localcharset.h>
76 #endif /* end localcharset */
77 #else /* not MINGW32 */
78 #if defined(__APPLE__) || defined(__ANDROID__)
79 #include <iconv.h>
80 #include <localcharset.h>
81 #else /* neither Mac OsX nor Android */
82 #include <iconv.h>
83 #include <langinfo.h>
84 #endif
85 #endif
86 
87 #include <spatialite/sqlite.h>
88 
89 #include <spatialite/gaiageo.h>
90 #include <spatialite/debug.h>
91 
92 #ifdef _WIN32
93 #define atoll	_atoi64
94 #endif /* not WIN32 */
95 
96 /* 64 bit integer: portable format for printf() */
97 #if defined(_WIN32) && !defined(__MINGW32__)
98 #define FRMT64 "%I64d"
99 #else
100 #define FRMT64 "%lld"
101 #endif
102 
103 #define SHAPEFILE_NO_DATA 1e-38
104 
105 #ifdef _WIN32
106 #define strcasecmp	_stricmp
107 #endif /* not WIN32 */
108 
109 struct auxdbf_fld
110 {
111 /* auxiliary DBF field struct */
112     char *name;
113     struct auxdbf_fld *next;
114 };
115 
116 struct auxdbf_list
117 {
118 /* auxiliary DBF struct */
119     struct auxdbf_fld *first;
120     struct auxdbf_fld *last;
121 };
122 
123 GAIAGEO_DECLARE void
gaiaFreeValue(gaiaValuePtr p)124 gaiaFreeValue (gaiaValuePtr p)
125 {
126 /* frees all memory allocations for this DBF Field value */
127     if (!p)
128 	return;
129     if (p->TxtValue)
130 	free (p->TxtValue);
131     free (p);
132 }
133 
134 GAIAGEO_DECLARE void
gaiaSetNullValue(gaiaDbfFieldPtr field)135 gaiaSetNullValue (gaiaDbfFieldPtr field)
136 {
137 /* assignes a NULL value to some DBF field */
138     if (field->Value)
139 	gaiaFreeValue (field->Value);
140     field->Value = malloc (sizeof (gaiaValue));
141     field->Value->Type = GAIA_NULL_VALUE;
142     field->Value->TxtValue = NULL;
143 }
144 
145 GAIAGEO_DECLARE void
gaiaSetIntValue(gaiaDbfFieldPtr field,sqlite3_int64 value)146 gaiaSetIntValue (gaiaDbfFieldPtr field, sqlite3_int64 value)
147 {
148 /* assignes an INTEGER value to some DBF field */
149     if (field->Value)
150 	gaiaFreeValue (field->Value);
151     field->Value = malloc (sizeof (gaiaValue));
152     field->Value->Type = GAIA_INT_VALUE;
153     field->Value->TxtValue = NULL;
154     field->Value->IntValue = value;
155 }
156 
157 GAIAGEO_DECLARE void
gaiaSetDoubleValue(gaiaDbfFieldPtr field,double value)158 gaiaSetDoubleValue (gaiaDbfFieldPtr field, double value)
159 {
160 /* assignes a DOUBLE value to some DBF field */
161     if (field->Value)
162 	gaiaFreeValue (field->Value);
163     field->Value = malloc (sizeof (gaiaValue));
164     field->Value->Type = GAIA_DOUBLE_VALUE;
165     field->Value->TxtValue = NULL;
166     field->Value->DblValue = value;
167 }
168 
169 GAIAGEO_DECLARE void
gaiaSetStrValue(gaiaDbfFieldPtr field,char * str)170 gaiaSetStrValue (gaiaDbfFieldPtr field, char *str)
171 {
172 /* assignes a STRING value to some DBF field */
173     int len = strlen (str);
174     if (field->Value)
175 	gaiaFreeValue (field->Value);
176     field->Value = malloc (sizeof (gaiaValue));
177     field->Value->Type = GAIA_TEXT_VALUE;
178     field->Value->TxtValue = malloc (len + 1);
179     strcpy (field->Value->TxtValue, str);
180 }
181 
182 GAIAGEO_DECLARE int
gaiaMemFseek(gaiaMemFilePtr mem,off_t offset)183 gaiaMemFseek (gaiaMemFilePtr mem, off_t offset)
184 {
185 /* repositioning a Memory File */
186     if (mem == NULL)
187 	return -1;
188     if (mem->buf == NULL)
189 	return -1;
190     if (offset < 0)
191 	return -1;
192     if (offset >= (off_t)mem->size)
193 	return -1;
194     mem->offset = offset;
195     return 0;
196 }
197 
198 GAIAGEO_DECLARE size_t
gaiaMemRead(void * ptr,size_t bytes,gaiaMemFilePtr mem)199 gaiaMemRead (void *ptr, size_t bytes, gaiaMemFilePtr mem)
200 {
201 /* reading from Memory File */
202     size_t rd = 0;
203     size_t i;
204     unsigned char *in;
205     unsigned char *out;
206 
207     if (mem == NULL)
208 	return 0;
209     if (mem->buf == NULL)
210 	return 0;
211 
212     for (i = 0; i < bytes; i++)
213       {
214 	  if (mem->offset >= mem->size)
215 	      break;
216 	  in = (unsigned char *) (mem->buf) + mem->offset;
217 	  out = (unsigned char *) ptr + i;
218 	  *out = *in;
219 	  mem->offset += 1;
220 	  rd++;
221       }
222     return rd;
223 }
224 
225 GAIAGEO_DECLARE gaiaDbfFieldPtr
gaiaAllocDbfField(char * name,unsigned char type,int offset,unsigned char length,unsigned char decimals)226 gaiaAllocDbfField (char *name, unsigned char type,
227 		   int offset, unsigned char length, unsigned char decimals)
228 {
229 /* allocates and initializes a DBF Field definition */
230     gaiaDbfFieldPtr p = malloc (sizeof (gaiaDbfField));
231     int len = strlen (name);
232     p->Name = malloc (len + 1);
233     strcpy (p->Name, name);
234     p->Type = type;
235     p->Offset = offset;
236     p->Length = length;
237     p->Decimals = decimals;
238     p->Value = NULL;
239     p->Next = NULL;
240     return p;
241 }
242 
243 GAIAGEO_DECLARE void
gaiaFreeDbfField(gaiaDbfFieldPtr p)244 gaiaFreeDbfField (gaiaDbfFieldPtr p)
245 {
246 /* frees all memory allocations for this DBF Field definition */
247     if (!p)
248 	return;
249     if (p->Name)
250 	free (p->Name);
251     if (p->Value)
252 	gaiaFreeValue (p->Value);
253     free (p);
254 }
255 
256 GAIAGEO_DECLARE gaiaDbfFieldPtr
gaiaCloneDbfField(gaiaDbfFieldPtr org)257 gaiaCloneDbfField (gaiaDbfFieldPtr org)
258 {
259 /* creating a new DBF LIST copied from the original one */
260     gaiaDbfFieldPtr p = malloc (sizeof (gaiaDbfField));
261     int len = strlen (org->Name);
262     p->Name = malloc (len + 1);
263     strcpy (p->Name, org->Name);
264     p->Type = org->Type;
265     p->Offset = org->Offset;
266     p->Length = org->Length;
267     p->Decimals = org->Decimals;
268     p->Value = gaiaCloneValue (org->Value);
269     p->Next = NULL;
270     return p;
271 }
272 
273 GAIAGEO_DECLARE gaiaDbfListPtr
gaiaAllocDbfList()274 gaiaAllocDbfList ()
275 {
276 /* allocates and initializes the DBF Fields list */
277     gaiaDbfListPtr list = malloc (sizeof (gaiaDbfList));
278     list->RowId = 0;
279     list->Geometry = NULL;
280     list->First = NULL;
281     list->Last = NULL;
282     return list;
283 }
284 
285 GAIAGEO_DECLARE void
gaiaFreeDbfList(gaiaDbfListPtr list)286 gaiaFreeDbfList (gaiaDbfListPtr list)
287 {
288 /* frees all memory allocations related to DBF Fields list */
289     gaiaDbfFieldPtr p;
290     gaiaDbfFieldPtr pn;
291     if (!list)
292 	return;
293     p = list->First;
294     while (p)
295       {
296 	  pn = p->Next;
297 	  gaiaFreeDbfField (p);
298 	  p = pn;
299       }
300     if (list->Geometry)
301 	gaiaFreeGeomColl (list->Geometry);
302     free (list);
303 }
304 
305 GAIAGEO_DECLARE int
gaiaIsValidDbfList(gaiaDbfListPtr list)306 gaiaIsValidDbfList (gaiaDbfListPtr list)
307 {
308 /* checks if the DBF fields list contains any invalid data type */
309     gaiaDbfFieldPtr p;
310     if (!list)
311 	return 0;
312     p = list->First;
313     while (p)
314       {
315 	  if (p->Type == 'N' || p->Type == 'C' || p->Type == 'L'
316 	      || p->Type == 'D' || p->Type == 'F')
317 	      ;
318 	  else
319 	      return 0;
320 	  p = p->Next;
321       }
322     return 1;
323 }
324 
325 GAIAGEO_DECLARE gaiaDbfFieldPtr
gaiaAddDbfField(gaiaDbfListPtr list,char * name,unsigned char type,int offset,unsigned char length,unsigned char decimals)326 gaiaAddDbfField (gaiaDbfListPtr list, char *name, unsigned char type,
327 		 int offset, unsigned char length, unsigned char decimals)
328 {
329 /* inserts a Field in the DBF Fields list */
330     gaiaDbfFieldPtr p;
331     if (!list)
332 	return NULL;
333     p = gaiaAllocDbfField (name, type, offset, length, decimals);
334     if (!(list->First))
335 	list->First = p;
336     if (list->Last)
337 	list->Last->Next = p;
338     list->Last = p;
339     return p;
340 }
341 
342 GAIAGEO_DECLARE void
gaiaResetDbfEntity(gaiaDbfListPtr list)343 gaiaResetDbfEntity (gaiaDbfListPtr list)
344 {
345 /* resets data values */
346     gaiaDbfFieldPtr p;
347     if (!list)
348 	return;
349     p = list->First;
350     while (p)
351       {
352 	  if (p->Value)
353 	      gaiaFreeValue (p->Value);
354 	  p->Value = NULL;
355 	  p = p->Next;
356       }
357     if (list->Geometry)
358 	gaiaFreeGeomColl (list->Geometry);
359     list->Geometry = NULL;
360 }
361 
362 GAIAGEO_DECLARE gaiaValuePtr
gaiaCloneValue(gaiaValuePtr org)363 gaiaCloneValue (gaiaValuePtr org)
364 {
365 /* creating a new VARIANT value copied from the original one */
366     gaiaValuePtr value;
367     int len;
368     value = malloc (sizeof (gaiaValue));
369     value->Type = GAIA_NULL_VALUE;
370     value->TxtValue = NULL;
371     switch (org->Type)
372       {
373       case GAIA_INT_VALUE:
374 	  value->Type = GAIA_INT_VALUE;
375 	  value->IntValue = org->IntValue;
376 	  break;
377       case GAIA_DOUBLE_VALUE:
378 	  value->Type = GAIA_DOUBLE_VALUE;
379 	  value->DblValue = org->DblValue;
380 	  break;
381       case GAIA_TEXT_VALUE:
382 	  value->Type = GAIA_TEXT_VALUE;
383 	  len = strlen (org->TxtValue);
384 	  value->TxtValue = malloc (len + 1);
385 	  strcpy (value->TxtValue, org->TxtValue);
386       };
387     return value;
388 }
389 
390 GAIAGEO_DECLARE gaiaDbfListPtr
gaiaCloneDbfEntity(gaiaDbfListPtr org)391 gaiaCloneDbfEntity (gaiaDbfListPtr org)
392 {
393 /* creating a new DBF LIST copied from the original one */
394     gaiaDbfFieldPtr p;
395     gaiaDbfFieldPtr newFld;
396     gaiaDbfListPtr entity = gaiaAllocDbfList ();
397     entity->RowId = org->RowId;
398     if (org->Geometry)
399 	entity->Geometry = gaiaCloneGeomColl (org->Geometry);
400     p = org->First;
401     while (p)
402       {
403 	  newFld =
404 	      gaiaAddDbfField (entity, p->Name, p->Type, p->Offset, p->Length,
405 			       p->Decimals);
406 	  if (p->Value)
407 	      newFld->Value = gaiaCloneValue (p->Value);
408 	  p = p->Next;
409       }
410     return entity;
411 }
412 
413 GAIAGEO_DECLARE gaiaShapefilePtr
gaiaAllocShapefile()414 gaiaAllocShapefile ()
415 {
416 /* allocates and initializes the Shapefile object */
417     gaiaShapefilePtr shp = malloc (sizeof (gaiaShapefile));
418     shp->endian_arch = 1;
419     shp->Path = NULL;
420     shp->Shape = -1;
421     shp->EffectiveType = GAIA_UNKNOWN;
422     shp->EffectiveDims = GAIA_XY;
423     shp->flShp = NULL;
424     shp->flShx = NULL;
425     shp->flDbf = NULL;
426     shp->memShp = NULL;
427     shp->memShx = NULL;
428     shp->memDbf = NULL;
429     shp->Dbf = NULL;
430     shp->BufShp = NULL;
431     shp->ShpBfsz = 0;
432     shp->BufDbf = NULL;
433     shp->DbfHdsz = 0;
434     shp->DbfReclen = 0;
435     shp->DbfSize = 0;
436     shp->DbfRecno = 0;
437     shp->ShpSize = 0;
438     shp->ShxSize = 0;
439     shp->MinX = DBL_MAX;
440     shp->MinY = DBL_MAX;
441     shp->MaxX = -DBL_MAX;
442     shp->MaxY = -DBL_MAX;
443     shp->Valid = 0;
444     shp->IconvObj = NULL;
445     shp->LastError = NULL;
446     return shp;
447 }
448 
449 GAIAGEO_DECLARE void
gaiaFreeShapefile(gaiaShapefilePtr shp)450 gaiaFreeShapefile (gaiaShapefilePtr shp)
451 {
452 /* frees all memory allocations related to the Shapefile object */
453     if (shp->Path)
454 	free (shp->Path);
455     if (shp->flShp)
456 	fclose (shp->flShp);
457     if (shp->flShx)
458 	fclose (shp->flShx);
459     if (shp->flDbf)
460 	fclose (shp->flDbf);
461     if (shp->Dbf)
462 	gaiaFreeDbfList (shp->Dbf);
463     if (shp->BufShp)
464 	free (shp->BufShp);
465     if (shp->BufDbf)
466 	free (shp->BufDbf);
467     if (shp->IconvObj)
468 	iconv_close ((iconv_t) shp->IconvObj);
469     if (shp->LastError)
470 	free (shp->LastError);
471     free (shp);
472 }
473 
474 GAIAGEO_DECLARE void
gaiaOpenShpRead(gaiaShapefilePtr shp,const char * path,const char * charFrom,const char * charTo)475 gaiaOpenShpRead (gaiaShapefilePtr shp, const char *path, const char *charFrom,
476 		 const char *charTo)
477 {
478 /* trying to open the shapefile and initial checkings */
479     FILE *fl_shx = NULL;
480     FILE *fl_shp = NULL;
481     FILE *fl_dbf = NULL;
482     char xpath[1024];
483     int rd;
484     unsigned char buf_shx[256];
485     unsigned char *buf_shp = NULL;
486     int buf_size = 1024;
487     int shape;
488     unsigned char bf[1024];
489     int dbf_size;
490     int dbf_reclen = 0;
491     int off_dbf;
492     int ind;
493     char field_name[2048];
494     char *sys_err;
495     char errMsg[4192];
496     iconv_t iconv_ret;
497     char utf8buf[2048];
498 #if !defined(__MINGW32__) && defined(_WIN32)
499     const char *pBuf;
500 #else /* not WIN32 */
501     char *pBuf;
502 #endif
503     size_t len;
504     size_t utf8len;
505     char *pUtf8buf;
506     int endian_arch = gaiaEndianArch ();
507     gaiaDbfListPtr dbf_list = NULL;
508     if (charFrom && charTo)
509       {
510 	  iconv_ret = iconv_open (charTo, charFrom);
511 	  if (iconv_ret == (iconv_t) (-1))
512 	    {
513 		sprintf (errMsg, "conversion from '%s' to '%s' not available\n",
514 			 charFrom, charTo);
515 		goto unsupported_conversion;
516 	    }
517 	  shp->IconvObj = iconv_ret;
518       }
519     else
520       {
521 	  sprintf (errMsg, "a NULL charset-name was passed\n");
522 	  goto unsupported_conversion;
523       }
524     if (shp->flShp != NULL || shp->flShx != NULL || shp->flDbf != NULL)
525       {
526 	  sprintf (errMsg,
527 		   "attempting to reopen an already opened Shapefile\n");
528 	  goto unsupported_conversion;
529       }
530     if (shp->memShx == NULL)
531       {
532 	  sprintf (xpath, "%s.shx", path);
533 #ifdef _WIN32
534 	  fl_shx = gaia_win_fopen (xpath, "rb");
535 #else
536 	  fl_shx = fopen (xpath, "rb");
537 #endif
538 	  if (!fl_shx)
539 	    {
540 		sys_err = strerror (errno);
541 		sprintf (errMsg, "unable to open '%s' for reading: %s", xpath,
542 			 sys_err);
543 		goto no_file;
544 	    }
545       }
546     if (shp->memShp == NULL)
547       {
548 	  sprintf (xpath, "%s.shp", path);
549 #ifdef _WIN32
550 	  fl_shp = gaia_win_fopen (xpath, "rb");
551 #else
552 	  fl_shp = fopen (xpath, "rb");
553 #endif
554 	  if (!fl_shp)
555 	    {
556 		sys_err = strerror (errno);
557 		sprintf (errMsg, "unable to open '%s' for reading: %s", xpath,
558 			 sys_err);
559 		goto no_file;
560 	    }
561       }
562     if (shp->memDbf == NULL)
563       {
564 	  sprintf (xpath, "%s.dbf", path);
565 #ifdef _WIN32
566 	  fl_dbf = gaia_win_fopen (xpath, "rb");
567 #else
568 	  fl_dbf = fopen (xpath, "rb");
569 #endif
570 	  if (!fl_dbf)
571 	    {
572 		sys_err = strerror (errno);
573 		sprintf (errMsg, "unable to open '%s' for reading: %s", xpath,
574 			 sys_err);
575 		goto no_file;
576 	    }
577       }
578 /* reading SHX file header */
579     if (shp->memShx != NULL)
580 	rd = gaiaMemRead (buf_shx, 100, shp->memShx);
581     else
582 	rd = fread (buf_shx, sizeof (unsigned char), 100, fl_shx);
583     if (rd != 100)
584 	goto error;
585     if (gaiaImport32 (buf_shx + 0, GAIA_BIG_ENDIAN, endian_arch) != 9994)	/* checks the SHX magic number */
586 	goto error;
587 /* reading SHP file header */
588     buf_shp = malloc (sizeof (unsigned char) * buf_size);
589     if (shp->memShp != NULL)
590 	rd = gaiaMemRead (buf_shp, 100, shp->memShp);
591     else
592 	rd = fread (buf_shp, sizeof (unsigned char), 100, fl_shp);
593     if (rd != 100)
594 	goto error;
595     if (gaiaImport32 (buf_shp + 0, GAIA_BIG_ENDIAN, endian_arch) != 9994)	/* checks the SHP magic number */
596 	goto error;
597     shape = gaiaImport32 (buf_shp + 32, GAIA_LITTLE_ENDIAN, endian_arch);
598     if (shape == GAIA_SHP_POINT || shape == GAIA_SHP_POINTZ
599 	|| shape == GAIA_SHP_POINTM || shape == GAIA_SHP_POLYLINE
600 	|| shape == GAIA_SHP_POLYLINEZ || shape == GAIA_SHP_POLYLINEM
601 	|| shape == GAIA_SHP_POLYGON || shape == GAIA_SHP_POLYGONZ
602 	|| shape == GAIA_SHP_POLYGONM || shape == GAIA_SHP_MULTIPOINT
603 	|| shape == GAIA_SHP_MULTIPOINTZ || shape == GAIA_SHP_MULTIPOINTM)
604 	;
605     else
606 	goto unsupported;
607     shp->MinX = gaiaImport64 (buf_shp + 36, GAIA_LITTLE_ENDIAN, endian_arch);
608     shp->MinY = gaiaImport64 (buf_shp + 44, GAIA_LITTLE_ENDIAN, endian_arch);
609     shp->MaxX = gaiaImport64 (buf_shp + 52, GAIA_LITTLE_ENDIAN, endian_arch);
610     shp->MaxY = gaiaImport64 (buf_shp + 60, GAIA_LITTLE_ENDIAN, endian_arch);
611 /* reading DBF file header */
612     if (shp->memDbf != NULL)
613 	rd = gaiaMemRead (bf, 32, shp->memDbf);
614     else
615 	rd = fread (bf, sizeof (unsigned char), 32, fl_dbf);
616     if (rd != 32)
617 	goto error;
618     switch (*bf)
619       {
620 	  /* checks the DBF magic number */
621       case 0x03:
622       case 0x83:
623 	  break;
624       case 0x02:
625       case 0xF8:
626 	  sprintf (errMsg, "'%s'\ninvalid magic number %02x [FoxBASE format]",
627 		   path, *bf);
628 	  goto dbf_bad_magic;
629       case 0xF5:
630 	  sprintf (errMsg,
631 		   "'%s'\ninvalid magic number %02x [FoxPro 2.x (or earlier) format]",
632 		   path, *bf);
633 	  goto dbf_bad_magic;
634       case 0x30:
635       case 0x31:
636       case 0x32:
637 	  sprintf (errMsg,
638 		   "'%s'\ninvalid magic number %02x [Visual FoxPro format]",
639 		   path, *bf);
640 	  goto dbf_bad_magic;
641       case 0x43:
642       case 0x63:
643       case 0xBB:
644       case 0xCB:
645 	  sprintf (errMsg, "'%s'\ninvalid magic number %02x [dBASE IV format]",
646 		   path, *bf);
647 	  goto dbf_bad_magic;
648       default:
649 	  sprintf (errMsg, "'%s'\ninvalid magic number %02x [unknown format]",
650 		   path, *bf);
651 	  goto dbf_bad_magic;
652       };
653     dbf_size = gaiaImport16 (bf + 8, GAIA_LITTLE_ENDIAN, endian_arch);
654     dbf_reclen = gaiaImport16 (bf + 10, GAIA_LITTLE_ENDIAN, endian_arch);
655     dbf_size--;
656     off_dbf = 0;
657     dbf_list = gaiaAllocDbfList ();
658     for (ind = 32; ind < dbf_size; ind += 32)
659       {
660 	  /* fetches DBF fields definitions */
661 	  if ((dbf_size - ind) < 32)
662 	    {
663 		/* some odd DBF could contain some unexpected extra-padding */
664 		int extra = dbf_size - ind;
665 		if (shp->memDbf != NULL)
666 		    rd = gaiaMemRead (bf, extra, shp->memDbf);
667 		else
668 		    rd = fread (bf, sizeof (unsigned char), extra, fl_dbf);
669 		if (rd != extra)
670 		    goto error;
671 		/* ignoring the extra-padding */
672 		break;
673 	    }
674 	  if (shp->memDbf != NULL)
675 	      rd = gaiaMemRead (bf, 32, shp->memDbf);
676 	  else
677 	      rd = fread (bf, sizeof (unsigned char), 32, fl_dbf);
678 	  if (rd != 32)
679 	      goto error;
680 	  if (*(bf + 11) == 'M')
681 	    {
682 		/* skipping any MEMO field */
683 		memcpy (field_name, bf, 11);
684 		field_name[11] = '\0';
685 		off_dbf += *(bf + 16);
686 		spatialite_e
687 		    ("WARNING: column \"%s\" is of the MEMO type and will be ignored\n",
688 		     field_name);
689 		continue;
690 	    }
691 	  memcpy (field_name, bf, 11);
692 	  field_name[11] = '\0';
693 	  len = strlen ((char *) field_name);
694 	  utf8len = 2048;
695 	  pBuf = (char *) field_name;
696 	  pUtf8buf = utf8buf;
697 	  if (iconv
698 	      ((iconv_t) (shp->IconvObj), &pBuf, &len, &pUtf8buf,
699 	       &utf8len) == (size_t) (-1))
700 	    {
701 		spatialite_e
702 		    ("**** libiconv: unable to convert string=\"%s\"\n",
703 		     field_name);
704 		goto conversion_error;
705 	    }
706 	  memcpy (field_name, utf8buf, 2048 - utf8len);
707 	  field_name[2048 - utf8len] = '\0';
708 	  gaiaAddDbfField (dbf_list, field_name, *(bf + 11), off_dbf,
709 			   *(bf + 16), *(bf + 17));
710 	  off_dbf += *(bf + 16);
711       }
712     if (!gaiaIsValidDbfList (dbf_list))
713       {
714 	  /* invalid DBF */
715 	  goto illegal_dbf;
716       }
717     len = strlen (path);
718     shp->Path = malloc (len + 1);
719     strcpy (shp->Path, path);
720     shp->ReadOnly = 1;
721     shp->Shape = shape;
722     switch (shape)
723       {
724 	  /* setting up a prudential geometry type */
725       case GAIA_SHP_POINT:
726       case GAIA_SHP_POINTZ:
727       case GAIA_SHP_POINTM:
728 	  shp->EffectiveType = GAIA_POINT;
729 	  break;
730       case GAIA_SHP_POLYLINE:
731       case GAIA_SHP_POLYLINEZ:
732       case GAIA_SHP_POLYLINEM:
733 	  shp->EffectiveType = GAIA_MULTILINESTRING;
734 	  break;
735       case GAIA_SHP_POLYGON:
736       case GAIA_SHP_POLYGONZ:
737       case GAIA_SHP_POLYGONM:
738 	  shp->EffectiveType = GAIA_MULTIPOLYGON;
739 	  break;
740       case GAIA_SHP_MULTIPOINT:
741       case GAIA_SHP_MULTIPOINTZ:
742       case GAIA_SHP_MULTIPOINTM:
743 	  shp->EffectiveType = GAIA_MULTIPOINT;
744 	  break;
745       }
746     switch (shape)
747       {
748 	  /* setting up a prudential dimension model */
749       case GAIA_SHP_POINTZ:
750       case GAIA_SHP_POLYLINEZ:
751       case GAIA_SHP_POLYGONZ:
752       case GAIA_SHP_MULTIPOINTZ:
753 	  shp->EffectiveDims = GAIA_XY_Z_M;
754 	  break;
755       case GAIA_SHP_POINTM:
756       case GAIA_SHP_POLYLINEM:
757       case GAIA_SHP_POLYGONM:
758       case GAIA_SHP_MULTIPOINTM:
759 	  shp->EffectiveDims = GAIA_XY_M;
760 	  break;
761       default:
762 	  shp->EffectiveDims = GAIA_XY;
763 	  break;
764       }
765     shp->flShp = fl_shp;
766     shp->flShx = fl_shx;
767     shp->flDbf = fl_dbf;
768     shp->Dbf = dbf_list;
769 /* saving the SHP buffer */
770     shp->BufShp = buf_shp;
771     shp->ShpBfsz = buf_size;
772 /* allocating DBF buffer */
773     shp->BufDbf = malloc (sizeof (unsigned char) * dbf_reclen);
774     shp->DbfHdsz = dbf_size + 1;
775     shp->DbfReclen = dbf_reclen;
776     shp->Valid = 1;
777     shp->endian_arch = endian_arch;
778     return;
779   unsupported_conversion:
780 /* illegal charset */
781     if (shp->LastError)
782 	free (shp->LastError);
783     len = strlen (errMsg);
784     shp->LastError = malloc (len + 1);
785     strcpy (shp->LastError, errMsg);
786     return;
787   no_file:
788 /* one of shapefile's files can't be accessed */
789     if (shp->LastError)
790 	free (shp->LastError);
791     len = strlen (errMsg);
792     shp->LastError = malloc (len + 1);
793     strcpy (shp->LastError, errMsg);
794     if (fl_shx)
795 	fclose (fl_shx);
796     if (fl_shp)
797 	fclose (fl_shp);
798     if (fl_dbf)
799 	fclose (fl_dbf);
800     return;
801   dbf_bad_magic:
802 /* the DBF has an invalid magin number */
803     if (shp->LastError)
804 	free (shp->LastError);
805     len = strlen (errMsg);
806     shp->LastError = malloc (len + 1);
807     strcpy (shp->LastError, errMsg);
808     gaiaFreeDbfList (dbf_list);
809     if (buf_shp)
810 	free (buf_shp);
811     fclose (fl_shx);
812     fclose (fl_shp);
813     fclose (fl_dbf);
814     return;
815   error:
816 /* the shapefile is invalid or corrupted */
817     if (shp->LastError)
818 	free (shp->LastError);
819     sprintf (errMsg, "'%s' is corrupted / has invalid format", path);
820     len = strlen (errMsg);
821     shp->LastError = malloc (len + 1);
822     strcpy (shp->LastError, errMsg);
823     gaiaFreeDbfList (dbf_list);
824     if (buf_shp)
825 	free (buf_shp);
826     fclose (fl_shx);
827     fclose (fl_shp);
828     fclose (fl_dbf);
829     return;
830   unsupported:
831 /* the shapefile has an unrecognized shape type */
832     if (shp->LastError)
833 	free (shp->LastError);
834     sprintf (errMsg, "'%s' shape=%d is not supported", path, shape);
835     len = strlen (errMsg);
836     shp->LastError = malloc (len + 1);
837     strcpy (shp->LastError, errMsg);
838     gaiaFreeDbfList (dbf_list);
839     if (buf_shp)
840 	free (buf_shp);
841     fclose (fl_shx);
842     fclose (fl_shp);
843     if (fl_dbf)
844 	fclose (fl_dbf);
845     return;
846   illegal_dbf:
847 /* the DBF-file contains unsupported data types */
848     if (shp->LastError)
849 	free (shp->LastError);
850     sprintf (errMsg, "'%s.dbf' contains unsupported data types", path);
851     len = strlen (errMsg);
852     shp->LastError = malloc (len + 1);
853     strcpy (shp->LastError, errMsg);
854     gaiaFreeDbfList (dbf_list);
855     if (buf_shp)
856 	free (buf_shp);
857     fclose (fl_shx);
858     fclose (fl_shp);
859     if (fl_dbf)
860 	fclose (fl_dbf);
861     return;
862   conversion_error:
863 /* libiconv error */
864     if (shp->LastError)
865 	free (shp->LastError);
866     sprintf (errMsg, "'%s.dbf' field name: invalid character sequence", path);
867     len = strlen (errMsg);
868     shp->LastError = malloc (len + 1);
869     strcpy (shp->LastError, errMsg);
870     gaiaFreeDbfList (dbf_list);
871     if (buf_shp)
872 	free (buf_shp);
873     fclose (fl_shx);
874     fclose (fl_shp);
875     if (fl_dbf)
876 	fclose (fl_dbf);
877     return;
878 }
879 
880 static struct auxdbf_list *
alloc_auxdbf(gaiaDbfListPtr dbf_list)881 alloc_auxdbf (gaiaDbfListPtr dbf_list)
882 {
883 /* allocating the auxiliary DBF struct */
884     int len;
885     gaiaDbfFieldPtr fld;
886     struct auxdbf_fld *fld_ex;
887     struct auxdbf_list *auxdbf = malloc (sizeof (struct auxdbf_list));
888     auxdbf->first = NULL;
889     auxdbf->last = NULL;
890     fld = dbf_list->First;
891     while (fld)
892       {
893 	  fld_ex = malloc (sizeof (struct auxdbf_fld));
894 	  len = strlen (fld->Name);
895 	  fld_ex->name = malloc (len + 1);
896 	  strcpy (fld_ex->name, fld->Name);
897 	  fld_ex->next = NULL;
898 	  if (auxdbf->first == NULL)
899 	      auxdbf->first = fld_ex;
900 	  if (auxdbf->last != NULL)
901 	      auxdbf->last->next = fld_ex;
902 	  auxdbf->last = fld_ex;
903 	  fld = fld->Next;
904       }
905     return auxdbf;
906 }
907 
908 static void
free_auxdbf(struct auxdbf_list * auxdbf)909 free_auxdbf (struct auxdbf_list *auxdbf)
910 {
911 /* freeing an auxiliary DBF struct */
912     struct auxdbf_fld *n_fld;
913     struct auxdbf_fld *fld = auxdbf->first;
914     while (fld != NULL)
915       {
916 	  n_fld = fld->next;
917 	  if (fld->name != NULL)
918 	      free (fld->name);
919 	  free (fld);
920 	  fld = n_fld;
921       }
922     free (auxdbf);
923 }
924 
925 static void
truncate_long_name(struct auxdbf_list * list,gaiaDbfFieldPtr xfld)926 truncate_long_name (struct auxdbf_list *list, gaiaDbfFieldPtr xfld)
927 {
928 /* attempting to create a unique short name <= 10 bytes */
929     char suffix;
930     char buf[16];
931     struct auxdbf_fld *fld;
932     struct auxdbf_fld *base = NULL;
933     memcpy (buf, xfld->Name, 9);
934     buf[10] = '\0';
935 
936     fld = list->first;
937     while (fld)
938       {
939 	  /* identifying the base aux Field */
940 	  if (strcmp (xfld->Name, fld->name) == 0)
941 	    {
942 		base = fld;
943 		break;
944 	    }
945 	  fld = fld->next;
946       }
947 
948     suffix = '0';
949     while (1)
950       {
951 	  /* attempting to find a numeric suffix ensuring uniqueness */
952 	  int ok = 1;
953 	  buf[9] = suffix;
954 	  fld = list->first;
955 	  while (fld)
956 	    {
957 		if (base != fld)
958 		  {
959 		      if (strcasecmp (buf, fld->name) == 0)
960 			{
961 			    /* invalid: already defined */
962 			    ok = 0;
963 			    break;
964 			}
965 		  }
966 		fld = fld->next;
967 	    }
968 	  if (ok)
969 	    {
970 		strcpy (xfld->Name, buf);
971 		if (base != NULL)
972 		    strcpy (base->name, buf);
973 		return;
974 	    }
975 	  if (suffix == '9')
976 	      break;
977 	  else
978 	      suffix++;
979       }
980 
981     suffix = 'A';
982     while (1)
983       {
984 	  /* attempting to find a letter suffix ensuring uniqueness */
985 	  int ok = 1;
986 	  buf[9] = suffix;
987 	  fld = list->first;
988 	  while (fld)
989 	    {
990 		if (base != fld)
991 		  {
992 		      if (strcasecmp (buf, fld->name) == 0)
993 			{
994 			    /* invalid: already defined */
995 			    ok = 0;
996 			    break;
997 			}
998 		  }
999 		fld = fld->next;
1000 	    }
1001 	  if (ok)
1002 	    {
1003 		strcpy (xfld->Name, buf);
1004 		if (base != NULL)
1005 		    strcpy (base->name, buf);
1006 		return;
1007 	    }
1008 	  if (suffix == 'Z')
1009 	      break;
1010 	  else
1011 	      suffix++;
1012       }
1013 }
1014 
1015 static void
convert_dbf_colname_case(char * buf,int colname_case)1016 convert_dbf_colname_case (char *buf, int colname_case)
1017 {
1018 /* converts a DBF column-name to Lower- or Upper-case */
1019     char *p = buf;
1020     while (*p != '\0')
1021       {
1022 	  if (colname_case == GAIA_DBF_COLNAME_LOWERCASE)
1023 	    {
1024 		if (*p >= 'A' && *p <= 'Z')
1025 		    *p = *p - 'A' + 'a';
1026 	    }
1027 	  if (colname_case == GAIA_DBF_COLNAME_UPPERCASE)
1028 	    {
1029 		if (*p >= 'a' && *p <= 'z')
1030 		    *p = *p - 'a' + 'A';
1031 	    }
1032 	  p++;
1033       }
1034 }
1035 
1036 GAIAGEO_DECLARE void
gaiaOpenShpWrite(gaiaShapefilePtr shp,const char * path,int shape,gaiaDbfListPtr dbf_list,const char * charFrom,const char * charTo)1037 gaiaOpenShpWrite (gaiaShapefilePtr shp, const char *path, int shape,
1038 		  gaiaDbfListPtr dbf_list, const char *charFrom,
1039 		  const char *charTo)
1040 {
1041 /* trying to create the shapefile */
1042     gaiaOpenShpWriteEx (shp, path, shape, dbf_list, charFrom, charTo,
1043 			GAIA_DBF_COLNAME_CASE_IGNORE);
1044 }
1045 
1046 GAIAGEO_DECLARE void
gaiaOpenShpWriteEx(gaiaShapefilePtr shp,const char * path,int shape,gaiaDbfListPtr dbf_list,const char * charFrom,const char * charTo,int colname_case)1047 gaiaOpenShpWriteEx (gaiaShapefilePtr shp, const char *path, int shape,
1048 		    gaiaDbfListPtr dbf_list, const char *charFrom,
1049 		    const char *charTo, int colname_case)
1050 {
1051 /* trying to create the shapefile */
1052     FILE *fl_shx = NULL;
1053     FILE *fl_shp = NULL;
1054     FILE *fl_dbf = NULL;
1055     char xpath[1024];
1056     unsigned char *buf_shp = NULL;
1057     int buf_size = 1024;
1058     unsigned char *dbf_buf = NULL;
1059     gaiaDbfFieldPtr fld;
1060     char *sys_err;
1061     char errMsg[4192];
1062     short dbf_reclen = 0;
1063     int shp_size = 0;
1064     int shx_size = 0;
1065     unsigned short dbf_size = 0;
1066     iconv_t iconv_ret;
1067     int endian_arch = gaiaEndianArch ();
1068     char buf[2048];
1069     char utf8buf[2048];
1070 #if !defined(__MINGW32__) && defined(_WIN32)
1071     const char *pBuf;
1072 #else /* not WIN32 */
1073     char *pBuf;
1074 #endif
1075     size_t len;
1076     size_t utf8len;
1077     char *pUtf8buf;
1078     int defaultId = 1;
1079     struct auxdbf_list *auxdbf = NULL;
1080     if (charFrom && charTo)
1081       {
1082 	  iconv_ret = iconv_open (charTo, charFrom);
1083 	  if (iconv_ret == (iconv_t) (-1))
1084 	    {
1085 		sprintf (errMsg, "conversion from '%s' to '%s' not available\n",
1086 			 charFrom, charTo);
1087 		goto unsupported_conversion;
1088 	    }
1089 	  shp->IconvObj = iconv_ret;
1090       }
1091     else
1092       {
1093 	  sprintf (errMsg, "a NULL charset-name was passed\n");
1094 	  goto unsupported_conversion;
1095       }
1096     if (shp->flShp != NULL || shp->flShx != NULL || shp->flDbf != NULL)
1097       {
1098 	  sprintf (errMsg,
1099 		   "attempting to reopen an already opened Shapefile\n");
1100 	  goto unsupported_conversion;
1101       }
1102     buf_shp = malloc (buf_size);
1103 /* trying to open shapefile files */
1104     sprintf (xpath, "%s.shx", path);
1105 #ifdef _WIN32
1106     fl_shx = gaia_win_fopen (xpath, "wb");
1107 #else
1108     fl_shx = fopen (xpath, "wb");
1109 #endif
1110     if (!fl_shx)
1111       {
1112 	  sys_err = strerror (errno);
1113 	  sprintf (errMsg, "unable to open '%s' for writing: %s", xpath,
1114 		   sys_err);
1115 	  goto no_file;
1116       }
1117     sprintf (xpath, "%s.shp", path);
1118 #ifdef _WIN32
1119     fl_shp = gaia_win_fopen (xpath, "wb");
1120 #else
1121     fl_shp = fopen (xpath, "wb");
1122 #endif
1123     if (!fl_shp)
1124       {
1125 	  sys_err = strerror (errno);
1126 	  sprintf (errMsg, "unable to open '%s' for writing: %s", xpath,
1127 		   sys_err);
1128 	  goto no_file;
1129       }
1130     sprintf (xpath, "%s.dbf", path);
1131 #ifdef _WIN32
1132     fl_dbf = gaia_win_fopen (xpath, "wb");
1133 #else
1134     fl_dbf = fopen (xpath, "wb");
1135 #endif
1136     if (!fl_dbf)
1137       {
1138 	  sys_err = strerror (errno);
1139 	  sprintf (errMsg, "unable to open '%s' for writing: %s", xpath,
1140 		   sys_err);
1141 	  goto no_file;
1142       }
1143 /* allocating DBF buffer */
1144     dbf_reclen = 1;		/* an extra byte is needed because in DBF rows first byte is a marker for deletion */
1145     fld = dbf_list->First;
1146     while (fld)
1147       {
1148 	  /* computing the DBF record length */
1149 	  dbf_reclen += fld->Length;
1150 	  fld = fld->Next;
1151       }
1152     dbf_buf = malloc (dbf_reclen);
1153 /* writing an empty SHP file header */
1154     memset (buf_shp, 0, 100);
1155     fwrite (buf_shp, 1, 100, fl_shp);
1156     shp_size = 50;		/* note: shapefile [SHP and SHX] counts sizes in WORDS of 16 bits, not in bytes of 8 bits !!!! */
1157 /* writing an empty SHX file header */
1158     memset (buf_shp, 0, 100);
1159     fwrite (buf_shp, 1, 100, fl_shx);
1160     shx_size = 50;
1161 /* writing the DBF file header */
1162     memset (buf_shp, '\0', 32);
1163     fwrite (buf_shp, 1, 32, fl_dbf);
1164     dbf_size = 32;		/* note: DBF counts sizes in bytes */
1165     auxdbf = alloc_auxdbf (dbf_list);
1166     fld = dbf_list->First;
1167     while (fld)
1168       {
1169 	  /* exporting DBF Fields specifications */
1170 	  memset (buf_shp, 0, 32);
1171 	  if (strlen (fld->Name) > 10)
1172 	    {
1173 		/* long name: attempting to safely truncate */
1174 		truncate_long_name (auxdbf, fld);
1175 	    }
1176 	  strcpy (buf, fld->Name);
1177 	  len = strlen (buf);
1178 	  utf8len = 2048;
1179 	  pBuf = buf;
1180 	  pUtf8buf = utf8buf;
1181 	  if (iconv
1182 	      ((iconv_t) (shp->IconvObj), &pBuf, &len, &pUtf8buf,
1183 	       &utf8len) == (size_t) (-1))
1184 	      sprintf (buf, "FLD#%d", defaultId++);
1185 	  else
1186 	    {
1187 		memcpy (buf, utf8buf, 2048 - utf8len);
1188 		buf[2048 - utf8len] = '\0';
1189 		if (strlen (buf) > 10)
1190 		    sprintf (buf, "FLD#%d", defaultId++);
1191 	    }
1192 	  convert_dbf_colname_case (buf, colname_case);
1193 	  memcpy (buf_shp, buf, strlen (buf));
1194 	  *(buf_shp + 11) = fld->Type;
1195 	  *(buf_shp + 16) = fld->Length;
1196 	  *(buf_shp + 17) = fld->Decimals;
1197 	  fwrite (buf_shp, 1, 32, fl_dbf);
1198 	  dbf_size += 32;
1199 	  fld = fld->Next;
1200       }
1201     free_auxdbf (auxdbf);
1202     fwrite ("\r", 1, 1, fl_dbf);	/* this one is a special DBF delimiter that closes file header */
1203     dbf_size++;
1204 /* setting up the SHP struct */
1205     len = strlen (path);
1206     shp->Path = malloc (len + 1);
1207     strcpy (shp->Path, path);
1208     shp->ReadOnly = 0;
1209     switch (shape)
1210       {
1211 	  /* setting up SHAPE and dimensions */
1212       case GAIA_POINT:
1213 	  shp->Shape = GAIA_SHP_POINT;
1214 	  shp->EffectiveType = GAIA_POINT;
1215 	  shp->EffectiveDims = GAIA_XY;
1216 	  break;
1217       case GAIA_POINTZ:
1218 	  shp->Shape = GAIA_SHP_POINTZ;
1219 	  shp->EffectiveType = GAIA_POINT;
1220 	  shp->EffectiveDims = GAIA_XY_Z;
1221 	  break;
1222       case GAIA_POINTM:
1223 	  shp->Shape = GAIA_SHP_POINTM;
1224 	  shp->EffectiveType = GAIA_POINT;
1225 	  shp->EffectiveDims = GAIA_XY_M;
1226 	  break;
1227       case GAIA_POINTZM:
1228 	  shp->Shape = GAIA_SHP_POINTZ;
1229 	  shp->EffectiveType = GAIA_POINT;
1230 	  shp->EffectiveDims = GAIA_XY_Z_M;
1231 	  break;
1232       case GAIA_MULTIPOINT:
1233 	  shp->Shape = GAIA_SHP_MULTIPOINT;
1234 	  shp->EffectiveType = GAIA_MULTIPOINT;
1235 	  shp->EffectiveDims = GAIA_XY;
1236 	  break;
1237       case GAIA_MULTIPOINTZ:
1238 	  shp->Shape = GAIA_SHP_MULTIPOINTZ;
1239 	  shp->EffectiveType = GAIA_MULTIPOINT;
1240 	  shp->EffectiveDims = GAIA_XY_Z;
1241 	  break;
1242       case GAIA_MULTIPOINTM:
1243 	  shp->Shape = GAIA_SHP_MULTIPOINTM;
1244 	  shp->EffectiveType = GAIA_MULTIPOINT;
1245 	  shp->EffectiveDims = GAIA_XY_M;
1246 	  break;
1247       case GAIA_MULTIPOINTZM:
1248 	  shp->Shape = GAIA_SHP_MULTIPOINTZ;
1249 	  shp->EffectiveType = GAIA_MULTIPOINT;
1250 	  shp->EffectiveDims = GAIA_XY_Z_M;
1251 	  break;
1252       case GAIA_LINESTRING:
1253 	  shp->Shape = GAIA_SHP_POLYLINE;
1254 	  shp->EffectiveType = GAIA_LINESTRING;
1255 	  shp->EffectiveDims = GAIA_XY;
1256 	  break;
1257       case GAIA_LINESTRINGZ:
1258 	  shp->Shape = GAIA_SHP_POLYLINEZ;
1259 	  shp->EffectiveType = GAIA_LINESTRING;
1260 	  shp->EffectiveDims = GAIA_XY_Z;
1261 	  break;
1262       case GAIA_LINESTRINGM:
1263 	  shp->Shape = GAIA_SHP_POLYLINEM;
1264 	  shp->EffectiveType = GAIA_LINESTRING;
1265 	  shp->EffectiveDims = GAIA_XY_M;
1266 	  break;
1267       case GAIA_LINESTRINGZM:
1268 	  shp->Shape = GAIA_SHP_POLYLINEZ;
1269 	  shp->EffectiveType = GAIA_LINESTRING;
1270 	  shp->EffectiveDims = GAIA_XY_Z_M;
1271 	  break;
1272       case GAIA_MULTILINESTRING:
1273 	  shp->Shape = GAIA_SHP_POLYLINE;
1274 	  shp->EffectiveType = GAIA_MULTILINESTRING;
1275 	  shp->EffectiveDims = GAIA_XY;
1276 	  break;
1277       case GAIA_MULTILINESTRINGZ:
1278 	  shp->Shape = GAIA_SHP_POLYLINEZ;
1279 	  shp->EffectiveType = GAIA_MULTILINESTRING;
1280 	  shp->EffectiveDims = GAIA_XY_Z;
1281 	  break;
1282       case GAIA_MULTILINESTRINGM:
1283 	  shp->Shape = GAIA_SHP_POLYLINEM;
1284 	  shp->EffectiveType = GAIA_MULTILINESTRING;
1285 	  shp->EffectiveDims = GAIA_XY_M;
1286 	  break;
1287       case GAIA_MULTILINESTRINGZM:
1288 	  shp->Shape = GAIA_SHP_POLYLINEZ;
1289 	  shp->EffectiveType = GAIA_MULTILINESTRING;
1290 	  shp->EffectiveDims = GAIA_XY_Z_M;
1291 	  break;
1292       case GAIA_POLYGON:
1293 	  shp->Shape = GAIA_SHP_POLYGON;
1294 	  shp->EffectiveType = GAIA_POLYGON;
1295 	  shp->EffectiveDims = GAIA_XY;
1296 	  break;
1297       case GAIA_POLYGONZ:
1298 	  shp->Shape = GAIA_SHP_POLYGONZ;
1299 	  shp->EffectiveType = GAIA_POLYGON;
1300 	  shp->EffectiveDims = GAIA_XY_Z;
1301 	  break;
1302       case GAIA_POLYGONM:
1303 	  shp->Shape = GAIA_SHP_POLYGONM;
1304 	  shp->EffectiveType = GAIA_POLYGON;
1305 	  shp->EffectiveDims = GAIA_XY_M;
1306 	  break;
1307       case GAIA_POLYGONZM:
1308 	  shp->Shape = GAIA_SHP_POLYGONZ;
1309 	  shp->EffectiveType = GAIA_POLYGON;
1310 	  shp->EffectiveDims = GAIA_XY_Z_M;
1311 	  break;
1312       case GAIA_MULTIPOLYGON:
1313 	  shp->Shape = GAIA_SHP_POLYGON;
1314 	  shp->EffectiveType = GAIA_MULTIPOLYGON;
1315 	  shp->EffectiveDims = GAIA_XY;
1316 	  break;
1317       case GAIA_MULTIPOLYGONZ:
1318 	  shp->Shape = GAIA_SHP_POLYGONZ;
1319 	  shp->EffectiveType = GAIA_MULTIPOLYGON;
1320 	  shp->EffectiveDims = GAIA_XY_Z;
1321 	  break;
1322       case GAIA_MULTIPOLYGONM:
1323 	  shp->Shape = GAIA_SHP_POLYGONM;
1324 	  shp->EffectiveType = GAIA_MULTIPOLYGON;
1325 	  shp->EffectiveDims = GAIA_XY_M;
1326 	  break;
1327       case GAIA_MULTIPOLYGONZM:
1328 	  shp->Shape = GAIA_SHP_POLYGONZ;
1329 	  shp->EffectiveType = GAIA_MULTIPOLYGON;
1330 	  shp->EffectiveDims = GAIA_XY_Z_M;
1331 	  break;
1332       };
1333     shp->flShp = fl_shp;
1334     shp->flShx = fl_shx;
1335     shp->flDbf = fl_dbf;
1336     shp->Dbf = dbf_list;
1337     shp->BufShp = buf_shp;
1338     shp->ShpBfsz = buf_size;
1339     shp->BufDbf = dbf_buf;
1340     shp->DbfHdsz = dbf_size + 1;
1341     shp->DbfReclen = dbf_reclen;
1342     shp->DbfSize = dbf_size;
1343     shp->DbfRecno = 0;
1344     shp->ShpSize = shp_size;
1345     shp->ShxSize = shx_size;
1346     shp->MinX = DBL_MAX;
1347     shp->MinY = DBL_MAX;
1348     shp->MaxX = -DBL_MAX;
1349     shp->MaxY = -DBL_MAX;
1350     shp->Valid = 1;
1351     shp->endian_arch = endian_arch;
1352     return;
1353   unsupported_conversion:
1354 /* illegal charset */
1355     if (shp->LastError)
1356 	free (shp->LastError);
1357     len = strlen (errMsg);
1358     shp->LastError = malloc (len + 1);
1359     strcpy (shp->LastError, errMsg);
1360     return;
1361   no_file:
1362 /* one of shapefile's files can't be created/opened */
1363     if (shp->LastError)
1364 	free (shp->LastError);
1365     len = strlen (errMsg);
1366     shp->LastError = malloc (len + 1);
1367     strcpy (shp->LastError, errMsg);
1368     if (buf_shp)
1369 	free (buf_shp);
1370     if (fl_shx)
1371 	fclose (fl_shx);
1372     if (fl_shp)
1373 	fclose (fl_shp);
1374     if (fl_dbf)
1375 	fclose (fl_dbf);
1376     return;
1377 }
1378 
1379 static double
to_sqlite_julian_date(int year,int month,int day,double * julian)1380 to_sqlite_julian_date (int year, int month, int day, double *julian)
1381 {
1382 /* trying to convert an 'YYYY-MM-DD' date into a JulianDate [double] */
1383     int Y;
1384     int M;
1385     int D;
1386     int A;
1387     int B;
1388     int X1;
1389     int X2;
1390     if (year < 1900 || year > 2400)
1391 	return 0;
1392     if (month < 1 || month > 12)
1393 	return 0;
1394     if (day < 1)
1395 	return 0;
1396     switch (month)
1397       {
1398       case 2:
1399 	  if ((year / 4) == 0)
1400 	    {
1401 		if (day > 29)
1402 		    return 0;
1403 	    }
1404 	  else
1405 	    {
1406 		if (day > 28)
1407 		    return 0;
1408 	    }
1409 	  break;
1410       case 4:
1411       case 6:
1412       case 9:
1413       case 11:
1414 	  if (day > 30)
1415 	      return 0;
1416 	  break;
1417       default:
1418 	  if (day > 31)
1419 	      return 0;
1420       };
1421 /* computing the Julian date */
1422     Y = year;
1423     M = month;
1424     D = day;
1425     if (M <= 2)
1426       {
1427 	  Y--;
1428 	  M += 12;
1429       }
1430     A = Y / 100;
1431     B = 2 - A + (A / 4);
1432     X1 = 36525 * (Y + 4716) / 100;
1433     X2 = 306001 * (M + 1) / 10000;
1434     *julian = (double) (X1 + X2 + D + B - 1524.5);
1435     return 1;
1436 }
1437 
1438 static int
parseDbfField(unsigned char * buf_dbf,void * iconv_obj,gaiaDbfFieldPtr pFld,int text_dates)1439 parseDbfField (unsigned char *buf_dbf, void *iconv_obj, gaiaDbfFieldPtr pFld,
1440 	       int text_dates)
1441 {
1442 /* parsing a generic DBF field */
1443     unsigned char buf[512];
1444     char utf8buf[2048];
1445 #if !defined(__MINGW32__) && defined(_WIN32)
1446     const char *pBuf;
1447 #else /* not WIN32 */
1448     char *pBuf;
1449 #endif
1450     size_t len;
1451     size_t utf8len;
1452     char *pUtf8buf;
1453     int i;
1454     memcpy (buf, buf_dbf + pFld->Offset + 1, pFld->Length);
1455     buf[pFld->Length] = '\0';
1456     if (*buf == '\0')
1457 	gaiaSetNullValue (pFld);
1458     else
1459       {
1460 	  if (pFld->Type == 'N')
1461 	    {
1462 		/* NUMERIC value */
1463 		if (pFld->Decimals > 0 || pFld->Length > 18)
1464 		    gaiaSetDoubleValue (pFld, atof ((char *) buf));
1465 		else
1466 		    gaiaSetIntValue (pFld, atoll ((char *) buf));
1467 	    }
1468 	  else if (pFld->Type == 'M')
1469 	    {
1470 		/* MEMO value - assumed to always be NULL */
1471 		gaiaSetNullValue (pFld);
1472 	    }
1473 	  else if (pFld->Type == 'F')
1474 	    {
1475 		/* FLOAT value */
1476 		gaiaSetDoubleValue (pFld, atof ((char *) buf));
1477 	    }
1478 	  else if (pFld->Type == 'D')
1479 	    {
1480 		/* DATE value */
1481 		if (text_dates)
1482 		  {
1483 		      /* assuming to be plain text */
1484 		      gaiaSetStrValue (pFld, (char *) buf);
1485 		  }
1486 		else
1487 		  {
1488 		      if (strlen ((char *) buf) != 8)
1489 			  gaiaSetNullValue (pFld);
1490 		      else
1491 			{
1492 			    /* converting into a Julian Date */
1493 			    double julian;
1494 			    char date[5];
1495 			    int year = 0;
1496 			    int month = 0;
1497 			    int day = 0;
1498 			    date[0] = buf[0];
1499 			    date[1] = buf[1];
1500 			    date[2] = buf[2];
1501 			    date[3] = buf[3];
1502 			    date[4] = '\0';
1503 			    year = atoi (date);
1504 			    date[0] = buf[4];
1505 			    date[1] = buf[5];
1506 			    date[2] = '\0';
1507 			    month = atoi (date);
1508 			    date[0] = buf[6];
1509 			    date[1] = buf[7];
1510 			    date[2] = '\0';
1511 			    day = atoi (date);
1512 			    if (to_sqlite_julian_date
1513 				(year, month, day, &julian))
1514 				gaiaSetDoubleValue (pFld, julian);
1515 			    else
1516 				gaiaSetNullValue (pFld);
1517 			}
1518 		  }
1519 	    }
1520 	  else if (pFld->Type == 'L')
1521 	    {
1522 		/* LOGICAL [aka Boolean] value */
1523 		if (*buf == '1' || *buf == 't' || *buf == 'T'
1524 		    || *buf == 'Y' || *buf == 'y')
1525 		    gaiaSetIntValue (pFld, 1);
1526 		else
1527 		    gaiaSetIntValue (pFld, 0);
1528 	    }
1529 	  else
1530 	    {
1531 		/* CHARACTER [aka String, Text] value */
1532 
1533 /* Sandro 2013-01-07
1534 / fixing an issue reported by Filip Arlet <filip.arlet@gmail.com>
1535 		for (i = strlen ((char *) buf) - 1; i > 1; i--)
1536 */
1537 		for (i = strlen ((char *) buf) - 1; i >= 0; i--)
1538 		  {
1539 		      /* cleaning up trailing spaces */
1540 		      if (buf[i] == ' ')
1541 			  buf[i] = '\0';
1542 		      else
1543 			  break;
1544 		  }
1545 		len = strlen ((char *) buf);
1546 		utf8len = 2048;
1547 		pBuf = (char *) buf;
1548 		pUtf8buf = utf8buf;
1549 		if (iconv
1550 		    ((iconv_t) (iconv_obj), &pBuf, &len, &pUtf8buf,
1551 		     &utf8len) == (size_t) (-1))
1552 		    return 0;
1553 		memcpy (buf, utf8buf, 2048 - utf8len);
1554 		buf[2048 - utf8len] = '\0';
1555 		gaiaSetStrValue (pFld, (char *) buf);
1556 	    }
1557       }
1558     return 1;
1559 }
1560 
1561 struct shp_ring_item
1562 {
1563 /* a RING item [to be reassembled into a (Multi)Polygon] */
1564     gaiaRingPtr Ring;
1565     int IsExterior;
1566     gaiaRingPtr Mother;
1567     struct shp_ring_item *Next;
1568 };
1569 
1570 struct shp_ring_collection
1571 {
1572 /* a collection of RING items */
1573     struct shp_ring_item *First;
1574     struct shp_ring_item *Last;
1575 };
1576 
1577 static void
shp_free_rings(struct shp_ring_collection * ringsColl)1578 shp_free_rings (struct shp_ring_collection *ringsColl)
1579 {
1580 /* memory cleanup: rings collection */
1581     struct shp_ring_item *p;
1582     struct shp_ring_item *pN;
1583     p = ringsColl->First;
1584     while (p)
1585       {
1586 	  pN = p->Next;
1587 	  if (p->Ring)
1588 	      gaiaFreeRing (p->Ring);
1589 	  free (p);
1590 	  p = pN;
1591       }
1592 }
1593 
1594 static void
shp_add_ring(struct shp_ring_collection * ringsColl,gaiaRingPtr ring)1595 shp_add_ring (struct shp_ring_collection *ringsColl, gaiaRingPtr ring)
1596 {
1597 /* inserting a ring into the rings collection */
1598     struct shp_ring_item *p = malloc (sizeof (struct shp_ring_item));
1599     p->Ring = ring;
1600     gaiaMbrRing (ring);
1601     gaiaClockwise (ring);
1602 /* accordingly to SHP rules interior/exterior depends on direction */
1603     p->IsExterior = ring->Clockwise;
1604     p->Mother = NULL;
1605     p->Next = NULL;
1606 /* updating the linked list */
1607     if (ringsColl->First == NULL)
1608 	ringsColl->First = p;
1609     if (ringsColl->Last != NULL)
1610 	ringsColl->Last->Next = p;
1611     ringsColl->Last = p;
1612 }
1613 
1614 static int
shp_check_rings(gaiaRingPtr exterior,gaiaRingPtr candidate)1615 shp_check_rings (gaiaRingPtr exterior, gaiaRingPtr candidate)
1616 {
1617 /*
1618 / speditively checks if the candidate could be an interior Ring
1619 / contained into the exterior Ring
1620 */
1621     double z;
1622     double m;
1623     double x0;
1624     double y0;
1625     double x1;
1626     double y1;
1627     int mid;
1628     int ret0;
1629     int ret1;
1630     if (candidate->DimensionModel == GAIA_XY_Z)
1631       {
1632 	  gaiaGetPointXYZ (candidate->Coords, 0, &x0, &y0, &z);
1633       }
1634     else if (candidate->DimensionModel == GAIA_XY_M)
1635       {
1636 	  gaiaGetPointXYM (candidate->Coords, 0, &x0, &y0, &m);
1637       }
1638     else if (candidate->DimensionModel == GAIA_XY_Z_M)
1639       {
1640 	  gaiaGetPointXYZM (candidate->Coords, 0, &x0, &y0, &z, &m);
1641       }
1642     else
1643       {
1644 	  gaiaGetPoint (candidate->Coords, 0, &x0, &y0);
1645       }
1646     mid = candidate->Points / 2;
1647     if (candidate->DimensionModel == GAIA_XY_Z)
1648       {
1649 	  gaiaGetPointXYZ (candidate->Coords, mid, &x1, &y1, &z);
1650       }
1651     else if (candidate->DimensionModel == GAIA_XY_M)
1652       {
1653 	  gaiaGetPointXYM (candidate->Coords, mid, &x1, &y1, &m);
1654       }
1655     else if (candidate->DimensionModel == GAIA_XY_Z_M)
1656       {
1657 	  gaiaGetPointXYZM (candidate->Coords, mid, &x1, &y1, &z, &m);
1658       }
1659     else
1660       {
1661 	  gaiaGetPoint (candidate->Coords, mid, &x1, &y1);
1662       }
1663 
1664 /* testing if the first point falls on the exterior ring surface */
1665     ret0 = gaiaIsPointOnRingSurface (exterior, x0, y0);
1666 /* testing if the second point falls on the exterior ring surface */
1667     ret1 = gaiaIsPointOnRingSurface (exterior, x1, y1);
1668     if (ret0 || ret1)
1669 	return 1;
1670     return 0;
1671 }
1672 
1673 static int
shp_mbr_contains(gaiaRingPtr r1,gaiaRingPtr r2)1674 shp_mbr_contains (gaiaRingPtr r1, gaiaRingPtr r2)
1675 {
1676 /* checks if the first Ring contains the second one - MBR based */
1677     int ok_1 = 0;
1678     int ok_2 = 0;
1679     int ok_3 = 0;
1680     int ok_4 = 0;
1681     if (r2->MinX >= r1->MinX && r2->MinX <= r1->MaxX)
1682 	ok_1 = 1;
1683     if (r2->MaxX >= r1->MinX && r2->MaxX <= r1->MaxX)
1684 	ok_2 = 1;
1685     if (r2->MinY >= r1->MinY && r2->MinY <= r1->MaxY)
1686 	ok_3 = 1;
1687     if (r2->MaxY >= r1->MinY && r2->MaxY <= r1->MaxY)
1688 	ok_4 = 1;
1689     if (ok_1 && ok_2 && ok_3 && ok_4)
1690 	return 1;
1691     return 0;
1692 }
1693 
1694 static void
shp_arrange_rings(struct shp_ring_collection * ringsColl)1695 shp_arrange_rings (struct shp_ring_collection *ringsColl)
1696 {
1697 /*
1698 / arranging Rings so to associate any interior ring
1699 / to the containing exterior ring
1700 */
1701     struct shp_ring_item *pInt;
1702     struct shp_ring_item *pExt;
1703     pExt = ringsColl->First;
1704     while (pExt != NULL)
1705       {
1706 	  /* looping on Exterior Rings */
1707 	  if (pExt->IsExterior)
1708 	    {
1709 		pInt = ringsColl->First;
1710 		while (pInt != NULL)
1711 		  {
1712 		      /* looping on Interior Rings */
1713 		      if (pInt->IsExterior == 0 && pInt->Mother == NULL
1714 			  && shp_mbr_contains (pExt->Ring, pInt->Ring))
1715 			{
1716 			    /* ok, matches */
1717 			    if (shp_check_rings (pExt->Ring, pInt->Ring))
1718 				pInt->Mother = pExt->Ring;
1719 			}
1720 		      pInt = pInt->Next;
1721 		  }
1722 	    }
1723 	  pExt = pExt->Next;
1724       }
1725     pExt = ringsColl->First;
1726     while (pExt != NULL)
1727       {
1728 	  if (pExt->IsExterior == 0 && pExt->Mother == NULL)
1729 	    {
1730 		/* orphan ring: promoting to Exterior */
1731 		pExt->IsExterior = 1;
1732 	    }
1733 	  pExt = pExt->Next;
1734       }
1735 }
1736 
1737 static void
shp_build_area(struct shp_ring_collection * ringsColl,gaiaGeomCollPtr geom)1738 shp_build_area (struct shp_ring_collection *ringsColl, gaiaGeomCollPtr geom)
1739 {
1740 /* building the final (Multi)Polygon Geometry */
1741     gaiaPolygonPtr polyg;
1742     struct shp_ring_item *pExt;
1743     struct shp_ring_item *pInt;
1744     pExt = ringsColl->First;
1745     while (pExt != NULL)
1746       {
1747 	  if (pExt->IsExterior)
1748 	    {
1749 		/* creating a new Polygon */
1750 		polyg = gaiaInsertPolygonInGeomColl (geom, pExt->Ring);
1751 		pInt = ringsColl->First;
1752 		while (pInt != NULL)
1753 		  {
1754 		      if (pExt->Ring == pInt->Mother)
1755 			{
1756 			    /* adding an interior ring to current POLYGON */
1757 			    gaiaAddRingToPolyg (polyg, pInt->Ring);
1758 			    /* releasing Ring ownership */
1759 			    pInt->Ring = NULL;
1760 			}
1761 		      pInt = pInt->Next;
1762 		  }
1763 		/* releasing Ring ownership */
1764 		pExt->Ring = NULL;
1765 	    }
1766 	  pExt = pExt->Next;
1767       }
1768 }
1769 
1770 GAIAGEO_DECLARE int
gaiaReadShpEntity(gaiaShapefilePtr shp,int current_row,int srid)1771 gaiaReadShpEntity (gaiaShapefilePtr shp, int current_row, int srid)
1772 {
1773     return gaiaReadShpEntity_ex (shp, current_row, srid, 0);
1774 }
1775 
1776 GAIAGEO_DECLARE int
gaiaReadShpEntity_ex(gaiaShapefilePtr shp,int current_row,int srid,int text_dates)1777 gaiaReadShpEntity_ex (gaiaShapefilePtr shp, int current_row, int srid,
1778 		      int text_dates)
1779 {
1780 /* trying to read an entity from shapefile */
1781     unsigned char buf[512];
1782     int len;
1783     int rd;
1784     int skpos;
1785     gaia_off_t offset;
1786     int off_shp;
1787     int sz;
1788     int shape;
1789     double x;
1790     double y;
1791     double z;
1792     double m;
1793     int points;
1794     int n;
1795     int n1;
1796     int base;
1797     int baseZ;
1798     int baseM;
1799     int start;
1800     int end;
1801     int iv;
1802     int ind;
1803     int max_size;
1804     int min_size;
1805     int hasM;
1806     char errMsg[1024];
1807     gaiaGeomCollPtr geom = NULL;
1808     gaiaLinestringPtr line = NULL;
1809     gaiaRingPtr ring = NULL;
1810     gaiaDbfFieldPtr pFld;
1811     struct shp_ring_collection ringsColl;
1812 /* initializing the RING collection */
1813     ringsColl.First = NULL;
1814     ringsColl.Last = NULL;
1815 /* positioning and reading the SHX file */
1816     offset = 100 + ((gaia_off_t) current_row * (gaia_off_t) 8);	/* 100 bytes for the header + current row displacement; each SHX row = 8 bytes */
1817     if (shp->memShx != NULL)
1818 	skpos = gaiaMemFseek (shp->memShx, offset);
1819     else
1820 	skpos = gaia_fseek (shp->flShx, offset, SEEK_SET);
1821     if (skpos != 0)
1822 	goto eof;
1823     if (shp->memDbf != NULL)
1824 	rd = gaiaMemRead (buf, 8, shp->memShx);
1825     else
1826 	rd = fread (buf, sizeof (unsigned char), 8, shp->flShx);
1827     if (rd != 8)
1828 	goto eof;
1829     off_shp = gaiaImport32 (buf, GAIA_BIG_ENDIAN, shp->endian_arch);
1830 /* positioning and reading the DBF file */
1831     offset =
1832 	shp->DbfHdsz +
1833 	((gaia_off_t) current_row * (gaia_off_t) (shp->DbfReclen));
1834     if (shp->memDbf != NULL)
1835 	skpos = gaiaMemFseek (shp->memDbf, offset);
1836     else
1837 	skpos = gaia_fseek (shp->flDbf, offset, SEEK_SET);
1838     if (skpos != 0)
1839 	goto error;
1840     if (shp->memDbf != NULL)
1841 	rd = gaiaMemRead (shp->BufDbf, shp->DbfReclen, shp->memDbf);
1842     else
1843 	rd = fread (shp->BufDbf, sizeof (unsigned char), shp->DbfReclen,
1844 		    shp->flDbf);
1845     if (rd != shp->DbfReclen)
1846 	goto error;
1847     if (*(shp->BufDbf) == '*')
1848 	goto dbf_deleted;
1849 /* positioning and reading corresponding SHP entity - geometry */
1850     offset = (gaia_off_t) off_shp *2;
1851     if (shp->memShp != NULL)
1852 	skpos = gaiaMemFseek (shp->memShp, offset);
1853     else
1854 	skpos = gaia_fseek (shp->flShp, offset, SEEK_SET);
1855     if (skpos != 0)
1856 	goto error;
1857     if (shp->memShp != NULL)
1858 	rd = gaiaMemRead (buf, 12, shp->memShp);
1859     else
1860 	rd = fread (buf, sizeof (unsigned char), 12, shp->flShp);
1861     if (rd != 12)
1862 	goto error;
1863     sz = gaiaImport32 (buf + 4, GAIA_BIG_ENDIAN, shp->endian_arch);
1864     shape = gaiaImport32 (buf + 8, GAIA_LITTLE_ENDIAN, shp->endian_arch);
1865     if (shape == GAIA_SHP_NULL)
1866       {
1867 	  /* handling a NULL shape */
1868 	  goto null_shape;
1869       }
1870     else if (shape != shp->Shape)
1871 	goto error;
1872     if ((sz * 2) > shp->ShpBfsz)
1873       {
1874 	  /* current buffer is too small; we need to allocate a bigger buffer */
1875 	  free (shp->BufShp);
1876 	  shp->ShpBfsz = sz * 2;
1877 	  shp->BufShp = malloc (sizeof (unsigned char) * shp->ShpBfsz);
1878       }
1879     if (shape == GAIA_SHP_POINT)
1880       {
1881 	  /* shape point */
1882 	  if (shp->memShp != NULL)
1883 	      rd = gaiaMemRead (shp->BufShp, 16, shp->memShp);
1884 	  else
1885 	      rd = fread (shp->BufShp, sizeof (unsigned char), 16, shp->flShp);
1886 	  if (rd != 16)
1887 	      goto error;
1888 	  x = gaiaImport64 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
1889 	  y = gaiaImport64 (shp->BufShp + 8, GAIA_LITTLE_ENDIAN,
1890 			    shp->endian_arch);
1891 	  if (shp->EffectiveDims == GAIA_XY_Z)
1892 	    {
1893 		geom = gaiaAllocGeomCollXYZ ();
1894 		gaiaAddPointToGeomCollXYZ (geom, x, y, 0.0);
1895 	    }
1896 	  else if (shp->EffectiveDims == GAIA_XY_M)
1897 	    {
1898 		geom = gaiaAllocGeomCollXYM ();
1899 		gaiaAddPointToGeomCollXYM (geom, x, y, 0.0);
1900 	    }
1901 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
1902 	    {
1903 		geom = gaiaAllocGeomCollXYZM ();
1904 		gaiaAddPointToGeomCollXYZM (geom, x, y, 0.0, 0.0);
1905 	    }
1906 	  else
1907 	    {
1908 		geom = gaiaAllocGeomColl ();
1909 		gaiaAddPointToGeomColl (geom, x, y);
1910 	    }
1911 	  geom->DeclaredType = GAIA_POINT;
1912 	  geom->Srid = srid;
1913       }
1914     if (shape == GAIA_SHP_POINTZ)
1915       {
1916 	  /* shape point Z */
1917 	  if (shp->memShp != NULL)
1918 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
1919 	  else
1920 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
1921 	  if (rd != 32)
1922 	    {
1923 		/* required by some buggish SHP (e.g. the GDAL/OGR ones) */
1924 		if (rd != 24)
1925 		    goto error;
1926 	    }
1927 	  x = gaiaImport64 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
1928 	  y = gaiaImport64 (shp->BufShp + 8, GAIA_LITTLE_ENDIAN,
1929 			    shp->endian_arch);
1930 	  z = gaiaImport64 (shp->BufShp + 16, GAIA_LITTLE_ENDIAN,
1931 			    shp->endian_arch);
1932 	  if (rd == 24)
1933 	      m = 0.0;
1934 	  else
1935 	      m = gaiaImport64 (shp->BufShp + 24, GAIA_LITTLE_ENDIAN,
1936 				shp->endian_arch);
1937 	  if (shp->EffectiveDims == GAIA_XY_Z)
1938 	    {
1939 		geom = gaiaAllocGeomCollXYZ ();
1940 		gaiaAddPointToGeomCollXYZ (geom, x, y, z);
1941 	    }
1942 	  else if (shp->EffectiveDims == GAIA_XY_M)
1943 	    {
1944 		geom = gaiaAllocGeomCollXYM ();
1945 		gaiaAddPointToGeomCollXYM (geom, x, y, m);
1946 	    }
1947 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
1948 	    {
1949 		geom = gaiaAllocGeomCollXYZM ();
1950 		gaiaAddPointToGeomCollXYZM (geom, x, y, z, m);
1951 	    }
1952 	  else
1953 	    {
1954 		geom = gaiaAllocGeomColl ();
1955 		gaiaAddPointToGeomColl (geom, x, y);
1956 	    }
1957 	  geom->DeclaredType = GAIA_POINT;
1958 	  geom->Srid = srid;
1959       }
1960     if (shape == GAIA_SHP_POINTM)
1961       {
1962 	  /* shape point M */
1963 	  if (shp->memShp != NULL)
1964 	      rd = gaiaMemRead (shp->BufShp, 24, shp->memShp);
1965 	  else
1966 	      rd = fread (shp->BufShp, sizeof (unsigned char), 24, shp->flShp);
1967 	  if (rd != 24)
1968 	      goto error;
1969 	  x = gaiaImport64 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
1970 	  y = gaiaImport64 (shp->BufShp + 8, GAIA_LITTLE_ENDIAN,
1971 			    shp->endian_arch);
1972 	  m = gaiaImport64 (shp->BufShp + 16, GAIA_LITTLE_ENDIAN,
1973 			    shp->endian_arch);
1974 	  if (shp->EffectiveDims == GAIA_XY_Z)
1975 	    {
1976 		geom = gaiaAllocGeomCollXYZ ();
1977 		gaiaAddPointToGeomCollXYZ (geom, x, y, 0.0);
1978 	    }
1979 	  else if (shp->EffectiveDims == GAIA_XY_M)
1980 	    {
1981 		geom = gaiaAllocGeomCollXYM ();
1982 		gaiaAddPointToGeomCollXYM (geom, x, y, m);
1983 	    }
1984 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
1985 	    {
1986 		geom = gaiaAllocGeomCollXYZM ();
1987 		gaiaAddPointToGeomCollXYZM (geom, x, y, 0.0, m);
1988 	    }
1989 	  else
1990 	    {
1991 		geom = gaiaAllocGeomColl ();
1992 		gaiaAddPointToGeomColl (geom, x, y);
1993 	    }
1994 	  geom->DeclaredType = GAIA_POINT;
1995 	  geom->Srid = srid;
1996       }
1997     if (shape == GAIA_SHP_POLYLINE)
1998       {
1999 	  /* shape polyline */
2000 	  int extra_check = 0;
2001 	  if (shp->memShp != NULL)
2002 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2003 	  else
2004 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2005 	  if (rd != 32)
2006 	      goto error;
2007 	  if (shp->memShp != NULL)
2008 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2009 	  else
2010 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2011 			  shp->flShp);
2012 	  if (rd != (sz * 2) - 36)
2013 	    {
2014 		if (rd == (sz * 2) - 44)
2015 		  {
2016 		      /* sandro 2018-02-17
2017 		       * it could be some defective SHP badly computing the
2018 		       * expected record length.
2019 		       * some unknown software producing defective shapefiles
2020 		       * of the 2D PolyLine type has been positively identified;
2021 		       * all record lengths were constantly declaring 4 extra words,
2022 		       * possibly because the Record Number and the Content Length
2023 		       * fields were wrongly included into the record length
2024 		       * calculation.
2025 		       */
2026 		      extra_check = 1;
2027 		  }
2028 		else
2029 		    goto error;
2030 	    }
2031 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2032 	  n1 = gaiaImport32 (shp->BufShp + 4, GAIA_LITTLE_ENDIAN,
2033 			     shp->endian_arch);
2034 	  if (extra_check)
2035 	    {
2036 		/* checking the expected buffer size */
2037 		int expected = 8 + (n * 4) + (n1 * 16);
2038 		if (rd != expected)
2039 		    goto error;
2040 	    }
2041 	  base = 8 + (n * 4);
2042 	  start = 0;
2043 	  for (ind = 0; ind < n; ind++)
2044 	    {
2045 		if (ind < (n - 1))
2046 		    end =
2047 			gaiaImport32 (shp->BufShp + 8 + ((ind + 1) * 4),
2048 				      GAIA_LITTLE_ENDIAN, shp->endian_arch);
2049 		else
2050 		    end = n1;
2051 		points = end - start;
2052 		if (shp->EffectiveDims == GAIA_XY_Z)
2053 		    line = gaiaAllocLinestringXYZ (points);
2054 		else if (shp->EffectiveDims == GAIA_XY_M)
2055 		    line = gaiaAllocLinestringXYM (points);
2056 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2057 		    line = gaiaAllocLinestringXYZM (points);
2058 		else
2059 		    line = gaiaAllocLinestring (points);
2060 		points = 0;
2061 		for (iv = start; iv < end; iv++)
2062 		  {
2063 		      x = gaiaImport64 (shp->BufShp + base + (iv * 16),
2064 					GAIA_LITTLE_ENDIAN, shp->endian_arch);
2065 		      y = gaiaImport64 (shp->BufShp + base + (iv * 16) +
2066 					8, GAIA_LITTLE_ENDIAN,
2067 					shp->endian_arch);
2068 		      if (shp->EffectiveDims == GAIA_XY_Z)
2069 			{
2070 			    gaiaSetPointXYZ (line->Coords, points, x, y, 0.0);
2071 			}
2072 		      else if (shp->EffectiveDims == GAIA_XY_M)
2073 			{
2074 			    gaiaSetPointXYM (line->Coords, points, x, y, 0.0);
2075 			}
2076 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2077 			{
2078 			    gaiaSetPointXYZM (line->Coords, points, x, y,
2079 					      0.0, 0.0);
2080 			}
2081 		      else
2082 			{
2083 			    gaiaSetPoint (line->Coords, points, x, y);
2084 			}
2085 		      start++;
2086 		      points++;
2087 		  }
2088 		if (!geom)
2089 		  {
2090 		      if (shp->EffectiveDims == GAIA_XY_Z)
2091 			  geom = gaiaAllocGeomCollXYZ ();
2092 		      else if (shp->EffectiveDims == GAIA_XY_M)
2093 			  geom = gaiaAllocGeomCollXYM ();
2094 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2095 			  geom = gaiaAllocGeomCollXYZM ();
2096 		      else
2097 			  geom = gaiaAllocGeomColl ();
2098 		      if (shp->EffectiveType == GAIA_LINESTRING)
2099 			  geom->DeclaredType = GAIA_LINESTRING;
2100 		      else
2101 			  geom->DeclaredType = GAIA_MULTILINESTRING;
2102 		      geom->Srid = srid;
2103 		  }
2104 		gaiaInsertLinestringInGeomColl (geom, line);
2105 	    }
2106       }
2107     if (shape == GAIA_SHP_POLYLINEZ)
2108       {
2109 	  /* shape polyline Z */
2110 	  if (shp->memShp != NULL)
2111 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2112 	  else
2113 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2114 	  if (rd != 32)
2115 	      goto error;
2116 	  if (shp->memShp != NULL)
2117 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2118 	  else
2119 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2120 			  shp->flShp);
2121 	  if (rd != (sz * 2) - 36)
2122 	      goto error;
2123 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2124 	  n1 = gaiaImport32 (shp->BufShp + 4, GAIA_LITTLE_ENDIAN,
2125 			     shp->endian_arch);
2126 	  hasM = 0;
2127 	  max_size = 38 + (2 * n) + (n1 * 16);	/* size [in 16 bits words !!!] ZM */
2128 	  min_size = 30 + (2 * n) + (n1 * 12);	/* size [in 16 bits words !!!] Z-only */
2129 	  if (sz < min_size)
2130 	      goto error;
2131 	  if (sz == max_size)
2132 	      hasM = 1;
2133 	  base = 8 + (n * 4);
2134 	  baseZ = base + (n1 * 16) + 16;
2135 	  baseM = baseZ + (n1 * 8) + 16;
2136 	  start = 0;
2137 	  for (ind = 0; ind < n; ind++)
2138 	    {
2139 		if (ind < (n - 1))
2140 		    end =
2141 			gaiaImport32 (shp->BufShp + 8 + ((ind + 1) * 4),
2142 				      GAIA_LITTLE_ENDIAN, shp->endian_arch);
2143 		else
2144 		    end = n1;
2145 		points = end - start;
2146 		if (shp->EffectiveDims == GAIA_XY_Z)
2147 		    line = gaiaAllocLinestringXYZ (points);
2148 		else if (shp->EffectiveDims == GAIA_XY_M)
2149 		    line = gaiaAllocLinestringXYM (points);
2150 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2151 		    line = gaiaAllocLinestringXYZM (points);
2152 		else
2153 		    line = gaiaAllocLinestring (points);
2154 		points = 0;
2155 		for (iv = start; iv < end; iv++)
2156 		  {
2157 		      x = gaiaImport64 (shp->BufShp + base + (iv * 16),
2158 					GAIA_LITTLE_ENDIAN, shp->endian_arch);
2159 		      y = gaiaImport64 (shp->BufShp + base + (iv * 16) +
2160 					8, GAIA_LITTLE_ENDIAN,
2161 					shp->endian_arch);
2162 		      z = gaiaImport64 (shp->BufShp + baseZ + (iv * 8),
2163 					GAIA_LITTLE_ENDIAN, shp->endian_arch);
2164 		      if (hasM)
2165 			  m = gaiaImport64 (shp->BufShp + baseM +
2166 					    (iv * 8), GAIA_LITTLE_ENDIAN,
2167 					    shp->endian_arch);
2168 		      else
2169 			  m = 0.0;
2170 		      if (m < SHAPEFILE_NO_DATA)
2171 			  m = 0.0;
2172 		      if (shp->EffectiveDims == GAIA_XY_Z)
2173 			{
2174 			    gaiaSetPointXYZ (line->Coords, points, x, y, z);
2175 			}
2176 		      else if (shp->EffectiveDims == GAIA_XY_M)
2177 			{
2178 			    gaiaSetPointXYM (line->Coords, points, x, y, m);
2179 			}
2180 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2181 			{
2182 			    gaiaSetPointXYZM (line->Coords, points, x, y, z, m);
2183 			}
2184 		      else
2185 			{
2186 			    gaiaSetPoint (line->Coords, points, x, y);
2187 			}
2188 		      start++;
2189 		      points++;
2190 		  }
2191 		if (!geom)
2192 		  {
2193 		      if (shp->EffectiveDims == GAIA_XY_Z)
2194 			  geom = gaiaAllocGeomCollXYZ ();
2195 		      else if (shp->EffectiveDims == GAIA_XY_M)
2196 			  geom = gaiaAllocGeomCollXYM ();
2197 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2198 			  geom = gaiaAllocGeomCollXYZM ();
2199 		      else
2200 			  geom = gaiaAllocGeomColl ();
2201 		      if (shp->EffectiveType == GAIA_LINESTRING)
2202 			  geom->DeclaredType = GAIA_LINESTRING;
2203 		      else
2204 			  geom->DeclaredType = GAIA_MULTILINESTRING;
2205 		      geom->Srid = srid;
2206 		  }
2207 		gaiaInsertLinestringInGeomColl (geom, line);
2208 	    }
2209       }
2210     if (shape == GAIA_SHP_POLYLINEM)
2211       {
2212 	  /* shape polyline M */
2213 	  if (shp->memShp != NULL)
2214 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2215 	  else
2216 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2217 	  if (rd != 32)
2218 	      goto error;
2219 	  if (shp->memShp != NULL)
2220 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2221 	  else
2222 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2223 			  shp->flShp);
2224 	  if (rd != (sz * 2) - 36)
2225 	      goto error;
2226 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2227 	  n1 = gaiaImport32 (shp->BufShp + 4, GAIA_LITTLE_ENDIAN,
2228 			     shp->endian_arch);
2229 	  hasM = 0;
2230 	  max_size = 30 + (2 * n) + (n1 * 12);	/* size [in 16 bits words !!!] M */
2231 	  min_size = 22 + (2 * n) + (n1 * 8);	/* size [in 16 bits words !!!] no-M */
2232 	  if (sz < min_size)
2233 	      goto error;
2234 	  if (sz == max_size)
2235 	      hasM = 1;
2236 	  base = 8 + (n * 4);
2237 	  baseM = base + (n1 * 16) + 16;
2238 	  start = 0;
2239 	  for (ind = 0; ind < n; ind++)
2240 	    {
2241 		if (ind < (n - 1))
2242 		    end =
2243 			gaiaImport32 (shp->BufShp + 8 + ((ind + 1) * 4),
2244 				      GAIA_LITTLE_ENDIAN, shp->endian_arch);
2245 		else
2246 		    end = n1;
2247 		points = end - start;
2248 		if (shp->EffectiveDims == GAIA_XY_Z)
2249 		    line = gaiaAllocLinestringXYZ (points);
2250 		else if (shp->EffectiveDims == GAIA_XY_M)
2251 		    line = gaiaAllocLinestringXYM (points);
2252 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2253 		    line = gaiaAllocLinestringXYZM (points);
2254 		else
2255 		    line = gaiaAllocLinestring (points);
2256 		points = 0;
2257 		for (iv = start; iv < end; iv++)
2258 		  {
2259 		      x = gaiaImport64 (shp->BufShp + base + (iv * 16),
2260 					GAIA_LITTLE_ENDIAN, shp->endian_arch);
2261 		      y = gaiaImport64 (shp->BufShp + base + (iv * 16) +
2262 					8, GAIA_LITTLE_ENDIAN,
2263 					shp->endian_arch);
2264 		      if (hasM)
2265 			  m = gaiaImport64 (shp->BufShp + baseM +
2266 					    (iv * 8), GAIA_LITTLE_ENDIAN,
2267 					    shp->endian_arch);
2268 		      else
2269 			  m = 0.0;
2270 		      if (m < SHAPEFILE_NO_DATA)
2271 			  m = 0.0;
2272 		      if (shp->EffectiveDims == GAIA_XY_Z)
2273 			{
2274 			    gaiaSetPointXYZ (line->Coords, points, x, y, 0.0);
2275 			}
2276 		      else if (shp->EffectiveDims == GAIA_XY_M)
2277 			{
2278 			    gaiaSetPointXYM (line->Coords, points, x, y, m);
2279 			}
2280 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2281 			{
2282 			    gaiaSetPointXYZM (line->Coords, points, x, y,
2283 					      0.0, m);
2284 			}
2285 		      else
2286 			{
2287 			    gaiaSetPoint (line->Coords, points, x, y);
2288 			}
2289 		      start++;
2290 		      points++;
2291 		  }
2292 		if (!geom)
2293 		  {
2294 		      if (shp->EffectiveDims == GAIA_XY_Z)
2295 			  geom = gaiaAllocGeomCollXYZ ();
2296 		      else if (shp->EffectiveDims == GAIA_XY_M)
2297 			  geom = gaiaAllocGeomCollXYM ();
2298 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2299 			  geom = gaiaAllocGeomCollXYZM ();
2300 		      else
2301 			  geom = gaiaAllocGeomColl ();
2302 		      if (shp->EffectiveType == GAIA_LINESTRING)
2303 			  geom->DeclaredType = GAIA_LINESTRING;
2304 		      else
2305 			  geom->DeclaredType = GAIA_MULTILINESTRING;
2306 		      geom->Srid = srid;
2307 		  }
2308 		gaiaInsertLinestringInGeomColl (geom, line);
2309 	    }
2310       }
2311     if (shape == GAIA_SHP_POLYGON)
2312       {
2313 	  /* shape polygon */
2314 	  if (shp->memShp != NULL)
2315 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2316 	  else
2317 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2318 	  if (rd != 32)
2319 	      goto error;
2320 	  if (shp->memShp != NULL)
2321 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2322 	  else
2323 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2324 			  shp->flShp);
2325 	  if (rd != (sz * 2) - 36)
2326 	      goto error;
2327 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2328 	  n1 = gaiaImport32 (shp->BufShp + 4, GAIA_LITTLE_ENDIAN,
2329 			     shp->endian_arch);
2330 	  base = 8 + (n * 4);
2331 	  start = 0;
2332 	  for (ind = 0; ind < n; ind++)
2333 	    {
2334 		if (ind < (n - 1))
2335 		    end =
2336 			gaiaImport32 (shp->BufShp + 8 + ((ind + 1) * 4),
2337 				      GAIA_LITTLE_ENDIAN, shp->endian_arch);
2338 		else
2339 		    end = n1;
2340 		points = end - start;
2341 		if (shp->EffectiveDims == GAIA_XY_Z)
2342 		    ring = gaiaAllocRingXYZ (points);
2343 		else if (shp->EffectiveDims == GAIA_XY_M)
2344 		    ring = gaiaAllocRingXYM (points);
2345 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2346 		    ring = gaiaAllocRingXYZM (points);
2347 		else
2348 		    ring = gaiaAllocRing (points);
2349 		points = 0;
2350 		for (iv = start; iv < end; iv++)
2351 		  {
2352 		      x = gaiaImport64 (shp->BufShp + base + (iv * 16),
2353 					GAIA_LITTLE_ENDIAN, shp->endian_arch);
2354 		      y = gaiaImport64 (shp->BufShp + base + (iv * 16) +
2355 					8, GAIA_LITTLE_ENDIAN,
2356 					shp->endian_arch);
2357 		      if (shp->EffectiveDims == GAIA_XY_Z)
2358 			{
2359 			    gaiaSetPointXYZ (ring->Coords, points, x, y, 0.0);
2360 			}
2361 		      else if (shp->EffectiveDims == GAIA_XY_M)
2362 			{
2363 			    gaiaSetPointXYM (ring->Coords, points, x, y, 0.0);
2364 			}
2365 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2366 			{
2367 			    gaiaSetPointXYZM (ring->Coords, points, x, y,
2368 					      0.0, 0.0);
2369 			}
2370 		      else
2371 			{
2372 			    gaiaSetPoint (ring->Coords, points, x, y);
2373 			}
2374 		      start++;
2375 		      points++;
2376 		  }
2377 		shp_add_ring (&ringsColl, ring);
2378 	    }
2379 	  shp_arrange_rings (&ringsColl);
2380 	  /* allocating the final geometry */
2381 	  if (shp->EffectiveDims == GAIA_XY_Z)
2382 	      geom = gaiaAllocGeomCollXYZ ();
2383 	  else if (shp->EffectiveDims == GAIA_XY_M)
2384 	      geom = gaiaAllocGeomCollXYM ();
2385 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
2386 	      geom = gaiaAllocGeomCollXYZM ();
2387 	  else
2388 	      geom = gaiaAllocGeomColl ();
2389 	  if (shp->EffectiveType == GAIA_POLYGON)
2390 	      geom->DeclaredType = GAIA_POLYGON;
2391 	  else
2392 	      geom->DeclaredType = GAIA_MULTIPOLYGON;
2393 	  geom->Srid = srid;
2394 	  shp_build_area (&ringsColl, geom);
2395       }
2396     if (shape == GAIA_SHP_POLYGONZ)
2397       {
2398 	  /* shape polygon Z */
2399 	  if (shp->memShp != NULL)
2400 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2401 	  else
2402 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2403 	  if (rd != 32)
2404 	      goto error;
2405 	  if (shp->memShp != NULL)
2406 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2407 	  else
2408 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2409 			  shp->flShp);
2410 	  if (rd != (sz * 2) - 36)
2411 	      goto error;
2412 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2413 	  n1 = gaiaImport32 (shp->BufShp + 4, GAIA_LITTLE_ENDIAN,
2414 			     shp->endian_arch);
2415 	  hasM = 0;
2416 	  max_size = 38 + (2 * n) + (n1 * 16);	/* size [in 16 bits words !!!] ZM */
2417 	  min_size = 30 + (2 * n) + (n1 * 12);	/* size [in 16 bits words !!!] Z-only */
2418 	  if (sz < min_size)
2419 	      goto error;
2420 	  if (sz == max_size)
2421 	      hasM = 1;
2422 	  base = 8 + (n * 4);
2423 	  baseZ = base + (n1 * 16) + 16;
2424 	  baseM = baseZ + (n1 * 8) + 16;
2425 	  start = 0;
2426 	  for (ind = 0; ind < n; ind++)
2427 	    {
2428 		if (ind < (n - 1))
2429 		    end =
2430 			gaiaImport32 (shp->BufShp + 8 + ((ind + 1) * 4),
2431 				      GAIA_LITTLE_ENDIAN, shp->endian_arch);
2432 		else
2433 		    end = n1;
2434 		points = end - start;
2435 		if (shp->EffectiveDims == GAIA_XY_Z)
2436 		    ring = gaiaAllocRingXYZ (points);
2437 		else if (shp->EffectiveDims == GAIA_XY_M)
2438 		    ring = gaiaAllocRingXYM (points);
2439 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2440 		    ring = gaiaAllocRingXYZM (points);
2441 		else
2442 		    ring = gaiaAllocRing (points);
2443 		points = 0;
2444 		for (iv = start; iv < end; iv++)
2445 		  {
2446 		      x = gaiaImport64 (shp->BufShp + base + (iv * 16),
2447 					GAIA_LITTLE_ENDIAN, shp->endian_arch);
2448 		      y = gaiaImport64 (shp->BufShp + base + (iv * 16) +
2449 					8, GAIA_LITTLE_ENDIAN,
2450 					shp->endian_arch);
2451 		      z = gaiaImport64 (shp->BufShp + baseZ + (iv * 8),
2452 					GAIA_LITTLE_ENDIAN, shp->endian_arch);
2453 		      if (hasM)
2454 			  m = gaiaImport64 (shp->BufShp + baseM +
2455 					    (iv * 8), GAIA_LITTLE_ENDIAN,
2456 					    shp->endian_arch);
2457 		      else
2458 			  m = 0.0;
2459 		      if (m < SHAPEFILE_NO_DATA)
2460 			  m = 0.0;
2461 		      if (shp->EffectiveDims == GAIA_XY_Z)
2462 			{
2463 			    gaiaSetPointXYZ (ring->Coords, points, x, y, z);
2464 			}
2465 		      else if (shp->EffectiveDims == GAIA_XY_M)
2466 			{
2467 			    gaiaSetPointXYM (ring->Coords, points, x, y, m);
2468 			}
2469 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2470 			{
2471 			    gaiaSetPointXYZM (ring->Coords, points, x, y, z, m);
2472 			}
2473 		      else
2474 			{
2475 			    gaiaSetPoint (ring->Coords, points, x, y);
2476 			}
2477 		      start++;
2478 		      points++;
2479 		  }
2480 		shp_add_ring (&ringsColl, ring);
2481 	    }
2482 	  shp_arrange_rings (&ringsColl);
2483 	  /* allocating the final geometry */
2484 	  if (shp->EffectiveDims == GAIA_XY_Z)
2485 	      geom = gaiaAllocGeomCollXYZ ();
2486 	  else if (shp->EffectiveDims == GAIA_XY_M)
2487 	      geom = gaiaAllocGeomCollXYM ();
2488 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
2489 	      geom = gaiaAllocGeomCollXYZM ();
2490 	  else
2491 	      geom = gaiaAllocGeomColl ();
2492 	  if (shp->EffectiveType == GAIA_POLYGON)
2493 	      geom->DeclaredType = GAIA_POLYGON;
2494 	  else
2495 	      geom->DeclaredType = GAIA_MULTIPOLYGON;
2496 	  geom->Srid = srid;
2497 	  shp_build_area (&ringsColl, geom);
2498       }
2499     if (shape == GAIA_SHP_POLYGONM)
2500       {
2501 	  /* shape polygon M */
2502 	  if (shp->memShp != NULL)
2503 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2504 	  else
2505 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2506 	  if (rd != 32)
2507 	      goto error;
2508 	  if (shp->memShp != NULL)
2509 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2510 	  else
2511 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2512 			  shp->flShp);
2513 	  if (rd != (sz * 2) - 36)
2514 	      goto error;
2515 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2516 	  n1 = gaiaImport32 (shp->BufShp + 4, GAIA_LITTLE_ENDIAN,
2517 			     shp->endian_arch);
2518 	  hasM = 0;
2519 	  max_size = 30 + (2 * n) + (n1 * 12);	/* size [in 16 bits words !!!] M */
2520 	  min_size = 22 + (2 * n) + (n1 * 8);	/* size [in 16 bits words !!!] no-M */
2521 	  if (sz < min_size)
2522 	      goto error;
2523 	  if (sz == max_size)
2524 	      hasM = 1;
2525 	  base = 8 + (n * 4);
2526 	  baseM = base + (n1 * 16) + 16;
2527 	  start = 0;
2528 	  for (ind = 0; ind < n; ind++)
2529 	    {
2530 		if (ind < (n - 1))
2531 		    end =
2532 			gaiaImport32 (shp->BufShp + 8 + ((ind + 1) * 4),
2533 				      GAIA_LITTLE_ENDIAN, shp->endian_arch);
2534 		else
2535 		    end = n1;
2536 		points = end - start;
2537 		if (shp->EffectiveDims == GAIA_XY_Z)
2538 		    ring = gaiaAllocRingXYZ (points);
2539 		else if (shp->EffectiveDims == GAIA_XY_M)
2540 		    ring = gaiaAllocRingXYM (points);
2541 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2542 		    ring = gaiaAllocRingXYZM (points);
2543 		else
2544 		    ring = gaiaAllocRing (points);
2545 		points = 0;
2546 		for (iv = start; iv < end; iv++)
2547 		  {
2548 		      x = gaiaImport64 (shp->BufShp + base + (iv * 16),
2549 					GAIA_LITTLE_ENDIAN, shp->endian_arch);
2550 		      y = gaiaImport64 (shp->BufShp + base + (iv * 16) +
2551 					8, GAIA_LITTLE_ENDIAN,
2552 					shp->endian_arch);
2553 		      if (hasM)
2554 			  m = gaiaImport64 (shp->BufShp + baseM +
2555 					    (iv * 8), GAIA_LITTLE_ENDIAN,
2556 					    shp->endian_arch);
2557 		      m = 0.0;
2558 		      if (m < SHAPEFILE_NO_DATA)
2559 			  m = 0.0;
2560 		      if (shp->EffectiveDims == GAIA_XY_Z)
2561 			{
2562 			    gaiaSetPointXYZ (ring->Coords, points, x, y, 0.0);
2563 			}
2564 		      else if (shp->EffectiveDims == GAIA_XY_M)
2565 			{
2566 			    gaiaSetPointXYM (ring->Coords, points, x, y, m);
2567 			}
2568 		      else if (shp->EffectiveDims == GAIA_XY_Z_M)
2569 			{
2570 			    gaiaSetPointXYZM (ring->Coords, points, x, y,
2571 					      0.0, m);
2572 			}
2573 		      else
2574 			{
2575 			    gaiaSetPoint (ring->Coords, points, x, y);
2576 			}
2577 		      start++;
2578 		      points++;
2579 		  }
2580 		shp_add_ring (&ringsColl, ring);
2581 	    }
2582 	  shp_arrange_rings (&ringsColl);
2583 	  /* allocating the final geometry */
2584 	  if (shp->EffectiveDims == GAIA_XY_Z)
2585 	      geom = gaiaAllocGeomCollXYZ ();
2586 	  else if (shp->EffectiveDims == GAIA_XY_M)
2587 	      geom = gaiaAllocGeomCollXYM ();
2588 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
2589 	      geom = gaiaAllocGeomCollXYZM ();
2590 	  else
2591 	      geom = gaiaAllocGeomColl ();
2592 	  if (shp->EffectiveType == GAIA_POLYGON)
2593 	      geom->DeclaredType = GAIA_POLYGON;
2594 	  else
2595 	      geom->DeclaredType = GAIA_MULTIPOLYGON;
2596 	  geom->Srid = srid;
2597 	  shp_build_area (&ringsColl, geom);
2598       }
2599     if (shape == GAIA_SHP_MULTIPOINT)
2600       {
2601 	  /* shape multipoint */
2602 	  if (shp->memShp != NULL)
2603 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2604 	  else
2605 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2606 	  if (rd != 32)
2607 	      goto error;
2608 	  if (shp->memShp != NULL)
2609 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2610 	  else
2611 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2612 			  shp->flShp);
2613 	  if (rd != (sz * 2) - 36)
2614 	      goto error;
2615 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2616 	  if (shp->EffectiveDims == GAIA_XY_Z)
2617 	      geom = gaiaAllocGeomCollXYZ ();
2618 	  else if (shp->EffectiveDims == GAIA_XY_M)
2619 	      geom = gaiaAllocGeomCollXYM ();
2620 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
2621 	      geom = gaiaAllocGeomCollXYZM ();
2622 	  else
2623 	      geom = gaiaAllocGeomColl ();
2624 	  geom->DeclaredType = GAIA_MULTIPOINT;
2625 	  geom->Srid = srid;
2626 	  for (iv = 0; iv < n; iv++)
2627 	    {
2628 		x = gaiaImport64 (shp->BufShp + 4 + (iv * 16),
2629 				  GAIA_LITTLE_ENDIAN, shp->endian_arch);
2630 		y = gaiaImport64 (shp->BufShp + 4 + (iv * 16) + 8,
2631 				  GAIA_LITTLE_ENDIAN, shp->endian_arch);
2632 		if (shp->EffectiveDims == GAIA_XY_Z)
2633 		    gaiaAddPointToGeomCollXYZ (geom, x, y, 0.0);
2634 		else if (shp->EffectiveDims == GAIA_XY_M)
2635 		    gaiaAddPointToGeomCollXYM (geom, x, y, 0.0);
2636 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2637 		    gaiaAddPointToGeomCollXYZM (geom, x, y, 0.0, 0.0);
2638 		else
2639 		    gaiaAddPointToGeomColl (geom, x, y);
2640 	    }
2641       }
2642     if (shape == GAIA_SHP_MULTIPOINTZ)
2643       {
2644 	  /* shape multipoint Z */
2645 	  if (shp->memShp != NULL)
2646 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2647 	  else
2648 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2649 	  if (rd != 32)
2650 	      goto error;
2651 	  if (shp->memShp != NULL)
2652 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2653 	  else
2654 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2655 			  shp->flShp);
2656 	  if (rd != (sz * 2) - 36)
2657 	      goto error;
2658 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2659 	  hasM = 0;
2660 	  max_size = 36 + (n * 16);	/* size [in 16 bits words !!!] ZM */
2661 	  min_size = 28 + (n * 12);	/* size [in 16 bits words !!!] Z-only */
2662 	  if (sz < min_size)
2663 	      goto error;
2664 	  if (sz == max_size)
2665 	      hasM = 1;
2666 	  baseZ = 4 + (n * 16) + 16;
2667 	  baseM = baseZ + (n * 8) + 16;
2668 	  if (shp->EffectiveDims == GAIA_XY_Z)
2669 	      geom = gaiaAllocGeomCollXYZ ();
2670 	  else if (shp->EffectiveDims == GAIA_XY_M)
2671 	      geom = gaiaAllocGeomCollXYM ();
2672 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
2673 	      geom = gaiaAllocGeomCollXYZM ();
2674 	  else
2675 	      geom = gaiaAllocGeomColl ();
2676 	  geom->DeclaredType = GAIA_MULTIPOINT;
2677 	  geom->Srid = srid;
2678 	  for (iv = 0; iv < n; iv++)
2679 	    {
2680 		x = gaiaImport64 (shp->BufShp + 4 + (iv * 16),
2681 				  GAIA_LITTLE_ENDIAN, shp->endian_arch);
2682 		y = gaiaImport64 (shp->BufShp + 4 + (iv * 16) + 8,
2683 				  GAIA_LITTLE_ENDIAN, shp->endian_arch);
2684 		z = gaiaImport64 (shp->BufShp + baseZ + (iv * 8),
2685 				  GAIA_LITTLE_ENDIAN, shp->endian_arch);
2686 		if (hasM)
2687 		    m = gaiaImport64 (shp->BufShp + baseM + (iv * 8),
2688 				      GAIA_LITTLE_ENDIAN, shp->endian_arch);
2689 		else
2690 		    m = 0.0;
2691 		if (m < SHAPEFILE_NO_DATA)
2692 		    m = 0.0;
2693 		if (shp->EffectiveDims == GAIA_XY_Z)
2694 		    gaiaAddPointToGeomCollXYZ (geom, x, y, z);
2695 		else if (shp->EffectiveDims == GAIA_XY_M)
2696 		    gaiaAddPointToGeomCollXYM (geom, x, y, m);
2697 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2698 		    gaiaAddPointToGeomCollXYZM (geom, x, y, z, m);
2699 		else
2700 		    gaiaAddPointToGeomColl (geom, x, y);
2701 	    }
2702       }
2703     if (shape == GAIA_SHP_MULTIPOINTM)
2704       {
2705 	  /* shape multipoint M */
2706 	  if (shp->memShp != NULL)
2707 	      rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
2708 	  else
2709 	      rd = fread (shp->BufShp, sizeof (unsigned char), 32, shp->flShp);
2710 	  if (rd != 32)
2711 	      goto error;
2712 	  if (shp->memShp != NULL)
2713 	      rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
2714 	  else
2715 	      rd = fread (shp->BufShp, sizeof (unsigned char), (sz * 2) - 36,
2716 			  shp->flShp);
2717 	  if (rd != (sz * 2) - 36)
2718 	      goto error;
2719 	  n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN, shp->endian_arch);
2720 	  hasM = 0;
2721 	  max_size = 28 + (n * 12);	/* size [in 16 bits words !!!] M */
2722 	  min_size = 20 + (n * 8);	/* size [in 16 bits words !!!] no-M */
2723 	  if (sz < min_size)
2724 	      goto error;
2725 	  if (sz == max_size)
2726 	      hasM = 1;
2727 	  baseM = 4 + (n * 16) + 16;
2728 	  if (shp->EffectiveDims == GAIA_XY_Z)
2729 	      geom = gaiaAllocGeomCollXYZ ();
2730 	  else if (shp->EffectiveDims == GAIA_XY_M)
2731 	      geom = gaiaAllocGeomCollXYM ();
2732 	  else if (shp->EffectiveDims == GAIA_XY_Z_M)
2733 	      geom = gaiaAllocGeomCollXYZM ();
2734 	  else
2735 	      geom = gaiaAllocGeomColl ();
2736 	  geom->DeclaredType = GAIA_MULTIPOINT;
2737 	  geom->Srid = srid;
2738 	  for (iv = 0; iv < n; iv++)
2739 	    {
2740 		x = gaiaImport64 (shp->BufShp + 4 + (iv * 16),
2741 				  GAIA_LITTLE_ENDIAN, shp->endian_arch);
2742 		y = gaiaImport64 (shp->BufShp + 4 + (iv * 16) + 8,
2743 				  GAIA_LITTLE_ENDIAN, shp->endian_arch);
2744 		if (hasM)
2745 		    m = gaiaImport64 (shp->BufShp + baseM + (iv * 8),
2746 				      GAIA_LITTLE_ENDIAN, shp->endian_arch);
2747 		else
2748 		    m = 0.0;
2749 		if (m < SHAPEFILE_NO_DATA)
2750 		    m = 0.0;
2751 		if (shp->EffectiveDims == GAIA_XY_Z)
2752 		    gaiaAddPointToGeomCollXYZ (geom, x, y, 0.0);
2753 		else if (shp->EffectiveDims == GAIA_XY_M)
2754 		    gaiaAddPointToGeomCollXYM (geom, x, y, m);
2755 		else if (shp->EffectiveDims == GAIA_XY_Z_M)
2756 		    gaiaAddPointToGeomCollXYZM (geom, x, y, 0.0, m);
2757 		else
2758 		    gaiaAddPointToGeomColl (geom, x, y);
2759 	    }
2760       }
2761 /* setting up the current SHP ENTITY */
2762   null_shape:
2763     gaiaResetDbfEntity (shp->Dbf);
2764     shp->Dbf->RowId = current_row;
2765     shp->Dbf->Geometry = geom;
2766 /* fetching the DBF values */
2767     pFld = shp->Dbf->First;
2768     while (pFld)
2769       {
2770 	  if (!parseDbfField (shp->BufDbf, shp->IconvObj, pFld, text_dates))
2771 	    {
2772 		char *text = malloc (pFld->Length + 1);
2773 		memcpy (text, shp->BufDbf + pFld->Offset + 1, pFld->Length);
2774 		text[pFld->Length] = '\0';
2775 		spatialite_e
2776 		    ("**** libiconv: unable to convert string=\"%s\"\n", text);
2777 		free (text);
2778 		goto conversion_error;
2779 	    }
2780 	  pFld = pFld->Next;
2781       }
2782     if (shp->LastError)
2783 	free (shp->LastError);
2784     shp->LastError = NULL;
2785     shp_free_rings (&ringsColl);
2786     return 1;
2787   eof:
2788     if (shp->LastError)
2789 	free (shp->LastError);
2790     shp->LastError = NULL;
2791     shp_free_rings (&ringsColl);
2792     return 0;
2793   error:
2794     if (shp->LastError)
2795 	free (shp->LastError);
2796     sprintf (errMsg, "'%s' is corrupted / has invalid format", shp->Path);
2797     len = strlen (errMsg);
2798     shp->LastError = malloc (len + 1);
2799     strcpy (shp->LastError, errMsg);
2800     shp_free_rings (&ringsColl);
2801     return 0;
2802   dbf_deleted:
2803     if (shp->LastError)
2804 	free (shp->LastError);
2805     shp->LastError = NULL;
2806     return -1;
2807   conversion_error:
2808     if (shp->LastError)
2809 	free (shp->LastError);
2810     sprintf (errMsg, "Invalid character sequence at DBF line %d", current_row);
2811     len = strlen (errMsg);
2812     shp->LastError = malloc (len + 1);
2813     strcpy (shp->LastError, errMsg);
2814     shp_free_rings (&ringsColl);
2815     return 0;
2816 }
2817 
2818 static void
gaiaSaneClockwise(gaiaPolygonPtr polyg)2819 gaiaSaneClockwise (gaiaPolygonPtr polyg)
2820 {
2821 /*
2822 / when exporting POLYGONs to SHAPEFILE, we must guarantee that:
2823 / - all EXTERIOR RING must be clockwise
2824 / - all INTERIOR RING must be anti-clockwise
2825 /
2826 / this function checks for the above conditions,
2827 / and if needed inverts the rings
2828 */
2829     int ib;
2830     int iv;
2831     int iv2;
2832     double x;
2833     double y;
2834     double z;
2835     double m;
2836     gaiaRingPtr new_ring;
2837     gaiaRingPtr ring = polyg->Exterior;
2838     gaiaClockwise (ring);
2839     if (!(ring->Clockwise))
2840       {
2841 	  /* exterior ring needs inversion */
2842 	  if (ring->DimensionModel == GAIA_XY_Z)
2843 	      new_ring = gaiaAllocRingXYZ (ring->Points);
2844 	  else if (ring->DimensionModel == GAIA_XY_M)
2845 	      new_ring = gaiaAllocRingXYM (ring->Points);
2846 	  else if (ring->DimensionModel == GAIA_XY_Z_M)
2847 	      new_ring = gaiaAllocRingXYZM (ring->Points);
2848 	  else
2849 	      new_ring = gaiaAllocRing (ring->Points);
2850 	  iv2 = 0;
2851 	  for (iv = ring->Points - 1; iv >= 0; iv--)
2852 	    {
2853 		if (ring->DimensionModel == GAIA_XY_Z)
2854 		  {
2855 		      gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
2856 		      gaiaSetPointXYZ (new_ring->Coords, iv2, x, y, z);
2857 		  }
2858 		else if (ring->DimensionModel == GAIA_XY_M)
2859 		  {
2860 		      gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
2861 		      gaiaSetPointXYM (new_ring->Coords, iv2, x, y, m);
2862 		  }
2863 		else if (ring->DimensionModel == GAIA_XY_Z_M)
2864 		  {
2865 		      gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
2866 		      gaiaSetPointXYZM (new_ring->Coords, iv2, x, y, z, m);
2867 		  }
2868 		else
2869 		  {
2870 		      gaiaGetPoint (ring->Coords, iv, &x, &y);
2871 		      gaiaSetPoint (new_ring->Coords, iv2, x, y);
2872 		  }
2873 		iv2++;
2874 	    }
2875 	  polyg->Exterior = new_ring;
2876 	  gaiaFreeRing (ring);
2877       }
2878     for (ib = 0; ib < polyg->NumInteriors; ib++)
2879       {
2880 	  ring = polyg->Interiors + ib;
2881 	  gaiaClockwise (ring);
2882 	  if (ring->Clockwise)
2883 	    {
2884 		/* interior ring needs inversion */
2885 		if (ring->DimensionModel == GAIA_XY_Z)
2886 		    new_ring = gaiaAllocRingXYZ (ring->Points);
2887 		else if (ring->DimensionModel == GAIA_XY_M)
2888 		    new_ring = gaiaAllocRingXYM (ring->Points);
2889 		else if (ring->DimensionModel == GAIA_XY_Z_M)
2890 		    new_ring = gaiaAllocRingXYZM (ring->Points);
2891 		else
2892 		    new_ring = gaiaAllocRing (ring->Points);
2893 		iv2 = 0;
2894 		for (iv = ring->Points - 1; iv >= 0; iv--)
2895 		  {
2896 		      if (ring->DimensionModel == GAIA_XY_Z)
2897 			{
2898 			    gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
2899 			    gaiaSetPointXYZ (new_ring->Coords, iv2, x, y, z);
2900 			}
2901 		      else if (ring->DimensionModel == GAIA_XY_M)
2902 			{
2903 			    gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
2904 			    gaiaSetPointXYM (new_ring->Coords, iv2, x, y, m);
2905 			}
2906 		      else if (ring->DimensionModel == GAIA_XY_Z_M)
2907 			{
2908 			    gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
2909 			    gaiaSetPointXYZM (new_ring->Coords, iv2, x, y,
2910 					      z, m);
2911 			}
2912 		      else
2913 			{
2914 			    gaiaGetPoint (ring->Coords, iv, &x, &y);
2915 			    gaiaSetPoint (new_ring->Coords, iv2, x, y);
2916 			}
2917 		      iv2++;
2918 		  }
2919 		for (iv = 0; iv < ring->Points; iv++)
2920 		  {
2921 		      if (ring->DimensionModel == GAIA_XY_Z)
2922 			{
2923 			    gaiaGetPointXYZ (new_ring->Coords, iv, &x, &y, &z);
2924 			    gaiaSetPointXYZ (ring->Coords, iv, x, y, z);
2925 			}
2926 		      else if (ring->DimensionModel == GAIA_XY_M)
2927 			{
2928 			    gaiaGetPointXYM (new_ring->Coords, iv, &x, &y, &m);
2929 			    gaiaSetPointXYM (ring->Coords, iv, x, y, m);
2930 			}
2931 		      else if (ring->DimensionModel == GAIA_XY_Z_M)
2932 			{
2933 			    gaiaGetPointXYZM (new_ring->Coords, iv, &x, &y,
2934 					      &z, &m);
2935 			    gaiaSetPointXYZM (ring->Coords, iv, x, y, z, m);
2936 			}
2937 		      else
2938 			{
2939 			    gaiaGetPoint (new_ring->Coords, iv, &x, &y);
2940 			    gaiaSetPoint (ring->Coords, iv, x, y);
2941 			}
2942 		  }
2943 		gaiaFreeRing (new_ring);
2944 	    }
2945       }
2946 }
2947 
2948 GAIAGEO_DECLARE int
gaiaWriteShpEntity(gaiaShapefilePtr shp,gaiaDbfListPtr entity)2949 gaiaWriteShpEntity (gaiaShapefilePtr shp, gaiaDbfListPtr entity)
2950 {
2951 /* trying to write an entity into shapefile */
2952     char dummy[128];
2953     char fmt[16];
2954     int endian_arch = shp->endian_arch;
2955     gaiaDbfFieldPtr fld;
2956     int iv;
2957     int tot_ln;
2958     int tot_v;
2959     int tot_pts;
2960     int this_size;
2961     int ix;
2962     double x;
2963     double y;
2964     double z;
2965     double m;
2966     int hasM;
2967     double minZ;
2968     double maxZ;
2969     double minM;
2970     double maxM;
2971 #if !defined(__MINGW32__) && defined(_WIN32)
2972     const char *pBuf;
2973 #else /* not WIN32 */
2974     char *pBuf;
2975 #endif
2976     size_t len;
2977     size_t utf8len;
2978     char *dynbuf;
2979     char *pUtf8buf;
2980     char utf8buf[2048];
2981 /* writing the DBF record */
2982     memset (shp->BufDbf, '\0', shp->DbfReclen);
2983     *(shp->BufDbf) = ' ';	/* in DBF first byte of each row marks for validity or deletion */
2984     fld = entity->First;
2985     while (fld)
2986       {
2987 	  /* transferring field values */
2988 	  switch (fld->Type)
2989 	    {
2990 	    case 'L':
2991 		if (!(fld->Value))
2992 		    *(shp->BufDbf + fld->Offset) = '?';
2993 		else if (fld->Value->Type != GAIA_INT_VALUE)
2994 		    *(shp->BufDbf + fld->Offset + 1) = '?';
2995 		else
2996 		  {
2997 		      if (fld->Value->IntValue == 0)
2998 			  *(shp->BufDbf + fld->Offset + 1) = 'N';
2999 		      else
3000 			  *(shp->BufDbf + fld->Offset + 1) = 'Y';
3001 		  }
3002 		break;
3003 	    case 'D':
3004 		memset (shp->BufDbf + fld->Offset + 1, '0', 8);
3005 		if (fld->Value)
3006 		  {
3007 		      if (fld->Value->Type == GAIA_TEXT_VALUE)
3008 			{
3009 			    if (strlen (fld->Value->TxtValue) == 8)
3010 				memcpy (shp->BufDbf + fld->Offset + 1,
3011 					fld->Value->TxtValue, 8);
3012 			}
3013 		  }
3014 		break;
3015 	    case 'C':
3016 		memset (shp->BufDbf + fld->Offset + 1, ' ', fld->Length);
3017 		if (fld->Value)
3018 		  {
3019 		      if (fld->Value->Type == GAIA_TEXT_VALUE)
3020 			{
3021 			    len = strlen (fld->Value->TxtValue);
3022 			    dynbuf = malloc (2048 + len + 1);
3023 			    strcpy (dynbuf, fld->Value->TxtValue);
3024 			    if (len > 512)
3025 			      {
3026 				  dynbuf[512] = '\0';
3027 				  len = strlen (dynbuf);
3028 			      }
3029 			    utf8len = 2048;
3030 			    pBuf = dynbuf;
3031 			    pUtf8buf = utf8buf;
3032 			    if (iconv
3033 				((iconv_t) (shp->IconvObj), &pBuf, &len,
3034 				 &pUtf8buf, &utf8len) == (size_t) (-1))
3035 			      {
3036 				  spatialite_e
3037 				      ("**** libiconv: unable to convert string=\"%s\"\n",
3038 				       dynbuf);
3039 				  free (dynbuf);
3040 				  goto conversion_error;
3041 			      }
3042 			    memcpy (dynbuf, utf8buf, 2048 - utf8len);
3043 			    dynbuf[2048 - utf8len] = '\0';
3044 			    if (strlen (dynbuf) < fld->Length)
3045 				memcpy (shp->BufDbf + fld->Offset + 1, dynbuf,
3046 					strlen (dynbuf));
3047 			    else
3048 				memcpy (shp->BufDbf + fld->Offset + 1, dynbuf,
3049 					fld->Length);
3050 			    free (dynbuf);
3051 			}
3052 		  }
3053 		break;
3054 	    case 'N':
3055 		memset (shp->BufDbf + fld->Offset + 1, '\0', fld->Length);
3056 		if (fld->Value)
3057 		  {
3058 		      if (fld->Value->Type == GAIA_INT_VALUE)
3059 			{
3060 			    sprintf (dummy, FRMT64, fld->Value->IntValue);
3061 			    if (strlen (dummy) <= fld->Length)
3062 				memcpy (shp->BufDbf + fld->Offset + 1,
3063 					dummy, strlen (dummy));
3064 			}
3065 		      if (fld->Value->Type == GAIA_DOUBLE_VALUE)
3066 			{
3067 			    sprintf (fmt, "%%1.%df", fld->Decimals);
3068 			    sprintf (dummy, fmt, fld->Value->DblValue);
3069 			    if (strlen (dummy) <= fld->Length)
3070 				memcpy (shp->BufDbf + fld->Offset + 1,
3071 					dummy, strlen (dummy));
3072 			}
3073 		  }
3074 		break;
3075 	    };
3076 	  fld = fld->Next;
3077       }
3078     if (!(entity->Geometry))
3079       {
3080 	  /* exporting a NULL Shape */
3081 	  gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3082 	  gaiaExport32 (shp->BufShp + 4, 2, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3083 	  fwrite (shp->BufShp, 1, 8, shp->flShx);
3084 	  (shp->ShxSize) += 4;	/* updating current SHX file position [in 16 bits words !!!] */
3085 	  gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3086 	  gaiaExport32 (shp->BufShp + 4, 2, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3087 	  gaiaExport32 (shp->BufShp + 8, GAIA_SHP_NULL, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = NULL */
3088 	  fwrite (shp->BufShp, 1, 12, shp->flShp);
3089 	  (shp->ShpSize) += 6;	/* updating current SHP file position [in 16 bits words !!!] */
3090       }
3091     else
3092       {
3093 	  /* updates the shapefile main MBR-BBOX */
3094 	  gaiaMbrGeometry (entity->Geometry);
3095 	  if (entity->Geometry->MinX < shp->MinX)
3096 	      shp->MinX = entity->Geometry->MinX;
3097 	  if (entity->Geometry->MaxX > shp->MaxX)
3098 	      shp->MaxX = entity->Geometry->MaxX;
3099 	  if (entity->Geometry->MinY < shp->MinY)
3100 	      shp->MinY = entity->Geometry->MinY;
3101 	  if (entity->Geometry->MaxY > shp->MaxY)
3102 	      shp->MaxY = entity->Geometry->MaxY;
3103 	  if (shp->Shape == GAIA_SHP_POINT)
3104 	    {
3105 		/* this one is expected to be a POINT */
3106 		gaiaPointPtr pt = entity->Geometry->FirstPoint;
3107 		if (!pt)
3108 		  {
3109 		      strcpy (dummy,
3110 			      "a POINT is expected, but there is no POINT in geometry");
3111 		      if (shp->LastError)
3112 			  free (shp->LastError);
3113 		      len = strlen (dummy);
3114 		      shp->LastError = malloc (len + 1);
3115 		      strcpy (shp->LastError, dummy);
3116 		      return 0;
3117 		  }
3118 		/* inserting POINT entity into SHX file */
3119 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3120 		gaiaExport32 (shp->BufShp + 4, 10, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3121 		fwrite (shp->BufShp, 1, 8, shp->flShx);
3122 		(shp->ShxSize) += 4;	/* updating current SHX file position [in 16 bits words !!!] */
3123 		/* inserting POINT into SHP file */
3124 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3125 		gaiaExport32 (shp->BufShp + 4, 10, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3126 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POINT, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POINT */
3127 		gaiaExport64 (shp->BufShp + 12, pt->X, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports X coordinate */
3128 		gaiaExport64 (shp->BufShp + 20, pt->Y, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports Y coordinate */
3129 		fwrite (shp->BufShp, 1, 28, shp->flShp);
3130 		(shp->ShpSize) += 14;	/* updating current SHP file position [in 16 bits words !!!] */
3131 	    }
3132 	  if (shp->Shape == GAIA_SHP_POINTZ)
3133 	    {
3134 		/* this one is expected to be a POINT Z */
3135 		gaiaPointPtr pt = entity->Geometry->FirstPoint;
3136 		if (!pt)
3137 		  {
3138 		      strcpy (dummy,
3139 			      "a POINT is expected, but there is no POINT in geometry");
3140 		      if (shp->LastError)
3141 			  free (shp->LastError);
3142 		      len = strlen (dummy);
3143 		      shp->LastError = malloc (len + 1);
3144 		      strcpy (shp->LastError, dummy);
3145 		      return 0;
3146 		  }
3147 		/* inserting POINT Z entity into SHX file */
3148 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3149 		gaiaExport32 (shp->BufShp + 4, 18, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3150 		fwrite (shp->BufShp, 1, 8, shp->flShx);
3151 		(shp->ShxSize) += 4;	/* updating current SHX file position [in 16 bits words !!!] */
3152 		/* inserting POINT into SHP file */
3153 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3154 		gaiaExport32 (shp->BufShp + 4, 18, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3155 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POINTZ, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POINT Z */
3156 		gaiaExport64 (shp->BufShp + 12, pt->X, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports X coordinate */
3157 		gaiaExport64 (shp->BufShp + 20, pt->Y, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports Y coordinate */
3158 		gaiaExport64 (shp->BufShp + 28, pt->Z, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports Z coordinate */
3159 		gaiaExport64 (shp->BufShp + 36, pt->M, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports M coordinate */
3160 		fwrite (shp->BufShp, 1, 44, shp->flShp);
3161 		(shp->ShpSize) += 22;	/* updating current SHP file position [in 16 bits words !!!] */
3162 	    }
3163 	  if (shp->Shape == GAIA_SHP_POINTM)
3164 	    {
3165 		/* this one is expected to be a POINT M */
3166 		gaiaPointPtr pt = entity->Geometry->FirstPoint;
3167 		if (!pt)
3168 		  {
3169 		      strcpy (dummy,
3170 			      "a POINT is expected, but there is no POINT in geometry");
3171 		      if (shp->LastError)
3172 			  free (shp->LastError);
3173 		      len = strlen (dummy);
3174 		      shp->LastError = malloc (len + 1);
3175 		      strcpy (shp->LastError, dummy);
3176 		      return 0;
3177 		  }
3178 		/* inserting POINT entity into SHX file */
3179 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3180 		gaiaExport32 (shp->BufShp + 4, 14, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3181 		fwrite (shp->BufShp, 1, 8, shp->flShx);
3182 		(shp->ShxSize) += 4;	/* updating current SHX file position [in 16 bits words !!!] */
3183 		/* inserting POINT into SHP file */
3184 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3185 		gaiaExport32 (shp->BufShp + 4, 14, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3186 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POINTM, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POINT M */
3187 		gaiaExport64 (shp->BufShp + 12, pt->X, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports X coordinate */
3188 		gaiaExport64 (shp->BufShp + 20, pt->Y, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports Y coordinate */
3189 		gaiaExport64 (shp->BufShp + 28, pt->Y, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports M coordinate */
3190 		fwrite (shp->BufShp, 1, 36, shp->flShp);
3191 		(shp->ShpSize) += 18;	/* updating current SHP file position [in 16 bits words !!!] */
3192 	    }
3193 	  if (shp->Shape == GAIA_SHP_POLYLINE)
3194 	    {
3195 		/* this one is expected to be a LINESTRING / MULTILINESTRING */
3196 		gaiaLinestringPtr line;
3197 		tot_ln = 0;
3198 		tot_v = 0;
3199 		line = entity->Geometry->FirstLinestring;
3200 		while (line)
3201 		  {
3202 		      /* computes # lines and total # points */
3203 		      tot_v += line->Points;
3204 		      tot_ln++;
3205 		      line = line->Next;
3206 		  }
3207 		if (!tot_ln)
3208 		  {
3209 		      strcpy (dummy,
3210 			      "a LINESTRING is expected, but there is no LINESTRING in geometry");
3211 		      if (shp->LastError)
3212 			  free (shp->LastError);
3213 		      len = strlen (dummy);
3214 		      shp->LastError = malloc (len + 1);
3215 		      strcpy (shp->LastError, dummy);
3216 		      return 0;
3217 		  }
3218 		this_size = 22 + (2 * tot_ln) + (tot_v * 8);	/* size [in 16 bits words !!!] for this SHP entity */
3219 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
3220 		  {
3221 		      /* current buffer is too small; we need to allocate a bigger one */
3222 		      free (shp->BufShp);
3223 		      shp->ShpBfsz = (this_size * 2) + 1024;
3224 		      shp->BufShp = malloc (shp->ShpBfsz);
3225 		  }
3226 		/* inserting LINESTRING or MULTILINESTRING in SHX file */
3227 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3228 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3229 		fwrite (shp->BufShp, 1, 8, shp->flShx);
3230 		(shp->ShxSize) += 4;
3231 		/* inserting LINESTRING or MULTILINESTRING in SHP file */
3232 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3233 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3234 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POLYLINE, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POLYLINE */
3235 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
3236 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
3237 			      GAIA_LITTLE_ENDIAN, endian_arch);
3238 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
3239 			      GAIA_LITTLE_ENDIAN, endian_arch);
3240 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
3241 			      GAIA_LITTLE_ENDIAN, endian_arch);
3242 		gaiaExport32 (shp->BufShp + 44, tot_ln, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports # lines in this polyline */
3243 		gaiaExport32 (shp->BufShp + 48, tot_v, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
3244 		tot_v = 0;	/* resets points counter */
3245 		ix = 52;	/* sets current buffer offset */
3246 		line = entity->Geometry->FirstLinestring;
3247 		while (line)
3248 		  {
3249 		      /* exports start point index for each line */
3250 		      gaiaExport32 (shp->BufShp + ix, tot_v,
3251 				    GAIA_LITTLE_ENDIAN, endian_arch);
3252 		      tot_v += line->Points;
3253 		      ix += 4;
3254 		      line = line->Next;
3255 		  }
3256 		line = entity->Geometry->FirstLinestring;
3257 		while (line)
3258 		  {
3259 		      /* exports points for each line */
3260 		      for (iv = 0; iv < line->Points; iv++)
3261 			{
3262 			    /* exports a POINT [x,y] */
3263 			    if (line->DimensionModel == GAIA_XY_Z)
3264 			      {
3265 				  gaiaGetPointXYZ (line->Coords, iv, &x, &y,
3266 						   &z);
3267 			      }
3268 			    else if (line->DimensionModel == GAIA_XY_M)
3269 			      {
3270 				  gaiaGetPointXYM (line->Coords, iv, &x, &y,
3271 						   &m);
3272 			      }
3273 			    else if (line->DimensionModel == GAIA_XY_Z_M)
3274 			      {
3275 				  gaiaGetPointXYZM (line->Coords, iv, &x,
3276 						    &y, &z, &m);
3277 			      }
3278 			    else
3279 			      {
3280 				  gaiaGetPoint (line->Coords, iv, &x, &y);
3281 			      }
3282 			    gaiaExport64 (shp->BufShp + ix, x,
3283 					  GAIA_LITTLE_ENDIAN, endian_arch);
3284 			    ix += 8;
3285 			    gaiaExport64 (shp->BufShp + ix, y,
3286 					  GAIA_LITTLE_ENDIAN, endian_arch);
3287 			    ix += 8;
3288 			}
3289 		      line = line->Next;
3290 		  }
3291 		fwrite (shp->BufShp, 1, ix, shp->flShp);
3292 		(shp->ShpSize) += (ix / 2);	/* updating current SHP file position [in 16 bits words !!!] */
3293 	    }
3294 	  if (shp->Shape == GAIA_SHP_POLYLINEZ)
3295 	    {
3296 		/* this one is expected to be a LINESTRING / MULTILINESTRING Z */
3297 		gaiaLinestringPtr line;
3298 		gaiaZRangeGeometry (entity->Geometry, &minZ, &maxZ);
3299 		gaiaMRangeGeometry (entity->Geometry, &minM, &maxM);
3300 		tot_ln = 0;
3301 		tot_v = 0;
3302 		line = entity->Geometry->FirstLinestring;
3303 		while (line)
3304 		  {
3305 		      /* computes # lines and total # points */
3306 		      tot_v += line->Points;
3307 		      tot_ln++;
3308 		      line = line->Next;
3309 		  }
3310 		if (!tot_ln)
3311 		  {
3312 		      strcpy (dummy,
3313 			      "a LINESTRING is expected, but there is no LINESTRING in geometry");
3314 		      if (shp->LastError)
3315 			  free (shp->LastError);
3316 		      len = strlen (dummy);
3317 		      shp->LastError = malloc (len + 1);
3318 		      strcpy (shp->LastError, dummy);
3319 		      return 0;
3320 		  }
3321 		hasM = 0;
3322 		if (shp->EffectiveDims == GAIA_XY_M
3323 		    || shp->EffectiveDims == GAIA_XY_Z_M)
3324 		    hasM = 1;
3325 		if (hasM)
3326 		    this_size = 38 + (2 * tot_ln) + (tot_v * 16);	/* size [in 16 bits words !!!] ZM */
3327 		else
3328 		    this_size = 30 + (2 * tot_ln) + (tot_v * 12);	/* size [in 16 bits words !!!] Z-only */
3329 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
3330 		  {
3331 		      /* current buffer is too small; we need to allocate a bigger one */
3332 		      free (shp->BufShp);
3333 		      shp->ShpBfsz = (this_size * 2) + 1024;
3334 		      shp->BufShp = malloc (shp->ShpBfsz);
3335 		  }
3336 		/* inserting LINESTRING or MULTILINESTRING in SHX file */
3337 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3338 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3339 		fwrite (shp->BufShp, 1, 8, shp->flShx);
3340 		(shp->ShxSize) += 4;
3341 		/* inserting LINESTRING or MULTILINESTRING in SHP file */
3342 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3343 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3344 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POLYLINEZ, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POLYLINE Z */
3345 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
3346 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
3347 			      GAIA_LITTLE_ENDIAN, endian_arch);
3348 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
3349 			      GAIA_LITTLE_ENDIAN, endian_arch);
3350 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
3351 			      GAIA_LITTLE_ENDIAN, endian_arch);
3352 		gaiaExport32 (shp->BufShp + 44, tot_ln, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports # lines in this polyline */
3353 		gaiaExport32 (shp->BufShp + 48, tot_v, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
3354 		tot_v = 0;	/* resets points counter */
3355 		ix = 52;	/* sets current buffer offset */
3356 		line = entity->Geometry->FirstLinestring;
3357 		while (line)
3358 		  {
3359 		      /* exports start point index for each line */
3360 		      gaiaExport32 (shp->BufShp + ix, tot_v,
3361 				    GAIA_LITTLE_ENDIAN, endian_arch);
3362 		      tot_v += line->Points;
3363 		      ix += 4;
3364 		      line = line->Next;
3365 		  }
3366 		line = entity->Geometry->FirstLinestring;
3367 		while (line)
3368 		  {
3369 		      /* exports points for each line */
3370 		      for (iv = 0; iv < line->Points; iv++)
3371 			{
3372 			    /* exports a POINT [x,y] */
3373 			    if (line->DimensionModel == GAIA_XY_Z)
3374 			      {
3375 				  gaiaGetPointXYZ (line->Coords, iv, &x, &y,
3376 						   &z);
3377 			      }
3378 			    else if (line->DimensionModel == GAIA_XY_M)
3379 			      {
3380 				  gaiaGetPointXYM (line->Coords, iv, &x, &y,
3381 						   &m);
3382 			      }
3383 			    else if (line->DimensionModel == GAIA_XY_Z_M)
3384 			      {
3385 				  gaiaGetPointXYZM (line->Coords, iv, &x,
3386 						    &y, &z, &m);
3387 			      }
3388 			    else
3389 			      {
3390 				  gaiaGetPoint (line->Coords, iv, &x, &y);
3391 			      }
3392 			    gaiaExport64 (shp->BufShp + ix, x,
3393 					  GAIA_LITTLE_ENDIAN, endian_arch);
3394 			    ix += 8;
3395 			    gaiaExport64 (shp->BufShp + ix, y,
3396 					  GAIA_LITTLE_ENDIAN, endian_arch);
3397 			    ix += 8;
3398 			}
3399 		      line = line->Next;
3400 		  }
3401 		/* exporting the Z-range [min/max] */
3402 		gaiaExport64 (shp->BufShp + ix, minZ, GAIA_LITTLE_ENDIAN,
3403 			      endian_arch);
3404 		ix += 8;
3405 		gaiaExport64 (shp->BufShp + ix, maxZ, GAIA_LITTLE_ENDIAN,
3406 			      endian_arch);
3407 		ix += 8;
3408 		line = entity->Geometry->FirstLinestring;
3409 		while (line)
3410 		  {
3411 		      /* exports Z-values for each line */
3412 		      for (iv = 0; iv < line->Points; iv++)
3413 			{
3414 			    /* exports Z-value */
3415 			    z = 0.0;
3416 			    if (line->DimensionModel == GAIA_XY_Z)
3417 			      {
3418 				  gaiaGetPointXYZ (line->Coords, iv, &x, &y,
3419 						   &z);
3420 			      }
3421 			    else if (line->DimensionModel == GAIA_XY_M)
3422 			      {
3423 				  gaiaGetPointXYM (line->Coords, iv, &x, &y,
3424 						   &m);
3425 			      }
3426 			    else if (line->DimensionModel == GAIA_XY_Z_M)
3427 			      {
3428 				  gaiaGetPointXYZM (line->Coords, iv, &x,
3429 						    &y, &z, &m);
3430 			      }
3431 			    else
3432 			      {
3433 				  gaiaGetPoint (line->Coords, iv, &x, &y);
3434 			      }
3435 			    gaiaExport64 (shp->BufShp + ix, z,
3436 					  GAIA_LITTLE_ENDIAN, endian_arch);
3437 			    ix += 8;
3438 			}
3439 		      line = line->Next;
3440 		  }
3441 		if (hasM)
3442 		  {
3443 		      /* exporting the M-range [min/max] */
3444 		      gaiaExport64 (shp->BufShp + ix, minM,
3445 				    GAIA_LITTLE_ENDIAN, endian_arch);
3446 		      ix += 8;
3447 		      gaiaExport64 (shp->BufShp + ix, maxM,
3448 				    GAIA_LITTLE_ENDIAN, endian_arch);
3449 		      ix += 8;
3450 		      line = entity->Geometry->FirstLinestring;
3451 		      while (line)
3452 			{
3453 			    /* exports M-values for each line */
3454 			    for (iv = 0; iv < line->Points; iv++)
3455 			      {
3456 				  /* exports M-value */
3457 				  m = 0.0;
3458 				  if (line->DimensionModel == GAIA_XY_Z)
3459 				    {
3460 					gaiaGetPointXYZ (line->Coords, iv,
3461 							 &x, &y, &z);
3462 				    }
3463 				  else if (line->DimensionModel == GAIA_XY_M)
3464 				    {
3465 					gaiaGetPointXYM (line->Coords, iv,
3466 							 &x, &y, &m);
3467 				    }
3468 				  else if (line->DimensionModel == GAIA_XY_Z_M)
3469 				    {
3470 					gaiaGetPointXYZM (line->Coords, iv,
3471 							  &x, &y, &z, &m);
3472 				    }
3473 				  else
3474 				    {
3475 					gaiaGetPoint (line->Coords, iv, &x, &y);
3476 				    }
3477 				  gaiaExport64 (shp->BufShp + ix, m,
3478 						GAIA_LITTLE_ENDIAN,
3479 						endian_arch);
3480 				  ix += 8;
3481 			      }
3482 			    line = line->Next;
3483 			}
3484 		  }
3485 		fwrite (shp->BufShp, 1, ix, shp->flShp);
3486 		(shp->ShpSize) += (ix / 2);	/* updating current SHP file position [in 16 bits words !!!] */
3487 	    }
3488 	  if (shp->Shape == GAIA_SHP_POLYLINEM)
3489 	    {
3490 		/* this one is expected to be a LINESTRING / MULTILINESTRING M */
3491 		gaiaLinestringPtr line;
3492 		gaiaMRangeGeometry (entity->Geometry, &minM, &maxM);
3493 		tot_ln = 0;
3494 		tot_v = 0;
3495 		line = entity->Geometry->FirstLinestring;
3496 		while (line)
3497 		  {
3498 		      /* computes # lines and total # points */
3499 		      tot_v += line->Points;
3500 		      tot_ln++;
3501 		      line = line->Next;
3502 		  }
3503 		if (!tot_ln)
3504 		  {
3505 		      strcpy (dummy,
3506 			      "a LINESTRING is expected, but there is no LINESTRING in geometry");
3507 		      if (shp->LastError)
3508 			  free (shp->LastError);
3509 		      len = strlen (dummy);
3510 		      shp->LastError = malloc (len + 1);
3511 		      strcpy (shp->LastError, dummy);
3512 		      return 0;
3513 		  }
3514 		this_size = 30 + (2 * tot_ln) + (tot_v * 12);	/* size [in 16 bits words !!!] for this SHP entity */
3515 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
3516 		  {
3517 		      /* current buffer is too small; we need to allocate a bigger one */
3518 		      free (shp->BufShp);
3519 		      shp->ShpBfsz = (this_size * 2) + 1024;
3520 		      shp->BufShp = malloc (shp->ShpBfsz);
3521 		  }
3522 		/* inserting LINESTRING or MULTILINESTRING in SHX file */
3523 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3524 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3525 		fwrite (shp->BufShp, 1, 8, shp->flShx);
3526 		(shp->ShxSize) += 4;
3527 		/* inserting LINESTRING or MULTILINESTRING in SHP file */
3528 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3529 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3530 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POLYLINEM, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POLYLINE M */
3531 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
3532 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
3533 			      GAIA_LITTLE_ENDIAN, endian_arch);
3534 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
3535 			      GAIA_LITTLE_ENDIAN, endian_arch);
3536 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
3537 			      GAIA_LITTLE_ENDIAN, endian_arch);
3538 		gaiaExport32 (shp->BufShp + 44, tot_ln, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports # lines in this polyline */
3539 		gaiaExport32 (shp->BufShp + 48, tot_v, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
3540 		tot_v = 0;	/* resets points counter */
3541 		ix = 52;	/* sets current buffer offset */
3542 		line = entity->Geometry->FirstLinestring;
3543 		while (line)
3544 		  {
3545 		      /* exports start point index for each line */
3546 		      gaiaExport32 (shp->BufShp + ix, tot_v,
3547 				    GAIA_LITTLE_ENDIAN, endian_arch);
3548 		      tot_v += line->Points;
3549 		      ix += 4;
3550 		      line = line->Next;
3551 		  }
3552 		line = entity->Geometry->FirstLinestring;
3553 		while (line)
3554 		  {
3555 		      /* exports points for each line */
3556 		      for (iv = 0; iv < line->Points; iv++)
3557 			{
3558 			    /* exports a POINT [x,y] */
3559 			    if (line->DimensionModel == GAIA_XY_Z)
3560 			      {
3561 				  gaiaGetPointXYZ (line->Coords, iv, &x, &y,
3562 						   &z);
3563 			      }
3564 			    else if (line->DimensionModel == GAIA_XY_M)
3565 			      {
3566 				  gaiaGetPointXYM (line->Coords, iv, &x, &y,
3567 						   &m);
3568 			      }
3569 			    else if (line->DimensionModel == GAIA_XY_Z_M)
3570 			      {
3571 				  gaiaGetPointXYZM (line->Coords, iv, &x,
3572 						    &y, &z, &m);
3573 			      }
3574 			    else
3575 			      {
3576 				  gaiaGetPoint (line->Coords, iv, &x, &y);
3577 			      }
3578 			    gaiaExport64 (shp->BufShp + ix, x,
3579 					  GAIA_LITTLE_ENDIAN, endian_arch);
3580 			    ix += 8;
3581 			    gaiaExport64 (shp->BufShp + ix, y,
3582 					  GAIA_LITTLE_ENDIAN, endian_arch);
3583 			    ix += 8;
3584 			}
3585 		      line = line->Next;
3586 		  }
3587 		/* exporting the M-range [min/max] */
3588 		gaiaExport64 (shp->BufShp + ix, minM, GAIA_LITTLE_ENDIAN,
3589 			      endian_arch);
3590 		ix += 8;
3591 		gaiaExport64 (shp->BufShp + ix, maxM, GAIA_LITTLE_ENDIAN,
3592 			      endian_arch);
3593 		ix += 8;
3594 		line = entity->Geometry->FirstLinestring;
3595 		while (line)
3596 		  {
3597 		      /* exports M-values for each line */
3598 		      for (iv = 0; iv < line->Points; iv++)
3599 			{
3600 			    /* exports M-value */
3601 			    m = 0.0;
3602 			    if (line->DimensionModel == GAIA_XY_Z)
3603 			      {
3604 				  gaiaGetPointXYZ (line->Coords, iv, &x, &y,
3605 						   &z);
3606 			      }
3607 			    else if (line->DimensionModel == GAIA_XY_M)
3608 			      {
3609 				  gaiaGetPointXYM (line->Coords, iv, &x, &y,
3610 						   &m);
3611 			      }
3612 			    else if (line->DimensionModel == GAIA_XY_Z_M)
3613 			      {
3614 				  gaiaGetPointXYZM (line->Coords, iv, &x,
3615 						    &y, &z, &m);
3616 			      }
3617 			    else
3618 			      {
3619 				  gaiaGetPoint (line->Coords, iv, &x, &y);
3620 			      }
3621 			    gaiaExport64 (shp->BufShp + ix, m,
3622 					  GAIA_LITTLE_ENDIAN, endian_arch);
3623 			    ix += 8;
3624 			}
3625 		      line = line->Next;
3626 		  }
3627 		fwrite (shp->BufShp, 1, ix, shp->flShp);
3628 		(shp->ShpSize) += (ix / 2);	/* updating current SHP file position [in 16 bits words !!!] */
3629 	    }
3630 	  if (shp->Shape == GAIA_SHP_POLYGON)
3631 	    {
3632 		/* this one is expected to be a POLYGON or a MULTIPOLYGON */
3633 		gaiaPolygonPtr polyg;
3634 		gaiaRingPtr ring;
3635 		int ib;
3636 		tot_ln = 0;
3637 		tot_v = 0;
3638 		polyg = entity->Geometry->FirstPolygon;
3639 		while (polyg)
3640 		  {
3641 		      /* computes # rings and total # points */
3642 		      gaiaSaneClockwise (polyg);	/* we must assure that exterior ring is clockwise, and interior rings are anti-clockwise */
3643 		      ring = polyg->Exterior;	/* this one is the exterior ring */
3644 		      tot_v += ring->Points;
3645 		      tot_ln++;
3646 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
3647 			{
3648 			    /* that ones are the interior rings */
3649 			    ring = polyg->Interiors + ib;
3650 			    tot_v += ring->Points;
3651 			    tot_ln++;
3652 			}
3653 		      polyg = polyg->Next;
3654 		  }
3655 		if (!tot_ln)
3656 		  {
3657 		      strcpy (dummy,
3658 			      "a POLYGON is expected, but there is no POLYGON in geometry");
3659 		      if (shp->LastError)
3660 			  free (shp->LastError);
3661 		      len = strlen (dummy);
3662 		      shp->LastError = malloc (len + 1);
3663 		      strcpy (shp->LastError, dummy);
3664 		      return 0;
3665 		  }
3666 		this_size = 22 + (2 * tot_ln) + (tot_v * 8);	/* size [in 16 bits words !!!] for this SHP entity */
3667 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
3668 		  {
3669 		      /* current buffer is too small; we need to allocate a bigger one */
3670 		      free (shp->BufShp);
3671 		      shp->ShpBfsz = (this_size * 2) + 1024;
3672 		      shp->BufShp = malloc (shp->ShpBfsz);
3673 		  }
3674 		/* inserting POLYGON or MULTIPOLYGON in SHX file */
3675 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3676 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3677 		fwrite (shp->BufShp, 1, 8, shp->flShx);
3678 		(shp->ShxSize) += 4;
3679 		/* inserting POLYGON or MULTIPOLYGON in SHP file */
3680 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3681 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3682 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POLYGON, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POLYGON */
3683 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
3684 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
3685 			      GAIA_LITTLE_ENDIAN, endian_arch);
3686 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
3687 			      GAIA_LITTLE_ENDIAN, endian_arch);
3688 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
3689 			      GAIA_LITTLE_ENDIAN, endian_arch);
3690 		gaiaExport32 (shp->BufShp + 44, tot_ln, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports # rings in this polygon */
3691 		gaiaExport32 (shp->BufShp + 48, tot_v, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
3692 		tot_v = 0;	/* resets points counter */
3693 		ix = 52;	/* sets current buffer offset */
3694 		polyg = entity->Geometry->FirstPolygon;
3695 		while (polyg)
3696 		  {
3697 		      /* exports start point index for each line */
3698 		      ring = polyg->Exterior;	/* this one is the exterior ring */
3699 		      gaiaExport32 (shp->BufShp + ix, tot_v,
3700 				    GAIA_LITTLE_ENDIAN, endian_arch);
3701 		      tot_v += ring->Points;
3702 		      ix += 4;
3703 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
3704 			{
3705 			    /* that ones are the interior rings */
3706 			    ring = polyg->Interiors + ib;
3707 			    gaiaExport32 (shp->BufShp + ix, tot_v,
3708 					  GAIA_LITTLE_ENDIAN, endian_arch);
3709 			    tot_v += ring->Points;
3710 			    ix += 4;
3711 			}
3712 		      polyg = polyg->Next;
3713 		  }
3714 		polyg = entity->Geometry->FirstPolygon;
3715 		while (polyg)
3716 		  {
3717 		      /* exports points for each ring */
3718 		      ring = polyg->Exterior;	/* this one is the exterior ring */
3719 		      for (iv = 0; iv < ring->Points; iv++)
3720 			{
3721 			    /* exports a POINT [x,y] - exterior ring */
3722 			    if (ring->DimensionModel == GAIA_XY_Z)
3723 			      {
3724 				  gaiaGetPointXYZ (ring->Coords, iv, &x, &y,
3725 						   &z);
3726 			      }
3727 			    else if (ring->DimensionModel == GAIA_XY_M)
3728 			      {
3729 				  gaiaGetPointXYM (ring->Coords, iv, &x, &y,
3730 						   &m);
3731 			      }
3732 			    else if (ring->DimensionModel == GAIA_XY_Z_M)
3733 			      {
3734 				  gaiaGetPointXYZM (ring->Coords, iv, &x,
3735 						    &y, &z, &m);
3736 			      }
3737 			    else
3738 			      {
3739 				  gaiaGetPoint (ring->Coords, iv, &x, &y);
3740 			      }
3741 			    gaiaExport64 (shp->BufShp + ix, x,
3742 					  GAIA_LITTLE_ENDIAN, endian_arch);
3743 			    ix += 8;
3744 			    gaiaExport64 (shp->BufShp + ix, y,
3745 					  GAIA_LITTLE_ENDIAN, endian_arch);
3746 			    ix += 8;
3747 			}
3748 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
3749 			{
3750 			    /* that ones are the interior rings */
3751 			    ring = polyg->Interiors + ib;
3752 			    for (iv = 0; iv < ring->Points; iv++)
3753 			      {
3754 				  /* exports a POINT [x,y] - interior ring */
3755 				  if (ring->DimensionModel == GAIA_XY_Z)
3756 				    {
3757 					gaiaGetPointXYZ (ring->Coords, iv,
3758 							 &x, &y, &z);
3759 				    }
3760 				  else if (ring->DimensionModel == GAIA_XY_M)
3761 				    {
3762 					gaiaGetPointXYM (ring->Coords, iv,
3763 							 &x, &y, &m);
3764 				    }
3765 				  else if (ring->DimensionModel == GAIA_XY_Z_M)
3766 				    {
3767 					gaiaGetPointXYZM (ring->Coords, iv,
3768 							  &x, &y, &z, &m);
3769 				    }
3770 				  else
3771 				    {
3772 					gaiaGetPoint (ring->Coords, iv, &x, &y);
3773 				    }
3774 				  gaiaExport64 (shp->BufShp + ix, x,
3775 						GAIA_LITTLE_ENDIAN,
3776 						endian_arch);
3777 				  ix += 8;
3778 				  gaiaExport64 (shp->BufShp + ix, y,
3779 						GAIA_LITTLE_ENDIAN,
3780 						endian_arch);
3781 				  ix += 8;
3782 			      }
3783 			}
3784 		      polyg = polyg->Next;
3785 		  }
3786 		fwrite (shp->BufShp, 1, ix, shp->flShp);
3787 		(shp->ShpSize) += (ix / 2);
3788 	    }
3789 	  if (shp->Shape == GAIA_SHP_POLYGONZ)
3790 	    {
3791 		/* this one is expected to be a POLYGON or a MULTIPOLYGON Z */
3792 		gaiaPolygonPtr polyg;
3793 		gaiaRingPtr ring;
3794 		int ib;
3795 		gaiaZRangeGeometry (entity->Geometry, &minZ, &maxZ);
3796 		gaiaMRangeGeometry (entity->Geometry, &minM, &maxM);
3797 		tot_ln = 0;
3798 		tot_v = 0;
3799 		polyg = entity->Geometry->FirstPolygon;
3800 		while (polyg)
3801 		  {
3802 		      /* computes # rings and total # points */
3803 		      gaiaSaneClockwise (polyg);	/* we must assure that exterior ring is clockwise, and interior rings are anti-clockwise */
3804 		      ring = polyg->Exterior;	/* this one is the exterior ring */
3805 		      tot_v += ring->Points;
3806 		      tot_ln++;
3807 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
3808 			{
3809 			    /* that ones are the interior rings */
3810 			    ring = polyg->Interiors + ib;
3811 			    tot_v += ring->Points;
3812 			    tot_ln++;
3813 			}
3814 		      polyg = polyg->Next;
3815 		  }
3816 		if (!tot_ln)
3817 		  {
3818 		      strcpy (dummy,
3819 			      "a POLYGON is expected, but there is no POLYGON in geometry");
3820 		      if (shp->LastError)
3821 			  free (shp->LastError);
3822 		      len = strlen (dummy);
3823 		      shp->LastError = malloc (len + 1);
3824 		      strcpy (shp->LastError, dummy);
3825 		      return 0;
3826 		  }
3827 		hasM = 0;
3828 		if (shp->EffectiveDims == GAIA_XY_M
3829 		    || shp->EffectiveDims == GAIA_XY_Z_M)
3830 		    hasM = 1;
3831 		if (hasM)
3832 		    this_size = 38 + (2 * tot_ln) + (tot_v * 16);	/* size [in 16 bits words !!!] ZM */
3833 		else
3834 		    this_size = 30 + (2 * tot_ln) + (tot_v * 12);	/* size [in 16 bits words !!!] Z-only */
3835 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
3836 		  {
3837 		      /* current buffer is too small; we need to allocate a bigger one */
3838 		      free (shp->BufShp);
3839 		      shp->ShpBfsz = (this_size * 2) + 1024;
3840 		      shp->BufShp = malloc (shp->ShpBfsz);
3841 		  }
3842 		/* inserting POLYGON or MULTIPOLYGON in SHX file */
3843 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
3844 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
3845 		fwrite (shp->BufShp, 1, 8, shp->flShx);
3846 		(shp->ShxSize) += 4;
3847 		/* inserting POLYGON or MULTIPOLYGON in SHP file */
3848 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
3849 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
3850 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POLYGONZ, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POLYGON Z */
3851 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
3852 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
3853 			      GAIA_LITTLE_ENDIAN, endian_arch);
3854 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
3855 			      GAIA_LITTLE_ENDIAN, endian_arch);
3856 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
3857 			      GAIA_LITTLE_ENDIAN, endian_arch);
3858 		gaiaExport32 (shp->BufShp + 44, tot_ln, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports # rings in this polygon */
3859 		gaiaExport32 (shp->BufShp + 48, tot_v, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
3860 		tot_v = 0;	/* resets points counter */
3861 		ix = 52;	/* sets current buffer offset */
3862 		polyg = entity->Geometry->FirstPolygon;
3863 		while (polyg)
3864 		  {
3865 		      /* exports start point index for each line */
3866 		      ring = polyg->Exterior;	/* this one is the exterior ring */
3867 		      gaiaExport32 (shp->BufShp + ix, tot_v,
3868 				    GAIA_LITTLE_ENDIAN, endian_arch);
3869 		      tot_v += ring->Points;
3870 		      ix += 4;
3871 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
3872 			{
3873 			    /* that ones are the interior rings */
3874 			    ring = polyg->Interiors + ib;
3875 			    gaiaExport32 (shp->BufShp + ix, tot_v,
3876 					  GAIA_LITTLE_ENDIAN, endian_arch);
3877 			    tot_v += ring->Points;
3878 			    ix += 4;
3879 			}
3880 		      polyg = polyg->Next;
3881 		  }
3882 		polyg = entity->Geometry->FirstPolygon;
3883 		while (polyg)
3884 		  {
3885 		      /* exports points for each ring */
3886 		      ring = polyg->Exterior;	/* this one is the exterior ring */
3887 		      for (iv = 0; iv < ring->Points; iv++)
3888 			{
3889 			    /* exports a POINT [x,y] - exterior ring */
3890 			    if (ring->DimensionModel == GAIA_XY_Z)
3891 			      {
3892 				  gaiaGetPointXYZ (ring->Coords, iv, &x, &y,
3893 						   &z);
3894 			      }
3895 			    else if (ring->DimensionModel == GAIA_XY_M)
3896 			      {
3897 				  gaiaGetPointXYM (ring->Coords, iv, &x, &y,
3898 						   &m);
3899 			      }
3900 			    else if (ring->DimensionModel == GAIA_XY_Z_M)
3901 			      {
3902 				  gaiaGetPointXYZM (ring->Coords, iv, &x,
3903 						    &y, &z, &m);
3904 			      }
3905 			    else
3906 			      {
3907 				  gaiaGetPoint (ring->Coords, iv, &x, &y);
3908 			      }
3909 			    gaiaExport64 (shp->BufShp + ix, x,
3910 					  GAIA_LITTLE_ENDIAN, endian_arch);
3911 			    ix += 8;
3912 			    gaiaExport64 (shp->BufShp + ix, y,
3913 					  GAIA_LITTLE_ENDIAN, endian_arch);
3914 			    ix += 8;
3915 			}
3916 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
3917 			{
3918 			    /* that ones are the interior rings */
3919 			    ring = polyg->Interiors + ib;
3920 			    for (iv = 0; iv < ring->Points; iv++)
3921 			      {
3922 				  /* exports a POINT [x,y] - interior ring */
3923 				  if (ring->DimensionModel == GAIA_XY_Z)
3924 				    {
3925 					gaiaGetPointXYZ (ring->Coords, iv,
3926 							 &x, &y, &z);
3927 				    }
3928 				  else if (ring->DimensionModel == GAIA_XY_M)
3929 				    {
3930 					gaiaGetPointXYM (ring->Coords, iv,
3931 							 &x, &y, &m);
3932 				    }
3933 				  else if (ring->DimensionModel == GAIA_XY_Z_M)
3934 				    {
3935 					gaiaGetPointXYZM (ring->Coords, iv,
3936 							  &x, &y, &z, &m);
3937 				    }
3938 				  else
3939 				    {
3940 					gaiaGetPoint (ring->Coords, iv, &x, &y);
3941 				    }
3942 				  gaiaExport64 (shp->BufShp + ix, x,
3943 						GAIA_LITTLE_ENDIAN,
3944 						endian_arch);
3945 				  ix += 8;
3946 				  gaiaExport64 (shp->BufShp + ix, y,
3947 						GAIA_LITTLE_ENDIAN,
3948 						endian_arch);
3949 				  ix += 8;
3950 			      }
3951 			}
3952 		      polyg = polyg->Next;
3953 		  }
3954 		/* exporting the Z-range [min/max] */
3955 		gaiaExport64 (shp->BufShp + ix, minZ, GAIA_LITTLE_ENDIAN,
3956 			      endian_arch);
3957 		ix += 8;
3958 		gaiaExport64 (shp->BufShp + ix, maxZ, GAIA_LITTLE_ENDIAN,
3959 			      endian_arch);
3960 		ix += 8;
3961 		polyg = entity->Geometry->FirstPolygon;
3962 		while (polyg)
3963 		  {
3964 		      /* exports Z-values for each ring */
3965 		      ring = polyg->Exterior;	/* this one is the exterior ring */
3966 		      for (iv = 0; iv < ring->Points; iv++)
3967 			{
3968 			    /* exports Z-values - exterior ring */
3969 			    z = 0.0;
3970 			    if (ring->DimensionModel == GAIA_XY_Z)
3971 			      {
3972 				  gaiaGetPointXYZ (ring->Coords, iv, &x, &y,
3973 						   &z);
3974 			      }
3975 			    else if (ring->DimensionModel == GAIA_XY_M)
3976 			      {
3977 				  gaiaGetPointXYM (ring->Coords, iv, &x, &y,
3978 						   &m);
3979 			      }
3980 			    else if (ring->DimensionModel == GAIA_XY_Z_M)
3981 			      {
3982 				  gaiaGetPointXYZM (ring->Coords, iv, &x,
3983 						    &y, &z, &m);
3984 			      }
3985 			    else
3986 			      {
3987 				  gaiaGetPoint (ring->Coords, iv, &x, &y);
3988 			      }
3989 			    gaiaExport64 (shp->BufShp + ix, z,
3990 					  GAIA_LITTLE_ENDIAN, endian_arch);
3991 			    ix += 8;
3992 			}
3993 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
3994 			{
3995 			    /* that ones are the interior rings */
3996 			    ring = polyg->Interiors + ib;
3997 			    for (iv = 0; iv < ring->Points; iv++)
3998 			      {
3999 				  /* exports Z-values - interior ring */
4000 				  z = 0.0;
4001 				  if (ring->DimensionModel == GAIA_XY_Z)
4002 				    {
4003 					gaiaGetPointXYZ (ring->Coords, iv,
4004 							 &x, &y, &z);
4005 				    }
4006 				  else if (ring->DimensionModel == GAIA_XY_M)
4007 				    {
4008 					gaiaGetPointXYM (ring->Coords, iv,
4009 							 &x, &y, &m);
4010 				    }
4011 				  else if (ring->DimensionModel == GAIA_XY_Z_M)
4012 				    {
4013 					gaiaGetPointXYZM (ring->Coords, iv,
4014 							  &x, &y, &z, &m);
4015 				    }
4016 				  else
4017 				    {
4018 					gaiaGetPoint (ring->Coords, iv, &x, &y);
4019 				    }
4020 				  gaiaExport64 (shp->BufShp + ix, z,
4021 						GAIA_LITTLE_ENDIAN,
4022 						endian_arch);
4023 				  ix += 8;
4024 			      }
4025 			}
4026 		      polyg = polyg->Next;
4027 		  }
4028 		if (hasM)
4029 		  {
4030 		      /* exporting the M-range [min/max] */
4031 		      gaiaExport64 (shp->BufShp + ix, minM,
4032 				    GAIA_LITTLE_ENDIAN, endian_arch);
4033 		      ix += 8;
4034 		      gaiaExport64 (shp->BufShp + ix, maxM,
4035 				    GAIA_LITTLE_ENDIAN, endian_arch);
4036 		      ix += 8;
4037 		      polyg = entity->Geometry->FirstPolygon;
4038 		      while (polyg)
4039 			{
4040 			    /* exports M-values for each ring */
4041 			    ring = polyg->Exterior;	/* this one is the exterior ring */
4042 			    for (iv = 0; iv < ring->Points; iv++)
4043 			      {
4044 				  /* exports M-values - exterior ring */
4045 				  m = 0.0;
4046 				  if (ring->DimensionModel == GAIA_XY_Z)
4047 				    {
4048 					gaiaGetPointXYZ (ring->Coords, iv,
4049 							 &x, &y, &z);
4050 				    }
4051 				  else if (ring->DimensionModel == GAIA_XY_M)
4052 				    {
4053 					gaiaGetPointXYM (ring->Coords, iv,
4054 							 &x, &y, &m);
4055 				    }
4056 				  else if (ring->DimensionModel == GAIA_XY_Z_M)
4057 				    {
4058 					gaiaGetPointXYZM (ring->Coords, iv,
4059 							  &x, &y, &z, &m);
4060 				    }
4061 				  else
4062 				    {
4063 					gaiaGetPoint (ring->Coords, iv, &x, &y);
4064 				    }
4065 				  gaiaExport64 (shp->BufShp + ix, m,
4066 						GAIA_LITTLE_ENDIAN,
4067 						endian_arch);
4068 				  ix += 8;
4069 			      }
4070 			    for (ib = 0; ib < polyg->NumInteriors; ib++)
4071 			      {
4072 				  /* that ones are the interior rings */
4073 				  ring = polyg->Interiors + ib;
4074 				  for (iv = 0; iv < ring->Points; iv++)
4075 				    {
4076 					/* exports M-values - interior ring */
4077 					m = 0.0;
4078 					if (ring->DimensionModel == GAIA_XY_Z)
4079 					  {
4080 					      gaiaGetPointXYZ (ring->Coords,
4081 							       iv, &x, &y, &z);
4082 					  }
4083 					else if (ring->DimensionModel ==
4084 						 GAIA_XY_M)
4085 					  {
4086 					      gaiaGetPointXYM (ring->Coords,
4087 							       iv, &x, &y, &m);
4088 					  }
4089 					else if (ring->DimensionModel ==
4090 						 GAIA_XY_Z_M)
4091 					  {
4092 					      gaiaGetPointXYZM (ring->Coords,
4093 								iv, &x, &y, &z,
4094 								&m);
4095 					  }
4096 					else
4097 					  {
4098 					      gaiaGetPoint (ring->Coords,
4099 							    iv, &x, &y);
4100 					  }
4101 					gaiaExport64 (shp->BufShp + ix, m,
4102 						      GAIA_LITTLE_ENDIAN,
4103 						      endian_arch);
4104 					ix += 8;
4105 				    }
4106 			      }
4107 			    polyg = polyg->Next;
4108 			}
4109 		  }
4110 		fwrite (shp->BufShp, 1, ix, shp->flShp);
4111 		(shp->ShpSize) += (ix / 2);
4112 	    }
4113 	  if (shp->Shape == GAIA_SHP_POLYGONM)
4114 	    {
4115 		/* this one is expected to be a POLYGON or a MULTIPOLYGON M */
4116 		gaiaPolygonPtr polyg;
4117 		gaiaRingPtr ring;
4118 		int ib;
4119 		gaiaMRangeGeometry (entity->Geometry, &minM, &maxM);
4120 		tot_ln = 0;
4121 		tot_v = 0;
4122 		polyg = entity->Geometry->FirstPolygon;
4123 		while (polyg)
4124 		  {
4125 		      /* computes # rings and total # points */
4126 		      gaiaSaneClockwise (polyg);	/* we must assure that exterior ring is clockwise, and interior rings are anti-clockwise */
4127 		      ring = polyg->Exterior;	/* this one is the exterior ring */
4128 		      tot_v += ring->Points;
4129 		      tot_ln++;
4130 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
4131 			{
4132 			    /* that ones are the interior rings */
4133 			    ring = polyg->Interiors + ib;
4134 			    tot_v += ring->Points;
4135 			    tot_ln++;
4136 			}
4137 		      polyg = polyg->Next;
4138 		  }
4139 		if (!tot_ln)
4140 		  {
4141 		      strcpy (dummy,
4142 			      "a POLYGON is expected, but there is no POLYGON in geometry");
4143 		      if (shp->LastError)
4144 			  free (shp->LastError);
4145 		      len = strlen (dummy);
4146 		      shp->LastError = malloc (len + 1);
4147 		      strcpy (shp->LastError, dummy);
4148 		      return 0;
4149 		  }
4150 		this_size = 30 + (2 * tot_ln) + (tot_v * 12);	/* size [in 16 bits words !!!] for this SHP entity */
4151 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
4152 		  {
4153 		      /* current buffer is too small; we need to allocate a bigger one */
4154 		      free (shp->BufShp);
4155 		      shp->ShpBfsz = (this_size * 2) + 1024;
4156 		      shp->BufShp = malloc (shp->ShpBfsz);
4157 		  }
4158 		/* inserting POLYGON or MULTIPOLYGON in SHX file */
4159 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
4160 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
4161 		fwrite (shp->BufShp, 1, 8, shp->flShx);
4162 		(shp->ShxSize) += 4;
4163 		/* inserting POLYGON or MULTIPOLYGON in SHP file */
4164 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
4165 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
4166 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_POLYGONM, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = POLYGON M */
4167 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
4168 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
4169 			      GAIA_LITTLE_ENDIAN, endian_arch);
4170 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
4171 			      GAIA_LITTLE_ENDIAN, endian_arch);
4172 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
4173 			      GAIA_LITTLE_ENDIAN, endian_arch);
4174 		gaiaExport32 (shp->BufShp + 44, tot_ln, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports # rings in this polygon */
4175 		gaiaExport32 (shp->BufShp + 48, tot_v, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
4176 		tot_v = 0;	/* resets points counter */
4177 		ix = 52;	/* sets current buffer offset */
4178 		polyg = entity->Geometry->FirstPolygon;
4179 		while (polyg)
4180 		  {
4181 		      /* exports start point index for each line */
4182 		      ring = polyg->Exterior;	/* this one is the exterior ring */
4183 		      gaiaExport32 (shp->BufShp + ix, tot_v,
4184 				    GAIA_LITTLE_ENDIAN, endian_arch);
4185 		      tot_v += ring->Points;
4186 		      ix += 4;
4187 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
4188 			{
4189 			    /* that ones are the interior rings */
4190 			    ring = polyg->Interiors + ib;
4191 			    gaiaExport32 (shp->BufShp + ix, tot_v,
4192 					  GAIA_LITTLE_ENDIAN, endian_arch);
4193 			    tot_v += ring->Points;
4194 			    ix += 4;
4195 			}
4196 		      polyg = polyg->Next;
4197 		  }
4198 		polyg = entity->Geometry->FirstPolygon;
4199 		while (polyg)
4200 		  {
4201 		      /* exports points for each ring */
4202 		      ring = polyg->Exterior;	/* this one is the exterior ring */
4203 		      for (iv = 0; iv < ring->Points; iv++)
4204 			{
4205 			    /* exports a POINT [x,y] - exterior ring */
4206 			    if (ring->DimensionModel == GAIA_XY_Z)
4207 			      {
4208 				  gaiaGetPointXYZ (ring->Coords, iv, &x, &y,
4209 						   &z);
4210 			      }
4211 			    else if (ring->DimensionModel == GAIA_XY_M)
4212 			      {
4213 				  gaiaGetPointXYM (ring->Coords, iv, &x, &y,
4214 						   &m);
4215 			      }
4216 			    else if (ring->DimensionModel == GAIA_XY_Z_M)
4217 			      {
4218 				  gaiaGetPointXYZM (ring->Coords, iv, &x,
4219 						    &y, &z, &m);
4220 			      }
4221 			    else
4222 			      {
4223 				  gaiaGetPoint (ring->Coords, iv, &x, &y);
4224 			      }
4225 			    gaiaExport64 (shp->BufShp + ix, x,
4226 					  GAIA_LITTLE_ENDIAN, endian_arch);
4227 			    ix += 8;
4228 			    gaiaExport64 (shp->BufShp + ix, y,
4229 					  GAIA_LITTLE_ENDIAN, endian_arch);
4230 			    ix += 8;
4231 			}
4232 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
4233 			{
4234 			    /* that ones are the interior rings */
4235 			    ring = polyg->Interiors + ib;
4236 			    for (iv = 0; iv < ring->Points; iv++)
4237 			      {
4238 				  /* exports a POINT [x,y] - interior ring */
4239 				  if (ring->DimensionModel == GAIA_XY_Z)
4240 				    {
4241 					gaiaGetPointXYZ (ring->Coords, iv,
4242 							 &x, &y, &z);
4243 				    }
4244 				  else if (ring->DimensionModel == GAIA_XY_M)
4245 				    {
4246 					gaiaGetPointXYM (ring->Coords, iv,
4247 							 &x, &y, &m);
4248 				    }
4249 				  else if (ring->DimensionModel == GAIA_XY_Z_M)
4250 				    {
4251 					gaiaGetPointXYZM (ring->Coords, iv,
4252 							  &x, &y, &z, &m);
4253 				    }
4254 				  else
4255 				    {
4256 					gaiaGetPoint (ring->Coords, iv, &x, &y);
4257 				    }
4258 				  gaiaExport64 (shp->BufShp + ix, x,
4259 						GAIA_LITTLE_ENDIAN,
4260 						endian_arch);
4261 				  ix += 8;
4262 				  gaiaExport64 (shp->BufShp + ix, y,
4263 						GAIA_LITTLE_ENDIAN,
4264 						endian_arch);
4265 				  ix += 8;
4266 			      }
4267 			}
4268 		      polyg = polyg->Next;
4269 		  }
4270 		/* exporting the M-range [min/max] */
4271 		gaiaExport64 (shp->BufShp + ix, minM, GAIA_LITTLE_ENDIAN,
4272 			      endian_arch);
4273 		ix += 8;
4274 		gaiaExport64 (shp->BufShp + ix, maxM, GAIA_LITTLE_ENDIAN,
4275 			      endian_arch);
4276 		ix += 8;
4277 		polyg = entity->Geometry->FirstPolygon;
4278 		while (polyg)
4279 		  {
4280 		      /* exports M-values for each ring */
4281 		      ring = polyg->Exterior;	/* this one is the exterior ring */
4282 		      for (iv = 0; iv < ring->Points; iv++)
4283 			{
4284 			    /* exports M-values - exterior ring */
4285 			    m = 0.0;
4286 			    if (ring->DimensionModel == GAIA_XY_Z)
4287 			      {
4288 				  gaiaGetPointXYZ (ring->Coords, iv, &x, &y,
4289 						   &z);
4290 			      }
4291 			    else if (ring->DimensionModel == GAIA_XY_M)
4292 			      {
4293 				  gaiaGetPointXYM (ring->Coords, iv, &x, &y,
4294 						   &m);
4295 			      }
4296 			    else if (ring->DimensionModel == GAIA_XY_Z_M)
4297 			      {
4298 				  gaiaGetPointXYZM (ring->Coords, iv, &x,
4299 						    &y, &z, &m);
4300 			      }
4301 			    else
4302 			      {
4303 				  gaiaGetPoint (ring->Coords, iv, &x, &y);
4304 			      }
4305 			    gaiaExport64 (shp->BufShp + ix, m,
4306 					  GAIA_LITTLE_ENDIAN, endian_arch);
4307 			    ix += 8;
4308 			}
4309 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
4310 			{
4311 			    /* that ones are the interior rings */
4312 			    ring = polyg->Interiors + ib;
4313 			    for (iv = 0; iv < ring->Points; iv++)
4314 			      {
4315 				  /* exports M-values - interior ring */
4316 				  m = 0.0;
4317 				  if (ring->DimensionModel == GAIA_XY_Z)
4318 				    {
4319 					gaiaGetPointXYZ (ring->Coords, iv,
4320 							 &x, &y, &z);
4321 				    }
4322 				  else if (ring->DimensionModel == GAIA_XY_M)
4323 				    {
4324 					gaiaGetPointXYM (ring->Coords, iv,
4325 							 &x, &y, &m);
4326 				    }
4327 				  else if (ring->DimensionModel == GAIA_XY_Z_M)
4328 				    {
4329 					gaiaGetPointXYZM (ring->Coords, iv,
4330 							  &x, &y, &z, &m);
4331 				    }
4332 				  else
4333 				    {
4334 					gaiaGetPoint (ring->Coords, iv, &x, &y);
4335 				    }
4336 				  gaiaExport64 (shp->BufShp + ix, m,
4337 						GAIA_LITTLE_ENDIAN,
4338 						endian_arch);
4339 				  ix += 8;
4340 			      }
4341 			}
4342 		      polyg = polyg->Next;
4343 		  }
4344 		fwrite (shp->BufShp, 1, ix, shp->flShp);
4345 		(shp->ShpSize) += (ix / 2);
4346 	    }
4347 	  if (shp->Shape == GAIA_SHP_MULTIPOINT)
4348 	    {
4349 		/* this one is expected to be a MULTIPOINT */
4350 		gaiaPointPtr pt;
4351 		tot_pts = 0;
4352 		pt = entity->Geometry->FirstPoint;
4353 		while (pt)
4354 		  {
4355 		      /* computes # points */
4356 		      tot_pts++;
4357 		      pt = pt->Next;
4358 		  }
4359 		if (!tot_pts)
4360 		  {
4361 		      strcpy (dummy,
4362 			      "a MULTIPOINT is expected, but there is no POINT/MULTIPOINT in geometry");
4363 		      if (shp->LastError)
4364 			  free (shp->LastError);
4365 		      len = strlen (dummy);
4366 		      shp->LastError = malloc (len + 1);
4367 		      strcpy (shp->LastError, dummy);
4368 		      return 0;
4369 		  }
4370 		this_size = 20 + (tot_pts * 8);	/* size [in 16 bits words !!!] for this SHP entity */
4371 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
4372 		  {
4373 		      /* current buffer is too small; we need to allocate a bigger one */
4374 		      free (shp->BufShp);
4375 		      shp->ShpBfsz = (this_size * 2) + 1024;
4376 		      shp->BufShp = malloc (shp->ShpBfsz);
4377 		  }
4378 		/* inserting MULTIPOINT in SHX file */
4379 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
4380 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
4381 		fwrite (shp->BufShp, 1, 8, shp->flShx);
4382 		(shp->ShxSize) += 4;
4383 		/* inserting MULTIPOINT in SHP file */
4384 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
4385 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
4386 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_MULTIPOINT, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = MULTIPOINT */
4387 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
4388 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
4389 			      GAIA_LITTLE_ENDIAN, endian_arch);
4390 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
4391 			      GAIA_LITTLE_ENDIAN, endian_arch);
4392 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
4393 			      GAIA_LITTLE_ENDIAN, endian_arch);
4394 		gaiaExport32 (shp->BufShp + 44, tot_pts, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
4395 		ix = 48;	/* sets current buffer offset */
4396 		pt = entity->Geometry->FirstPoint;
4397 		while (pt)
4398 		  {
4399 		      /* exports each point */
4400 		      gaiaExport64 (shp->BufShp + ix, pt->X,
4401 				    GAIA_LITTLE_ENDIAN, endian_arch);
4402 		      ix += 8;
4403 		      gaiaExport64 (shp->BufShp + ix, pt->Y,
4404 				    GAIA_LITTLE_ENDIAN, endian_arch);
4405 		      ix += 8;
4406 		      pt = pt->Next;
4407 		  }
4408 		fwrite (shp->BufShp, 1, ix, shp->flShp);
4409 		(shp->ShpSize) += (ix / 2);	/* updating current SHP file position [in 16 bits words !!!] */
4410 	    }
4411 	  if (shp->Shape == GAIA_SHP_MULTIPOINTZ)
4412 	    {
4413 		/* this one is expected to be a MULTIPOINT Z */
4414 		gaiaPointPtr pt;
4415 		gaiaZRangeGeometry (entity->Geometry, &minZ, &maxZ);
4416 		gaiaMRangeGeometry (entity->Geometry, &minM, &maxM);
4417 		tot_pts = 0;
4418 		pt = entity->Geometry->FirstPoint;
4419 		while (pt)
4420 		  {
4421 		      /* computes # points */
4422 		      tot_pts++;
4423 		      pt = pt->Next;
4424 		  }
4425 		if (!tot_pts)
4426 		  {
4427 		      strcpy (dummy,
4428 			      "a MULTIPOINT is expected, but there is no POINT/MULTIPOINT in geometry");
4429 		      if (shp->LastError)
4430 			  free (shp->LastError);
4431 		      len = strlen (dummy);
4432 		      shp->LastError = malloc (len + 1);
4433 		      strcpy (shp->LastError, dummy);
4434 		      return 0;
4435 		  }
4436 		hasM = 0;
4437 		if (shp->EffectiveDims == GAIA_XY_M
4438 		    || shp->EffectiveDims == GAIA_XY_Z_M)
4439 		    hasM = 1;
4440 		if (hasM)
4441 		    this_size = 36 + (tot_pts * 16);	/* size [in 16 bits words !!!] ZM */
4442 		else
4443 		    this_size = 28 + (tot_pts * 12);	/* size [in 16 bits words !!!] Z-only */
4444 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
4445 		  {
4446 		      /* current buffer is too small; we need to allocate a bigger one */
4447 		      free (shp->BufShp);
4448 		      shp->ShpBfsz = (this_size * 2) + 1024;
4449 		      shp->BufShp = malloc (shp->ShpBfsz);
4450 		  }
4451 		/* inserting MULTIPOINT in SHX file */
4452 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
4453 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
4454 		fwrite (shp->BufShp, 1, 8, shp->flShx);
4455 		(shp->ShxSize) += 4;
4456 		/* inserting MULTIPOINT in SHP file */
4457 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
4458 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
4459 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_MULTIPOINTZ, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = MULTIPOINT Z */
4460 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
4461 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
4462 			      GAIA_LITTLE_ENDIAN, endian_arch);
4463 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
4464 			      GAIA_LITTLE_ENDIAN, endian_arch);
4465 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
4466 			      GAIA_LITTLE_ENDIAN, endian_arch);
4467 		gaiaExport32 (shp->BufShp + 44, tot_pts, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
4468 		ix = 48;	/* sets current buffer offset */
4469 		pt = entity->Geometry->FirstPoint;
4470 		while (pt)
4471 		  {
4472 		      /* exports each point */
4473 		      gaiaExport64 (shp->BufShp + ix, pt->X,
4474 				    GAIA_LITTLE_ENDIAN, endian_arch);
4475 		      ix += 8;
4476 		      gaiaExport64 (shp->BufShp + ix, pt->Y,
4477 				    GAIA_LITTLE_ENDIAN, endian_arch);
4478 		      ix += 8;
4479 		      pt = pt->Next;
4480 		  }
4481 		/* exporting the Z-range [min/max] */
4482 		gaiaExport64 (shp->BufShp + ix, minZ, GAIA_LITTLE_ENDIAN,
4483 			      endian_arch);
4484 		ix += 8;
4485 		gaiaExport64 (shp->BufShp + ix, maxZ, GAIA_LITTLE_ENDIAN,
4486 			      endian_arch);
4487 		ix += 8;
4488 		pt = entity->Geometry->FirstPoint;
4489 		while (pt)
4490 		  {
4491 		      /* exports Z-values */
4492 		      gaiaExport64 (shp->BufShp + ix, pt->Z,
4493 				    GAIA_LITTLE_ENDIAN, endian_arch);
4494 		      ix += 8;
4495 		      pt = pt->Next;
4496 		  }
4497 		if (hasM)
4498 		  {
4499 		      /* exporting the M-range [min/max] */
4500 		      gaiaExport64 (shp->BufShp + ix, minM,
4501 				    GAIA_LITTLE_ENDIAN, endian_arch);
4502 		      ix += 8;
4503 		      gaiaExport64 (shp->BufShp + ix, maxM,
4504 				    GAIA_LITTLE_ENDIAN, endian_arch);
4505 		      ix += 8;
4506 		      pt = entity->Geometry->FirstPoint;
4507 		      while (pt)
4508 			{
4509 			    /* exports M-values */
4510 			    gaiaExport64 (shp->BufShp + ix, pt->M,
4511 					  GAIA_LITTLE_ENDIAN, endian_arch);
4512 			    ix += 8;
4513 			    pt = pt->Next;
4514 			}
4515 		  }
4516 		fwrite (shp->BufShp, 1, ix, shp->flShp);
4517 		(shp->ShpSize) += (ix / 2);	/* updating current SHP file position [in 16 bits words !!!] */
4518 	    }
4519 	  if (shp->Shape == GAIA_SHP_MULTIPOINTM)
4520 	    {
4521 		/* this one is expected to be a MULTIPOINT M */
4522 		gaiaPointPtr pt;
4523 		gaiaMRangeGeometry (entity->Geometry, &minM, &maxM);
4524 		tot_pts = 0;
4525 		pt = entity->Geometry->FirstPoint;
4526 		while (pt)
4527 		  {
4528 		      /* computes # points */
4529 		      tot_pts++;
4530 		      pt = pt->Next;
4531 		  }
4532 		if (!tot_pts)
4533 		  {
4534 		      strcpy (dummy,
4535 			      "a MULTIPOINT is expected, but there is no POINT/MULTIPOINT in geometry");
4536 		      if (shp->LastError)
4537 			  free (shp->LastError);
4538 		      len = strlen (dummy);
4539 		      shp->LastError = malloc (len + 1);
4540 		      strcpy (shp->LastError, dummy);
4541 		      return 0;
4542 		  }
4543 		this_size = 28 + (tot_pts * 12);	/* size [in 16 bits words !!!] for this SHP entity */
4544 		if ((this_size * 2) + 1024 > shp->ShpBfsz)
4545 		  {
4546 		      /* current buffer is too small; we need to allocate a bigger one */
4547 		      free (shp->BufShp);
4548 		      shp->ShpBfsz = (this_size * 2) + 1024;
4549 		      shp->BufShp = malloc (shp->ShpBfsz);
4550 		  }
4551 		/* inserting MULTIPOINT in SHX file */
4552 		gaiaExport32 (shp->BufShp, shp->ShpSize, GAIA_BIG_ENDIAN, endian_arch);	/* exports current SHP file position */
4553 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entitiy size [in 16 bits words !!!] */
4554 		fwrite (shp->BufShp, 1, 8, shp->flShx);
4555 		(shp->ShxSize) += 4;
4556 		/* inserting MULTIPOINT in SHP file */
4557 		gaiaExport32 (shp->BufShp, shp->DbfRecno + 1, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity ID */
4558 		gaiaExport32 (shp->BufShp + 4, this_size, GAIA_BIG_ENDIAN, endian_arch);	/* exports entity size [in 16 bits words !!!] */
4559 		gaiaExport32 (shp->BufShp + 8, GAIA_SHP_MULTIPOINTM, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports geometry type = MULTIPOINT M */
4560 		gaiaExport64 (shp->BufShp + 12, entity->Geometry->MinX, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the MBR for this geometry */
4561 		gaiaExport64 (shp->BufShp + 20, entity->Geometry->MinY,
4562 			      GAIA_LITTLE_ENDIAN, endian_arch);
4563 		gaiaExport64 (shp->BufShp + 28, entity->Geometry->MaxX,
4564 			      GAIA_LITTLE_ENDIAN, endian_arch);
4565 		gaiaExport64 (shp->BufShp + 36, entity->Geometry->MaxY,
4566 			      GAIA_LITTLE_ENDIAN, endian_arch);
4567 		gaiaExport32 (shp->BufShp + 44, tot_pts, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports total # points */
4568 		ix = 48;	/* sets current buffer offset */
4569 		pt = entity->Geometry->FirstPoint;
4570 		while (pt)
4571 		  {
4572 		      /* exports each point */
4573 		      gaiaExport64 (shp->BufShp + ix, pt->X,
4574 				    GAIA_LITTLE_ENDIAN, endian_arch);
4575 		      ix += 8;
4576 		      gaiaExport64 (shp->BufShp + ix, pt->Y,
4577 				    GAIA_LITTLE_ENDIAN, endian_arch);
4578 		      ix += 8;
4579 		      pt = pt->Next;
4580 		  }
4581 		/* exporting the M-range [min/max] */
4582 		gaiaExport64 (shp->BufShp + ix, minM, GAIA_LITTLE_ENDIAN,
4583 			      endian_arch);
4584 		ix += 8;
4585 		gaiaExport64 (shp->BufShp + ix, maxM, GAIA_LITTLE_ENDIAN,
4586 			      endian_arch);
4587 		ix += 8;
4588 		pt = entity->Geometry->FirstPoint;
4589 		while (pt)
4590 		  {
4591 		      /* exports M-values */
4592 		      gaiaExport64 (shp->BufShp + ix, pt->M,
4593 				    GAIA_LITTLE_ENDIAN, endian_arch);
4594 		      ix += 8;
4595 		      pt = pt->Next;
4596 		  }
4597 		fwrite (shp->BufShp, 1, ix, shp->flShp);
4598 		(shp->ShpSize) += (ix / 2);	/* updating current SHP file position [in 16 bits words !!!] */
4599 	    }
4600       }
4601 /* inserting entity in DBF file */
4602     fwrite (shp->BufDbf, 1, shp->DbfReclen, shp->flDbf);
4603     (shp->DbfRecno)++;
4604     return 1;
4605   conversion_error:
4606     if (shp->LastError)
4607 	free (shp->LastError);
4608     sprintf (dummy, "Invalid character sequence");
4609     len = strlen (dummy);
4610     shp->LastError = malloc (len + 1);
4611     strcpy (shp->LastError, dummy);
4612     return 0;
4613 }
4614 
4615 GAIAGEO_DECLARE void
gaiaFlushShpHeaders(gaiaShapefilePtr shp)4616 gaiaFlushShpHeaders (gaiaShapefilePtr shp)
4617 {
4618 /* updates the various file headers */
4619     FILE *fl_shp = shp->flShp;
4620     FILE *fl_shx = shp->flShx;
4621     FILE *fl_dbf = shp->flDbf;
4622     int shp_size = shp->ShpSize;
4623     int shx_size = shp->ShxSize;
4624     int dbf_size = shp->DbfSize;
4625     int dbf_reclen = shp->DbfReclen;
4626     int dbf_recno = shp->DbfRecno;
4627     int endian_arch = shp->endian_arch;
4628     double minx = shp->MinX;
4629     double miny = shp->MinY;
4630     double maxx = shp->MaxX;
4631     double maxy = shp->MaxY;
4632     unsigned char *buf_shp = shp->BufShp;
4633 /* writing the SHP file header */
4634     gaia_fseek (fl_shp, 0, SEEK_SET);	/* repositioning at SHP file start */
4635     gaiaExport32 (buf_shp, 9994, GAIA_BIG_ENDIAN, endian_arch);	/* SHP magic number */
4636     gaiaExport32 (buf_shp + 4, 0, GAIA_BIG_ENDIAN, endian_arch);
4637     gaiaExport32 (buf_shp + 8, 0, GAIA_BIG_ENDIAN, endian_arch);
4638     gaiaExport32 (buf_shp + 12, 0, GAIA_BIG_ENDIAN, endian_arch);
4639     gaiaExport32 (buf_shp + 16, 0, GAIA_BIG_ENDIAN, endian_arch);
4640     gaiaExport32 (buf_shp + 20, 0, GAIA_BIG_ENDIAN, endian_arch);
4641     gaiaExport32 (buf_shp + 24, shp_size, GAIA_BIG_ENDIAN, endian_arch);	/* SHP file size - measured in 16 bits words !!! */
4642     gaiaExport32 (buf_shp + 28, 1000, GAIA_LITTLE_ENDIAN, endian_arch);	/* version */
4643     gaiaExport32 (buf_shp + 32, shp->Shape, GAIA_LITTLE_ENDIAN, endian_arch);	/* ESRI shape */
4644     gaiaExport64 (buf_shp + 36, minx, GAIA_LITTLE_ENDIAN, endian_arch);	/* the MBR/BBOX for the whole shapefile */
4645     gaiaExport64 (buf_shp + 44, miny, GAIA_LITTLE_ENDIAN, endian_arch);
4646     gaiaExport64 (buf_shp + 52, maxx, GAIA_LITTLE_ENDIAN, endian_arch);
4647     gaiaExport64 (buf_shp + 60, maxy, GAIA_LITTLE_ENDIAN, endian_arch);
4648     gaiaExport64 (buf_shp + 68, 0.0, GAIA_LITTLE_ENDIAN, endian_arch);
4649     gaiaExport64 (buf_shp + 76, 0.0, GAIA_LITTLE_ENDIAN, endian_arch);
4650     gaiaExport64 (buf_shp + 84, 0.0, GAIA_LITTLE_ENDIAN, endian_arch);
4651     gaiaExport64 (buf_shp + 92, 0.0, GAIA_LITTLE_ENDIAN, endian_arch);
4652     fwrite (buf_shp, 1, 100, fl_shp);
4653 /* writing the SHX file header */
4654     gaia_fseek (fl_shx, 0, SEEK_SET);	/* repositioning at SHX file start */
4655     gaiaExport32 (buf_shp, 9994, GAIA_BIG_ENDIAN, endian_arch);	/* SHP magic number */
4656     gaiaExport32 (buf_shp + 4, 0, GAIA_BIG_ENDIAN, endian_arch);
4657     gaiaExport32 (buf_shp + 8, 0, GAIA_BIG_ENDIAN, endian_arch);
4658     gaiaExport32 (buf_shp + 12, 0, GAIA_BIG_ENDIAN, endian_arch);
4659     gaiaExport32 (buf_shp + 16, 0, GAIA_BIG_ENDIAN, endian_arch);
4660     gaiaExport32 (buf_shp + 20, 0, GAIA_BIG_ENDIAN, endian_arch);
4661     gaiaExport32 (buf_shp + 24, shx_size, GAIA_BIG_ENDIAN, endian_arch);	/* SHXfile size - measured in 16 bits words !!! */
4662     gaiaExport32 (buf_shp + 28, 1000, GAIA_LITTLE_ENDIAN, endian_arch);	/* version */
4663     gaiaExport32 (buf_shp + 32, shp->Shape, GAIA_LITTLE_ENDIAN, endian_arch);	/* ESRI shape */
4664     gaiaExport64 (buf_shp + 36, minx, GAIA_LITTLE_ENDIAN, endian_arch);	/* the MBR for the whole shapefile */
4665     gaiaExport64 (buf_shp + 44, miny, GAIA_LITTLE_ENDIAN, endian_arch);
4666     gaiaExport64 (buf_shp + 52, maxx, GAIA_LITTLE_ENDIAN, endian_arch);
4667     gaiaExport64 (buf_shp + 60, maxy, GAIA_LITTLE_ENDIAN, endian_arch);
4668     gaiaExport64 (buf_shp + 68, 0.0, GAIA_LITTLE_ENDIAN, endian_arch);
4669     gaiaExport64 (buf_shp + 76, 0.0, GAIA_LITTLE_ENDIAN, endian_arch);
4670     gaiaExport64 (buf_shp + 84, 0.0, GAIA_LITTLE_ENDIAN, endian_arch);
4671     gaiaExport64 (buf_shp + 92, 0.0, GAIA_LITTLE_ENDIAN, endian_arch);
4672     fwrite (buf_shp, 1, 100, fl_shx);
4673 /* writing the DBF file header */
4674     *buf_shp = 0x1a;		/* DBF - this is theEOF marker */
4675     fwrite (buf_shp, 1, 1, fl_dbf);
4676     gaia_fseek (fl_dbf, 0, SEEK_SET);	/* repositioning at DBF file start */
4677     memset (buf_shp, '\0', 32);
4678     *buf_shp = 0x03;		/* DBF magic number */
4679     *(buf_shp + 1) = 1;		/* this is supposed to be the last update date [Year, Month, Day], but we ignore it at all */
4680     *(buf_shp + 2) = 1;
4681     *(buf_shp + 3) = 1;
4682     gaiaExport32 (buf_shp + 4, dbf_recno, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports # records in this DBF */
4683     gaiaExport16 (buf_shp + 8, (short) dbf_size, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the file header size */
4684     gaiaExport16 (buf_shp + 10, (short) dbf_reclen, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the record length */
4685     fwrite (buf_shp, 1, 32, fl_dbf);
4686 }
4687 
4688 GAIAGEO_DECLARE void
gaiaShpAnalyze(gaiaShapefilePtr shp)4689 gaiaShpAnalyze (gaiaShapefilePtr shp)
4690 {
4691 /* analyzing the SHP content, in order to detect if there are LINESTRINGS or MULTILINESTRINGS
4692 / the same check is needed in order to detect if there are POLYGONS or MULTIPOLYGONS
4693  */
4694     unsigned char buf[512];
4695     int rd;
4696     int skpos;
4697     gaia_off_t offset;
4698     int off_shp;
4699     int sz;
4700     int shape;
4701     int points;
4702     int n;
4703     int n1;
4704     int base;
4705     int start;
4706     int end;
4707     int iv;
4708     int ind;
4709     double x;
4710     double y;
4711     int polygons;
4712     int ZM_size;
4713     int multi = 0;
4714     int hasM = 0;
4715     int current_row = 0;
4716 
4717     gaiaRingPtr ring = NULL;
4718     while (1)
4719       {
4720 	  /* positioning and reading the SHX file */
4721 	  offset = 100 + ((gaia_off_t) current_row * (gaia_off_t) 8);	/* 100 bytes for the header + current row displacement; each SHX row = 8 bytes */
4722 	  if (shp->memShx != NULL)
4723 	      skpos = gaiaMemFseek (shp->memShx, offset);
4724 	  else
4725 	      skpos = gaia_fseek (shp->flShx, offset, SEEK_SET);
4726 	  if (skpos != 0)
4727 	      goto exit;
4728 	  if (shp->memShx != NULL)
4729 	      rd = gaiaMemRead (buf, 8, shp->memShx);
4730 	  else
4731 	      rd = fread (buf, sizeof (unsigned char), 8, shp->flShx);
4732 	  if (rd != 8)
4733 	      goto exit;
4734 	  off_shp = gaiaImport32 (buf, GAIA_BIG_ENDIAN, shp->endian_arch);
4735 	  /* positioning and reading corresponding SHP entity - geometry */
4736 	  offset = (gaia_off_t) off_shp *2;
4737 	  if (shp->memShp != NULL)
4738 	      skpos = gaiaMemFseek (shp->memShp, offset);
4739 	  else
4740 	      skpos = gaia_fseek (shp->flShp, offset, SEEK_SET);
4741 	  if (skpos != 0)
4742 	      goto exit;
4743 	  if (shp->memShp != NULL)
4744 	      rd = gaiaMemRead (buf, 12, shp->memShp);
4745 	  else
4746 	      rd = fread (buf, sizeof (unsigned char), 12, shp->flShp);
4747 	  if (rd != 12)
4748 	      goto exit;
4749 	  sz = gaiaImport32 (buf + 4, GAIA_BIG_ENDIAN, shp->endian_arch);
4750 	  shape = gaiaImport32 (buf + 8, GAIA_LITTLE_ENDIAN, shp->endian_arch);
4751 	  if ((sz * 2) > shp->ShpBfsz)
4752 	    {
4753 		/* current buffer is too small; we need to allocate a bigger buffer */
4754 		free (shp->BufShp);
4755 		shp->ShpBfsz = sz * 2;
4756 		shp->BufShp = malloc (sizeof (unsigned char) * shp->ShpBfsz);
4757 	    }
4758 	  if (shape == GAIA_SHP_POLYLINE || shape == GAIA_SHP_POLYLINEZ
4759 	      || shape == GAIA_SHP_POLYLINEM)
4760 	    {
4761 		/* shape polyline */
4762 		if (shp->memShp != NULL)
4763 		    rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
4764 		else
4765 		    rd = fread (shp->BufShp, sizeof (unsigned char), 32,
4766 				shp->flShp);
4767 		if (rd != 32)
4768 		    goto exit;
4769 		if (shp->memShp != NULL)
4770 		    rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
4771 		else
4772 		    rd = fread (shp->BufShp, sizeof (unsigned char),
4773 				(sz * 2) - 36, shp->flShp);
4774 		if (rd != (sz * 2) - 36)
4775 		    goto exit;
4776 		n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN,
4777 				  shp->endian_arch);
4778 		n1 = gaiaImport32 (shp->BufShp + 4, GAIA_LITTLE_ENDIAN,
4779 				   shp->endian_arch);
4780 		if (n > 1)
4781 		    multi++;
4782 		if (shape == GAIA_SHP_POLYLINEZ)
4783 		  {
4784 		      ZM_size = 38 + (2 * n) + (n1 * 16);	/* size [in 16 bits words !!!] ZM */
4785 		      if (sz == ZM_size)
4786 			  hasM = 1;
4787 		  }
4788 	    }
4789 	  if (shape == GAIA_SHP_POLYGON || shape == GAIA_SHP_POLYGONZ
4790 	      || shape == GAIA_SHP_POLYGONM)
4791 	    {
4792 		/* shape polygon */
4793 		struct shp_ring_item *pExt;
4794 		struct shp_ring_collection ringsColl;
4795 		/* initializing the RING collection */
4796 		ringsColl.First = NULL;
4797 		ringsColl.Last = NULL;
4798 
4799 		if (shp->memShp != NULL)
4800 		    rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
4801 		else
4802 		    rd = fread (shp->BufShp, sizeof (unsigned char), 32,
4803 				shp->flShp);
4804 		if (rd != 32)
4805 		    goto exit;
4806 		if (shp->memShp != NULL)
4807 		    rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
4808 		else
4809 		    rd = fread (shp->BufShp, sizeof (unsigned char),
4810 				(sz * 2) - 36, shp->flShp);
4811 		if (rd != (sz * 2) - 36)
4812 		    goto exit;
4813 		n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN,
4814 				  shp->endian_arch);
4815 		n1 = gaiaImport32 (shp->BufShp + 4, GAIA_LITTLE_ENDIAN,
4816 				   shp->endian_arch);
4817 		base = 8 + (n * 4);
4818 		start = 0;
4819 		for (ind = 0; ind < n; ind++)
4820 		  {
4821 		      if (ind < (n - 1))
4822 			  end =
4823 			      gaiaImport32 (shp->BufShp + 8 +
4824 					    ((ind + 1) * 4),
4825 					    GAIA_LITTLE_ENDIAN,
4826 					    shp->endian_arch);
4827 		      else
4828 			  end = n1;
4829 		      points = end - start;
4830 		      ring = gaiaAllocRing (points);
4831 		      points = 0;
4832 		      for (iv = start; iv < end; iv++)
4833 			{
4834 			    x = gaiaImport64 (shp->BufShp + base +
4835 					      (iv * 16), GAIA_LITTLE_ENDIAN,
4836 					      shp->endian_arch);
4837 			    y = gaiaImport64 (shp->BufShp + base +
4838 					      (iv * 16) + 8,
4839 					      GAIA_LITTLE_ENDIAN,
4840 					      shp->endian_arch);
4841 			    gaiaSetPoint (ring->Coords, points, x, y);
4842 			    start++;
4843 			    points++;
4844 			}
4845 		      shp_add_ring (&ringsColl, ring);
4846 		      ring = NULL;
4847 		  }
4848 		shp_arrange_rings (&ringsColl);
4849 		pExt = ringsColl.First;
4850 		polygons = 0;
4851 		while (pExt != NULL)
4852 		  {
4853 		      if (pExt->IsExterior)
4854 			  polygons++;
4855 		      pExt = pExt->Next;
4856 		  }
4857 		shp_free_rings (&ringsColl);
4858 
4859 		if (polygons > 1)
4860 		    multi++;
4861 		if (shape == GAIA_SHP_POLYGONZ)
4862 		  {
4863 		      ZM_size = 38 + (2 * n) + (n1 * 16);	/* size [in 16 bits words !!!] ZM */
4864 		      if (sz == ZM_size)
4865 			  hasM = 1;
4866 		  }
4867 	    }
4868 	  if (shape == GAIA_SHP_MULTIPOINTZ)
4869 	    {
4870 		/* shape multipoint Z */
4871 		if (shp->memShp != NULL)
4872 		    rd = gaiaMemRead (shp->BufShp, 32, shp->memShp);
4873 		else
4874 		    rd = fread (shp->BufShp, sizeof (unsigned char), 32,
4875 				shp->flShp);
4876 		if (rd != 32)
4877 		    goto exit;
4878 		if (shp->memShp != NULL)
4879 		    rd = gaiaMemRead (shp->BufShp, (sz * 2) - 36, shp->memShp);
4880 		else
4881 		    rd = fread (shp->BufShp, sizeof (unsigned char),
4882 				(sz * 2) - 36, shp->flShp);
4883 		if (rd != (sz * 2) - 36)
4884 		    goto exit;
4885 		n = gaiaImport32 (shp->BufShp, GAIA_LITTLE_ENDIAN,
4886 				  shp->endian_arch);
4887 		ZM_size = 38 + (n * 16);	/* size [in 16 bits words !!!] ZM */
4888 		if (sz == ZM_size)
4889 		    hasM = 1;
4890 	    }
4891 	  current_row++;
4892       }
4893   exit:
4894     if (ring)
4895 	gaiaFreeRing (ring);
4896     if (shp->LastError)
4897 	free (shp->LastError);
4898     shp->LastError = NULL;
4899 /* setting the EffectiveType, as determined by this analysis */
4900     if (shp->Shape == GAIA_SHP_POLYLINE || shp->Shape == GAIA_SHP_POLYLINEZ
4901 	|| shp->Shape == GAIA_SHP_POLYLINEM)
4902       {
4903 	  /* SHAPE polyline */
4904 	  if (multi)
4905 	      shp->EffectiveType = GAIA_MULTILINESTRING;
4906 	  else
4907 	      shp->EffectiveType = GAIA_LINESTRING;
4908       }
4909     if (shp->Shape == GAIA_SHP_POLYGON || shp->Shape == GAIA_SHP_POLYGONZ
4910 	|| shp->Shape == GAIA_SHP_POLYGONM)
4911       {
4912 	  /* SHAPE polygon */
4913 	  if (multi)
4914 	      shp->EffectiveType = GAIA_MULTIPOLYGON;
4915 	  else
4916 	      shp->EffectiveType = GAIA_POLYGON;
4917       }
4918     if (shp->Shape == GAIA_SHP_POLYLINEZ || shp->Shape == GAIA_SHP_POLYGONZ
4919 	|| shp->Shape == GAIA_SHP_MULTIPOINTZ)
4920       {
4921 	  if (hasM)
4922 	      shp->EffectiveDims = GAIA_XY_Z_M;
4923 	  else
4924 	      shp->EffectiveDims = GAIA_XY_Z;
4925       }
4926 }
4927 
4928 GAIAGEO_DECLARE gaiaDbfPtr
gaiaAllocDbf()4929 gaiaAllocDbf ()
4930 {
4931 /* allocates and initializes the DBF object */
4932     gaiaDbfPtr dbf = malloc (sizeof (gaiaDbf));
4933     dbf->endian_arch = 1;
4934     dbf->Path = NULL;
4935     dbf->flDbf = NULL;
4936     dbf->memDbf = NULL;
4937     dbf->Dbf = NULL;
4938     dbf->BufDbf = NULL;
4939     dbf->DbfHdsz = 0;
4940     dbf->DbfReclen = 0;
4941     dbf->DbfSize = 0;
4942     dbf->DbfRecno = 0;
4943     dbf->Valid = 0;
4944     dbf->IconvObj = NULL;
4945     dbf->LastError = NULL;
4946     return dbf;
4947 }
4948 
4949 GAIAGEO_DECLARE void
gaiaFreeDbf(gaiaDbfPtr dbf)4950 gaiaFreeDbf (gaiaDbfPtr dbf)
4951 {
4952 /* frees all memory allocations related to the DBF object */
4953     if (dbf->Path)
4954 	free (dbf->Path);
4955     if (dbf->flDbf)
4956 	fclose (dbf->flDbf);
4957     if (dbf->Dbf)
4958 	gaiaFreeDbfList (dbf->Dbf);
4959     if (dbf->BufDbf)
4960 	free (dbf->BufDbf);
4961     if (dbf->IconvObj)
4962 	iconv_close ((iconv_t) dbf->IconvObj);
4963     if (dbf->LastError)
4964 	free (dbf->LastError);
4965     free (dbf);
4966 }
4967 
4968 GAIAGEO_DECLARE void
gaiaOpenDbfRead(gaiaDbfPtr dbf,const char * path,const char * charFrom,const char * charTo)4969 gaiaOpenDbfRead (gaiaDbfPtr dbf, const char *path, const char *charFrom,
4970 		 const char *charTo)
4971 {
4972 /* trying to open the DBF and initial checkings */
4973     FILE *fl_dbf = NULL;
4974     int rd;
4975     unsigned char bf[1024];
4976     int dbf_size;
4977     int dbf_reclen = 0;
4978     int off_dbf;
4979     int ind;
4980     char field_name[2048];
4981     char *sys_err;
4982     char errMsg[1024];
4983     iconv_t iconv_ret;
4984     char utf8buf[2048];
4985 #if !defined(__MINGW32__) && defined(_WIN32)
4986     const char *pBuf;
4987 #else /* not WIN32 */
4988     char *pBuf;
4989 #endif
4990     size_t len;
4991     size_t utf8len;
4992     char *pUtf8buf;
4993     int endian_arch = gaiaEndianArch ();
4994     gaiaDbfListPtr dbf_list = NULL;
4995     if (charFrom && charTo)
4996       {
4997 	  iconv_ret = iconv_open (charTo, charFrom);
4998 	  if (iconv_ret == (iconv_t) (-1))
4999 	    {
5000 		sprintf (errMsg,
5001 			 "conversion from '%s' to '%s' not available\n",
5002 			 charFrom, charTo);
5003 		goto unsupported_conversion;
5004 	    }
5005 	  dbf->IconvObj = iconv_ret;
5006       }
5007     else
5008       {
5009 	  sprintf (errMsg, "a NULL charset-name was passed\n");
5010 	  goto unsupported_conversion;
5011       }
5012     if (dbf->flDbf != NULL)
5013       {
5014 	  sprintf (errMsg, "attempting to reopen an already opened DBF\n");
5015 	  goto unsupported_conversion;
5016       }
5017     if (dbf->memDbf == NULL)
5018       {
5019 #ifdef _WIN32
5020 	  fl_dbf = gaia_win_fopen (path, "rb");
5021 #else
5022 	  fl_dbf = fopen (path, "rb");
5023 #endif
5024 	  if (!fl_dbf)
5025 	    {
5026 		sys_err = strerror (errno);
5027 		sprintf (errMsg, "unable to open '%s' for reading: %s", path,
5028 			 sys_err);
5029 		goto no_file;
5030 	    }
5031       }
5032 /* reading DBF file header */
5033     if (dbf->memDbf != NULL)
5034 	rd = gaiaMemRead (bf, 32, dbf->memDbf);
5035     else
5036 	rd = fread (bf, sizeof (unsigned char), 32, fl_dbf);
5037     if (rd != 32)
5038 	goto error;
5039     switch (*bf)
5040       {
5041 	  /* checks the DBF magic number */
5042       case 0x03:
5043       case 0x83:
5044 	  break;
5045       case 0x02:
5046       case 0xF8:
5047 	  sprintf (errMsg, "'%s'\ninvalid magic number %02x [FoxBASE format]",
5048 		   path, *bf);
5049 	  goto dbf_bad_magic;
5050       case 0xF5:
5051 	  sprintf (errMsg,
5052 		   "'%s'\ninvalid magic number %02x [FoxPro 2.x (or earlier) format]",
5053 		   path, *bf);
5054 	  goto dbf_bad_magic;
5055       case 0x30:
5056       case 0x31:
5057       case 0x32:
5058 	  sprintf (errMsg,
5059 		   "'%s'\ninvalid magic number %02x [Visual FoxPro format]",
5060 		   path, *bf);
5061 	  goto dbf_bad_magic;
5062       case 0x43:
5063       case 0x63:
5064       case 0xBB:
5065       case 0xCB:
5066 	  sprintf (errMsg, "'%s'\ninvalid magic number %02x [dBASE IV format]",
5067 		   path, *bf);
5068 	  goto dbf_bad_magic;
5069       default:
5070 	  sprintf (errMsg, "'%s'\ninvalid magic number %02x [unknown format]",
5071 		   path, *bf);
5072 	  goto dbf_bad_magic;
5073       };
5074     dbf_size = gaiaImport16 (bf + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5075     dbf_reclen = gaiaImport16 (bf + 10, GAIA_LITTLE_ENDIAN, endian_arch);
5076     dbf_size--;
5077     off_dbf = 0;
5078     dbf_list = gaiaAllocDbfList ();
5079     for (ind = 32; ind < dbf_size; ind += 32)
5080       {
5081 	  /* fetches DBF fields definitions */
5082 	  if ((dbf_size - ind) < 32)
5083 	    {
5084 		/* some odd DBF could contain some unexpected extra-padding */
5085 		int extra = dbf_size - ind;
5086 		if (dbf->memDbf != NULL)
5087 		    rd = gaiaMemRead (bf, extra, dbf->memDbf);
5088 		else
5089 		    rd = fread (bf, sizeof (unsigned char), extra, fl_dbf);
5090 		if (rd != extra)
5091 		    goto error;
5092 		/* ignoring the extra-padding */
5093 		break;
5094 	    }
5095 	  if (dbf->memDbf != NULL)
5096 	      rd = gaiaMemRead (bf, 32, dbf->memDbf);
5097 	  else
5098 	      rd = fread (bf, sizeof (unsigned char), 32, fl_dbf);
5099 	  if (rd != 32)
5100 	      goto error;
5101 	  if (*(bf + 11) == 'M')
5102 	    {
5103 		/* skipping any MEMO field */
5104 		memcpy (field_name, bf, 11);
5105 		field_name[11] = '\0';
5106 		off_dbf += *(bf + 16);
5107 		spatialite_e
5108 		    ("WARNING: column \"%s\" is of the MEMO type and will be ignored\n",
5109 		     field_name);
5110 		continue;
5111 	    }
5112 	  memcpy (field_name, bf, 11);
5113 	  field_name[11] = '\0';
5114 	  len = strlen ((char *) field_name);
5115 	  utf8len = 2048;
5116 	  pBuf = (char *) field_name;
5117 	  pUtf8buf = utf8buf;
5118 	  if (iconv
5119 	      ((iconv_t) (dbf->IconvObj), &pBuf, &len, &pUtf8buf,
5120 	       &utf8len) == (size_t) (-1))
5121 	    {
5122 		spatialite_e
5123 		    ("**** libiconv: unable to convert string=\"%s\"\n",
5124 		     field_name);
5125 		goto conversion_error;
5126 	    }
5127 	  memcpy (field_name, utf8buf, 2048 - utf8len);
5128 	  field_name[2048 - utf8len] = '\0';
5129 	  gaiaAddDbfField (dbf_list, field_name, *(bf + 11), off_dbf,
5130 			   *(bf + 16), *(bf + 17));
5131 	  off_dbf += *(bf + 16);
5132       }
5133     if (!gaiaIsValidDbfList (dbf_list))
5134       {
5135 	  /* invalid DBF */
5136 	  goto illegal_dbf;
5137       }
5138     len = strlen (path);
5139     dbf->Path = malloc (len + 1);
5140     strcpy (dbf->Path, path);
5141     dbf->flDbf = fl_dbf;
5142     dbf->Dbf = dbf_list;
5143 /* allocating DBF buffer */
5144     dbf->BufDbf = malloc (sizeof (unsigned char) * dbf_reclen);
5145     dbf->DbfHdsz = dbf_size + 1;
5146     dbf->DbfReclen = dbf_reclen;
5147     dbf->Valid = 1;
5148     dbf->endian_arch = endian_arch;
5149     return;
5150   unsupported_conversion:
5151 /* illegal charset */
5152     if (dbf->LastError)
5153 	free (dbf->LastError);
5154     len = strlen (errMsg);
5155     dbf->LastError = malloc (len + 1);
5156     strcpy (dbf->LastError, errMsg);
5157     return;
5158   no_file:
5159 /* the DBF file can't be accessed */
5160     if (dbf->LastError)
5161 	free (dbf->LastError);
5162     len = strlen (errMsg);
5163     dbf->LastError = malloc (len + 1);
5164     strcpy (dbf->LastError, errMsg);
5165     if (fl_dbf)
5166 	fclose (fl_dbf);
5167     return;
5168   error:
5169 /* the DBF is invalid or corrupted */
5170     if (dbf->LastError)
5171 	free (dbf->LastError);
5172     sprintf (errMsg, "'%s' is corrupted / has invalid format", path);
5173     len = strlen (errMsg);
5174     dbf->LastError = malloc (len + 1);
5175     strcpy (dbf->LastError, errMsg);
5176     gaiaFreeDbfList (dbf_list);
5177     fclose (fl_dbf);
5178     return;
5179   dbf_bad_magic:
5180 /* the DBF has an invalid magic number */
5181     if (dbf->LastError)
5182 	free (dbf->LastError);
5183     len = strlen (errMsg);
5184     dbf->LastError = malloc (len + 1);
5185     strcpy (dbf->LastError, errMsg);
5186     gaiaFreeDbfList (dbf_list);
5187     fclose (fl_dbf);
5188     return;
5189   illegal_dbf:
5190 /* the DBF-file contains unsupported data types */
5191     if (dbf->LastError)
5192 	free (dbf->LastError);
5193     sprintf (errMsg, "'%s' contains unsupported data types", path);
5194     len = strlen (errMsg);
5195     dbf->LastError = malloc (len + 1);
5196     strcpy (dbf->LastError, errMsg);
5197     gaiaFreeDbfList (dbf_list);
5198     if (fl_dbf)
5199 	fclose (fl_dbf);
5200     return;
5201   conversion_error:
5202 /* libiconv error */
5203     if (dbf->LastError)
5204 	free (dbf->LastError);
5205     sprintf (errMsg, "'%s.dbf' field name: invalid character sequence", path);
5206     len = strlen (errMsg);
5207     dbf->LastError = malloc (len + 1);
5208     strcpy (dbf->LastError, errMsg);
5209     gaiaFreeDbfList (dbf_list);
5210     if (fl_dbf)
5211 	fclose (fl_dbf);
5212     return;
5213 }
5214 
5215 GAIAGEO_DECLARE void
gaiaOpenDbfWrite(gaiaDbfPtr dbf,const char * path,const char * charFrom,const char * charTo)5216 gaiaOpenDbfWrite (gaiaDbfPtr dbf, const char *path, const char *charFrom,
5217 		  const char *charTo)
5218 {
5219 /* trying to create the DBF file */
5220     gaiaOpenDbfWriteEx (dbf, path, charFrom, charTo,
5221 			GAIA_DBF_COLNAME_CASE_IGNORE);
5222 }
5223 
5224 GAIAGEO_DECLARE void
gaiaOpenDbfWriteEx(gaiaDbfPtr dbf,const char * path,const char * charFrom,const char * charTo,int colname_case)5225 gaiaOpenDbfWriteEx (gaiaDbfPtr dbf, const char *path, const char *charFrom,
5226 		    const char *charTo, int colname_case)
5227 {
5228 /* trying to create the DBF file */
5229     FILE *fl_dbf = NULL;
5230     unsigned char bf[1024];
5231     unsigned char *dbf_buf = NULL;
5232     gaiaDbfFieldPtr fld;
5233     char *sys_err;
5234     char errMsg[1024];
5235     short dbf_reclen = 0;
5236     unsigned short dbf_size = 0;
5237     iconv_t iconv_ret;
5238     char buf[2048];
5239     char utf8buf[2048];
5240 #if !defined(__MINGW32__) && defined(_WIN32)
5241     const char *pBuf;
5242 #else /* not WIN32 */
5243     char *pBuf;
5244 #endif
5245     size_t len;
5246     size_t utf8len;
5247     char *pUtf8buf;
5248     int defaultId = 1;
5249     struct auxdbf_list *auxdbf = NULL;
5250     if (charFrom && charTo)
5251       {
5252 	  iconv_ret = iconv_open (charTo, charFrom);
5253 	  if (iconv_ret == (iconv_t) (-1))
5254 	    {
5255 		sprintf (errMsg, "conversion from '%s' to '%s' not available\n",
5256 			 charFrom, charTo);
5257 		goto unsupported_conversion;
5258 	    }
5259 	  dbf->IconvObj = iconv_ret;
5260       }
5261     else
5262       {
5263 	  sprintf (errMsg, "a NULL charset-name was passed\n");
5264 	  goto unsupported_conversion;
5265       }
5266     if (dbf->flDbf != NULL)
5267       {
5268 	  sprintf (errMsg, "attempting to reopen an already opened DBF file\n");
5269 	  goto unsupported_conversion;
5270       }
5271 /* trying to open the DBF file */
5272 #ifdef _WIN32
5273     fl_dbf = gaia_win_fopen (path, "wb");
5274 #else
5275     fl_dbf = fopen (path, "wb");
5276 #endif
5277     if (!fl_dbf)
5278       {
5279 	  sys_err = strerror (errno);
5280 	  sprintf (errMsg, "unable to open '%s' for writing: %s", path,
5281 		   sys_err);
5282 	  goto no_file;
5283       }
5284 /* allocating DBF buffer */
5285     dbf_reclen = 1;		/* an extra byte is needed because in DBF rows first byte is a marker for deletion */
5286     fld = dbf->Dbf->First;
5287     while (fld)
5288       {
5289 	  /* computing the DBF record length */
5290 	  dbf_reclen += fld->Length;
5291 	  fld = fld->Next;
5292       }
5293     dbf_buf = malloc (dbf_reclen);
5294 /* writing the DBF file header */
5295     memset (bf, '\0', 32);
5296     fwrite (bf, 1, 32, fl_dbf);
5297     dbf_size = 32;		/* note: DBF counts sizes in bytes */
5298     auxdbf = alloc_auxdbf (dbf->Dbf);
5299     fld = dbf->Dbf->First;
5300     while (fld)
5301       {
5302 	  /* exporting DBF Fields specifications */
5303 	  memset (bf, 0, 32);
5304 	  if (strlen (fld->Name) > 10)
5305 	    {
5306 		/* long name: attempting to safely truncate */
5307 		truncate_long_name (auxdbf, fld);
5308 	    }
5309 	  strcpy (buf, fld->Name);
5310 	  len = strlen (buf);
5311 	  utf8len = 2048;
5312 	  pBuf = buf;
5313 	  pUtf8buf = utf8buf;
5314 	  if (iconv
5315 	      ((iconv_t) (dbf->IconvObj), &pBuf, &len, &pUtf8buf,
5316 	       &utf8len) == (size_t) (-1))
5317 	      sprintf (buf, "FLD#%d", defaultId++);
5318 	  else
5319 	    {
5320 		memcpy (buf, utf8buf, 2048 - utf8len);
5321 		buf[2048 - utf8len] = '\0';
5322 		if (strlen (buf) > 10)
5323 		    sprintf (buf, "FLD#%d", defaultId++);
5324 	    }
5325 	  convert_dbf_colname_case (buf, colname_case);
5326 	  memcpy (bf, buf, strlen (buf));
5327 	  *(bf + 11) = fld->Type;
5328 	  *(bf + 16) = fld->Length;
5329 	  *(bf + 17) = fld->Decimals;
5330 	  fwrite (bf, 1, 32, fl_dbf);
5331 	  dbf_size += 32;
5332 	  fld = fld->Next;
5333       }
5334     free_auxdbf (auxdbf);
5335     fwrite ("\r", 1, 1, fl_dbf);	/* this one is a special DBF delimiter that closes file header */
5336     dbf_size++;
5337     dbf->Valid = 1;
5338     dbf->flDbf = fl_dbf;
5339     dbf->BufDbf = dbf_buf;
5340     dbf->DbfHdsz = dbf_size + 1;
5341     dbf->DbfReclen = dbf_reclen;
5342     dbf->DbfSize = dbf_size;
5343     dbf->DbfRecno = 0;
5344     return;
5345   unsupported_conversion:
5346 /* illegal charset */
5347     if (dbf->LastError)
5348 	free (dbf->LastError);
5349     len = strlen (errMsg);
5350     dbf->LastError = malloc (len + 1);
5351     strcpy (dbf->LastError, errMsg);
5352     return;
5353   no_file:
5354 /* the DBF file can't be created/opened */
5355     if (dbf->LastError)
5356 	free (dbf->LastError);
5357     len = strlen (errMsg);
5358     dbf->LastError = malloc (len + 1);
5359     strcpy (dbf->LastError, errMsg);
5360     if (dbf_buf)
5361 	free (dbf_buf);
5362     if (fl_dbf)
5363 	fclose (fl_dbf);
5364     return;
5365 }
5366 
5367 GAIAGEO_DECLARE int
gaiaWriteDbfEntity(gaiaDbfPtr dbf,gaiaDbfListPtr entity)5368 gaiaWriteDbfEntity (gaiaDbfPtr dbf, gaiaDbfListPtr entity)
5369 {
5370 /* trying to write an entity into some DBF file */
5371     char dummy[128];
5372     char fmt[16];
5373     gaiaDbfFieldPtr fld;
5374 #if !defined(__MINGW32__) && defined(_WIN32)
5375     const char *pBuf;
5376 #else /* not WIN32 */
5377     char *pBuf;
5378 #endif
5379     size_t len;
5380     size_t utf8len;
5381     char *pUtf8buf;
5382     char *dynbuf;
5383     char utf8buf[2048];
5384 /* writing the DBF record */
5385     memset (dbf->BufDbf, '\0', dbf->DbfReclen);
5386     *(dbf->BufDbf) = ' ';	/* in DBF first byte of each row marks for validity or deletion */
5387     fld = entity->First;
5388     while (fld)
5389       {
5390 	  /* transferring field values */
5391 	  switch (fld->Type)
5392 	    {
5393 	    case 'L':
5394 		if (!(fld->Value))
5395 		    *(dbf->BufDbf + fld->Offset) = '?';
5396 		else if (fld->Value->Type != GAIA_INT_VALUE)
5397 		    *(dbf->BufDbf + fld->Offset + 1) = '?';
5398 		else
5399 		  {
5400 		      if (fld->Value->IntValue == 0)
5401 			  *(dbf->BufDbf + fld->Offset + 1) = 'N';
5402 		      else
5403 			  *(dbf->BufDbf + fld->Offset + 1) = 'Y';
5404 		  }
5405 		break;
5406 	    case 'D':
5407 		memset (dbf->BufDbf + fld->Offset + 1, '0', 8);
5408 		if (fld->Value)
5409 		  {
5410 		      if (fld->Value->Type == GAIA_TEXT_VALUE)
5411 			{
5412 			    if (strlen (fld->Value->TxtValue) == 8)
5413 				memcpy (dbf->BufDbf + fld->Offset + 1,
5414 					fld->Value->TxtValue, 8);
5415 			}
5416 		  }
5417 		break;
5418 	    case 'C':
5419 		memset (dbf->BufDbf + fld->Offset + 1, ' ', fld->Length);
5420 		if (fld->Value)
5421 		  {
5422 		      if (fld->Value->Type == GAIA_TEXT_VALUE)
5423 			{
5424 			    len = strlen (fld->Value->TxtValue);
5425 			    dynbuf = malloc (len + 1);
5426 			    strcpy (dynbuf, fld->Value->TxtValue);
5427 			    if (len > 512)
5428 			      {
5429 				  dynbuf[512] = '\0';
5430 				  len = strlen (dynbuf);
5431 			      }
5432 			    utf8len = 2048;
5433 			    pBuf = dynbuf;
5434 			    pUtf8buf = utf8buf;
5435 			    if (iconv
5436 				((iconv_t) (dbf->IconvObj), &pBuf, &len,
5437 				 &pUtf8buf, &utf8len) == (size_t) (-1))
5438 			      {
5439 				  spatialite_e
5440 				      ("**** libiconv: unable to convert string=\"%s\"\n",
5441 				       dynbuf);
5442 				  free (dynbuf);
5443 				  goto conversion_error;
5444 			      }
5445 			    memcpy (dynbuf, utf8buf, 2048 - utf8len);
5446 			    dynbuf[2048 - utf8len] = '\0';
5447 			    if (strlen (dynbuf) < fld->Length)
5448 				memcpy (dbf->BufDbf + fld->Offset + 1, dynbuf,
5449 					strlen (dynbuf));
5450 			    else
5451 				memcpy (dbf->BufDbf + fld->Offset + 1, dynbuf,
5452 					fld->Length);
5453 			    free (dynbuf);
5454 			}
5455 		  }
5456 		break;
5457 	    case 'N':
5458 		memset (dbf->BufDbf + fld->Offset + 1, '\0', fld->Length);
5459 		if (fld->Value)
5460 		  {
5461 		      if (fld->Value->Type == GAIA_INT_VALUE)
5462 			{
5463 			    sprintf (dummy, FRMT64, fld->Value->IntValue);
5464 			    if (strlen (dummy) <= fld->Length)
5465 				memcpy (dbf->BufDbf + fld->Offset + 1,
5466 					dummy, strlen (dummy));
5467 			}
5468 		      if (fld->Value->Type == GAIA_DOUBLE_VALUE)
5469 			{
5470 			    sprintf (fmt, "%%1.%df", fld->Decimals);
5471 			    sprintf (dummy, fmt, fld->Value->DblValue);
5472 			    if (strlen (dummy) <= fld->Length)
5473 				memcpy (dbf->BufDbf + fld->Offset + 1,
5474 					dummy, strlen (dummy));
5475 			}
5476 		  }
5477 		break;
5478 	    };
5479 	  fld = fld->Next;
5480       }
5481 /* inserting entity in DBF file */
5482     fwrite (dbf->BufDbf, 1, dbf->DbfReclen, dbf->flDbf);
5483     (dbf->DbfRecno)++;
5484     return 1;
5485   conversion_error:
5486     if (dbf->LastError)
5487 	free (dbf->LastError);
5488     sprintf (dummy, "Invalid character sequence");
5489     len = strlen (dummy);
5490     dbf->LastError = malloc (len + 1);
5491     strcpy (dbf->LastError, dummy);
5492     return 0;
5493 }
5494 
5495 GAIAGEO_DECLARE void
gaiaFlushDbfHeader(gaiaDbfPtr dbf)5496 gaiaFlushDbfHeader (gaiaDbfPtr dbf)
5497 {
5498 /* updates the DBF file header */
5499     FILE *fl_dbf = dbf->flDbf;
5500     int dbf_size = dbf->DbfSize;
5501     int dbf_reclen = dbf->DbfReclen;
5502     int dbf_recno = dbf->DbfRecno;
5503     int endian_arch = dbf->endian_arch;
5504     unsigned char bf[64];
5505 /* writing the DBF file header */
5506     *bf = 0x1a;			/* DBF - this is theEOF marker */
5507     fwrite (bf, 1, 1, fl_dbf);
5508     gaia_fseek (fl_dbf, 0, SEEK_SET);	/* repositioning at DBF file start */
5509     memset (bf, '\0', 32);
5510     *bf = 0x03;			/* DBF magic number */
5511     *(bf + 1) = 1;		/* this is supposed to be the last update date [Year, Month, Day], but we ignore it at all */
5512     *(bf + 2) = 1;
5513     *(bf + 3) = 1;
5514     gaiaExport32 (bf + 4, dbf_recno, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports # records in this DBF */
5515     gaiaExport16 (bf + 8, (short) dbf_size, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the file header size */
5516     gaiaExport16 (bf + 10, (short) dbf_reclen, GAIA_LITTLE_ENDIAN, endian_arch);	/* exports the record length */
5517     fwrite (bf, 1, 32, fl_dbf);
5518 }
5519 
5520 GAIAGEO_DECLARE int
gaiaReadDbfEntity(gaiaDbfPtr dbf,int current_row,int * deleted)5521 gaiaReadDbfEntity (gaiaDbfPtr dbf, int current_row, int *deleted)
5522 {
5523     return gaiaReadDbfEntity_ex (dbf, current_row, deleted, 0);
5524 }
5525 
5526 GAIAGEO_DECLARE int
gaiaReadDbfEntity_ex(gaiaDbfPtr dbf,int current_row,int * deleted,int text_dates)5527 gaiaReadDbfEntity_ex (gaiaDbfPtr dbf, int current_row, int *deleted,
5528 		      int text_dates)
5529 {
5530 /* trying to read an entity from DBF */
5531     int rd;
5532     int skpos;
5533     gaia_off_t offset;
5534     int len;
5535     char errMsg[1024];
5536     gaiaDbfFieldPtr pFld;
5537 /* positioning and reading the DBF file */
5538     offset =
5539 	dbf->DbfHdsz +
5540 	((gaia_off_t) current_row * (gaia_off_t) (dbf->DbfReclen));
5541     if (dbf->memDbf != NULL)
5542 	skpos = gaiaMemFseek (dbf->memDbf, offset);
5543     else
5544 	skpos = gaia_fseek (dbf->flDbf, offset, SEEK_SET);
5545     if (skpos != 0)
5546 	goto eof;
5547     if (dbf->memDbf != NULL)
5548 	rd = gaiaMemRead (dbf->BufDbf, dbf->DbfReclen, dbf->memDbf);
5549     else
5550 	rd = fread (dbf->BufDbf, sizeof (unsigned char), dbf->DbfReclen,
5551 		    dbf->flDbf);
5552     if (rd != dbf->DbfReclen)
5553 	goto eof;
5554 /* setting up the current DBF ENTITY */
5555     gaiaResetDbfEntity (dbf->Dbf);
5556     dbf->Dbf->RowId = current_row;
5557     if (*(dbf->BufDbf) == '*')
5558       {
5559 	  /* deleted row */
5560 	  *deleted = 1;
5561 	  if (dbf->LastError)
5562 	      free (dbf->LastError);
5563 	  dbf->LastError = NULL;
5564 	  return 1;
5565       }
5566 /* fetching the DBF values */
5567     pFld = dbf->Dbf->First;
5568     while (pFld)
5569       {
5570 	  if (!parseDbfField (dbf->BufDbf, dbf->IconvObj, pFld, text_dates))
5571 	    {
5572 		char *text = malloc (pFld->Length + 1);
5573 		memcpy (text, dbf->BufDbf + pFld->Offset + 1, pFld->Length);
5574 		text[pFld->Length] = '\0';
5575 		spatialite_e
5576 		    ("**** libiconv: unable to convert string=\"%s\"\n", text);
5577 		free (text);
5578 		goto conversion_error;
5579 	    }
5580 	  pFld = pFld->Next;
5581       }
5582     if (dbf->LastError)
5583 	free (dbf->LastError);
5584     dbf->LastError = NULL;
5585     *deleted = 0;
5586     return 1;
5587   eof:
5588     if (dbf->LastError)
5589 	free (dbf->LastError);
5590     dbf->LastError = NULL;
5591     return 0;
5592   conversion_error:
5593     if (dbf->LastError)
5594 	free (dbf->LastError);
5595     sprintf (errMsg, "Invalid character sequence");
5596     sprintf (errMsg, "Invalid character sequence at DBF line %d", current_row);
5597     len = strlen (errMsg);
5598     dbf->LastError = malloc (len + 1);
5599     strcpy (dbf->LastError, errMsg);
5600     return 0;
5601 }
5602 
5603 #endif /* ICONV enabled/disabled */
5604 
5605 #ifdef _WIN32
5606 GAIAGEO_DECLARE FILE *
gaia_win_fopen(const char * path,const char * mode)5607 gaia_win_fopen (const char *path, const char *mode)
5608 {
5609 /* only for Windows: opening a file with an UTF16 path */
5610     wchar_t *path16;
5611     wchar_t *mode16;
5612     int len;
5613     FILE *fl;
5614 
5615 /* converting the PATH from UTF-8 to UNICODE UTF-16 */
5616     len = MultiByteToWideChar (CP_UTF8, 0, path, -1, NULL, 0);
5617     path16 = malloc ((len + 1) * 2);
5618     len = MultiByteToWideChar (CP_UTF8, 0, path, -1, path16, len);
5619 
5620 /* converting the MODE from UTF-8 to UNICODE UTF-16 */
5621     len = MultiByteToWideChar (CP_UTF8, 0, mode, -1, NULL, 0);
5622     mode16 = malloc ((len + 1) * 2);
5623     MultiByteToWideChar (CP_UTF8, 0, mode, -1, mode16, len);
5624 
5625 /* calling the UTF-16 version of fopen() */
5626     fl = _wfopen (path16, mode16);
5627 
5628 /* memory cleanup */
5629     free (path16);
5630     free (mode16);
5631 
5632     return fl;
5633 }
5634 #endif
5635