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